author | Phil Ringnalda <philringnalda@gmail.com> |
Sat, 05 Oct 2013 17:39:34 -0700 | |
changeset 149996 | f191c70fcbfba32d19f34bb377b2f6bd1e31222c |
parent 149974 | 87fd173f56f185c01a652d984ada2accc296f8a4 (current diff) |
parent 149995 | 8434bf06134c7284d28c365be764a13292d1be49 (diff) |
child 149999 | 977391f7a45d7252038a41a0468720401cc3d585 |
child 150003 | 22a5355a3460db1e85482735cce5f24126a026cd |
child 150009 | 641378038788b77a1d1915381975bc14513bdf2c |
child 155821 | a657ab82443bb4d3571cfc8f8ac92d7a0219577c |
push id | 25412 |
push user | philringnalda@gmail.com |
push date | Sun, 06 Oct 2013 00:39:45 +0000 |
treeherder | autoland@f191c70fcbfb [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 27.0a1 |
first release with | nightly linux32
f191c70fcbfb
/
27.0a1
/
20131006030201
/
files
nightly linux64
f191c70fcbfb
/
27.0a1
/
20131006030201
/
files
nightly mac
f191c70fcbfb
/
27.0a1
/
20131006030201
/
files
nightly win32
f191c70fcbfb
/
27.0a1
/
20131006030201
/
files
nightly win64
f191c70fcbfb
/
27.0a1
/
20131006030201
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
27.0a1
/
20131006030201
/
pushlog to previous
nightly linux64
27.0a1
/
20131006030201
/
pushlog to previous
nightly mac
27.0a1
/
20131006030201
/
pushlog to previous
nightly win32
27.0a1
/
20131006030201
/
pushlog to previous
nightly win64
27.0a1
/
20131006030201
/
pushlog to previous
|
--- a/content/events/test/test_all_synthetic_events.html +++ b/content/events/test/test_all_synthetic_events.html @@ -379,16 +379,20 @@ const kEventConstructors = { var e = document.createEvent("touchevent"); e.initTouchEvent(aName, aProps.bubbles, aProps.cancelable, aProps.view, aProps.detail, aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey, aProps.touches, aProps.targetTouches, aProps.changedTouches); return e; }, }, + TrackEvent: { create: function (aName, aProps) { + return new TrackEvent(aName, aProps); + }, + }, TransitionEvent: { create: function (aName, aProps) { return new TransitionEvent(aName, aProps); }, }, UIEvent: { create: function (aName, aProps) { return new UIEvent(aName, aProps); }, },
--- a/content/html/content/reftests/468263-2-alternate-ref.html +++ b/content/html/content/reftests/468263-2-alternate-ref.html @@ -1,6 +1,7 @@ <!DOCTYPE HTML> <html> <body> + <img id="image1" src=""> <input id="image3" type="image"> </body> </html>
--- a/content/media/TextTrackList.cpp +++ b/content/media/TextTrackList.cpp @@ -1,15 +1,17 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/TextTrackList.h" #include "mozilla/dom/TextTrackListBinding.h" +#include "mozilla/dom/TrackEvent.h" +#include "nsThreadUtils.h" namespace mozilla { namespace dom { NS_IMPL_CYCLE_COLLECTION_INHERITED_2(TextTrackList, nsDOMEventTargetHelper, mGlobal, mTextTracks) @@ -49,18 +51,20 @@ TextTrackList::IndexedGetter(uint32_t aI already_AddRefed<TextTrack> TextTrackList::AddTextTrack(HTMLMediaElement* aMediaElement, TextTrackKind aKind, const nsAString& aLabel, const nsAString& aLanguage) { nsRefPtr<TextTrack> track = new TextTrack(mGlobal, aMediaElement, aKind, aLabel, aLanguage); - mTextTracks.AppendElement(track); - // TODO: dispatch addtrack event + if (mTextTracks.AppendElement(track)) { + CreateAndDispatchTrackEventRunner(track, NS_LITERAL_STRING("addtrack")); + } + return track.forget(); } TextTrack* TextTrackList::GetTrackById(const nsAString& aId) { nsAutoString id; for (uint32_t i = 0; i < Length(); i++) { @@ -68,23 +72,65 @@ TextTrackList::GetTrackById(const nsAStr if (aId.Equals(id)) { return mTextTracks[i]; } } return nullptr; } void -TextTrackList::RemoveTextTrack(const TextTrack& aTrack) +TextTrackList::RemoveTextTrack(TextTrack& aTrack) { - mTextTracks.RemoveElement(&aTrack); + if (mTextTracks.RemoveElement(&aTrack)) { + CreateAndDispatchTrackEventRunner(&aTrack, NS_LITERAL_STRING("removetrack")); + } } void TextTrackList::DidSeek() { for (uint32_t i = 0; i < mTextTracks.Length(); i++) { mTextTracks[i]->SetDirty(); } } +class TrackEventRunner MOZ_FINAL: public nsRunnable +{ +public: + TrackEventRunner(TextTrackList* aList, TrackEvent* aEvent) + : mList(aList) + , mEvent(aEvent) + {} + + NS_IMETHOD Run() MOZ_OVERRIDE + { + return mList->DispatchTrackEvent(mEvent); + } + +private: + nsRefPtr<TextTrackList> mList; + nsRefPtr<TrackEvent> mEvent; +}; + +nsresult +TextTrackList::DispatchTrackEvent(TrackEvent* aEvent) +{ + return DispatchTrustedEvent(aEvent); +} + +void +TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack, + const nsAString& aEventName) +{ + TrackEventInitInitializer eventInit; + eventInit.mBubbles = false; + eventInit.mCancelable = false; + eventInit.mTrack = aTrack; + nsRefPtr<TrackEvent> trackEvent = + TrackEvent::Constructor(this, aEventName, eventInit); + + // Dispatch the TrackEvent asynchronously. + nsCOMPtr<nsIRunnable> event = new TrackEventRunner(this, trackEvent); + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); +} + } // namespace dom } // namespace mozilla
--- a/content/media/TextTrackList.h +++ b/content/media/TextTrackList.h @@ -9,16 +9,19 @@ #include "mozilla/dom/TextTrack.h" #include "nsCycleCollectionParticipant.h" #include "nsDOMEventTargetHelper.h" namespace mozilla { namespace dom { +class TrackEvent; +class TrackEventRunner; + class TextTrackList MOZ_FINAL : public nsDOMEventTargetHelper { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextTrackList, nsDOMEventTargetHelper) TextTrackList(nsISupports* aGlobal); @@ -45,23 +48,28 @@ public: const nsAString& aLabel, const nsAString& aLanguage); TextTrack* GetTrackById(const nsAString& aId); void AddTextTrack(TextTrack* aTextTrack) { mTextTracks.AppendElement(aTextTrack); } - void RemoveTextTrack(const TextTrack& aTrack); + void RemoveTextTrack(TextTrack& aTrack); void DidSeek(); + nsresult DispatchTrackEvent(TrackEvent* aEvent); + IMPL_EVENT_HANDLER(addtrack) IMPL_EVENT_HANDLER(removetrack) private: nsCOMPtr<nsISupports> mGlobal; nsTArray< nsRefPtr<TextTrack> > mTextTracks; + + void CreateAndDispatchTrackEventRunner(TextTrack* aTrack, + const nsAString& aEventName); }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_TextTrackList_h
--- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -140,16 +140,17 @@ MOCHITEST_FILES = \ test_streams_element_capture.html \ test_streams_element_capture_reset.html \ test_streams_element_capture_createObjectURL.html \ test_streams_gc.html \ test_streams_tracks.html \ $(filter disabled-for-intermittent-failures--bug-608634, test_error_in_video_document.html) \ test_texttrack.html \ test_texttrackcue.html \ + test_trackevent.html \ test_texttrackregion.html \ test_timeupdate_small_files.html \ test_unseekable.html \ test_VideoPlaybackQuality.html \ test_VideoPlaybackQuality_disabled.html \ test_webvtt_disabled.html \ $(NULL)
new file mode 100644 --- /dev/null +++ b/content/media/test/test_trackevent.html @@ -0,0 +1,62 @@ + +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 893309 - Implement TrackEvent</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]}, + function() { + var video = document.createElement("video"); + isnot(video.textTracks, undefined, "HTMLMediaElement::TextTrack() property should be available.") + ok(typeof video.addTextTrack == "function", "HTMLMediaElement::AddTextTrack() function should be available.") + + var trackList = video.textTracks; + is(trackList.length, 0, "Length should be 0."); + + var evtTextTrack, numOfCalls = 0; + trackList.onaddtrack = function(event) { + ok(event instanceof TrackEvent, "Fired event from onaddtrack should be a TrackEvent"); + is(event.type, "addtrack", "Event type should be addtrack"); + ok(event.isTrusted, "Event should be trusted!"); + ok(!event.bubbles, "Event shouldn't bubble!"); + ok(!event.cancelable, "Event shouldn't be cancelable!"); + + evtTextTrack = event.track; + ok(textTrack[numOfCalls] === evtTextTrack, "Text tracks should be the same"); + is(evtTextTrack.label, label[numOfCalls], "Label should be set to "+ label[numOfCalls]); + is(evtTextTrack.language, language[numOfCalls], "Language should be " + language[numOfCalls]); + is(evtTextTrack.kind, kind[numOfCalls], "Kind should be " + kind[numOfCalls]); + + if (++numOfCalls == 3) { + SimpleTest.finish(); + } + }; + + var label = ["Oasis", "Coldplay", "t.A.T.u"]; + language = ["en-CA", "en-GB", "ru" ]; + kind = ["subtitles", "captions", "chapters"]; + + var textTrack = new Array(3); + for (var i = 0; i < 3; ++i) { + textTrack[i] = video.addTextTrack(kind[i], label[i], language[i]); + is(trackList.length, i + 1, "Length should be " + (i+1)); + } + + //TODO: Tests for removetrack event to be added along with bug 882677 + } +); +</script> +</pre> +</body> +</html> +
--- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -118,22 +118,24 @@ nsDSURIContentListener::DoContent(const mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL); } rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler); if (rv == NS_ERROR_REMOTE_XUL) { request->Cancel(rv); + *aAbortProcess = true; return NS_OK; } - if (NS_FAILED(rv)) { - // it's okay if we don't know how to handle the content - return NS_OK; + if (NS_FAILED(rv)) { + // we don't know how to handle the content + *aContentHandler = nullptr; + return rv; } if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(static_cast<nsIDocShell*>(mDocShell)); NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); domWindow->Focus(); }
--- a/dom/apps/src/Webapps.js +++ b/dom/apps/src/Webapps.js @@ -39,35 +39,40 @@ WebappsRegistry.prototype = { if (msg.oid != this._id) return let req = this.getRequest(msg.requestID); if (!req) return; let app = msg.app; switch (aMessage.name) { case "Webapps:Install:Return:OK": + this.removeMessageListeners("Webapps:Install:Return:KO"); Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); cpmm.sendAsyncMessage("Webapps:Install:Return:Ack", { manifestURL : app.manifestURL }); break; case "Webapps:Install:Return:KO": + this.removeMessageListeners(aMessage.name); Services.DOMRequest.fireError(req, msg.error || "DENIED"); break; case "Webapps:GetSelf:Return:OK": + this.removeMessageListeners(aMessage.name); if (msg.apps.length) { app = msg.apps[0]; Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); } else { Services.DOMRequest.fireSuccess(req, null); } break; case "Webapps:CheckInstalled:Return:OK": + this.removeMessageListeners(aMessage.name); Services.DOMRequest.fireSuccess(req, msg.app); break; case "Webapps:GetInstalled:Return:OK": + this.removeMessageListeners(aMessage.name); Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window)); break; } this.removeRequest(msg.requestID); }, _getOrigin: function(aURL) { let uri = Services.io.newURI(aURL, null, null); @@ -150,46 +155,51 @@ WebappsRegistry.prototype = { // mozIDOMApplicationRegistry implementation install: function(aURL, aParams) { let uri = this._validateURL(aURL); let request = this.createRequest(); if (this._ensureForeground(request)) { + this.addMessageListeners("Webapps:Install:Return:KO"); cpmm.sendAsyncMessage("Webapps:Install", this._prepareInstall(uri, request, aParams, false)); } return request; }, getSelf: function() { let request = this.createRequest(); + this.addMessageListeners("Webapps:GetSelf:Return:OK"); cpmm.sendAsyncMessage("Webapps:GetSelf", { origin: this._getOrigin(this._window.location.href), appId: this._window.document.nodePrincipal.appId, oid: this._id, requestID: this.getRequestId(request) }); return request; }, checkInstalled: function(aManifestURL) { let manifestURL = Services.io.newURI(aManifestURL, null, this._window.document.baseURIObject); this._window.document.nodePrincipal.checkMayLoad(manifestURL, true, false); let request = this.createRequest(); + + this.addMessageListeners("Webapps:CheckInstalled:Return:OK"); cpmm.sendAsyncMessage("Webapps:CheckInstalled", { origin: this._getOrigin(this._window.location.href), manifestURL: manifestURL.spec, oid: this._id, requestID: this.getRequestId(request) }); return request; }, getInstalled: function() { let request = this.createRequest(); + this.addMessageListeners("Webapps:GetInstalled:Return:OK"); cpmm.sendAsyncMessage("Webapps:GetInstalled", { origin: this._getOrigin(this._window.location.href), oid: this._id, requestID: this.getRequestId(request) }); return request; }, get mgmt() { if (!this.hasMgmtPrivilege) { @@ -208,29 +218,27 @@ WebappsRegistry.prototype = { }, installPackage: function(aURL, aParams) { let uri = this._validateURL(aURL); let request = this.createRequest(); if (this._ensureForeground(request)) { + this.addMessageListeners("Webapps:Install:Return:KO"); cpmm.sendAsyncMessage("Webapps:InstallPackage", this._prepareInstall(uri, request, aParams, true)); } return request; }, // nsIDOMGlobalPropertyInitializer implementation init: function(aWindow) { - this.initDOMRequestHelper(aWindow, ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO", - "Webapps:GetInstalled:Return:OK", - "Webapps:GetSelf:Return:OK", - "Webapps:CheckInstalled:Return:OK" ]); + this.initDOMRequestHelper(aWindow, "Webapps:Install:Return:OK"); let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); this._id = util.outerWindowID; cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { messages: ["Webapps:Install:Return:OK"]}); let principal = aWindow.document.nodePrincipal; @@ -333,26 +341,25 @@ WebappsApplication.prototype = { this._onprogress = null; this._ondownloadsuccess = null; this._ondownloaderror = null; this._ondownloadavailable = null; this._ondownloadapplied = null; this._downloadError = null; - this.initDOMRequestHelper(aWindow, ["Webapps:OfflineCache", - "Webapps:CheckForUpdate:Return:OK", - "Webapps:CheckForUpdate:Return:KO", - "Webapps:Launch:Return:OK", - "Webapps:Launch:Return:KO", - "Webapps:PackageEvent", - "Webapps:ClearBrowserData:Return", - "Webapps:Connect:Return:OK", - "Webapps:Connect:Return:KO", - "Webapps:GetConnections:Return:OK"]); + this.initDOMRequestHelper(aWindow, [ + "Webapps:OfflineCache", + "Webapps:CheckForUpdate:Return:OK", + "Webapps:CheckForUpdate:Return:KO", + "Webapps:PackageEvent", + "Webapps:Connect:Return:OK", + "Webapps:Connect:Return:KO", + "Webapps:GetConnections:Return:OK" + ]); cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { messages: ["Webapps:OfflineCache", "Webapps:PackageEvent", "Webapps:CheckForUpdate:Return:OK"], app: { id: this.id, @@ -436,30 +443,33 @@ WebappsApplication.prototype = { { manifestURL: this.manifestURL, oid: this._id, requestID: this.getRequestId(request) }); return request; }, launch: function(aStartPoint) { let request = this.createRequest(); + this.addMessageListeners(["Webapps:Launch:Return:OK", + "Webapps:Launch:Return:KO"]); cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin, manifestURL: this.manifestURL, startPoint: aStartPoint || "", oid: this._id, timestamp: Date.now(), requestID: this.getRequestId(request) }); return request; }, clearBrowserData: function() { let request = this.createRequest(); let browserChild = BrowserElementPromptService.getBrowserElementChildForWindow(this._window); if (browserChild) { + this.addMessageListeners("Webapps:ClearBrowserData:Return"); browserChild.messageManager.sendAsyncMessage( "Webapps:ClearBrowserData", { manifestURL: this.manifestURL, oid: this._id, requestID: this.getRequestId(request) } ); } else { let runnable = { @@ -531,19 +541,23 @@ WebappsApplication.prototype = { // ondownload* callbacks should be triggered on all app instances if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache" && aMessage.name !== "Webapps:PackageEvent" && aMessage.name !== "Webapps:CheckForUpdate:Return:OK") return; switch (aMessage.name) { case "Webapps:Launch:Return:KO": + this.removeMessageListeners(["Webapps:Launch:Return:OK", + "Webapps:Launch:Return:KO"]); Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING"); break; case "Webapps:Launch:Return:OK": + this.removeMessageListeners(["Webapps:Launch:Return:OK", + "Webapps:Launch:Return:KO"]); Services.DOMRequest.fireSuccess(req, null); break; case "Webapps:CheckForUpdate:Return:KO": Services.DOMRequest.fireError(req, msg.error); break; case "Webapps:CheckForUpdate:Return:OK": if (msg.manifestURL != this.manifestURL) return; @@ -643,16 +657,17 @@ WebappsApplication.prototype = { case "applied": manifestCache.evict(this.manifestURL, this.innerWindowID); this._manifest = msg.manifest; this._fireEvent("downloadapplied", this._ondownloadapplied); break; } break; case "Webapps:ClearBrowserData:Return": + this.removeMessageListeners(aMessage.name); Services.DOMRequest.fireSuccess(req, null); break; case "Webapps:Connect:Return:OK": let messagePorts = []; msg.messagePortIDs.forEach(function(aPortID) { let port = new this._window.MozInterAppMessagePort(aPortID); messagePorts.push(port); }, this); @@ -686,23 +701,24 @@ WebappsApplication.prototype = { flags: Ci.nsIClassInfo.DOM_OBJECT, classDescription: "Webapps Application"}) } /** * mozIDOMApplicationMgmt object */ function WebappsApplicationMgmt(aWindow) { - this.initDOMRequestHelper(aWindow, ["Webapps:GetAll:Return:OK", - "Webapps:GetAll:Return:KO", - "Webapps:Uninstall:Return:OK", - "Webapps:Uninstall:Broadcast:Return:OK", - "Webapps:Uninstall:Return:KO", - "Webapps:Install:Return:OK", - "Webapps:GetNotInstalled:Return:OK"]); + this.initDOMRequestHelper(aWindow, [ + { name: "Webapps:GetAll:Return:OK", strongRef: true }, + { name: "Webapps:GetAll:Return:KO", strongRef: true }, + { name: "Webapps:Uninstall:Return:OK", strongRef: true }, + { name: "Webapps:Uninstall:Broadcast:Return:OK", strongRef: true }, + { name: "Webapps:Uninstall:Return:KO", strongRef: true }, + { name: "Webapps:Install:Return:OK", strongRef: true }, + { name: "Webapps:GetNotInstalled:Return:OK", strongRef: true }]); cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { messages: ["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Broadcast:Return:OK"] } );
--- a/dom/apps/tests/file_app.template.html +++ b/dom/apps/tests/file_app.template.html @@ -47,17 +47,18 @@ function go() { request.onerror = cbError; } function checkApp(app) { // If the app is installed, |app| will be non-null. If it is, verify its state. installed(!!app); if (app) { var appName = "Really Rapid Release (APPTYPETOKEN)"; - is(app.manifest.name, appName, "Manifest name should be correct"); + var manifest = SpecialPowers.wrap(app.manifest); + is(manifest.name, appName, "Manifest name should be correct"); is(app.origin, "http://test", "App origin should be correct"); is(app.installOrigin, "http://mochi.test:8888", "Install origin should be correct"); } finish(); } </script> </head>
--- a/dom/base/DOMRequestHelper.jsm +++ b/dom/base/DOMRequestHelper.jsm @@ -1,230 +1,286 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ /** - * Helper object for APIs that deal with DOMRequests and Promises and need to - * release them when the window goes out of scope. + * Helper object for APIs that deal with DOMRequests and Promises. + * It allows objects inheriting from it to create and keep track of DOMRequests + * and Promises objects in the common scenario where requests are created in + * the child, handed out to content and delivered to the parent within an async + * message (containing the identifiers of these requests). The parent may send + * messages back as answers to different requests and the child will use this + * helper to get the right request object. This helper also takes care of + * releasing the requests objects when the window goes out of scope. + * + * DOMRequestIPCHelper also deals with message listeners, allowing to add them + * to the child side of frame and process message manager and removing them + * when needed. */ const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; +const Cr = Components.results; this.EXPORTED_SYMBOLS = ["DOMRequestIpcHelper"]; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", "nsIMessageListenerManager"); -/** - * We use DOMRequestIpcHelperMessageListener to avoid leaking objects which - * "inherit" from DOMRequestIpcHelper. - * - * The issue is that the message manager will hold a strong ref to the message - * listener we register with it. But we don't want to hold a strong ref to the - * DOMRequestIpcHelper object, because that object may be arbitrarily large. - * - * So instead the message manager holds a strong ref to the - * DOMRequestIpcHelperMessageListener, and that holds a /weak/ ref to its - * DOMRequestIpcHelper. - * - * Additionally, we want to unhook all of these message listeners when the - * appropriate window is destroyed. We use DOMRequestIpcHelperMessageListener - * for this, too. - */ -this.DOMRequestIpcHelperMessageListener = function(aHelper, aWindow, aMessages) { - this._weakHelper = Cu.getWeakReference(aHelper); - - this._messages = aMessages; - this._messages.forEach(function(msgName) { - cpmm.addWeakMessageListener(msgName, this); - }, this); - - Services.obs.addObserver(this, "inner-window-destroyed", /* weakRef */ true); - - // aWindow may be null; in that case, the DOMRequestIpcHelperMessageListener - // is not tied to a particular window and lives forever. - if (aWindow) { - let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - this._innerWindowID = util.currentInnerWindowID; - } +this.DOMRequestIpcHelper = function DOMRequestIpcHelper() { + // _listeners keeps a list of messages for which we added a listener and the + // kind of listener that we added (strong or weak). It's an object of this + // form: + // { + // "message1": true, + // "messagen": false + // } + // + // where each property is the name of the message and its value is a boolean + // that indicates if the listener is strong or not. + this._listeners = null; + this._requests = null; + this._window = null; } -DOMRequestIpcHelperMessageListener.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener, - Ci.nsIObserver, - Ci.nsISupportsWeakReference]), +DOMRequestIpcHelper.prototype = { + /** + * An object which "inherits" from DOMRequestIpcHelper, declares its own + * queryInterface method and adds at least one weak listener to the Message + * Manager MUST implement Ci.nsISupportsWeakReference. + */ + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]), + + /** + * 'aMessages' is expected to be an array of either: + * - objects of this form: + * { + * name: "messageName", + * strongRef: false + * } + * where 'name' is the message identifier and 'strongRef' a boolean + * indicating if the listener should be a strong referred one or not. + * + * - or only strings containing the message name, in which case the listener + * will be added as a weak reference by default. + */ + addMessageListeners: function(aMessages) { + if (!aMessages) { + return; + } + + if (!this._listeners) { + this._listeners = {}; + } + + if (!Array.isArray(aMessages)) { + aMessages = [aMessages]; + } + + aMessages.forEach((aMsg) => { + let name = aMsg.name || aMsg; + // If the listener is already set and it is of the same type we just + // bail out. If it is not of the same type, we throw an exception. + if (this._listeners[name] != undefined) { + if (!!aMsg.strongRef == this._listeners[name]) { + return; + } else { + throw Cr.NS_ERROR_FAILURE; + } + } + + aMsg.strongRef ? cpmm.addMessageListener(name, this) + : cpmm.addWeakMessageListener(name, this); + this._listeners[name] = !!aMsg.strongRef; + }); + }, + + /** + * 'aMessages' is expected to be a string or an array of strings containing + * the message names of the listeners to be removed. + */ + removeMessageListeners: function(aMessages) { + if (!this._listeners || !aMessages) { + return; + } + + if (!Array.isArray(aMessages)) { + aMessages = [aMessages]; + } + + aMessages.forEach((aName) => { + if (this._listeners[aName] == undefined) { + return; + } + + this._listeners[aName] ? cpmm.removeMessageListener(aName, this) + : cpmm.removeWeakMessageListener(aName, this); + delete this._listeners[aName]; + }); + }, + + /** + * Initialize the helper adding the corresponding listeners to the messages + * provided as the second parameter. + * + * 'aMessages' is expected to be an array of either: + * + * - objects of this form: + * { + * name: 'messageName', + * strongRef: false + * } + * where 'name' is the message identifier and 'strongRef' a boolean + * indicating if the listener should be a strong referred one or not. + * + * - or only strings containing the message name, in which case the listener + * will be added as a weak referred one by default. + */ + initDOMRequestHelper: function(aWindow, aMessages) { + if (aMessages) { + this.addMessageListeners(aMessages); + } + + this._id = this._getRandomId(); + + this._window = aWindow; + if (this._window) { + // We don't use this.innerWindowID, but other classes rely on it. + let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + this.innerWindowID = util.currentInnerWindowID; + } + + Services.obs.addObserver(this, "inner-window-destroyed", false); + }, + + destroyDOMRequestHelper: function() { + Services.obs.removeObserver(this, "inner-window-destroyed"); + + if (this._listeners) { + Object.keys(this._listeners).forEach((aName) => { + this._listeners[aName] ? cpmm.removeMessageListener(aName, this) + : cpmm.removeWeakMessageListener(aName, this); + delete this._listeners[aName]; + }); + } + + this._listeners = null; + this._requests = null; + this._window = null; + }, observe: function(aSubject, aTopic, aData) { if (aTopic !== "inner-window-destroyed") { return; } let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data; - if (wId != this._innerWindowID) { + if (wId != this.innerWindowID) { return; } - this.destroy(); - }, - - receiveMessage: function(aMsg) { - let helper = this._weakHelper.get(); - if (helper) { - helper.receiveMessage(aMsg); - } else { - this.destroy(); - } - }, - - destroy: function() { - // DOMRequestIpcHelper.destroy() calls back into this function. - if (this._destroyed) { - return; - } - this._destroyed = true; - - Services.obs.removeObserver(this, "inner-window-destroyed"); - - this._messages.forEach(function(msgName) { - cpmm.removeWeakMessageListener(msgName, this); - }, this); - this._messages = null; - - let helper = this._weakHelper.get(); - if (helper) { - helper.destroyDOMRequestHelper(); - } - } -} - -this.DOMRequestIpcHelper = function DOMRequestIpcHelper() { -} - -DOMRequestIpcHelper.prototype = { - /** - * An object which "inherits" from DOMRequestIpcHelper and declares its own - * queryInterface method MUST implement Ci.nsISupportsWeakReference. - */ - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]), - - initDOMRequestHelper: function(aWindow, aMessages) { - this._DOMRequestIpcHelperMessageListener = - new DOMRequestIpcHelperMessageListener(this, aWindow, aMessages); - - this._window = aWindow; - this._requests = {}; - this._id = this._getRandomId(); - - if (this._window) { - // We don't use this.innerWindowID, but other classes rely on it. - let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - this.innerWindowID = util.currentInnerWindowID; - } + this.destroyDOMRequestHelper(); }, getRequestId: function(aRequest) { + if (!this._requests) { + this._requests = {}; + } + let id = "id" + this._getRandomId(); this._requests[id] = aRequest; return id; }, getPromiseResolverId: function(aPromiseResolver) { // Delegates to getRequest() since the lookup table is agnostic about // storage. return this.getRequestId(aPromiseResolver); }, getRequest: function(aId) { - if (this._requests[aId]) + if (this._requests && this._requests[aId]) { return this._requests[aId]; + } }, getPromiseResolver: function(aId) { // Delegates to getRequest() since the lookup table is agnostic about // storage. return this.getRequest(aId); }, removeRequest: function(aId) { - if (this._requests[aId]) + if (this._requests && this._requests[aId]) { delete this._requests[aId]; + } }, removePromiseResolver: function(aId) { // Delegates to getRequest() since the lookup table is agnostic about // storage. this.removeRequest(aId); }, takeRequest: function(aId) { - if (!this._requests[aId]) + if (!this._requests || !this._requests[aId]) { return null; + } let request = this._requests[aId]; delete this._requests[aId]; return request; }, takePromiseResolver: function(aId) { // Delegates to getRequest() since the lookup table is agnostic about // storage. return this.takeRequest(aId); }, _getRandomId: function() { - return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString(); - }, - - destroyDOMRequestHelper: function() { - // This function is re-entrant -- - // DOMRequestIpcHelperMessageListener.destroy() calls back into this - // function, and this.uninit() may also call it. - if (this._destroyed) { - return; - } - this._destroyed = true; - - this._DOMRequestIpcHelperMessageListener.destroy(); - this._requests = {}; - this._window = null; - - if(this.uninit) { - this.uninit(); - } + return Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); }, createRequest: function() { return Services.DOMRequest.createRequest(this._window); }, /** * createPromise() creates a new Promise, with `aPromiseInit` as the * PromiseInit callback. The promise constructor is obtained from the * reference to window owned by this DOMRequestIPCHelper. */ createPromise: function(aPromiseInit) { return new this._window.Promise(aPromiseInit); }, forEachRequest: function(aCallback) { - Object.keys(this._requests).forEach(function(k) { - if (this.getRequest(k) instanceof this._window.DOMRequest) { - aCallback(k); + if (!this._requests) { + return; + } + + Object.keys(this._requests).forEach((aKey) => { + if (this.getRequest(aKey) instanceof this._window.DOMRequest) { + aCallback(aKey); } - }, this); + }); }, forEachPromiseResolver: function(aCallback) { - Object.keys(this._requests).forEach(function(k) { - if ("resolve" in this.getPromiseResolver(k) && - "reject" in this.getPromiseResolver(k)) { - aCallback(k); + if (!this._requests) { + return; + } + + Object.keys(this._requests).forEach((aKey) => { + if ("resolve" in this.getPromiseResolver(aKey) && + "reject" in this.getPromiseResolver(aKey)) { + aCallback(aKey); } - }, this); + }); }, }
--- a/dom/base/test/test_domrequesthelper.xul +++ b/dom/base/test/test_domrequesthelper.xul @@ -12,113 +12,349 @@ <title>DOMRequestHelper Test</title> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> <script type="application/javascript"> <![CDATA[ Components.utils.import("resource://gre/modules/DOMRequestHelper.jsm"); + function DummyHelperSubclass() { - this.initDOMRequestHelper(window, []); } - DummyHelperSubclass.prototype = { __proto__: DOMRequestIpcHelper.prototype }; var dummy = new DummyHelperSubclass(); - function createPromise() { - ok(Promise, "Promise object should exist"); + /** + * Init & destroy. + */ + function initDOMRequestHelperTest(aMessages) { + is(dummy._requests, undefined, "Request is undefined"); + is(dummy._messages, undefined, "Messages is undefined"); + is(dummy._window, undefined, "Window is undefined"); + + dummy.initDOMRequestHelper(window, aMessages); - var promise = dummy.createPromise(function(resolve, reject) { - resolve(true); - }); - ok(promise instanceof Promise, "returned a Promise"); - promise.then(runTest); + ok(dummy._window, "Window exists"); + is(dummy._window, window, "Correct window"); + if (aMessages) { + is(typeof dummy._listeners, "object", "Listeners is an object"); + } + } + + function destroyDOMRequestHelperTest() { + dummy.destroyDOMRequestHelper(); + + is(dummy._requests, undefined, "Request is undefined"); + is(dummy._messages, undefined, "Messages is undefined"); + is(dummy._window, undefined, "Window is undefined"); } - function getResolver() { - var id; - var resolver; - var promise = dummy.createPromise(function(resolve, reject) { - var r = { resolve: resolve, reject: reject }; - id = dummy.getPromiseResolverId(r); - resolver = r; - ok(typeof id === "string", "id should be string"); - r.resolve(true); - }).then(function(unused) { - var r = dummy.getPromiseResolver(id); - ok(resolver === r, "get should succeed"); - runTest(); + /** + * Message listeners. + */ + function checkMessageListeners(aExpectedListeners, aCount) { + ok(true, "Checking message listeners\n" + "Expected listeners " + + JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount); + let count = 0; + Object.keys(dummy._listeners).forEach(function(name) { + count++; + is(aExpectedListeners[name], dummy._listeners[name], + "Message found " + name + " - Same listeners"); }); + is(aCount, count, "Correct number of listeners"); + } + + function addMessageListenersTest(aMessages, aExpectedListeners, aCount) { + dummy.addMessageListeners(aMessages); + ok(true, JSON.stringify(dummy._listeners)); + checkMessageListeners(aExpectedListeners, aCount); + } + + function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) { + dummy.removeMessageListeners(aMessages); + checkMessageListeners(aExpectedListeners, aCount); } - function removeResolver() { - var id; - var promise = dummy.createPromise(function(resolve, reject) { - var r = { resolve: resolve, reject: reject }; - id = dummy.getPromiseResolverId(r); - ok(typeof id === "string", "id should be string"); - - var resolver = dummy.getPromiseResolver(id); - ok(resolver === r, "resolver get should succeed"); - - r.resolve(true); - }).then(function(unused) { - dummy.removePromiseResolver(id); - var resolver = dummy.getPromiseResolver(id); - ok(resolver === undefined, "removeResolver: get should fail"); - runTest(); - }); - } + /** + * Test steps. + */ + var tests = [ + function() { + ok(true, "== InitDOMRequestHelper no messages"); + initDOMRequestHelperTest(null); + next(); + }, + function() { + ok(true, "== DestroyDOMRequestHelper"); + destroyDOMRequestHelperTest(); + next(); + }, + function() { + ok(true, "== InitDOMRequestHelper empty array"); + initDOMRequestHelperTest([]); + checkMessageListeners({}, 0); + next(); + }, + function() { + ok(true, "== DestroyDOMRequestHelper"); + destroyDOMRequestHelperTest(); + next(); + }, + function() { + ok(true, "== InitDOMRequestHelper with strings array"); + initDOMRequestHelperTest(["name1", "nameN"]); + checkMessageListeners({"name1": false, "nameN": false}, 2); + next(); + }, + function() { + ok(true, "== DestroyDOMRequestHelper"); + destroyDOMRequestHelperTest(); + next(); + }, + function() { + ok(true, "== InitDOMRequestHelper with objects array"); + initDOMRequestHelperTest([{ + name: "name1", + strongRef: false + }, { + name: "nameN", + strongRef: true + }]); + checkMessageListeners({"name1": false, "nameN": true}, 2); + next(); + }, + function() { + ok(true, "== AddMessageListeners empty array"); + addMessageListenersTest([], {"name1": false, "nameN": true}, 2); + next(); + }, + function() { + ok(true, "== AddMessageListeners null"); + addMessageListenersTest(null, {"name1": false, "nameN": true}, 2); + next(); + }, + function() { + ok(true, "== AddMessageListeners new listener, string only"); + addMessageListenersTest("name2", { + "name1": false, + "name2": false, + "nameN": true + }, 3); + next(); + }, + function() { + ok(true, "== AddMessageListeners new listeners, strings array"); + addMessageListenersTest(["name3", "name4"], { + "name1": false, + "name2": false, + "name3": false, + "name4": false, + "nameN": true + }, 5); + next(); + }, + function() { + ok(true, "== AddMessageListeners new listeners, objects array"); + addMessageListenersTest([{ + name: "name5", + strongRef: true + }, { + name: "name6", + strongRef: false + }], { + "name1": false, + "name2": false, + "name3": false, + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 7); + next(); + }, + function() { + ok(true, "== RemoveMessageListeners, null"); + removeMessageListenersTest(null, { + "name1": false, + "name2": false, + "name3": false, + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 7); + next(); + }, + function() { + ok(true, "== RemoveMessageListeners, one message"); + removeMessageListenersTest("name1", { + "name2": false, + "name3": false, + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 6); + next(); + }, + function() { + ok(true, "== RemoveMessageListeners, array of messages"); + removeMessageListenersTest(["name2", "name3"], { + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 4); + next(); + }, + function() { + ok(true, "== RemoveMessageListeners, unknown message"); + removeMessageListenersTest("unknown", { + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 4); + next(); + }, + function() { + try { + ok(true, "== AddMessageListeners, same message, same kind"); + addMessageListenersTest("name4", { + "name4": false, + "name5": true, + "name6": false, + "nameN": true + }, 4); + next(); + } catch (ex) { + ok(false, "Unexpected exception " + ex); + } + }, + function() { + ok(true, "== AddMessageListeners, same message, different kind"); + try { + addMessageListenersTest({name: "name4", strongRef: true}, { + "name4": true, + "name5": true, + "name6": false, + "nameN": true + }, 4); + ok(false, "Should have thrown an exception"); + } catch (ex) { + ok(true, "Expected exception"); + next(); + } + }, + function() { + ok(true, "== Test createRequest()"); + ok(DOMRequest, "DOMRequest object exists"); + var req = dummy.createRequest(); + ok(req instanceof DOMRequest, "Returned a DOMRequest"); + next(); + }, + function() { + ok(true, "== Test getRequestId(), removeRequest() and getRequest()"); + var req = dummy.createRequest(); + var id = dummy.getRequestId(req); + is(typeof id, "string", "id is a string"); + var req_ = dummy.getRequest(id); + is(req, req_, "Got correct request"); + dummy.removeRequest(id); + req = dummy.getRequest(id); + is(req, null, "No request"); + next(); + }, + function() { + ok(true, "== Test createPromise()"); + ok(Promise, "Promise object exists"); + var promise = dummy.createPromise(function(resolve, reject) { + resolve(true); + }); + ok(promise instanceof Promise, "Returned a Promise"); + promise.then(next); + }, + function() { + ok(true, "== Test getResolver()"); + var id; + var resolver; + var promise = dummy.createPromise(function(resolve, reject) { + var r = { resolve: resolve, reject: reject }; + id = dummy.getPromiseResolverId(r); + resolver = r; + ok(typeof id === "string", "id is a string"); + r.resolve(true); + }).then(function(unused) { + var r = dummy.getPromiseResolver(id); + ok(resolver === r, "Get succeeded"); + next(); + }); + }, + function() { + ok(true, "== Test removeResolver"); + var id; + var promise = dummy.createPromise(function(resolve, reject) { + var r = { resolve: resolve, reject: reject }; + id = dummy.getPromiseResolverId(r); + ok(typeof id === "string", "id is a string"); - function takeResolver() { - var id; - var resolver; - var promise = dummy.createPromise(function(resolve, reject) { - var r = { resolve: resolve, reject: reject }; - id = dummy.getPromiseResolverId(r); - resolver = r; - ok(typeof id === "string", "id should be string"); - - var gotR = dummy.getPromiseResolver(id); - ok(gotR === r, "resolver get should succeed"); + var resolver = dummy.getPromiseResolver(id); + ok(true, "Got resolver " + JSON.stringify(resolver)); + ok(resolver === r, "Resolver get succeeded"); - r.resolve(true); - }).then(function(unused) { - var r = dummy.takePromiseResolver(id); - ok(resolver === r, "take should succeed"); + r.resolve(true); + }).then(function(unused) { + dummy.removePromiseResolver(id); + var resolver = dummy.getPromiseResolver(id); + ok(resolver === undefined, "removeResolver: get failed"); + next(); + }); + }, + function() { + ok(true, "== Test takeResolver"); + var id; + var resolver; + var promise = dummy.createPromise(function(resolve, reject) { + var r = { resolve: resolve, reject: reject }; + id = dummy.getPromiseResolverId(r); + resolver = r; + ok(typeof id === "string", "id is a string"); - r = dummy.getPromiseResolver(id); - ok(r === undefined, "takeResolver: get should fail"); - runTest(); - }); - } + var gotR = dummy.getPromiseResolver(id); + ok(gotR === r, "resolver get succeeded"); + + r.resolve(true); + }).then(function(unused) { + var r = dummy.takePromiseResolver(id); + ok(resolver === r, "take should succeed"); - var tests = [ createPromise, - getResolver, - removeResolver, - takeResolver, - ]; + r = dummy.getPromiseResolver(id); + ok(r === undefined, "takeResolver: get failed"); + next(); + }); + } + ]; - function runTest() { + function next() { if (!tests.length) { SimpleTest.finish(); return; } var test = tests.shift(); test(); } function start() { SimpleTest.waitForExplicitFinish(); - runTest(); + next(); } ]]> </script> <body xmlns="http://www.w3.org/1999/xhtml"> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre>
--- a/dom/imptests/failures/editing/conformancetest/test_runtest.html.json +++ b/dom/imptests/failures/editing/conformancetest/test_runtest.html.json @@ -2881,17 +2881,16 @@ "[[\"defaultparagraphseparator\",\"div\"],[\"forwarddelete\",\"\"]] \"<div>foo[]</div><div>bar</div>\" queryCommandValue(\"defaultparagraphseparator\") after":true, "[[\"defaultparagraphseparator\",\"p\"],[\"forwarddelete\",\"\"]] \"<div>foo[]</div><div>bar</div>\": execCommand(\"defaultparagraphseparator\", false, \"p\") return value":true, "[[\"defaultparagraphseparator\",\"p\"],[\"forwarddelete\",\"\"]] \"<div>foo[]</div><div>bar</div>\" queryCommandValue(\"defaultparagraphseparator\") before":true, "[[\"defaultparagraphseparator\",\"p\"],[\"forwarddelete\",\"\"]] \"<div>foo[]</div><div>bar</div>\" queryCommandValue(\"defaultparagraphseparator\") after":true, "[[\"forwarddelete\",\"\"]] \"<p>foo[]<hr><p>bar\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<p>foo[]</p><br><p>bar</p>\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<p>foo[]</p><br><br><p>bar</p>\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<p>foo[]</p><img src=/img/lion.svg><p>bar\" compare innerHTML":true, - "[[\"forwarddelete\",\"\"]] \"foo[]<img src=/img/lion.svg>bar\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"foo [] \" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"foo []<span> </span> bar\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"foo <span> </span>[] bar\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<b>foo[] </b> bar\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<pre>foo[] bar</pre>\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<div style=white-space:pre>foo[] bar</div>\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<div style=white-space:pre-wrap>foo[] bar</div>\" compare innerHTML":true, "[[\"forwarddelete\",\"\"]] \"<div style=white-space:pre-line>foo [] </div>\" compare innerHTML":true,
--- a/dom/inputmethod/MozKeyboard.js +++ b/dom/inputmethod/MozKeyboard.js @@ -470,17 +470,18 @@ MozInputContext.prototype = { _window: null, _context: null, _contextId: -1, classID: Components.ID("{1e38633d-d08b-4867-9944-afa5c648adb6}"), QueryInterface: XPCOMUtils.generateQI([ Ci.nsIB2GInputContext, - Ci.nsIObserver + Ci.nsIObserver, + Ci.nsISupportsWeakReference ]), classInfo: XPCOMUtils.generateCI({ "classID": Components.ID("{1e38633d-d08b-4867-9944-afa5c648adb6}"), "contractID": "@mozilla.org/b2g-inputcontext;1", "interfaces": [Ci.nsIB2GInputContext], "flags": Ci.nsIClassInfo.DOM_OBJECT, "classDescription": "B2G Input Context"
--- a/dom/phonenumberutils/PhoneNumberService.js +++ b/dom/phonenumberutils/PhoneNumberService.js @@ -86,12 +86,13 @@ PhoneNumberService.prototype = { this.initDOMRequestHelper(aWindow, [ "PhoneNumberService:FuzzyMatch:Return:OK", "PhoneNumberService:FuzzyMatch:Return:KO" ]); }, classID : Components.ID("{e2768710-eb17-11e2-91e2-0800200c9a66}"), contractID : "@mozilla.org/phoneNumberService;1", - QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]), + QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, + Ci.nsISupportsWeakReference]), } this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PhoneNumberService]);
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -539,16 +539,17 @@ var interfaceNamesInGlobalScope = "TextDecoder", "TextEncoder", "TextMetrics", "TimeEvent", "TimeRanges", "Touch", "TouchEvent", "TouchList", + "TrackEvent", "TransitionEvent", {name: "TreeColumn", xbl: true}, {name: "TreeColumns", xbl: true}, {name: "TreeContentView", xbl: true}, {name: "TreeSelection", xbl: true}, "TreeWalker", "UIEvent", "UndoManager",
new file mode 100644 --- /dev/null +++ b/dom/webidl/TrackEvent.webidl @@ -0,0 +1,17 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +[Constructor(DOMString type, optional TrackEventInit eventInitDict)] +interface TrackEvent : Event +{ + readonly attribute TextTrack? track; +}; + +dictionary TrackEventInit : EventInit +{ + TextTrack? track = null; +};
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -543,16 +543,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'DataStoreChangeEvent.webidl', 'DeviceLightEvent.webidl', 'DeviceProximityEvent.webidl', 'ErrorEvent.webidl', 'MediaStreamEvent.webidl', 'MozInterAppMessageEvent.webidl', 'RTCDataChannelEvent.webidl', 'RTCPeerConnectionIceEvent.webidl', + 'TrackEvent.webidl', 'UserProximityEvent.webidl', ] if CONFIG['MOZ_GAMEPAD']: GENERATED_EVENTS_WEBIDL_FILES += [ 'GamepadAxisMoveEvent.webidl', 'GamepadButtonEvent.webidl', 'GamepadEvent.webidl',
--- a/image/test/mochitest/test_bug733553.html +++ b/image/test/mochitest/test_bug733553.html @@ -46,16 +46,17 @@ var testParts = [ // We'll append the part number to this, and tell the informant const BASE_URL = "bug733553-informant.sjs?"; function initializeOnload() { var firstimg = document.createElement('img'); firstimg.addEventListener("load", imageLoad, false); firstimg.addEventListener("error", imageLoad, false); + firstimg.alt = ""; firstimg.src = "bug733553.sjs"; document.getElementById('content').appendChild(firstimg); // Really ready for first, but who's counting readyForNext(); } function readyForNext() {
--- a/image/test/reftest/bmp/bmp-corrupted/wrapper.html +++ b/image/test/reftest/bmp/bmp-corrupted/wrapper.html @@ -15,13 +15,14 @@ </head> <body> <img id="image1"> <script> // Use as "wrapper.html?image.png" var imgURL = document.location.search.substr(1); document.images[0].onload = onImageLoad; document.images[0].onerror = onImageLoad; + document.images[0].alt = ""; document.images[0].src = imgURL; </script> </body> </html>
--- a/image/test/reftest/ico/ico-bmp-corrupted/wrapper.html +++ b/image/test/reftest/ico/ico-bmp-corrupted/wrapper.html @@ -15,13 +15,14 @@ </head> <body> <img id="image1"> <script> // Use as "wrapper.html?image.png var imgURL = document.location.search.substr(1); document.images[0].onload = onImageLoad; document.images[0].onerror = onImageLoad; + document.images[0].alt = ""; document.images[0].src = imgURL; </script> </body> </html>
--- a/image/test/reftest/ico/ico-png/wrapper.html +++ b/image/test/reftest/ico/ico-png/wrapper.html @@ -15,13 +15,14 @@ </head> <body> <img id="image1"> <script> // Use as "wrapper.html?image.png var imgURL = document.location.search.substr(1); document.images[0].onload = onImageLoad; document.images[0].onerror = onImageLoad; + document.images[0].alt = ""; document.images[0].src = imgURL; </script> </body> </html>
--- a/image/test/reftest/pngsuite-corrupted/wrapper.html +++ b/image/test/reftest/pngsuite-corrupted/wrapper.html @@ -15,13 +15,14 @@ </head> <body> <img id="image1"> <script> // Use as "wrapper.html?image.png var imgURL = document.location.search.substr(1); document.images[0].onload = onImageLoad; document.images[0].onerror = onImageLoad; + document.images[0].alt = ""; document.images[0].src = imgURL; </script> </body> </html>
--- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -834,17 +834,17 @@ static bool EmitGetterCall(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher, JSObject *obj, JSObject *holder, HandleShape shape, RegisterSet liveRegs, Register object, Register scratchReg, TypedOrValueRegister output, void *returnAddr) { // saveLive() - masm.PushRegsInMask(liveRegs); + MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs); // Remaining registers should basically be free, but we need to use |object| still // so leave it alone. RegisterSet regSet(RegisterSet::All()); regSet.take(AnyRegister(object)); // This is a slower stub path, and we're going to be doing a call anyway. Don't need // to try so hard to not use the stack. Scratch regs are just taken from the register @@ -885,17 +885,17 @@ EmitGetterCall(JSContext *cx, MacroAssem masm.loadJSContext(argJSContextReg); masm.move32(Imm32(0), argUintNReg); masm.movePtr(StackPointer, argVpReg); // Push marking data for later use. masm.Push(argUintNReg); attacher.pushStubCodePointer(masm); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_NATIVE); // Construct and execute call. masm.setupUnalignedABICall(3, scratchReg); masm.passABIArg(argJSContextReg); masm.passABIArg(argUintNReg); masm.passABIArg(argVpReg); @@ -931,17 +931,17 @@ EmitGetterCall(JSContext *cx, MacroAssem masm.Push(propId, scratchReg); masm.movePtr(StackPointer, argIdReg); masm.Push(object); masm.movePtr(StackPointer, argObjReg); masm.loadJSContext(argJSContextReg); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_PROPERTY_OP); // Make the call. masm.setupUnalignedABICall(4, scratchReg); masm.passABIArg(argJSContextReg); masm.passABIArg(argObjReg); masm.passABIArg(argIdReg); @@ -1287,17 +1287,17 @@ GetPropertyIC::tryAttachTypedArrayLength static bool EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher, PropertyName *name, RegisterSet liveRegs, Register object, TypedOrValueRegister output, void *returnAddr) { JS_ASSERT(output.hasValue()); // saveLive() - masm.PushRegsInMask(liveRegs); + MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs); // Remaining registers should be free, but we need to use |object| still // so leave it alone. RegisterSet regSet(RegisterSet::All()); regSet.take(AnyRegister(object)); // Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, // MutableHandleValue vp) @@ -1324,17 +1324,17 @@ EmitCallProxyGet(JSContext *cx, MacroAss // Pushing object and receiver. Both are the same, so Handle to one is equivalent to // handle to other. masm.Push(object); masm.Push(object); masm.movePtr(StackPointer, argProxyReg); masm.loadJSContext(argJSContextReg); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_PROXY); // Make the call. masm.setupUnalignedABICall(5, scratch); masm.passABIArg(argJSContextReg); masm.passABIArg(argProxyReg); masm.passABIArg(argProxyReg); @@ -2055,17 +2055,17 @@ IsCacheableSetPropCallPropertyOp(HandleO } static bool EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher, HandleId propId, RegisterSet liveRegs, Register object, ConstantOrRegister value, void *returnAddr, bool strict) { // saveLive() - masm.PushRegsInMask(liveRegs); + MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs); // Remaining registers should be free, but we need to use |object| still // so leave it alone. RegisterSet regSet(RegisterSet::All()); regSet.take(AnyRegister(object)); // Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, // bool strict, MutableHandleValue vp) @@ -2093,17 +2093,17 @@ EmitCallProxySet(JSContext *cx, MacroAss // handle to other. masm.Push(object); masm.Push(object); masm.movePtr(StackPointer, argProxyReg); masm.loadJSContext(argJSContextReg); masm.move32(Imm32(strict? 1 : 0), argStrictReg); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_PROXY); // Make the call. masm.setupUnalignedABICall(6, scratch); masm.passABIArg(argJSContextReg); masm.passABIArg(argProxyReg); masm.passABIArg(argProxyReg); @@ -2261,17 +2261,17 @@ GenerateCallSetter(JSContext *cx, IonScr masm.bind(&protoSuccess); masm.pop(scratchReg); } // Good to go for invoking setter. // saveLive() - masm.PushRegsInMask(liveRegs); + MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs); // Remaining registers should basically be free, but we need to use |object| still // so leave it alone. RegisterSet regSet(RegisterSet::All()); regSet.take(AnyRegister(object)); // This is a slower stub path, and we're going to be doing a call anyway. Don't need // to try so hard to not use the stack. Scratch regs are just taken from the register @@ -2314,17 +2314,17 @@ GenerateCallSetter(JSContext *cx, IonScr // Preload other regs masm.loadJSContext(argJSContextReg); masm.move32(Imm32(1), argUintNReg); // Push data for GC marking masm.Push(argUintNReg); attacher.pushStubCodePointer(masm); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_NATIVE); // Make the call masm.setupUnalignedABICall(3, scratchReg); masm.passABIArg(argJSContextReg); masm.passABIArg(argUintNReg); masm.passABIArg(argVpReg); @@ -2357,17 +2357,17 @@ GenerateCallSetter(JSContext *cx, IonScr masm.Push(propId, argIdReg); masm.movePtr(StackPointer, argIdReg); masm.Push(object); masm.movePtr(StackPointer, argObjReg); masm.loadJSContext(argJSContextReg); - if (!masm.buildOOLFakeExitFrame(returnAddr)) + if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic)) return false; masm.enterFakeExitFrame(ION_FRAME_OOL_PROPERTY_OP); // Make the call. masm.setupUnalignedABICall(5, scratchReg); masm.passABIArg(argJSContextReg); masm.passABIArg(argObjReg); masm.passABIArg(argIdReg);
--- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -232,16 +232,31 @@ class MacroAssembler : public MacroAssem sps_(nullptr) { #ifdef JS_CPU_ARM initWithAllocator(); m_buffer.id = 0; #endif } + MacroAssembler(JSContext *cx, IonScript *ion) + : enoughMemory_(true), + embedsNurseryPointers_(false), + sps_(NULL) + { + constructRoot(cx); + ionContext_.construct(cx, (js::jit::TempAllocator *)NULL); + alloc_.construct(cx); +#ifdef JS_CPU_ARM + initWithAllocator(); + m_buffer.id = GetIonContext()->getNextAssemblerId(); +#endif + setFramePushed(ion->frameSize()); + } + void setInstrumentation(IonInstrumentation *sps) { sps_ = sps; } void resetForNewCodeGenerator() { setFramePushed(0); moveResolver_.clearTempObjectPool(); } @@ -1309,16 +1324,36 @@ class MacroAssembler : public MacroAssem return convertConstantOrRegisterToInt(cx, src, temp, output, fail, IntConversion_ClampToUint8); } void clampTypedOrValueToUint8(TypedOrValueRegister src, FloatRegister temp, Register output, Label *fail) { convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8); } + + public: + class AfterICSaveLive { + friend class MacroAssembler; + AfterICSaveLive() + {} + }; + + AfterICSaveLive icSaveLive(RegisterSet &liveRegs) { + PushRegsInMask(liveRegs); + return AfterICSaveLive(); + } + + bool icBuildOOLFakeExitFrame(void *fakeReturnAddr, AfterICSaveLive &aic) { + return buildOOLFakeExitFrame(fakeReturnAddr); + } + + void icRestoreLive(RegisterSet &liveRegs, AfterICSaveLive &aic) { + PopRegsInMask(liveRegs); + } }; static inline Assembler::DoubleCondition JSOpToDoubleCondition(JSOp op) { switch (op) { case JSOP_EQ: case JSOP_STRICTEQ:
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1186,17 +1186,16 @@ class MacroAssemblerARMCompat : public M } void setFramePushed(uint32_t framePushed) { framePushed_ = framePushed; } // Builds an exit frame on the stack, with a return address to an internal // non-function. Returns offset to be passed to markSafepointAt(). bool buildFakeExitFrame(const Register &scratch, uint32_t *offset); - bool buildOOLFakeExitFrame(void *fakeReturnAddr); void callWithExitFrame(IonCode *target); void callWithExitFrame(IonCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // indep code to make a call void callIon(const Register &callee); @@ -1394,16 +1393,19 @@ class MacroAssemblerARMCompat : public M // automatically adjusted. It is extremely important that esp-relative // addresses are computed *after* setupABICall(). Furthermore, no // operations should be emitted while setting arguments. void passABIArg(const MoveOperand &from); void passABIArg(const Register ®); void passABIArg(const FloatRegister ®); void passABIArg(const ValueOperand ®s); + protected: + bool buildOOLFakeExitFrame(void *fakeReturnAddr); + private: void callWithABIPre(uint32_t *stackAdjust); void callWithABIPost(uint32_t stackAdjust, Result result); public: // Emits a call to a C/C++ function, resolving all argument moves. void callWithABI(void *fun, Result result = GENERAL); void callWithABI(AsmJSImmPtr imm, Result result = GENERAL);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -122,17 +122,17 @@ CodeGeneratorShared::addOutOfLineCode(Ou static inline int32_t ToStackIndex(LAllocation *a) { if (a->isStackSlot()) { JS_ASSERT(a->toStackSlot()->slot() >= 1); return a->toStackSlot()->slot(); } JS_ASSERT(-int32_t(sizeof(IonJSFrameLayout)) <= a->toArgument()->index()); - return -(sizeof(IonJSFrameLayout) + a->toArgument()->index()); + return -int32_t(sizeof(IonJSFrameLayout) + a->toArgument()->index()); } bool CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex) { IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u", resumePoint->numOperands(), (void *) resumePoint, *startIndex);
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -633,41 +633,42 @@ class MacroAssemblerX86Shared : public A bind(cl.src()); *offset = currentOffset(); JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size()); return addCodeLabel(cl); } - bool buildOOLFakeExitFrame(void *fakeReturnAddr) { - uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); - Push(Imm32(descriptor)); - Push(ImmPtr(fakeReturnAddr)); - return true; - } - void callWithExitFrame(IonCode *target) { uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); Push(Imm32(descriptor)); call(target); } void callIon(const Register &callee) { call(callee); } void checkStackAlignment() { // Exists for ARM compatibility. } CodeOffsetLabel labelForPatch() { return CodeOffsetLabel(size()); } - + void abiret() { ret(); } + + protected: + bool buildOOLFakeExitFrame(void *fakeReturnAddr) { + uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); + Push(Imm32(descriptor)); + Push(ImmPtr(fakeReturnAddr)); + return true; + } }; } // namespace jit } // namespace js #endif /* jit_shared_MacroAssembler_x86_shared_h */
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -539,17 +539,21 @@ TypeSet::unionSets(TypeSet *a, TypeSet * // // At the end of compilation, when linking the result on the main thread, the // list of compiler constraints are read and converted to type constraints and // attached to the type sets. If the property type sets have changed so that the // assumptions no longer hold then the compilation is aborted and its result // discarded. static LifoAlloc *IonAlloc() { +#ifdef JS_ION return jit::GetIonContext()->temp->lifoAlloc(); +#else + MOZ_CRASH(); +#endif } // Superclass of all constraints generated during Ion compilation. These may // be allocated off the main thread, using the current Ion context's allocator. class types::CompilerConstraint { public: // Property being queried by the compiler. @@ -570,18 +574,22 @@ class types::CompilerConstraint // Generate the type constraint recording the assumption made by this // compilation. Returns true if the assumption originally made still holds. virtual bool generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo) = 0; }; void CompilerConstraintList::add(CompilerConstraint *constraint) { +#ifdef JS_ION if (!constraint || !constraint->expected || !constraints.append(constraint)) setFailed(); +#else + MOZ_CRASH(); +#endif } namespace { template <typename T> class CompilerConstraintInstance : public CompilerConstraint { T data; @@ -667,35 +675,43 @@ TypeObjectKey::newScript() return addendum->asNewScript(); } return NULL; } bool TypeObjectKey::unknownProperties() { +#ifdef JS_ION JSContext *cx = jit::GetIonContext()->cx; TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject(); if (!type) MOZ_CRASH(); return type->unknownProperties(); +#else + MOZ_CRASH(); +#endif } HeapTypeSetKey TypeObjectKey::property(jsid id) { +#ifdef JS_ION JSContext *cx = jit::GetIonContext()->cx; TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject(); if (!type) MOZ_CRASH(); HeapTypeSetKey property; property.actualTypes = type->getProperty(cx, id); if (!property.actualTypes) MOZ_CRASH(); return property; +#else + MOZ_CRASH(); +#endif } bool types::FinishCompilation(JSContext *cx, JSScript *script, jit::ExecutionMode executionMode, CompilerConstraintList *constraints, RecompileInfo *precompileInfo) { if (constraints->failed()) return false; @@ -933,28 +949,32 @@ class ConstraintDataFreezeObjectFlags } }; } /* anonymous namespace */ bool TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags) { +#ifdef JS_ION JS_ASSERT(flags); JSContext *cx = jit::GetIonContext()->cx; TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject(); if (!type) MOZ_CRASH(); if (type->hasAnyFlags(flags)) return true; HeapTypeSetKey objectProperty = property(JSID_EMPTY); constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, flags))); return false; +#else + MOZ_CRASH(); +#endif } void TypeObjectKey::watchStateChange(CompilerConstraintList *constraints) { HeapTypeSetKey objectProperty = property(JSID_EMPTY); constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, 0))); } @@ -1648,21 +1668,25 @@ PrototypeHasIndexedProperty(CompilerCons return false; } bool types::ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, HandleScript script) { +#ifdef JS_ION JSObject *proto = script->global().getOrCreateArrayPrototype(jit::GetIonContext()->cx); if (!proto) return true; return PrototypeHasIndexedProperty(constraints, proto); +#else + MOZ_CRASH(); +#endif } bool types::TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, TemporaryTypeSet *types) { const Class *clasp = types->getKnownClass();
--- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -1397,34 +1397,44 @@ TypeNewScript::writeBarrierPre(TypeNewSc // still hold. bool FinishCompilation(JSContext *cx, JSScript *script, jit::ExecutionMode executionMode, CompilerConstraintList *constraints, RecompileInfo *precompileInfo); class CompilerConstraint; class CompilerConstraintList { +#ifdef JS_ION // Generated constraints. Vector<CompilerConstraint *, 0, jit::IonAllocPolicy> constraints; +#endif // OOM during generation of some constraint. bool failed_; public: CompilerConstraintList() : failed_(false) {} void add(CompilerConstraint *constraint); size_t length() { +#ifdef JS_ION return constraints.length(); +#else + MOZ_CRASH(); +#endif } CompilerConstraint *get(size_t i) { +#ifdef JS_ION return constraints[i]; +#else + MOZ_CRASH(); +#endif } bool failed() { return failed_; } void setFailed() { failed_ = true; }
--- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -20,17 +20,19 @@ #include "jsgc.h" #include "jsmath.h" #include "jsnativestack.h" #include "jsobj.h" #include "jsscript.h" #include "jswatchpoint.h" #include "jswrapper.h" -#include "assembler/assembler/MacroAssembler.h" +#if defined(JS_ION) +# include "assembler/assembler/MacroAssembler.h" +#endif #include "jit/AsmJSSignalHandlers.h" #include "jit/IonCompartment.h" #include "jit/PcScriptCache.h" #include "js/MemoryMetrics.h" #include "yarr/BumpPointerAllocator.h" #include "jscntxtinlines.h" #include "jsgcinlines.h"
--- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -446,54 +446,47 @@ nsImageFrame::ShouldCreateImageFrameFor( } // Check if we want to use a placeholder box with an icon or just // let the presShell make us into inline text. Decide as follows: // // - if our special "force icons" style is set, show an icon // - else if our "do not show placeholders" pref is set, skip the icon // - else: - // - if QuirksMode, and there is no alt attribute, and this is not an - // <object> (which could not possibly have such an attribute), show an - // icon. + // - if there is a src attribute, there is no alt attribute, + // and this is not an <object> (which could not possibly have + // such an attribute), show an icon. // - if QuirksMode, and the IMG has a size show an icon. // - otherwise, skip the icon bool useSizedBox; if (aStyleContext->StyleUIReset()->mForceBrokenImageIcon) { useSizedBox = true; } else if (gIconLoad && gIconLoad->mPrefForceInlineAltText) { useSizedBox = false; } + else if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::src) && + !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::alt) && + !aElement->IsHTML(nsGkAtoms::object) && + !aElement->IsHTML(nsGkAtoms::input)) { + // Use a sized box if we have no alt text. This means no alt attribute + // and the node is not an object or an input (since those always have alt + // text). + useSizedBox = true; + } + else if (aStyleContext->PresContext()->CompatibilityMode() != + eCompatibility_NavQuirks) { + useSizedBox = false; + } else { - if (aStyleContext->PresContext()->CompatibilityMode() != - eCompatibility_NavQuirks) { - useSizedBox = false; - } - else { - // We are in quirks mode, so we can just check the tag name; no need to - // check the namespace. - nsIAtom *localName = aElement->Tag(); + // check whether we have fixed size + useSizedBox = HaveFixedSize(aStyleContext->StylePosition()); + } - // Use a sized box if we have no alt text. This means no alt attribute - // and the node is not an object or an input (since those always have alt - // text). - if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::alt) && - localName != nsGkAtoms::object && - localName != nsGkAtoms::input) { - useSizedBox = true; - } - else { - // check whether we have fixed size - useSizedBox = HaveFixedSize(aStyleContext->StylePosition()); - } - } - } - return useSizedBox; } nsresult nsImageFrame::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData) { if (aType == imgINotificationObserver::SIZE_AVAILABLE) { nsCOMPtr<imgIContainer> image; @@ -715,19 +708,17 @@ nsImageFrame::EnsureIntrinsicSizeAndRati if (mImage) { UpdateIntrinsicSize(mImage); UpdateIntrinsicRatio(mImage); } else { // image request is null or image size not known, probably an // invalid image specified // - make the image big enough for the icon (it may not be // used if inline alt expansion is used instead) - // XXX: we need this in composer, but it is also good for - // XXX: general quirks mode to always have room for the icon - if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) { + if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) { nscoord edgeLengthToUse = nsPresContext::CSSPixelsToAppUnits( ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH))); mIntrinsicSize.width.SetCoordValue(edgeLengthToUse); mIntrinsicSize.height.SetCoordValue(edgeLengthToUse); mIntrinsicRatio.SizeTo(1, 1); } }
--- a/layout/reftests/image/invalid-url-image-1-ref.html +++ b/layout/reftests/image/invalid-url-image-1-ref.html @@ -1,6 +1,7 @@ +<!DOCTYPE html> <html> <body> <img> <input type="image"> </body> </html>
--- a/layout/reftests/image/invalid-url-image-1.html +++ b/layout/reftests/image/invalid-url-image-1.html @@ -1,6 +1,7 @@ +<!DOCTYPE html> <html> <body> - <img src="http://www.foo oo.com"> + <img src="http://www.foo oo.com" alt=""> <input type="image" src="http://www.foo oo.com"> </body> </html>
--- a/memory/jemalloc/moz.build +++ b/memory/jemalloc/moz.build @@ -2,41 +2,41 @@ # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. MODULE = 'jemalloc' CSRCS += [ - 'arena.c', - 'atomic.c', - 'base.c', - 'bitmap.c', - 'chunk.c', - 'chunk_dss.c', - 'chunk_mmap.c', - 'ckh.c', - 'ctl.c', - 'extent.c', - 'hash.c', - 'huge.c', - 'jemalloc.c', - 'mb.c', - 'mutex.c', - 'prof.c', - 'quarantine.c', - 'rtree.c', - 'stats.c', - 'tcache.c', - 'tsd.c', - 'util.c', + 'src/src/arena.c', + 'src/src/atomic.c', + 'src/src/base.c', + 'src/src/bitmap.c', + 'src/src/chunk.c', + 'src/src/chunk_dss.c', + 'src/src/chunk_mmap.c', + 'src/src/ckh.c', + 'src/src/ctl.c', + 'src/src/extent.c', + 'src/src/hash.c', + 'src/src/huge.c', + 'src/src/jemalloc.c', + 'src/src/mb.c', + 'src/src/mutex.c', + 'src/src/prof.c', + 'src/src/quarantine.c', + 'src/src/rtree.c', + 'src/src/stats.c', + 'src/src/tcache.c', + 'src/src/tsd.c', + 'src/src/util.c', ] # Only OSX needs the zone allocation implementation, # but only if replace-malloc is not enabled. if CONFIG['OS_TARGET'] == 'Darwin' and not CONFIG['MOZ_REPLACE_MALLOC']: CSRCS += [ - 'zone.c', + 'src/src/zone.c', ] LIBRARY_NAME = 'jemalloc'
--- a/memory/replace/dmd/Makefile.in +++ b/memory/replace/dmd/Makefile.in @@ -2,20 +2,16 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. FORCE_SHARED_LIB= 1 DEFINES += -DMOZ_NO_MOZALLOC -VPATH += $(topsrcdir)/xpcom/base -VPATH += $(topsrcdir)/nsprpub/lib/libc/src -VPATH += $(topsrcdir)/mfbt - # Disable mozglue. WRAP_LDFLAGS = MOZ_GLUE_LDFLAGS= STL_FLAGS = ifeq ($(OS_ARCH),WINNT) OS_LIBS += $(call EXPAND_LIBNAME,dbghelp)
--- a/memory/replace/dmd/moz.build +++ b/memory/replace/dmd/moz.build @@ -7,18 +7,18 @@ MODULE = 'dmd' EXPORTS += [ 'DMD.h', ] CPP_SOURCES += [ 'DMD.cpp', - 'HashFunctions.cpp', - 'nsStackWalk.cpp', + '../../../mfbt/HashFunctions.cpp', + '../../../xpcom/base/nsStackWalk.cpp', ] CSRCS += [ - 'strcpy.c', + '../../../nsprpub/lib/libc/src/strcpy.c', ] LIBRARY_NAME = 'dmd'
--- a/memory/replace/jemalloc/moz.build +++ b/memory/replace/jemalloc/moz.build @@ -3,18 +3,18 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. MODULE = 'memory' NO_DIST_INSTALL = True CSRCS += [ - 'jemalloc_config.c', - 'mozjemalloc_compat.c', + '../../build/jemalloc_config.c', + '../../build/mozjemalloc_compat.c', ] # Android doesn't have pthread_atfork, so just implement a dummy function. # It shouldn't make much problem, as the use of fork is pretty limited on # Android. if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': CSRCS += [ 'pthread_atfork.c',
--- a/security/sandbox/seccomp_filter.h +++ b/security/sandbox/seccomp_filter.h @@ -65,16 +65,25 @@ ALLOW_ARM_SYSCALL(cacheflush), \ ALLOW_ARM_SYSCALL(usr26), \ ALLOW_ARM_SYSCALL(usr32), \ ALLOW_ARM_SYSCALL(set_tls), #else #define SECCOMP_WHITELIST_ADD_ARM_LAST #endif +/* System calls used by the profiler */ +#ifdef MOZ_PROFILING +#define PROFILING_WHITELIST_ADD \ + ALLOW_SYSCALL(sigaction), \ + ALLOW_SYSCALL(tgkill), +#else +#define PROFILING_WHITELIST_ADD +#endif + /* Syscalls specific to arm that should eventually be removed */ #if defined(__arm__) #define SECCOMP_WHITELIST_REMOVE_ARM \ ALLOW_SYSCALL(fstat64), \ ALLOW_SYSCALL(stat64), \ ALLOW_SYSCALL(sigprocmask), #else #define SECCOMP_WHITELIST_REMOVE_ARM @@ -146,15 +155,16 @@ ALLOW_SYSCALL(prctl), \ ALLOW_SYSCALL(access), \ ALLOW_SYSCALL(getdents64), \ ALLOW_SYSCALL(unlink), \ /* Should remove all of the following in the future, if possible */ \ ALLOW_SYSCALL(getpriority), \ ALLOW_SYSCALL(setpriority), \ ALLOW_SYSCALL(sched_setscheduler), \ + PROFILING_WHITELIST_ADD \ /* Always last and always OK calls */ \ SECCOMP_WHITELIST_ADD_ARM_LAST \ /* restart_syscall is called internally, generally when debugging */ \ ALLOW_SYSCALL(restart_syscall), \ ALLOW_SYSCALL(exit_group), \ ALLOW_SYSCALL(exit)
--- a/uriloader/base/nsIURIContentListener.idl +++ b/uriloader/base/nsIURIContentListener.idl @@ -36,19 +36,21 @@ interface nsIURIContentListener : nsISup * * @param aContentType Content type of the data. * @param aIsContentPreferred Indicates whether the content should be * preferred by this listener. * @param aRequest Request that is providing the data. * @param aContentHandler nsIStreamListener that will consume the data. * This should be set to <code>nullptr</code> if * this content listener can't handle the content - * type. + * type; in this case, doContent should also fail + * (i.e., return failure nsresult). * - * @return <code>true</code> if the consumer wants to + * @return <code>true</code> if the load should + * be aborted and consumer wants to * handle the load completely by itself. This * causes the URI Loader do nothing else... * <code>false</code> if the URI Loader should * continue handling the load and call the * returned streamlistener's methods. */ boolean doContent(in string aContentType, in boolean aIsContentPreferred,