author | Ryan VanderMeulen <ryanvm@gmail.com> |
Thu, 30 Apr 2015 13:56:09 -0400 | |
changeset 241794 | 7723b15ea695e321e6acda04beef9bc98728dd13 |
parent 241709 | 985244566b19fb277fd4fc900eb615e0f01c21d9 (current diff) |
parent 241793 | da60d90cc685bfc079c54cd4abcd1c888c9e843c (diff) |
child 241797 | 4869fe8e1487bc202bd1166c94dc73c8eb01b0db |
child 241849 | 2f1bfe2f725ae198f09f65ecfbcf544bb8a4cb5f |
child 241886 | fe44cfb27e75ac966193b7128024d0939a676af3 |
push id | 28669 |
push user | ryanvm@gmail.com |
push date | Thu, 30 Apr 2015 17:57:05 +0000 |
treeherder | mozilla-central@7723b15ea695 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 40.0a1 |
first release with | nightly linux32
7723b15ea695
/
40.0a1
/
20150501030205
/
files
nightly linux64
7723b15ea695
/
40.0a1
/
20150501030205
/
files
nightly mac
7723b15ea695
/
40.0a1
/
20150501030205
/
files
nightly win32
7723b15ea695
/
40.0a1
/
20150501030205
/
files
nightly win64
7723b15ea695
/
40.0a1
/
20150501030205
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
40.0a1
/
20150501030205
/
pushlog to previous
nightly linux64
40.0a1
/
20150501030205
/
pushlog to previous
nightly mac
40.0a1
/
20150501030205
/
pushlog to previous
nightly win32
40.0a1
/
20150501030205
/
pushlog to previous
nightly win64
40.0a1
/
20150501030205
/
pushlog to previous
|
--- a/CLOBBER +++ b/CLOBBER @@ -17,9 +17,10 @@ # # Modifying this file will now automatically clobber the buildbot machines \o/ # # Are you updating CLOBBER because you think it's needed for your WebIDL # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1154356: escape variable name in Declaration::AppendVariableAndValueToString; +Bug 1159082 - Renaming *Readonly animation interfaces to *ReadOnly causes +build bustage on case-insensitive filesystems.
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -313,16 +313,21 @@ pref("media.cache_size", 4096); // 4M // below 10s of buffered data. pref("media.cache_resume_threshold", 10); pref("media.cache_readahead_limit", 30); #ifdef MOZ_FMP4 // Enable/Disable Gonk Decoder Module pref("media.fragmented-mp4.gonk.enabled", true); #endif + +//Encrypted media extensions. +pref("media.eme.enabled", true); +pref("media.eme.apiVisible", true); + // The default number of decoded video frames that are enqueued in // MediaDecoderReader's mVideoQueue. pref("media.video-queue.default-size", 3); // optimize images' memory usage pref("image.decode-only-on-draw.enabled", false); pref("image.mem.allow_locking_in_content_processes", true); // Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
--- a/browser/base/content/aboutNetError.xhtml +++ b/browser/base/content/aboutNetError.xhtml @@ -459,28 +459,32 @@ <!-- UI for option to report certificate errors to Mozilla. Removed on init for other error types .--> <div id="certificateErrorReporting"> <a id="showCertificateErrorReportingPanel" href="#">&errorReporting.title;<span class="downArrow"> ▼</span></a> </div> <div id="certificateErrorReportingPanel"> - <p>&errorReporting.longDesc;</p> - <p> - <input type="checkbox" id="automaticallyReportInFuture" /> - <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label> - </p> - <a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a> - <span id="reportingState"> - <button id="reportCertificateError">&errorReporting.report;</button> - <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button> - <span id="reportSendingMessage">&errorReporting.sending;</span> - <span id="reportSentMessage">&errorReporting.sent;</span> - </span> + <div id="certificateErrorReportingDescription"> + <p>&errorReporting.longDesc;</p> + <p> + <input type="checkbox" id="automaticallyReportInFuture" /> + <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label> + </p> + </div> + <div id="errorStatePanel"> + <a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a> + <span id="reportingState"> + <button id="reportCertificateError">&errorReporting.report;</button> + <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button> + <span id="reportSendingMessage">&errorReporting.sending;</span> + <span id="reportSentMessage">&errorReporting.sent;</span> + </span> + </div> </div> </div> <!-- - Note: It is important to run the script this way, instead of using - an onload handler. This is because error pages are loaded as - LOAD_BACKGROUND, which means that onload handlers will not be executed.
--- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -23,20 +23,16 @@ key="key_newNavigator" command="cmd_newNavigator"/> <menuitem id="menu_newPrivateWindow" label="&newPrivateWindow.label;" accesskey="&newPrivateWindow.accesskey;" command="Tools:PrivateBrowsing" key="key_privatebrowsing"/> #ifdef E10S_TESTING_ONLY - <menuitem id="menu_newRemoteWindow" - label="New e10s Window" - hidden="true" - command="Tools:RemoteWindow"/> <menuitem id="menu_newNonRemoteWindow" label="New Non-e10s Window" hidden="true" command="Tools:NonRemoteWindow"/> #endif #ifdef MAC_NON_BROWSER_WINDOW <menuitem id="menu_openLocation" label="&openLocationCmd.label;"
--- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -109,18 +109,16 @@ <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/> <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/> <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/> <command id="Tools:Sanitize" oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/> <command id="Tools:PrivateBrowsing" oncommand="OpenBrowserWindow({private: true});" reserved="true"/> #ifdef E10S_TESTING_ONLY - <command id="Tools:RemoteWindow" - oncommand="OpenBrowserWindow({remote: true});"/> <command id="Tools:NonRemoteWindow" oncommand="OpenBrowserWindow({remote: false});"/> #endif <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/> <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/> <command id="Social:SharePage" oncommand="SocialShare.sharePage();"/> <command id="Social:ToggleSidebar" oncommand="SocialSidebar.toggleSidebar();" hidden="true"/> <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -7225,20 +7225,18 @@ let gRemoteTabsUI = { #ifdef XP_MACOSX if (Services.prefs.getBoolPref("layers.acceleration.disabled")) { // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces // a fallback to Basic Layers. This is incompatible with e10s. return; } #endif - let newRemoteWindow = document.getElementById("menu_newRemoteWindow"); let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow"); let autostart = Services.appinfo.browserTabsRemoteAutostart; - newRemoteWindow.hidden = autostart; newNonRemoteWindow.hidden = !autostart; } }; /** * Switch to a tab that has a given URI, and focusses its browser window. * If a matching tab is in this window, it will be switched to. Otherwise, other * windows will be searched.
--- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -203,16 +203,25 @@ let AboutNetErrorListener = { enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"), automatic: automatic }) } )); if (automatic) { this.onSendReport(evt); } + // hide parts of the UI we don't need yet + let contentDoc = content.document; + + let reportSendingMsg = contentDoc.getElementById("reportSendingMessage"); + let reportSentMsg = contentDoc.getElementById("reportSentMessage"); + let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry"); + reportSendingMsg.style.display = "none"; + reportSentMsg.style.display = "none"; + retryBtn.style.display = "none"; }, onSetAutomatic: function(evt) { sendAsyncMessage("Browser:SetSSLErrorReportAuto", { automatic: evt.detail }); }, @@ -229,33 +238,32 @@ let AboutNetErrorListener = { // document - we'll compare on document URI if (contentDoc.documentURI === message.data.documentURI) { switch(message.data.reportStatus) { case "activity": // Hide the button that was just clicked reportBtn.style.display = "none"; retryBtn.style.display = "none"; reportSentMsg.style.display = "none"; - reportSendingMsg.style.display = "inline"; + reportSendingMsg.style.removeProperty("display"); break; case "error": // show the retry button - retryBtn.style.display = "inline"; + retryBtn.style.removeProperty("display"); reportSendingMsg.style.display = "none"; break; case "complete": // Show a success indicator - reportSentMsg.style.display = "inline"; + reportSentMsg.style.removeProperty("display"); reportSendingMsg.style.display = "none"; break; } } }); - let failedChannel = docShell.failedChannel; let location = contentDoc.location.href; let serhelper = Cc["@mozilla.org/network/serialization-helper;1"] .getService(Ci.nsISerializationHelper); let serializable = docShell.failedChannel.securityInfo .QueryInterface(Ci.nsITransportSecurityInfo)
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -526,48 +526,42 @@ <parameter name="aBrowser"/> <parameter name="aMethod"/> <parameter name="aArguments"/> <parameter name="aCallGlobalListeners"/> <parameter name="aCallTabsListeners"/> <body><![CDATA[ var rv = true; - if (!aBrowser) - aBrowser = this.mCurrentBrowser; - - if (aCallGlobalListeners != false && - aBrowser == this.mCurrentBrowser) { - for (let p of this.mProgressListeners) { + function callListeners(listeners, args) { + for (let p of listeners) { if (aMethod in p) { try { - if (!p[aMethod].apply(p, aArguments)) + if (!p[aMethod].apply(p, args)) rv = false; } catch (e) { // don't inhibit other listeners Components.utils.reportError(e); } } } } + if (!aBrowser) + aBrowser = this.mCurrentBrowser; + + if (aCallGlobalListeners != false && + aBrowser == this.mCurrentBrowser) { + callListeners(this.mProgressListeners, aArguments); + } + if (aCallTabsListeners != false) { aArguments.unshift(aBrowser); - for (let p of this.mTabsProgressListeners) { - if (aMethod in p) { - try { - if (!p[aMethod].apply(p, aArguments)) - rv = false; - } catch (e) { - // don't inhibit other listeners - Components.utils.reportError(e); - } - } - } + callListeners(this.mTabsProgressListeners, aArguments); } return rv; ]]></body> </method> <!-- A web progress listener object definition for a given tab. --> <method name="mTabProgressListener"> @@ -1513,23 +1507,21 @@ // keep the old one. Re-set it explicitly after unbinding from DOM. aBrowser._permanentKey = permanentKey; parent.appendChild(aBrowser); // Restore the progress listener. aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL); if (aShouldBeRemote) { - tab.setAttribute("remote", "true"); // Switching the browser to be remote will connect to a new child // process so the browser can no longer be considered to be // crashed. tab.removeAttribute("crashed"); } else { - tab.removeAttribute("remote"); aBrowser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned }) } if (wasActive) aBrowser.focus(); let evt = document.createEvent("Events"); evt.initEvent("TabRemotenessChange", true, false); @@ -1736,18 +1728,16 @@ t.setAttribute("onerror", "this.removeAttribute('image');"); t.className = "tabbrowser-tab"; // The new browser should be remote if this is an e10s window and // the uri to load can be loaded remotely. let remote = gMultiProcessBrowser && !aForceNotRemote && E10SUtils.canLoadURIInProcess(aURI, Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT); - if (remote) - t.setAttribute("remote", "true"); this.tabContainer._unlockTabSizing(); // When overflowing, new tabs are scrolled into view smoothly, which // doesn't go well together with the width transition. So we skip the // transition in that case. let animate = !aSkipAnimation && this.tabContainer.getAttribute("overflow") != "true" && @@ -3680,19 +3670,21 @@ <parameter name="event"/> <body><![CDATA[ event.stopPropagation(); var tab = document.tooltipNode; if (tab.localName != "tab") { event.preventDefault(); return; } - event.target.setAttribute("label", tab.mOverCloseButton ? - tab.getAttribute("closetabtext") : - tab.getAttribute("label")); + event.target.setAttribute("label", + tab.mOverCloseButton ? + tab.getAttribute("closetabtext") : + tab.getAttribute("label") + + (this.AppConstants.E10S_TESTING_ONLY && tab.linkedBrowser && tab.linkedBrowser.isRemoteBrowser ? " - e10s" : "")); ]]></body> </method> <method name="handleEvent"> <parameter name="aEvent"/> <body><![CDATA[ switch (aEvent.type) { case "keydown":
--- a/browser/base/content/test/general/browser_bug623155.js +++ b/browser/base/content/test/general/browser_bug623155.js @@ -110,17 +110,17 @@ function delayed(aIsSelectedTab) { ok(isRedirectedURISpec(content.location.href), "The content area is redirected. aIsSelectedTab:" + aIsSelectedTab); is(gURLBar.value, content.location.href, "The URL bar shows the content URI. aIsSelectedTab:" + aIsSelectedTab); if (!aIsSelectedTab) { // If this was a background request, go on a foreground request. - content.location = REDIRECT_FROM + "#FG"; + gBrowser.selectedBrowser.loadURI(REDIRECT_FROM + "#FG"); } else { // Othrewise, nothing to do remains. finish(); } } /* Cleanup */
--- a/browser/base/content/test/general/browser_e10s_switchbrowser.js +++ b/browser/base/content/test/general/browser_e10s_switchbrowser.js @@ -102,158 +102,158 @@ let forward = Task.async(function*() { gBrowser.goForward(); yield waitForDocLoadComplete(); gExpectedHistory.index++; }); // Tests that navigating from a page that should be in the remote process and // a page that should be in the main process works and retains history add_task(function* test_navigation() { - let expectedRemote = gMultiProcessBrowser ? "true" : ""; + let expectedRemote = gMultiProcessBrowser; info("1"); // Create a tab and load a remote page in it gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true}); let {permanentKey} = gBrowser.selectedBrowser; yield waitForLoad("http://example.org/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); info("2"); // Load another page yield waitForLoad("http://example.com/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("3"); // Load a non-remote page yield waitForLoad("about:robots"); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("4"); // Load a remote page yield waitForLoad("http://example.org/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("5"); yield back(); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("6"); yield back(); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("7"); yield forward(); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("8"); yield forward(); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("9"); yield back(); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("10"); // Load a new remote page, this should replace the last history entry gExpectedHistory.entries.splice(gExpectedHistory.entries.length - 1, 1); yield waitForLoad("http://example.com/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield check_history(); info("11"); gBrowser.removeCurrentTab(); clear_history(); }); // Tests that calling gBrowser.loadURI or browser.loadURI to load a page in a // different process updates the browser synchronously add_task(function* test_synchronous() { - let expectedRemote = gMultiProcessBrowser ? "true" : ""; + let expectedRemote = gMultiProcessBrowser; info("1"); // Create a tab and load a remote page in it gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true}); let {permanentKey} = gBrowser.selectedBrowser; yield waitForLoad("http://example.org/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); info("2"); // Load another page info("Loading about:robots"); gBrowser.selectedBrowser.loadURI("about:robots"); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield waitForDocLoadComplete(); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); info("3"); // Load the remote page again info("Loading http://example.org/" + DUMMY_PATH); gBrowser.loadURI("http://example.org/" + DUMMY_PATH); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); yield waitForDocLoadComplete(); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same"); info("4"); gBrowser.removeCurrentTab(); clear_history(); }); // Tests that load flags are correctly passed through to the child process with // normal loads add_task(function* test_loadflags() { - let expectedRemote = gMultiProcessBrowser ? "true" : ""; + let expectedRemote = gMultiProcessBrowser; info("1"); // Create a tab and load a remote page in it gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true}); yield waitForLoadWithFlags("about:robots"); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); yield check_history(); info("2"); // Load a page in the remote process with some custom flags yield waitForLoadWithFlags("http://example.com/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); yield check_history(); info("3"); // Load a non-remote page yield waitForLoadWithFlags("about:robots"); - is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, false, "Remote attribute should be correct"); yield check_history(); info("4"); // Load another remote page yield waitForLoadWithFlags("http://example.org/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY); - is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct"); + is(gBrowser.selectedBrowser.isRemoteBrowser, expectedRemote, "Remote attribute should be correct"); yield check_history(); is(gExpectedHistory.entries.length, 2, "Should end with the right number of history entries"); info("5"); gBrowser.removeCurrentTab(); clear_history(); });
--- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -1212,45 +1212,31 @@ if (Services.prefs.getBoolPref("browser. }; CustomizableWidgets.push(pocketButton); CustomizableUI.addListener(pocketButton); } } #ifdef E10S_TESTING_ONLY -/** - * The e10s button's purpose is to lower the barrier of entry - * for our Nightly testers to use e10s windows. We'll be removing it - * once remote tabs are enabled. This button should never ever make it - * to production. If it does, that'd be bad, and we should all feel bad. - */ -let getCommandFunction = function(aOpenRemote) { - return function(aEvent) { - let win = aEvent.view; - if (win && typeof win.OpenBrowserWindow == "function") { - win.OpenBrowserWindow({remote: aOpenRemote}); - } - }; -} - -let openRemote = !Services.appinfo.browserTabsRemoteAutostart; -// Like the XUL menuitem counterparts, we hard-code these strings in because -// this button should never roll into production. -let buttonLabel = openRemote ? "New e10s Window" - : "New Non-e10s Window"; - let e10sDisabled = Services.appinfo.inSafeMode; #ifdef XP_MACOSX // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces // a fallback to Basic Layers. This is incompatible with e10s. e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled"); #endif -CustomizableWidgets.push({ - id: "e10s-button", - label: buttonLabel, - tooltiptext: buttonLabel, - disabled: e10sDisabled, - defaultArea: CustomizableUI.AREA_PANEL, - onCommand: getCommandFunction(openRemote), -}); +if (Services.appinfo.browserTabsRemoteAutostart) { + CustomizableWidgets.push({ + id: "e10s-button", + label: "New Non-e10s Window", + tooltiptext: "New Non-e10s Window", + disabled: e10sDisabled, + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(aEvent) { + let win = aEvent.view; + if (win && typeof win.OpenBrowserWindow == "function") { + win.OpenBrowserWindow({remote: false}); + } + }, + }); +} #endif
--- a/browser/themes/shared/aboutNetError.css +++ b/browser/themes/shared/aboutNetError.css @@ -115,38 +115,34 @@ div#certificateErrorReportingPanel { div#certificateErrorReportingPanel:-moz-dir(ltr) { left: 34%; } div#certificateErrorReportingPanel:-moz-dir(rtl) { right: 0; } +#errorStatePanel { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-content: space-between; + align-items: flex-start; +} + span#hostname { font-weight: bold; } #automaticallyReportInFuture { cursor: pointer; } -#reportingState { - padding-left: 150px; -} - #reportSendingMessage { - position: relative; - display: none; + /* adjust the line-height to match the link */ + line-height: 22px; } #reportSentMessage { - position: relative; - display: none; + /* adjust the line-height to match the link */ + line-height: 22px; } - -button#reportCertificateError { - position: relative; -} - -button#reportCertificateErrorRetry { - position: relative; - display: none; -}
--- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -37,20 +37,16 @@ margin: 0; padding: 0; } .tabbrowser-tab { -moz-box-align: stretch; } -.tabbrowser-tab[remote] { - text-decoration: underline; -} - /* The selected tab should appear above adjacent tabs, .tabs-newtab-button and the highlight of #nav-bar */ .tabbrowser-tab[visuallyselected=true] { position: relative; z-index: 2; } .tab-background-middle { -moz-box-flex: 1;
--- a/configure.in +++ b/configure.in @@ -1495,19 +1495,21 @@ if test "$GNU_CC"; then _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs" + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=uninitialized" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas" MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_werror_non_literal_null_conversion) + MOZ_C_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_c_has_sometimes_uninitialized) fi # Turn off the following warnings that -Wall turns on: # -Wno-unused - lots of violations in third-party code # _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused" if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then @@ -1588,19 +1590,21 @@ if test "$GNU_CXX"; then _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=uninitialized" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label" MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_werror_non_literal_null_conversion) + MOZ_CXX_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized) fi # Turn off the following warnings that -Wall turns on: # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc # for performance reasons, and because GCC and clang accept it (though # clang warns about it). # @@ -6903,24 +6907,21 @@ AC_SUBST(MOZ_STACKWALKING) dnl ======================================================== dnl = Disable treating compiler warnings as errors dnl ======================================================== if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then WARNINGS_AS_ERRORS='' elif test "$GNU_CC"; then # Prevent the following GCC warnings from being treated as errors: - # -Wuninitialized - too many false positives # -Wmaybe-uninitialized - too many false positives # -Wdeprecated-declarations - we don't want our builds held hostage when a # platform-specific API becomes deprecated. # -Wfree-nonheap-object - false positives during PGO # -Warray-bounds - false positives depending on optimization - MOZ_C_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_c_has_noerror_uninitialized) - MOZ_CXX_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_cxx_has_noerror_uninitialized) MOZ_C_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_c_has_noerror_maybe_uninitialized) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_cxx_has_noerror_maybe_uninitialized) MOZ_C_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_c_has_noerror_deprecated_declarations) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_cxx_has_noerror_deprecated_declarations) MOZ_C_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_c_has_noerror_array_bounds) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_cxx_has_noerror_array_bounds) if test -n "$MOZ_PGO"; then
--- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -34,17 +34,17 @@ Animation::WrapObject(JSContext* aCx, JS // --------------------------------------------------------------------------- // // Animation interface: // // --------------------------------------------------------------------------- void -Animation::SetEffect(KeyframeEffectReadonly* aEffect) +Animation::SetEffect(KeyframeEffectReadOnly* aEffect) { if (mEffect) { mEffect->SetParentTime(Nullable<TimeDuration>()); } mEffect = aEffect; if (mEffect) { mEffect->SetParentTime(GetCurrentTime()); }
--- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -7,17 +7,17 @@ #define mozilla_dom_Animation_h #include "nsWrapperCache.h" #include "nsCycleCollectionParticipant.h" #include "mozilla/Attributes.h" #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration #include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState #include "mozilla/dom/DocumentTimeline.h" // for DocumentTimeline -#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly +#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadOnly #include "mozilla/dom/Promise.h" // for Promise #include "nsCSSProperty.h" // for nsCSSProperty // X11 has a #define for CurrentTime. #ifdef CurrentTime #undef CurrentTime #endif @@ -81,18 +81,18 @@ public: */ enum class LimitBehavior { AutoRewind, Continue }; // Animation interface methods - KeyframeEffectReadonly* GetEffect() const { return mEffect; } - void SetEffect(KeyframeEffectReadonly* aEffect); + KeyframeEffectReadOnly* GetEffect() const { return mEffect; } + void SetEffect(KeyframeEffectReadOnly* aEffect); DocumentTimeline* Timeline() const { return mTimeline; } Nullable<TimeDuration> GetStartTime() const { return mStartTime; } void SetStartTime(const Nullable<TimeDuration>& aNewStartTime); Nullable<TimeDuration> GetCurrentTime() const; void SetCurrentTime(const TimeDuration& aNewCurrentTime); double PlaybackRate() const { return mPlaybackRate; } void SetPlaybackRate(double aPlaybackRate); AnimationPlayState PlayState() const; @@ -313,17 +313,17 @@ protected: StickyTimeDuration EffectEnd() const; nsIDocument* GetRenderedDocument() const; nsPresContext* GetPresContext() const; virtual css::CommonAnimationManager* GetAnimationManager() const = 0; AnimationCollection* GetCollection() const; nsRefPtr<DocumentTimeline> mTimeline; - nsRefPtr<KeyframeEffectReadonly> mEffect; + nsRefPtr<KeyframeEffectReadOnly> mEffect; // The beginning of the delay period. Nullable<TimeDuration> mStartTime; // Timeline timescale Nullable<TimeDuration> mHoldTime; // Animation timescale Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale double mPlaybackRate; // A Promise that is replaced on each call to Play() (and in future Pause())
rename from dom/animation/AnimationEffectReadonly.cpp rename to dom/animation/AnimationEffectReadOnly.cpp --- a/dom/animation/AnimationEffectReadonly.cpp +++ b/dom/animation/AnimationEffectReadOnly.cpp @@ -1,23 +1,23 @@ /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* 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/AnimationEffectReadonly.h" -#include "mozilla/dom/AnimationEffectReadonlyBinding.h" +#include "mozilla/dom/AnimationEffectReadOnly.h" +#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectReadonly, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectReadOnly, mParent) -NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadonly) -NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadonly) +NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadOnly) +NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadOnly) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadonly) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadOnly) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END } // namespace dom } // namespace mozilla
rename from dom/animation/AnimationEffectReadonly.h rename to dom/animation/AnimationEffectReadOnly.h --- a/dom/animation/AnimationEffectReadonly.h +++ b/dom/animation/AnimationEffectReadOnly.h @@ -9,28 +9,28 @@ #include "nsISupports.h" #include "nsWrapperCache.h" #include "nsCycleCollectionParticipant.h" #include "nsCOMPtr.h" namespace mozilla { namespace dom { -class AnimationEffectReadonly +class AnimationEffectReadOnly : public nsISupports , public nsWrapperCache { protected: - virtual ~AnimationEffectReadonly() { } + virtual ~AnimationEffectReadOnly() { } public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadonly) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadOnly) - explicit AnimationEffectReadonly(nsISupports* aParent) + explicit AnimationEffectReadOnly(nsISupports* aParent) : mParent(aParent) { } nsISupports* GetParentObject() const { return mParent; } protected: nsCOMPtr<nsISupports> mParent;
--- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -54,45 +54,45 @@ ComputedTimingFunction::GetValue(double } // In the Web Animations model, the time fraction can be outside the range // [0.0, 1.0] but it shouldn't be Infinity. const double ComputedTiming::kNullTimeFraction = PositiveInfinity<double>(); namespace dom { -NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadonly, - AnimationEffectReadonly, +NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly, + AnimationEffectReadOnly, mTarget) -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadonly, - AnimationEffectReadonly) +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly, + AnimationEffectReadOnly) NS_IMPL_CYCLE_COLLECTION_TRACE_END -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadonly) -NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadonly) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly) +NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadOnly) -NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadonly, AnimationEffectReadonly) -NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadonly, AnimationEffectReadonly) +NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly) +NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly) JSObject* -KeyframeEffectReadonly::WrapObject(JSContext* aCx, +KeyframeEffectReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { - return KeyframeEffectReadonlyBinding::Wrap(aCx, this, aGivenProto); + return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto); } void -KeyframeEffectReadonly::SetParentTime(Nullable<TimeDuration> aParentTime) +KeyframeEffectReadOnly::SetParentTime(Nullable<TimeDuration> aParentTime) { mParentTime = aParentTime; } ComputedTiming -KeyframeEffectReadonly::GetComputedTimingAt( +KeyframeEffectReadOnly::GetComputedTimingAt( const Nullable<TimeDuration>& aLocalTime, const AnimationTiming& aTiming) { const TimeDuration zeroDuration; // Currently we expect negative durations to be picked up during CSS // parsing but when we start receiving timing parameters from other sources // we will need to clamp negative durations here. @@ -212,99 +212,99 @@ KeyframeEffectReadonly::GetComputedTimin if (thisIterationReverse) { result.mTimeFraction = 1.0 - result.mTimeFraction; } return result; } StickyTimeDuration -KeyframeEffectReadonly::ActiveDuration(const AnimationTiming& aTiming) +KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming) { if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) { // An animation that repeats forever has an infinite active duration // unless its iteration duration is zero, in which case it has a zero // active duration. const StickyTimeDuration zeroDuration; return aTiming.mIterationDuration == zeroDuration ? zeroDuration : StickyTimeDuration::Forever(); } return StickyTimeDuration( aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount)); } // http://w3c.github.io/web-animations/#in-play bool -KeyframeEffectReadonly::IsInPlay(const Animation& aAnimation) const +KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const { if (IsFinishedTransition() || aAnimation.PlayState() == AnimationPlayState::Finished) { return false; } return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase_Active; } // http://w3c.github.io/web-animations/#current bool -KeyframeEffectReadonly::IsCurrent(const Animation& aAnimation) const +KeyframeEffectReadOnly::IsCurrent(const Animation& aAnimation) const { if (IsFinishedTransition() || aAnimation.PlayState() == AnimationPlayState::Finished) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before || computedTiming.mPhase == ComputedTiming::AnimationPhase_Active; } bool -KeyframeEffectReadonly::IsInEffect() const +KeyframeEffectReadOnly::IsInEffect() const { if (IsFinishedTransition()) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction; } const AnimationProperty* -KeyframeEffectReadonly::GetAnimationOfProperty(nsCSSProperty aProperty) const +KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const { for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { if (aProperty == mProperties[propIdx].mProperty) { const AnimationProperty* result = &mProperties[propIdx]; if (!result->mWinsInCascade) { result = nullptr; } return result; } } return nullptr; } bool -KeyframeEffectReadonly::HasAnimationOfProperties( +KeyframeEffectReadOnly::HasAnimationOfProperties( const nsCSSProperty* aProperties, size_t aPropertyCount) const { for (size_t i = 0; i < aPropertyCount; i++) { if (HasAnimationOfProperty(aProperties[i])) { return true; } } return false; } void -KeyframeEffectReadonly::ComposeStyle( +KeyframeEffectReadOnly::ComposeStyle( nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, nsCSSPropertySet& aSetProperties) { ComputedTiming computedTiming = GetComputedTiming(); // If the time fraction is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mTimeFraction == ComputedTiming::kNullTimeFraction) {
--- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -10,17 +10,17 @@ #include "nsCycleCollectionParticipant.h" #include "nsCSSPseudoElements.h" #include "nsIDocument.h" #include "nsWrapperCache.h" #include "mozilla/Attributes.h" #include "mozilla/StickyTimeDuration.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/TimeStamp.h" -#include "mozilla/dom/AnimationEffectReadonly.h" +#include "mozilla/dom/AnimationEffectReadOnly.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Nullable.h" #include "nsSMILKeySpline.h" #include "nsStyleStruct.h" // for nsTimingFunction struct JSContext; class nsCSSPropertySet; @@ -180,47 +180,47 @@ struct AnimationProperty return !(*this == aOther); } }; struct ElementPropertyTransition; namespace dom { -class KeyframeEffectReadonly : public AnimationEffectReadonly +class KeyframeEffectReadOnly : public AnimationEffectReadOnly { public: - KeyframeEffectReadonly(nsIDocument* aDocument, + KeyframeEffectReadOnly(nsIDocument* aDocument, Element* aTarget, nsCSSPseudoElements::Type aPseudoType, const AnimationTiming &aTiming, const nsSubstring& aName) - : AnimationEffectReadonly(aDocument) + : AnimationEffectReadOnly(aDocument) , mTarget(aTarget) , mTiming(aTiming) , mName(aName) , mIsFinishedTransition(false) , mPseudoType(aPseudoType) { MOZ_ASSERT(aTarget, "null animation target is not yet supported"); } NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadonly, - AnimationEffectReadonly) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly, + AnimationEffectReadOnly) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual ElementPropertyTransition* AsTransition() { return nullptr; } virtual const ElementPropertyTransition* AsTransition() const { return nullptr; } - // KeyframeEffectReadonly interface + // KeyframeEffectReadOnly interface Element* GetTarget() const { // Currently we only implement Element.getAnimations() which only // returns animations targetting Elements so this should never // be called for an animation that targets a pseudo-element. MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement, "Requesting the target of a KeyframeEffect that targets a" " pseudo-element is not yet supported."); return mTarget; @@ -327,17 +327,17 @@ public: // Updates |aStyleRule| with the animation values produced by this // Animation for the current time except any properties already contained // in |aSetProperties|. // Any updated properties are added to |aSetProperties|. void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, nsCSSPropertySet& aSetProperties); protected: - virtual ~KeyframeEffectReadonly() { } + virtual ~KeyframeEffectReadOnly() { } nsCOMPtr<Element> mTarget; Nullable<TimeDuration> mParentTime; AnimationTiming mTiming; nsString mName; // A flag to mark transitions that have finished and are due to // be removed on the next throttle-able cycle.
--- a/dom/animation/moz.build +++ b/dom/animation/moz.build @@ -4,30 +4,30 @@ # 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/. MOCHITEST_MANIFESTS += ['test/mochitest.ini'] MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] EXPORTS.mozilla.dom += [ 'Animation.h', - 'AnimationEffectReadonly.h', + 'AnimationEffectReadOnly.h', 'AnimationTimeline.h', 'DocumentTimeline.h', 'KeyframeEffect.h', ] EXPORTS.mozilla += [ 'AnimationUtils.h', 'PendingAnimationTracker.h', ] UNIFIED_SOURCES += [ 'Animation.cpp', - 'AnimationEffectReadonly.cpp', + 'AnimationEffectReadOnly.cpp', 'AnimationTimeline.cpp', 'DocumentTimeline.cpp', 'KeyframeEffect.cpp', 'PendingAnimationTracker.cpp', ] FAIL_ON_WARNINGS = True
--- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -340,17 +340,17 @@ void nsMutationReceiver::NodeWillBeDestr NS_ASSERTION(!mParent, "Shouldn't have mParent here!"); Disconnect(true); } void nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation, AnimationMutation aMutationType) { - KeyframeEffectReadonly* effect = aAnimation->GetEffect(); + KeyframeEffectReadOnly* effect = aAnimation->GetEffect(); if (!effect) { return; } Element* animationTarget = effect->GetTarget(); if (!animationTarget) { return; }
--- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -213,17 +213,17 @@ nsNodeUtils::ContentRemoved(nsINode* aCo IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer, (document, container, aChild, aIndexInContainer, aPreviousSibling)); } static inline Element* GetTarget(Animation* aAnimation) { - KeyframeEffectReadonly* effect = aAnimation->GetEffect(); + KeyframeEffectReadOnly* effect = aAnimation->GetEffect(); if (!effect) { return nullptr; } Element* target; nsCSSPseudoElements::Type pseudoType; effect->GetTarget(target, pseudoType);
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -83,17 +83,17 @@ DOMInterfaces = { 'MozAbortablePromise': { 'nativeType': 'mozilla::dom::AbortablePromise', }, 'AbstractWorker': { 'concrete': False }, -'AnimationEffectReadonly': { +'AnimationEffectReadOnly': { 'concrete': False }, 'AnimationTimeline': { 'concrete': False }, 'AnonymousContent': {
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the public domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Bug 1097479 - Allow embed remote apps or widgets in content +// process if nested-oop is enabled + +"use strict"; + +SimpleTest.waitForExplicitFinish(); +browserElementTestHelpers.setEnabledPref(true); +browserElementTestHelpers.addPermission(); + +SpecialPowers.setAllAppsLaunchable(true); + +function runTest() { + var iframe = document.createElement('iframe'); + iframe.setAttribute('mozbrowser', 'true'); + iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { + is(e.detail.message == 'app', true, e.detail.message); + SimpleTest.finish(); + }); + + document.body.appendChild(iframe); + + var context = { 'url': 'http://example.org', + 'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID, + 'isInBrowserElement': true }; + SpecialPowers.pushPermissions([ + {'type': 'browser', 'allow': 1, 'context': context}, + {'type': 'embed-apps', 'allow': 1, 'context': context} + ], function() { + iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AllowEmbedAppsInNestedOOIframe.html'; + }); +} + +addEventListener('testready', () => { + SpecialPowers.pushPrefEnv({"set": [["dom.ipc.tabs.nested.enabled", true]]}, runTest); +});
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/file_browserElement_AllowEmbedAppsInNestedOOIframe.html @@ -0,0 +1,19 @@ +<html> +<head> +<script type="text/javascript"> + addEventListener('load', function(e) { + var iframe = document.createElement('iframe'); + iframe.setAttribute('mozbrowser', 'true'); + iframe.setAttribute('remote', 'true'); + iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp'); + iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { + alert(e.detail.message); + }); + document.body.appendChild(iframe); + iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AppFramePermission.html'; + }); +</script> +</head> +<body> +</body> +</html>
--- a/dom/browser-element/mochitest/mochitest-oop.ini +++ b/dom/browser-element/mochitest/mochitest-oop.ini @@ -11,16 +11,18 @@ support-files = [test_browserElement_oop_ThemeColor.html] [test_browserElement_inproc_ErrorSecurity.html] skip-if = toolkit=='gonk' [test_browserElement_inproc_OpenMixedProcess.html] skip-if = toolkit=='gonk' || (toolkit == 'gonk' && !debug) [test_browserElement_oop_Alert.html] [test_browserElement_oop_AlertInFrame.html] +[test_browserElement_oop_AllowEmbedAppsInNestedOOIframe.html] +skip-if = toolkit=='gonk' [test_browserElement_oop_AppFramePermission.html] skip-if = (toolkit == 'gonk' && !debug) [test_browserElement_oop_AppWindowNamespace.html] skip-if = (toolkit == 'gonk' && !debug) [test_browserElement_oop_Auth.html] skip-if = (toolkit == 'gonk' && !debug) [test_browserElement_oop_BackForward.html] [test_browserElement_oop_BadScreenshot.html]
--- a/dom/browser-element/mochitest/mochitest.ini +++ b/dom/browser-element/mochitest/mochitest.ini @@ -1,16 +1,17 @@ [DEFAULT] skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s support-files = ../../../browser/base/content/test/general/audio.ogg ../../../dom/media/test/short-video.ogv browserElementTestHelpers.js browserElement_Alert.js browserElement_AlertInFrame.js + browserElement_AllowEmbedAppsInNestedOOIframe.js browserElement_AppFramePermission.js browserElement_AppWindowNamespace.js browserElement_Auth.js browserElement_BackForward.js browserElement_BadScreenshot.js browserElement_ThemeColor.js browserElement_BrowserWindowNamespace.js browserElement_BrowserWindowResize.js @@ -68,16 +69,17 @@ support-files = browserElement_XFrameOptions.js browserElement_XFrameOptionsAllowFrom.js browserElement_XFrameOptionsDeny.js browserElement_XFrameOptionsSameOrigin.js browserElement_XFrameOptionsSameOrigin.js browserElement_GetContentDimensions.js file_browserElement_AlertInFrame.html file_browserElement_AlertInFrame_Inner.html + file_browserElement_AllowEmbedAppsInNestedOOIframe.html file_browserElement_AppFramePermission.html file_browserElement_AppWindowNamespace.html file_browserElement_ThemeColor.html file_browserElement_BrowserWindowNamespace.html file_browserElement_CloseApp.html file_browserElement_CloseFromOpener.html file_browserElement_CookiesNotThirdParty.html file_browserElement_DisallowEmbedAppsInOOP.html
new file mode 100644 --- /dev/null +++ b/dom/browser-element/mochitest/test_browserElement_oop_AllowEmbedAppsInNestedOOIframe.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 1097479</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="browserElementTestHelpers.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script type="application/javascript;version=1.7" src="browserElement_AllowEmbedAppsInNestedOOIframe.js"> +</script> +</body> +</html>
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -632,16 +632,20 @@ public: dom::ImageData* pixels, ErrorResult& rv); // Allow whatever element types the bindings are willing to pass // us in TexSubImage2D template<class ElementType> void TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, ElementType& elt, ErrorResult& rv) { + // TODO: Consolidate all the parameter validation + // checks. Instead of spreading out the cheks in multple + // places, consolidate into one spot. + if (IsContextLost()) return; if (!ValidateTexImageTarget(rawTexImageTarget, WebGLTexImageFunc::TexSubImage, WebGLTexDimensions::Tex2D)) { ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget); @@ -1303,17 +1307,17 @@ protected: // If jsArrayType is MaxTypedArrayViewType, it means no array. void TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border, GLenum format, GLenum type, void* data, uint32_t byteLength, js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat, bool srcPremultiplied); - void TexSubImage2D_base(TexImageTarget texImageTarget, GLint level, + void TexSubImage2D_base(GLenum texImageTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLenum format, GLenum type, void* pixels, uint32_t byteLength, js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat, bool srcPremultiplied); void TexParameter_base(GLenum target, GLenum pname, GLint* const out_intParam,
--- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -3418,30 +3418,35 @@ WebGLContext::TexImage2D(GLenum rawTarge return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(), pixels->Height(), 4*pixels->Width(), 0, format, type, pixelData, pixelDataLength, js::Scalar::MaxTypedArrayViewType, WebGLTexelFormat::RGBA8, false); } void -WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level, +WebGLContext::TexSubImage2D_base(GLenum rawImageTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLenum format, GLenum type, void* data, uint32_t byteLength, js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat, bool srcPremultiplied) { const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage; const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D; if (type == LOCAL_GL_HALF_FLOAT_OES) type = LOCAL_GL_HALF_FLOAT; + if (!ValidateTexImageTarget(rawImageTarget, func, dims)) + return; + + TexImageTarget texImageTarget(rawImageTarget); + WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget); if (!tex) return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit"); if (!tex->HasImageInfoAt(texImageTarget, level)) return ErrorInvalidOperation("texSubImage2D: no previously defined texture image"); const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
--- a/dom/canvas/WebGLElementArrayCache.cpp +++ b/dom/canvas/WebGLElementArrayCache.cpp @@ -14,17 +14,20 @@ #include "mozilla/MemoryReporting.h" namespace mozilla { static void UpdateUpperBound(uint32_t* const out_upperBound, uint32_t newBound) { MOZ_ASSERT(out_upperBound); - *out_upperBound = std::max(*out_upperBound, newBound); + // Move *out_upperBound to a local variable to work around a false positive + // -Wuninitialized gcc warning about std::max() in PGO builds. + uint32_t upperBound = *out_upperBound; + *out_upperBound = std::max(upperBound, newBound); } /* WebGLElementArrayCacheTree contains most of the implementation of * WebGLElementArrayCache, which performs WebGL element array buffer validation * for drawElements. * * Attention: Here lie nontrivial data structures, bug-prone algorithms, and * non-canonical tweaks! Whence the explanatory comments, and compiled unit
--- a/dom/canvas/compiledtest/TestWebGLElementArrayCache.cpp +++ b/dom/canvas/compiledtest/TestWebGLElementArrayCache.cpp @@ -110,17 +110,17 @@ void CheckValidateAllTypes(WebGLElementA template<typename T> void CheckSanity() { const size_t numElems = 64; // should be significantly larger than tree leaf size to // ensure we exercise some nontrivial tree-walking T data[numElems] = {1,0,3,1,2,6,5,4}; // intentionally specify only 8 elements for now size_t numBytes = numElems * sizeof(T); - MOZ_ASSERT(numBytes == sizeof(data)); + MOZ_RELEASE_ASSERT(numBytes == sizeof(data)); GLenum type = GLType<T>(); WebGLElementArrayCache c; c.BufferData(data, numBytes); CheckValidate(true, c, type, 6, 0, 8); CheckValidate(false, c, type, 5, 0, 8); CheckValidate(true, c, type, 3, 0, 3); @@ -134,34 +134,34 @@ CheckSanity() // now test a somewhat larger size to ensure we exceed the size of a tree leaf for(size_t i = 0; i < numElems; i++) data[i] = numElems - i; c.BufferData(data, numBytes); CheckValidate(true, c, type, numElems, 0, numElems); CheckValidate(false, c, type, numElems - 1, 0, numElems); - MOZ_ASSERT(numElems > 10); + MOZ_RELEASE_ASSERT(numElems > 10); CheckValidate(true, c, type, numElems - 10, 10, numElems - 10); CheckValidate(false, c, type, numElems - 11, 10, numElems - 10); } template<typename T> void CheckUintOverflow() { // This test is only for integer types smaller than uint32_t static_assert(sizeof(T) < sizeof(uint32_t), "This test is only for integer types \ smaller than uint32_t"); const size_t numElems = 64; // should be significantly larger than tree leaf size to // ensure we exercise some nontrivial tree-walking T data[numElems]; size_t numBytes = numElems * sizeof(T); - MOZ_ASSERT(numBytes == sizeof(data)); + MOZ_RELEASE_ASSERT(numBytes == sizeof(data)); GLenum type = GLType<T>(); WebGLElementArrayCache c; for(size_t i = 0; i < numElems; i++) data[i] = numElems - i; c.BufferData(data, numBytes);
--- a/dom/fetch/Response.h +++ b/dom/fetch/Response.h @@ -72,16 +72,22 @@ public: } InternalHeaders* GetInternalHeaders() const { return mInternalResponse->Headers(); } + const nsCString& + GetSecurityInfo() const + { + return mInternalResponse->GetSecurityInfo(); + } + Headers* Headers_(); void GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); } static already_AddRefed<Response> Error(const GlobalObject& aGlobal);
--- a/dom/html/nsGenericHTMLFrameElement.cpp +++ b/dom/html/nsGenericHTMLFrameElement.cpp @@ -474,16 +474,30 @@ bool WidgetsEnabled() sBoolVarCacheInitialized = true; Preferences::AddBoolVarCache(&sMozWidgetsEnabled, "dom.enable_widgets"); } return sMozWidgetsEnabled; } +bool NestedEnabled() +{ + static bool sMozNestedEnabled = false; + static bool sBoolVarCacheInitialized = false; + + if (!sBoolVarCacheInitialized) { + sBoolVarCacheInitialized = true; + Preferences::AddBoolVarCache(&sMozNestedEnabled, + "dom.ipc.tabs.nested.enabled"); + } + + return sMozNestedEnabled; +} + } // anonymous namespace /* [infallible] */ NS_IMETHODIMP nsGenericHTMLFrameElement::GetReallyIsWidget(bool *aOut) { *aOut = false; if (!WidgetsEnabled()) { return NS_OK; @@ -576,18 +590,22 @@ nsGenericHTMLFrameElement::GetAppManifes { aOut.Truncate(); // At the moment, you can't be an app without being a browser. if (!nsIMozBrowserFrame::GetReallyIsBrowserOrApp()) { return NS_OK; } - if (XRE_GetProcessType() != GeckoProcessType_Default) { - NS_WARNING("Can't embed-apps. Embed-apps is restricted to in-proc apps, see bug 1059662"); + // Only allow content process to embed an app when nested content + // process is enabled. + if (XRE_GetProcessType() != GeckoProcessType_Default && + !(GetBoolAttr(nsGkAtoms::Remote) && NestedEnabled())){ + NS_WARNING("Can't embed-apps. Embed-apps is restricted to in-proc apps " + "or content processes with nested pref enabled, see bug 1097479"); return NS_OK; } nsAutoString appManifestURL; nsAutoString widgetManifestURL; GetManifestURLByType(nsGkAtoms::mozapp, appManifestURL);
--- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -8,24 +8,26 @@ #include "mozilla/dom/MediaKeySystemAccessBinding.h" #include "mozilla/Preferences.h" #include "nsContentTypeParser.h" #ifdef MOZ_FMP4 #include "MP4Decoder.h" #endif #ifdef XP_WIN #include "mozilla/WindowsVersion.h" +#include "WMFDecoderModule.h" #endif #include "nsContentCID.h" #include "nsServiceManagerUtils.h" #include "mozIGeckoMediaPluginService.h" #include "VideoUtils.h" #include "mozilla/Services.h" #include "nsIObserverService.h" #include "mozilla/EMEUtils.h" +#include "GMPUtils.h" namespace mozilla { namespace dom { NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess) NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess) @@ -154,16 +156,23 @@ MediaKeySystemAccess::GetKeySystemStatus aKeySystem.EqualsLiteral("com.adobe.primetime"))) { // Win Vista and later only. if (!IsVistaOrLater()) { return MediaKeySystemStatus::Cdm_not_supported; } if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) { return MediaKeySystemStatus::Cdm_disabled; } + if ((!WMFDecoderModule::HasH264() || !WMFDecoderModule::HasAAC()) || + !EMEVoucherFileExists()) { + // The system doesn't have the codecs that Adobe EME relies + // on installed, or doesn't have a voucher for the plugin-container. + // Adobe EME isn't going to work, so don't advertise that it will. + return MediaKeySystemStatus::Cdm_not_supported; + } return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, true); } #endif return MediaKeySystemStatus::Cdm_not_supported; } static bool
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp @@ -389,17 +389,17 @@ GonkVideoDecoderManager::Output(int64_t if (mDecoder->UpdateOutputBuffers()) { return Output(aStreamOffset, aOutData); } GVDM_LOG("Fails to update output buffers!"); return NS_ERROR_FAILURE; } case -EAGAIN: { - GVDM_LOG("Need to try again!"); +// GVDM_LOG("Need to try again!"); return NS_ERROR_NOT_AVAILABLE; } case android::ERROR_END_OF_STREAM: { GVDM_LOG("Got the EOS frame!"); nsRefPtr<VideoData> data; nsresult rv = CreateVideoData(aStreamOffset, getter_AddRefs(data)); if (rv == NS_ERROR_NOT_AVAILABLE) { @@ -487,29 +487,34 @@ GonkVideoDecoderManager::Flush() } void GonkVideoDecoderManager::codecReserved() { GVDM_LOG("codecReserved"); sp<AMessage> format = new AMessage; sp<Surface> surface; - + status_t rv = OK; // Fixed values GVDM_LOG("Configure mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight); format->setString("mime", mMimeType.get()); format->setInt32("width", mVideoWidth); format->setInt32("height", mVideoHeight); if (mNativeWindow != nullptr) { surface = new Surface(mNativeWindow->getBufferQueue()); } mDecoder->configure(format, surface, nullptr, 0); mDecoder->Prepare(); - status_t rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG); + + if (mMimeType.EqualsLiteral("video/mp4v-es")) { + rv = mDecoder->Input(mCodecSpecificData->Elements(), + mCodecSpecificData->Length(), 0, + android::MediaCodec::BUFFER_FLAG_CODECCONFIG); + } + if (rv != OK) { GVDM_LOG("Failed to configure codec!!!!"); mReaderCallback->Error(); } } void GonkVideoDecoderManager::codecCanceled()
copy from dom/media/gmp-plugin/Makefile.in copy to dom/media/gmp-plugin-openh264/Makefile.in --- a/dom/media/gmp-plugin/Makefile.in +++ b/dom/media/gmp-plugin-openh264/Makefile.in @@ -1,13 +1,12 @@ # # 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/. -INSTALL_TARGETS += FAKE_GMP_PLUGIN -FAKE_GMP_PLUGIN_DEST = $(DEPTH)/dist/bin/gmp-fake/1.0 -FAKE_GMP_PLUGIN_FILES = \ - $(SHARED_LIBRARY) \ - $(srcdir)/fake.info \ - $(srcdir)/fake.voucher +INSTALL_TARGETS += FAKE_GMP_OPENH264_PLUGIN +FAKE_GMP_OPENH264_PLUGIN_DEST = $(DEPTH)/dist/bin/gmp-fakeopenh264/1.0 +FAKE_GMP_OPENH264_PLUGIN_FILES = \ + $(srcdir)/fakeopenh264.info \ + $(srcdir)/fakeopenh264.voucher \ + $(NULL) -include $(topsrcdir)/config/rules.mk
copy from dom/media/gmp-plugin/fake.info copy to dom/media/gmp-plugin-openh264/fakeopenh264.info --- a/dom/media/gmp-plugin/fake.info +++ b/dom/media/gmp-plugin-openh264/fakeopenh264.info @@ -1,5 +1,4 @@ -Name: fake +Name: fakeopenh264 Description: Fake GMP Plugin Version: 1.0 -APIs: encode-video[h264], decode-video[h264], eme-decrypt-v7[fake] -Libraries: dxva2.dll +APIs: encode-video[h264], decode-video[h264]
copy from dom/media/gmp-plugin/fake.voucher copy to dom/media/gmp-plugin-openh264/fakeopenh264.voucher --- a/dom/media/gmp-plugin/fake.voucher +++ b/dom/media/gmp-plugin-openh264/fakeopenh264.voucher @@ -1,1 +1,1 @@ -gmp-fake placeholder voucher \ No newline at end of file +gmp-fakeopenh264 placeholder voucher
copy from dom/media/gmp-plugin/moz.build copy to dom/media/gmp-plugin-openh264/moz.build --- a/dom/media/gmp-plugin/moz.build +++ b/dom/media/gmp-plugin-openh264/moz.build @@ -1,22 +1,22 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # 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/. -NO_DIST_INSTALL = True +# largely a copy of dom/media/gmp-fake/moz.build + +FINAL_TARGET = 'dist/bin/gmp-fakeopenh264/1.0' SOURCES += [ - 'gmp-fake.cpp', - 'gmp-test-decryptor.cpp', - 'gmp-test-storage.cpp', + '../gmp-plugin/gmp-fake.cpp', ] -SharedLibrary("fake") +SharedLibrary("fakeopenh264") if CONFIG['OS_ARCH'] == 'WINNT': OS_LIBS += [ 'ole32', ] USE_STATIC_LIBS = True NO_VISIBILITY_FLAGS = True
--- a/dom/media/gmp-plugin/fake.info +++ b/dom/media/gmp-plugin/fake.info @@ -1,5 +1,5 @@ Name: fake Description: Fake GMP Plugin Version: 1.0 -APIs: encode-video[h264], decode-video[h264], eme-decrypt-v7[fake] +APIs: encode-video[h264:fake], decode-video[h264:fake], eme-decrypt-v7[fake] Libraries: dxva2.dll
--- a/dom/media/gmp-plugin/gmp-fake.cpp +++ b/dom/media/gmp-plugin/gmp-fake.cpp @@ -44,20 +44,22 @@ #include <limits.h> #include "gmp-platform.h" #include "gmp-video-host.h" #include "gmp-video-encode.h" #include "gmp-video-decode.h" #include "gmp-video-frame-i420.h" #include "gmp-video-frame-encoded.h" + +#if defined(GMP_FAKE_SUPPORT_DECRYPT) #include "gmp-decryption.h" - #include "gmp-test-decryptor.h" #include "gmp-test-storage.h" +#endif #if defined(_MSC_VER) #define PUBLIC_FUNC __declspec(dllexport) #else #define PUBLIC_FUNC #endif #define BIG_FRAME 10000 @@ -402,22 +404,24 @@ extern "C" { PUBLIC_FUNC GMPErr GMPGetAPI (const char* aApiName, void* aHostAPI, void** aPluginApi) { if (!strcmp (aApiName, GMP_API_VIDEO_DECODER)) { *aPluginApi = new FakeVideoDecoder (static_cast<GMPVideoHost*> (aHostAPI)); return GMPNoErr; } else if (!strcmp (aApiName, GMP_API_VIDEO_ENCODER)) { *aPluginApi = new FakeVideoEncoder (static_cast<GMPVideoHost*> (aHostAPI)); return GMPNoErr; +#if defined(GMP_FAKE_SUPPORT_DECRYPT) } else if (!strcmp (aApiName, GMP_API_DECRYPTOR)) { *aPluginApi = new FakeDecryptor(static_cast<GMPDecryptorHost*> (aHostAPI)); return GMPNoErr; } else if (!strcmp (aApiName, GMP_API_ASYNC_SHUTDOWN)) { *aPluginApi = new TestAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI)); return GMPNoErr; +#endif } return GMPGenericErr; } PUBLIC_FUNC void GMPShutdown (void) { g_platform_api = NULL; }
--- a/dom/media/gmp-plugin/moz.build +++ b/dom/media/gmp-plugin/moz.build @@ -6,16 +6,18 @@ NO_DIST_INSTALL = True SOURCES += [ 'gmp-fake.cpp', 'gmp-test-decryptor.cpp', 'gmp-test-storage.cpp', ] +DEFINES['GMP_FAKE_SUPPORT_DECRYPT'] = True + SharedLibrary("fake") if CONFIG['OS_ARCH'] == 'WINNT': OS_LIBS += [ 'ole32', ] USE_STATIC_LIBS = True
--- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -50,16 +50,17 @@ extern PRLogModuleInfo* GetGMPLog(); namespace gmp { GMPParent::GMPParent() : mState(GMPStateNotLoaded) , mProcess(nullptr) , mDeleteProcessOnlyOnUnload(false) , mAbnormalShutdownInProgress(false) , mIsBlockingDeletion(false) + , mCanDecrypt(false) , mGMPContentChildCount(0) , mAsyncShutdownRequired(false) , mAsyncShutdownInProgress(false) #ifdef PR_LOGGING , mChildPid(0) #endif { LOGD("GMPParent ctor"); @@ -751,41 +752,50 @@ GMPParent::ReadGMPMetaData() nsCCharSeparatedTokenizer tagTokens(ts, ':'); while (tagTokens.hasMoreTokens()) { const nsDependentCSubstring tag(tagTokens.nextToken()); cap->mAPITags.AppendElement(tag); } } } + if (cap->mAPIName.EqualsLiteral(GMP_API_DECRYPTOR) || + cap->mAPIName.EqualsLiteral(GMP_API_DECRYPTOR_COMPAT)) { + mCanDecrypt = true; + #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX) - if (cap->mAPIName.EqualsLiteral(GMP_API_DECRYPTOR) && - !mozilla::SandboxInfo::Get().CanSandboxMedia()) { - printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM" - " but this system can't sandbox it; not loading.\n", - mDisplayName.get()); - delete cap; - return NS_ERROR_FAILURE; + if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) { + printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM" + " but this system can't sandbox it; not loading.\n", + mDisplayName.get()); + delete cap; + return NS_ERROR_FAILURE; + } +#endif } -#endif mCapabilities.AppendElement(cap); } if (mCapabilities.IsEmpty()) { return NS_ERROR_FAILURE; } return NS_OK; } bool GMPParent::CanBeSharedCrossNodeIds() const { - return mNodeId.IsEmpty(); + return mNodeId.IsEmpty() && + // XXX bug 1159300 hack -- maybe remove after openh264 1.4 + // We don't want to use CDM decoders for non-encrypted playback + // just yet; especially not for WebRTC. Don't allow CDMs to be used + // without a node ID. + !mCanDecrypt; } bool GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const { return (mNodeId.IsEmpty() && State() == GMPStateNotLoaded) || mNodeId == aNodeId; }
--- a/dom/media/gmp/GMPParent.h +++ b/dom/media/gmp/GMPParent.h @@ -194,16 +194,18 @@ private: nsCString mVersion; nsCString mPluginId; nsTArray<nsAutoPtr<GMPCapability>> mCapabilities; GMPProcessParent* mProcess; bool mDeleteProcessOnlyOnUnload; bool mAbnormalShutdownInProgress; bool mIsBlockingDeletion; + bool mCanDecrypt; + nsTArray<nsRefPtr<GMPTimerParent>> mTimers; nsTArray<nsRefPtr<GMPStorageParent>> mStorage; nsCOMPtr<nsIThread> mGMPThread; nsCOMPtr<nsITimer> mAsyncShutdownTimeout; // GMP Thread only. // NodeId the plugin is assigned to, or empty if the the plugin is not // assigned to a NodeId. nsAutoCString mNodeId; // This is used for GMP content in the parent, there may be more of these in
--- a/dom/media/gmp/GMPProcessParent.cpp +++ b/dom/media/gmp/GMPProcessParent.cpp @@ -1,17 +1,16 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: sw=2 ts=2 et : * 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 "GMPProcessParent.h" -#include "nsDirectoryServiceDefs.h" -#include "nsIFile.h" +#include "GMPUtils.h" #include "base/string_util.h" #include "base/process_util.h" #include <string> using std::vector; using std::string; @@ -40,25 +39,23 @@ GMPProcessParent::GMPProcessParent(const GMPProcessParent::~GMPProcessParent() { MOZ_COUNT_DTOR(GMPProcessParent); } bool GMPProcessParent::Launch(int32_t aTimeoutMs) { - nsCOMPtr<nsIFile> greDir; - NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir)); - if (!greDir) { - NS_WARNING("GMPProcessParent can't get NS_GRE_DIR"); + nsCOMPtr<nsIFile> path; + if (!GetEMEVoucherPath(getter_AddRefs(path))) { + NS_WARNING("GMPProcessParent can't get EME voucher path!"); return false; } - greDir->AppendNative(NS_LITERAL_CSTRING("voucher.bin")); nsAutoCString voucherPath; - greDir->GetNativePath(voucherPath); + path->GetNativePath(voucherPath); vector<string> args; args.push_back(mGMPPath); args.push_back(string(voucherPath.BeginReading(), voucherPath.EndReading())); #if defined(XP_WIN) && defined(MOZ_SANDBOX) std::wstring wGMPPath = UTF8ToWide(mGMPPath.c_str()); mAllowedFilesRead.push_back(wGMPPath + L"\\*");
--- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -668,31 +668,33 @@ GeckoMediaPluginServiceParent::ClonePlug MutexAutoLock lock(mMutex); mPlugins.AppendElement(gmp); return gmp.get(); } class NotifyObserversTask final : public nsRunnable { public: - explicit NotifyObserversTask(const char* aTopic) + explicit NotifyObserversTask(const char* aTopic, nsString aData = EmptyString()) : mTopic(aTopic) + , mData(aData) {} NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); MOZ_ASSERT(obsService); if (obsService) { - obsService->NotifyObservers(nullptr, mTopic, nullptr); + obsService->NotifyObservers(nullptr, mTopic, mData.get()); } return NS_OK; } private: ~NotifyObserversTask() {} const char* mTopic; + const nsString mData; }; void GeckoMediaPluginServiceParent::AddOnGMPThread(const nsAString& aDirectory) { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get())); @@ -732,46 +734,62 @@ GeckoMediaPluginServiceParent::RemoveOnG LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get())); nsCOMPtr<nsIFile> directory; nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } + // Plugin destruction can modify |mPlugins|. Put them aside for now and + // destroy them once we're done with |mPlugins|. + nsTArray<nsRefPtr<GMPParent>> deadPlugins; + + bool inUse = false; MutexAutoLock lock(mMutex); for (size_t i = mPlugins.Length() - 1; i < mPlugins.Length(); i--) { nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory(); bool equals; if (NS_FAILED(directory->Equals(pluginpath, &equals)) || !equals) { continue; } nsRefPtr<GMPParent> gmp = mPlugins[i]; if (aDeleteFromDisk && gmp->State() != GMPStateNotLoaded) { // We have to wait for the child process to release its lib handle // before we can delete the GMP. + inUse = true; gmp->MarkForDeletion(); if (!mPluginsWaitingForDeletion.Contains(aDirectory)) { mPluginsWaitingForDeletion.AppendElement(aDirectory); } } if (gmp->State() == GMPStateNotLoaded || !aCanDefer) { // GMP not in use or shutdown is being forced; can shut it down now. - gmp->AbortAsyncShutdown(); - gmp->CloseActive(true); + deadPlugins.AppendElement(gmp); mPlugins.RemoveElementAt(i); } } - if (aDeleteFromDisk) { + { + MutexAutoUnlock unlock(mMutex); + for (auto& gmp : deadPlugins) { + gmp->AbortAsyncShutdown(); + gmp->CloseActive(true); + } + } + + if (aDeleteFromDisk && !inUse) { if (NS_SUCCEEDED(directory->Remove(true))) { mPluginsWaitingForDeletion.RemoveElement(aDirectory); + NS_DispatchToMainThread(new NotifyObserversTask("gmp-directory-deleted", + nsString(aDirectory)), + NS_DISPATCH_NORMAL); } } } // May remove when Bug 1043671 is fixed static void Dummy(nsRefPtr<GMPParent>& aOnDeathsDoor) { // exists solely to do nothing and let the Runnable kill the GMPParent
new file mode 100644 --- /dev/null +++ b/dom/media/gmp/GMPUtils.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "GMPUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIFile.h" +#include "nsCOMPtr.h" + +namespace mozilla { + +bool +GetEMEVoucherPath(nsIFile** aPath) +{ + nsCOMPtr<nsIFile> path; + NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(path)); + if (!path) { + NS_WARNING("GetEMEVoucherPath can't get NS_GRE_DIR!"); + return false; + } + path->AppendNative(NS_LITERAL_CSTRING("voucher.bin")); + path.forget(aPath); + return true; +} + +bool +EMEVoucherFileExists() +{ + nsCOMPtr<nsIFile> path; + bool exists; + return GetEMEVoucherPath(getter_AddRefs(path)) && + NS_SUCCEEDED(path->Exists(&exists)) && + exists; +} + +} // namespace mozilla
--- a/dom/media/gmp/GMPUtils.h +++ b/dom/media/gmp/GMPUtils.h @@ -16,11 +16,15 @@ struct DestroyPolicy void operator()(T* aGMPObject) const { aGMPObject->Destroy(); } }; template<typename T> using GMPUniquePtr = mozilla::UniquePtr<T, DestroyPolicy<T>>; +bool GetEMEVoucherPath(nsIFile** aPath); + +bool EMEVoucherFileExists(); + } // namespace mozilla #endif
--- a/dom/media/gmp/moz.build +++ b/dom/media/gmp/moz.build @@ -93,16 +93,17 @@ UNIFIED_SOURCES += [ 'GMPService.cpp', 'GMPServiceChild.cpp', 'GMPServiceParent.cpp', 'GMPSharedMemManager.cpp', 'GMPStorageChild.cpp', 'GMPStorageParent.cpp', 'GMPTimerChild.cpp', 'GMPTimerParent.cpp', + 'GMPUtils.cpp', 'GMPVideoDecoderChild.cpp', 'GMPVideoDecoderParent.cpp', 'GMPVideoEncodedFrameImpl.cpp', 'GMPVideoEncoderChild.cpp', 'GMPVideoEncoderParent.cpp', 'GMPVideoHost.cpp', 'GMPVideoi420FrameImpl.cpp', 'GMPVideoPlaneImpl.cpp',
new file mode 100644 --- /dev/null +++ b/dom/media/gtest/GMPTestMonitor.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "nsThreadUtils.h" + +#ifndef __GMPTestMonitor_h__ +#define __GMPTestMonitor_h__ + +class GMPTestMonitor +{ +public: + GMPTestMonitor() + : mFinished(false) + { + } + + void AwaitFinished() + { + MOZ_ASSERT(NS_IsMainThread()); + while (!mFinished) { + NS_ProcessNextEvent(nullptr, true); + } + mFinished = false; + } + +private: + void MarkFinished() + { + mFinished = true; + } + +public: + void SetFinished() + { + NS_DispatchToMainThread(NS_NewNonOwningRunnableMethod(this, + &GMPTestMonitor::MarkFinished)); + } + +private: + bool mFinished; +}; + +#endif // __GMPTestMonitor_h__
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -3,16 +3,17 @@ /* 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 "gtest/gtest.h" #include "nsIObserverService.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" +#include "GMPTestMonitor.h" #include "GMPVideoDecoderProxy.h" #include "GMPVideoEncoderProxy.h" #include "GMPDecryptorProxy.h" #include "GMPServiceParent.h" #include "nsAppDirectoryServiceDefs.h" #include "nsIFile.h" #include "nsISimpleEnumerator.h" #include "mozilla/Atomics.h" @@ -23,50 +24,16 @@ #include "mozilla/WindowsVersion.h" #endif using namespace std; using namespace mozilla; using namespace mozilla::gmp; -class GMPTestMonitor -{ -public: - GMPTestMonitor() - : mFinished(false) - { - } - - void AwaitFinished() - { - MOZ_ASSERT(NS_IsMainThread()); - while (!mFinished) { - NS_ProcessNextEvent(nullptr, true); - } - mFinished = false; - } - -private: - void MarkFinished() - { - mFinished = true; - } - -public: - void SetFinished() - { - NS_DispatchToMainThread(NS_NewNonOwningRunnableMethod(this, - &GMPTestMonitor::MarkFinished)); - } - -private: - bool mFinished; -}; - struct GMPTestRunner { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPTestRunner) void DoTest(void (GMPTestRunner::*aTestMethod)(GMPTestMonitor&)); void RunTestGMPTestCodec1(GMPTestMonitor& aMonitor); void RunTestGMPTestCodec2(GMPTestMonitor& aMonitor); void RunTestGMPTestCodec3(GMPTestMonitor& aMonitor);
new file mode 100644 --- /dev/null +++ b/dom/media/gtest/TestGMPRemoveAndDelete.cpp @@ -0,0 +1,449 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "GMPService.h" +#include "GMPTestMonitor.h" +#include "gmp-api/gmp-video-host.h" +#include "gtest/gtest.h" +#include "mozilla/Services.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIObserverService.h" + +#define GMP_DIR_NAME NS_LITERAL_STRING("gmp-fake") +#define GMP_OLD_VERSION NS_LITERAL_STRING("1.0") +#define GMP_NEW_VERSION NS_LITERAL_STRING("1.1") + +#define GMP_DELETED_TOPIC "gmp-directory-deleted" + +#define EXPECT_OK(X) EXPECT_TRUE(NS_SUCCEEDED(X)) + +class GMPRemoveTest : public nsIObserver + , public GMPVideoDecoderCallbackProxy +{ +public: + GMPRemoveTest(); + + NS_DECL_THREADSAFE_ISUPPORTS + + // Called when a GMP plugin directory has been successfully deleted. + // |aData| will contain the directory path. + NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) override; + + // Create a new GMP plugin directory that we can trash and add it to the GMP + // service. Remove the original plugin directory. Original plugin directory + // gets re-added at destruction. + void Setup(); + + bool CreateVideoDecoder(nsCString aNodeId = EmptyCString()); + void CloseVideoDecoder(); + + void DeletePluginDirectory(bool aCanDefer); + + // Decode a dummy frame. + GMPErr Decode(); + + // Wait until TestMonitor has been signaled. + void Wait(); + + // Did we get a Terminated() callback from the plugin? + bool IsTerminated(); + + // From GMPVideoDecoderCallbackProxy + // Set mDecodeResult; unblock TestMonitor. + virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override; + virtual void Error(GMPErr aError) override; + + // From GMPVideoDecoderCallbackProxy + // We expect this to be called when a plugin has been forcibly closed. + virtual void Terminated() override; + + // Ignored GMPVideoDecoderCallbackProxy members + virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override {} + virtual void ReceivedDecodedFrame(const uint64_t aPictureId) override {} + virtual void InputDataExhausted() override {} + virtual void DrainComplete() override {} + virtual void ResetComplete() override {} + +private: + virtual ~GMPRemoveTest(); + + void gmp_Decode(); + void gmp_GetVideoDecoder(nsCString aNodeId, + GMPVideoDecoderProxy** aOutDecoder, + GMPVideoHost** aOutHost); + void GeneratePlugin(); + + GMPTestMonitor mTestMonitor; + nsCOMPtr<nsIThread> mGMPThread; + + bool mIsTerminated; + + // Path to the cloned GMP we have created. + nsString mTmpPath; + nsCOMPtr<nsIFile> mTmpDir; + + // Path to the original GMP. Store so that we can re-add it after we're done + // testing. + nsString mOriginalPath; + + GMPVideoDecoderProxy* mDecoder; + GMPVideoHost* mHost; + GMPErr mDecodeResult; +}; + +/* + * Simple test that the plugin is deleted when forcibly removed and deleted. + */ +TEST(GeckoMediaPlugins, RemoveAndDeleteForcedSimple) +{ + nsRefPtr<GMPRemoveTest> test(new GMPRemoveTest()); + + test->Setup(); + test->DeletePluginDirectory(false /* force immediate */); + test->Wait(); +} + +/* + * Simple test that the plugin is deleted when deferred deletion is allowed. + */ +TEST(GeckoMediaPlugins, RemoveAndDeleteDeferredSimple) +{ + nsRefPtr<GMPRemoveTest> test(new GMPRemoveTest()); + + test->Setup(); + test->DeletePluginDirectory(true /* can defer */); + test->Wait(); +} + +/* + * Test that the plugin is unavailable immediately after a forced + * RemoveAndDelete, and that the plugin is deleted afterwards. + */ +TEST(GeckoMediaPlugins, RemoveAndDeleteForcedInUse) +{ + nsRefPtr<GMPRemoveTest> test(new GMPRemoveTest()); + + test->Setup(); + EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin"))); + + // Test that we can decode a frame. + GMPErr err = test->Decode(); + EXPECT_EQ(err, GMPNoErr); + + test->DeletePluginDirectory(false /* force immediate */); + test->Wait(); + + // Test that the VideoDecoder is no longer available. + EXPECT_FALSE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin"))); + + // Test that we were notified of the plugin's destruction. + EXPECT_TRUE(test->IsTerminated()); +} + +/* + * Test that the plugin is still usable after a deferred RemoveAndDelete, and + * that the plugin is deleted afterwards. + */ +TEST(GeckoMediaPlugins, RemoveAndDeleteDeferredInUse) +{ + nsRefPtr<GMPRemoveTest> test(new GMPRemoveTest()); + + test->Setup(); + EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin"))); + + // Make sure decoding works before we do anything. + GMPErr err = test->Decode(); + EXPECT_EQ(err, GMPNoErr); + + test->DeletePluginDirectory(true /* can defer */); + + // Test that decoding still works. + err = test->Decode(); + EXPECT_EQ(err, GMPNoErr); + + // Test that this origin is still able to fetch the video decoder. + EXPECT_TRUE(test->CreateVideoDecoder(NS_LITERAL_CSTRING("thisOrigin"))); + + test->CloseVideoDecoder(); + test->Wait(); +} + +static StaticRefPtr<GeckoMediaPluginService> gService; +static StaticRefPtr<GeckoMediaPluginServiceParent> gServiceParent; + +static GeckoMediaPluginService* +GetService() +{ + if (!gService) { + nsRefPtr<GeckoMediaPluginService> service = + GeckoMediaPluginService::GetGeckoMediaPluginService(); + gService = service; + } + + return gService.get(); +} + +static GeckoMediaPluginServiceParent* +GetServiceParent() +{ + if (!gServiceParent) { + nsRefPtr<GeckoMediaPluginServiceParent> parent = + GeckoMediaPluginServiceParent::GetSingleton(); + gServiceParent = parent; + } + + return gServiceParent.get(); +} + +NS_IMPL_ISUPPORTS(GMPRemoveTest, nsIObserver) + +GMPRemoveTest::GMPRemoveTest() + : mIsTerminated(false) + , mDecoder(nullptr) + , mHost(nullptr) +{ +} + +GMPRemoveTest::~GMPRemoveTest() +{ + bool exists; + EXPECT_TRUE(NS_SUCCEEDED(mTmpDir->Exists(&exists)) && !exists); + + EXPECT_OK(GetServiceParent()->AddPluginDirectory(mOriginalPath)); +} + +void +GMPRemoveTest::Setup() +{ + GeneratePlugin(); + EXPECT_OK(GetServiceParent()->RemovePluginDirectory(mOriginalPath)); + + GetServiceParent()->AddPluginDirectory(mTmpPath); + + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + obs->AddObserver(this, GMP_DELETED_TOPIC, false /* strong ref */); + + GetService()->GetThread(getter_AddRefs(mGMPThread)); +} + +bool +GMPRemoveTest::CreateVideoDecoder(nsCString aNodeId) +{ + GMPVideoHost* host; + GMPVideoDecoderProxy* decoder = nullptr; + + mGMPThread->Dispatch( + NS_NewNonOwningRunnableMethodWithArgs<nsCString, GMPVideoDecoderProxy**, GMPVideoHost**>( + this, &GMPRemoveTest::gmp_GetVideoDecoder, aNodeId, &decoder, &host), + NS_DISPATCH_NORMAL); + + mTestMonitor.AwaitFinished(); + + if (!decoder) { + return false; + } + + GMPVideoCodec codec; + memset(&codec, 0, sizeof(codec)); + codec.mGMPApiVersion = 33; + + nsTArray<uint8_t> empty; + mGMPThread->Dispatch( + NS_NewNonOwningRunnableMethodWithArgs<const GMPVideoCodec&, const nsTArray<uint8_t>&, GMPVideoDecoderCallbackProxy*, int32_t>( + decoder, &GMPVideoDecoderProxy::InitDecode, + codec, empty, this, 1 /* core count */), + NS_DISPATCH_SYNC); + + if (mDecoder) { + CloseVideoDecoder(); + } + + mDecoder = decoder; + mHost = host; + + return true; +} + +void +GMPRemoveTest::gmp_GetVideoDecoder(nsCString aNodeId, + GMPVideoDecoderProxy** aOutDecoder, + GMPVideoHost** aOutHost) +{ + nsTArray<nsCString> tags; + tags.AppendElement(NS_LITERAL_CSTRING("h264")); + tags.AppendElement(NS_LITERAL_CSTRING("fake")); + + class Callback : public GetGMPVideoDecoderCallback + { + public: + Callback(GMPTestMonitor* aMonitor, GMPVideoDecoderProxy** aDecoder, GMPVideoHost** aHost) + : mMonitor(aMonitor), mDecoder(aDecoder), mHost(aHost) { } + virtual void Done(GMPVideoDecoderProxy* aDecoder, GMPVideoHost* aHost) override { + *mDecoder = aDecoder; + *mHost = aHost; + mMonitor->SetFinished(); + } + private: + GMPTestMonitor* mMonitor; + GMPVideoDecoderProxy** mDecoder; + GMPVideoHost** mHost; + }; + + UniquePtr<GetGMPVideoDecoderCallback> + cb(new Callback(&mTestMonitor, aOutDecoder, aOutHost)); + + if (NS_FAILED(GetService()->GetGMPVideoDecoder(&tags, aNodeId, Move(cb)))) { + mTestMonitor.SetFinished(); + } +} + +void +GMPRemoveTest::CloseVideoDecoder() +{ + mGMPThread->Dispatch( + NS_NewNonOwningRunnableMethod(mDecoder, &GMPVideoDecoderProxy::Close), + NS_DISPATCH_SYNC); + + mDecoder = nullptr; + mHost = nullptr; +} + +void +GMPRemoveTest::DeletePluginDirectory(bool aCanDefer) +{ + GetServiceParent()->RemoveAndDeletePluginDirectory(mTmpPath, aCanDefer); +} + +GMPErr +GMPRemoveTest::Decode() +{ + mGMPThread->Dispatch( + NS_NewNonOwningRunnableMethod(this, &GMPRemoveTest::gmp_Decode), + NS_DISPATCH_NORMAL); + + mTestMonitor.AwaitFinished(); + return mDecodeResult; +} + +void +GMPRemoveTest::gmp_Decode() +{ + // from gmp-fake.cpp + struct EncodedFrame { + uint32_t length_; + uint8_t h264_compat_; + uint32_t magic_; + uint32_t width_; + uint32_t height_; + uint8_t y_; + uint8_t u_; + uint8_t v_; + uint32_t timestamp_; + }; + + GMPVideoFrame* absFrame; + GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &absFrame); + EXPECT_EQ(err, GMPNoErr); + + GMPUniquePtr<GMPVideoEncodedFrame> + frame(static_cast<GMPVideoEncodedFrame*>(absFrame)); + err = frame->CreateEmptyFrame(sizeof(EncodedFrame) /* size */); + EXPECT_EQ(err, GMPNoErr); + + EncodedFrame* frameData = reinterpret_cast<EncodedFrame*>(frame->Buffer()); + frameData->magic_ = 0x4652414d; + frameData->width_ = frameData->height_ = 16; + + nsTArray<uint8_t> empty; + nsresult rv = mDecoder->Decode(Move(frame), false /* aMissingFrames */, empty); + EXPECT_OK(rv); +} + +void +GMPRemoveTest::Wait() +{ + mTestMonitor.AwaitFinished(); +} + +bool +GMPRemoveTest::IsTerminated() +{ + return mIsTerminated; +} + +// nsIObserver +NS_IMETHODIMP +GMPRemoveTest::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + EXPECT_TRUE(!strcmp(GMP_DELETED_TOPIC, aTopic)); + + nsString data(aData); + if (mTmpPath.Equals(data)) { + mTestMonitor.SetFinished(); + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + obs->RemoveObserver(this, GMP_DELETED_TOPIC); + } + + return NS_OK; +} + +// GMPVideoDecoderCallbackProxy +void +GMPRemoveTest::Decoded(GMPVideoi420Frame* aDecodedFrame) +{ + aDecodedFrame->Destroy(); + mDecodeResult = GMPNoErr; + mTestMonitor.SetFinished(); +} + +// GMPVideoDecoderCallbackProxy +void +GMPRemoveTest::Error(GMPErr aError) +{ + mDecodeResult = aError; + mTestMonitor.SetFinished(); +} + +// GMPVideoDecoderCallbackProxy +void +GMPRemoveTest::Terminated() +{ + mIsTerminated = true; +} + +void +GMPRemoveTest::GeneratePlugin() +{ + nsresult rv; + nsCOMPtr<nsIFile> gmpDir; + nsCOMPtr<nsIFile> origDir; + nsCOMPtr<nsIFile> tmpDir; + + rv = NS_GetSpecialDirectory(NS_GRE_DIR, + getter_AddRefs(gmpDir)); + EXPECT_OK(rv); + rv = gmpDir->Append(GMP_DIR_NAME); + EXPECT_OK(rv); + + rv = gmpDir->Clone(getter_AddRefs(origDir)); + EXPECT_OK(rv); + rv = origDir->Append(GMP_OLD_VERSION); + EXPECT_OK(rv); + + rv = origDir->CopyTo(gmpDir, GMP_NEW_VERSION); + EXPECT_OK(rv); + + rv = gmpDir->Clone(getter_AddRefs(tmpDir)); + EXPECT_OK(rv); + rv = tmpDir->Append(GMP_NEW_VERSION); + EXPECT_OK(rv); + + EXPECT_OK(origDir->GetPath(mOriginalPath)); + EXPECT_OK(tmpDir->GetPath(mTmpPath)); + mTmpDir = tmpDir; +}
--- a/dom/media/gtest/moz.build +++ b/dom/media/gtest/moz.build @@ -3,16 +3,17 @@ # 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/. UNIFIED_SOURCES += [ 'MockMediaResource.cpp', 'TestAudioCompactor.cpp', 'TestGMPCrossOrigin.cpp', + 'TestGMPRemoveAndDelete.cpp', 'TestMP4Demuxer.cpp', 'TestMP4Reader.cpp', 'TestTrackEncoder.cpp', 'TestVideoSegment.cpp', 'TestWebMBuffered.cpp', ] if CONFIG['MOZ_EME']:
--- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -18,16 +18,17 @@ with Files('RTC*'): component_av = ('Core', 'WebRTC: Audio/Video') with Files('GetUserMedia*'): BUG_COMPONENT = component_av DIRS += [ 'encoder', 'gmp', 'gmp-plugin', + 'gmp-plugin-openh264', 'imagecapture', 'mediasource', 'ogg', 'systemservices', 'webaudio', 'webrtc', 'webspeech', 'webvtt',
--- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1541,17 +1541,17 @@ PeerConnectionWrapper.prototype = { * A promise that resolves when we're receiving the tone from |from|. */ checkReceivingToneFrom : function(from) { var inputElem = from.localMediaElements[0]; // As input we use the stream of |from|'s first available audio sender. var inputSenderTracks = from._pc.getSenders().map(sn => sn.track); var inputAudioStream = from._pc.getLocalStreams() - .find(s => s.getAudioTracks().some(t => inputSenderTracks.includes(t))); + .find(s => s.getAudioTracks().some(t => inputSenderTracks.some(t2 => t == t2))); var inputAnalyser = new AudioStreamAnalyser(inputAudioStream); // It would have been nice to have a working getReceivers() here, but until // we do, let's use what remote streams we have. var outputAudioStream = this._pc.getRemoteStreams() .find(s => s.getAudioTracks().length > 0); var outputAnalyser = new AudioStreamAnalyser(outputAudioStream);
--- a/dom/media/webaudio/AnalyserNode.cpp +++ b/dom/media/webaudio/AnalyserNode.cpp @@ -11,19 +11,19 @@ #include "mozilla/Mutex.h" #include "mozilla/PodOperations.h" namespace mozilla { namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode) -class AnalyserNodeEngine : public AudioNodeEngine +class AnalyserNodeEngine final : public AudioNodeEngine { - class TransferBuffer : public nsRunnable + class TransferBuffer final : public nsRunnable { public: TransferBuffer(AudioNodeStream* aStream, const AudioChunk& aChunk) : mStream(aStream) , mChunk(aChunk) { }
--- a/dom/media/webaudio/AnalyserNode.h +++ b/dom/media/webaudio/AnalyserNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "FFTBlock.h" namespace mozilla { namespace dom { class AudioContext; -class AnalyserNode : public AudioNode +class AnalyserNode final : public AudioNode { public: explicit AnalyserNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -48,21 +48,21 @@ NS_IMPL_ADDREF_INHERITED(AudioBufferSour NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioNode) /** * Media-thread playback engine for AudioBufferSourceNode. * Nothing is played until a non-null buffer has been set (via * AudioNodeStream::SetBuffer) and a non-zero mBufferEnd has been set (via * AudioNodeStream::SetInt32Parameter). */ -class AudioBufferSourceNodeEngine : public AudioNodeEngine +class AudioBufferSourceNodeEngine final : public AudioNodeEngine { public: - explicit AudioBufferSourceNodeEngine(AudioNode* aNode, - AudioDestinationNode* aDestination) : + AudioBufferSourceNodeEngine(AudioNode* aNode, + AudioDestinationNode* aDestination) : AudioNodeEngine(aNode), mStart(0.0), mBeginProcessing(0), mStop(STREAM_TIME_MAX), mResampler(nullptr), mRemainingResamplerTail(0), mBufferEnd(0), mLoopStart(0), mLoopEnd(0), mBufferSampleRate(0), mBufferPosition(0), mChannels(0), mDopplerShift(1.0f), @@ -708,22 +708,22 @@ AudioBufferSourceNode::Stop(double aWhen ns->SetStreamTimeParameter(STOP, Context(), std::max(0.0, aWhen)); } void AudioBufferSourceNode::NotifyMainThreadStateChanged() { if (mStream->IsFinished()) { - class EndedEventDispatcher : public nsRunnable + class EndedEventDispatcher final : public nsRunnable { public: explicit EndedEventDispatcher(AudioBufferSourceNode* aNode) : mNode(aNode) {} - NS_IMETHODIMP Run() + NS_IMETHODIMP Run() override { // If it's not safe to run scripts right now, schedule this to run later if (!nsContentUtils::IsSafeToRunScript()) { nsContentUtils::AddScriptRunner(this); return NS_OK; } mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
--- a/dom/media/webaudio/AudioBufferSourceNode.h +++ b/dom/media/webaudio/AudioBufferSourceNode.h @@ -10,18 +10,18 @@ #include "AudioNode.h" #include "AudioBuffer.h" namespace mozilla { namespace dom { class AudioParam; -class AudioBufferSourceNode : public AudioNode, - public MainThreadMediaStreamListener +class AudioBufferSourceNode final : public AudioNode, + public MainThreadMediaStreamListener { public: explicit AudioBufferSourceNode(AudioContext* aContext); virtual void DestroyMediaStream() override { if (mStream) { mStream->RemoveMainThreadListener(this);
--- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -25,17 +25,17 @@ #include "nsWidgetsCID.h" #include "mozilla/dom/Promise.h" namespace mozilla { namespace dom { static uint8_t gWebAudioOutputKey; -class OfflineDestinationNodeEngine : public AudioNodeEngine +class OfflineDestinationNodeEngine final : public AudioNodeEngine { public: typedef AutoFallibleTArray<nsAutoArrayPtr<float>, 2> InputChannels; OfflineDestinationNodeEngine(AudioDestinationNode* aNode, uint32_t aNumberOfChannels, uint32_t aLength, float aSampleRate) @@ -130,17 +130,17 @@ public: class OnCompleteTask final : public nsRunnable { public: OnCompleteTask(AudioContext* aAudioContext, AudioBuffer* aRenderedBuffer) : mAudioContext(aAudioContext) , mRenderedBuffer(aRenderedBuffer) {} - NS_IMETHOD Run() + NS_IMETHOD Run() override { nsRefPtr<OfflineAudioCompletionEvent> event = new OfflineAudioCompletionEvent(mAudioContext, nullptr, nullptr); event->InitEvent(mRenderedBuffer); mAudioContext->DispatchTrustedEvent(event); return NS_OK; } @@ -205,27 +205,27 @@ private: uint32_t mWriteIndex; uint32_t mNumberOfChannels; // How many frames the OfflineAudioContext intends to produce. uint32_t mLength; float mSampleRate; bool mBufferAllocated; }; -class InputMutedRunnable : public nsRunnable +class InputMutedRunnable final : public nsRunnable { public: InputMutedRunnable(AudioNodeStream* aStream, bool aInputMuted) : mStream(aStream) , mInputMuted(aInputMuted) { } - NS_IMETHOD Run() + NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); nsRefPtr<AudioNode> node = mStream->Engine()->NodeMainThread(); if (node) { nsRefPtr<AudioDestinationNode> destinationNode = static_cast<AudioDestinationNode*>(node.get()); destinationNode->InputMuted(mInputMuted); @@ -233,17 +233,17 @@ public: return NS_OK; } private: nsRefPtr<AudioNodeStream> mStream; bool mInputMuted; }; -class DestinationNodeEngine : public AudioNodeEngine +class DestinationNodeEngine final : public AudioNodeEngine { public: explicit DestinationNodeEngine(AudioDestinationNode* aNode) : AudioNodeEngine(aNode) , mVolume(1.0f) , mLastInputMuted(false) { MOZ_ASSERT(aNode);
--- a/dom/media/webaudio/AudioEventTimeline.h +++ b/dom/media/webaudio/AudioEventTimeline.h @@ -16,18 +16,20 @@ #include "math.h" #include "WebAudioUtils.h" namespace mozilla { namespace dom { // This is an internal helper class and should not be used outside of this header. -struct AudioTimelineEvent { - enum Type : uint32_t { +struct AudioTimelineEvent final +{ + enum Type : uint32_t + { SetValue, LinearRamp, ExponentialRamp, SetTarget, SetValueCurve }; AudioTimelineEvent(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
--- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -320,17 +320,18 @@ AudioNode::Disconnect(uint32_t aOutput, return; } // An upstream node may be starting to play on the graph thread, and the // engine for a downstream node may be sending a PlayingRefChangeHandler // ADDREF message to this (main) thread. Wait for a round trip before // releasing nodes, to give engines receiving sound now time to keep their // nodes alive. - class RunnableRelease : public nsRunnable { + class RunnableRelease final : public nsRunnable + { public: explicit RunnableRelease(already_AddRefed<AudioNode> aNode) : mNode(aNode) {} NS_IMETHODIMP Run() override { mNode = nullptr; return NS_OK;
--- a/dom/media/webaudio/AudioNode.h +++ b/dom/media/webaudio/AudioNode.h @@ -69,17 +69,18 @@ public: // This should be idempotent (safe to call multiple times). virtual void DestroyMediaStream(); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode, DOMEventTargetHelper) - virtual AudioBufferSourceNode* AsAudioBufferSourceNode() { + virtual AudioBufferSourceNode* AsAudioBufferSourceNode() + { return nullptr; } AudioContext* GetParentObject() const { return mContext; } @@ -132,17 +133,18 @@ public: return mChannelInterpretation; } void SetChannelInterpretationValue(ChannelInterpretation aMode) { mChannelInterpretation = aMode; SendChannelMixingParametersToStream(); } - struct InputNode { + struct InputNode final + { ~InputNode() { if (mStreamPort) { mStreamPort->Destroy(); } } size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/AudioNodeEngine.h +++ b/dom/media/webaudio/AudioNodeEngine.h @@ -22,27 +22,29 @@ class DelayNodeEngine; class AudioNodeStream; /** * This class holds onto a set of immutable channel buffers. The storage * for the buffers must be malloced, but the buffer pointers and the malloc * pointers can be different (e.g. if the buffers are contained inside * some malloced object). */ -class ThreadSharedFloatArrayBufferList : public ThreadSharedObject { +class ThreadSharedFloatArrayBufferList final : public ThreadSharedObject +{ public: /** * Construct with null data. */ explicit ThreadSharedFloatArrayBufferList(uint32_t aCount) { mContents.SetLength(aCount); } - struct Storage { + struct Storage final + { Storage() : mDataToFree(nullptr), mFree(nullptr), mSampleData(nullptr) {} ~Storage() { if (mFree) { mFree(mDataToFree); @@ -229,17 +231,18 @@ AudioBlockPanStereoToStereo(const float */ float AudioBufferSumOfSquares(const float* aInput, uint32_t aLength); /** * All methods of this class and its subclasses are called on the * MediaStreamGraph thread. */ -class AudioNodeEngine { +class AudioNodeEngine +{ public: // This should be compatible with AudioNodeStream::OutputChunks. typedef nsAutoTArray<AudioChunk, 1> OutputChunks; explicit AudioNodeEngine(dom::AudioNode* aNode) : mNode(aNode) , mNodeMutex("AudioNodeEngine::mNodeMutex") , mInputCount(aNode ? aNode->NumberOfInputs() : 1)
--- a/dom/media/webaudio/AudioNodeExternalInputStream.h +++ b/dom/media/webaudio/AudioNodeExternalInputStream.h @@ -13,24 +13,27 @@ namespace mozilla { /** * This is a MediaStream implementation that acts for a Web Audio node but * unlike other AudioNodeStreams, supports any kind of MediaStream as an * input --- handling any number of audio tracks and handling blocking of * the input MediaStream. */ -class AudioNodeExternalInputStream : public AudioNodeStream { +class AudioNodeExternalInputStream final : public AudioNodeStream +{ public: - AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, uint32_t aContextId); + AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, + uint32_t aContextId); protected: ~AudioNodeExternalInputStream(); public: - virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override; + virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, + uint32_t aFlags) override; private: /** * Determines if this is enabled or not. Disabled nodes produce silence. * This node becomes disabled if the document principal does not subsume the * DOMMediaStream principal. */ bool IsEnabled();
--- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -90,23 +90,25 @@ AudioNodeStream::SizeOfAudioNodesIncludi mEngine->SizeOfIncludingThis(aMallocSizeOf, aUsage); } } void AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, AudioContext* aContext, double aStreamTime) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, MediaStream* aRelativeToStream, double aStreamTime) : ControlMessage(aStream), mStreamTime(aStreamTime), - mRelativeToStream(aRelativeToStream), mIndex(aIndex) {} - virtual void Run() + mRelativeToStream(aRelativeToStream), mIndex(aIndex) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)-> SetStreamTimeParameterImpl(mIndex, mRelativeToStream, mStreamTime); } double mStreamTime; MediaStream* mRelativeToStream; uint32_t mIndex; }; @@ -122,151 +124,163 @@ AudioNodeStream::SetStreamTimeParameterI { StreamTime ticks = TicksFromDestinationTime(aRelativeToStream, aStreamTime); mEngine->SetStreamTimeParameter(aIndex, ticks); } void AudioNodeStream::SetDoubleParameter(uint32_t aIndex, double aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, double aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()-> SetDoubleParameter(mIndex, mValue); } double mValue; uint32_t mIndex; }; GraphImpl()->AppendMessage(new Message(this, aIndex, aValue)); } void AudioNodeStream::SetInt32Parameter(uint32_t aIndex, int32_t aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, int32_t aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()-> SetInt32Parameter(mIndex, mValue); } int32_t mValue; uint32_t mIndex; }; GraphImpl()->AppendMessage(new Message(this, aIndex, aValue)); } void AudioNodeStream::SetTimelineParameter(uint32_t aIndex, const AudioParamTimeline& aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, const AudioParamTimeline& aValue) : ControlMessage(aStream), mValue(aValue), mSampleRate(aStream->SampleRate()), - mIndex(aIndex) {} - virtual void Run() + mIndex(aIndex) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()-> SetTimelineParameter(mIndex, mValue, mSampleRate); } AudioParamTimeline mValue; TrackRate mSampleRate; uint32_t mIndex; }; GraphImpl()->AppendMessage(new Message(this, aIndex, aValue)); } void AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, const ThreeDPoint& aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()-> SetThreeDPointParameter(mIndex, mValue); } ThreeDPoint mValue; uint32_t mIndex; }; GraphImpl()->AppendMessage(new Message(this, aIndex, aValue)); } void AudioNodeStream::SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList>&& aBuffer) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, already_AddRefed<ThreadSharedFloatArrayBufferList>& aBuffer) - : ControlMessage(aStream), mBuffer(aBuffer) {} - virtual void Run() + : ControlMessage(aStream), mBuffer(aBuffer) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()-> SetBuffer(mBuffer.forget()); } nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer; }; GraphImpl()->AppendMessage(new Message(this, aBuffer)); } void AudioNodeStream::SetRawArrayData(nsTArray<float>& aData) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, nsTArray<float>& aData) : ControlMessage(aStream) { mData.SwapElements(aData); } - virtual void Run() + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->Engine()->SetRawArrayData(mData); } nsTArray<float> mData; }; GraphImpl()->AppendMessage(new Message(this, aData)); } void AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode, ChannelInterpretation aChannelInterpretation) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode, ChannelInterpretation aChannelInterpretation) : ControlMessage(aStream), mNumberOfChannels(aNumberOfChannels), mChannelCountMode(aChannelCountMode), mChannelInterpretation(aChannelInterpretation) {} - virtual void Run() + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)-> SetChannelMixingParametersImpl(mNumberOfChannels, mChannelCountMode, mChannelInterpretation); } uint32_t mNumberOfChannels; ChannelCountMode mChannelCountMode; ChannelInterpretation mChannelInterpretation; @@ -275,21 +289,23 @@ AudioNodeStream::SetChannelMixingParamet GraphImpl()->AppendMessage(new Message(this, aNumberOfChannels, aChannelCountMode, aChannelInterpretation)); } void AudioNodeStream::SetPassThrough(bool aPassThrough) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, bool aPassThrough) - : ControlMessage(aStream), mPassThrough(aPassThrough) {} - virtual void Run() + : ControlMessage(aStream), mPassThrough(aPassThrough) + {} + virtual void Run() override { static_cast<AudioNodeStream*>(mStream)->mPassThrough = mPassThrough; } bool mPassThrough; }; GraphImpl()->AppendMessage(new Message(this, aPassThrough)); }
--- a/dom/media/webaudio/AudioNodeStream.h +++ b/dom/media/webaudio/AudioNodeStream.h @@ -26,17 +26,18 @@ class AudioNodeEngine; * The start time of the AudioTrack is aligned to the start time of the * AudioContext's destination node stream, plus some multiple of BLOCK_SIZE * samples. * * An AudioNodeStream has an AudioNodeEngine plugged into it that does the * actual audio processing. AudioNodeStream contains the glue code that * integrates audio processing with the MediaStreamGraph. */ -class AudioNodeStream : public ProcessedMediaStream { +class AudioNodeStream : public ProcessedMediaStream +{ typedef dom::ChannelCountMode ChannelCountMode; typedef dom::ChannelInterpretation ChannelInterpretation; public: typedef mozilla::dom::AudioContext AudioContext; enum { AUDIO_TRACK = 1 };
--- a/dom/media/webaudio/AudioProcessingEvent.h +++ b/dom/media/webaudio/AudioProcessingEvent.h @@ -9,17 +9,17 @@ #include "AudioBuffer.h" #include "ScriptProcessorNode.h" #include "mozilla/dom/Event.h" namespace mozilla { namespace dom { -class AudioProcessingEvent : public Event +class AudioProcessingEvent final : public Event { public: AudioProcessingEvent(ScriptProcessorNode* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_TO_EVENT
--- a/dom/media/webaudio/BiquadFilterNode.cpp +++ b/dom/media/webaudio/BiquadFilterNode.cpp @@ -68,17 +68,17 @@ SetParamsOnBiquad(WebCore::Biquad& aBiqu aBiquad.setAllpassParams(normalizedFrequency, aQ); break; default: NS_NOTREACHED("We should never see the alternate names here"); break; } } -class BiquadFilterNodeEngine : public AudioNodeEngine +class BiquadFilterNodeEngine final : public AudioNodeEngine { public: BiquadFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) // Keep the default values in sync with the default values in // BiquadFilterNode::BiquadFilterNode
--- a/dom/media/webaudio/BiquadFilterNode.h +++ b/dom/media/webaudio/BiquadFilterNode.h @@ -11,17 +11,17 @@ #include "AudioParam.h" #include "mozilla/dom/BiquadFilterNodeBinding.h" namespace mozilla { namespace dom { class AudioContext; -class BiquadFilterNode : public AudioNode +class BiquadFilterNode final : public AudioNode { public: explicit BiquadFilterNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/BufferDecoder.h +++ b/dom/media/webaudio/BufferDecoder.h @@ -13,17 +13,17 @@ #include "mozilla/ReentrantMonitor.h" namespace mozilla { /** * This class provides a decoder object which decodes a media file that lives in * a memory buffer. */ -class BufferDecoder : public AbstractMediaDecoder +class BufferDecoder final : public AbstractMediaDecoder { public: // This class holds a weak pointer to MediaResource. It's the responsibility // of the caller to manage the memory of the MediaResource object. explicit BufferDecoder(MediaResource* aResource); NS_DECL_THREADSAFE_ISUPPORTS
--- a/dom/media/webaudio/ChannelMergerNode.cpp +++ b/dom/media/webaudio/ChannelMergerNode.cpp @@ -9,17 +9,17 @@ #include "AudioNodeEngine.h" #include "AudioNodeStream.h" namespace mozilla { namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(ChannelMergerNode, AudioNode) -class ChannelMergerNodeEngine : public AudioNodeEngine +class ChannelMergerNodeEngine final : public AudioNodeEngine { public: explicit ChannelMergerNodeEngine(ChannelMergerNode* aNode) : AudioNodeEngine(aNode) { MOZ_ASSERT(NS_IsMainThread()); }
--- a/dom/media/webaudio/ChannelMergerNode.h +++ b/dom/media/webaudio/ChannelMergerNode.h @@ -9,17 +9,17 @@ #include "AudioNode.h" namespace mozilla { namespace dom { class AudioContext; -class ChannelMergerNode : public AudioNode +class ChannelMergerNode final : public AudioNode { public: ChannelMergerNode(AudioContext* aContext, uint16_t aInputCount); NS_DECL_ISUPPORTS_INHERITED virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -9,17 +9,17 @@ #include "AudioNodeEngine.h" #include "AudioNodeStream.h" namespace mozilla { namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(ChannelSplitterNode, AudioNode) -class ChannelSplitterNodeEngine : public AudioNodeEngine +class ChannelSplitterNodeEngine final : public AudioNodeEngine { public: explicit ChannelSplitterNodeEngine(ChannelSplitterNode* aNode) : AudioNodeEngine(aNode) { MOZ_ASSERT(NS_IsMainThread()); }
--- a/dom/media/webaudio/ChannelSplitterNode.h +++ b/dom/media/webaudio/ChannelSplitterNode.h @@ -9,17 +9,17 @@ #include "AudioNode.h" namespace mozilla { namespace dom { class AudioContext; -class ChannelSplitterNode : public AudioNode +class ChannelSplitterNode final : public AudioNode { public: ChannelSplitterNode(AudioContext* aContext, uint16_t aOutputCount); NS_DECL_ISUPPORTS_INHERITED virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/ConvolverNode.cpp +++ b/dom/media/webaudio/ConvolverNode.cpp @@ -17,17 +17,17 @@ namespace dom { NS_IMPL_CYCLE_COLLECTION_INHERITED(ConvolverNode, AudioNode, mBuffer) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ConvolverNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(ConvolverNode, AudioNode) NS_IMPL_RELEASE_INHERITED(ConvolverNode, AudioNode) -class ConvolverNodeEngine : public AudioNodeEngine +class ConvolverNodeEngine final : public AudioNodeEngine { typedef PlayingRefChangeHandler PlayingRefChanged; public: ConvolverNodeEngine(AudioNode* aNode, bool aNormalize) : AudioNodeEngine(aNode) , mBufferLength(0) , mLeftOverData(INT32_MIN) , mSampleRate(0.0f)
--- a/dom/media/webaudio/ConvolverNode.h +++ b/dom/media/webaudio/ConvolverNode.h @@ -8,17 +8,17 @@ #define ConvolverNode_h_ #include "AudioNode.h" #include "AudioBuffer.h" namespace mozilla { namespace dom { -class ConvolverNode : public AudioNode +class ConvolverNode final : public AudioNode { public: explicit ConvolverNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ConvolverNode, AudioNode); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/DelayBuffer.h +++ b/dom/media/webaudio/DelayBuffer.h @@ -8,17 +8,18 @@ #define DelayBuffer_h_ #include "nsTArray.h" #include "AudioSegment.h" #include "mozilla/dom/AudioNodeBinding.h" // for ChannelInterpretation namespace mozilla { -class DelayBuffer { +class DelayBuffer final +{ typedef dom::ChannelInterpretation ChannelInterpretation; public: // See WebAudioUtils::ComputeSmoothingRate() for frame to frame exponential // |smoothingRate| multiplier. DelayBuffer(double aMaxDelayTicks, double aSmoothingRate) : mSmoothingRate(aSmoothingRate) , mCurrentDelay(-1.0)
--- a/dom/media/webaudio/DelayNode.cpp +++ b/dom/media/webaudio/DelayNode.cpp @@ -20,17 +20,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Delay mDelay) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DelayNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode) NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode) -class DelayNodeEngine : public AudioNodeEngine +class DelayNodeEngine final : public AudioNodeEngine { typedef PlayingRefChangeHandler PlayingRefChanged; public: DelayNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination, double aMaxDelayTicks) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
--- a/dom/media/webaudio/DelayNode.h +++ b/dom/media/webaudio/DelayNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "AudioParam.h" namespace mozilla { namespace dom { class AudioContext; -class DelayNode : public AudioNode +class DelayNode final : public AudioNode { public: DelayNode(AudioContext* aContext, double aMaxDelay); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DelayNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/DynamicsCompressorNode.cpp +++ b/dom/media/webaudio/DynamicsCompressorNode.cpp @@ -25,17 +25,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Dynam mRelease) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode) NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode) -class DynamicsCompressorNodeEngine : public AudioNodeEngine +class DynamicsCompressorNodeEngine final : public AudioNodeEngine { public: explicit DynamicsCompressorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) // Keep the default value in sync with the default value in @@ -146,26 +146,26 @@ public: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } private: void SendReductionParamToMainThread(AudioNodeStream* aStream, float aReduction) { MOZ_ASSERT(!NS_IsMainThread()); - class Command : public nsRunnable + class Command final : public nsRunnable { public: Command(AudioNodeStream* aStream, float aReduction) : mStream(aStream) , mReduction(aReduction) { } - NS_IMETHODIMP Run() + NS_IMETHOD Run() override { nsRefPtr<DynamicsCompressorNode> node; { // No need to keep holding the lock for the whole duration of this // function, since we're holding a strong reference to it, so if // we can obtain the reference, we will hold the node alive in // this function. MutexAutoLock lock(mStream->Engine()->NodeMutex());
--- a/dom/media/webaudio/DynamicsCompressorNode.h +++ b/dom/media/webaudio/DynamicsCompressorNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "AudioParam.h" namespace mozilla { namespace dom { class AudioContext; -class DynamicsCompressorNode : public AudioNode +class DynamicsCompressorNode final : public AudioNode { public: explicit DynamicsCompressorNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/FFTBlock.h +++ b/dom/media/webaudio/FFTBlock.h @@ -11,17 +11,18 @@ #include "AudioNodeEngine.h" #include "kiss_fft/kiss_fftr.h" namespace mozilla { // This class defines an FFT block, loosely modeled after Blink's FFTFrame // class to make sharing code with Blink easy. // Currently it's implemented on top of KissFFT on all platforms. -class FFTBlock { +class FFTBlock final +{ public: explicit FFTBlock(uint32_t aFFTSize) : mFFT(nullptr) , mIFFT(nullptr) , mFFTSize(aFFTSize) { MOZ_COUNT_CTOR(FFTBlock); mOutputBuffer.SetLength(aFFTSize / 2 + 1);
--- a/dom/media/webaudio/GainNode.cpp +++ b/dom/media/webaudio/GainNode.cpp @@ -18,17 +18,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(GainN mGain) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GainNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode) NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode) -class GainNodeEngine : public AudioNodeEngine +class GainNodeEngine final : public AudioNodeEngine { public: GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) // Keep the default value in sync with the default value in GainNode::GainNode. , mGain(1.f)
--- a/dom/media/webaudio/GainNode.h +++ b/dom/media/webaudio/GainNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "AudioParam.h" namespace mozilla { namespace dom { class AudioContext; -class GainNode : public AudioNode +class GainNode final : public AudioNode { public: explicit GainNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/MediaBufferDecoder.cpp +++ b/dom/media/webaudio/MediaBufferDecoder.cpp @@ -45,17 +45,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release) using namespace dom; -class ReportResultTask : public nsRunnable +class ReportResultTask final : public nsRunnable { public: ReportResultTask(WebAudioDecodeJob& aDecodeJob, WebAudioDecodeJob::ResultFn aFunction, WebAudioDecodeJob::ErrorCode aErrorCode) : mDecodeJob(aDecodeJob) , mFunction(aFunction) , mErrorCode(aErrorCode) @@ -77,23 +77,24 @@ private: // Therefore, it is not safe to do anything fancy with it in this class. // Really, this class is only used because nsRunnableMethod doesn't support // methods accepting arguments. WebAudioDecodeJob& mDecodeJob; WebAudioDecodeJob::ResultFn mFunction; WebAudioDecodeJob::ErrorCode mErrorCode; }; -enum class PhaseEnum : int { +enum class PhaseEnum : int +{ Decode, AllocateBuffer, Done }; -class MediaDecodeTask : public nsRunnable +class MediaDecodeTask final : public nsRunnable { public: MediaDecodeTask(const char* aContentType, uint8_t* aBuffer, uint32_t aLength, WebAudioDecodeJob& aDecodeJob) : mContentType(aContentType) , mBuffer(aBuffer) , mLength(aLength) @@ -209,17 +210,18 @@ MediaDecodeTask::CreateReader() if (!mDecoderReader->EnsureTaskQueue()) { return false; } return true; } -class AutoResampler { +class AutoResampler final +{ public: AutoResampler() : mResampler(nullptr) {} ~AutoResampler() { if (mResampler) { speex_resampler_destroy(mResampler);
--- a/dom/media/webaudio/MediaElementAudioSourceNode.h +++ b/dom/media/webaudio/MediaElementAudioSourceNode.h @@ -7,17 +7,17 @@ #ifndef MediaElementAudioSourceNode_h_ #define MediaElementAudioSourceNode_h_ #include "MediaStreamAudioSourceNode.h" namespace mozilla { namespace dom { -class MediaElementAudioSourceNode : public MediaStreamAudioSourceNode +class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { public: MediaElementAudioSourceNode(AudioContext* aContext, DOMMediaStream* aStream); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual const char* NodeType() const override
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.h +++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.h @@ -7,17 +7,17 @@ #ifndef MediaStreamAudioDestinationNode_h_ #define MediaStreamAudioDestinationNode_h_ #include "AudioNode.h" namespace mozilla { namespace dom { -class MediaStreamAudioDestinationNode : public AudioNode +class MediaStreamAudioDestinationNode final : public AudioNode { public: explicit MediaStreamAudioDestinationNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioDestinationNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/MediaStreamAudioSourceNode.h +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "DOMMediaStream.h" #include "AudioNodeEngine.h" namespace mozilla { namespace dom { -class MediaStreamAudioSourceNodeEngine : public AudioNodeEngine +class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine { public: explicit MediaStreamAudioSourceNodeEngine(AudioNode* aNode) : AudioNodeEngine(aNode), mEnabled(false) {} bool IsEnabled() const { return mEnabled; } enum Parameters { ENABLE
--- a/dom/media/webaudio/OfflineAudioCompletionEvent.h +++ b/dom/media/webaudio/OfflineAudioCompletionEvent.h @@ -10,17 +10,17 @@ #include "AudioBuffer.h" #include "mozilla/dom/Event.h" namespace mozilla { namespace dom { class AudioContext; -class OfflineAudioCompletionEvent : public Event +class OfflineAudioCompletionEvent final : public Event { public: OfflineAudioCompletionEvent(AudioContext* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_TO_EVENT
--- a/dom/media/webaudio/OscillatorNode.cpp +++ b/dom/media/webaudio/OscillatorNode.cpp @@ -18,17 +18,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Oscil mPeriodicWave, mFrequency, mDetune) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OscillatorNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode) NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode) -class OscillatorNodeEngine : public AudioNodeEngine +class OscillatorNodeEngine final : public AudioNodeEngine { public: OscillatorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) , mStart(-1) , mStop(STREAM_TIME_MAX) @@ -510,22 +510,22 @@ OscillatorNode::Stop(double aWhen, Error ns->SetStreamTimeParameter(OscillatorNodeEngine::STOP, Context(), std::max(0.0, aWhen)); } void OscillatorNode::NotifyMainThreadStateChanged() { if (mStream->IsFinished()) { - class EndedEventDispatcher : public nsRunnable + class EndedEventDispatcher final : public nsRunnable { public: explicit EndedEventDispatcher(OscillatorNode* aNode) : mNode(aNode) {} - NS_IMETHODIMP Run() + NS_IMETHOD Run() override { // If it's not safe to run scripts right now, schedule this to run later if (!nsContentUtils::IsSafeToRunScript()) { nsContentUtils::AddScriptRunner(this); return NS_OK; } mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
--- a/dom/media/webaudio/OscillatorNode.h +++ b/dom/media/webaudio/OscillatorNode.h @@ -13,18 +13,18 @@ #include "mozilla/dom/OscillatorNodeBinding.h" #include "mozilla/Preferences.h" namespace mozilla { namespace dom { class AudioContext; -class OscillatorNode : public AudioNode, - public MainThreadMediaStreamListener +class OscillatorNode final : public AudioNode, + public MainThreadMediaStreamListener { public: explicit OscillatorNode(AudioContext* aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioNode) virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/media/webaudio/PannerNode.cpp +++ b/dom/media/webaudio/PannerNode.cpp @@ -34,17 +34,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PannerNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(PannerNode, AudioNode) NS_IMPL_RELEASE_INHERITED(PannerNode, AudioNode) -class PannerNodeEngine : public AudioNodeEngine +class PannerNodeEngine final : public AudioNodeEngine { public: explicit PannerNodeEngine(AudioNode* aNode) : AudioNodeEngine(aNode) // Please keep these default values consistent with PannerNode::PannerNode below. , mPanningModelFunction(&PannerNodeEngine::EqualPowerPanningFunction) , mDistanceModelFunction(&PannerNodeEngine::InverseGainFunction) , mPosition()
--- a/dom/media/webaudio/PannerNode.h +++ b/dom/media/webaudio/PannerNode.h @@ -16,18 +16,18 @@ #include <set> namespace mozilla { namespace dom { class AudioContext; class AudioBufferSourceNode; -class PannerNode : public AudioNode, - public SupportsWeakPtr<PannerNode> +class PannerNode final : public AudioNode, + public SupportsWeakPtr<PannerNode> { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode) explicit PannerNode(AudioContext* aContext); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual void DestroyMediaStream() override;
--- a/dom/media/webaudio/PlayingRefChangeHandler.h +++ b/dom/media/webaudio/PlayingRefChangeHandler.h @@ -8,17 +8,17 @@ #define PlayingRefChangeHandler_h__ #include "nsThreadUtils.h" #include "AudioNodeStream.h" namespace mozilla { namespace dom { -class PlayingRefChangeHandler : public nsRunnable +class PlayingRefChangeHandler final : public nsRunnable { public: enum ChangeType { ADDREF, RELEASE }; PlayingRefChangeHandler(AudioNodeStream* aStream, ChangeType aChange) : mStream(aStream) , mChange(aChange) { }
--- a/dom/media/webaudio/ReportDecodeResultTask.h +++ b/dom/media/webaudio/ReportDecodeResultTask.h @@ -7,17 +7,17 @@ #ifndef ReportDecodeResultTask_h_ #define ReportDecodeResultTask_h_ #include "mozilla/Attributes.h" #include "MediaBufferDecoder.h" namespace mozilla { -class ReportDecodeResultTask : public nsRunnable +class ReportDecodeResultTask final : public nsRunnable { public: ReportDecodeResultTask(DecodeJob& aDecodeJob, DecodeJob::ResultFn aFunction) : mDecodeJob(aDecodeJob) , mFunction(aFunction) { MOZ_ASSERT(aFunction);
--- a/dom/media/webaudio/ScriptProcessorNode.cpp +++ b/dom/media/webaudio/ScriptProcessorNode.cpp @@ -23,20 +23,20 @@ namespace dom { // The maximum latency, in seconds, that we can live with before dropping // buffers. static const float MAX_LATENCY_S = 0.5; NS_IMPL_ISUPPORTS_INHERITED0(ScriptProcessorNode, AudioNode) // This class manages a queue of output buffers shared between // the main thread and the Media Stream Graph thread. -class SharedBuffers +class SharedBuffers final { private: - class OutputQueue + class OutputQueue final { public: explicit OutputQueue(const char* aName) : mMutex(aName) {} size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { @@ -232,17 +232,17 @@ private: float mLatency; // This is the time at which we last produced a buffer, to detect if the main // thread has been blocked. TimeStamp mLastEventTime; // True if we should be dropping buffers. bool mDroppingBuffers; }; -class ScriptProcessorNodeEngine : public AudioNodeEngine +class ScriptProcessorNodeEngine final : public AudioNodeEngine { public: typedef nsAutoTArray<nsAutoArrayPtr<float>, 2> InputChannels; ScriptProcessorNodeEngine(ScriptProcessorNode* aNode, AudioDestinationNode* aDestination, uint32_t aBufferSize, uint32_t aNumberOfInputChannels) @@ -356,17 +356,17 @@ private: // Add the duration of the current sample playbackTick += WEBAUDIO_BLOCK_SIZE; // Add the delay caused by the main thread playbackTick += mSharedBuffers->DelaySoFar(); // Compute the playback time in the coordinate system of the destination double playbackTime = mSource->DestinationTimeFromTicks(mDestination, playbackTick); - class Command : public nsRunnable + class Command final : public nsRunnable { public: Command(AudioNodeStream* aStream, InputChannels& aInputChannels, double aPlaybackTime, bool aNullInput) : mStream(aStream) , mPlaybackTime(aPlaybackTime) @@ -375,17 +375,17 @@ private: mInputChannels.SetLength(aInputChannels.Length()); if (!aNullInput) { for (uint32_t i = 0; i < mInputChannels.Length(); ++i) { mInputChannels[i] = aInputChannels[i].forget(); } } } - NS_IMETHODIMP Run() + NS_IMETHOD Run() override { nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*> (mStream->Engine()->NodeMainThread()); if (!node) { return NS_OK; } AudioContext* context = node->Context(); if (!context) {
--- a/dom/media/webaudio/ScriptProcessorNode.h +++ b/dom/media/webaudio/ScriptProcessorNode.h @@ -11,17 +11,17 @@ #include "nsAutoPtr.h" namespace mozilla { namespace dom { class AudioContext; class SharedBuffers; -class ScriptProcessorNode : public AudioNode +class ScriptProcessorNode final : public AudioNode { public: ScriptProcessorNode(AudioContext* aContext, uint32_t aBufferSize, uint32_t aNumberOfInputChannels, uint32_t aNumberOfOutputChannels); NS_DECL_ISUPPORTS_INHERITED
--- a/dom/media/webaudio/StereoPannerNode.cpp +++ b/dom/media/webaudio/StereoPannerNode.cpp @@ -22,17 +22,17 @@ using namespace std; NS_IMPL_CYCLE_COLLECTION_INHERITED(StereoPannerNode, AudioNode, mPan) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(StereoPannerNode) NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(StereoPannerNode, AudioNode) NS_IMPL_RELEASE_INHERITED(StereoPannerNode, AudioNode) -class StereoPannerNodeEngine : public AudioNodeEngine +class StereoPannerNodeEngine final : public AudioNodeEngine { public: StereoPannerNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) , mDestination(static_cast<AudioNodeStream*>(aDestination->Stream())) // Keep the default value in sync with the default value in
--- a/dom/media/webaudio/StereoPannerNode.h +++ b/dom/media/webaudio/StereoPannerNode.h @@ -10,17 +10,17 @@ #include "AudioNode.h" #include "mozilla/dom/StereoPannerNodeBinding.h" namespace mozilla { namespace dom { class AudioContext; -class StereoPannerNode : public AudioNode +class StereoPannerNode final : public AudioNode { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode) explicit StereoPannerNode(AudioContext* aContext); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) override
--- a/dom/media/webaudio/ThreeDPoint.h +++ b/dom/media/webaudio/ThreeDPoint.h @@ -9,17 +9,18 @@ #include <cmath> #include <algorithm> namespace mozilla { namespace dom { -struct ThreeDPoint { +struct ThreeDPoint final +{ ThreeDPoint() : x(0.) , y(0.) , z(0.) { } ThreeDPoint(double aX, double aY, double aZ) : x(aX)
--- a/dom/media/webaudio/WaveShaperNode.cpp +++ b/dom/media/webaudio/WaveShaperNode.cpp @@ -43,17 +43,17 @@ static uint32_t ValueOf(OverSampleType a case OverSampleType::_2x: return 2; case OverSampleType::_4x: return 4; default: NS_NOTREACHED("We should never reach here"); return 1; } } -class Resampler +class Resampler final { public: Resampler() : mType(OverSampleType::None) , mUpSampler(nullptr) , mDownSampler(nullptr) , mChannels(0) , mSampleRate(0) @@ -156,17 +156,17 @@ private: OverSampleType mType; SpeexResamplerState* mUpSampler; SpeexResamplerState* mDownSampler; uint32_t mChannels; TrackRate mSampleRate; nsTArray<float> mBuffer; }; -class WaveShaperNodeEngine : public AudioNodeEngine +class WaveShaperNodeEngine final : public AudioNodeEngine { public: explicit WaveShaperNodeEngine(AudioNode* aNode) : AudioNodeEngine(aNode) , mType(OverSampleType::None) { }
--- a/dom/media/webaudio/WaveShaperNode.h +++ b/dom/media/webaudio/WaveShaperNode.h @@ -11,17 +11,17 @@ #include "mozilla/dom/WaveShaperNodeBinding.h" #include "mozilla/dom/TypedArray.h" namespace mozilla { namespace dom { class AudioContext; -class WaveShaperNode : public AudioNode +class WaveShaperNode final : public AudioNode { public: explicit WaveShaperNode(AudioContext *aContext); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WaveShaperNode, AudioNode) virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -127,17 +127,17 @@ var interfaceNamesInGlobalScope = {name: "MozAbortablePromise", pref: "dom.abortablepromise.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "AlarmsManager", pref: "dom.mozAlarms.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "AnalyserNode", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "Animation", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "AnimationEffectReadonly", pref: "dom.animations-api.core.enabled"}, + {name: "AnimationEffectReadOnly", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "AnimationEvent", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "AnimationTimeline", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "Attr", // IMPORTANT: Do not change this list without review from a DOM peer! "Audio", @@ -646,17 +646,17 @@ var interfaceNamesInGlobalScope = {name: "InputPortManager", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "InstallTrigger", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "KeyEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "KeyboardEvent", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "KeyframeEffectReadonly", pref: "dom.animations-api.core.enabled"}, + {name: "KeyframeEffectReadOnly", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "LocalMediaStream", // IMPORTANT: Do not change this list without review from a DOM peer! "Location", // IMPORTANT: Do not change this list without review from a DOM peer! "MediaDeviceInfo", // IMPORTANT: Do not change this list without review from a DOM peer! "MediaDevices",
--- a/dom/webidl/Animation.webidl +++ b/dom/webidl/Animation.webidl @@ -11,17 +11,17 @@ */ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" }; [Func="nsDocument::IsWebAnimationsEnabled"] interface Animation { // Bug 1049975: Make 'effect' writeable [Pure] - readonly attribute AnimationEffectReadonly? effect; + readonly attribute AnimationEffectReadOnly? effect; readonly attribute AnimationTimeline timeline; [BinaryName="startTimeAsDouble"] attribute double? startTime; [SetterThrows, BinaryName="currentTimeAsDouble"] attribute double? currentTime; attribute double playbackRate; [BinaryName="playStateFromJS"]
rename from dom/webidl/AnimationEffectReadonly.webidl rename to dom/webidl/AnimationEffectReadOnly.webidl --- a/dom/webidl/AnimationEffectReadonly.webidl +++ b/dom/webidl/AnimationEffectReadOnly.webidl @@ -6,13 +6,13 @@ * The origin of this IDL file is * http://w3c.github.io/web-animations/#animationeffectreadonly * * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ [Func="nsDocument::IsWebAnimationsEnabled"] -interface AnimationEffectReadonly { +interface AnimationEffectReadOnly { // Not yet implemented: - // readonly attribute AnimationEffectTimingReadonly timing; + // readonly attribute AnimationEffectTimingReadOnly timing; // readonly attribute ComputedTimingProperties computedTiming; };
--- a/dom/webidl/KeyframeEffect.webidl +++ b/dom/webidl/KeyframeEffect.webidl @@ -7,17 +7,17 @@ * http://w3c.github.io/web-animations/#the-keyframeeffect-interfaces * * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ [HeaderFile="mozilla/dom/KeyframeEffect.h", Func="nsDocument::IsWebAnimationsEnabled"] -interface KeyframeEffectReadonly : AnimationEffectReadonly { +interface KeyframeEffectReadOnly : AnimationEffectReadOnly { readonly attribute Element? target; readonly attribute DOMString name; // Not yet implemented: // readonly attribute IterationCompositeOperation iterationComposite; // readonly attribute CompositeOperation composite; // readonly attribute DOMString spacing; // KeyframeEffect clone(); // sequence<ComputedKeyframe> getFrames ();
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -18,17 +18,17 @@ PREPROCESSED_WEBIDL_FILES = [ WEBIDL_FILES = [ 'AbortablePromise.webidl', 'AbstractWorker.webidl', 'ActivityRequestHandler.webidl', 'AlarmsManager.webidl', 'AnalyserNode.webidl', 'Animatable.webidl', 'Animation.webidl', - 'AnimationEffectReadonly.webidl', + 'AnimationEffectReadOnly.webidl', 'AnimationEvent.webidl', 'AnimationTimeline.webidl', 'AnonymousContent.webidl', 'AppInfo.webidl', 'AppNotificationServiceOptions.webidl', 'Apps.webidl', 'APZTestData.webidl', 'ArchiveReader.webidl',
--- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -8,16 +8,17 @@ #include "nsIChannel.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" #include "nsIHttpChannel.h" #include "nsIInputStreamPump.h" #include "nsIIOService.h" #include "nsIProtocolHandler.h" #include "nsIScriptSecurityManager.h" +#include "nsISerializable.h" #include "nsIStreamLoader.h" #include "nsIStreamListenerTee.h" #include "nsIThreadRetargetableRequest.h" #include "nsIURI.h" #include "jsapi.h" #include "nsError.h" #include "nsContentPolicyUtils.h" @@ -415,16 +416,17 @@ private: ScriptLoadInfo& mLoadInfo; uint32_t mIndex; nsRefPtr<ScriptLoaderRunnable> mRunnable; bool mIsWorkerScript; bool mFailed; nsCOMPtr<nsIInputStreamPump> mPump; nsCOMPtr<nsIURI> mBaseURI; + nsCString mSecurityInfo; }; NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver) class CachePromiseHandler final : public PromiseNativeHandler { public: CachePromiseHandler(ScriptLoaderRunnable* aRunnable, @@ -452,26 +454,28 @@ private: nsRefPtr<ScriptLoaderRunnable> mRunnable; ScriptLoadInfo& mLoadInfo; uint32_t mIndex; }; class ScriptLoaderRunnable final : public WorkerFeature, public nsIRunnable, - public nsIStreamLoaderObserver + public nsIStreamLoaderObserver, + public nsIRequestObserver { friend class ScriptExecutorRunnable; friend class CachePromiseHandler; friend class CacheScriptLoader; WorkerPrivate* mWorkerPrivate; nsCOMPtr<nsIEventTarget> mSyncLoopTarget; nsTArray<ScriptLoadInfo> mLoadInfos; nsRefPtr<CacheCreator> mCacheCreator; + nsCOMPtr<nsIInputStream> mReader; bool mIsMainScript; WorkerScriptType mWorkerScriptType; bool mCanceled; bool mCanceledMainThread; public: NS_DECL_THREADSAFE_ISUPPORTS @@ -555,16 +559,89 @@ private: ScriptLoadInfo& loadInfo = mLoadInfos[index]; nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus, aStringLen, aString, loadInfo); LoadingFinished(index, rv); return NS_OK; } + NS_IMETHOD + OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) + { + AssertIsOnMainThread(); + + nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext)); + MOZ_ASSERT(indexSupports, "This should never fail!"); + + uint32_t index = UINT32_MAX; + if (NS_FAILED(indexSupports->GetData(&index)) || + index >= mLoadInfos.Length()) { + MOZ_CRASH("Bad index!"); + } + + ScriptLoadInfo& loadInfo = mLoadInfos[index]; + + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); + MOZ_ASSERT(channel == loadInfo.mChannel); + + // We synthesize the result code, but its never exposed to content. + nsRefPtr<InternalResponse> ir = + new InternalResponse(200, NS_LITERAL_CSTRING("OK")); + ir->SetBody(mReader); + + // Set the security info of the channel on the response so that it's + // saved in the cache. + nsCOMPtr<nsISupports> infoObj; + channel->GetSecurityInfo(getter_AddRefs(infoObj)); + if (infoObj) { + nsCOMPtr<nsISerializable> serializable = do_QueryInterface(infoObj); + if (serializable) { + ir->SetSecurityInfo(serializable); + MOZ_ASSERT(!ir->GetSecurityInfo().IsEmpty()); + } else { + NS_WARNING("A non-serializable object was obtained from nsIChannel::GetSecurityInfo()!"); + } + } + + nsRefPtr<Response> response = new Response(mCacheCreator->Global(), ir); + + RequestOrUSVString request; + + MOZ_ASSERT(!loadInfo.mFullURL.IsEmpty()); + request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(), + loadInfo.mFullURL.Length()); + + ErrorResult error; + nsRefPtr<Promise> cachePromise = + mCacheCreator->Cache_()->Put(request, *response, error); + if (NS_WARN_IF(error.Failed())) { + nsresult rv = error.StealNSResult(); + channel->Cancel(rv); + return rv; + } + + nsRefPtr<CachePromiseHandler> promiseHandler = + new CachePromiseHandler(this, loadInfo, index); + cachePromise->AppendNativeHandler(promiseHandler); + + loadInfo.mCachePromise.swap(cachePromise); + loadInfo.mCacheStatus = ScriptLoadInfo::WritingToCache; + + return NS_OK; + } + + NS_IMETHOD + OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, + nsresult aStatusCode) + { + // Nothing to do here! + return NS_OK; + } + virtual bool Notify(JSContext* aCx, Status aStatus) override { mWorkerPrivate->AssertIsOnWorkerThread(); if (aStatus >= Terminating && !mCanceled) { mCanceled = true; @@ -768,69 +845,39 @@ private: } if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) { rv = channel->AsyncOpen(loader, indexSupports); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { - nsCOMPtr<nsIInputStream> reader; nsCOMPtr<nsIOutputStream> writer; // In case we return early. loadInfo.mCacheStatus = ScriptLoadInfo::Cancel; - rv = NS_NewPipe(getter_AddRefs(reader), getter_AddRefs(writer), 0, + rv = NS_NewPipe(getter_AddRefs(mReader), getter_AddRefs(writer), 0, UINT32_MAX, // unlimited size to avoid writer WOULD_BLOCK case true, false); // non-blocking reader, blocking writer if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // We synthesize the result code, but its never exposed to content. - nsRefPtr<InternalResponse> ir = - new InternalResponse(200, NS_LITERAL_CSTRING("OK")); - ir->SetBody(reader); - nsCOMPtr<nsIStreamListenerTee> tee = do_CreateInstance(NS_STREAMLISTENERTEE_CONTRACTID); - rv = tee->Init(loader, writer, nullptr); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = channel->AsyncOpen(tee, indexSupports); + rv = tee->Init(loader, writer, this); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - nsRefPtr<Response> response = new Response(mCacheCreator->Global(), ir); - - RequestOrUSVString request; - - MOZ_ASSERT(!loadInfo.mFullURL.IsEmpty()); - request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(), - loadInfo.mFullURL.Length()); - - ErrorResult error; - nsRefPtr<Promise> cachePromise = - mCacheCreator->Cache_()->Put(request, *response, error); - if (NS_WARN_IF(error.Failed())) { - nsresult rv = error.StealNSResult(); - channel->Cancel(rv); + nsresult rv = channel->AsyncOpen(tee, indexSupports); + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - - nsRefPtr<CachePromiseHandler> promiseHandler = - new CachePromiseHandler(this, loadInfo, aIndex); - cachePromise->AppendNativeHandler(promiseHandler); - - loadInfo.mCachePromise.swap(cachePromise); - loadInfo.mCacheStatus = ScriptLoadInfo::WritingToCache; } loadInfo.mChannel.swap(channel); return NS_OK; } nsresult @@ -912,16 +959,30 @@ private: } // Update the principal of the worker and its base URI if we just loaded the // worker's primary script. if (IsMainWorkerScript()) { // Take care of the base URI first. mWorkerPrivate->SetBaseURI(finalURI); + // Store the security info if needed. + if (mWorkerPrivate->IsServiceWorker()) { + nsCOMPtr<nsISupports> infoObj; + channel->GetSecurityInfo(getter_AddRefs(infoObj)); + if (infoObj) { + nsCOMPtr<nsISerializable> serializable = do_QueryInterface(infoObj); + if (serializable) { + mWorkerPrivate->SetSecurityInfo(serializable); + } else { + NS_WARNING("A non-serializable object was obtained from nsIChannel::GetSecurityInfo()!"); + } + } + } + // Now to figure out which principal to give this worker. WorkerPrivate* parent = mWorkerPrivate->GetParent(); NS_ASSERTION(mWorkerPrivate->GetPrincipal() || parent, "Must have one of these!"); nsCOMPtr<nsIPrincipal> loadPrincipal = mWorkerPrivate->GetPrincipal() ? mWorkerPrivate->GetPrincipal() : @@ -985,17 +1046,17 @@ private: } DataReceived(); return NS_OK; } void DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString, - uint32_t aStringLen) + uint32_t aStringLen, const nsCString& aSecurityInfo) { AssertIsOnMainThread(); MOZ_ASSERT(aIndex < mLoadInfos.Length()); ScriptLoadInfo& loadInfo = mLoadInfos[aIndex]; MOZ_ASSERT(loadInfo.mCacheStatus == ScriptLoadInfo::Cached); // May be null. nsIDocument* parentDoc = mWorkerPrivate->GetDocument(); @@ -1013,16 +1074,17 @@ private: if (NS_SUCCEEDED(rv)) { mWorkerPrivate->SetBaseURI(finalURI); } nsIPrincipal* principal = mWorkerPrivate->GetPrincipal(); MOZ_ASSERT(principal); nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup(); MOZ_ASSERT(loadGroup); + mWorkerPrivate->SetSecurityInfo(aSecurityInfo); // Needed to initialize the principal info. This is fine because // the cache principal cannot change, unlike the channel principal. mWorkerPrivate->SetPrincipal(principal, loadGroup); } if (NS_SUCCEEDED(rv)) { DataReceived(); } @@ -1096,17 +1158,19 @@ private: firstIndex, lastIndex); if (!runnable->Dispatch(nullptr)) { MOZ_ASSERT(false, "This should never fail!"); } } } }; -NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable, nsIStreamLoaderObserver) +NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable, + nsIStreamLoaderObserver, + nsIRequestObserver) void CachePromiseHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { AssertIsOnMainThread(); // May already have been canceled by CacheScriptLoader::Fail from // CancelMainThread. @@ -1364,20 +1428,21 @@ CacheScriptLoader::ResolvedCallback(JSCo nsresult rv = UNWRAP_OBJECT(Response, obj, response); if (NS_WARN_IF(NS_FAILED(rv))) { Fail(rv); return; } nsCOMPtr<nsIInputStream> inputStream; response->GetBody(getter_AddRefs(inputStream)); + mSecurityInfo = response->GetSecurityInfo(); if (!inputStream) { mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached; - mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0); + mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mSecurityInfo); return; } MOZ_ASSERT(!mPump); rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream); if (NS_WARN_IF(NS_FAILED(rv))) { Fail(rv); return; @@ -1423,17 +1488,17 @@ CacheScriptLoader::OnStreamComplete(nsIS if (NS_FAILED(aStatus)) { Fail(aStatus); return NS_OK; } mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached; - mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen); + mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mSecurityInfo); return NS_OK; } class ChannelGetterRunnable final : public nsRunnable { WorkerPrivate* mParentWorker; nsCOMPtr<nsIEventTarget> mSyncLoopTarget; const nsAString& mScriptURL;
--- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -13,16 +13,17 @@ #include "nsContentUtils.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsStreamUtils.h" #include "nsNetCID.h" #include "nsSerializationHelper.h" #include "nsQueryObject.h" +#include "mozilla/Preferences.h" #include "mozilla/dom/FetchEventBinding.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/Request.h" #include "mozilla/dom/Response.h" #include "mozilla/dom/WorkerScope.h" #include "mozilla/dom/workers/bindings/ServiceWorker.h" #include "WorkerPrivate.h" @@ -92,31 +93,40 @@ public: return NS_OK; } }; class FinishResponse final : public nsRunnable { nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel; nsRefPtr<InternalResponse> mInternalResponse; + nsCString mWorkerSecurityInfo; public: FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel, - InternalResponse* aInternalResponse) + InternalResponse* aInternalResponse, + const nsCString& aWorkerSecurityInfo) : mChannel(aChannel) , mInternalResponse(aInternalResponse) + , mWorkerSecurityInfo(aWorkerSecurityInfo) { } NS_IMETHOD Run() { AssertIsOnMainThread(); nsCOMPtr<nsISupports> infoObj; - nsresult rv = NS_DeserializeObject(mInternalResponse->GetSecurityInfo(), getter_AddRefs(infoObj)); + nsAutoCString securityInfo(mInternalResponse->GetSecurityInfo()); + if (securityInfo.IsEmpty()) { + // We are dealing with a synthesized response here, so fall back to the + // security info for the worker script. + securityInfo = mWorkerSecurityInfo; + } + nsresult rv = NS_DeserializeObject(securityInfo, getter_AddRefs(infoObj)); if (NS_SUCCEEDED(rv)) { rv = mChannel->SetSecurityInfo(infoObj); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } mChannel->SynthesizeStatus(mInternalResponse->GetStatus(), mInternalResponse->GetStatusText()); @@ -154,31 +164,36 @@ public: void CancelRequest(); }; struct RespondWithClosure { nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel; nsRefPtr<InternalResponse> mInternalResponse; + nsCString mWorkerSecurityInfo; RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel, - InternalResponse* aInternalResponse) + InternalResponse* aInternalResponse, + const nsCString& aWorkerSecurityInfo) : mInterceptedChannel(aChannel) , mInternalResponse(aInternalResponse) + , mWorkerSecurityInfo(aWorkerSecurityInfo) { } }; void RespondWithCopyComplete(void* aClosure, nsresult aStatus) { nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure)); nsCOMPtr<nsIRunnable> event; if (NS_SUCCEEDED(aStatus)) { - event = new FinishResponse(data->mInterceptedChannel, data->mInternalResponse); + event = new FinishResponse(data->mInterceptedChannel, + data->mInternalResponse, + data->mWorkerSecurityInfo); } else { event = new CancelChannelRunnable(data->mInterceptedChannel); } MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event))); } class MOZ_STACK_CLASS AutoCancel { @@ -229,17 +244,22 @@ RespondWithHandler::ResolvedCallback(JSC return; } nsRefPtr<InternalResponse> ir = response->GetInternalResponse(); if (NS_WARN_IF(!ir)) { return; } - nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir)); + WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(worker); + worker->AssertIsOnWorkerThread(); + + nsAutoPtr<RespondWithClosure> closure( + new RespondWithClosure(mInterceptedChannel, ir, worker->GetSecurityInfo())); nsCOMPtr<nsIInputStream> body; response->GetBody(getter_AddRefs(body)); // Errors and redirects may not have a body. if (body) { response->SetBodyUsed(); nsCOMPtr<nsIOutputStream> responseBody; rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -27,16 +27,17 @@ #include "nsITimer.h" #include "nsIURI.h" #include "nsIURL.h" #include "nsIWeakReferenceUtils.h" #include "nsIWorkerDebugger.h" #include "nsIXPConnect.h" #include "nsPerformance.h" #include "nsPIDOMWindow.h" +#include "nsSerializationHelper.h" #include <algorithm> #include "jsfriendapi.h" #include "js/MemoryMetrics.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/ContentEvents.h" #include "mozilla/EventDispatcher.h" @@ -4077,16 +4078,27 @@ WorkerPrivateParent<Derived>::SetPrincip mLoadInfo.mPrincipalInfo = new PrincipalInfo(); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo))); } template <class Derived> +void +WorkerPrivateParent<Derived>::SetSecurityInfo(nsISerializable* aSerializable) +{ + MOZ_ASSERT(IsServiceWorker()); + AssertIsOnMainThread(); + nsAutoCString securityInfo; + NS_SerializeToString(aSerializable, securityInfo); + SetSecurityInfo(securityInfo); +} + +template <class Derived> JSContext* WorkerPrivateParent<Derived>::ParentJSContext() const { AssertIsOnParentThread(); if (mParent) { return mParent->GetJSContext(); }
--- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -32,16 +32,17 @@ #include "WorkerFeature.h" class JSAutoStructuredCloneBuffer; class nsIChannel; class nsIDocument; class nsIEventTarget; class nsIPrincipal; class nsIScriptContext; +class nsISerializable; class nsIThread; class nsIThreadInternal; class nsITimer; class nsIURI; namespace JS { struct RuntimeStats; } @@ -486,16 +487,35 @@ public: const nsString& ServiceWorkerCacheName() const { MOZ_ASSERT(IsServiceWorker()); AssertIsOnMainThread(); return mLoadInfo.mServiceWorkerCacheName; } + const nsCString& + GetSecurityInfo() const + { + MOZ_ASSERT(IsServiceWorker()); + return mLoadInfo.mSecurityInfo; + } + + void + SetSecurityInfo(const nsCString& aSecurityInfo) + { + MOZ_ASSERT(IsServiceWorker()); + AssertIsOnMainThread(); + MOZ_ASSERT(mLoadInfo.mSecurityInfo.IsEmpty()); + mLoadInfo.mSecurityInfo = aSecurityInfo; + } + + void + SetSecurityInfo(nsISerializable* aSerializable); + // This is used to handle importScripts(). When the worker is first loaded // and executed, it happens in a sync loop. At this point it sets // mLoadingWorkerScript to true. importScripts() calls that occur during the // execution run in nested sync loops and so this continues to return true, // leading to these scripts being cached offline. // mLoadingWorkerScript is set to false when the top level loop ends. // importScripts() in function calls or event handlers are always fetched // from the network.
--- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -238,16 +238,18 @@ struct WorkerLoadInfo // Only set if we have a custom overriden load group nsRefPtr<InterfaceRequestor> mInterfaceRequestor; nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; nsCString mDomain; nsString mServiceWorkerCacheName; + nsCString mSecurityInfo; + uint64_t mWindowID; bool mFromWindow; bool mEvalAllowed; bool mReportCSPViolations; bool mXHRParamsAllowed; bool mPrincipalIsSystem; bool mIsInPrivilegedApp;
--- a/dom/workers/test/serviceworkers/fetch/https/https_test.js +++ b/dom/workers/test/serviceworkers/fetch/https/https_test.js @@ -2,10 +2,13 @@ self.addEventListener("install", functio event.waitUntil(caches.open("cache").then(function(cache) { return cache.add("index.html"); })); }); self.addEventListener("fetch", function(event) { if (event.request.url.indexOf("index.html") >= 0) { event.respondWith(caches.match(event.request)); + } else if (event.request.url.indexOf("synth.html") >= 0) { + event.respondWith(new Response('<!DOCTYPE html><script>window.parent.postMessage({status: "done-synth"}, "*");</script>', + {headers:{"Content-Type": "text/html"}})); } });
--- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -77,16 +77,17 @@ support-files = periodic/register.html periodic/unregister.html [test_unregister.html] [test_installation_simple.html] [test_fetch_event.html] [test_https_fetch.html] [test_https_fetch_cloned_response.html] +[test_https_synth_fetch_from_cached_sw.html] [test_match_all.html] [test_match_all_advanced.html] [test_install_event.html] [test_navigator.html] [test_scopes.html] [test_controller.html] [test_workerUnregister.html] [test_workerUpdate.html]
--- a/dom/workers/test/serviceworkers/test_https_fetch.html +++ b/dom/workers/test/serviceworkers/test_https_fetch.html @@ -26,16 +26,18 @@ if (e.data.status == "ok") { ok(e.data.result, e.data.message); } else if (e.data.status == "registrationdone") { ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"] .getService(SpecialPowers.Ci.nsIIOService); ios.offline = true; iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/index.html"; } else if (e.data.status == "done") { + iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth.html"; + } else if (e.data.status == "done-synth") { ios.offline = false; iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/unregister.html"; } else if (e.data.status == "unregistrationdone") { window.onmessage = null; ok(true, "Test finished successfully"); SimpleTest.finish(); } };
copy from dom/workers/test/serviceworkers/test_https_fetch.html copy to dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html --- a/dom/workers/test/serviceworkers/test_https_fetch.html +++ b/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html @@ -1,22 +1,22 @@ <!-- Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ --> <!DOCTYPE HTML> <html> <head> - <title>Bug 1133763 - test fetch event in HTTPS origins</title> + <title>Bug 1156847 - test fetch event generating a synthesized response in HTTPS origins from a cached SW</title> <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 id="content" tyle="display: none"> <iframe></iframe> </div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> var iframe; function runTest() { iframe = document.querySelector("iframe"); @@ -24,18 +24,31 @@ var ios; window.onmessage = function(e) { if (e.data.status == "ok") { ok(e.data.result, e.data.message); } else if (e.data.status == "registrationdone") { ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"] .getService(SpecialPowers.Ci.nsIIOService); ios.offline = true; - iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/index.html"; - } else if (e.data.status == "done") { + + // In order to load synth.html from a cached service worker, we first + // remove the existing window that is keeping the service worker alive, + // and do a GC to ensure that the SW is destroyed. This way, when we + // load synth.html for the second time, we will first recreate the + // service worker from the cache. This is intended to test that we + // properly store and retrieve the security info from the cache. + iframe.parentNode.removeChild(iframe); + iframe = null; + SpecialPowers.exactGC(window, function() { + iframe = document.createElement("iframe"); + iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth.html"; + document.body.appendChild(iframe); + }); + } else if (e.data.status == "done-synth") { ios.offline = false; iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/unregister.html"; } else if (e.data.status == "unregistrationdone") { window.onmessage = null; ok(true, "Test finished successfully"); SimpleTest.finish(); } };
--- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -215,16 +215,19 @@ public: }; class NoLog { public: NoLog() {} ~NoLog() {} + // No-op + MOZ_IMPLICIT NoLog(const NoLog&) {} + template<typename T> NoLog &operator <<(const T &aLogText) { return *this; } }; enum class LogOptions : int { NoNewline = 0x01, AutoPrefix = 0x02, AssertOnCall = 0x04 @@ -248,45 +251,31 @@ public: return (int(LogOptions::AutoPrefix) | (aWithAssert ? int(LogOptions::AssertOnCall) : 0)); } // Note that we're calling BasicLogger::ShouldOutputMessage, rather than // Logger::ShouldOutputMessage. Since we currently don't have a different // version of that method for different loggers, this is OK. Once we do, // change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage. - explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL)) - : mOptions(aOptions) - , mLogIt(BasicLogger::ShouldOutputMessage(L)) - { - if (mLogIt && AutoPrefix()) { - if (mOptions & int(LogOptions::AssertOnCall)) { - mMessage << "[GFX" << L << "]: "; - } else { - mMessage << "[GFX" << L << "-]: "; - } - } + explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL)) { + Init(aOptions, BasicLogger::ShouldOutputMessage(L)); } + ~Log() { Flush(); } void Flush() { if (MOZ_LIKELY(!LogIt())) return; std::string str = mMessage.str(); if (!str.empty()) { WriteLog(str); } - if (AutoPrefix()) { - mMessage.str("[GFX"); - mMessage << L << "]: "; - } else { - mMessage.str(""); - } mMessage.clear(); } Log &operator <<(char aChar) { if (MOZ_UNLIKELY(LogIt())) { mMessage << aChar; } return *this; @@ -473,18 +462,34 @@ public: } return *this; } inline bool LogIt() const { return mLogIt; } inline bool NoNewline() const { return mOptions & int(LogOptions::NoNewline); } inline bool AutoPrefix() const { return mOptions & int(LogOptions::AutoPrefix); } + // We do not want this version to do any work, and stringstream can't be + // copied anyway. It does come in handy for the "Once" macro defined below. + MOZ_IMPLICIT Log(const Log& log) { Init(log.mOptions, false); } private: + // Initialization common to two constructors + void Init(int aOptions, bool aLogIt) { + mOptions = aOptions; + mLogIt = aLogIt; + if (mLogIt && AutoPrefix()) { + if (mOptions & int(LogOptions::AssertOnCall)) { + mMessage << "[GFX" << L << "]: "; + } else { + mMessage << "[GFX" << L << "-]: "; + } + } + } + void WriteLog(const std::string &aString) { if (MOZ_UNLIKELY(LogIt())) { Logger::OutputMessage(aString, L, NoNewline()); if (mOptions & int(LogOptions::AssertOnCall)) { MOZ_ASSERT(false, "An assert from the graphics logger"); } } } @@ -493,30 +498,50 @@ private: int mOptions; bool mLogIt; }; typedef Log<LOG_DEBUG> DebugLog; typedef Log<LOG_WARNING> WarningLog; typedef Log<LOG_CRITICAL, CriticalLogger> CriticalLog; +// Macro to glue names to get us less chance of name clashing. +#if defined GFX_LOGGING_GLUE1 || defined GFX_LOGGING_GLUE +#error "Clash of the macro GFX_LOGGING_GLUE1 or GFX_LOGGING_GLUE" +#endif +#define GFX_LOGGING_GLUE1(x, y) x##y +#define GFX_LOGGING_GLUE(x, y) GFX_LOGGING_GLUE1(x, y) + +// This log goes into crash reports, use with care. +#define gfxCriticalError mozilla::gfx::CriticalLog +#define gfxCriticalErrorOnce static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxCriticalError + +// The "once" versions will only trigger the first time through. You can do this: +// gfxCriticalErrorOnce() << "This message only shows up once; +// instead of the usual: +// static bool firstTime = true; +// if (firstTime) { +// firstTime = false; +// gfxCriticalError() << "This message only shows up once; +// } #ifdef GFX_LOG_DEBUG #define gfxDebug mozilla::gfx::DebugLog +#define gfxDebugOnce static gfxDebug GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxDebug #else #define gfxDebug if (1) ; else mozilla::gfx::NoLog +#define gfxDebugOnce if (1) ; else mozilla::gfx::NoLog #endif #ifdef GFX_LOG_WARNING #define gfxWarning mozilla::gfx::WarningLog +#define gfxWarningOnce static gfxWarning GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxWarning #else #define gfxWarning if (1) ; else mozilla::gfx::NoLog +#define gfxWarningOnce if (1) ; else mozilla::gfx::NoLog #endif -// This log goes into crash reports, use with care. -#define gfxCriticalError mozilla::gfx::CriticalLog - // See nsDebug.h and the NS_WARN_IF macro #ifdef __cplusplus // For now, have MOZ2D_ERROR_IF available in debug and non-debug builds inline bool MOZ2D_error_if_impl(bool aCondition, const char* aExpr, const char* aFile, int32_t aLine) { if (MOZ_UNLIKELY(aCondition)) {
--- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -8,17 +8,17 @@ #include <stdint.h> // for uint32_t #include "apz/src/AsyncPanZoomController.h" #include "FrameMetrics.h" // for FrameMetrics #include "LayerManagerComposite.h" // for LayerManagerComposite, etc #include "Layers.h" // for Layer, ContainerLayer, etc #include "gfxPoint.h" // for gfxPoint, gfxSize #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc #include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation -#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly +#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadOnly #include "mozilla/gfx/BaseRect.h" // for BaseRect #include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped #include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "nsCoord.h" // for NSAppUnitsToFloatPixels, etc @@ -469,17 +469,17 @@ SampleAnimations(Layer* aLayer, TimeStam timing.mDirection = animation.direction(); // Animations typically only run on the compositor during their active // interval but if we end up sampling them outside that range (for // example, while they are waiting to be removed) we currently just // assume that we should fill. timing.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_BOTH; ComputedTiming computedTiming = - dom::KeyframeEffectReadonly::GetComputedTimingAt( + dom::KeyframeEffectReadOnly::GetComputedTimingAt( Nullable<TimeDuration>(elapsedDuration), timing); MOZ_ASSERT(0.0 <= computedTiming.mTimeFraction && computedTiming.mTimeFraction <= 1.0, "time fraction should be in [0-1]"); int segmentIndex = 0; AnimationSegment* segment = animation.segments().Elements();
--- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -981,17 +981,18 @@ EnableScreenConfigurationNotifications() void DisableScreenConfigurationNotifications() { } void GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration) { - *aScreenConfiguration = nsScreenGonk::GetConfiguration(); + nsRefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); + *aScreenConfiguration = screen->GetConfiguration(); } bool LockScreenOrientation(const dom::ScreenOrientation& aOrientation) { return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation); }
--- a/image/src/DynamicImage.cpp +++ b/image/src/DynamicImage.cpp @@ -19,22 +19,16 @@ using namespace mozilla::gfx; using mozilla::layers::LayerManager; using mozilla::layers::ImageContainer; namespace mozilla { namespace image { // Inherited methods from Image. -nsresult -DynamicImage::Init(const char* aMimeType, uint32_t aFlags) -{ - return NS_OK; -} - already_AddRefed<ProgressTracker> DynamicImage::GetProgressTracker() { return nullptr; } size_t DynamicImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
--- a/image/src/DynamicImage.h +++ b/image/src/DynamicImage.h @@ -26,18 +26,16 @@ public: explicit DynamicImage(gfxDrawable* aDrawable) : mDrawable(aDrawable) { MOZ_ASSERT(aDrawable, "Must have a gfxDrawable to wrap"); } // Inherited methods from Image. - virtual nsresult Init(const char* aMimeType, uint32_t aFlags) override; - virtual already_AddRefed<ProgressTracker> GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) const override; virtual void IncrementAnimationConsumers() override; virtual void DecrementAnimationConsumers() override;
--- a/image/src/Image.cpp +++ b/image/src/Image.cpp @@ -58,16 +58,22 @@ ImageResource::ImageResource(ImageURL* a mInnerWindowId(0), mAnimationConsumers(0), mAnimationMode(kNormalAnimMode), mInitialized(false), mAnimating(false), mError(false) { } +ImageResource::~ImageResource() +{ + // Ask our ProgressTracker to drop its weak reference to us. + mProgressTracker->ResetImage(); +} + // Translates a mimetype into a concrete decoder Image::eDecoderType Image::GetDecoderType(const char* aMimeType) { // By default we don't know eDecoderType rv = eDecoderType_unknown; // PNG
--- a/image/src/Image.h +++ b/image/src/Image.h @@ -168,25 +168,16 @@ public: */ static const uint32_t INIT_FLAG_NONE = 0x0; static const uint32_t INIT_FLAG_DISCARDABLE = 0x1; static const uint32_t INIT_FLAG_DECODE_ONLY_ON_DRAW = 0x2; static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x4; static const uint32_t INIT_FLAG_TRANSIENT = 0x8; static const uint32_t INIT_FLAG_DOWNSCALE_DURING_DECODE = 0x10; - /** - * Creates a new image container. - * - * @param aMimeType The mimetype of the image. - * @param aFlags Initialization flags of the INIT_FLAG_* variety. - */ - virtual nsresult Init(const char* aMimeType, - uint32_t aFlags) = 0; - virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0; virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {} /** * The size, in bytes, occupied by the compressed source data of the image. * If MallocSizeOf does not work on this platform, uses a fallback approach to * ensure that something reasonable is always returned. */ @@ -293,16 +284,17 @@ public: /* * Returns a non-AddRefed pointer to the URI associated with this image. * Illegal to use off-main-thread. */ virtual ImageURL* GetURI() override { return mURI.get(); } protected: explicit ImageResource(ImageURL* aURI); + ~ImageResource(); // Shared functionality for implementors of imgIContainer. Every // implementation of attribute animationMode should forward here. nsresult GetAnimationModeInternal(uint16_t* aAnimationMode); nsresult SetAnimationModeInternal(uint16_t aAnimationMode); /** * Helper for RequestRefresh.
--- a/image/src/ImageFactory.cpp +++ b/image/src/ImageFactory.cpp @@ -9,16 +9,17 @@ #include "mozilla/Likely.h" #include "nsIHttpChannel.h" #include "nsIFileChannel.h" #include "nsIFile.h" #include "nsMimeTypes.h" #include "nsIRequest.h" +#include "MultipartImage.h" #include "RasterImage.h" #include "VectorImage.h" #include "Image.h" #include "nsMediaFragmentURIParser.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" #include "ImageFactory.h" @@ -144,22 +145,42 @@ BadImage(nsRefPtr<T>& image) /* static */ already_AddRefed<Image> ImageFactory::CreateAnonymousImage(const nsCString& aMimeType) { nsresult rv; nsRefPtr<RasterImage> newImage = new RasterImage(); + nsRefPtr<ProgressTracker> newTracker = new ProgressTracker(); + newTracker->SetImage(newImage); + newImage->SetProgressTracker(newTracker); + rv = newImage->Init(aMimeType.get(), Image::INIT_FLAG_NONE); NS_ENSURE_SUCCESS(rv, BadImage(newImage)); return newImage.forget(); } +/* static */ already_AddRefed<MultipartImage> +ImageFactory::CreateMultipartImage(Image* aFirstPart, + ProgressTracker* aProgressTracker) +{ + MOZ_ASSERT(aFirstPart); + MOZ_ASSERT(aProgressTracker); + + nsRefPtr<MultipartImage> newImage = new MultipartImage(aFirstPart); + aProgressTracker->SetImage(newImage); + newImage->SetProgressTracker(aProgressTracker); + + newImage->Init(); + + return newImage.forget(); +} + int32_t SaturateToInt32(int64_t val) { if (val > INT_MAX) { return INT_MAX; } if (val < INT_MIN) { return INT_MIN; @@ -201,19 +222,23 @@ GetContentSize(nsIRequest* aRequest) /* static */ already_AddRefed<Image> ImageFactory::CreateRasterImage(nsIRequest* aRequest, ProgressTracker* aProgressTracker, const nsCString& aMimeType, ImageURL* aURI, uint32_t aImageFlags, uint32_t aInnerWindowId) { + MOZ_ASSERT(aProgressTracker); + nsresult rv; - nsRefPtr<RasterImage> newImage = new RasterImage(aProgressTracker, aURI); + nsRefPtr<RasterImage> newImage = new RasterImage(aURI); + aProgressTracker->SetImage(newImage); + newImage->SetProgressTracker(aProgressTracker); rv = newImage->Init(aMimeType.get(), aImageFlags); NS_ENSURE_SUCCESS(rv, BadImage(newImage)); newImage->SetInnerWindowID(aInnerWindowId); uint32_t len = GetContentSize(aRequest); @@ -263,19 +288,23 @@ ImageFactory::CreateRasterImage(nsIReque /* static */ already_AddRefed<Image> ImageFactory::CreateVectorImage(nsIRequest* aRequest, ProgressTracker* aProgressTracker, const nsCString& aMimeType, ImageURL* aURI, uint32_t aImageFlags, uint32_t aInnerWindowId) { + MOZ_ASSERT(aProgressTracker); + nsresult rv; - nsRefPtr<VectorImage> newImage = new VectorImage(aProgressTracker, aURI); + nsRefPtr<VectorImage> newImage = new VectorImage(aURI); + aProgressTracker->SetImage(newImage); + newImage->SetProgressTracker(aProgressTracker); rv = newImage->Init(aMimeType.get(), aImageFlags); NS_ENSURE_SUCCESS(rv, BadImage(newImage)); newImage->SetInnerWindowID(aInnerWindowId); rv = newImage->OnStartRequest(aRequest, nullptr); NS_ENSURE_SUCCESS(rv, BadImage(newImage));
--- a/image/src/ImageFactory.h +++ b/image/src/ImageFactory.h @@ -13,16 +13,17 @@ class nsCString; class nsIRequest; namespace mozilla { namespace image { class Image; class ImageURL; +class MultipartImage; class ProgressTracker; class ImageFactory { public: /** * Registers vars with Preferences. Should only be called on the main thread. */ @@ -49,16 +50,28 @@ public: * Creates a new image which isn't associated with a URI or loaded through * the usual image loading mechanism. * * @param aMimeType The mimetype of the image. */ static already_AddRefed<Image> CreateAnonymousImage(const nsCString& aMimeType); + /** + * Creates a new multipart/x-mixed-replace image wrapper, and initializes it + * with the first part. Subsequent parts should be passed to the existing + * MultipartImage via MultipartImage::BeginTransitionToPart(). + * + * @param aFirstPart An image containing the first part of the multipart + * stream. + * @param aProgressTracker A progress tracker for the multipart image. + */ + static already_AddRefed<MultipartImage> + CreateMultipartImage(Image* aFirstPart, ProgressTracker* aProgressTracker); + private: // Factory functions that create specific types of image containers. static already_AddRefed<Image> CreateRasterImage(nsIRequest* aRequest, ProgressTracker* aProgressTracker, const nsCString& aMimeType, ImageURL* aURI, uint32_t aImageFlags,
--- a/image/src/ImageWrapper.cpp +++ b/image/src/ImageWrapper.cpp @@ -16,22 +16,16 @@ using gfx::DataSourceSurface; using gfx::SourceSurface; using layers::LayerManager; using layers::ImageContainer; namespace image { // Inherited methods from Image. -nsresult -ImageWrapper::Init(const char* aMimeType, uint32_t aFlags) -{ - return mInnerImage->Init(aMimeType, aFlags); -} - already_AddRefed<ProgressTracker> ImageWrapper::GetProgressTracker() { return mInnerImage->GetProgressTracker(); } size_t ImageWrapper::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
--- a/image/src/ImageWrapper.h +++ b/image/src/ImageWrapper.h @@ -17,18 +17,16 @@ namespace image { */ class ImageWrapper : public Image { public: NS_DECL_ISUPPORTS NS_DECL_IMGICONTAINER // Inherited methods from Image. - virtual nsresult Init(const char* aMimeType, uint32_t aFlags) override; - virtual already_AddRefed<ProgressTracker> GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) const override; virtual void IncrementAnimationConsumers() override;
--- a/image/src/MultipartImage.cpp +++ b/image/src/MultipartImage.cpp @@ -98,33 +98,42 @@ private: nsRefPtr<Image> mImage; }; /////////////////////////////////////////////////////////////////////////////// // Implementation /////////////////////////////////////////////////////////////////////////////// -MultipartImage::MultipartImage(Image* aImage, ProgressTracker* aTracker) - : ImageWrapper(aImage) +MultipartImage::MultipartImage(Image* aFirstPart) + : ImageWrapper(aFirstPart) , mDeferNotifications(false) { - MOZ_ASSERT(aTracker); - mProgressTrackerInit = new ProgressTrackerInit(this, aTracker); mNextPartObserver = new NextPartObserver(this); +} + +void +MultipartImage::Init() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mTracker, "Should've called SetProgressTracker() by now"); // Start observing the first part. nsRefPtr<ProgressTracker> firstPartTracker = InnerImage()->GetProgressTracker(); firstPartTracker->AddObserver(this); InnerImage()->RequestDecode(); InnerImage()->IncrementAnimationConsumers(); } -MultipartImage::~MultipartImage() { } +MultipartImage::~MultipartImage() +{ + // Ask our ProgressTracker to drop its weak reference to us. + mTracker->ResetImage(); +} NS_IMPL_QUERY_INTERFACE_INHERITED0(MultipartImage, ImageWrapper) NS_IMPL_ADDREF(MultipartImage) NS_IMPL_RELEASE(MultipartImage) void MultipartImage::BeginTransitionToPart(Image* aNextPart) { @@ -141,32 +150,42 @@ MultipartImage::BeginTransitionToPart(Im // Start observing the next part; we'll complete the transition when // NextPartObserver calls FinishTransition. mNextPartObserver->BeginObserving(mNextPart); mNextPart->RequestDecode(); mNextPart->IncrementAnimationConsumers(); } -void MultipartImage::FinishTransition() +static Progress +FilterProgress(Progress aProgress) +{ + // Filter out onload blocking notifications, since we don't want to block + // onload for multipart images. + return aProgress & ~(FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED); +} + +void +MultipartImage::FinishTransition() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mNextPart, "Should have a next part here"); nsRefPtr<ProgressTracker> newCurrentPartTracker = mNextPart->GetProgressTracker(); if (newCurrentPartTracker->GetProgress() & FLAG_HAS_ERROR) { // This frame has an error; drop it. mNextPart = nullptr; // We still need to notify, though. mTracker->ResetForNewRequest(); nsRefPtr<ProgressTracker> currentPartTracker = InnerImage()->GetProgressTracker(); - mTracker->SyncNotifyProgress(currentPartTracker->GetProgress()); + mTracker + ->SyncNotifyProgress(FilterProgress(currentPartTracker->GetProgress())); return; } // Stop observing the current part. { nsRefPtr<ProgressTracker> currentPartTracker = InnerImage()->GetProgressTracker(); @@ -176,18 +195,19 @@ void MultipartImage::FinishTransition() // Make the next part become the current part. mTracker->ResetForNewRequest(); SetInnerImage(mNextPart); mNextPart = nullptr; newCurrentPartTracker->AddObserver(this); // Finally, send all the notifications for the new current part and send a // FRAME_UPDATE notification so that observers know to redraw. - mTracker->SyncNotifyProgress(newCurrentPartTracker->GetProgress(), - GetMaxSizedIntRect()); + mTracker + ->SyncNotifyProgress(FilterProgress(newCurrentPartTracker->GetProgress()), + GetMaxSizedIntRect()); } already_AddRefed<imgIContainer> MultipartImage::Unwrap() { // Although we wrap another image, we don't allow callers to unwrap as. As far // as external code is concerned, MultipartImage is atomic. nsCOMPtr<imgIContainer> image = this;
--- a/image/src/MultipartImage.h +++ b/image/src/MultipartImage.h @@ -22,18 +22,16 @@ class NextPartObserver; class MultipartImage : public ImageWrapper , public IProgressObserver { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(MultipartImage) NS_DECL_ISUPPORTS - MultipartImage(Image* aImage, ProgressTracker* aTracker); - void BeginTransitionToPart(Image* aNextPart); // Overridden ImageWrapper methods: virtual already_AddRefed<imgIContainer> Unwrap() override; virtual already_AddRefed<ProgressTracker> GetProgressTracker() override; virtual void SetProgressTracker(ProgressTracker* aTracker) override; virtual nsresult OnImageDataAvailable(nsIRequest* aRequest, nsISupports* aContext, @@ -68,22 +66,25 @@ public: // methods to do nothing. virtual void BlockOnload() override { } virtual void UnblockOnload() override { } protected: virtual ~MultipartImage(); private: + friend class ImageFactory; friend class NextPartObserver; + explicit MultipartImage(Image* aFirstPart); + void Init(); + void FinishTransition(); nsRefPtr<ProgressTracker> mTracker; - nsAutoPtr<ProgressTrackerInit> mProgressTrackerInit; nsRefPtr<NextPartObserver> mNextPartObserver; nsRefPtr<Image> mNextPart; bool mDeferNotifications : 1; }; } // namespace image } // namespace mozilla
--- a/image/src/ProgressTracker.cpp +++ b/image/src/ProgressTracker.cpp @@ -17,36 +17,16 @@ #include "mozilla/Assertions.h" #include "mozilla/Services.h" using mozilla::WeakPtr; namespace mozilla { namespace image { -ProgressTrackerInit::ProgressTrackerInit(Image* aImage, - ProgressTracker* aTracker) -{ - MOZ_ASSERT(aImage); - - if (aTracker) { - mTracker = aTracker; - } else { - mTracker = new ProgressTracker(); - } - mTracker->SetImage(aImage); - aImage->SetProgressTracker(mTracker); - MOZ_ASSERT(mTracker); -} - -ProgressTrackerInit::~ProgressTrackerInit() -{ - mTracker->ResetImage(); -} - static void CheckProgressConsistency(Progress aProgress) { // Check preconditions for every progress bit. if (aProgress & FLAG_SIZE_AVAILABLE) { // No preconditions. }
--- a/image/src/ProgressTracker.h +++ b/image/src/ProgressTracker.h @@ -153,32 +153,31 @@ public: return mObservers.Length(); } // This is intentionally non-general because its sole purpose is to support // some obscure network priority logic in imgRequest. That stuff could // probably be improved, but it's too scary to mess with at the moment. bool FirstObserverIs(IProgressObserver* aObserver); + // Resets our weak reference to our image. Image subclasses should call this + // in their destructor. + void ResetImage(); + private: typedef nsTObserverArray<mozilla::WeakPtr<IProgressObserver>> ObserverArray; friend class AsyncNotifyRunnable; friend class AsyncNotifyCurrentStateRunnable; - friend class ProgressTrackerInit; + friend class ImageFactory; ProgressTracker(const ProgressTracker& aOther) = delete; - // This method should only be called once, and only on an ProgressTracker - // that was initialized without an image. ProgressTrackerInit automates this. + // Sets our weak reference to our image. Only ImageFactory should call this. void SetImage(Image* aImage); - // Resets our weak reference to our image, for when mImage is about to go out - // of scope. ProgressTrackerInit automates this. - void ResetImage(); - // Send some notifications that would be necessary to make |aObserver| believe // the request is finished downloading and decoding. We only send // FLAG_LOAD_COMPLETE and FLAG_ONLOAD_UNBLOCKED, and only if necessary. void EmulateRequestFinished(IProgressObserver* aObserver); // Main thread only because it deals with the observer service. void FireFailureNotification(); @@ -196,21 +195,12 @@ private: // List of observers attached to the image. Each observer represents a // consumer using the image. Array and/or individual elements should only be // accessed on the main thread. ObserverArray mObservers; Progress mProgress; }; -class ProgressTrackerInit -{ -public: - ProgressTrackerInit(Image* aImage, ProgressTracker* aTracker); - ~ProgressTrackerInit(); -private: - ProgressTracker* mTracker; -}; - } // namespace image } // namespace mozilla #endif // mozilla_image_src_ProgressTracker_h
--- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -245,18 +245,17 @@ static nsCOMPtr<nsIThread> sScaleWorkerT #ifndef DEBUG NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties) #else NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties, imgIContainerDebug) #endif //****************************************************************************** -RasterImage::RasterImage(ProgressTracker* aProgressTracker, - ImageURL* aURI /* = nullptr */) : +RasterImage::RasterImage(ImageURL* aURI /* = nullptr */) : ImageResource(aURI), // invoke superclass's constructor mSize(0,0), mLockCount(0), mDecodeCount(0), mRequestedSampleSize(0), mLastImageContainerDrawResult(DrawResult::NOT_READY), #ifdef DEBUG mFramesNotified(0), @@ -268,18 +267,16 @@ RasterImage::RasterImage(ProgressTracker mTransient(false), mDiscardable(false), mHasSourceData(false), mHasBeenDecoded(false), mPendingAnimation(false), mAnimationFinished(false), mWantFullDecode(false) { - mProgressTrackerInit = new ProgressTrackerInit(this, aProgressTracker); - Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0); } //****************************************************************************** RasterImage::~RasterImage() { // Make sure our SourceBuffer is marked as complete. This will ensure that any // outstanding decoders terminate.
--- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -161,19 +161,16 @@ public: #ifdef DEBUG NS_DECL_IMGICONTAINERDEBUG #endif virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; // Methods inherited from Image - nsresult Init(const char* aMimeType, - uint32_t aFlags) override; - virtual void OnSurfaceDiscarded() override; // Raster-specific methods static NS_METHOD WriteToSourceBuffer(nsIInputStream* aIn, void* aClosure, const char* aFromRawSegment, uint32_t aToOffset, uint32_t aCount, uint32_t* aWriteCount); @@ -283,16 +280,18 @@ public: nsCString spec; if (GetURI()) { GetURI()->GetSpec(spec); } return spec; } private: + nsresult Init(const char* aMimeType, uint32_t aFlags); + DrawResult DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef, gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, GraphicsFilter aFilter, uint32_t aFlags); TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame, @@ -420,19 +419,16 @@ private: // data bool mAnimationFinished:1; // Whether, once we are done doing a size decode, we should immediately kick // off a full decode. bool mWantFullDecode:1; TimeStamp mDrawStartTime; - // Initializes ProgressTracker and resets it on RasterImage destruction. - nsAutoPtr<ProgressTrackerInit> mProgressTrackerInit; - ////////////////////////////////////////////////////////////////////////////// // Scaling. ////////////////////////////////////////////////////////////////////////////// // Initiates an HQ scale for the given frame, if possible. void RequestScale(imgFrame* aFrame, uint32_t aFlags, const nsIntSize& aSize); @@ -470,18 +466,17 @@ private: // data nsRefPtr<RasterImage> mImage; }; // Helpers bool CanDiscard(); protected: - explicit RasterImage(ProgressTracker* aProgressTracker = nullptr, - ImageURL* aURI = nullptr); + explicit RasterImage(ImageURL* aURI = nullptr); bool ShouldAnimate() override; friend class ImageFactory; }; inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t* aAnimationMode) {
--- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -322,28 +322,25 @@ SVGDrawingCallback::operator()(gfxContex NS_IMPL_ISUPPORTS(VectorImage, imgIContainer, nsIStreamListener, nsIRequestObserver) //------------------------------------------------------------------------------ // Constructor / Destructor -VectorImage::VectorImage(ProgressTracker* aProgressTracker, - ImageURL* aURI /* = nullptr */) : +VectorImage::VectorImage(ImageURL* aURI /* = nullptr */) : ImageResource(aURI), // invoke superclass's constructor mLockCount(0), mIsInitialized(false), mIsFullyLoaded(false), mIsDrawing(false), mHaveAnimations(false), mHasPendingInvalidation(false) -{ - mProgressTrackerInit = new ProgressTrackerInit(this, aProgressTracker); -} +{ } VectorImage::~VectorImage() { CancelAllListeners(); SurfaceCache::RemoveImage(ImageKey(this)); } //------------------------------------------------------------------------------
--- a/image/src/VectorImage.h +++ b/image/src/VectorImage.h @@ -29,19 +29,16 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_IMGICONTAINER // (no public constructor - use ImageFactory) // Methods inherited from Image - nsresult Init(const char* aMimeType, - uint32_t aFlags) override; - virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) const override; virtual nsresult OnImageDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aInStr, @@ -67,28 +64,29 @@ public: // Callback for SVGParseCompleteListener. void OnSVGDocumentParsed(); // Callbacks for SVGLoadEventListener. void OnSVGDocumentLoaded(); void OnSVGDocumentError(); protected: - explicit VectorImage(ProgressTracker* aProgressTracker = nullptr, - ImageURL* aURI = nullptr); + explicit VectorImage(ImageURL* aURI = nullptr); virtual ~VectorImage(); virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; virtual bool ShouldAnimate() override; void CreateSurfaceAndShow(const SVGDrawingParameters& aParams); void Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams); private: + nsresult Init(const char* aMimeType, uint32_t aFlags); + /** * In catastrophic circumstances like a GPU driver crash, we may lose our * surfaces even if they're locked. RecoverFromLossOfSurfaces discards all * existing surfaces, allowing us to recover. */ void RecoverFromLossOfSurfaces(); void CancelAllListeners(); @@ -107,19 +105,16 @@ private: bool mIsFullyLoaded; // Has the SVG document finished // loading? bool mIsDrawing; // Are we currently drawing? bool mHaveAnimations; // Is our SVG content SMIL-animated? // (Only set after mIsFullyLoaded.) bool mHasPendingInvalidation; // Invalidate observers next refresh // driver tick. - // Initializes ProgressTracker and resets it on RasterImage destruction. - nsAutoPtr<ProgressTrackerInit> mProgressTrackerInit; - friend class ImageFactory; }; inline NS_IMETHODIMP VectorImage::GetAnimationMode(uint16_t* aAnimationMode) { return GetAnimationModeInternal(aAnimationMode); } inline NS_IMETHODIMP VectorImage::SetAnimationMode(uint16_t aAnimationMode) {
--- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -972,17 +972,18 @@ PrepareForNewPart(nsIRequest* aRequest, nsRefPtr<Image> partImage = ImageFactory::CreateImage(aRequest, progressTracker, result.mContentType, aURI, /* aIsMultipart = */ true, aInnerWindowId); if (result.mIsFirstPart) { // First part for a multipart channel. Create the MultipartImage wrapper. MOZ_ASSERT(aProgressTracker, "Shouldn't have given away tracker yet"); - result.mImage = new MultipartImage(partImage, aProgressTracker); + result.mImage = + ImageFactory::CreateMultipartImage(partImage, aProgressTracker); } else { // Transition to the new part. auto multipartImage = static_cast<MultipartImage*>(aExistingImage); multipartImage->BeginTransitionToPart(partImage); } } else { MOZ_ASSERT(!aExistingImage, "New part for non-multipart channel?"); MOZ_ASSERT(aProgressTracker, "Shouldn't have given away tracker yet");
--- a/js/src/configure.in +++ b/js/src/configure.in @@ -1227,20 +1227,22 @@ if test "$GNU_CC"; then _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=parentheses" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-to-int-cast" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=switch" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs" + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=uninitialized" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas" _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=write-strings" MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_werror_non_literal_null_conversion) + MOZ_C_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_c_has_sometimes_uninitialized) fi # Turn off the following warnings that -Wall turns on: # -Wno-unused - lots of violations in third-party code # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc # _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused" @@ -1330,23 +1332,25 @@ if test "$GNU_CXX"; then _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=overloaded-virtual" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=reorder" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=uninitialized" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unknown-pragmas" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-value" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=write-strings" MOZ_CXX_SUPPORTS_WARNING(-Werror=, conversion-null, ac_cxx_has_werror_conversion_null) MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_werror_non_literal_null_conversion) + MOZ_CXX_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized) fi # Turn off the following warnings that -Wall turns on: # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently # _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof" if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then @@ -2912,24 +2916,21 @@ fi dnl ======================================================== dnl = Disable treating compiler warnings as errors dnl ======================================================== if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then WARNINGS_AS_ERRORS='' elif test "$GNU_CC"; then # Prevent the following GCC warnings from being treated as errors: - # -Wuninitialized - too many false positives # -Wmaybe-uninitialized - too many false positives # -Wdeprecated-declarations - we don't want our builds held hostage when a # platform-specific API becomes deprecated. # -Wfree-nonheap-object - false positives during PGO # -Warray-bounds - false positives depending on optimization - MOZ_C_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_c_has_noerror_uninitialized) - MOZ_CXX_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_cxx_has_noerror_uninitialized) MOZ_C_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_c_has_noerror_maybe_uninitialized) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_cxx_has_noerror_maybe_uninitialized) MOZ_C_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_c_has_noerror_deprecated_declarations) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_cxx_has_noerror_deprecated_declarations) MOZ_C_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_c_has_noerror_array_bounds) MOZ_CXX_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_cxx_has_noerror_array_bounds) if test -n "$MOZ_PGO"; then
--- a/js/src/devtools/automation/autospider.sh +++ b/js/src/devtools/automation/autospider.sh @@ -1,11 +1,14 @@ #!/bin/bash + +# Note that the -x will be temporarily cancelled and reinstated below, so if +# you want to eliminate this, you'll need to eliminate it there too. +set -x set -e -set -x DIR="$(dirname $0)" ABSDIR="$(cd $DIR; pwd)" SOURCE="$(cd $DIR/../../../..; pwd)" function usage() { echo "Usage: $0 [--dep] <variant>" } @@ -138,17 +141,19 @@ RUN_JSTESTS=true PARENT=$$ # Spawn off a child process, detached from any of our fds, that will kill us after a timeout. # To report the timeout, catch the signal in the parent before exiting. sh -c "sleep $TIMEOUT; kill -INT $PARENT" <&- >&- 2>&- & KILLER=$! disown %1 +set +x trap "echo 'TEST-UNEXPECTED-FAIL | autospider.sh $TIMEOUT timeout | ignore later failures' >&2; exit 1" INT +set -x # If we do *not* hit that timeout, kill off the spawned process on a regular exit. trap "kill $KILLER" EXIT if [[ "$VARIANT" = "rootanalysis" ]]; then export JS_GC_ZEAL=7 elif [[ "$VARIANT" = "compacting" ]]; then
--- a/js/src/devtools/automation/cgc-jittest-timeouts.txt +++ b/js/src/devtools/automation/cgc-jittest-timeouts.txt @@ -2,16 +2,17 @@ asm.js/testParallelCompile.js auto-regress/bug653395.js auto-regress/bug675251.js baseline/bug847446.js baseline/bug852175.js basic/bug632964-regexp.js basic/bug677957-2.js basic/testBug614653.js basic/testBug686274.js +basic/testManyVars.js basic/testTypedArrayInit.js gc/bug-1014972.js gc/bug-906236.js gc/bug-906241.js ion/bug787921.js parallel/alloc-many-objs.js parallel/alloc-too-many-objs.js self-test/assertDeepEq.js
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4799,17 +4799,16 @@ Parser<FullParseHandler>::forStatement() * Parse the rest of the for/in or for/of head. * * Here pn1 is everything to the left of 'in' or 'of'. At the end of * this block, pn1 is a decl or nullptr, pn2 is the assignment target * that receives the enumeration value each iteration, and pn3 is the * rhs of 'in'. */ if (headKind == PNK_FOROF) { - forStmt.type = STMT_FOR_OF_LOOP; forStmt.type = (headKind == PNK_FOROF) ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP; if (isForEach) { report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP); return null(); } } else { forStmt.type = STMT_FOR_IN_LOOP; iflags |= JSITER_ENUMERATE;
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -661,16 +661,27 @@ template <typename S, typename T> void js::GCMarker::traverse(S source, T target) { MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(target), runtime()->isAtomsZone(target->zone()) || target->zone() == source->zone()); traverse(target); } +namespace js { +// Special-case JSObject->JSObject edges to check the compartment too. +template <> +void +GCMarker::traverse(JSObject* source, JSObject* target) +{ + MOZ_ASSERT(target->compartment() == source->compartment()); + traverse(target); +} +} // namespace js + template <typename V, typename S> struct TraverseFunctor : public VoidDefaultAdaptor<V> { template <typename T> void operator()(T t, GCMarker* gcmarker, S s) { return gcmarker->traverse(s, t); } }; template <typename S> void @@ -770,16 +781,192 @@ js::GCMarker::eagerlyMarkChildren(Shape* traverse(shape, shape->getterObject()); if (shape->hasSetterObject() && shape->setterObject()->isTenured()) traverse(shape, shape->setterObject()); shape = shape->previous(); } while (shape && mark(shape)); } +void +JSString::traceChildren(JSTracer* trc) +{ + if (hasBase()) + traceBase(trc); + else if (isRope()) + asRope().traceChildren(trc); +} +inline void +GCMarker::eagerlyMarkChildren(JSString* str) +{ + if (str->isLinear()) + eagerlyMarkChildren(&str->asLinear()); + else + eagerlyMarkChildren(&str->asRope()); +} + +void +JSString::traceBase(JSTracer* trc) +{ + MOZ_ASSERT(hasBase()); + TraceManuallyBarrieredEdge(trc, &d.s.u3.base, "base"); +} +inline void +js::GCMarker::eagerlyMarkChildren(JSLinearString* linearStr) +{ + JS_COMPARTMENT_ASSERT(runtime(), linearStr); + MOZ_ASSERT(linearStr->isMarked()); + MOZ_ASSERT(linearStr->JSString::isLinear()); + + // Use iterative marking to avoid blowing out the stack. + while (linearStr->hasBase()) { + linearStr = linearStr->base(); + MOZ_ASSERT(linearStr->JSString::isLinear()); + if (linearStr->isPermanentAtom()) + break; + JS_COMPARTMENT_ASSERT(runtime(), linearStr); + if (!mark(static_cast<JSString*>(linearStr))) + break; + } +} + +void +JSRope::traceChildren(JSTracer* trc) { + js::TraceManuallyBarrieredEdge(trc, &d.s.u2.left, "left child"); + js::TraceManuallyBarrieredEdge(trc, &d.s.u3.right, "right child"); +} +inline void +js::GCMarker::eagerlyMarkChildren(JSRope* rope) +{ + // This function tries to scan the whole rope tree using the marking stack + // as temporary storage. If that becomes full, the unscanned ropes are + // added to the delayed marking list. When the function returns, the + // marking stack is at the same depth as it was on entry. This way we avoid + // using tags when pushing ropes to the stack as ropes never leak to other + // users of the stack. This also assumes that a rope can only point to + // other ropes or linear strings, it cannot refer to GC things of other + // types. + ptrdiff_t savedPos = stack.position(); + JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); + while (true) { + JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); + JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope()); + JS_COMPARTMENT_ASSERT(runtime(), rope); + MOZ_ASSERT(rope->isMarked()); + JSRope* next = nullptr; + + JSString* right = rope->rightChild(); + if (!right->isPermanentAtom() && + mark(right)) + { + if (right->isLinear()) + eagerlyMarkChildren(&right->asLinear()); + else + next = &right->asRope(); + } + + JSString* left = rope->leftChild(); + if (!left->isPermanentAtom() && + mark(left)) + { + if (left->isLinear()) { + eagerlyMarkChildren(&left->asLinear()); + } else { + // When both children are ropes, set aside the right one to + // scan it later. + if (next && !stack.push(reinterpret_cast<uintptr_t>(next))) + delayMarkingChildren(next); + next = &left->asRope(); + } + } + if (next) { + rope = next; + } else if (savedPos != stack.position()) { + MOZ_ASSERT(savedPos < stack.position()); + rope = reinterpret_cast<JSRope*>(stack.pop()); + } else { + break; + } + } + MOZ_ASSERT(savedPos == stack.position()); +} + +void +js::ObjectGroup::traceChildren(JSTracer* trc) +{ + unsigned count = getPropertyCount(); + for (unsigned i = 0; i < count; i++) { + if (ObjectGroup::Property* prop = getProperty(i)) + TraceEdge(trc, &prop->id, "group_property"); + } + + if (proto().isObject()) + TraceEdge(trc, &protoRaw(), "group_proto"); + + if (newScript()) + newScript()->trace(trc); + + if (maybePreliminaryObjects()) + maybePreliminaryObjects()->trace(trc); + + if (maybeUnboxedLayout()) + unboxedLayout().trace(trc); + + if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) { + TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group"); + setOriginalUnboxedGroup(unboxedGroup); + } + + if (JSObject* descr = maybeTypeDescr()) { + TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr"); + setTypeDescr(&descr->as<TypeDescr>()); + } + + if (JSObject* fun = maybeInterpretedFunction()) { + TraceManuallyBarrieredEdge(trc, &fun, "group_function"); + setInterpretedFunction(&fun->as<JSFunction>()); + } +} +void +js::GCMarker::lazilyMarkChildren(ObjectGroup* group) +{ + unsigned count = group->getPropertyCount(); + for (unsigned i = 0; i < count; i++) { + if (ObjectGroup::Property* prop = group->getProperty(i)) + traverse(group, prop->id.get()); + } + + if (group->proto().isObject()) + traverse(group, group->proto().toObject()); + + group->compartment()->mark(); + + if (GlobalObject* global = group->compartment()->unsafeUnbarrieredMaybeGlobal()) + traverse(group, static_cast<JSObject*>(global)); + + if (group->newScript()) + group->newScript()->trace(this); + + if (group->maybePreliminaryObjects()) + group->maybePreliminaryObjects()->trace(this); + + if (group->maybeUnboxedLayout()) + group->unboxedLayout().trace(this); + + if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) + traverse(group, unboxedGroup); + + if (TypeDescr* descr = group->maybeTypeDescr()) + traverse(group, static_cast<JSObject*>(descr)); + + if (JSFunction* fun = group->maybeInterpretedFunction()) + traverse(group, static_cast<JSObject*>(fun)); +} + + template <typename T> static inline void CheckIsMarkedThing(T* thingp) { #define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value || static_assert( FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) false, "Only the base cell layout types are allowed into marking/tracing internals"); @@ -1067,102 +1254,16 @@ gc::MarkValueForBarrier(JSTracer* trc, V void gc::MarkIdForBarrier(JSTracer* trc, jsid* idp, const char* name) { TraceManuallyBarrieredEdge(trc, idp, name); } /*** Push Mark Stack ***/ -static inline void -ScanLinearString(GCMarker* gcmarker, JSLinearString* str) -{ - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str); - MOZ_ASSERT(str->isMarked()); - - /* - * Add extra asserts to confirm the static type to detect incorrect string - * mutations. - */ - MOZ_ASSERT(str->JSString::isLinear()); - while (str->hasBase()) { - str = str->base(); - MOZ_ASSERT(str->JSString::isLinear()); - if (str->isPermanentAtom()) - break; - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str); - if (!str->markIfUnmarked()) - break; - } -} - -/* - * The function tries to scan the whole rope tree using the marking stack as - * temporary storage. If that becomes full, the unscanned ropes are added to - * the delayed marking list. When the function returns, the marking stack is - * at the same depth as it was on entry. This way we avoid using tags when - * pushing ropes to the stack as ropes never leaks to other users of the - * stack. This also assumes that a rope can only point to other ropes or - * linear strings, it cannot refer to GC things of other types. - */ -static void -ScanRope(GCMarker* gcmarker, JSRope* rope) -{ - ptrdiff_t savedPos = gcmarker->stack.position(); - JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); - for (;;) { - JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); - JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope()); - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), rope); - MOZ_ASSERT(rope->isMarked()); - JSRope* next = nullptr; - - JSString* right = rope->rightChild(); - if (!right->isPermanentAtom() && right->markIfUnmarked()) { - if (right->isLinear()) - ScanLinearString(gcmarker, &right->asLinear()); - else - next = &right->asRope(); - } - - JSString* left = rope->leftChild(); - if (!left->isPermanentAtom() && left->markIfUnmarked()) { - if (left->isLinear()) { - ScanLinearString(gcmarker, &left->asLinear()); - } else { - /* - * When both children are ropes, set aside the right one to - * scan it later. - */ - if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next))) - gcmarker->delayMarkingChildren(next); - next = &left->asRope(); - } - } - if (next) { - rope = next; - } else if (savedPos != gcmarker->stack.position()) { - MOZ_ASSERT(savedPos < gcmarker->stack.position()); - rope = reinterpret_cast<JSRope*>(gcmarker->stack.pop()); - } else { - break; - } - } - MOZ_ASSERT(savedPos == gcmarker->stack.position()); - } - -inline void -GCMarker::eagerlyMarkChildren(JSString* str) -{ - if (str->isLinear()) - ScanLinearString(this, &str->asLinear()); - else - ScanRope(this, &str->asRope()); -} - /* * This function is used by the cycle collector to trace through a * shape. The cycle collector does not care about shapes or base * shapes, so those are not marked. Instead, any shapes or base shapes * that are encountered have their children marked. Stack space is * bounded. */ void @@ -1273,89 +1374,16 @@ gc::MarkCycleCollectorChildren(JSTracer* TraceChildren(&groupTracer, group, JSTRACE_OBJECT_GROUP); while (!groupTracer.worklist.empty()) { ObjectGroup* innerGroup = groupTracer.worklist.popCopy(); TraceChildren(&groupTracer, innerGroup, JSTRACE_OBJECT_GROUP); } } -static void -ScanObjectGroup(GCMarker* gcmarker, ObjectGroup* group) -{ - unsigned count = group->getPropertyCount(); - for (unsigned i = 0; i < count; i++) { - if (ObjectGroup::Property* prop = group->getProperty(i)) - DoMarking(gcmarker, prop->id.get()); - } - - if (group->proto().isObject()) - gcmarker->traverse(group->proto().toObject()); - - group->compartment()->mark(); - - if (GlobalObject* global = group->compartment()->unsafeUnbarrieredMaybeGlobal()) - gcmarker->traverse(static_cast<JSObject*>(global)); - - if (group->newScript()) - group->newScript()->trace(gcmarker); - - if (group->maybePreliminaryObjects()) - group->maybePreliminaryObjects()->trace(gcmarker); - - if (group->maybeUnboxedLayout()) - group->unboxedLayout().trace(gcmarker); - - if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) - gcmarker->traverse(unboxedGroup); - - if (TypeDescr* descr = group->maybeTypeDescr()) - gcmarker->traverse(static_cast<JSObject*>(descr)); - - if (JSFunction* fun = group->maybeInterpretedFunction()) - gcmarker->traverse(static_cast<JSObject*>(fun)); -} - -void -js::ObjectGroup::traceChildren(JSTracer* trc) -{ - unsigned count = getPropertyCount(); - for (unsigned i = 0; i < count; i++) { - if (ObjectGroup::Property* prop = getProperty(i)) - TraceEdge(trc, &prop->id, "group_property"); - } - - if (proto().isObject()) - TraceEdge(trc, &protoRaw(), "group_proto"); - - if (newScript()) - newScript()->trace(trc); - - if (maybePreliminaryObjects()) - maybePreliminaryObjects()->trace(trc); - - if (maybeUnboxedLayout()) - unboxedLayout().trace(trc); - - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) { - TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group"); - setOriginalUnboxedGroup(unboxedGroup); - } - - if (JSObject* descr = maybeTypeDescr()) { - TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr"); - setTypeDescr(&descr->as<TypeDescr>()); - } - - if (JSObject* fun = maybeInterpretedFunction()) { - TraceManuallyBarrieredEdge(trc, &fun, "group_function"); - setInterpretedFunction(&fun->as<JSFunction>()); - } -} - template<typename T> static void PushArenaTyped(GCMarker* gcmarker, ArenaHeader* aheader) { for (ArenaCellIterUnderGC i(aheader); !i.done(); i.next()) gcmarker->traverse(i.get<T>()); } @@ -1506,74 +1534,79 @@ GCMarker::restoreValueArray(NativeObject *vpp = *endp = vp; } } MOZ_ASSERT(*vpp <= *endp); return true; } -void -GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr) -{ - if (tag == GroupTag) { - ScanObjectGroup(this, reinterpret_cast<ObjectGroup*>(addr)); - } else if (tag == SavedValueArrayTag) { - MOZ_ASSERT(!(addr & CellMask)); - NativeObject* obj = reinterpret_cast<NativeObject*>(addr); - HeapValue* vp; - HeapValue* end; - if (restoreValueArray(obj, (void**)&vp, (void**)&end)) - pushValueArray(obj, vp, end); - else - repush(obj); - } else if (tag == JitCodeTag) { - reinterpret_cast<jit::JitCode*>(addr)->traceChildren(this); - } -} - inline void GCMarker::processMarkStackTop(SliceBudget& budget) { /* * The function uses explicit goto and implements the scanning of the * object directly. It allows to eliminate the tail recursion and * significantly improve the marking performance, see bug 641025. */ HeapSlot* vp; HeapSlot* end; JSObject* obj; const int32_t* unboxedTraceList; uint8_t* unboxedMemory; + // Decode uintptr_t addr = stack.pop(); uintptr_t tag = addr & StackTagMask; addr &= ~StackTagMask; - if (tag == ValueArrayTag) { + // Dispatch + switch (tag) { + case ValueArrayTag: { JS_STATIC_ASSERT(ValueArrayTag == 0); MOZ_ASSERT(!(addr & CellMask)); obj = reinterpret_cast<JSObject*>(addr); uintptr_t addr2 = stack.pop(); uintptr_t addr3 = stack.pop(); MOZ_ASSERT(addr2 <= addr3); MOZ_ASSERT((addr3 - addr2) % sizeof(Value) == 0); vp = reinterpret_cast<HeapSlot*>(addr2); end = reinterpret_cast<HeapSlot*>(addr3); goto scan_value_array; - } + } - if (tag == ObjectTag) { + case ObjectTag: { obj = reinterpret_cast<JSObject*>(addr); JS_COMPARTMENT_ASSERT(runtime(), obj); goto scan_obj; - } + } + + case GroupTag: { + return lazilyMarkChildren(reinterpret_cast<ObjectGroup*>(addr)); + } + + case JitCodeTag: { + return reinterpret_cast<jit::JitCode*>(addr)->traceChildren(this); + } - processMarkStackOther(tag, addr); + case SavedValueArrayTag: { + MOZ_ASSERT(!(addr & CellMask)); + NativeObject* obj = reinterpret_cast<NativeObject*>(addr); + HeapValue* vp; + HeapValue* end; + if (restoreValueArray(obj, (void**)&vp, (void**)&end)) + pushValueArray(obj, vp, end); + else + repush(obj); + return; + } + + default: MOZ_CRASH("Invalid tag in mark stack"); + } return; scan_value_array: MOZ_ASSERT(vp <= end); while (vp != end) { budget.step(); if (budget.isOverBudget()) { pushValueArray(obj, vp, end); @@ -1604,30 +1637,27 @@ GCMarker::processMarkStackTop(SliceBudge JSString* str = *reinterpret_cast<JSString**>(unboxedMemory + *unboxedTraceList); traverse(obj, str); unboxedTraceList++; } unboxedTraceList++; while (*unboxedTraceList != -1) { JSObject* obj2 = *reinterpret_cast<JSObject**>(unboxedMemory + *unboxedTraceList); MOZ_ASSERT_IF(obj2, obj->compartment() == obj2->compartment()); - if (obj2 && mark(obj2)) - repush(obj2); + if (obj2) + traverse(obj, obj2); unboxedTraceList++; } unboxedTraceList++; while (*unboxedTraceList != -1) { const Value& v = *reinterpret_cast<Value*>(unboxedMemory + *unboxedTraceList); if (v.isString()) { traverse(obj, v.toString()); } else if (v.isObject()) { - JSObject* obj2 = &v.toObject(); - MOZ_ASSERT(obj->compartment() == obj2->compartment()); - if (mark(obj2)) - repush(obj2); + traverse(obj, &v.toObject()); } else if (v.isSymbol()) { traverse(obj, v.toSymbol()); } unboxedTraceList++; } return; } @@ -1637,69 +1667,69 @@ GCMarker::processMarkStackTop(SliceBudge budget.step(); if (budget.isOverBudget()) { repush(obj); return; } ObjectGroup* group = obj->groupFromGC(); - traverse(group); + traverse(obj, group); /* Call the trace hook if necessary. */ const Class* clasp = group->clasp(); if (clasp->trace) { // Global objects all have the same trace hook. That hook is safe without barriers // if the global has no custom trace hook of its own, or has been moved to a different // compartment, and so can't have one. MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook && (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())), clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS); if (clasp->trace == InlineTypedObject::obj_trace) { Shape* shape = obj->as<InlineTypedObject>().shapeFromGC(); - traverse(shape); + traverse(obj, shape); TypeDescr* descr = &obj->as<InlineTypedObject>().typeDescr(); if (!descr->hasTraceList()) return; unboxedTraceList = descr->traceList(); unboxedMemory = obj->as<InlineTypedObject>().inlineTypedMem(); goto scan_unboxed; } if (clasp == &UnboxedPlainObject::class_) { JSObject* expando = obj->as<UnboxedPlainObject>().maybeExpando(); - if (expando && mark(expando)) - repush(expando); + if (expando) + traverse(obj, expando); const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); unboxedTraceList = layout.traceList(); if (!unboxedTraceList) return; unboxedMemory = obj->as<UnboxedPlainObject>().data(); goto scan_unboxed; } clasp->trace(this, obj); } if (!clasp->isNative()) return; NativeObject* nobj = &obj->as<NativeObject>(); Shape* shape = nobj->lastProperty(); - traverse(shape); + traverse(obj, shape); unsigned nslots = nobj->slotSpan(); do { if (nobj->hasEmptyElements()) break; if (nobj->denseElementsAreCopyOnWrite()) { JSObject* owner = nobj->getElementsHeader()->ownerObject(); if (owner != nobj) { - traverse(owner); + traverse(obj, owner); break; } } vp = nobj->getDenseElementsAllowCopyOnWrite(); end = vp + nobj->getDenseInitializedLength(); if (!nslots) goto scan_value_array;
--- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -9,16 +9,18 @@ #include "mozilla/DebugOnly.h" #include "gc/Heap.h" #include "js/GCAPI.h" #include "js/SliceBudget.h" #include "js/TracingAPI.h" +class JSLinearString; +class JSRope; namespace js { class BaseShape; class GCMarker; class LazyScript; class NativeObject; class ObjectGroup; namespace gc { struct ArenaHeader; @@ -240,19 +242,22 @@ class GCMarker : public JSTracer void repush(JSObject* obj) { MOZ_ASSERT(gc::TenuredCell::fromPointer(obj)->isMarked(markColor())); pushTaggedPtr(ObjectTag, obj); } template <typename T> void markAndTraceChildren(T* thing); template <typename T> void markAndPush(StackTag tag, T* thing); template <typename T> void markAndScan(T* thing); - void eagerlyMarkChildren(Shape* shape); + void eagerlyMarkChildren(JSLinearString* str); + void eagerlyMarkChildren(JSRope* rope); void eagerlyMarkChildren(JSString* str); void eagerlyMarkChildren(LazyScript *thing); + void eagerlyMarkChildren(Shape* shape); + void lazilyMarkChildren(ObjectGroup* group); // We may not have concrete types yet, so this has to be out of the header. template <typename T> void dispatchToTraceChildren(T* thing); // Mark the given GC thing, but do not trace its children. Return true // if the thing became marked. template <typename T> @@ -284,17 +289,16 @@ class GCMarker : public JSTracer bool isMarkStackEmpty() { return stack.isEmpty(); } bool restoreValueArray(NativeObject* obj, void** vpp, void** endp); void saveValueRanges(); inline void processMarkStackTop(SliceBudget& budget); - void processMarkStackOther(uintptr_t tag, uintptr_t addr); /* The color is only applied to objects and functions. */ uint32_t color; /* Pointer to the top of the stack of arenas we are delaying marking on. */ js::gc::ArenaHeader* unmarkedArenaStackTop; /* Count of arenas that are currently in the stack. */
--- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -115,27 +115,27 @@ class GlobalObject : public NativeObject * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and * we won't expose GlobalObject, so just assert that the two values are * synchronized. */ static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, "global object slot counts are inconsistent"); enum WarnOnceFlag : int32_t { - WARN_WATCH_DEPRECATED = 0x00000001, - WARN_PROTO_SETTING_SLOW = 0x00000002, - WARN_STRING_CONTAINS_DEPRECATED = 0x00000004 + WARN_WATCH_DEPRECATED = 0x00000001, + WARN_PROTO_SETTING_SLOW = 0x00000002, + WARN_STRING_CONTAINS_DEPRECATED = 0x00000004 }; // Emit the specified warning if the given slot in |obj|'s global isn't // true, then set the slot to true. Thus calling this method warns once // for each global object it's called on, and every other call does // nothing. static bool - warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag slot, unsigned errorNumber); + warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, unsigned errorNumber); public: void setThrowTypeError(JSFunction* fun) { MOZ_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined()); setSlot(THROWTYPEERROR, ObjectValue(*fun)); }
--- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -461,20 +461,17 @@ class JSString : public js::gc::TenuredC /* Only called by the GC for dependent or undepended strings. */ inline bool hasBase() const { return d.u1.flags & HAS_BASE_BIT; } inline JSLinearString* base() const; - void traceBase(JSTracer* trc) { - MOZ_ASSERT(hasBase()); - js::TraceManuallyBarrieredEdge(trc, &d.s.u3.base, "base"); - } + void traceBase(JSTracer* trc); /* Only called by the GC for strings with the AllocKind::STRING kind. */ inline void finalize(js::FreeOp* fop); /* Gets the number of bytes that the chars take on the heap. */ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); @@ -504,17 +501,17 @@ class JSString : public js::gc::TenuredC void dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const; template <typename CharT> static void dumpChars(const CharT* s, size_t len, FILE* fp=stderr); bool equals(const char* s); #endif - inline void traceChildren(JSTracer* trc); + void traceChildren(JSTracer* trc); static MOZ_ALWAYS_INLINE void readBarrier(JSString* thing) { if (thing->isPermanentAtom()) return; TenuredCell::readBarrier(thing); } @@ -573,20 +570,17 @@ class JSRope : public JSString return d.s.u2.left; } JSString* rightChild() const { MOZ_ASSERT(isRope()); return d.s.u3.right; } - void traceChildren(JSTracer* trc) { - js::TraceManuallyBarrieredEdge(trc, &d.s.u2.left, "left child"); - js::TraceManuallyBarrieredEdge(trc, &d.s.u3.right, "right child"); - } + void traceChildren(JSTracer* trc); static size_t offsetOfLeft() { return offsetof(JSRope, d.s.u2.left); } static size_t offsetOfRight() { return offsetof(JSRope, d.s.u3.right); } @@ -1267,25 +1261,16 @@ JSString::ensureFlat(js::ExclusiveContex inline JSLinearString* JSString::base() const { MOZ_ASSERT(hasBase()); MOZ_ASSERT(!d.s.u3.base->isInline()); return d.s.u3.base; } -inline void -JSString::traceChildren(JSTracer* trc) -{ - if (hasBase()) - traceBase(trc); - else if (isRope()) - asRope().traceChildren(trc); -} - template<> MOZ_ALWAYS_INLINE const char16_t* JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC& nogc) const { return nonInlineTwoByteChars(nogc); } template<>
--- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -1389,28 +1389,16 @@ nsFrameConstructorSaveState::~nsFrameCon #endif } } NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(), "Something corrupted our list"); } } -static -bool IsBorderCollapse(nsIFrame* aFrame) -{ - for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) { - if (nsGkAtoms::tableFrame == frame->GetType()) { - return ((nsTableFrame*)frame)->IsBorderCollapse(); - } - } - NS_ASSERTION(false, "program error"); - return false; -} - /** * Moves aFrameList from aOldParent to aNewParent. This updates the parent * pointer of the frames in the list, and reparents their views as needed. * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its * ancestors as needed. Then it sets the list as the initial child list * on aNewParent, unless aNewParent either already has kids or has been * reflowed; in that case it appends the new frames. Note that this * method differs from ReparentFrames in that it doesn't change the kids' @@ -2182,32 +2170,34 @@ nsCSSFrameConstructor::ConstructTableCel { NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL, "Unexpected call"); nsIContent* const content = aItem.mContent; nsStyleContext* const styleContext = aItem.mStyleContext; const uint32_t nameSpaceID = aItem.mNameSpaceID; - bool borderCollapse = IsBorderCollapse(aParentFrame); + nsTableFrame* tableFrame = + static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame(); nsContainerFrame* newFrame; // <mtable> is border separate in mathml.css and the MathML code doesn't implement // border collapse. For those users who style <mtable> with border collapse, // give them the default non-MathML table frames that understand border collapse. // This won't break us because MathML table frames are all subclasses of the default // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>. // What will happen is just that non-MathML frames won't understand MathML attributes // and will therefore miss the special handling that the MathML code does. - if (kNameSpaceID_MathML == nameSpaceID && !borderCollapse) - newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext); - else + if (kNameSpaceID_MathML == nameSpaceID && !tableFrame->IsBorderCollapse()) { + newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext, tableFrame); + } else { // Warning: If you change this and add a wrapper frame around table cell // frames, make sure Bug 368554 doesn't regress! // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp. - newFrame = NS_NewTableCellFrame(mPresShell, styleContext, borderCollapse); + newFrame = NS_NewTableCellFrame(mPresShell, styleContext, tableFrame); + } // Initialize the table cell frame InitAndRestoreFrame(aState, content, aParentFrame, newFrame); // Resolve pseudo style and initialize the body cell frame nsRefPtr<nsStyleContext> innerPseudoStyle; innerPseudoStyle = mPresShell->StyleSet()-> ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent, styleContext); @@ -8694,18 +8684,20 @@ nsCSSFrameConstructor::CreateContinuingF rowFrame->SetInitialChildList(kPrincipalList, newChildList); newFrame = rowFrame; } else if (IS_TABLE_CELL(frameType)) { // Warning: If you change this and add a wrapper frame around table cell // frames, make sure Bug 368554 doesn't regress! // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp. + nsTableFrame* tableFrame = + static_cast<nsTableRowFrame*>(aParentFrame)->GetTableFrame(); nsTableCellFrame* cellFrame = - NS_NewTableCellFrame(shell, styleContext, IsBorderCollapse(aParentFrame)); + NS_NewTableCellFrame(shell, styleContext, tableFrame); cellFrame->Init(content, aParentFrame, aFrame); if (cellFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { nsTableFrame::RegisterPositionedTablePart(cellFrame); } // Create a continuing area frame nsIFrame* blockFrame = aFrame->GetFirstPrincipalChild();
--- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -421,17 +421,17 @@ AddAnimationsForProperty(nsIFrame* aFram "inconsistent property flags"); // Add from first to last (since last overrides) for (size_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) { dom::Animation* anim = aAnimations[animIdx]; if (!anim->IsPlaying()) { continue; } - dom::KeyframeEffectReadonly* effect = anim->GetEffect(); + dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); MOZ_ASSERT(effect, "A playing animation should have an effect"); const AnimationProperty* property = effect->GetAnimationOfProperty(aProperty); if (!property) { continue; } // Note that if mWinsInCascade on property was false,
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -500,17 +500,17 @@ GetMinAndMaxScaleForAnimationProperty(ns gfxSize& aMaxScale, gfxSize& aMinScale) { for (size_t animIdx = aAnimations->mAnimations.Length(); animIdx-- != 0; ) { dom::Animation* anim = aAnimations->mAnimations[animIdx]; if (!anim->GetEffect() || anim->GetEffect()->IsFinishedTransition()) { continue; } - dom::KeyframeEffectReadonly* effect = anim->GetEffect(); + dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) { AnimationProperty& prop = effect->Properties()[propIdx]; if (prop.mProperty == eCSSProperty_transform) { for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) { AnimationPropertySegment& segment = prop.mSegments[segIdx]; gfxSize from = GetScaleForValue(segment.mFromValue, aContent->GetPrimaryFrame()); aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
--- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -4877,22 +4877,22 @@ ScrollFrameHelper::SetScrollbarEnabled(n void ScrollFrameHelper::SetCoordAttribute(nsIContent* aContent, nsIAtom* aAtom, nscoord aSize) { DebugOnly<nsWeakPtr> weakShell( do_GetWeakReference(mOuter->PresContext()->PresShell())); // convert to pixels - int32_t pizelSize = nsPresContext::AppUnitsToIntCSSPixels(aSize); + int32_t pixelSize = nsPresContext::AppUnitsToIntCSSPixels(aSize); // only set the attribute if it changed. nsAutoString newValue; - newValue.AppendInt(pizelSize); + newValue.AppendInt(pixelSize); if (aContent->AttrValueIs(kNameSpaceID_None, aAtom, newValue, eCaseMatters)) return; nsWeakFrame weakFrame(mOuter); nsCOMPtr<nsIContent> kungFuDeathGrip = aContent; aContent->SetAttr(kNameSpaceID_None, aAtom, newValue, true); MOZ_ASSERT(ShellIsAlive(weakShell), "pres shell was destroyed by scrolling");
--- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -191,17 +191,17 @@ NS_NewTableColGroupFrame(nsIPresShell* a class nsTableRowFrame; nsTableRowFrame* NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); class nsTableRowGroupFrame; nsTableRowGroupFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); class nsTableCellFrame; nsTableCellFrame* -NS_NewTableCellFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsBorderCollapse); +NS_NewTableCellFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsTableFrame* aTableFrame); nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, nsIDocument* aDoc, nsIURI* aURL, nsISupports* aContainer, // e.g. docshell nsIChannel* aChannel); nsresult NS_NewHTMLFragmentContentSink(nsIFragmentContentSink** aInstancePtrResult);
--- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -1699,16 +1699,21 @@ nsMathMLChar::StretchInternal(nsPresCont // We did not find a size variant or a glyph assembly to stretch this // operator. Verify whether a font with an OpenType MATH table is available // and record missing math script otherwise. gfxMissingFontRecorder* MFR = aPresContext->MissingFontRecorder(); if (MFR && !fm->GetThebesFontGroup()->GetFirstMathFont()) { MFR->RecordScript(MOZ_SCRIPT_MATHEMATICAL_NOTATION); } + // If the scale_stretchy_operators option is disabled, we are done. + if (!Preferences::GetBool("mathml.scale_stretchy_operators.enabled", true)) { + return NS_OK; + } + // stretchy character if (stretchy) { if (isVertical) { float scale = std::min(kMaxScaleFactor, float(aContainerSize.ascent + aContainerSize.descent) / (aDesiredStretchSize.ascent + aDesiredStretchSize.descent)); if (!largeop || scale > 1.0) { // make the character match the desired height.
--- a/layout/mathml/nsMathMLParts.h +++ b/layout/mathml/nsMathMLParts.h @@ -4,16 +4,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsMathMLParts_h___ #define nsMathMLParts_h___ #include "nscore.h" #include "nsISupports.h" +class nsTableFrame; + // Factory methods for creating MathML objects nsIFrame* NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmrowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmpaddedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmspaceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); @@ -21,17 +23,17 @@ nsIFrame* NS_NewMathMLmfracFrame(nsIPres nsIFrame* NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmsubsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsContainerFrame* NS_NewMathMLmtableOuterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsContainerFrame* NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsContainerFrame* NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -nsContainerFrame* NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); +nsContainerFrame* NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsTableFrame* aTableFrame); nsContainerFrame* NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmactionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLsemanticsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsContainerFrame* NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags);
--- a/layout/mathml/nsMathMLmtableFrame.cpp +++ b/layout/mathml/nsMathMLmtableFrame.cpp @@ -225,17 +225,17 @@ ApplyBorderToStyle(const nsMathMLmtdFram } static nsMargin ComputeBorderOverflow(nsMathMLmtdFrame* aFrame, nsStyleBorder aStyleBorder) { nsMargin overflow; int32_t rowIndex; int32_t columnIndex; - nsTableFrame* table = nsTableFrame::GetTableFrame(aFrame); + nsTableFrame* table = aFrame->GetTableFrame(); aFrame->GetCellIndexes(rowIndex, columnIndex); if (!columnIndex) { overflow.left = table->GetColSpacing(-1); overflow.right = table->GetColSpacing(0) / 2; } else if (columnIndex == table->GetColCount() - 1) { overflow.left = table->GetColSpacing(columnIndex - 1) / 2; overflow.right = table->GetColSpacing(columnIndex + 1); } else { @@ -1102,19 +1102,20 @@ nsMathMLmtrFrame::AttributeChanged(int32 return NS_OK; } // -------- // implementation of nsMathMLmtdFrame nsContainerFrame* -NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, + nsTableFrame* aTableFrame) { - return new (aPresShell) nsMathMLmtdFrame(aContext); + return new (aPresShell) nsMathMLmtdFrame(aContext, aTableFrame); } NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame) nsMathMLmtdFrame::~nsMathMLmtdFrame() { }
--- a/layout/mathml/nsMathMLmtableFrame.h +++ b/layout/mathml/nsMathMLmtableFrame.h @@ -213,17 +213,17 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { return nsTableRowFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML)); } // helper to restyle and reflow the table -- @see nsMathMLmtableFrame. void RestyleTable() { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame && tableFrame->IsFrameOfType(nsIFrame::eMathML)) { // relayout the table ((nsMathMLmtableFrame*)tableFrame)->RestyleTable(); } } protected: explicit nsMathMLmtrFrame(nsStyleContext* aContext) : nsTableRowFrame(aContext) {} @@ -233,17 +233,18 @@ protected: // -------------- class nsMathMLmtdFrame : public nsTableCellFrame { public: NS_DECL_FRAMEARENA_HELPERS friend nsContainerFrame* NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, - nsStyleContext* aContext); + nsStyleContext* aContext, + nsTableFrame* aTableFrame); // overloaded nsTableCellFrame methods virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) override; virtual nsresult @@ -263,17 +264,18 @@ public: return nsTableCellFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML)); } virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const override; virtual nsMargin GetBorderOverflow() override; protected: - explicit nsMathMLmtdFrame(nsStyleContext* aContext) : nsTableCellFrame(aContext) {} + nsMathMLmtdFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame) + : nsTableCellFrame(aContext, aTableFrame) {} virtual ~nsMathMLmtdFrame(); }; // class nsMathMLmtdFrame // -------------- class nsMathMLmtdInnerFrame : public nsBlockFrame, public nsMathMLFrame { public:
--- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -19,8 +19,18 @@ HTTP(..) == marker-shadow.html marker-sh skip-if(Android||B2G) == clipped-elements.html clipped-elements-ref.html HTTP(..) == theme-overflow.html theme-overflow-ref.html skip-if(B2G||Mulet) HTTP(..) == table-cell.html table-cell-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Mulet) HTTP(..) == two-value-syntax.html two-value-syntax-ref.html # MULET: Bug 1144079: Re-enable Mulet mochitests and reftests taskcluster-specific disables skip-if(B2G||Mulet) HTTP(..) == single-value.html single-value-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) HTTP(..) == atomic-under-marker.html atomic-under-marker-ref.html # Initial mulet triage: parity with B2G/B2G Desktop fuzzy(1,702) skip-if(Android||B2G||Mulet) fuzzy-if(asyncPanZoom&&!layersGPUAccelerated,102,12352) HTTP(..) == xulscroll.html xulscroll-ref.html # Initial mulet triage: parity with B2G/B2G Desktop HTTP(..) == combobox-zoom.html combobox-zoom-ref.html + +# The vertical-text pref setting can be removed after bug 1138384 lands +pref(layout.css.vertical-text.enabled,true) == vertical-decorations-1.html vertical-decorations-1-ref.html +pref(layout.css.vertical-text.enabled,true) == vertical-decorations-2.html vertical-decorations-2-ref.html +pref(layout.css.vertical-text.enabled,true) != vertical-decorations-1.html vertical-decorations-1-2-notref.html +pref(layout.css.vertical-text.enabled,true) != vertical-decorations-2.html vertical-decorations-1-2-notref.html +pref(layout.css.vertical-text.enabled,true) == vertical-decorations-3.html vertical-decorations-3-ref.html +pref(layout.css.vertical-text.enabled,true) == vertical-decorations-4.html vertical-decorations-4-ref.html +pref(layout.css.vertical-text.enabled,true) != vertical-decorations-3.html vertical-decorations-3-4-notref.html +pref(layout.css.vertical-text.enabled,true) != vertical-decorations-4.html vertical-decorations-3-4-notref.html
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-1-2-notref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vlr { + writing-mode: vertical-lr; + text-orientation: sideways-right; + height: 10ch; +} +</style> +</head> + +<body> +<div class="vlr">abcdefghijklm</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-1-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vlr { + writing-mode: vertical-lr; + text-orientation: sideways-right; + height: 10ch; +} +</style> +</head> + +<body> +<div class="vlr"><u>abcdefghi</u>…</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-1.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vlr { + writing-mode: vertical-lr; + text-orientation: sideways-right; + height: 10ch; +} +</style> +</head> + +<body> +<div class="vlr"><u>abcdefghijklm</u></div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-2-ref.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +span { + text-decoration: overline; +} +.vlr { + writing-mode: vertical-lr; + text-orientation: sideways-right; + height: 10ch; +} +</style> +</head> + +<body> +<div class="vlr"><span>abcdefghi</span>…</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-2.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +span { + text-decoration: overline; +} +.vlr { + writing-mode: vertical-lr; + text-orientation: sideways-right; + height: 10ch; +} +</style> +</head> + +<body> +<div class="vlr"><span>abcdefghijklm</span></div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-3-4-notref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vrl { + writing-mode: vertical-rl; + text-orientation: upright; + height: 6em; +} +</style> +</head> + +<body> +<div class="vrl">你好吗?我很好!</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-3-ref.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vrl { + writing-mode: vertical-rl; + text-orientation: upright; + height: 6em; +} +</style> +</head> + +<body> +<div class="vrl"><u>你好吗?我</u>…</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-3.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +.vrl { + writing-mode: vertical-rl; + text-orientation: upright; + height: 6em; +} +</style> +</head> + +<body> +<div class="vrl"><u>你好吗?我很好!</u></div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-4-ref.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +span { + text-decoration: overline; +} +.vrl { + writing-mode: vertical-rl; + text-orientation: upright; + height: 6em; +} +</style> +</head> + +<body> +<div class="vrl"><span>你好吗?我</span>…</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/vertical-decorations-4.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +div { + font: 25px monospace; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; + border: 1px solid gray; + padding: 5px; + display: inline-block; + vertical-align: top; +} +span { + text-decoration: overline; +} +.vrl { + writing-mode: vertical-rl; + text-orientation: upright; + height: 6em; +} +</style> +</head> + +<body> +<div class="vrl"><span>你好吗?我很好!</span></div> +</body> +</html>
--- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -25,17 +25,17 @@ #include "RestyleManager.h" #include "nsRuleProcessorData.h" #include "nsStyleSet.h" #include "nsStyleChangeList.h" using mozilla::layers::Layer; using mozilla::dom::Animation; -using mozilla::dom::KeyframeEffectReadonly; +using mozilla::dom::KeyframeEffectReadOnly; namespace mozilla { /* static */ bool IsGeometricProperty(nsCSSProperty aProperty) { switch (aProperty) { case eCSSProperty_bottom: @@ -596,17 +596,17 @@ AnimationCollection::CanPerformOnComposi } for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { const Animation* anim = mAnimations[animIdx]; if (!anim->IsPlaying()) { continue; } - const KeyframeEffectReadonly* effect = anim->GetEffect(); + const KeyframeEffectReadOnly* effect = anim->GetEffect(); MOZ_ASSERT(effect, "A playing animation should have an effect"); for (size_t propIdx = 0, propEnd = effect->Properties().Length(); propIdx != propEnd; ++propIdx) { if (IsGeometricProperty(effect->Properties()[propIdx].mProperty)) { aFlags = CanAnimateFlags(aFlags | CanAnimate_HasGeometricProperty); break; } @@ -615,17 +615,17 @@ AnimationCollection::CanPerformOnComposi bool existsProperty = false; for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { const Animation* anim = mAnimations[animIdx]; if (!anim->IsPlaying()) { continue; } - const KeyframeEffectReadonly* effect = anim->GetEffect(); + const KeyframeEffectReadOnly* effect = anim->GetEffect(); MOZ_ASSERT(effect, "A playing animation should have an effect"); existsProperty = existsProperty || effect->Properties().Length() > 0; for (size_t propIdx = 0, propEnd = effect->Properties().Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = effect->Properties()[propIdx]; if (!CanAnimatePropertyOnCompositor(mElement, @@ -668,17 +668,17 @@ AnimationCollection::PostUpdateLayerAnim } } } bool AnimationCollection::HasAnimationOfProperty(nsCSSProperty aProperty) const { for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { - const KeyframeEffectReadonly* effect = mAnimations[animIdx]->GetEffect(); + const KeyframeEffectReadOnly* effect = mAnimations[animIdx]->GetEffect(); if (effect && effect->HasAnimationOfProperty(aProperty) && !effect->IsFinishedTransition()) { return true; } } return false; } @@ -917,17 +917,17 @@ AnimationCollection::HasCurrentAnimation bool AnimationCollection::HasCurrentAnimationsForProperties( const nsCSSProperty* aProperties, size_t aPropertyCount) const { for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { const Animation& anim = *mAnimations[animIdx]; - const KeyframeEffectReadonly* effect = anim.GetEffect(); + const KeyframeEffectReadOnly* effect = anim.GetEffect(); if (effect && effect->IsCurrent(anim) && effect->HasAnimationOfProperties(aProperties, aPropertyCount)) { return true; } } return false;
--- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -21,17 +21,17 @@ #include "nsIDocument.h" #include "nsDOMMutationObserver.h" #include <math.h> using namespace mozilla; using namespace mozilla::css; using mozilla::dom::Animation; using mozilla::dom::AnimationPlayState; -using mozilla::dom::KeyframeEffectReadonly; +using mozilla::dom::KeyframeEffectReadOnly; using mozilla::CSSAnimation; mozilla::dom::Promise* CSSAnimation::GetReady(ErrorResult& aRv) { FlushStyle(); return Animation::GetReady(aRv); } @@ -347,18 +347,18 @@ nsAnimationManager::CheckAnimationRule(n continue; } bool animationChanged = false; // Update the old from the new so we can keep the original object // identity (and any expando properties attached to it). if (oldAnim->GetEffect() && newAnim->GetEffect()) { - KeyframeEffectReadonly* oldEffect = oldAnim->GetEffect(); - KeyframeEffectReadonly* newEffect = newAnim->GetEffect(); + KeyframeEffectReadOnly* oldEffect = oldAnim->GetEffect(); + KeyframeEffectReadOnly* newEffect = newAnim->GetEffect(); animationChanged = oldEffect->Timing() != newEffect->Timing() || oldEffect->Properties() != newEffect->Properties(); oldEffect->Timing() = newEffect->Timing(); oldEffect->Properties() = newEffect->Properties(); } // Reset compositor state so animation will be re-synchronized. @@ -521,18 +521,18 @@ nsAnimationManager::BuildAnimations(nsSt AnimationTiming timing; timing.mIterationDuration = TimeDuration::FromMilliseconds(src.GetDuration()); timing.mDelay = TimeDuration::FromMilliseconds(src.GetDelay()); timing.mIterationCount = src.GetIterationCount(); timing.mDirection = src.GetDirection(); timing.mFillMode = src.GetFillMode(); - nsRefPtr<KeyframeEffectReadonly> destEffect = - new KeyframeEffectReadonly(mPresContext->Document(), aTarget, + nsRefPtr<KeyframeEffectReadOnly> destEffect = + new KeyframeEffectReadOnly(mPresContext->Document(), aTarget, aStyleContext->GetPseudoType(), timing, src.GetName()); dest->SetEffect(destEffect); // Even in the case where we call PauseFromStyle below, we still need to // call PlayFromStyle first. This is because a newly-created animation is // idle and has no effect until it is played (or otherwise given a start // time). @@ -749,17 +749,17 @@ nsAnimationManager::UpdateCascadeResults nsAutoTArray<nsCSSProperty, 2> propertiesToTrack; { nsCSSPropertySet propertiesToTrackAsSet; for (size_t animIdx = aElementAnimations->mAnimations.Length(); animIdx-- != 0; ) { const Animation* anim = aElementAnimations->mAnimations[animIdx]; - const KeyframeEffectReadonly* effect = anim->GetEffect(); + const KeyframeEffectReadOnly* effect = anim->GetEffect(); if (!effect) { continue; } for (size_t propIdx = 0, propEnd = effect->Properties().Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = effect->Properties()[propIdx]; // We only bother setting mWinsInCascade for properties that we @@ -797,17 +797,17 @@ nsAnimationManager::UpdateCascadeResults * currently in effect. */ bool changed = false; for (size_t animIdx = aElementAnimations->mAnimations.Length(); animIdx-- != 0; ) { CSSAnimation* anim = aElementAnimations->mAnimations[animIdx]->AsCSSAnimation(); - KeyframeEffectReadonly* effect = anim->GetEffect(); + KeyframeEffectReadOnly* effect = anim->GetEffect(); anim->mInEffectForCascadeResults = anim->IsInEffect(); if (!effect) { continue; } for (size_t propIdx = 0, propEnd = effect->Properties().Length();
--- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -29,29 +29,29 @@ #include "nsStyleChangeList.h" #include "nsStyleSet.h" #include "RestyleManager.h" #include "nsDOMMutationObserver.h" using mozilla::TimeStamp; using mozilla::TimeDuration; using mozilla::dom::Animation; -using mozilla::dom::KeyframeEffectReadonly; +using mozilla::dom::KeyframeEffectReadOnly; using namespace mozilla; using namespace mozilla::css; const nsString& ElementPropertyTransition::Name() const { if (!mName.Length()) { const_cast<ElementPropertyTransition*>(this)->mName = NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(TransitionProperty())); } - return dom::KeyframeEffectReadonly::Name(); + return dom::KeyframeEffectReadOnly::Name(); } double ElementPropertyTransition::CurrentValuePortion() const { // It would be easy enough to handle finished transitions by using a time // fraction of 1 but currently we should not be called for finished // transitions. @@ -316,17 +316,17 @@ nsTransitionManager::StyleContextChanged AnimationPtrArray& animations = collection->mAnimations; size_t i = animations.Length(); MOZ_ASSERT(i != 0, "empty transitions list?"); StyleAnimationValue currentValue; do { --i; Animation* anim = animations[i]; - dom::KeyframeEffectReadonly* effect = anim->GetEffect(); + dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); MOZ_ASSERT(effect && effect->Properties().Length() == 1, "Should have one animation property for a transition"); MOZ_ASSERT(effect && effect->Properties()[0].mSegments.Length() == 1, "Animation property should have one segment for a transition"); const AnimationProperty& prop = effect->Properties()[0]; const AnimationPropertySegment& segment = prop.mSegments[0]; // properties no longer in 'transition-property' if ((checkProperties && @@ -628,17 +628,17 @@ nsTransitionManager::PruneCompletedTrans // FIXME (bug 1158431): Really, we should also cancel running // transitions whose destination doesn't match as well. AnimationPtrArray& animations = collection->mAnimations; size_t i = animations.Length(); MOZ_ASSERT(i != 0, "empty transitions list?"); do { --i; Animation* anim = animations[i]; - dom::KeyframeEffectReadonly* effect = anim->GetEffect(); + dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); if (!effect->IsFinishedTransition()) { continue; } MOZ_ASSERT(effect && effect->Properties().Length() == 1, "Should have one animation property for a transition"); MOZ_ASSERT(effect && effect->Properties()[0].mSegments.Length() == 1,
--- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -24,23 +24,23 @@ struct StyleTransition; } /***************************************************************************** * Per-Element data * *****************************************************************************/ namespace mozilla { -struct ElementPropertyTransition : public dom::KeyframeEffectReadonly +struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly { ElementPropertyTransition(nsIDocument* aDocument, dom::Element* aTarget, nsCSSPseudoElements::Type aPseudoType, const AnimationTiming &aTiming) - : dom::KeyframeEffectReadonly(aDocument, aTarget, aPseudoType, + : dom::KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType, aTiming, EmptyString()) { } virtual ElementPropertyTransition* AsTransition() override { return this; } virtual const ElementPropertyTransition* AsTransition() const override { return this; } virtual const nsString& Name() const override;
--- a/layout/tables/BasicTableLayoutStrategy.cpp +++ b/layout/tables/BasicTableLayoutStrategy.cpp @@ -9,16 +9,17 @@ * used for CSS2's 'table-layout: auto'. */ #include "BasicTableLayoutStrategy.h" #include <algorithm> #include "nsTableFrame.h" +#include "nsTableColFrame.h" #include "nsTableCellFrame.h" #include "nsLayoutUtils.h" #include "nsGkAtoms.h" #include "SpanningCellSorter.h" #include "nsIContent.h" using namespace mozilla; using namespace mozilla::layout;
--- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -37,19 +37,20 @@ //TABLECELL SELECTION #include "nsFrameSelection.h" #include "mozilla/LookAndFeel.h" using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::image; -nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) : - nsContainerFrame(aContext) - , mDesiredSize(GetWritingMode()) +nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext, + nsTableFrame* aTableFrame) + : nsContainerFrame(aContext) + , mDesiredSize(aTableFrame->GetWritingMode()) { mColIndex = 0; mPriorAvailWidth = 0; SetContentEmpty(false); SetHasPctOverHeight(false); } @@ -126,17 +127,17 @@ nsTableCellFrame::NotifyPercentHeight(co // are based on the height of the cell, since its containing block // is the inner cell frame. // We'll only honor the percent height if sibling-cells/ancestors // have specified/pct height. (Also, siblings only count for this if // both this cell and the sibling cell span exactly 1 row.) if (nsTableFrame::AncestorsHaveStyleHeight(*cellRS) || - (nsTableFrame::GetTableFrame(this)->GetEffectiveRowSpan(*this) == 1 && + (GetTableFrame()->GetEffectiveRowSpan(*this) == 1 && (cellRS->parentReflowState->frame->GetStateBits() & NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT))) { for (const nsHTMLReflowState *rs = aReflowState.parentReflowState; rs != cellRS; rs = rs->parentReflowState) { rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); } @@ -215,30 +216,29 @@ nsTableCellFrame::AttributeChanged(int32 // We need to recalculate in this case because of the nowrap quirk in // BasicTableLayoutStrategy if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap && PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) { PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY); } // let the table frame decide what to do - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - tableFrame->AttributeChangedFor(this, mContent, aAttribute); + GetTableFrame()->AttributeChangedFor(this, mContent, aAttribute); return NS_OK; } /* virtual */ void nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsContainerFrame::DidSetStyleContext(aOldStyleContext); if (!aOldStyleContext) //avoid this on init return; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { int32_t colIndex, rowIndex; GetColIndex(colIndex); GetRowIndex(rowIndex); // row span needs to be clamped as we do not create rows in the cellmap // which do not have cells originating in them nsIntRect damageArea(colIndex, rowIndex, GetColSpan(), @@ -474,17 +474,17 @@ PaintTableCellSelection(nsIFrame* aFrame void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); if (IsVisibleInSelection(aBuilder)) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? StyleTableBorder()->mEmptyCells : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; // take account of 'empty-cells' if (StyleVisibility()->IsVisible() && (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { // display outset box-shadows if we need to. const nsStyleBorder* borderStyle = StyleBorder(); @@ -896,17 +896,17 @@ nsTableCellFrame::Reflow(nsPresContext* availSize.height = 1; WritingMode wm = aReflowState.GetWritingMode(); nsHTMLReflowMetrics kidSize(wm, aDesiredSize.mFlags); kidSize.ClearSize(); SetPriorAvailWidth(aReflowState.AvailableWidth()); nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (aReflowState.mFlags.mSpecialHeightReflow) { const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset); DISPLAY_REFLOW_CHANGE(); } else if (aPresContext->IsPaginated()) { nscoord computedUnpaginatedHeight = CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this, @@ -1065,22 +1065,22 @@ nsTableCellFrame::GetCellIndexes(int32_t } aColIndex = mColIndex; return NS_OK; } nsTableCellFrame* NS_NewTableCellFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, - bool aIsBorderCollapse) + nsTableFrame* aTableFrame) { - if (aIsBorderCollapse) - return new (aPresShell) nsBCTableCellFrame(aContext); + if (aTableFrame->IsBorderCollapse()) + return new (aPresShell) nsBCTableCellFrame(aContext, aTableFrame); else - return new (aPresShell) nsTableCellFrame(aContext); + return new (aPresShell) nsTableCellFrame(aContext, aTableFrame); } NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame) nsMargin* nsTableCellFrame::GetBorderWidth(nsMargin& aBorder) const { aBorder = StyleBorder()->GetComputedBorder(); @@ -1098,18 +1098,19 @@ nsresult nsTableCellFrame::GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult); } #endif // nsBCTableCellFrame -nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext) -:nsTableCellFrame(aContext) +nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext, + nsTableFrame* aTableFrame) + : nsTableCellFrame(aContext, aTableFrame) { mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0; } nsBCTableCellFrame::~nsBCTableCellFrame() { }
--- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -11,18 +11,17 @@ #include "nsITableCellLayout.h" #include "nscore.h" #include "nsContainerFrame.h" #include "nsStyleContext.h" #include "nsIPercentHeightObserver.h" #include "nsGkAtoms.h" #include "nsLayoutUtils.h" #include "nsTArray.h" - -class nsTableFrame; +#include "nsTableRowFrame.h" /** * nsTableCellFrame * data structure to maintain information about a single table cell's frame * * NOTE: frames are not ref counted. We expose addref and release here * so we can change that decsion in the future. Users of nsITableCellLayout * should refcount correctly as if this object is being ref counted, though @@ -38,19 +37,31 @@ class nsTableCellFrame : public nsContai public: NS_DECL_QUERYFRAME_TARGET(nsTableCellFrame) NS_DECL_QUERYFRAME NS_DECL_FRAMEARENA_HELPERS // default constructor supplied by the compiler - explicit nsTableCellFrame(nsStyleContext* aContext); + nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame); ~nsTableCellFrame(); + nsTableRowFrame* GetTableRowFrame() const + { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableRowFrame); + return static_cast<nsTableRowFrame*>(parent); + } + + nsTableFrame* GetTableFrame() const + { + return GetTableRowFrame()->GetTableFrame(); + } + virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) override; virtual void DestroyFrom(nsIFrame* aDestructRoot) override; #ifdef ACCESSIBILITY virtual mozilla::a11y::AccType AccessibleType() override; @@ -80,23 +91,16 @@ public: } virtual nsMargin GetUsedMargin() const override; virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState) override; virtual bool NeedsToObserve(const nsHTMLReflowState& aReflowState) override; - /** instantiate a new instance of nsTableRowFrame. - * @param aPresShell the pres shell for this frame - * - * @return the frame that was created - */ - friend nsIFrame* NS_NewTableCellFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); - virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; DrawResult PaintCellBackground(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt, uint32_t aFlags); @@ -121,16 +125,24 @@ public: * @see nsLayoutAtoms::tableCellFrame */ virtual nsIAtom* GetType() const override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif + // Although the spec doesn't say that writing-mode is not applied to + // table-cells, we still override this method here because we want to + // make effective writing mode of table structure frames consistent + // within a table. The content inside table cells is reflowed by an + // anonymous block, hence their writing mode is not affected. + virtual mozilla::WritingMode GetWritingMode() const override + { return GetTableFrame()->GetWritingMode(); } + void VerticallyAlignChild(nscoord aMaxAscent); /* * Get the value of vertical-align adjusted for CSS 2's rules for a * table cell, which means the result is always * NS_STYLE_VERTICAL_ALIGN_{TOP,MIDDLE,BOTTOM,BASELINE}. */ virtual uint8_t GetVerticalAlign() const; @@ -291,17 +303,17 @@ inline void nsTableCellFrame::SetHasPctO // nsBCTableCellFrame class nsBCTableCellFrame final : public nsTableCellFrame { typedef mozilla::image::DrawResult DrawResult; public: NS_DECL_FRAMEARENA_HELPERS - explicit nsBCTableCellFrame(nsStyleContext* aContext); + nsBCTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame); ~nsBCTableCellFrame(); virtual nsIAtom* GetType() const override; virtual nsMargin GetUsedBorder() const override; virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
--- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -54,17 +54,17 @@ nsTableColFrame::SetColType(nsTableColTy /* virtual */ void nsTableColFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsSplittableFrame::DidSetStyleContext(aOldStyleContext); if (!aOldStyleContext) //avoid this on init return; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { nsIntRect damageArea(GetColIndex(), 0, 1, tableFrame->GetRowCount()); tableFrame->AddBCDamageArea(damageArea); } } void nsTableColFrame::SetContinuousBCBorderWidth(uint8_t aForSide, @@ -93,18 +93,17 @@ nsTableColFrame::Reflow(nsPresContext* { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableColFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aDesiredSize.ClearSize(); const nsStyleVisibility* colVis = StyleVisibility(); bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); if (collapseCol) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - tableFrame->SetNeedToCollapse(true); + GetTableFrame()->SetNeedToCollapse(true); } aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); } int32_t nsTableColFrame::GetSpan() { return StyleTable()->mSpan;
--- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -5,23 +5,18 @@ #ifndef nsTableColFrame_h__ #define nsTableColFrame_h__ #include "mozilla/Attributes.h" #include "celldata.h" #include "nscore.h" #include "nsContainerFrame.h" #include "nsTArray.h" - -enum nsTableColType { - eColContent = 0, // there is real col content associated - eColAnonymousCol = 1, // the result of a span on a col - eColAnonymousColGroup = 2, // the result of a span on a col group - eColAnonymousCell = 3 // the result of a cell alone -}; +#include "nsTableColGroupFrame.h" +#include "mozilla/WritingModes.h" class nsTableColFrame : public nsSplittableFrame { public: NS_DECL_FRAMEARENA_HELPERS enum {eWIDTH_SOURCE_NONE =0, // no cell has contributed to the width style eWIDTH_SOURCE_CELL =1, // a cell specified a width eWIDTH_SOURCE_CELL_WITH_SPAN=2 // a cell implicitly specified a width via colspan @@ -32,16 +27,29 @@ public: /** instantiate a new instance of nsTableRowFrame. * @param aPresShell the pres shell for this frame * * @return the frame that was created */ friend nsTableColFrame* NS_NewTableColFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + + nsTableColGroupFrame* GetTableColGroupFrame() const + { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableColGroupFrame); + return static_cast<nsTableColGroupFrame*>(parent); + } + + nsTableFrame* GetTableFrame() const + { + return GetTableColGroupFrame()->GetTableFrame(); + } + /** @see nsIFrame::DidSetStyleContext */ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override; int32_t GetColIndex() const; void SetColIndex (int32_t aColIndex); nsTableColFrame* GetNextCol() const; @@ -66,16 +74,19 @@ public: virtual nsIAtom* GetType() const override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif virtual nsSplittableType GetSplittableType() const override; + virtual mozilla::WritingMode GetWritingMode() const override + { return GetTableFrame()->GetWritingMode(); } + /** return the number of the columns the col represents. always >= 1 */ int32_t GetSpan(); /** convenience method, calls into cellmap */ int32_t Count() const; nscoord GetLeftBorderWidth(); void SetLeftBorderWidth(BCPixelSize aWidth);
--- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -70,17 +70,17 @@ void nsTableColGroupFrame::ResetColIndic } nsresult nsTableColGroupFrame::AddColsToTable(int32_t aFirstColIndex, bool aResetSubsequentColIndices, const nsFrameList::Slice& aCols) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); tableFrame->InvalidateFrameSubtree(); // set the col indices of the col frames and and add col info to the table int32_t colIndex = aFirstColIndex; nsFrameList::Enumerator e(aCols); for (; !e.AtEnd(); e.Next()) { ((nsTableColFrame*)e.get())->SetColIndex(colIndex); @@ -136,34 +136,33 @@ nsTableColGroupFrame::GetLastRealColGrou void nsTableColGroupFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) { MOZ_ASSERT(mFrames.IsEmpty(), "unexpected second call to SetInitialChildList"); MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list"); if (aChildList.IsEmpty()) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - tableFrame->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup, - false); + GetTableFrame()->AppendAnonymousColFrames(this, GetSpan(), + eColAnonymousColGroup, false); return; } mFrames.AppendFrames(this, aChildList); } /* virtual */ void nsTableColGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsContainerFrame::DidSetStyleContext(aOldStyleContext); if (!aOldStyleContext) //avoid this on init return; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { int32_t colCount = GetColCount(); if (!colCount) return; // this is a degenerated colgroup nsIntRect damageArea(GetFirstColumn()->GetColIndex(), 0, colCount, tableFrame->GetRowCount()); tableFrame->AddBCDamageArea(damageArea); @@ -312,17 +311,17 @@ nsTableColGroupFrame::RemoveFrame(ChildL col = nextCol; } } int32_t colIndex = colFrame->GetColIndex(); // The RemoveChild call handles calling FrameNeedsReflow on us. RemoveChild(*colFrame, true); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); tableFrame->RemoveCol(this, colIndex, true, true); if (mFrames.IsEmpty() && contentRemoval && GetColType() == eColGroupContent) { tableFrame->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup, true); } } else { @@ -357,18 +356,17 @@ nsTableColGroupFrame::Reflow(nsPresConte MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_ASSERTION(nullptr!=mContent, "bad state -- null content for frame"); const nsStyleVisibility* groupVis = StyleVisibility(); bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible); if (collapseGroup) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - tableFrame->SetNeedToCollapse(true); + GetTableFrame()->SetNeedToCollapse(true); } // for every content child that (is a column thingy and does not already have a frame) // create a frame and adjust it's style for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) { // Give the child frame a chance to reflow, even though we know it'll have 0 size nsHTMLReflowMetrics kidSize(aReflowState); @@ -431,18 +429,18 @@ void nsTableColGroupFrame::SetContinuous default: NS_ERROR("invalid side arg"); } } void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin& aBorder) { int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel(); - nsTableFrame* table = nsTableFrame::GetTableFrame(this); - nsTableColFrame* col = table->GetColFrame(mStartColIndex + mColCount - 1); + nsTableColFrame* col = GetTableFrame()-> + GetColFrame(mStartColIndex + mColCount - 1); col->GetContinuousBCBorderWidth(aBorder); aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopContBorderWidth); aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomContBorderWidth); } /* ----- global methods ----- */
--- a/layout/tables/nsTableColGroupFrame.h +++ b/layout/tables/nsTableColGroupFrame.h @@ -3,26 +3,20 @@ * 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/. */ #ifndef nsTableColGroupFrame_h__ #define nsTableColGroupFrame_h__ #include "mozilla/Attributes.h" #include "nscore.h" #include "nsContainerFrame.h" -#include "nsTableColFrame.h" - -class nsTableFrame; -class nsTableColFrame; +#include "nsTableFrame.h" +#include "mozilla/WritingModes.h" -enum nsTableColGroupType { - eColGroupContent = 0, // there is real col group content associated - eColGroupAnonymousCol = 1, // the result of a col - eColGroupAnonymousCell = 2 // the result of a cell alone -}; +class nsTableColFrame; /** * nsTableColGroupFrame * data structure to maintain information about a single table cell's frame * * @author sclark */ class nsTableColGroupFrame final : public nsContainerFrame @@ -35,16 +29,23 @@ public: /** instantiate a new instance of nsTableRowFrame. * @param aPresShell the pres shell for this frame * * @return the frame that was created */ friend nsTableColGroupFrame* NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + nsTableFrame* GetTableFrame() const + { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableFrame); + return static_cast<nsTableFrame*>(parent); + } + /** * ColGroups never paint anything, nor receive events. */ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override {} /** A colgroup can be caused by three things: @@ -108,16 +109,19 @@ public: /** * Get the "type" of the frame * * @see nsGkAtoms::tableColGroupFrame */ virtual nsIAtom* GetType() const override; + virtual mozilla::WritingMode GetWritingMode() const override + { return GetTableFrame()->GetWritingMode(); } + /** Add column frames to the table storages: colframe cache and cellmap * this doesn't change the mFrames of the colgroup frame. * @param aFirstColIndex - the index at which aFirstFrame should be inserted * into the colframe cache. * @param aResetSubsequentColIndices - the indices of the col frames * after the insertion might need * an update * @param aCols - an iterator that can be used to iterate over the col
--- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -7,18 +7,16 @@ #include "mozilla/Attributes.h" #include "celldata.h" #include "imgIContainer.h" #include "nscore.h" #include "nsContainerFrame.h" #include "nsStyleCoord.h" #include "nsStyleConsts.h" -#include "nsTableColFrame.h" -#include "nsTableColGroupFrame.h" #include "nsCellMap.h" #include "nsGkAtoms.h" #include "nsDisplayList.h" class nsTableCellFrame; class nsTableCellMap; class nsTableColFrame; class nsTableRowGroupFrame; @@ -95,16 +93,29 @@ private: nsDisplayTableItem* mOldCurrentItem; #ifdef DEBUG nsDisplayTableItem* mPushedItem; #endif }; /* ============================================================================ */ +enum nsTableColGroupType { + eColGroupContent = 0, // there is real col group content associated + eColGroupAnonymousCol = 1, // the result of a col + eColGroupAnonymousCell = 2 // the result of a cell alone +}; + +enum nsTableColType { + eColContent = 0, // there is real col content associated + eColAnonymousCol = 1, // the result of a span on a col + eColAnonymousColGroup = 2, // the result of a span on a col group + eColAnonymousCell = 3 // the result of a cell alone +}; + /** * nsTableFrame maps the inner portion of a table (everything except captions.) * Used as a pseudo-frame within nsTableOuterFrame, it may also be used * stand-alone as the top-level frame. * * The principal child list contains row group frames. There is also an * additional child list, kColGroupList, which contains the col group frames. */
--- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -166,17 +166,17 @@ nsTableRowFrame::DestroyFrom(nsIFrame* a /* virtual */ void nsTableRowFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsContainerFrame::DidSetStyleContext(aOldStyleContext); if (!aOldStyleContext) //avoid this on init return; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { nsIntRect damageArea(0, GetRowIndex(), tableFrame->GetColCount(), 1); tableFrame->AddBCDamageArea(damageArea); } } void @@ -184,17 +184,17 @@ nsTableRowFrame::AppendFrames(ChildListI nsFrameList& aFrameList) { NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); DrainSelfOverflowList(); // ensure the last frame is in mFrames const nsFrameList::Slice& newCells = mFrames.AppendFrames(nullptr, aFrameList); // Add the new cell frames to the table - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); for (nsFrameList::Enumerator e(newCells) ; !e.AtEnd(); e.Next()) { nsIFrame *childFrame = e.get(); NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure"); tableFrame->AppendCell(static_cast<nsTableCellFrame&>(*childFrame), GetRowIndex()); } PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_HAS_DIRTY_CHILDREN); @@ -210,17 +210,17 @@ nsTableRowFrame::InsertFrames(ChildListI NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this, "inserting after sibling frame with different parent"); DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames //Insert Frames in the frame list const nsFrameList::Slice& newCells = mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList); // Get the table frame - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); nsIAtom* cellFrameType = tableFrame->IsBorderCollapse() ? nsGkAtoms::bcTableCellFrame : nsGkAtoms::tableCellFrame; nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, cellFrameType); nsTArray<nsTableCellFrame*> cellChildren; for (nsFrameList::Enumerator e(newCells); !e.AtEnd(); e.Next()) { nsIFrame *childFrame = e.get(); NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure"); cellChildren.AppendElement(static_cast<nsTableCellFrame*>(childFrame)); } @@ -240,17 +240,17 @@ void nsTableRowFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) { NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); MOZ_ASSERT((nsTableCellFrame*)do_QueryFrame(aOldFrame)); nsTableCellFrame* cellFrame = static_cast<nsTableCellFrame*>(aOldFrame); // remove the cell from the cell map - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); tableFrame->RemoveCell(cellFrame, GetRowIndex()); // Remove the frame and destroy it mFrames.DestroyFrame(aOldFrame); PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_HAS_DIRTY_CHILDREN); @@ -311,17 +311,17 @@ nsTableRowFrame::GetFirstCell() /** * Post-reflow hook. This is where the table row does its post-processing */ void nsTableRowFrame::DidResize() { // Resize and re-align the cell frames based on our row height - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); nsTableIterator iter(*this); nsIFrame* childFrame = iter.First(); WritingMode wm = GetWritingMode(); nsHTMLReflowMetrics desiredSize(wm); desiredSize.SetSize(wm, GetLogicalSize(wm)); desiredSize.SetOverflowAreasToDesiredBounds(); @@ -477,17 +477,17 @@ nsTableRowFrame::UpdateHeight(nscoord } } } } nscoord nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight()) ? 0 : aReflowState.ComputedHeight(); ResetHeight(computedHeight); const nsStylePosition* position = StylePosition(); if (position->mHeight.ConvertsToLength()) { SetFixedHeight(nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0)); } @@ -541,26 +541,24 @@ public: nsRenderingContext* aCtx) override; NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND) }; void nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame); - TableBackgroundPainter painter(tableFrame, + auto rowFrame = static_cast<nsTableRowFrame*>(mFrame); + TableBackgroundPainter painter(rowFrame->GetTableFrame(), TableBackgroundPainter::eOrigin_TableRow, mFrame->PresContext(), *aCtx, mVisibleRect, ToReferenceFrame(), aBuilder->GetBackgroundPaintFlags()); - DrawResult result = - painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame)); - + DrawResult result = painter.PaintRow(rowFrame); nsDisplayTableItemGeometry::UpdateDrawResult(this, result); } void nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { @@ -606,18 +604,17 @@ nsresult nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame* aCellFrame, nscoord& aDesiredHeight) { nscoord specifiedHeight = 0; // Get the height specified in the style information const nsStylePosition* position = aCellFrame->StylePosition(); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - int32_t rowSpan = tableFrame->GetEffectiveRowSpan(*aCellFrame); + int32_t rowSpan = GetTableFrame()->GetEffectiveRowSpan(*aCellFrame); switch (position->mHeight.GetUnit()) { case eStyleUnit_Calc: { if (position->mHeight.CalcHasPercent()) { // Treat this like "auto" break; } // Fall through to the coord case @@ -1038,17 +1035,17 @@ nsTableRowFrame::Reflow(nsPresContext* nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); const nsStyleVisibility* rowVis = StyleVisibility(); bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible); if (collapseRow) { tableFrame->SetNeedToCollapse(true); } // see if a special height reflow needs to occur due to having a pct height nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); @@ -1094,18 +1091,17 @@ nsTableRowFrame::ReflowCellFrame(nsPresC nscoord aAvailableHeight, nsReflowStatus& aStatus) { // Reflow the cell frame with the specified height. Use the existing width nsRect cellRect = aCellFrame->GetRect(); nsRect cellVisualOverflow = aCellFrame->GetVisualOverflowRect(); nsSize availSize(cellRect.width, aAvailableHeight); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - bool borderCollapse = tableFrame->IsBorderCollapse(); + bool borderCollapse = GetTableFrame()->IsBorderCollapse(); nsTableCellReflowState cellReflowState(aPresContext, aReflowState, aCellFrame, LogicalSize(aCellFrame->GetWritingMode(), availSize), nsHTMLReflowState::CALLER_WILL_INIT); InitChildReflowState(*aPresContext, availSize, borderCollapse, cellReflowState); cellReflowState.mFlags.mIsTopOfPage = aIsTopOfPage; @@ -1139,18 +1135,18 @@ nsTableRowFrame::ReflowCellFrame(nsPresC nscoord nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, nscoord aWidth, bool aCollapseGroup, bool& aDidCollapse) { const nsStyleVisibility* rowVis = StyleVisibility(); bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible); - nsTableFrame* tableFrame = static_cast<nsTableFrame*>( - nsTableFrame::GetTableFrame(this)->FirstInFlow()); + nsTableFrame* tableFrame = + static_cast<nsTableFrame*>(GetTableFrame()->FirstInFlow()); if (collapseRow) { tableFrame->SetNeedToCollapse(true); } if (aRowOffset != 0) { // We're moving, so invalidate our old position InvalidateFrameSubtree(); }
--- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -4,18 +4,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsTableRowFrame_h__ #define nsTableRowFrame_h__ #include "mozilla/Attributes.h" #include "nscore.h" #include "nsContainerFrame.h" #include "nsTablePainter.h" +#include "nsTableRowGroupFrame.h" +#include "mozilla/WritingModes.h" -class nsTableFrame; class nsTableCellFrame; struct nsTableCellReflowState; /** * nsTableRowFrame is the frame that maps table rows * (HTML tag TR). This class cannot be reused * outside of an nsTableRowGroupFrame. It assumes that its parent is an nsTableRowGroupFrame, * and its children are nsTableCellFrames. @@ -53,16 +54,28 @@ public: /** instantiate a new instance of nsTableRowFrame. * @param aPresShell the pres shell for this frame * * @return the frame that was created */ friend nsTableRowFrame* NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + nsTableRowGroupFrame* GetTableRowGroupFrame() const + { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableRowGroupFrame); + return static_cast<nsTableRowGroupFrame*>(parent); + } + + nsTableFrame* GetTableFrame() const + { + return GetTableRowGroupFrame()->GetTableFrame(); + } + virtual nsMargin GetUsedMargin() const override; virtual nsMargin GetUsedBorder() const override; virtual nsMargin GetUsedPadding() const override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; @@ -93,16 +106,19 @@ public: * * @see nsGkAtoms::tableRowFrame */ virtual nsIAtom* GetType() const override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif + + virtual mozilla::WritingMode GetWritingMode() const override + { return GetTableFrame()->GetWritingMode(); } void UpdateHeight(nscoord aHeight, nscoord aAscent, nscoord aDescent, nsTableFrame* aTableFrame = nullptr, nsTableCellFrame* aCellFrame = nullptr); void ResetHeight(nscoord aRowStyleHeight);
--- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -69,18 +69,17 @@ int32_t nsTableRowGroupFrame::GetStartRo int32_t result = -1; if (mFrames.NotEmpty()) { NS_ASSERTION(mFrames.FirstChild()->GetType() == nsGkAtoms::tableRowFrame, "Unexpected frame type"); result = static_cast<nsTableRowFrame*>(mFrames.FirstChild())->GetRowIndex(); } // if the row group doesn't have any children, get it the hard way if (-1 == result) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - return tableFrame->GetStartRowIndex(this); + return GetTableFrame()->GetStartRowIndex(this); } return result; } void nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex, int32_t anAdjustment) { @@ -152,26 +151,24 @@ public: NS_DISPLAY_DECL_NAME("TableRowGroupBackground", TYPE_TABLE_ROW_GROUP_BACKGROUND) }; void nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame); - TableBackgroundPainter painter(tableFrame, + auto rgFrame = static_cast<nsTableRowGroupFrame*>(mFrame); + TableBackgroundPainter painter(rgFrame->GetTableFrame(), TableBackgroundPainter::eOrigin_TableRowGroup, mFrame->PresContext(), *aCtx, mVisibleRect, ToReferenceFrame(), aBuilder->GetBackgroundPaintFlags()); - DrawResult result = - painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame)); - + DrawResult result = painter.PaintRowGroup(rgFrame); nsDisplayTableItemGeometry::UpdateDrawResult(this, result); } // Handle the child-traversal part of DisplayGenericTablePart static void DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { @@ -322,17 +319,17 @@ nsTableRowGroupFrame::ReflowChildren(nsP nsHTMLReflowMetrics& aDesiredSize, nsRowGroupReflowState& aReflowState, nsReflowStatus& aStatus, bool* aPageBreakBeforeEnd) { if (aPageBreakBeforeEnd) *aPageBreakBeforeEnd = false; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); const bool borderCollapse = tableFrame->IsBorderCollapse(); // XXXldb Should we really be checking this rather than available height? // (Think about multi-column layout!) bool isPaginated = aPresContext->IsPaginated() && NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height; bool haveRow = false; @@ -520,17 +517,17 @@ nsTableRowGroupFrame::DidResizeRows(nsHT // Actual row heights will be adjusted later if the table has a style height. // Even if rows don't change height, this method must be called to set the heights of each // cell in the row to the height of its row. void nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); const bool isPaginated = aPresContext->IsPaginated(); int32_t numEffCols = tableFrame->GetEffectiveColCount(); int32_t startRowIndex = GetStartRowIndex(); // find the row corresponding to the row index we just found nsTableRowFrame* startRowFrame = GetFirstRow(); @@ -799,17 +796,17 @@ nsTableRowGroupFrame::CalculateRowHeight aDesiredSize.Height() = rowGroupHeight; // Adjust our desired size } nscoord nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset, nscoord aWidth) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); const nsStyleVisibility* groupVis = StyleVisibility(); bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible); if (collapseGroup) { tableFrame->SetNeedToCollapse(true); } nsOverflowAreas overflow; @@ -1289,17 +1286,17 @@ nsTableRowGroupFrame::Reflow(nsPresConte aStatus = NS_FRAME_COMPLETE; // Row geometry may be going to change so we need to invalidate any row cursor. ClearRowCursor(); // see if a special height reflow needs to occur due to having a pct height nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); nsRowGroupReflowState state(aReflowState, tableFrame); const nsStyleVisibility* groupVis = StyleVisibility(); bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible); if (collapseGroup) { tableFrame->SetNeedToCollapse(true); } // Check for an overflow list @@ -1370,17 +1367,17 @@ nsTableRowGroupFrame::UpdateOverflow() /* virtual */ void nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsContainerFrame::DidSetStyleContext(aOldStyleContext); if (!aOldStyleContext) //avoid this on init return; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { nsIntRect damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(), GetRowCount()); tableFrame->AddBCDamageArea(damageArea); } } @@ -1407,17 +1404,17 @@ nsTableRowGroupFrame::AppendFrames(Child } } int32_t rowIndex = GetRowCount(); // Append the frames to the sibling chain mFrames.AppendFrames(nullptr, aFrameList); if (rows.Length() > 0) { - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); tableFrame->AppendRows(this, rowIndex, rows); PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_HAS_DIRTY_CHILDREN); tableFrame->SetGeometryDirty(); } } @@ -1430,17 +1427,17 @@ nsTableRowGroupFrame::InsertFrames(Child NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this, "inserting after sibling frame with different parent"); DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames ClearRowCursor(); // collect the new row frames in an array // XXXbz why are we doing the QI stuff? There shouldn't be any non-rows here. - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); nsTArray<nsTableRowFrame*> rows; bool gotFirstRow = false; for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) { nsTableRowFrame *rowFrame = do_QueryFrame(e.get()); NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up"); if (rowFrame) { NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == e.get()->StyleDisplay()->mDisplay, @@ -1474,20 +1471,20 @@ nsTableRowGroupFrame::InsertFrames(Child void nsTableRowGroupFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) { NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); ClearRowCursor(); - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); // XXX why are we doing the QI stuff? There shouldn't be any non-rows here. nsTableRowFrame* rowFrame = do_QueryFrame(aOldFrame); if (rowFrame) { + nsTableFrame* tableFrame = GetTableFrame(); // remove the rows from the table (and flag a rebalance) tableFrame->RemoveRows(*rowFrame, 1, true); PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_HAS_DIRTY_CHILDREN); tableFrame->SetGeometryDirty(); } @@ -1511,17 +1508,17 @@ nsTableRowGroupFrame::GetUsedPadding() c { return nsMargin(0,0,0,0); } nscoord nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState) { nscoord result = 0; - nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsTableFrame* tableFrame = GetTableFrame(); int32_t startRowIndex = GetStartRowIndex(); if ((aReflowState.ComputedHeight() > 0) && (aReflowState.ComputedHeight() < NS_UNCONSTRAINEDSIZE)) { nscoord cellSpacing = tableFrame->GetRowSpacing(startRowIndex, std::max(startRowIndex, startRowIndex + GetRowCount() - 1)); result = aReflowState.ComputedHeight() - cellSpacing; } else { @@ -1647,31 +1644,30 @@ int32_t nsTableRowGroupFrame::GetNumLines() { return GetRowCount(); } bool nsTableRowGroupFrame::GetDirection() { - nsTableFrame* table = nsTableFrame::GetTableFrame(this); return (NS_STYLE_DIRECTION_RTL == - table->StyleVisibility()->mDirection); + GetTableFrame()->StyleVisibility()->mDirection); } NS_IMETHODIMP nsTableRowGroupFrame::GetLine(int32_t aLineNumber, nsIFrame** aFirstFrameOnLine, int32_t* aNumFramesOnLine, nsRect& aLineBounds) { NS_ENSURE_ARG_POINTER(aFirstFrameOnLine); NS_ENSURE_ARG_POINTER(aNumFramesOnLine); - nsTableFrame* table = nsTableFrame::GetTableFrame(this); + nsTableFrame* table = GetTableFrame(); nsTableCellMap* cellMap = table->GetCellMap(); *aFirstFrameOnLine = nullptr; *aNumFramesOnLine = 0; aLineBounds.SetRect(0, 0, 0, 0); if ((aLineNumber < 0) || (aLineNumber >= GetRowCount())) { return NS_OK; @@ -1723,17 +1719,17 @@ nsTableRowGroupFrame::CheckLineOrder(int NS_IMETHODIMP nsTableRowGroupFrame::FindFrameAt(int32_t aLineNumber, nsPoint aPos, nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame, bool* aPosIsAfterLastFrame) { - nsTableFrame* table = nsTableFrame::GetTableFrame(this); + nsTableFrame* table = GetTableFrame(); nsTableCellMap* cellMap = table->GetCellMap(); WritingMode wm = table->GetWritingMode(); nscoord cw = table->GetRect().width; LogicalPoint pos(wm, aPos, cw); *aFrameFound = nullptr; *aPosIsBeforeFirstFrame = true;
--- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -7,18 +7,18 @@ #include "mozilla/Attributes.h" #include "nscore.h" #include "nsContainerFrame.h" #include "nsIAtom.h" #include "nsILineIterator.h" #include "nsTablePainter.h" #include "nsTArray.h" +#include "nsTableFrame.h" -class nsTableFrame; class nsTableRowFrame; struct nsRowGroupReflowState { const nsHTMLReflowState& reflowState; // Our reflow state nsTableFrame* tableFrame; // The available size (computed from the parent) @@ -63,16 +63,23 @@ public: * @param aPresShell the pres shell for this frame * * @return the frame that was created */ friend nsTableRowGroupFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); virtual ~nsTableRowGroupFrame(); + nsTableFrame* GetTableFrame() const + { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableFrame); + return static_cast<nsTableFrame*>(parent); + } + virtual void DestroyFrom(nsIFrame* aDestructRoot) override; /** @see nsIFrame::DidSetStyleContext */ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override; virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override; virtual void InsertFrames(ChildListID aListID, @@ -113,16 +120,19 @@ public: virtual nsIAtom* GetType() const override; nsTableRowFrame* GetFirstRow(); #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif + virtual mozilla::WritingMode GetWritingMode() const override + { return GetTableFrame()->GetWritingMode(); } + /** return the number of child rows (not necessarily == number of child frames) */ int32_t GetRowCount(); /** return the table-relative row index of the first row in this rowgroup. * if there are no rows, -1 is returned. */ int32_t GetStartRowIndex();
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -127,17 +127,20 @@ pref("dom.indexedDB.logging.profiler-mar // Whether or not Web Workers are enabled. pref("dom.workers.enabled", true); // The number of workers per domain allowed to run concurrently. pref("dom.workers.maxPerDomain", 20); // Whether or not Shared Web Workers are enabled. pref("dom.workers.sharedWorkers.enabled", true); -// WebSocket in workers are disabled by default. +// Whether or not WebSockets in workers are enabled. +// Note: we need this pref because WebSocket in Workers is a new implementation +// and we want to be able to disable it quickly in case of regressions. +// When this feature is stable enough we can get rid of this pref: Bug 1159792 pref("dom.workers.websocket.enabled", true); // Service workers pref("dom.serviceWorkers.enabled", false); // Whether nonzero values can be returned from performance.timing.* pref("dom.enable_performance", true); @@ -243,16 +246,19 @@ pref("browser.chrome.toolbar_style", // if 0, no images are used for tab icons for image documents. pref("browser.chrome.image_icons.max_size", 1024); pref("browser.triple_click_selects_paragraph", true); // Print/Preview Shrink-To-Fit won't shrink below 20% for text-ish documents. pref("print.shrink-to-fit.scale-limit-percent", 20); +// Enable scale transform for stretchy MathML operators. See bug 414277. +pref("mathml.scale_stretchy_operators.enabled", true); + // Media cache size in kilobytes pref("media.cache_size", 512000); // When a network connection is suspended, don't resume it until the // amount of buffered data falls below this threshold (in seconds). pref("media.cache_resume_threshold", 999999); // Stop reading ahead when our buffered data is this many seconds ahead // of the current playback position. This limit can stop us from using arbitrary // amounts of network bandwidth prefetching huge videos. @@ -433,17 +439,17 @@ pref("media.webvtt.regions.enabled", fal // AudioTrack and VideoTrack support pref("media.track.enabled", false); // Whether to enable MediaSource support. // We want to enable on non-release builds and on release windows and mac // but on release builds restrict to YouTube. We don't enable for other // configurations because code for those platforms isn't ready yet. -#if defined(XP_WIN) || defined(XP_MACOSX) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) pref("media.mediasource.enabled", true); #else pref("media.mediasource.enabled", false); #endif #ifdef RELEASE_BUILD pref("media.mediasource.whitelist", true); #else @@ -2378,17 +2384,17 @@ pref("plugin.persistentPermissionAlways. // before we consider it "hung". pref("dom.ipc.plugins.timeoutSecs", 45); // How long a plugin process will wait for a response from the parent // to a synchronous request before terminating itself. After this // point the child assumes the parent is hung. Currently disabled. pref("dom.ipc.plugins.parentTimeoutSecs", 0); // How long a plugin in e10s is allowed to process a synchronous IPC // message before we notify the chrome process of a hang. -pref("dom.ipc.plugins.contentTimeoutSecs", 45); +pref("dom.ipc.plugins.contentTimeoutSecs", 10); // How long a plugin launch is allowed to take before // we consider it failed. pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45); #ifdef XP_WIN // How long a plugin is allowed to process a synchronous IPC message // before we display the plugin hang UI pref("dom.ipc.plugins.hangUITimeoutSecs", 11); // Minimum time that the plugin hang UI will be displayed
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -316,35 +316,44 @@ nsHttpChannel::Connect() // Even if we're in private browsing mode, we still enforce existing STS // data (it is read-only). // if the connection is not using SSL and either the exact host matches or // a superdomain wants to force HTTPS, do it. bool isHttps = false; rv = mURI->SchemeIs("https", &isHttps); NS_ENSURE_SUCCESS(rv,rv); - if (mAllowSTS && !isHttps) { + if (!isHttps) { // enforce Strict-Transport-Security nsISiteSecurityService* sss = gHttpHandler->GetSSService(); NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY); bool isStsHost = false; uint32_t flags = mPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, mURI, flags, &isStsHost); // if the SSS check fails, it's likely because this load is on a // malformed URI or something else in the setup is wrong, so any error // should be reported. NS_ENSURE_SUCCESS(rv, rv); if (isStsHost) { LOG(("nsHttpChannel::Connect() STS permissions found\n")); - return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps); + if (mAllowSTS) { + Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 3); + return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps); + } else { + Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 2); + } + } else { + Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 1); } + } else { + Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 0); } // ensure that we are using a valid hostname if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Host()))) return NS_ERROR_UNKNOWN_HOST; // Finalize ConnectionInfo flags before SpeculativeConnect mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0); @@ -2320,17 +2329,17 @@ nsHttpChannel::ProcessPartialContent() this, mTransaction.get(), cachedContentLength, entitySize, mResponseHead->PeekHeader(nsHttp::Content_Range))); if ((entitySize >= 0) && (cachedContentLength >= 0) && (entitySize != cachedContentLength)) { LOG(("nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length " "of the original partially cached entity.\n", this)); - + mCacheEntry->AsyncDoom(nullptr); Cancel(NS_ERROR_CORRUPTED_CONTENT); return CallOnStartRequest(); } if (mConcurentCacheAccess) { // We started to read cached data sooner than its write has been done. // But the concurrent write has not finished completely, so we had to @@ -2755,17 +2764,17 @@ nsHttpChannel::OpenCacheEntry(bool isHtt cacheEntryOpenFlags = nsICacheStorage::OPEN_TRUNCATE; } else { cacheEntryOpenFlags = nsICacheStorage::OPEN_NORMALLY | nsICacheStorage::CHECK_MULTITHREADED; } if (!mPostID && mApplicationCache) { - rv = cacheStorageService->AppCacheStorage(info, + rv = cacheStorageService->AppCacheStorage(info, mApplicationCache, getter_AddRefs(cacheStorage)); } else if (PossiblyIntercepted() || mLoadFlags & INHIBIT_PERSISTENT_CACHING) { rv = cacheStorageService->MemoryCacheStorage(info, // ? choose app cache as well... getter_AddRefs(cacheStorage)); } else { @@ -5806,17 +5815,17 @@ nsHttpChannel::OnDataAvailable(nsIReques "http channel Listener OnDataAvailable contract violation")); if (consoleService) { consoleService->LogStringMessage(message.get()); } } } mLogicalOffset += count; } - + return rv; } return NS_ERROR_ABORT; } //----------------------------------------------------------------------------- // nsHttpChannel::nsIThreadRetargetableRequest
--- a/python/mozbuild/mozbuild/mach_commands.py +++ b/python/mozbuild/mozbuild/mach_commands.py @@ -671,17 +671,20 @@ class GTestCommands(MachCommandBase): # Use GTest environment variable to control test execution # For details see: # https://code.google.com/p/googletest/wiki/AdvancedGuide#Running_Test_Programs:_Advanced_Options gtest_env = {b'GTEST_FILTER': gtest_filter} xre_path = os.path.join(self.topobjdir, "dist", "bin") gtest_env["MOZ_XRE_DIR"] = xre_path - gtest_env["MOZ_GMP_PATH"] = os.path.join(xre_path, "gmp-fake", "1.0") + gtest_env["MOZ_GMP_PATH"] = os.pathsep.join( + os.path.join(xre_path, p, "1.0") + for p in ('gmp-fake', 'gmp-fakeopenh264') + ) gtest_env[b"MOZ_RUN_GTEST"] = b"True" if shuffle: gtest_env[b"GTEST_SHUFFLE"] = b"True" if tbpl_parser: gtest_env[b"MOZ_TBPL_PARSER"] = b"True"
--- a/security/sandbox/win/wow_helper/Makefile.in +++ b/security/sandbox/win/wow_helper/Makefile.in @@ -35,8 +35,13 @@ LIB = $(call lazy,LIB,$$(shell python -c CXXFLAGS := $(filter-out -arch:IA32,$(CXXFLAGS)) # OS_COMPILE_CXXFLAGS includes mozilla-config.h, which contains x86-specific # defines breaking the build. OS_COMPILE_CXXFLAGS := # LNK1246: '/SAFESEH' not compatible with 'x64' target machine LDFLAGS := $(filter-out -SAFESEH,$(LDFLAGS)) + +# When targetting x64, we need to specify a subsystem of at least 5.02, because +# the 5.01 value we inherit from the x86 parts is silently ignored, making the +# linker default to 6.00 (Vista) as of VS2013. +WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,5.02
--- a/testing/gtest/rungtests.py +++ b/testing/gtest/rungtests.py @@ -62,17 +62,20 @@ class GTests(object): return result def build_core_environment(self, env = {}): """ Add environment variables likely to be used across all platforms, including remote systems. """ env["MOZILLA_FIVE_HOME"] = self.xre_path env["MOZ_XRE_DIR"] = self.xre_path - env["MOZ_GMP_PATH"] = os.path.join(self.xre_path, "gmp-fake", "1.0") + env["MOZ_GMP_PATH"] = os.pathsep.join( + os.path.join(self.xre_path, p, "1.0") + for p in ('gmp-fake', 'gmp-fakeopenh264') + ) env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" env["MOZ_CRASHREPORTER"] = "1" env["MOZ_RUN_GTEST"] = "1" # Normally we run with GTest default output, override this to use the TBPL test format. env["MOZ_TBPL_PARSER"] = "1" if not mozinfo.has_sandbox:
deleted file mode 100644 --- a/testing/marionette/client/marionette/tests/unit/test_submit.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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/. - -import time - -from marionette_driver.by import By -from marionette_driver.errors import NoSuchElementException -from marionette_driver.wait import Wait -from marionette import MarionetteTestCase - -class TestSubmit(MarionetteTestCase): - - def test_should_be_able_to_submit_forms(self): - test_html = self.marionette.absolute_url("formPage.html") - self.marionette.navigate(test_html) - self.marionette.find_element(By.NAME, "login").submit() - for x in xrange(1, 10): - try: - self.marionette.find_element(By.NAME, "login") - time.sleep(1) - except NoSuchElementException: - break - - Wait(self.marionette, timeout=10, ignored_exceptions=NoSuchElementException)\ - .until(lambda m: m.find_element(By.ID, 'email')) - title = self.marionette.title - count = 0 - while self.marionette.title == '' and count <= 10: - time.sleep(1) - title = self.marionette.title - count = count + 1 - if title != '': - break - self.assertEqual(title, "We Arrive Here") - - def test_should_submit_a_form_when_any_input_element_within_that_form_is_submitted(self): - test_html = self.marionette.absolute_url("formPage.html") - self.marionette.navigate(test_html) - self.marionette.find_element(By.ID, "checky").submit() - - for x in xrange(1, 10): - try: - self.marionette.find_element(By.ID, "checky") - time.sleep(1) - except NoSuchElementException: - break - - Wait(self.marionette, ignored_exceptions=NoSuchElementException).until( - lambda m: m.find_element(By.ID, 'email')) - self.assertEqual(self.marionette.title, "We Arrive Here") - - def test_should_submit_a_form_when_any_element_wihin_that_form_is_submitted(self): - test_html = self.marionette.absolute_url("formPage.html") - self.marionette.navigate(test_html) - self.marionette.find_element(By.XPATH, "//form/p").submit() - - for x in xrange(1, 10): - try: - self.marionette.find_element(By.XPATH, "//form/p") - time.sleep(1) - except NoSuchElementException: - break - - Wait(self.marionette, ignored_exceptions=NoSuchElementException).until( - lambda m: m.find_element(By.ID, 'email')) - self.assertEqual(self.marionette.title, "We Arrive Here")
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -127,17 +127,16 @@ b2g = false b2g = false [test_implicit_waits.py] [test_wait.py] [test_expected.py] [test_date_time_value.py] [test_getactiveframe_oop.py] disabled = "Bug 925688" b2g = false -[test_submit.py] [test_chrome_async_finish.js] [test_screen_orientation.py] browser = false [test_errors.py] [test_execute_isolate.py] [test_click_scrolling.py] [test_profile_management.py]
--- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -2083,35 +2083,16 @@ GeckoDriver.prototype.getElementValueOfC case Context.CONTENT: resp.value = yield this.listener.getElementValueOfCssProperty( {id: id, propertyName: prop}); break; } }; /** - * Submit a form on a content page by either using form or element in - * a form. - * - * @param {string} id - * Reference to the elemen that will be checked. - */ -GeckoDriver.prototype.submitElement = function(cmd, resp) { - switch (this.context) { - case Context.CHROME: - throw new WebDriverError( - "Command 'submitElement' is not available in chrome context"); - - case Context.CONTENT: - yield this.listener.submitElement({id: cmd.parameters.id}); - break; - } -}; - -/** * Check if element is enabled. * * @param {string} id * Reference ID to the element that will be checked. */ GeckoDriver.prototype.isElementEnabled = function(cmd, resp) { let id = cmd.parameters.id; @@ -2947,17 +2928,16 @@ GeckoDriver.prototype.commands = { "findElements": GeckoDriver.prototype.findElements, "findChildElements":GeckoDriver.prototype.findChildElements, // Needed for WebDriver compat "clickElement": GeckoDriver.prototype.clickElement, "getElementAttribute": GeckoDriver.prototype.getElementAttribute, "getElementText": GeckoDriver.prototype.getElementText, "getElementTagName": GeckoDriver.prototype.getElementTagName, "isElementDisplayed": GeckoDriver.prototype.isElementDisplayed, "getElementValueOfCssProperty": GeckoDriver.prototype.getElementValueOfCssProperty, - "submitElement": GeckoDriver.prototype.submitElement, "getElementSize": GeckoDriver.prototype.getElementSize, //deprecated "getElementRect": GeckoDriver.prototype.getElementRect, "isElementEnabled": GeckoDriver.prototype.isElementEnabled, "isElementSelected": GeckoDriver.prototype.isElementSelected, "sendKeysToElement": GeckoDriver.prototype.sendKeysToElement, "getElementLocation": GeckoDriver.prototype.getElementLocation, // deprecated "getElementPosition": GeckoDriver.prototype.getElementLocation, // deprecated "clearElement": GeckoDriver.prototype.clearElement,
--- a/testing/marionette/driver/marionette_driver/marionette.py +++ b/testing/marionette/driver/marionette_driver/marionette.py @@ -169,21 +169,16 @@ class HTMLElement(object): ''' Gets the value of the specified CSS property name. :param property_name: Property name to get the value of. ''' return self.marionette._send_message('getElementValueOfCssProperty', 'value', id=self.id, propertyName=property_name) - def submit(self): - ''' - Submits if the element is a form or is within a form - ''' - return self.marionette._send_message('submitElement', 'ok', id=self.id) class MouseButton(object): ''' Enum-like class for mouse button constants ''' LEFT = 0 MIDDLE = 1 RIGHT = 2
--- a/testing/marionette/driver/setup.py +++ b/testing/marionette/driver/setup.py @@ -1,11 +1,11 @@ from setuptools import setup, find_packages -version = '0.5' +version = '0.6' # dependencies with open('requirements.txt') as f: deps = f.read().splitlines() setup(name='marionette_driver', version=version, description="Marionette Driver",
--- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -216,17 +216,16 @@ function startListeners() { addMessageListenerId("Marionette:findElementsContent", findElementsContent); addMessageListenerId("Marionette:getActiveElement", getActiveElementFn); addMessageListenerId("Marionette:clickElement", clickElementFn); addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn); addMessageListenerId("Marionette:getElementText", getElementTextFn); addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn); addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed); addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty); - addMessageListenerId("Marionette:submitElement", submitElement); addMessageListenerId("Marionette:getElementSize", getElementSizeFn); // deprecated addMessageListenerId("Marionette:getElementRect", getElementRectFn); addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn); addMessageListenerId("Marionette:isElementSelected", isElementSelected); addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); addMessageListenerId("Marionette:getElementLocation", getElementLocation); //deprecated addMessageListenerId("Marionette:clearElement", clearElement); addMessageListenerId("Marionette:switchToFrame", switchToFrame); @@ -321,17 +320,16 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:findElementsContent", findElementsContent); removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn); removeMessageListenerId("Marionette:clickElement", clickElementFn); removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn); removeMessageListenerId("Marionette:getElementText", getElementTextFn); removeMessageListenerId("Marionette:getElementTagName", getElementTagNameFn); removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed); removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssProperty); - removeMessageListenerId("Marionette:submitElement", submitElement); removeMessageListenerId("Marionette:getElementSize", getElementSizeFn); // deprecated removeMessageListenerId("Marionette:getElementRect", getElementRectFn); removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn); removeMessageListenerId("Marionette:isElementSelected", isElementSelected); removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); removeMessageListenerId("Marionette:getElementLocation", getElementLocation); removeMessageListenerId("Marionette:clearElement", clearElement); removeMessageListenerId("Marionette:switchToFrame", switchToFrame); @@ -451,53 +449,54 @@ function checkForInterrupted() { /* * Marionette Methods */ /** * Returns a content sandbox that can be used by the execute_foo functions. */ -function createExecuteContentSandbox(aWindow, timeout) { - let sandbox = new Cu.Sandbox(aWindow, {sandboxPrototype: aWindow}); +function createExecuteContentSandbox(win, timeout) { + let mn = new Marionette( + this, + win, + "content", + marionetteLogObj, + timeout, + heartbeatCallback, + marionetteTestName); + mn.runEmulatorCmd = (cmd, cb) => this.runEmulatorCmd(cmd, cb); + mn.runEmulatorShell = (args, cb) => this.runEmulatorShell(args, cb); + + let sandbox = new Cu.Sandbox(win, {sandboxPrototype: win}); sandbox.global = sandbox; - sandbox.window = aWindow; + sandbox.window = win; sandbox.document = sandbox.window.document; sandbox.navigator = sandbox.window.navigator; sandbox.testUtils = utils; sandbox.asyncTestCommandId = asyncTestCommandId; + sandbox.marionette = mn; - let marionette = new Marionette(this, aWindow, "content", - marionetteLogObj, timeout, - heartbeatCallback, - marionetteTestName); - marionette.runEmulatorCmd = (cmd, cb) => this.runEmulatorCmd(cmd, cb); - marionette.runEmulatorShell = (args, cb) => this.runEmulatorShell(args, cb); - sandbox.marionette = marionette; - marionette.exports.forEach(function(fn) { - try { - sandbox[fn] = marionette[fn].bind(marionette); - } - catch(e) { - sandbox[fn] = marionette[fn]; + mn.exports.forEach(fn => { + if (typeof mn[fn] == "function") { + sandbox[fn] = mn[fn].bind(mn); + } else { + sandbox[fn] = mn[fn]; } }); - if (aWindow.wrappedJSObject.SpecialPowers != undefined) { - XPCOMUtils.defineLazyGetter(sandbox, 'SpecialPowers', function() { - return aWindow.wrappedJSObject.SpecialPowers; - }); + let specialPowersFn; + if (typeof win.wrappedJSObject.SpecialPowers != "undefined") { + specialPowersFn = () => win.wrappedJSObject.SpecialPowers; + } else { + specialPowersFn = () => new SpecialPowers(win); } - else { - XPCOMUtils.defineLazyGetter(sandbox, 'SpecialPowers', function() { - return new SpecialPowers(aWindow); - }); - } + XPCOMUtils.defineLazyGetter(sandbox, "SpecialPowers", specialPowersFn); - sandbox.asyncComplete = function(obj, id) { + sandbox.asyncComplete = (obj, id) => { if (id == asyncTestCommandId) { curFrame.removeEventListener("unload", onunload, false); curFrame.clearTimeout(asyncTestTimeoutId); if (inactivityTimeoutId != null) { curFrame.clearTimeout(inactivityTimeoutId); } @@ -520,19 +519,19 @@ function createExecuteContentSandbox(aWi asyncTestTimeoutId = undefined; asyncTestCommandId = undefined; inactivityTimeoutId = null; } }; sandbox.finish = function() { if (asyncTestRunning) { - sandbox.asyncComplete(marionette.generate_results(), sandbox.asyncTestCommandId); + sandbox.asyncComplete(mn.generate_results(), sandbox.asyncTestCommandId); } else { - return marionette.generate_results(); + return mn.generate_results(); } }; sandbox.marionetteScriptFinished = val => sandbox.asyncComplete(val, sandbox.asyncTestCommandId); return sandbox; } @@ -1449,39 +1448,16 @@ function getElementValueOfCssProperty(ms sendResponse({value: curFrame.document.defaultView.getComputedStyle(el, null).getPropertyValue(propertyName)}, command_id); } catch (e) { sendError(e, command_id); } } /** - * Submit a form on a content page by either using form or element in a form - * @param object msg - * 'json' JSON object containing 'id' member of the element - */ -function submitElement (msg) { - let command_id = msg.json.command_id; - try { - let el = elementManager.getKnownElement(msg.json.id, curFrame); - while (el.parentNode != null && el.tagName.toLowerCase() != 'form') { - el = el.parentNode; - } - if (el.tagName && el.tagName.toLowerCase() == 'form') { - el.submit(); - sendOk(command_id); - } else { - sendError(new NoSuchElementError("Element is not a form element or in a form"), command_id); - } - } catch (e) { - sendError(e, command_id); - } -} - -/** * Get the size of the element. * * @param {WebElement} id * Web element reference. * * @return {Object.<string, number>} * The width/height dimensions of th element. */
--- a/testing/mochitest/Makefile.in +++ b/testing/mochitest/Makefile.in @@ -81,16 +81,17 @@ TEST_HARNESS_PLUGINS := \ endif # Rules for staging the necessary harness bits for a test package PKG_STAGE = $(DIST)/test-stage DIST_BIN = $(DIST)/bin GMP_TEST_PLUGIN_DIRS := \ $(DIST_BIN)/gmp-fake \ + $(DIST_BIN)/gmp-fakeopenh264 \ $(DIST_BIN)/gmp-clearkey \ $(NULL) $(_DEST_DIR): $(NSINSTALL) -D $@ # On Android only, include a release signed Robocop APK in the test package. ifeq ($(MOZ_BUILD_APP),mobile/android)
--- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -452,25 +452,24 @@ class MochitestRunner(MozbuildObject): if app_override == "dist": options.app = self.get_binary_path(where='staged-package') elif app_override: options.app = app_override if options.gmp_path is None: # Need to fix the location of gmp_fake which might not be # shipped in the binary bin_path = self.get_binary_path() - options.gmp_path = os.path.join( - os.path.dirname(bin_path), - 'gmp-fake', - '1.0') - options.gmp_path += os.pathsep - options.gmp_path += os.path.join( - os.path.dirname(bin_path), - 'gmp-clearkey', - '0.1') + gmp_modules = ( + ('gmp-fake', '1.0'), + ('gmp-clearkey', '0.1'), + ('gmp-fakeopenh264', '1.0') + ) + options.gmp_path = os.pathsep.join( + os.path.join(os.path.dirname(bin_path), *p) + for p in gmp_modules) logger_options = { key: value for key, value in vars(options).iteritems() if key.startswith('log')} runner = mochitest.Mochitest(logger_options) options = opts.verifyOptions(options, runner) if options is None:
--- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -1446,16 +1446,17 @@ class Mochitest(MochitestUtilsMixin): options.xrePath, # For packaged builds, GMP plugins will get copied under # $profile/plugins. os.path.join(self.profile.profile, 'plugins'), ] gmp_subdirs = [ os.path.join('gmp-fake', '1.0'), + os.path.join('gmp-fakeopenh264', '1.0'), os.path.join('gmp-clearkey', '0.1'), ] gmp_paths = [os.path.join(parent, sub) for parent in gmp_parentdirs for sub in gmp_subdirs if os.path.isdir(os.path.join(parent, sub))]
--- a/testing/mozharness/mozharness.json +++ b/testing/mozharness/mozharness.json @@ -1,4 +1,4 @@ { "repo": "https://hg.mozilla.org/build/mozharness", - "revision": "23dee28169d6" + "revision": "fa7ea67fc5a2" }
--- a/testing/web-platform/harness/wptrunner/executors/executormarionette.py +++ b/testing/web-platform/harness/wptrunner/executors/executormarionette.py @@ -152,30 +152,29 @@ class MarionetteProtocol(Protocol): def set_pref(self, name, value): self.logger.info("Setting pref %s (%s)" % (name, value)) self.marionette.set_context(self.marionette.CONTEXT_CHROME) script = """ let prefInterface = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch); let pref = '%s'; - let value = '%s'; let type = prefInterface.getPrefType(pref); switch(type) { case prefInterface.PREF_STRING: - prefInterface.setCharPref(pref, value); + prefInterface.setCharPref(pref, '%s'); break; case prefInterface.PREF_BOOL: - prefInterface.setBoolPref(pref, value); + prefInterface.setBoolPref(pref, %s); break; case prefInterface.PREF_INT: - prefInterface.setIntPref(pref, value); + prefInterface.setIntPref(pref, %s); break; } - """ % (name, value) + """ % (name, value, value, value) self.marionette.execute_script(script) self.marionette.set_context(self.marionette.CONTEXT_CONTENT) def clear_user_pref(self, name): self.logger.info("Clearing pref %s" % (name)) self.marionette.set_context(self.marionette.CONTEXT_CHROME) script = """ let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
--- a/testing/web-platform/harness/wptrunner/executors/executorservo.py +++ b/testing/web-platform/harness/wptrunner/executors/executorservo.py @@ -181,17 +181,18 @@ class ServoRefTestExecutor(ProcessTestEx os.rmdir(self.tempdir) ProcessTestExecutor.teardown(self) def screenshot(self, test): full_url = self.test_url(test) with TempFilename(self.tempdir) as output_path: self.command = [self.binary, "--cpu", "--hard-fail", "--exit", - "--output=%s" % output_path, full_url] + "-Z", "disable-text-aa", "--output=%s" % output_path, + full_url] env = os.environ.copy() env["HOST_FILE"] = self.hosts_path self.proc = ProcessHandler(self.command, processOutputLine=[self.on_output], env=env)
--- a/toolkit/components/addoncompat/RemoteAddonsChild.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsChild.jsm @@ -129,16 +129,20 @@ let NotificationTracker = { let watchers = this._watchers[component1]; let index = watchers.lastIndexOf(watcher); if (index > -1) { watchers.splice(index, 1); } this._registered.delete(watcher); }, + + getCount(component1) { + return this.findPaths([component1]).length; + }, }; // This code registers an nsIContentPolicy in the child process. When // it runs, it notifies the parent that it needs to run its own // nsIContentPolicy list. If any policy in the parent rejects a // resource load, that answer is returned to the child. let ContentPolicyChild = { _classDescription: "Addon shim content policy", @@ -538,9 +542,13 @@ let RemoteAddonsChild = { for (let shim of perTabShims) { try { shim.uninit(); } catch(e) { Cu.reportError(e); } } }, + + get useSyncWebProgress() { + return NotificationTracker.getCount("web-progress") > 0; + }, };
--- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -5,16 +5,17 @@ this.EXPORTED_SYMBOLS = ["RemoteAddonsParent"]; const Ci = Components.interfaces; const Cc = Components.classes; const Cu = Components.utils; const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/RemoteWebProgress.jsm"); Cu.import('resource://gre/modules/Services.jsm'); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Prefetcher", "resource://gre/modules/Prefetcher.jsm"); @@ -874,16 +875,80 @@ TabBrowserElementInterposition.getters.c TabBrowserElementInterposition.getters.contentDocument = function(addon, target) { CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.", addon, CompatWarning.warnings.content); let browser = target.selectedBrowser; return getContentDocument(addon, browser); }; +// This function returns a wrapper around an +// nsIWebProgressListener. When the wrapper is invoked, it calls the +// real listener but passes CPOWs for the nsIWebProgress and +// nsIRequest arguments. +let progressListeners = {global: new WeakMap(), tabs: new WeakMap()}; +function wrapProgressListener(kind, listener) +{ + if (progressListeners[kind].has(listener)) { + return progressListeners[kind].get(listener); + } + + let ListenerHandler = { + get: function(target, name) { + if (name.startsWith("on")) { + return function(...args) { + listener[name].apply(listener, RemoteWebProgressManager.argumentsForAddonListener(kind, args)); + }; + } + + return listener[name]; + } + }; + let listenerProxy = new Proxy(listener, ListenerHandler); + + progressListeners[kind].set(listener, listenerProxy); + return listenerProxy; +} + +TabBrowserElementInterposition.methods.addProgressListener = function(addon, target, listener) { + if (!target.ownerDocument.defaultView.gMultiProcessBrowser) { + return target.addProgressListener(listener); + } + + NotificationTracker.add(["web-progress", addon]); + return target.addProgressListener(wrapProgressListener("global", listener)); +}; + +TabBrowserElementInterposition.methods.removeProgressListener = function(addon, target, listener) { + if (!target.ownerDocument.defaultView.gMultiProcessBrowser) { + return target.removeProgressListener(listener); + } + + NotificationTracker.remove(["web-progress", addon]); + return target.removeProgressListener(wrapProgressListener("global", listener)); +}; + +TabBrowserElementInterposition.methods.addTabsProgressListener = function(addon, target, listener) { + if (!target.ownerDocument.defaultView.gMultiProcessBrowser) { + return target.addTabsProgressListener(listener); + } + + NotificationTracker.add(["web-progress", addon]); + return target.addTabsProgressListener(wrapProgressListener("tabs", listener)); +}; + +TabBrowserElementInterposition.methods.removeTabsProgressListener = function(addon, target, listener) { + if (!target.ownerDocument.defaultView.gMultiProcessBrowser) { + return target.removeTabsProgressListener(listener); + } + + NotificationTracker.remove(["web-progress", addon]); + return target.removeTabsProgressListener(wrapProgressListener("tabs", listener)); +}; + let ChromeWindowInterposition = new Interposition("ChromeWindowInterposition", EventTargetInterposition); // _content is for older add-ons like pinboard and all-in-one gestures // that should be using content instead. ChromeWindowInterposition.getters.content = ChromeWindowInterposition.getters._content = function(addon, target) { CompatWarning.warn("Direct access to content objects will no longer work in the chrome process.",
--- a/toolkit/components/addoncompat/tests/addon/bootstrap.js +++ b/toolkit/components/addoncompat/tests/addon/bootstrap.js @@ -489,32 +489,78 @@ function testAboutModuleRegistration() gBrowser.removeTab(newTab); unregisterModules(); resolve(); }); }); }); } +function testProgressListener() +{ + const url = baseURL + "browser_addonShims_testpage.html"; + + let sawGlobalLocChange = false; + let sawTabsLocChange = false; + + let globalListener = { + onLocationChange: function(webProgress, request, uri) { + if (uri.spec == url) { + sawGlobalLocChange = true; + ok(request instanceof Ci.nsIHttpChannel, "Global listener channel is an HTTP channel"); + } + }, + }; + + let tabsListener = { + onLocationChange: function(browser, webProgress, request, uri) { + if (uri.spec == url) { + sawTabsLocChange = true; + ok(request instanceof Ci.nsIHttpChannel, "Tab listener channel is an HTTP channel"); + } + }, + }; + + gBrowser.addProgressListener(globalListener); + gBrowser.addTabsProgressListener(tabsListener); + info("Added progress listeners"); + + return new Promise(function(resolve, reject) { + let tab = gBrowser.addTab(url); + gBrowser.selectedTab = tab; + addLoadListener(tab.linkedBrowser, function handler() { + ok(sawGlobalLocChange, "Saw global onLocationChange"); + ok(sawTabsLocChange, "Saw tabs onLocationChange"); + + gBrowser.removeTab(tab); + gBrowser.removeProgressListener(globalListener); + gBrowser.removeTabsProgressListener(tabsListener); + resolve(); + }); + }); +} + function runTests(win, funcs) { ok = funcs.ok; is = funcs.is; info = funcs.info; gWin = win; gBrowser = win.gBrowser; return testContentWindow(). then(testListeners). then(testCapturing). then(testObserver). then(testSandbox). then(testAddonContent). - then(testAboutModuleRegistration); + then(testAboutModuleRegistration). + then(testProgressListener). + then(Promise.resolve()); } /* bootstrap.js API */ function startup(aData, aReason) {
--- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -1196,16 +1196,22 @@ "kind": "boolean", "description": "Whether a HTTP transaction routed via Alt-Svc was scheme=http" }, "HTTP_WAP_CONTENT_TYPE_RECEIVED": { "expires_in_version": "40", "kind": "boolean", "description": "Whether a WAP content type response is served to the browser." }, + "HTTP_SCHEME_UPGRADE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 10, + "description": "Was the URL upgraded to HTTPS? (0=already HTTPS, 1=no reason to upgrade, 2=STS upgrade blocked by pref, 3=upgraded with STS)" + }, "SSL_HANDSHAKE_VERSION": { "expires_in_version": "never", "kind": "enumerated", "n_values": 16, "description": "SSL Version (1=tls1, 2=tls1.1, 3=tls1.2)" }, "SSL_TIME_UNTIL_READY": { "expires_in_version": "never",
--- a/toolkit/content/aboutServiceWorkers.js +++ b/toolkit/content/aboutServiceWorkers.js @@ -127,17 +127,17 @@ function display(info) { error => { dump("about:serviceworkers - push registration failed\n"); } ); let updateButton = document.createElement("button"); updateButton.appendChild(document.createTextNode(bundle.GetStringFromName('update'))); updateButton.onclick = function() { - gSWM.update(info.scope); + gSWM.softUpdate(info.scope); }; div.appendChild(updateButton); let unregisterButton = document.createElement("button"); unregisterButton.appendChild(document.createTextNode(bundle.GetStringFromName('unregister'))); div.appendChild(unregisterButton); let loadingMessage = document.createElement('span');
--- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -69,63 +69,73 @@ let WebProgressListener = { return { webProgress: aWebProgress || null, requestURI: this._requestSpec(aRequest, "URI"), originalRequestURI: this._requestSpec(aRequest, "originalURI"), documentContentType: content.document && content.document.contentType }; }, - _setupObjects: function setupObjects(aWebProgress) { + _setupObjects: function setupObjects(aWebProgress, aRequest) { let domWindow; try { domWindow = aWebProgress && aWebProgress.DOMWindow; } catch (e) { // If nsDocShell::Destroy has already been called, then we'll // get NS_NOINTERFACE when trying to get the DOM window. Ignore // that here. domWindow = null; } return { contentWindow: content, // DOMWindow is not necessarily the content-window with subframes. - DOMWindow: domWindow + DOMWindow: domWindow, + webProgress: aWebProgress, + request: aRequest, }; }, + _send(name, data, objects) { + if (RemoteAddonsChild.useSyncWebProgress) { + sendRpcMessage(name, data, objects); + } else { + sendAsyncMessage(name, data, objects); + } + }, + onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { let json = this._setupJSON(aWebProgress, aRequest); - let objects = this._setupObjects(aWebProgress); + let objects = this._setupObjects(aWebProgress, aRequest); json.stateFlags = aStateFlags; json.status = aStatus; - sendAsyncMessage("Content:StateChange", json, objects); + this._send("Content:StateChange", json, objects); }, onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) { let json = this._setupJSON(aWebProgress, aRequest); - let objects = this._setupObjects(aWebProgress); + let objects = this._setupObjects(aWebProgress, aRequest); json.curSelf = aCurSelf; json.maxSelf = aMaxSelf; json.curTotal = aCurTotal; json.maxTotal = aMaxTotal; - sendAsyncMessage("Content:ProgressChange", json, objects); + this._send("Content:ProgressChange", json, objects); }, onProgressChange64: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) { this.onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal); }, onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) { let json = this._setupJSON(aWebProgress, aRequest); - let objects = this._setupObjects(aWebProgress); + let objects = this._setupObjects(aWebProgress, aRequest); json.location = aLocationURI ? aLocationURI.spec : ""; json.flags = aFlags; // These properties can change even for a sub-frame navigation. let webNav = docShell.QueryInterface(Ci.nsIWebNavigation); json.canGoBack = webNav.canGoBack; json.canGoForward = webNav.canGoForward; @@ -134,37 +144,37 @@ let WebProgressListener = { json.documentURI = content.document.documentURIObject.spec; json.title = content.document.title; json.charset = content.document.characterSet; json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu; json.principal = content.document.nodePrincipal; json.synthetic = content.document.mozSyntheticDocument; } - sendAsyncMessage("Content:LocationChange", json, objects); + this._send("Content:LocationChange", json, objects); }, onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) { let json = this._setupJSON(aWebProgress, aRequest); - let objects = this._setupObjects(aWebProgress); + let objects = this._setupObjects(aWebProgress, aRequest); json.status = aStatus; json.message = aMessage; - sendAsyncMessage("Content:StatusChange", json, objects); + this._send("Content:StatusChange", json, objects); }, onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) { let json = this._setupJSON(aWebProgress, aRequest); - let objects = this._setupObjects(aWebProgress); + let objects = this._setupObjects(aWebProgress, aRequest); json.state = aState; json.status = SecurityUI.getSSLStatusAsString(); - sendAsyncMessage("Content:SecurityChange", json, objects); + this._send("Content:SecurityChange", json, objects); }, onRefreshAttempted: function onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) { return true; }, QueryInterface: function QueryInterface(aIID) { if (aIID.equals(Ci.nsIWebProgressListener) ||
--- a/toolkit/modules/RemoteWebProgress.jsm +++ b/toolkit/modules/RemoteWebProgress.jsm @@ -12,30 +12,35 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); function newURI(spec) { return Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService) .newURI(spec, null, null); } -function RemoteWebProgressRequest(spec, originalSpec) +function RemoteWebProgressRequest(spec, originalSpec, requestCPOW) { + this.wrappedJSObject = this; + this._uri = newURI(spec); this._originalURI = newURI(originalSpec); + this._requestCPOW = requestCPOW; } RemoteWebProgressRequest.prototype = { QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannel]), get URI() { return this._uri.clone(); }, get originalURI() { return this._originalURI.clone(); } }; function RemoteWebProgress(aManager, aIsTopLevel) { + this.wrappedJSObject = this; + this._manager = aManager; this._isLoadingDocument = false; this._DOMWindow = null; this._DOMWindowID = 0; this._isTopLevel = aIsTopLevel; this._loadType = 0; } @@ -70,16 +75,45 @@ RemoteWebProgress.prototype = { function RemoteWebProgressManager (aBrowser) { this._topLevelWebProgress = new RemoteWebProgress(this, true); this._progressListeners = []; this.swapBrowser(aBrowser); } +RemoteWebProgressManager.argumentsForAddonListener = function(kind, args) { + function checkType(arg, typ) {