diff --git a/accessible/base/MarkupMap.h b/accessible/base/MarkupMap.h index 5ba1a06e6926..7e16f5d28b8a 100644 --- a/accessible/base/MarkupMap.h +++ b/accessible/base/MarkupMap.h @@ -95,6 +95,10 @@ MARKUPMAP(h6, New_HyperText, roles::HEADING) +MARKUPMAP(input, + New_HTMLInput, + 0) + MARKUPMAP(label, New_HTMLLabel, roles::LABEL) diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index efccd31627de..59b003abea0b 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -195,6 +195,19 @@ New_HTMLDefinition(nsIContent* aContent, Accessible* aContext) static Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext) { return new HTMLLabelAccessible(aContent, aContext->Document()); } +static Accessible* New_HTMLInput(nsIContent* aContent, Accessible* aContext) +{ + if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::checkbox, eIgnoreCase)) { + return new HTMLCheckboxAccessible(aContent, aContext->Document()); + } + if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::radio, eIgnoreCase)) { + return new HTMLRadioButtonAccessible(aContent, aContext->Document()); + } + return nullptr; +} + static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext) { return new HTMLOutputAccessible(aContent, aContext->Document()); } diff --git a/accessible/tests/mochitest/events/test_scroll.xul b/accessible/tests/mochitest/events/test_scroll.xul index e33161376328..1b597cdb3f00 100644 --- a/accessible/tests/mochitest/events/test_scroll.xul +++ b/accessible/tests/mochitest/events/test_scroll.xul @@ -64,7 +64,13 @@ this.invoke = function loadTabInBackground_invoke() { - tabBrowser().loadOneTab(aURL, null, "", null, true); + tabBrowser().loadOneTab(aURL, { + referrerURI: null, + charset: "", + postData: null, + inBackground: true, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); } this.getID = function loadTabInBackground_getID() diff --git a/accessible/tests/mochitest/relations/test_embeds.xul b/accessible/tests/mochitest/relations/test_embeds.xul index 0cb6d6c6517d..07f8cb56180e 100644 --- a/accessible/tests/mochitest/relations/test_embeds.xul +++ b/accessible/tests/mochitest/relations/test_embeds.xul @@ -56,7 +56,13 @@ { this.invoke = function loadOneTab_invoke() { - tabBrowser().loadOneTab(aURI, null, null, null, false); + tabBrowser().loadOneTab(aURI, { + referrerURI: null, + charset: null, + postData: null, + inBackground: false, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); } this.eventSeq = [ diff --git a/accessible/tests/mochitest/states/test_visibility.html b/accessible/tests/mochitest/states/test_visibility.html index 83e9d7c6ef7b..a3e5ffafbabf 100644 --- a/accessible/tests/mochitest/states/test_visibility.html +++ b/accessible/tests/mochitest/states/test_visibility.html @@ -53,7 +53,13 @@ this.invoke = function addTabInvoker_invoke() { - tabBrowser().loadOneTab(aURL, null, "", null, false); + tabBrowser().loadOneTab(aURL, { + referrerURI: null, + charset: "", + postData: null, + inBackground: false, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); } this.finalCheck = function addTabInvoker_finalCheck() diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index 51bc989d58f4..79ec281ab1e9 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* eslint-env mozilla/browser-window */ -/* global OpenGraphBuilder:false, DynamicResizeWatcher:false */ +/* global OpenGraphBuilder:false, DynamicResizeWatcher:false, Utils:false*/ // the "exported" symbols var SocialUI, @@ -25,6 +25,12 @@ XPCOMUtils.defineLazyGetter(this, "DynamicResizeWatcher", function() { return tmp.DynamicResizeWatcher; }); +XPCOMUtils.defineLazyGetter(this, "Utils", function() { + let tmp = {}; + Cu.import("resource://gre/modules/sessionstore/Utils.jsm", tmp); + return tmp.Utils; +}); + let messageManager = window.messageManager; let openUILinkIn = window.openUILinkIn; @@ -203,7 +209,11 @@ SocialActivationListener = { if (provider.postActivationURL) { // if activated from an open share panel, we load the landing page in // a background tab - gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"}); + let triggeringPrincipal = Utils.deserializePrincipal(aMessage.data.triggeringPrincipal); + gBrowser.loadOneTab(provider.postActivationURL, { + inBackground: SocialShare.panel.state == "open", + triggeringPrincipal, + }); } }); }, options); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index de1f21c97065..9efb75df6a7a 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -2291,11 +2291,14 @@ function delayedOpenWindow(chrome, flags, href, postData) { the URI kicked off before becoming the active content area. */ function delayedOpenTab(aUrl, aReferrer, aCharset, aPostData, aAllowThirdPartyFixup) { gBrowser.loadOneTab(aUrl, { - referrerURI: aReferrer, - charset: aCharset, - postData: aPostData, - inBackground: false, - allowThirdPartyFixup: aAllowThirdPartyFixup}); + referrerURI: aReferrer, + charset: aCharset, + postData: aPostData, + inBackground: false, + allowThirdPartyFixup: aAllowThirdPartyFixup, + // Bug 1367168: only use systemPrincipal till we can remove that function + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); } var gLastOpenDirectory = { @@ -2603,7 +2606,8 @@ function BrowserViewSourceOfDocument(aArgsOrDocument) { relatedToCurrent: true, inBackground: false, preferredRemoteType, - sameProcessAsFrameLoader: args.browser ? args.browser.frameLoader : null + sameProcessAsFrameLoader: args.browser ? args.browser.frameLoader : null, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); args.viewSourceBrowser = tabBrowser.getBrowserForTab(tab); top.gViewSourceUtils.viewSourceInBrowser(args); @@ -3412,7 +3416,8 @@ var PrintPreviewListener = { return gBrowser.loadOneTab("about:printpreview", { inBackground: true, preferredRemoteType, - sameProcessAsFrameLoader: browser.frameLoader + sameProcessAsFrameLoader: browser.frameLoader, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); }, getPrintPreviewBrowser() { @@ -3437,7 +3442,8 @@ var PrintPreviewListener = { let browser = this.getSourceBrowser(); this._simplifyPageTab = gBrowser.loadOneTab("about:printpreview", { inBackground: true, - sameProcessAsFrameLoader: browser.frameLoader + sameProcessAsFrameLoader: browser.frameLoader, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); return this.getSimplifiedSourceBrowser(); }, diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 7b494e53c4e6..d52c0cb8d243 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -41,6 +41,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata", "resource://gre/modules/PageMetadata.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils", "resource:///modules/PlacesUIUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Utils", + "resource://gre/modules/sessionstore/Utils.jsm"); XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() { let tmp = {}; Cu.import("resource://gre/modules/PageMenu.jsm", tmp); @@ -808,7 +810,8 @@ addEventListener("ActivateSocialFeature", function(aEvent) { sendAsyncMessage("Social:Activation", { url: ownerDocument.location.href, origin: ownerDocument.nodePrincipal.origin, - manifest: data + manifest: data, + triggeringPrincipal: Utils.serializePrincipal(ownerDocument.nodePrincipal), }); }, true, true); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 8fe21b6a6d1f..53bc215617d1 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1179,7 +1179,8 @@ nsContextMenu.prototype = { } let tab = tabBrowser.loadOneTab("about:blank", { relatedToCurrent: true, - inBackground: false + inBackground: false, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); return tabBrowser.getBrowserForTab(tab); } diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index a4623b53180f..92861d38eb57 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils", "resource:///modules/E10SUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Utils", + "resource://gre/modules/sessionstore/Utils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "AboutReader", @@ -657,7 +659,7 @@ let PrerenderContentHandler = { } }, - startPrerenderingDocument(aHref, aReferrer) { + startPrerenderingDocument(aHref, aReferrer, aTriggeringPrincipal) { // XXX: Make this constant a pref if (this._pending.length >= 2) { return; @@ -668,6 +670,7 @@ let PrerenderContentHandler = { href: aHref.spec, referrer: aReferrer ? aReferrer.spec : null, id, + triggeringPrincipal: Utils.serializePrincipal(aTriggeringPrincipal), }); this._pending.push({ @@ -729,9 +732,9 @@ var WebBrowserChrome = { return true; }, - startPrerenderingDocument(aHref, aReferrer) { + startPrerenderingDocument(aHref, aReferrer, aTriggeringPrincipal) { if (PrerenderContentHandler.initialized) { - PrerenderContentHandler.startPrerenderingDocument(aHref, aReferrer); + PrerenderContentHandler.startPrerenderingDocument(aHref, aReferrer, aTriggeringPrincipal); } }, diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index ffada3bbb236..0f785f062cb2 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -5222,6 +5222,7 @@ allowThirdPartyFixup: true, relatedToCurrent: true, isPrerendered: true, + triggeringPrincipal: Utils.deserializePrincipal(data.triggeringPrincipal), }); let partialSHistory = newTab.linkedBrowser.frameLoader.partialSHistory; groupedSHistory.addPrerenderingPartialSHistory(partialSHistory, data.id); diff --git a/browser/base/content/test/performance/browser.ini b/browser/base/content/test/performance/browser.ini index acb6c701e2d4..ae9cce17f73b 100644 --- a/browser/base/content/test/performance/browser.ini +++ b/browser/base/content/test/performance/browser.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = head.js +[browser_startup.js] [browser_tabclose_reflows.js] [browser_tabopen_reflows.js] [browser_toolbariconcolor_restyles.js] diff --git a/browser/base/content/test/performance/browser_startup.js b/browser/base/content/test/performance/browser_startup.js new file mode 100644 index 000000000000..bf14c1720de9 --- /dev/null +++ b/browser/base/content/test/performance/browser_startup.js @@ -0,0 +1,135 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* This test records at which phase of startup the JS components and modules + * are first loaded. + * If you made changes that cause this test to fail, it's likely because you + * are loading more JS code during startup. + * Most code has no reason to run off of the app-startup notification + * (this is very early, before we have selected the user profile, so + * preferences aren't accessible yet). + * If your code isn't strictly required to show the first browser window, + * it shouldn't be loaded before we are done with first paint. + * Finally, if your code isn't really needed during startup, it should not be + * loaded before we have started handling user events. + */ + +"use strict"; + +const startupPhases = { + // For app-startup, we have a whitelist of acceptable JS files. + // Anything loaded during app-startup must have a compelling reason + // to run before we have even selected the user profile. + // Consider loading your code after first paint instead, + // eg. from nsBrowserGlue.js' _onFirstWindowLoaded method). + "before profile selection": {whitelist: { + components: new Set([ + "nsBrowserGlue.js", + "MainProcessSingleton.js", + + // Bugs to fix: The following components shouldn't be initialized that early. + "WebContentConverter.js", + "nsSessionStartup.js", + "PushComponents.js", + ]), + modules: new Set([ + "resource://gre/modules/AppConstants.jsm", + "resource://gre/modules/XPCOMUtils.jsm", + "resource://gre/modules/Services.jsm", + + // Bugs to fix: Probably loaded too early, needs investigation. + "resource://gre/modules/Log.jsm", + "resource://gre/modules/AsyncPrefs.jsm", + "resource://gre/modules/RemotePageManager.jsm", + "resource://gre/modules/TelemetryStopwatch.jsm", + "resource://gre/modules/PrivateBrowsingUtils.jsm", + "resource://gre/modules/Promise.jsm" + ]) + }}, + + // For the following phases of startup we have only a black list for now + + // We are at this phase after creating the first browser window (ie. after final-ui-startup). + "before opening first browser window": {blacklist: { + components: new Set([ + "nsSearchService.js", + ]) + }}, + + // We reach this phase right after showing the first browser window. + // This means that anything already loaded at this point has been loaded + // before first paint and delayed it. + "before first paint": {}, + + // We are at this phase once we are ready to handle user events. + // Anything loaded at this phase or before gets in the way of the user + // interacting with the first browser window. + "before handling user events": {}, +} + +function test() { + if (!AppConstants.NIGHTLY_BUILD && !AppConstants.DEBUG) { + ok(!("@mozilla.org/test/startuprecorder;1" in Cc), + "the startup recorder component shouldn't exist in this non-nightly non-debug build."); + return; + } + + let data = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject.data; + // Keep only the file name for components, as the path is an absolute file + // URL rather than a resource:// URL like for modules. + for (let phase in data) { + data[phase].components = + data[phase].components.map(f => f.replace(/.*\//, "")) + .filter(c => c != "startupRecorder.js"); + } + + // This block only adds debug output to help find the next bugs to file, + // it doesn't contribute to the actual test. + SimpleTest.requestCompleteLog(); + let previous; + for (let phase in data) { + for (let scriptType in data[phase]) { + for (let f of data[phase][scriptType]) { + // phases are ordered, so if a script wasn't loaded yet at the immediate + // previous phase, it wasn't loaded during any of the previous phases + // either, and is new in the current phase. + if (!previous || !data[previous][scriptType].includes(f)) + info(`${scriptType} loaded ${phase}: ${f}`); + } + } + previous = phase; + } + + for (let phase in startupPhases) { + let loadedList = data[phase]; + let whitelist = startupPhases[phase].whitelist || null; + if (whitelist) { + for (let scriptType in loadedList) { + loadedList[scriptType] = loadedList[scriptType].filter(c => { + if (!whitelist[scriptType].has(c)) + return true; + whitelist[scriptType].delete(c); + return false; + }); + is(loadedList[scriptType].length, 0, + `should have no unexpected ${scriptType} loaded ${phase}`); + for (let script of loadedList[scriptType]) { + ok(false, `unexpected ${scriptType}: ${script}`); + } + is(whitelist[scriptType].size, 0, + `all ${scriptType} whitelist entries should have been used`); + for (let script of whitelist[scriptType]) { + ok(false, `unused ${scriptType} whitelist entry: ${script}`); + } + } + } + let blacklist = startupPhases[phase].blacklist || null; + if (blacklist) { + for (let scriptType in blacklist) { + for (let file of blacklist[scriptType]) { + ok(!loadedList[scriptType].includes(file), `${file} is not allowed ${phase}`); + } + } + } + } +} diff --git a/browser/base/content/usercontext-briefcase.svg b/browser/base/content/usercontext-briefcase.svg new file mode 100644 index 000000000000..d38a745f9e7a --- /dev/null +++ b/browser/base/content/usercontext-briefcase.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/browser/base/content/usercontext-cart.svg b/browser/base/content/usercontext-cart.svg new file mode 100644 index 000000000000..aedff937e890 --- /dev/null +++ b/browser/base/content/usercontext-cart.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/browser/base/content/usercontext-circle.svg b/browser/base/content/usercontext-circle.svg new file mode 100644 index 000000000000..24bd6dc6014b --- /dev/null +++ b/browser/base/content/usercontext-circle.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/browser/base/content/usercontext-dollar.svg b/browser/base/content/usercontext-dollar.svg new file mode 100644 index 000000000000..c96faa8d51ae --- /dev/null +++ b/browser/base/content/usercontext-dollar.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/browser/base/content/usercontext-fingerprint.svg b/browser/base/content/usercontext-fingerprint.svg new file mode 100644 index 000000000000..58dd78cd097a --- /dev/null +++ b/browser/base/content/usercontext-fingerprint.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/browser/base/content/usercontext.svg b/browser/base/content/usercontext.svg deleted file mode 100644 index 705f80bfdd15..000000000000 --- a/browser/base/content/usercontext.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - diff --git a/browser/base/jar.mn b/browser/base/jar.mn index c7e6ae67a687..c6b43595f249 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -138,7 +138,11 @@ browser.jar: content/browser/tabbrowser.xml (content/tabbrowser.xml) * content/browser/urlbarBindings.xml (content/urlbarBindings.xml) content/browser/utilityOverlay.js (content/utilityOverlay.js) - content/browser/usercontext.svg (content/usercontext.svg) + content/browser/usercontext-briefcase.svg (content/usercontext-briefcase.svg) + content/browser/usercontext-cart.svg (content/usercontext-cart.svg) + content/browser/usercontext-circle.svg (content/usercontext-circle.svg) + content/browser/usercontext-dollar.svg (content/usercontext-dollar.svg) + content/browser/usercontext-fingerprint.svg (content/usercontext-fingerprint.svg) content/browser/web-panels.js (content/web-panels.js) * content/browser/web-panels.xul (content/web-panels.xul) content/browser/webext-panels.js (content/webext-panels.js) diff --git a/browser/components/contextualidentity/content/usercontext.css b/browser/components/contextualidentity/content/usercontext.css index 4ef99ad5c6ff..e1e55fd2c0ec 100644 --- a/browser/components/contextualidentity/content/usercontext.css +++ b/browser/components/contextualidentity/content/usercontext.css @@ -39,23 +39,23 @@ } [data-identity-icon="fingerprint"] { - --identity-icon: url("chrome://browser/content/usercontext.svg#fingerprint"); + --identity-icon: url("chrome://browser/content/usercontext-fingerprint.svg"); } [data-identity-icon="briefcase"] { - --identity-icon: url("chrome://browser/content/usercontext.svg#briefcase"); + --identity-icon: url("chrome://browser/content/usercontext-briefcase.svg"); } [data-identity-icon="dollar"] { - --identity-icon: url("chrome://browser/content/usercontext.svg#dollar"); + --identity-icon: url("chrome://browser/content/usercontext-dollar.svg"); } [data-identity-icon="cart"] { - --identity-icon: url("chrome://browser/content/usercontext.svg#cart"); + --identity-icon: url("chrome://browser/content/usercontext-cart.svg"); } [data-identity-icon="circle"] { - --identity-icon: url("chrome://browser/content/usercontext.svg#circle"); + --identity-icon: url("chrome://browser/content/usercontext-circle.svg"); } #userContext-indicator { @@ -83,7 +83,7 @@ .subviewbutton[usercontextid] > .toolbarbutton-icon, #userContext-indicator { background-image: var(--identity-icon); - filter: url(chrome://global/skin/filters.svg#fill); + -moz-context-properties: fill; fill: var(--identity-icon-color); background-size: contain; background-repeat: no-repeat; diff --git a/browser/components/customizableui/CustomizeMode.jsm b/browser/components/customizableui/CustomizeMode.jsm index e22e2f16e2f4..0d85ab2bf412 100644 --- a/browser/components/customizableui/CustomizeMode.jsm +++ b/browser/components/customizableui/CustomizeMode.jsm @@ -218,10 +218,12 @@ CustomizeMode.prototype = { } if (!gTab) { - this.setTab(this.browser.loadOneTab("about:blank", - { inBackground: false, - forceNotRemote: true, - skipAnimation: true })); + this.setTab(this.browser.loadOneTab("about:blank", { + inBackground: false, + forceNotRemote: true, + skipAnimation: true, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + })); return; } if (!gTab.selected) { diff --git a/browser/components/moz.build b/browser/components/moz.build index 9f816dd38b08..81757f5468f9 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -66,6 +66,8 @@ EXTRA_PP_COMPONENTS += [ EXTRA_COMPONENTS += [ 'nsBrowserContentHandler.js', 'nsBrowserGlue.js', + 'tests/startupRecorder.js', + 'tests/testComponents.manifest', ] EXTRA_JS_MODULES += [ diff --git a/browser/components/tests/startupRecorder.js b/browser/components/tests/startupRecorder.js new file mode 100644 index 000000000000..ef07417451c1 --- /dev/null +++ b/browser/components/tests/startupRecorder.js @@ -0,0 +1,71 @@ +/* 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/. */ + +const {classes: Cc, utils: Cu, interfaces: Ci} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +/** + * The startupRecorder component observes notifications at various stages of + * startup and records the set of JS components and modules that were already + * loaded at each of these points. + * The records are meant to be used by startup tests in + * browser/base/content/test/performance + * This component only exists in nightly and debug builds, it doesn't ship in + * our release builds. + */ +function startupRecorder() { + this.wrappedJSObject = this; + this.loader = Cc["@mozilla.org/moz/jsloader;1"].getService(Ci.xpcIJSModuleLoader); + this.data = {}; +} +startupRecorder.prototype = { + classID: Components.ID("{11c095b2-e42e-4bdf-9dd0-aed87595f6a4}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + + record(name) { + this.data[name] = { + components: this.loader.loadedComponents(), + modules: this.loader.loadedModules() + }; + }, + + observe(subject, topic, data) { + + if (topic == "app-startup") { + // We can't ensure our observer will be called first or last, so the list of + // topics we observe here should avoid the topics used to trigger things + // during startup (eg. the topics observed by nsBrowserGlue.js). + let topics = [ + "profile-do-change", // This catches stuff loaded during app-startup + "toplevel-window-ready", // Catches stuff from final-ui-startup + "widget-first-paint", + "sessionstore-windows-restored", + ]; + for (let t of topics) + Services.obs.addObserver(this, t); + return; + } + + Services.obs.removeObserver(this, topic); + + if (topic == "sessionstore-windows-restored") { + // We use idleDispatch here to record the set of loaded scripts after we + // are fully done with startup and ready to react to user events. + Services.tm.mainThread.idleDispatch( + this.record.bind(this, "before handling user events")); + } else { + const topicsToNames = { + "profile-do-change": "before profile selection", + "toplevel-window-ready": "before opening first browser window", + "widget-first-paint": "before first paint", + }; + this.record(topicsToNames[topic]); + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([startupRecorder]); diff --git a/browser/components/tests/testComponents.manifest b/browser/components/tests/testComponents.manifest new file mode 100644 index 000000000000..efd8bc959686 --- /dev/null +++ b/browser/components/tests/testComponents.manifest @@ -0,0 +1,5 @@ +# This component restricts its registration for the app-startup category +# to the browser app so it doesn't get loaded in xpcshell. +component {11c095b2-e42e-4bdf-9dd0-aed87595f6a4} startupRecorder.js +contract @mozilla.org/test/startuprecorder;1 {11c095b2-e42e-4bdf-9dd0-aed87595f6a4} +category app-startup startupRecorder service,@mozilla.org/test/startuprecorder;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} diff --git a/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm b/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm index 02f45e136354..054d28d72a18 100644 --- a/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm +++ b/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm @@ -121,7 +121,7 @@ let WebCompatReporter = { let tab = gBrowser.loadOneTab( `${WebCompatReporter.endpoint}?url=${encodeURIComponent(tabData.url)}&src=desktop-reporter`, - {inBackground: false}); + {inBackground: false, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()}); // If we successfully got a screenshot blob, add a listener to know when // the new tab is loaded before sending it over. diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 48f0abddf9ed..528226de41c1 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -568,6 +568,11 @@ @RESPATH@/components/TestInterfaceJSMaplike.js #endif +#if defined(MOZ_DEBUG) || defined(NIGHTLY_BUILD) +@RESPATH@/browser/components/testComponents.manifest +@RESPATH@/browser/components/startupRecorder.js +#endif + ; [Extensions] @RESPATH@/components/extensions-toolkit.manifest @RESPATH@/browser/components/extensions-browser.manifest diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 20a9bf6cb780..9327f37dab40 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -11018,6 +11018,28 @@ nsDocShell::DoURILoad(nsIURI* aURI, new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode, securityFlags, aContentPolicyType); + if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) { + enum TopLevelDataState { + DATA_NAVIGATED = 0, + DATA_TYPED = 1, + NO_DATA = 2, + }; + bool isDataURI = (NS_SUCCEEDED(aURI->SchemeIs("data", &isDataURI)) && isDataURI); + if (isDataURI) { + // In all cases where the toplevel document is navigated to a data: URI + // the triggeringPrincipal is a CodeBasePrincipal. In all other cases + // e.g. typing a data: URL into the URL-Bar or also clicking a bookmark + // uses a SystemPrincipal as the triggeringPrincipal. + if (aTriggeringPrincipal->GetIsCodebasePrincipal()) { + Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, DATA_NAVIGATED); + } else { + Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, DATA_TYPED); + } + } else { + Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, NO_DATA); + } + } + if (aPrincipalToInherit) { loadInfo->SetPrincipalToInherit(aPrincipalToInherit); } diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 9002ac268d88..55ec73df344d 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -4009,6 +4009,11 @@ Element::RegisteredIntersectionObservers() return &slots->mRegisteredIntersectionObservers; } +enum nsPreviousIntersectionThreshold { + eUninitialized = -2, + eNonIntersecting = -1 +}; + void Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) { @@ -4017,7 +4022,13 @@ Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) if (observers->Contains(aObserver)) { return; } - RegisteredIntersectionObservers()->Put(aObserver, -1); + + // Value can be: + // -2: Makes sure next calculated threshold always differs, leading to a + // notification task being scheduled. + // -1: Non-intersecting. + // >= 0: Intersecting, valid index of aObserver->mThresholds. + RegisteredIntersectionObservers()->Put(aObserver, eUninitialized); } void diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index ae5c5e92eab7..b35cc61a9090 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -73,9 +73,6 @@ extern mozilla::LazyLogModule gContentSinkLogModuleInfo; //---------------------------------------------------------------------- -// 1/2 second fudge factor for window creation -#define NS_DELAY_FOR_WINDOW_CREATION 500000 - class nsContentSink : public nsICSSLoaderObserver, public nsSupportsWeakReference, public nsStubDocumentObserver, diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 3cf56a224a50..5117805aa518 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -3145,7 +3145,7 @@ nsIDocument::PrerenderHref(nsIURI* aHref) tabChild->GetWebBrowserChrome(getter_AddRefs(wbc3)); NS_ENSURE_TRUE(wbc3, false); - rv = wbc3->StartPrerenderingDocument(aHref, referrer); + rv = wbc3->StartPrerenderingDocument(aHref, referrer, NodePrincipal()); NS_ENSURE_SUCCESS(rv, false); return true; @@ -12338,7 +12338,8 @@ nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const &aWindowSizes->mLayoutPresShellSize, &aWindowSizes->mLayoutStyleSetsSize, &aWindowSizes->mLayoutTextRunsSize, - &aWindowSizes->mLayoutPresContextSize); + &aWindowSizes->mLayoutPresContextSize, + &aWindowSizes->mLayoutFramePropertiesSize); } aWindowSizes->mPropertyTablesSize += diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 333f55b3cc74..fe1fbcbab757 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -178,7 +178,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool , mClipSubdocument(true) , mClampScrollPosition(true) , mObservingOwnerContent(false) - , mVisible(true) { mRemoteFrame = ShouldUseRemoteProcess(); MOZ_ASSERT(!mRemoteFrame || !aOpener, @@ -3495,29 +3494,6 @@ nsFrameLoader::Print(uint64_t aOuterWindowID, return NS_OK; } -/* [infallible] */ NS_IMETHODIMP -nsFrameLoader::SetVisible(bool aVisible) -{ - if (mVisible == aVisible) { - return NS_OK; - } - - mVisible = aVisible; - nsCOMPtr os = services::GetObserverService(); - if (os) { - os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), - "frameloader-visible-changed", nullptr); - } - return NS_OK; -} - -/* [infallible] */ NS_IMETHODIMP -nsFrameLoader::GetVisible(bool* aVisible) -{ - *aVisible = mVisible; - return NS_OK; -} - NS_IMETHODIMP nsFrameLoader::GetTabParent(nsITabParent** aTabParent) { diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h index 26177e7a9f3f..fc3dcd0df582 100644 --- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -375,10 +375,6 @@ private: bool mClampScrollPosition : 1; bool mObservingOwnerContent : 1; - // Backs nsIFrameLoader::{Get,Set}Visible. Visibility state here relates to - // whether this frameloader's is setVisible(true)'ed, and - // doesn't necessarily correlate with docshell/document visibility. - bool mVisible : 1; bool mFreshProcess : 1; }; diff --git a/dom/base/nsIFrameLoader.idl b/dom/base/nsIFrameLoader.idl index 1df2b1f297f4..ae6bf3a3fb79 100644 --- a/dom/base/nsIFrameLoader.idl +++ b/dom/base/nsIFrameLoader.idl @@ -222,15 +222,6 @@ interface nsIFrameLoader : nsISupports */ readonly attribute unsigned long long childID; - /** - * Get or set this frame loader's visibility. - * - * The notion of "visibility" here is separate from the notion of a - * window/docshell's visibility. This field is mostly here so that we can - * have a notion of visibility in the parent process when frames are OOP. - */ - [infallible] attribute boolean visible; - /** * Find out whether the owner content really is a mozbrowser. * is not considered to be a mozbrowser frame. diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index 5e808b0fe00f..108c094b0387 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -400,6 +400,12 @@ CollectWindowReports(nsGlobalWindow *aWindow, aWindowTotalSizes->mLayoutPresContextSize += windowSizes.mLayoutPresContextSize; + REPORT_SIZE("/layout/frame-properties", windowSizes.mLayoutFramePropertiesSize, + "Memory used for frame properties attached to frames " + "within a window."); + aWindowTotalSizes->mLayoutFramePropertiesSize += + windowSizes.mLayoutFramePropertiesSize; + // There are many different kinds of frames, but it is very likely // that only a few matter. Implement a cutoff so we don't bloat // about:memory with many uninteresting entries. @@ -565,6 +571,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport, REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize, "This is the sum of all windows' 'layout/pres-contexts' numbers."); + REPORT("window-objects/layout/frame-properties", windowTotalSizes.mLayoutFramePropertiesSize, + "This is the sum of all windows' 'layout/frame-properties' numbers."); + size_t frameTotal = 0; #define FRAME_ID(classname, ...) \ frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname); diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h index b9e9869590e6..5d40dc9f562c 100644 --- a/dom/base/nsWindowMemoryReporter.h +++ b/dom/base/nsWindowMemoryReporter.h @@ -33,6 +33,7 @@ class nsWindowSizes { macro(Style, mLayoutStyleSetsSize) \ macro(Other, mLayoutTextRunsSize) \ macro(Other, mLayoutPresContextSize) \ + macro(Other, mLayoutFramePropertiesSize) \ macro(Other, mPropertyTablesSize) \ public: diff --git a/dom/base/test/mozbrowser_api_utils.js b/dom/base/test/mozbrowser_api_utils.js index ebb16fc27eb2..21473967f646 100644 --- a/dom/base/test/mozbrowser_api_utils.js +++ b/dom/base/test/mozbrowser_api_utils.js @@ -1,10 +1,6 @@ const FRAME_URL = "http://example.org/"; const METHODS = { - setVisible: {}, - getVisible: {}, - setActive: {}, - getActive: {}, addNextPaintListener: {}, removeNextPaintListener: {}, sendMouseEvent: {}, diff --git a/dom/base/test/test_intersectionobservers.html b/dom/base/test/test_intersectionobservers.html index e2db8ad2884c..495348d97926 100644 --- a/dom/base/test/test_intersectionobservers.html +++ b/dom/base/test/test_intersectionobservers.html @@ -322,7 +322,7 @@ limitations under the License. }); - it('does not trigger if target does not intersect when observing begins', + it('does trigger if target does not intersect when observing begins', function(done) { var spy = sinon.spy(); @@ -331,7 +331,7 @@ limitations under the License. targetEl2.style.top = '-40px'; io.observe(targetEl2); callDelayed(function() { - expect(spy.callCount).to.be(0); + expect(spy.callCount).to.be(1); done(); }, ASYNC_TIMEOUT); }); @@ -525,7 +525,7 @@ limitations under the License. spy.waitForNotification(function() { expect(spy.callCount).to.be(1); var records = sortRecords(spy.lastCall.args[0]); - expect(records.length).to.be(2); + expect(records.length).to.be(3); expect(records[0].target).to.be(targetEl1); expect(records[0].intersectionRatio).to.be(0.25); expect(records[1].target).to.be(targetEl2); @@ -630,13 +630,13 @@ limitations under the License. function(done) { io = new IntersectionObserver(function(records) { records = sortRecords(records); - expect(records.length).to.be(3); + expect(records.length).to.be(4); expect(records[0].target).to.be(targetEl1); expect(records[0].intersectionRatio).to.be(0.5); - expect(records[1].target).to.be(targetEl3); - expect(records[1].intersectionRatio).to.be(0.5); - expect(records[2].target).to.be(targetEl4); + expect(records[2].target).to.be(targetEl3); expect(records[2].intersectionRatio).to.be(0.5); + expect(records[3].target).to.be(targetEl4); + expect(records[3].intersectionRatio).to.be(0.5); io.disconnect(); done(); }, {root: rootEl, rootMargin: '-10px 10%'}); @@ -649,11 +649,11 @@ limitations under the License. function(done) { io = new IntersectionObserver(function(records) { records = sortRecords(records); - expect(records.length).to.be(2); + expect(records.length).to.be(4); expect(records[0].target).to.be(targetEl1); expect(records[0].intersectionRatio).to.be(0.5); - expect(records[1].target).to.be(targetEl4); - expect(records[1].intersectionRatio).to.be(0.5); + expect(records[3].target).to.be(targetEl4); + expect(records[3].intersectionRatio).to.be(0.5); io.disconnect(); done(); }, {root: rootEl, rootMargin: '-5% -2.5% 0px'}); @@ -666,13 +666,13 @@ limitations under the License. function(done) { io = new IntersectionObserver(function(records) { records = sortRecords(records); - expect(records.length).to.be(3); + expect(records.length).to.be(4); expect(records[0].target).to.be(targetEl1); expect(records[0].intersectionRatio).to.be(0.5); expect(records[1].target).to.be(targetEl2); expect(records[1].intersectionRatio).to.be(0.5); - expect(records[2].target).to.be(targetEl4); - expect(records[2].intersectionRatio).to.be(0.25); + expect(records[3].target).to.be(targetEl4); + expect(records[3].intersectionRatio).to.be(0.25); io.disconnect(); done(); }, {root: rootEl, rootMargin: '5% -2.5% -10px -190px'}); @@ -702,9 +702,9 @@ limitations under the License. spy.waitForNotification(function() { expect(spy.callCount).to.be(1); var records = sortRecords(spy.lastCall.args[0]); - expect(records.length).to.be(1); - expect(records[0].intersectionRatio).to.be(0); - expect(records[0].target).to.be(targetEl2); + expect(records.length).to.be(2); + expect(records[1].intersectionRatio).to.be(0); + expect(records[1].target).to.be(targetEl2); done(); }); }, @@ -814,14 +814,14 @@ limitations under the License. function(done) { document.getElementById('fixtures').appendChild(rootEl); callDelayed(function() { - expect(spy.callCount).to.be(0); + expect(spy.callCount).to.be(1); done(); }, ASYNC_TIMEOUT); }, function(done) { parentEl.insertBefore(targetEl1, targetEl2); spy.waitForNotification(function() { - expect(spy.callCount).to.be(1); + expect(spy.callCount).to.be(2); var records = sortRecords(spy.lastCall.args[0]); expect(records.length).to.be(1); expect(records[0].intersectionRatio).to.be(1); @@ -832,7 +832,7 @@ limitations under the License. function(done) { grandParentEl.remove(); spy.waitForNotification(function() { - expect(spy.callCount).to.be(2); + expect(spy.callCount).to.be(3); var records = sortRecords(spy.lastCall.args[0]); expect(records.length).to.be(1); expect(records[0].intersectionRatio).to.be(0); @@ -843,7 +843,7 @@ limitations under the License. function(done) { rootEl.appendChild(targetEl1); spy.waitForNotification(function() { - expect(spy.callCount).to.be(3); + expect(spy.callCount).to.be(4); var records = sortRecords(spy.lastCall.args[0]); expect(records.length).to.be(1); expect(records[0].intersectionRatio).to.be(1); @@ -854,7 +854,7 @@ limitations under the License. function(done) { rootEl.remove(); spy.waitForNotification(function() { - expect(spy.callCount).to.be(4); + expect(spy.callCount).to.be(5); var records = sortRecords(spy.lastCall.args[0]); expect(records.length).to.be(1); expect(records[0].intersectionRatio).to.be(0); @@ -885,7 +885,13 @@ limitations under the License. targetEl1.style.top = '220px'; targetEl1.style.left = '220px'; + var callCount = 0; + io = new IntersectionObserver(function(records) { + callCount++; + if (callCount <= 1) { + return; + } expect(records.length).to.be(1); expect(records[0].intersectionRatio).to.be(1); done(); diff --git a/dom/base/test/test_websocket_basic.html b/dom/base/test/test_websocket_basic.html index e3269382e682..fa5e6b4f2198 100644 --- a/dom/base/test/test_websocket_basic.html +++ b/dom/base/test/test_websocket_basic.html @@ -238,7 +238,7 @@ function testWebSocket5() { gTestElement.textContent += "\ntestWebSocket5() completed"; - SimpleTest.executeSoon(SimpleTest.finish); + SimpleTest.executeSoon(testWebSocket6); }; ws.onerror = function(e) { ok(false, "[5] onerror() should not have been called!"); @@ -247,6 +247,40 @@ function testWebSocket5() { }; } +function testWebSocket6() { + gTestElement.textContent = "Running testWebSocket6()"; + + var msgReceived = false; + ws = new WebSocket(kUrl, "test"); + ws.onopen = function(e) { + gTestElement.textContent += "\nSending ©"; + ws.send("©"); + gTestElement.textContent += " end"; + ws.send("end"); + }; + ws.onclose = function(e) { + ok(msgReceived, "[6] Number of received messages"); + ok(e.wasClean, "[6] Connection closed cleanly"); + + SimpleTest.executeSoon(SimpleTest.finish); + }; + ws.onerror = function(e) { + ok(false, "[6] onerror() should not have been called!"); + gTestElement.textContent += "\nonerror() should not have been called!"; + SimpleTest.executeSoon(SimpleTest.finish); + }; + + ws.onmessage = function(e) { + if (msgReceived) { + is(e.data, "end", "[6] Received message"); + } else { + gTestElement.textContent += "\nReceived: " + e.data; + is(e.data, "©", "[6] Received message"); + msgReceived = true; + } + }; +} + SimpleTest.waitForExplicitFinish(); diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 285851d56b17..4a39599f0656 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -116,15 +116,6 @@ function BrowserElementChild() { // Maps outer window id --> weak ref to window. Used by modal dialog code. this._windowIDDict = {}; - // _forcedVisible corresponds to the visibility state our owner has set on us - // (via iframe.setVisible). ownerVisible corresponds to whether the docShell - // whose window owns this element is visible. - // - // Our docShell is visible iff _forcedVisible and _ownerVisible are both - // true. - this._forcedVisible = true; - this._ownerVisible = true; - this._nextPaintHandler = null; this._isContentWindowCreated = false; @@ -286,8 +277,6 @@ BrowserElementChild.prototype = { "purge-history": this._recvPurgeHistory, "get-screenshot": this._recvGetScreenshot, "get-contentdimensions": this._recvGetContentDimensions, - "set-visible": this._recvSetVisible, - "get-visible": this._recvVisible, "send-mouse-event": this._recvSendMouseEvent, "send-touch-event": this._recvSendTouchEvent, "get-can-go-back": this._recvCanGoBack, @@ -1231,35 +1220,13 @@ BrowserElementChild.prototype = { return menuObj; }, - _recvSetVisible: function(data) { - debug("Received setVisible message: (" + data.json.visible + ")"); - if (this._forcedVisible == data.json.visible) { - return; - } - - this._forcedVisible = data.json.visible; - this._updateVisibility(); - }, - - _recvVisible: function(data) { - sendAsyncMsg('got-visible', { - id: data.json.id, - successRv: docShell.isActive - }); - }, - /** * Called when the window which contains this iframe becomes hidden or * visible. */ _recvOwnerVisibilityChange: function(data) { debug("Received ownerVisibilityChange: (" + data.json.visible + ")"); - this._ownerVisible = data.json.visible; - this._updateVisibility(); - }, - - _updateVisibility: function() { - var visible = this._forcedVisible && this._ownerVisible; + var visible = data.json.visible; if (docShell && docShell.isActive !== visible) { docShell.isActive = visible; sendAsyncMsg('visibilitychange', {visible: visible}); diff --git a/dom/browser-element/BrowserElementParent.js b/dom/browser-element/BrowserElementParent.js index 98347b27af28..9cb86c04e3b2 100644 --- a/dom/browser-element/BrowserElementParent.js +++ b/dom/browser-element/BrowserElementParent.js @@ -528,26 +528,6 @@ BrowserElementParent.prototype = { } }, - setVisible: defineNoReturnMethod(function(visible) { - this._sendAsyncMsg('set-visible', {visible: visible}); - this._frameLoader.visible = visible; - }), - - getVisible: defineDOMRequestMethod('get-visible'), - - setActive: defineNoReturnMethod(function(active) { - this._frameLoader.visible = active; - }), - - getActive: function() { - if (!this._isAlive()) { - throw Components.Exception("Dead content process", - Cr.NS_ERROR_DOM_INVALID_STATE_ERR); - } - - return this._frameLoader.visible; - }, - getChildProcessOffset: function() { let offset = { x: 0, y: 0 }; let tabParent = this._frameLoader.tabParent; @@ -884,11 +864,6 @@ BrowserElementParent.prototype = { /* * Called when the child notices that its visibility has changed. - * - * This is sometimes redundant; for example, the child's visibility may - * change in response to a setVisible request that we made here! But it's - * not always redundant; for example, the child's visibility may change in - * response to its parent docshell being hidden. */ _childVisibilityChange: function(data) { debug("_childVisibilityChange(" + data.json.visible + ")"); diff --git a/dom/browser-element/mochitest/browserElement_SetVisible.js b/dom/browser-element/mochitest/browserElement_SetVisible.js deleted file mode 100644 index 20dc9c1380ac..000000000000 --- a/dom/browser-element/mochitest/browserElement_SetVisible.js +++ /dev/null @@ -1,75 +0,0 @@ -/* Any copyright is dedicated to the public domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test the setVisible property for mozbrowser -"use strict"; - -SimpleTest.waitForExplicitFinish(); -SimpleTest.requestFlakyTimeout("untriaged"); -browserElementTestHelpers.setEnabledPref(true); - -var iframeScript = function() { - content.document.addEventListener("visibilitychange", function() { - sendAsyncMessage('test:visibilitychange', { - hidden: content.document.hidden - }); - }); -} - -function runTest() { - var mm; - var numEvents = 0; - var iframe1 = document.createElement('iframe'); - iframe1.setAttribute('mozbrowser', 'true'); - iframe1.src = 'data:text/html,1'; - - document.body.appendChild(iframe1); - - function recvVisibilityChanged(msg) { - msg = SpecialPowers.wrap(msg); - numEvents++; - if (numEvents === 1) { - ok(true, 'iframe recieved visibility changed'); - ok(msg.json.hidden === true, 'hidden attribute correctly set'); - iframe1.setVisible(false); - iframe1.setVisible(true); - } else if (numEvents === 2) { - ok(msg.json.hidden === false, 'hidden attribute correctly set'); - // Allow some time in case we generate too many events - setTimeout(function() { - mm.removeMessageListener('test:visibilitychange', recvVisibilityChanged); - SimpleTest.finish(); - }, 100); - } else { - ok(false, 'Too many visibilitychange events'); - } - } - - function iframeLoaded() { - testGetVisible(); - } - - function testGetVisible() { - iframe1.setVisible(false); - iframe1.getVisible().onsuccess = function(evt) { - ok(evt.target.result === false, 'getVisible() responds false after setVisible(false)'); - - iframe1.setVisible(true); - iframe1.getVisible().onsuccess = function(evt) { - ok(evt.target.result === true, 'getVisible() responds true after setVisible(true)'); - testVisibilityChanges(); - }; - }; - } - - function testVisibilityChanges() { - mm = SpecialPowers.getBrowserFrameMessageManager(iframe1); - mm.addMessageListener('test:visibilitychange', recvVisibilityChanged); - mm.loadFrameScript('data:,(' + iframeScript.toString() + ')();', false); - iframe1.setVisible(false); - } - - iframe1.addEventListener('mozbrowserloadend', iframeLoaded); -} - -addEventListener('testready', runTest); diff --git a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js deleted file mode 100644 index 721248ab9922..000000000000 --- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Any copyright is dedicated to the public domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Bug 762939 - Test that visibility propagates down properly through -// hierarchies of . -// -// In this test, we modify the parent's visibility and check that the child's -// visibility is changed as appopriate. We test modifying the child's -// visibility in a separate testcase. - -"use strict"; - -SimpleTest.waitForExplicitFinish(); -browserElementTestHelpers.setEnabledPref(true); - -var iframe; - -function runTest() { - iframe = document.createElement('iframe'); - iframe.setAttribute('mozbrowser', 'true'); - - // Our test involves three 's, parent, child1, and child2. - // child1 and child2 are contained inside parent. child1 is visibile, and - // child2 is not. - // - // For the purposes of this test, we want there to be a process barrier - // between child{1,2} and parent. Therefore parent must be a non-remote - // , until bug 761935 is resolved and we can have nested - // content processes. - iframe.remote = false; - - iframe.addEventListener('mozbrowsershowmodalprompt', checkMessage); - expectMessage('parent:ready', test1); - - document.body.appendChild(iframe); - iframe.src = 'file_browserElement_SetVisibleFrames_Outer.html'; -} - -function test1() { - expectMessage('child1:hidden', getVisibleTest1); - iframe.setVisible(false); -} - -function getVisibleTest1() { - iframe.getVisible().onsuccess = function(evt) { - ok(evt.target.result === false, 'getVisible shows a hidden frame'); - test2(); - }; -} - -function test2() { - expectMessage('child1:visible', getVisibleTest2); - iframe.setVisible(true); -} - -function getVisibleTest2() { - iframe.getVisible().onsuccess = function(evt) { - ok(evt.target.result === true, 'getVisible shows a displayed frame'); - finish(); - }; -} - -function finish() { - // We need to remove this listener because when this test finishes and the - // iframe containing this document is navigated, we'll fire a - // visibilitychange(false) event on all child iframes. That's OK and - // expected, but if we don't remove our listener, then we'll end up causing - // the /next/ test to fail! - iframe.removeEventListener('mozbrowsershowmodalprompt', checkMessage); - SimpleTest.finish(); -} - -var expectedMsg = null; -var expectedMsgCallback = null; -function expectMessage(msg, next) { - expectedMsg = msg; - expectedMsgCallback = next; -} - -function checkMessage(e) { - var msg = e.detail.message; - is(msg, expectedMsg); - if (msg == expectedMsg) { - expectedMsg = null; - SimpleTest.executeSoon(function() { expectedMsgCallback() }); - } -} - -addEventListener('testready', runTest); diff --git a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js deleted file mode 100644 index c9e1bc2bdfb2..000000000000 --- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js +++ /dev/null @@ -1,54 +0,0 @@ -/* Any copyright is dedicated to the public domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Bug 762939 - Test that setting a to invisible / visible -// inside an invisible doesn't trigger any events. - -"use strict"; - -SimpleTest.waitForExplicitFinish(); -browserElementTestHelpers.setEnabledPref(true); - -function runTest() { - var iframe = document.createElement('iframe'); - iframe.setAttribute('mozbrowser', 'true'); - - // We need remote = false here until bug 761935 is fixed; see - // SetVisibleFrames.js for an explanation. - iframe.remote = false; - - iframe.addEventListener('mozbrowserloadend', function(e) { - iframe.setVisible(false); - iframe.src = 'file_browserElement_SetVisibleFrames2_Outer.html'; - }, {once: true}); - - iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { - if (e.detail.message == 'parent:finish') { - ok(true, "Got parent:finish"); - - // Give any extra events a chance to fire, then end the test. - SimpleTest.executeSoon(function() { - SimpleTest.executeSoon(function() { - SimpleTest.executeSoon(function() { - SimpleTest.executeSoon(function() { - SimpleTest.executeSoon(function() { - finish(); - }); - }); - }); - }); - }); - } - else { - ok(false, "Got unexpected message: " + e.detail.message); - } - }); - - document.body.appendChild(iframe); -} - -function finish() { - SimpleTest.finish(); -} - -addEventListener('testready', runTest); diff --git a/dom/browser-element/mochitest/browserElement_VisibilityChange.js b/dom/browser-element/mochitest/browserElement_VisibilityChange.js deleted file mode 100644 index d7db5f45d8dd..000000000000 --- a/dom/browser-element/mochitest/browserElement_VisibilityChange.js +++ /dev/null @@ -1,42 +0,0 @@ -/* Any copyright is dedicated to the public domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test that the onmozbrowservisibilitychange event works. -'use strict'; - -SimpleTest.waitForExplicitFinish(); -browserElementTestHelpers.setEnabledPref(true); - -var iframe1 = null; -function runTest() { - iframe1 = document.createElement('iframe'); - iframe1.setAttribute('mozbrowser', 'true'); - document.body.appendChild(iframe1); - - iframe1.src = 'data:text/html,Title'; - checkVisibilityFalse(); -} - -function checkVisibilityFalse() { - iframe1.addEventListener('mozbrowservisibilitychange', function onvisibilitychange(e) { - iframe1.removeEventListener(e.type, onvisibilitychange); - - is(e.detail.visible, false, 'Visibility should be false'); - checkVisibilityTrue(); - }); - - iframe1.setVisible(false); -} - -function checkVisibilityTrue() { - iframe1.addEventListener('mozbrowservisibilitychange', function onvisibilitychange(e) { - iframe1.removeEventListener(e.type, onvisibilitychange); - - is(e.detail.visible, true, 'Visibility should be true'); - SimpleTest.finish(); - }); - - iframe1.setVisible(true); -} - -addEventListener('testready', runTest); diff --git a/dom/browser-element/mochitest/chrome.ini b/dom/browser-element/mochitest/chrome.ini index 9b96fff227dc..ee322fbaf781 100644 --- a/dom/browser-element/mochitest/chrome.ini +++ b/dom/browser-element/mochitest/chrome.ini @@ -20,17 +20,10 @@ support-files = browserElement_PurgeHistory.js browserElement_ReloadPostRequest.js browserElement_SendEvent.js - browserElement_SetVisible.js - browserElement_SetVisibleFrames.js - browserElement_SetVisibleFrames2.js browserElement_Stop.js - browserElement_VisibilityChange.js file_browserElement_ExecuteScript.html file_browserElement_NextPaint.html file_browserElement_SendEvent.html - file_browserElement_SetVisibleFrames2_Outer.html - file_browserElement_SetVisibleFrames_Inner.html - file_browserElement_SetVisibleFrames_Outer.html file_bug709759.sjs file_empty.html file_post_request.html @@ -55,8 +48,4 @@ skip-if = true # bug 1332850, bug 1332862 [test_browserElement_inproc_ReloadPostRequest.html] disabled = no modal prompt on POST reload for chrome window [test_browserElement_inproc_SendEvent.html] -[test_browserElement_inproc_SetVisible.html] -[test_browserElement_inproc_SetVisibleFrames.html] -[test_browserElement_inproc_SetVisibleFrames2.html] [test_browserElement_inproc_Stop.html] -[test_browserElement_inproc_VisibilityChange.html] diff --git a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html deleted file mode 100644 index c4fa25d26bb0..000000000000 --- a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html deleted file mode 100644 index 6abcc6b0c5ec..000000000000 --- a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini index afa4dbc13889..27f2f58ad195 100644 --- a/dom/browser-element/mochitest/mochitest-oop.ini +++ b/dom/browser-element/mochitest/mochitest-oop.ini @@ -80,20 +80,12 @@ disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re skip-if = toolkit == 'android' #TIMED_OUT, bug 766586 [test_browserElement_oop_SendEvent.html] disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) -[test_browserElement_oop_SetVisible.html] -disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) -[test_browserElement_oop_SetVisibleFrames.html] -disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) -[test_browserElement_oop_SetVisibleFrames2.html] -disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) [test_browserElement_oop_Stop.html] disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) [test_browserElement_oop_TargetBlank.html] [test_browserElement_oop_TargetTop.html] [test_browserElement_oop_Titlechange.html] [test_browserElement_oop_TopBarrier.html] -[test_browserElement_oop_VisibilityChange.html] -disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling) [test_browserElement_oop_XFrameOptions.html] [test_browserElement_oop_XFrameOptionsAllowFrom.html] #skip-if = asan # bug 1189592 - should be OK when ASAN mochitests are on Ubuntu 16.04 diff --git a/dom/browser-element/mochitest/priority/chrome.ini b/dom/browser-element/mochitest/priority/chrome.ini deleted file mode 100644 index cfb682cc9891..000000000000 --- a/dom/browser-element/mochitest/priority/chrome.ini +++ /dev/null @@ -1,16 +0,0 @@ -[DEFAULT] -# Good luck running these tests on anything but desktop Linux. -run-if = os == 'linux' && buildapp == 'browser' && !e10s -support-files = - file_MultipleFrames.html - file_NestedFramesOuter.html - file_WebGLContextLost.html - silence.ogg - !/dom/browser-element/mochitest/browserElementTestHelpers.js - !/dom/browser-element/mochitest/file_empty.html - -[test_Activity.html] -[test_Background.html] -[test_MultipleFrames.html] -[test_NestedFrames.html] -[test_Visibility.html] diff --git a/dom/browser-element/mochitest/priority/file_MultipleFrames.html b/dom/browser-element/mochitest/priority/file_MultipleFrames.html deleted file mode 100644 index b3b56f5608be..000000000000 --- a/dom/browser-element/mochitest/priority/file_MultipleFrames.html +++ /dev/null @@ -1,14 +0,0 @@ - - -file_MultipleFrames.html - - - - - diff --git a/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html b/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html deleted file mode 100644 index e4378935f2da..000000000000 --- a/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html +++ /dev/null @@ -1,20 +0,0 @@ - - -file_NestedFramesOuter.html - - - diff --git a/dom/browser-element/mochitest/priority/file_WebGLContextLost.html b/dom/browser-element/mochitest/priority/file_WebGLContextLost.html deleted file mode 100644 index bd5c84f11a18..000000000000 --- a/dom/browser-element/mochitest/priority/file_WebGLContextLost.html +++ /dev/null @@ -1,22 +0,0 @@ - - -file_WebGLContextLost.html - - - - - diff --git a/dom/browser-element/mochitest/priority/mochitest.ini b/dom/browser-element/mochitest/priority/mochitest.ini deleted file mode 100644 index cac4aced2d66..000000000000 --- a/dom/browser-element/mochitest/priority/mochitest.ini +++ /dev/null @@ -1,15 +0,0 @@ -[DEFAULT] -# Good luck running these tests on anything but desktop Linux. -run-if = os == 'linux' && buildapp == 'browser' && !e10s -support-files = - silence.ogg - !/dom/browser-element/mochitest/browserElementTestHelpers.js - !/dom/browser-element/mochitest/file_empty.html - -# Note: ../browserElementTestHelpers.js makes all tests in this directory OOP, -# because testing the process-priority manager without OOP frames does not make -# much sense. - -[test_Simple.html] -[test_WebGLContextLost.html] -disabled = bug 865844 diff --git a/dom/browser-element/mochitest/priority/silence.ogg b/dom/browser-element/mochitest/priority/silence.ogg deleted file mode 100644 index 6e0b352a321a..000000000000 Binary files a/dom/browser-element/mochitest/priority/silence.ogg and /dev/null differ diff --git a/dom/browser-element/mochitest/priority/test_Background.html b/dom/browser-element/mochitest/priority/test_Background.html deleted file mode 100644 index 7870a23d5336..000000000000 --- a/dom/browser-element/mochitest/priority/test_Background.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/priority/test_MultipleFrames.html b/dom/browser-element/mochitest/priority/test_MultipleFrames.html deleted file mode 100644 index 74bd59a7e676..000000000000 --- a/dom/browser-element/mochitest/priority/test_MultipleFrames.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/priority/test_NestedFrames.html b/dom/browser-element/mochitest/priority/test_NestedFrames.html deleted file mode 100644 index 441356600216..000000000000 --- a/dom/browser-element/mochitest/priority/test_NestedFrames.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/priority/test_Simple.html b/dom/browser-element/mochitest/priority/test_Simple.html deleted file mode 100644 index a32dc0ed192d..000000000000 --- a/dom/browser-element/mochitest/priority/test_Simple.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/priority/test_Visibility.html b/dom/browser-element/mochitest/priority/test_Visibility.html deleted file mode 100644 index d33a1f75bce0..000000000000 --- a/dom/browser-element/mochitest/priority/test_Visibility.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/priority/test_WebGLContextLost.html b/dom/browser-element/mochitest/priority/test_WebGLContextLost.html deleted file mode 100644 index 621757307a71..000000000000 --- a/dom/browser-element/mochitest/priority/test_WebGLContextLost.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html deleted file mode 100644 index 257a81ec9b33..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Test for Bug 702880 - - - - - -Mozilla Bug 702880 - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html deleted file mode 100644 index 3e122c45040c..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Test for Bug 762939 - - - - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html deleted file mode 100644 index becd48998df8..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Test for Bug 762939 - - - - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html b/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html deleted file mode 100644 index 239d4065b83f..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Test for Bug 868816 - - - - - -Mozilla Bug 868816 - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html deleted file mode 100644 index bbde694adb1d..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Test for Bug 702880 - - - - - -Mozilla Bug 702880 - - - - - diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html deleted file mode 100644 index 5690b0419c35..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Test for Bug 762939 - - - - - - - - \ No newline at end of file diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html deleted file mode 100644 index 5546b1d1bef0..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Test for Bug 762939 - - - - - - - - \ No newline at end of file diff --git a/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html b/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html deleted file mode 100644 index 811562906931..000000000000 --- a/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Test for Bug 868816 - - - - - -Mozilla Bug 868816 - - - - - diff --git a/dom/browser-element/moz.build b/dom/browser-element/moz.build index eaf3d90510b9..1f267d905ecf 100644 --- a/dom/browser-element/moz.build +++ b/dom/browser-element/moz.build @@ -47,10 +47,8 @@ LOCAL_INCLUDES += [ MOCHITEST_MANIFESTS += [ 'mochitest/mochitest-oop.ini', 'mochitest/mochitest.ini', - 'mochitest/priority/mochitest.ini', ] MOCHITEST_CHROME_MANIFESTS += [ 'mochitest/chrome.ini', - 'mochitest/priority/chrome.ini', ] diff --git a/dom/browser-element/nsIBrowserElementAPI.idl b/dom/browser-element/nsIBrowserElementAPI.idl index 9222e38fb804..f1a054ab3c2d 100644 --- a/dom/browser-element/nsIBrowserElementAPI.idl +++ b/dom/browser-element/nsIBrowserElementAPI.idl @@ -42,11 +42,6 @@ interface nsIBrowserElementAPI : nsISupports void setFrameLoader(in nsIFrameLoader frameLoader); - void setVisible(in boolean visible); - nsIDOMDOMRequest getVisible(); - void setActive(in boolean active); - boolean getActive(); - void sendMouseEvent(in DOMString type, in uint32_t x, in uint32_t y, diff --git a/dom/html/HTMLOptionElement.cpp b/dom/html/HTMLOptionElement.cpp index c389bcd5d8d7..8e197a984264 100644 --- a/dom/html/HTMLOptionElement.cpp +++ b/dom/html/HTMLOptionElement.cpp @@ -151,11 +151,6 @@ HTMLOptionElement::Index() bool HTMLOptionElement::Selected() const { - // If we haven't been explictly selected or deselected, use our default value - if (!mSelectedChanged) { - return DefaultSelected(); - } - return mIsSelected; } @@ -193,21 +188,14 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName, return NS_OK; } - bool defaultSelected = aValue; - // First make sure we actually set our mIsSelected state to reflect our new - // defaultSelected state. If that turns out to be wrong, - // SetOptionsSelectedByIndex will fix it up. But otherwise we can end up in a - // situation where mIsSelected is still false, but mSelectedChanged becomes - // true (later in this method, when we compare mIsSelected to - // defaultSelected), and then we start returning false for Selected() even - // though we're actually selected. - mIsSelected = defaultSelected; - // We just changed out selected state (since we look at the "selected" // attribute when mSelectedChanged is false). Let's tell our select about // it. HTMLSelectElement* selectInt = GetSelect(); if (!selectInt) { + // If option is a child of select, SetOptionsSelectedByIndex will set + // mIsSelected if needed. + mIsSelected = aValue; return NS_OK; } @@ -218,7 +206,7 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName, int32_t index = Index(); uint32_t mask = HTMLSelectElement::SET_DISABLED; - if (defaultSelected) { + if (aValue) { mask |= HTMLSelectElement::IS_SELECTED; } @@ -236,8 +224,8 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName, // rigt selected state. mIsInSetDefaultSelected = inSetDefaultSelected; // mIsSelected might have been changed by SetOptionsSelectedByIndex. Possibly - // more than once; make sure our mSelectedChanged state is set correctly. - mSelectedChanged = mIsSelected != defaultSelected; + // more than once; make sure our mSelectedChanged state is set back correctly. + mSelectedChanged = false; return NS_OK; } @@ -426,13 +414,13 @@ HTMLOptionElement::Option(const GlobalObject& aGlobal, } } - if (aSelected) { - option->SetSelected(true, aError); - if (aError.Failed()) { - return nullptr; - } + option->SetSelected(aSelected, aError); + if (aError.Failed()) { + return nullptr; } + option->SetSelectedChanged(false); + return option.forget(); } diff --git a/dom/html/nsBrowserElement.cpp b/dom/html/nsBrowserElement.cpp index 61b72aa498ac..ffe893c524f1 100644 --- a/dom/html/nsBrowserElement.cpp +++ b/dom/html/nsBrowserElement.cpp @@ -66,62 +66,6 @@ nsBrowserElement::DestroyBrowserElementFrameScripts() mBrowserElementAPI->DestroyFrameScripts(); } -void -nsBrowserElement::SetVisible(bool aVisible, ErrorResult& aRv) -{ - NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); - - nsresult rv = mBrowserElementAPI->SetVisible(aVisible); - - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - } -} - -already_AddRefed -nsBrowserElement::GetVisible(ErrorResult& aRv) -{ - NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); - - nsCOMPtr req; - nsresult rv = mBrowserElementAPI->GetVisible(getter_AddRefs(req)); - - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - return req.forget().downcast(); -} - -void -nsBrowserElement::SetActive(bool aVisible, ErrorResult& aRv) -{ - NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv)); - - nsresult rv = mBrowserElementAPI->SetActive(aVisible); - - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - } -} - -bool -nsBrowserElement::GetActive(ErrorResult& aRv) -{ - NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), false); - - bool isActive; - nsresult rv = mBrowserElementAPI->GetActive(&isActive); - - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return false; - } - - return isActive; -} - void nsBrowserElement::SendMouseEvent(const nsAString& aType, uint32_t aX, diff --git a/dom/html/nsBrowserElement.h b/dom/html/nsBrowserElement.h index 9ed96008720c..3099c5994eba 100644 --- a/dom/html/nsBrowserElement.h +++ b/dom/html/nsBrowserElement.h @@ -36,11 +36,6 @@ public: nsBrowserElement() {} virtual ~nsBrowserElement() {} - void SetVisible(bool aVisible, ErrorResult& aRv); - already_AddRefed GetVisible(ErrorResult& aRv); - void SetActive(bool aActive, ErrorResult& aRv); - bool GetActive(ErrorResult& aRv); - void SendMouseEvent(const nsAString& aType, uint32_t aX, uint32_t aY, diff --git a/dom/html/test/test_bug596511.html b/dom/html/test/test_bug596511.html index ea7d0cd9d6a7..578e487f308d 100644 --- a/dom/html/test/test_bug596511.html +++ b/dom/html/test/test_bug596511.html @@ -186,7 +186,7 @@ function checkInvalidWhenValueMissing(element) // Setting defaultSelected to true should not make the option selected select.add(new Option("", "", true), null); - checkSufferingFromBeingMissing(select, true); + checkSufferingFromBeingMissing(select); select.remove(0); select.add(new Option("", "", true, true), null); @@ -210,13 +210,13 @@ function checkInvalidWhenValueMissing(element) checkSufferingFromBeingMissing(select); select.add(new Option("", "", true), null); - checkSufferingFromBeingMissing(select, true); + checkSufferingFromBeingMissing(select); select.add(new Option("", "", true), null); - checkSufferingFromBeingMissing(select, true); + checkSufferingFromBeingMissing(select); select.add(new Option("foo"), null); - checkSufferingFromBeingMissing(select, true); + checkSufferingFromBeingMissing(select); select.options[2].selected = true; checkNotSufferingFromBeingMissing(select); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 0f35317b0c1d..af3dce7edebe 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1388,30 +1388,6 @@ RemoteWindowContext::OpenURI(nsIURI* aURI) } // namespace -bool -ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority) -{ - ProcessPriorityManager::SetProcessPriority(this, aPriority); - - // Now that we've set this process's priority, check whether the process is - // still alive. Hopefully we've set the priority to FOREGROUND*, so the - // process won't unexpectedly crash after this point! - // - // Bug 943174: use waitid() with WNOWAIT so that, if the process - // did exit, we won't consume its zombie and confuse the - // GeckoChildProcessHost dtor. -#ifdef MOZ_WIDGET_GONK - siginfo_t info; - info.si_pid = 0; - if (waitid(P_PID, Pid(), &info, WNOWAIT | WNOHANG | WEXITED) == 0 - && info.si_pid != 0) { - return false; - } -#endif - - return true; -} - void ContentParent::ShutDownProcess(ShutDownMethod aMethod) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index f4a3ba0027d3..7fedde4bd38d 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -731,12 +731,6 @@ private: // called after the process has been transformed to browser. void ForwardKnownInfo(); - // Set the child process's priority and then check whether the child is - // still alive. Returns true if the process is still alive, and false - // otherwise. If you pass a FOREGROUND* priority here, it's (hopefully) - // unlikely that the process will be killed after this point. - bool SetPriorityAndCheckIsAlive(hal::ProcessPriority aPriority); - /** * Decide whether the process should be kept alive even when it would normally * be shut down, for example when all its tabs are closed. diff --git a/dom/ipc/ProcessPriorityManager.cpp b/dom/ipc/ProcessPriorityManager.cpp index e21487b618a1..d3a3986ac238 100644 --- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -135,11 +135,6 @@ public: void FireTestOnlyObserverNotification(const char* aTopic, const nsACString& aData = EmptyCString()); - /** - * Does one of the child processes have priority FOREGROUND_HIGH? - */ - bool ChildProcessHasHighPriority(); - /** * This must be called by a ParticularProcessPriorityManager when it changes * its priority. @@ -207,7 +202,6 @@ public: NS_DECL_NSIOBSERVER bool CurrentProcessIsForeground(); - bool CurrentProcessIsHighPriority(); private: static StaticRefPtr sSingleton; @@ -257,11 +251,8 @@ public: */ const nsAutoCString& NameWithComma(); - bool IsExpectingSystemMessage(); - void OnRemoteBrowserFrameShown(nsISupports* aSubject); void OnTabParentDestroyed(nsISupports* aSubject); - void OnFrameloaderVisibleChanged(nsISupports* aSubject); void OnActivityOpened(const char16_t* aData); void OnActivityClosed(const char16_t* aData); @@ -516,12 +507,6 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject) } } -bool -ProcessPriorityManagerImpl::ChildProcessHasHighPriority( void ) -{ - return mHighPriorityChildIDs.Count() > 0; -} - void ProcessPriorityManagerImpl::NotifyProcessPriorityChanged( ParticularProcessPriorityManager* aParticularManager, @@ -592,7 +577,6 @@ ParticularProcessPriorityManager::Init() if (os) { os->AddObserver(this, "remote-browser-shown", /* ownsWeak */ true); os->AddObserver(this, "ipc:browser-destroyed", /* ownsWeak */ true); - os->AddObserver(this, "frameloader-visible-changed", /* ownsWeak */ true); os->AddObserver(this, "activity-opened", /* ownsWeak */ true); os->AddObserver(this, "activity-closed", /* ownsWeak */ true); } @@ -666,8 +650,6 @@ ParticularProcessPriorityManager::Observe(nsISupports* aSubject, OnRemoteBrowserFrameShown(aSubject); } else if (topic.EqualsLiteral("ipc:browser-destroyed")) { OnTabParentDestroyed(aSubject); - } else if (topic.EqualsLiteral("frameloader-visible-changed")) { - OnFrameloaderVisibleChanged(aSubject); } else if (topic.EqualsLiteral("activity-opened")) { OnActivityOpened(aData); } else if (topic.EqualsLiteral("activity-closed")) { @@ -755,38 +737,6 @@ ParticularProcessPriorityManager::OnTabParentDestroyed(nsISupports* aSubject) ResetPriority(); } -void -ParticularProcessPriorityManager::OnFrameloaderVisibleChanged(nsISupports* aSubject) -{ - nsCOMPtr fl = do_QueryInterface(aSubject); - NS_ENSURE_TRUE_VOID(fl); - - TabParent* tp = TabParent::GetFrom(fl); - if (!tp) { - return; - } - - MOZ_ASSERT(XRE_IsParentProcess()); - if (tp->Manager() != mContentParent) { - return; - } - - // Most of the time when something changes in a process we call - // ResetPriority(), giving a grace period before downgrading its priority. - // But notice that here don't give a grace period: We call ResetPriorityNow() - // instead. - // - // We do this because we're reacting here to a setVisibility() call, which is - // an explicit signal from the process embedder that we should re-prioritize - // a process. If we gave a grace period in response to setVisibility() - // calls, it would be impossible for the embedder to explicitly prioritize - // processes and prevent e.g. the case where we switch which process is in - // the foreground and, during the old fg processs's grace period, it OOMs the - // new fg process. - - ResetPriorityNow(); -} - void ParticularProcessPriorityManager::OnActivityOpened(const char16_t* aData) { @@ -874,22 +824,6 @@ ParticularProcessPriorityManager::Notify(nsITimer* aTimer) return NS_OK; } -bool -ParticularProcessPriorityManager::IsExpectingSystemMessage() -{ - const ManagedContainer& browsers = - mContentParent->ManagedPBrowserParent(); - for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) { - TabParent* tp = TabParent::GetFrom(iter.Get()->GetKey()); - nsCOMPtr bf = do_QueryInterface(tp->GetOwnerElement()); - if (!bf) { - continue; - } - } - - return false; -} - ProcessPriority ParticularProcessPriorityManager::CurrentPriority() { @@ -899,22 +833,10 @@ ParticularProcessPriorityManager::CurrentPriority() ProcessPriority ParticularProcessPriorityManager::ComputePriority() { - bool isVisible = false; - const ManagedContainer& browsers = - mContentParent->ManagedPBrowserParent(); - for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) { - if (TabParent::GetFrom(iter.Get()->GetKey())->IsVisible()) { - isVisible = true; - break; - } - } + // TODO... + return PROCESS_PRIORITY_FOREGROUND; - if (isVisible) { - return PROCESS_PRIORITY_FOREGROUND; - } - - if ((mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) && - IsExpectingSystemMessage()) { + if (mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) { return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE; } @@ -1055,8 +977,7 @@ ProcessPriorityManagerChild::Singleton() return sSingleton; } -NS_IMPL_ISUPPORTS(ProcessPriorityManagerChild, - nsIObserver) +NS_IMPL_ISUPPORTS(ProcessPriorityManagerChild, nsIObserver) ProcessPriorityManagerChild::ProcessPriorityManagerChild() { @@ -1080,10 +1001,9 @@ ProcessPriorityManagerChild::Init() } NS_IMETHODIMP -ProcessPriorityManagerChild::Observe( - nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) +ProcessPriorityManagerChild::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) { MOZ_ASSERT(!strcmp(aTopic, "ipc:process-priority-changed")); @@ -1106,13 +1026,6 @@ ProcessPriorityManagerChild::CurrentProcessIsForeground() mCachedPriority >= PROCESS_PRIORITY_FOREGROUND; } -bool -ProcessPriorityManagerChild::CurrentProcessIsHighPriority() -{ - return mCachedPriority == PROCESS_PRIORITY_UNKNOWN || - mCachedPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH; -} - } // namespace namespace mozilla { @@ -1145,18 +1058,4 @@ ProcessPriorityManager::CurrentProcessIsForeground() CurrentProcessIsForeground(); } -/* static */ bool -ProcessPriorityManager::AnyProcessHasHighPriority() -{ - ProcessPriorityManagerImpl* singleton = - ProcessPriorityManagerImpl::GetSingleton(); - - if (singleton) { - return singleton->ChildProcessHasHighPriority(); - } else { - return ProcessPriorityManagerChild::Singleton()-> - CurrentProcessIsHighPriority(); - } -} - } // namespace mozilla diff --git a/dom/ipc/ProcessPriorityManager.h b/dom/ipc/ProcessPriorityManager.h index 5e02c9c323af..aa3e0ad7993d 100644 --- a/dom/ipc/ProcessPriorityManager.h +++ b/dom/ipc/ProcessPriorityManager.h @@ -68,12 +68,6 @@ public: */ static bool CurrentProcessIsForeground(); - /** - * Returns true if one or more processes with FOREGROUND_HIGH priority are - * present, false otherwise. - */ - static bool AnyProcessHasHighPriority(); - private: ProcessPriorityManager(); DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 0c5d5709ca2b..0cb06bc6bfa5 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -320,17 +320,6 @@ TabParent::RemoveWindowListeners() } } -bool -TabParent::IsVisible() const -{ - RefPtr frameLoader = GetFrameLoader(); - if (!frameLoader) { - return false; - } - - return frameLoader->GetVisible(); -} - void TabParent::DestroyInternal() { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index e5c157bb8c1d..e418efadd10f 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -118,14 +118,6 @@ public: void CacheFrameLoader(nsFrameLoader* aFrameLoader); - /** - * Returns true iff this TabParent's nsIFrameLoader is visible. - * - * The frameloader's visibility can be independent of e.g. its docshell's - * visibility. - */ - bool IsVisible() const; - nsIBrowserDOMWindow *GetBrowserDOMWindow() const { return mBrowserDOMWindow; } void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp index 238c837b27e7..51b1cee125c1 100644 --- a/dom/url/URL.cpp +++ b/dom/url/URL.cpp @@ -5,1638 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "URL.h" +#include "URLMainThread.h" +#include "URLWorker.h" -#include "DOMMediaStream.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/MediaSource.h" +#include "MainThreadUtils.h" #include "mozilla/dom/URLBinding.h" -#include "mozilla/ipc/BackgroundChild.h" -#include "nsContentUtils.h" -#include "nsEscape.h" -#include "nsHostObjectProtocolHandler.h" -#include "nsIIOService.h" -#include "nsIURL.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" -#include "nsServiceManagerUtils.h" -#include "WorkerPrivate.h" -#include "WorkerRunnable.h" -#include "WorkerScope.h" +#include "mozilla/dom/BindingUtils.h" +#include "nsIDocument.h" namespace mozilla { namespace dom { -/////////////////////////////////////////////////////////////////////////////// -// URL for main-thread -/////////////////////////////////////////////////////////////////////////////// - -namespace { - -template -void -CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject, - nsAString& aResult, ErrorResult& aRv) -{ - nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); - if (NS_WARN_IF(!global)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsCOMPtr principal = - nsContentUtils::ObjectPrincipal(aGlobal.Get()); - - nsAutoCString url; - aRv = nsHostObjectProtocolHandler::AddDataEntry(aObject, principal, url); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - global->RegisterHostObjectURI(url); - CopyASCIItoUTF16(url, aResult); -} - -// The URL implementation for the main-thread -class URLMainThread final : public URL -{ -public: - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv); - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const Optional& aBase, ErrorResult& aRv); - - static already_AddRefed - Constructor(nsISupports* aParent, const nsAString& aURL, - const nsAString& aBase, ErrorResult& aRv); - - static already_AddRefed - Constructor(nsISupports* aParent, const nsAString& aURL, nsIURI* aBase, - ErrorResult& aRv); - - static void - CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, - nsAString& aResult, ErrorResult& aRv) - { - MOZ_ASSERT(NS_IsMainThread()); - CreateObjectURLInternal(aGlobal, aBlob.Impl(), aResult, aRv); - } - - static void - CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream, - nsAString& aResult, ErrorResult& aRv) - { - MOZ_ASSERT(NS_IsMainThread()); - CreateObjectURLInternal(aGlobal, &aStream, aResult, aRv); - } - - static void - CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource, - nsAString& aResult, ErrorResult& aRv); - - static void - RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL, - ErrorResult& aRv); - - static bool - IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, - ErrorResult& aRv); - - URLMainThread(nsISupports* aParent, already_AddRefed aURI) - : URL(aParent) - , mURI(aURI) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - virtual void - GetHref(nsAString& aHref, ErrorResult& aRv) const override; - - virtual void - SetHref(const nsAString& aHref, ErrorResult& aRv) override; - - virtual void - GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; - - virtual void - GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override; - - virtual void - SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override; - - virtual void - GetUsername(nsAString& aUsername, ErrorResult& aRv) const override; - - virtual void - SetUsername(const nsAString& aUsername, ErrorResult& aRv) override; - - virtual void - GetPassword(nsAString& aPassword, ErrorResult& aRv) const override; - - virtual void - SetPassword(const nsAString& aPassword, ErrorResult& aRv) override; - - virtual void - GetHost(nsAString& aHost, ErrorResult& aRv) const override; - - virtual void - SetHost(const nsAString& aHost, ErrorResult& aRv) override; - - virtual void - GetHostname(nsAString& aHostname, ErrorResult& aRv) const override; - - virtual void - SetHostname(const nsAString& aHostname, ErrorResult& aRv) override; - - virtual void - GetPort(nsAString& aPort, ErrorResult& aRv) const override; - - virtual void - SetPort(const nsAString& aPort, ErrorResult& aRv) override; - - virtual void - GetPathname(nsAString& aPathname, ErrorResult& aRv) const override; - - virtual void - SetPathname(const nsAString& aPathname, ErrorResult& aRv) override; - - virtual void - GetSearch(nsAString& aSearch, ErrorResult& aRv) const override; - - virtual void - GetHash(nsAString& aHost, ErrorResult& aRv) const override; - - virtual void - SetHash(const nsAString& aHash, ErrorResult& aRv) override; - - virtual void UpdateURLSearchParams() override; - - virtual void - SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override; - - nsIURI* - GetURI() const - { - MOZ_ASSERT(NS_IsMainThread()); - return mURI; - } - -private: - ~URLMainThread() - { - MOZ_ASSERT(NS_IsMainThread()); - } - - nsCOMPtr mURI; -}; - -/* static */ already_AddRefed -URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - URLMainThread& base = static_cast(aBase); - return Constructor(aGlobal.GetAsSupports(), aURL, base.GetURI(), aRv); -} - -/* static */ already_AddRefed -URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const Optional& aBase, ErrorResult& aRv) -{ - if (aBase.WasPassed()) { - return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv); - } - - return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv); -} - -/* static */ already_AddRefed -URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL, - const nsAString& aBase, ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr baseUri; - nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr, - nsContentUtils::GetIOService()); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.ThrowTypeError(aBase); - return nullptr; - } - - return Constructor(aParent, aURL, baseUri, aRv); -} - -/* static */ already_AddRefed -URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL, - nsIURI* aBase, ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase, - nsContentUtils::GetIOService()); - if (NS_FAILED(rv)) { - // No need to warn in this case. It's common to use the URL constructor - // to determine if a URL is valid and an exception will be propagated. - aRv.ThrowTypeError(aURL); - return nullptr; - } - - RefPtr url = new URLMainThread(aParent, uri.forget()); - return url.forget(); -} - -/* static */ void -URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, - MediaSource& aSource, - nsAString& aResult, ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr principal = - nsContentUtils::ObjectPrincipal(aGlobal.Get()); - - nsAutoCString url; - aRv = nsHostObjectProtocolHandler::AddDataEntry(&aSource, principal, url); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - nsCOMPtr revocation = NS_NewRunnableFunction( - [url] { - nsHostObjectProtocolHandler::RemoveDataEntry(url); - }); - - nsContentUtils::RunInStableState(revocation.forget()); - - CopyASCIItoUTF16(url, aResult); -} - -/* static */ void -URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal, - const nsAString& aURL, ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); - if (!global) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal.Get()); - - NS_LossyConvertUTF16toASCII asciiurl(aURL); - - nsIPrincipal* urlPrincipal = - nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl); - - if (urlPrincipal && principal->Subsumes(urlPrincipal)) { - global->UnregisterHostObjectURI(asciiurl); - nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl); - } -} - -/* static */ bool -URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, - ErrorResult& aRv) -{ - MOZ_ASSERT(NS_IsMainThread()); - NS_LossyConvertUTF16toASCII asciiurl(aURL); - return nsHostObjectProtocolHandler::HasDataEntry(asciiurl); -} - -void -URLMainThread::GetHref(nsAString& aHref, ErrorResult& aRv) const -{ - aHref.Truncate(); - - nsAutoCString href; - nsresult rv = mURI->GetSpec(href); - if (NS_SUCCEEDED(rv)) { - CopyUTF8toUTF16(href, aHref); - } -} - -void -URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv) -{ - NS_ConvertUTF16toUTF8 href(aHref); - - nsresult rv; - nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return; - } - - nsCOMPtr uri; - rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri)); - if (NS_FAILED(rv)) { - aRv.ThrowTypeError(aHref); - return; - } - - mURI = uri; - UpdateURLSearchParams(); -} - -void -URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const -{ - nsContentUtils::GetUTFOrigin(mURI, aOrigin); -} - -void -URLMainThread::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const -{ - nsAutoCString protocol; - if (NS_SUCCEEDED(mURI->GetScheme(protocol))) { - aProtocol.Truncate(); - } - - CopyASCIItoUTF16(protocol, aProtocol); - aProtocol.Append(char16_t(':')); -} - -void -URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) -{ - nsAString::const_iterator start, end; - aProtocol.BeginReading(start); - aProtocol.EndReading(end); - nsAString::const_iterator iter(start); - - FindCharInReadable(':', iter, end); - - // Changing the protocol of a URL, changes the "nature" of the URI - // implementation. In order to do this properly, we have to serialize the - // existing URL and reparse it in a new object. - nsCOMPtr clone; - nsresult rv = mURI->Clone(getter_AddRefs(clone)); - if (NS_WARN_IF(NS_FAILED(rv)) || !clone) { - return; - } - - rv = clone->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsAutoCString href; - rv = clone->GetSpec(href); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), href); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - mURI = uri; -} - -#define URL_GETTER( value, func ) \ - value.Truncate(); \ - nsAutoCString tmp; \ - nsresult rv = mURI->func(tmp); \ - if (NS_SUCCEEDED(rv)) { \ - CopyUTF8toUTF16(tmp, value); \ - } - -void -URLMainThread::GetUsername(nsAString& aUsername, ErrorResult& aRv) const -{ - URL_GETTER(aUsername, GetUsername); -} - -void -URLMainThread::SetUsername(const nsAString& aUsername, ErrorResult& aRv) -{ - mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); -} - -void -URLMainThread::GetPassword(nsAString& aPassword, ErrorResult& aRv) const -{ - URL_GETTER(aPassword, GetPassword); -} - -void -URLMainThread::SetPassword(const nsAString& aPassword, ErrorResult& aRv) -{ - mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); -} - -void -URLMainThread::GetHost(nsAString& aHost, ErrorResult& aRv) const -{ - URL_GETTER(aHost, GetHostPort); -} - -void -URLMainThread::SetHost(const nsAString& aHost, ErrorResult& aRv) -{ - mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); -} - -void -URLMainThread::UpdateURLSearchParams() -{ - if (!mSearchParams) { - return; - } - - nsAutoCString search; - nsCOMPtr url(do_QueryInterface(mURI)); - if (url) { - nsresult rv = url->GetQuery(search); - if (NS_WARN_IF(NS_FAILED(rv))) { - search.Truncate(); - } - } - - mSearchParams->ParseInput(search); -} - -void -URLMainThread::GetHostname(nsAString& aHostname, ErrorResult& aRv) const -{ - aHostname.Truncate(); - nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname); -} - -void -URLMainThread::SetHostname(const nsAString& aHostname, ErrorResult& aRv) -{ - // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname - // The return code is silently ignored - mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname)); -} - -void -URLMainThread::GetPort(nsAString& aPort, ErrorResult& aRv) const -{ - aPort.Truncate(); - - int32_t port; - nsresult rv = mURI->GetPort(&port); - if (NS_SUCCEEDED(rv) && port != -1) { - nsAutoString portStr; - portStr.AppendInt(port, 10); - aPort.Assign(portStr); - } -} - -void -URLMainThread::SetPort(const nsAString& aPort, ErrorResult& aRv) -{ - nsresult rv; - nsAutoString portStr(aPort); - int32_t port = -1; - - // nsIURI uses -1 as default value. - if (!portStr.IsEmpty()) { - port = portStr.ToInteger(&rv); - if (NS_FAILED(rv)) { - return; - } - } - - mURI->SetPort(port); -} - -void -URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const -{ - aPathname.Truncate(); - - // Do not throw! Not having a valid URI or URL should result in an empty - // string. - - nsAutoCString file; - nsresult rv = mURI->GetFilePath(file); - if (NS_SUCCEEDED(rv)) { - CopyUTF8toUTF16(file, aPathname); - } -} - -void -URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv) -{ - // Do not throw! - - mURI->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); -} - -void -URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const -{ - aSearch.Truncate(); - - // Do not throw! Not having a valid URI or URL should result in an empty - // string. - - nsAutoCString search; - nsresult rv; - - rv = mURI->GetQuery(search); - if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { - CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); - } -} - -void -URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const -{ - aHash.Truncate(); - - nsAutoCString ref; - nsresult rv = mURI->GetRef(ref); - if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { - aHash.Assign(char16_t('#')); - AppendUTF8toUTF16(ref, aHash); - } -} - -void -URLMainThread::SetHash(const nsAString& aHash, ErrorResult& aRv) -{ - mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); -} - -void -URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) -{ - // Ignore failures to be compatible with NS4. - - mURI->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); -} - -} // anonymous namespace - -/////////////////////////////////////////////////////////////////////////////// -// URL for Workers -/////////////////////////////////////////////////////////////////////////////// - -namespace { - -using namespace workers; - -// Proxy class to forward all the requests to a URLMainThread object. -class URLProxy final -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy) - - explicit URLProxy(already_AddRefed aURL) - : mURL(aURL) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - URLMainThread* URL() - { - MOZ_ASSERT(NS_IsMainThread()); - return mURL; - } - - nsIURI* URI() - { - MOZ_ASSERT(NS_IsMainThread()); - return mURL->GetURI(); - } - - void ReleaseURI() - { - MOZ_ASSERT(NS_IsMainThread()); - mURL = nullptr; - } - -private: - // Private destructor, to discourage deletion outside of Release(): - ~URLProxy() - { - MOZ_ASSERT(!mURL); - } - - RefPtr mURL; -}; - -// URLWorker implements the URL object in workers. -class URLWorker final : public URL -{ -public: - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv); - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const Optional& aBase, ErrorResult& aRv); - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const nsAString& aBase, ErrorResult& aRv); - - static void - CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, - nsAString& aResult, mozilla::ErrorResult& aRv); - - static void - RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl, - ErrorResult& aRv); - - static bool - IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, - ErrorResult& aRv); - - URLWorker(WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy); - - virtual void - GetHref(nsAString& aHref, ErrorResult& aRv) const override; - - virtual void - SetHref(const nsAString& aHref, ErrorResult& aRv) override; - - virtual void - GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; - - virtual void - GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override; - - virtual void - SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override; - - virtual void - GetUsername(nsAString& aUsername, ErrorResult& aRv) const override; - - virtual void - SetUsername(const nsAString& aUsername, ErrorResult& aRv) override; - - virtual void - GetPassword(nsAString& aPassword, ErrorResult& aRv) const override; - - virtual void - SetPassword(const nsAString& aPassword, ErrorResult& aRv) override; - - virtual void - GetHost(nsAString& aHost, ErrorResult& aRv) const override; - - virtual void - SetHost(const nsAString& aHost, ErrorResult& aRv) override; - - virtual void - GetHostname(nsAString& aHostname, ErrorResult& aRv) const override; - - virtual void - SetHostname(const nsAString& aHostname, ErrorResult& aRv) override; - - virtual void - GetPort(nsAString& aPort, ErrorResult& aRv) const override; - - virtual void - SetPort(const nsAString& aPort, ErrorResult& aRv) override; - - virtual void - GetPathname(nsAString& aPathname, ErrorResult& aRv) const override; - - virtual void - SetPathname(const nsAString& aPathname, ErrorResult& aRv) override; - - virtual void - GetSearch(nsAString& aSearch, ErrorResult& aRv) const override; - - virtual void - GetHash(nsAString& aHost, ErrorResult& aRv) const override; - - virtual void - SetHash(const nsAString& aHash, ErrorResult& aRv) override; - - virtual void UpdateURLSearchParams() override; - - virtual void - SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override; - - URLProxy* - GetURLProxy() const - { - mWorkerPrivate->AssertIsOnWorkerThread(); - return mURLProxy; - } - -private: - ~URLWorker(); - - workers::WorkerPrivate* mWorkerPrivate; - RefPtr mURLProxy; -}; - -// This class creates an URL from a DOM Blob on the main thread. -class CreateURLRunnable : public WorkerMainThreadRunnable -{ -private: - BlobImpl* mBlobImpl; - nsAString& mURL; - -public: - CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl, - nsAString& aURL) - : WorkerMainThreadRunnable(aWorkerPrivate, - NS_LITERAL_CSTRING("URL :: CreateURL")) - , mBlobImpl(aBlobImpl) - , mURL(aURL) - { - MOZ_ASSERT(aBlobImpl); - - DebugOnly isMutable; - MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable))); - MOZ_ASSERT(!isMutable); - } - - bool - MainThreadRun() - { - using namespace mozilla::ipc; - - AssertIsOnMainThread(); - - DebugOnly isMutable; - MOZ_ASSERT(NS_SUCCEEDED(mBlobImpl->GetMutable(&isMutable))); - MOZ_ASSERT(!isMutable); - - nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); - - nsAutoCString url; - nsresult rv = - nsHostObjectProtocolHandler::AddDataEntry(mBlobImpl, principal, url); - - if (NS_FAILED(rv)) { - NS_WARNING("Failed to add data entry for the blob!"); - SetDOMStringToNull(mURL); - return false; - } - - if (!mWorkerPrivate->IsSharedWorker() && - !mWorkerPrivate->IsServiceWorker()) { - // Walk up to top worker object. - WorkerPrivate* wp = mWorkerPrivate; - while (WorkerPrivate* parent = wp->GetParent()) { - wp = parent; - } - - nsCOMPtr sc = wp->GetScriptContext(); - // We could not have a ScriptContext in JSM code. In this case, we leak. - if (sc) { - nsCOMPtr global = sc->GetGlobalObject(); - MOZ_ASSERT(global); - - global->RegisterHostObjectURI(url); - } - } - - mURL = NS_ConvertUTF8toUTF16(url); - return true; - } -}; - -// This class revokes an URL on the main thread. -class RevokeURLRunnable : public WorkerMainThreadRunnable -{ -private: - const nsString mURL; - -public: - RevokeURLRunnable(WorkerPrivate* aWorkerPrivate, - const nsAString& aURL) - : WorkerMainThreadRunnable(aWorkerPrivate, - NS_LITERAL_CSTRING("URL :: RevokeURL")) - , mURL(aURL) - {} - - bool - MainThreadRun() - { - AssertIsOnMainThread(); - - NS_ConvertUTF16toUTF8 url(mURL); - - nsIPrincipal* urlPrincipal = - nsHostObjectProtocolHandler::GetDataEntryPrincipal(url); - - nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); - - bool subsumes; - if (urlPrincipal && - NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) && - subsumes) { - nsHostObjectProtocolHandler::RemoveDataEntry(url); - } - - if (!mWorkerPrivate->IsSharedWorker() && - !mWorkerPrivate->IsServiceWorker()) { - // Walk up to top worker object. - WorkerPrivate* wp = mWorkerPrivate; - while (WorkerPrivate* parent = wp->GetParent()) { - wp = parent; - } - - nsCOMPtr sc = wp->GetScriptContext(); - // We could not have a ScriptContext in JSM code. In this case, we leak. - if (sc) { - nsCOMPtr global = sc->GetGlobalObject(); - MOZ_ASSERT(global); - - global->UnregisterHostObjectURI(url); - } - } - - return true; - } -}; - -// This class checks if an URL is valid on the main thread. -class IsValidURLRunnable : public WorkerMainThreadRunnable -{ -private: - const nsString mURL; - bool mValid; - -public: - IsValidURLRunnable(WorkerPrivate* aWorkerPrivate, - const nsAString& aURL) - : WorkerMainThreadRunnable(aWorkerPrivate, - NS_LITERAL_CSTRING("URL :: IsValidURL")) - , mURL(aURL) - , mValid(false) - {} - - bool - MainThreadRun() - { - AssertIsOnMainThread(); - - NS_ConvertUTF16toUTF8 url(mURL); - mValid = nsHostObjectProtocolHandler::HasDataEntry(url); - - return true; - } - - bool - IsValidURL() const - { - return mValid; - } -}; - -// This class creates a URL object on the main thread. -class ConstructorRunnable : public WorkerMainThreadRunnable -{ -private: - const nsString mURL; - - nsString mBase; // IsVoid() if we have no base URI string. - RefPtr mBaseProxy; - - RefPtr mRetval; - -public: - ConstructorRunnable(WorkerPrivate* aWorkerPrivate, - const nsAString& aURL, const Optional& aBase) - : WorkerMainThreadRunnable(aWorkerPrivate, - NS_LITERAL_CSTRING("URL :: Constructor")) - , mURL(aURL) - { - if (aBase.WasPassed()) { - mBase = aBase.Value(); - } else { - mBase.SetIsVoid(true); - } - mWorkerPrivate->AssertIsOnWorkerThread(); - } - - ConstructorRunnable(WorkerPrivate* aWorkerPrivate, - const nsAString& aURL, URLProxy* aBaseProxy) - : WorkerMainThreadRunnable(aWorkerPrivate, - NS_LITERAL_CSTRING("URL :: Constructor with BaseURL")) - , mURL(aURL) - , mBaseProxy(aBaseProxy) - { - mBase.SetIsVoid(true); - mWorkerPrivate->AssertIsOnWorkerThread(); - } - - bool - MainThreadRun() - { - AssertIsOnMainThread(); - - ErrorResult rv; - RefPtr url; - if (mBaseProxy) { - url = URLMainThread::Constructor(nullptr, mURL, mBaseProxy->URI(), rv); - } else if (!mBase.IsVoid()) { - url = URLMainThread::Constructor(nullptr, mURL, mBase, rv); - } else { - url = URLMainThread::Constructor(nullptr, mURL, nullptr, rv); - } - - if (rv.Failed()) { - rv.SuppressException(); - return true; - } - - mRetval = new URLProxy(url.forget()); - return true; - } - - URLProxy* - GetURLProxy(ErrorResult& aRv) const - { - MOZ_ASSERT(mWorkerPrivate); - mWorkerPrivate->AssertIsOnWorkerThread(); - - if (!mRetval) { - aRv.ThrowTypeError(mURL); - } - - return mRetval; - } -}; - -class TeardownURLRunnable : public Runnable -{ -public: - explicit TeardownURLRunnable(URLProxy* aURLProxy) - : mURLProxy(aURLProxy) - { - } - - NS_IMETHOD Run() - { - AssertIsOnMainThread(); - - mURLProxy->ReleaseURI(); - mURLProxy = nullptr; - - return NS_OK; - } - -private: - RefPtr mURLProxy; -}; - -// This class is the generic getter for any URL property. -class GetterRunnable : public WorkerMainThreadRunnable -{ -public: - enum GetterType { - GetterHref, - GetterOrigin, - GetterProtocol, - GetterUsername, - GetterPassword, - GetterHost, - GetterHostname, - GetterPort, - GetterPathname, - GetterSearch, - GetterHash, - }; - - GetterRunnable(WorkerPrivate* aWorkerPrivate, - GetterType aType, nsAString& aValue, - URLProxy* aURLProxy) - : WorkerMainThreadRunnable(aWorkerPrivate, - // We can have telemetry keys for each getter when - // needed. - NS_LITERAL_CSTRING("URL :: getter")) - , mValue(aValue) - , mType(aType) - , mURLProxy(aURLProxy) - { - mWorkerPrivate->AssertIsOnWorkerThread(); - } - - bool - MainThreadRun() - { - AssertIsOnMainThread(); - ErrorResult rv; - - switch (mType) { - case GetterHref: - mURLProxy->URL()->GetHref(mValue, rv); - break; - - case GetterOrigin: - mURLProxy->URL()->GetOrigin(mValue, rv); - break; - - case GetterProtocol: - mURLProxy->URL()->GetProtocol(mValue, rv); - break; - - case GetterUsername: - mURLProxy->URL()->GetUsername(mValue, rv); - break; - - case GetterPassword: - mURLProxy->URL()->GetPassword(mValue, rv); - break; - - case GetterHost: - mURLProxy->URL()->GetHost(mValue, rv); - break; - - case GetterHostname: - mURLProxy->URL()->GetHostname(mValue, rv); - break; - - case GetterPort: - mURLProxy->URL()->GetPort(mValue, rv); - break; - - case GetterPathname: - mURLProxy->URL()->GetPathname(mValue, rv); - break; - - case GetterSearch: - mURLProxy->URL()->GetSearch(mValue, rv); - break; - - case GetterHash: - mURLProxy->URL()->GetHash(mValue, rv); - break; - } - - MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail."); - return true; - } - - void - Dispatch(ErrorResult& aRv) - { - WorkerMainThreadRunnable::Dispatch(Terminating, aRv); - } - -private: - nsAString& mValue; - GetterType mType; - RefPtr mURLProxy; -}; - -// This class is the generic setter for any URL property. -class SetterRunnable : public WorkerMainThreadRunnable -{ -public: - enum SetterType { - SetterHref, - SetterProtocol, - SetterUsername, - SetterPassword, - SetterHost, - SetterHostname, - SetterPort, - SetterPathname, - SetterSearch, - SetterHash, - }; - - SetterRunnable(WorkerPrivate* aWorkerPrivate, - SetterType aType, const nsAString& aValue, - URLProxy* aURLProxy) - : WorkerMainThreadRunnable(aWorkerPrivate, - // We can have telemetry keys for each setter when - // needed. - NS_LITERAL_CSTRING("URL :: setter")) - , mValue(aValue) - , mType(aType) - , mURLProxy(aURLProxy) - , mFailed(false) - { - mWorkerPrivate->AssertIsOnWorkerThread(); - } - - bool - MainThreadRun() - { - AssertIsOnMainThread(); - ErrorResult rv; - - switch (mType) { - case SetterHref: { - mURLProxy->URL()->SetHref(mValue, rv); - break; - } - - case SetterProtocol: - mURLProxy->URL()->SetProtocol(mValue, rv); - break; - - case SetterUsername: - mURLProxy->URL()->SetUsername(mValue, rv); - break; - - case SetterPassword: - mURLProxy->URL()->SetPassword(mValue, rv); - break; - - case SetterHost: - mURLProxy->URL()->SetHost(mValue, rv); - break; - - case SetterHostname: - mURLProxy->URL()->SetHostname(mValue, rv); - break; - - case SetterPort: - mURLProxy->URL()->SetPort(mValue, rv); - break; - - case SetterPathname: - mURLProxy->URL()->SetPathname(mValue, rv); - break; - - case SetterSearch: - mURLProxy->URL()->SetSearch(mValue, rv); - break; - - case SetterHash: - mURLProxy->URL()->SetHash(mValue, rv); - break; - } - - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - mFailed = true; - } - - return true; - } - - bool Failed() const - { - return mFailed; - } - - void - Dispatch(ErrorResult& aRv) - { - WorkerMainThreadRunnable::Dispatch(Terminating, aRv); - } - -private: - const nsString mValue; - SetterType mType; - RefPtr mURLProxy; - bool mFailed; -}; - -already_AddRefed -FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate, - ConstructorRunnable* aRunnable, ErrorResult& aRv) -{ - aRunnable->Dispatch(Terminating, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - RefPtr proxy = aRunnable->GetURLProxy(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - RefPtr url = new URLWorker(aPrivate, proxy); - return url.forget(); -} - -/* static */ already_AddRefed -URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - URLWorker& base = static_cast(aBase); - RefPtr runnable = - new ConstructorRunnable(workerPrivate, aURL, base.GetURLProxy()); - - return FinishConstructor(cx, workerPrivate, runnable, aRv); -} - -/* static */ already_AddRefed -URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const Optional& aBase, ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - RefPtr runnable = - new ConstructorRunnable(workerPrivate, aURL, aBase); - - return FinishConstructor(cx, workerPrivate, runnable, aRv); -} - -/* static */ already_AddRefed -URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - const nsAString& aBase, ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - Optional base; - base = &aBase; - - RefPtr runnable = - new ConstructorRunnable(workerPrivate, aURL, base); - - return FinishConstructor(cx, workerPrivate, runnable, aRv); -} - -/* static */ void -URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, - nsAString& aResult, mozilla::ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - RefPtr blobImpl = aBlob.Impl(); - MOZ_ASSERT(blobImpl); - - aRv = blobImpl->SetMutable(false); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - RefPtr runnable = - new CreateURLRunnable(workerPrivate, blobImpl, aResult); - - runnable->Dispatch(Terminating, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) { - WorkerGlobalScope* scope = workerPrivate->GlobalScope(); - MOZ_ASSERT(scope); - - scope->RegisterHostObjectURI(NS_ConvertUTF16toUTF8(aResult)); - } -} - -/* static */ void -URLWorker::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl, - ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - RefPtr runnable = - new RevokeURLRunnable(workerPrivate, aUrl); - - runnable->Dispatch(Terminating, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) { - WorkerGlobalScope* scope = workerPrivate->GlobalScope(); - MOZ_ASSERT(scope); - - scope->UnregisterHostObjectURI(NS_ConvertUTF16toUTF8(aUrl)); - } -} - -/* static */ bool -URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, - ErrorResult& aRv) -{ - JSContext* cx = aGlobal.Context(); - WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); - - RefPtr runnable = - new IsValidURLRunnable(workerPrivate, aUrl); - - runnable->Dispatch(Terminating, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return false; - } - - return runnable->IsValidURL(); -} - -URLWorker::URLWorker(WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy) - : URL(nullptr) - , mWorkerPrivate(aWorkerPrivate) - , mURLProxy(aURLProxy) -{} - -URLWorker::~URLWorker() -{ - if (mURLProxy) { - mWorkerPrivate->AssertIsOnWorkerThread(); - - RefPtr runnable = - new TeardownURLRunnable(mURLProxy); - mURLProxy = nullptr; - - if (NS_FAILED(NS_DispatchToMainThread(runnable))) { - NS_ERROR("Failed to dispatch teardown runnable!"); - } - } -} - -void -URLWorker::GetHref(nsAString& aHref, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHref, aHref, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref, - mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - if (runnable->Failed()) { - aRv.ThrowTypeError(aHref); - return; - } - - UpdateURLSearchParams(); -} - -void -URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterProtocol, aProtocol, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterProtocol, - aProtocol, mURLProxy); - - runnable->Dispatch(aRv); - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetUsername(nsAString& aUsername, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterUsername, aUsername, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetUsername(const nsAString& aUsername, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterUsername, - aUsername, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetPassword(nsAString& aPassword, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPassword, aPassword, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetPassword(const nsAString& aPassword, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPassword, - aPassword, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetHost(nsAString& aHost, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHost, aHost, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetHost(const nsAString& aHost, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHost, - aHost, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetHostname(nsAString& aHostname, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHostname, aHostname, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetHostname(const nsAString& aHostname, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHostname, - aHostname, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetPort(nsAString& aPort, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPort, aPort, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetPort(const nsAString& aPort, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPort, - aPort, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetPathname(nsAString& aPathname, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPathname, - aPathname, mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetPathname(const nsAString& aPathname, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPathname, - aPathname, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::GetSearch(nsAString& aSearch, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::GetHash(nsAString& aHash, ErrorResult& aRv) const -{ - RefPtr runnable = - new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash, - mURLProxy); - - runnable->Dispatch(aRv); -} - -void -URLWorker::SetHash(const nsAString& aHash, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHash, - aHash, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) -{ - RefPtr runnable = - new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch, - aSearch, mURLProxy); - - runnable->Dispatch(aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - MOZ_ASSERT(!runnable->Failed()); -} - -void -URLWorker::UpdateURLSearchParams() -{ - if (mSearchParams) { - nsAutoString search; - - ErrorResult rv; - GetSearch(search, rv); - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - } - - mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1))); - } -} - -} // anonymous namespace - -/////////////////////////////////////////////////////////////////////////////// -// Base class for URL -/////////////////////////////////////////////////////////////////////////////// - NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URL, mParent, mSearchParams) NS_IMPL_CYCLE_COLLECTING_ADDREF(URL) @@ -1653,17 +32,6 @@ URL::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return URLBinding::Wrap(aCx, this, aGivenProto); } -/* static */ already_AddRefed -URL::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv) -{ - if (NS_IsMainThread()) { - return URLMainThread::Constructor(aGlobal, aURL, aBase, aRv); - } - - return URLWorker::Constructor(aGlobal, aURL, aBase, aRv); -} - /* static */ already_AddRefed URL::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, const Optional& aBase, ErrorResult& aRv) diff --git a/dom/url/URL.h b/dom/url/URL.h index 9080bca79471..422ffb3d827c 100644 --- a/dom/url/URL.h +++ b/dom/url/URL.h @@ -47,10 +47,6 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aURL, - URL& aBase, ErrorResult& aRv); - static already_AddRefed Constructor(const GlobalObject& aGlobal, const nsAString& aURL, const Optional& aBase, ErrorResult& aRv); diff --git a/dom/url/URLMainThread.cpp b/dom/url/URLMainThread.cpp new file mode 100644 index 000000000000..39f5bd3a6963 --- /dev/null +++ b/dom/url/URLMainThread.cpp @@ -0,0 +1,461 @@ +/* -*- 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 "URLMainThread.h" + +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Blob.h" +#include "nsContentUtils.h" +#include "nsHostObjectProtocolHandler.h" +#include "nsIURL.h" +#include "nsNetUtil.h" + +namespace mozilla { +namespace dom { + +namespace { + +template +void +CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject, + nsAString& aResult, ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + if (NS_WARN_IF(!global)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsCOMPtr principal = + nsContentUtils::ObjectPrincipal(aGlobal.Get()); + + nsAutoCString url; + aRv = nsHostObjectProtocolHandler::AddDataEntry(aObject, principal, url); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + global->RegisterHostObjectURI(url); + CopyASCIItoUTF16(url, aResult); +} + +} // anonymous namespace + +/* static */ already_AddRefed +URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv) +{ + if (aBase.WasPassed()) { + return Constructor(aGlobal.GetAsSupports(), aURL, aBase.Value(), aRv); + } + + return Constructor(aGlobal.GetAsSupports(), aURL, nullptr, aRv); +} + +/* static */ already_AddRefed +URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL, + const nsAString& aBase, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr baseUri; + nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr, + nsContentUtils::GetIOService()); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.ThrowTypeError(aBase); + return nullptr; + } + + return Constructor(aParent, aURL, baseUri, aRv); +} + +/* static */ already_AddRefed +URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL, + nsIURI* aBase, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase, + nsContentUtils::GetIOService()); + if (NS_FAILED(rv)) { + // No need to warn in this case. It's common to use the URL constructor + // to determine if a URL is valid and an exception will be propagated. + aRv.ThrowTypeError(aURL); + return nullptr; + } + + RefPtr url = new URLMainThread(aParent, uri.forget()); + return url.forget(); +} + +/* static */ void +URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, + nsAString& aResult, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + CreateObjectURLInternal(aGlobal, aBlob.Impl(), aResult, aRv); +} + +/* static */ void +URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, + DOMMediaStream& aStream, + nsAString& aResult, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + CreateObjectURLInternal(aGlobal, &aStream, aResult, aRv); +} + +/* static */ void +URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, + MediaSource& aSource, + nsAString& aResult, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr principal = + nsContentUtils::ObjectPrincipal(aGlobal.Get()); + + nsAutoCString url; + aRv = nsHostObjectProtocolHandler::AddDataEntry(&aSource, principal, url); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + nsCOMPtr revocation = NS_NewRunnableFunction( + [url] { + nsHostObjectProtocolHandler::RemoveDataEntry(url); + }); + + nsContentUtils::RunInStableState(revocation.forget()); + + CopyASCIItoUTF16(url, aResult); +} + +/* static */ void +URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal, + const nsAString& aURL, ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal.Get()); + + NS_LossyConvertUTF16toASCII asciiurl(aURL); + + nsIPrincipal* urlPrincipal = + nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl); + + if (urlPrincipal && principal->Subsumes(urlPrincipal)) { + global->UnregisterHostObjectURI(asciiurl); + nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl); + } +} + +URLMainThread::URLMainThread(nsISupports* aParent, + already_AddRefed aURI) + : URL(aParent) + , mURI(aURI) +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +URLMainThread::~URLMainThread() +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +/* static */ bool +URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, + ErrorResult& aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + NS_LossyConvertUTF16toASCII asciiurl(aURL); + return nsHostObjectProtocolHandler::HasDataEntry(asciiurl); +} + +void +URLMainThread::GetHref(nsAString& aHref, ErrorResult& aRv) const +{ + aHref.Truncate(); + + nsAutoCString href; + nsresult rv = mURI->GetSpec(href); + if (NS_SUCCEEDED(rv)) { + CopyUTF8toUTF16(href, aHref); + } +} + +void +URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv) +{ + NS_ConvertUTF16toUTF8 href(aHref); + + nsresult rv; + nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return; + } + + nsCOMPtr uri; + rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri)); + if (NS_FAILED(rv)) { + aRv.ThrowTypeError(aHref); + return; + } + + mURI = uri; + UpdateURLSearchParams(); +} + +void +URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const +{ + nsContentUtils::GetUTFOrigin(mURI, aOrigin); +} + +void +URLMainThread::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const +{ + nsAutoCString protocol; + if (NS_SUCCEEDED(mURI->GetScheme(protocol))) { + aProtocol.Truncate(); + } + + CopyASCIItoUTF16(protocol, aProtocol); + aProtocol.Append(char16_t(':')); +} + +void +URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) +{ + nsAString::const_iterator start, end; + aProtocol.BeginReading(start); + aProtocol.EndReading(end); + nsAString::const_iterator iter(start); + + FindCharInReadable(':', iter, end); + + // Changing the protocol of a URL, changes the "nature" of the URI + // implementation. In order to do this properly, we have to serialize the + // existing URL and reparse it in a new object. + nsCOMPtr clone; + nsresult rv = mURI->Clone(getter_AddRefs(clone)); + if (NS_WARN_IF(NS_FAILED(rv)) || !clone) { + return; + } + + rv = clone->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + nsAutoCString href; + rv = clone->GetSpec(href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), href); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + mURI = uri; +} + +#define URL_GETTER( value, func ) \ + value.Truncate(); \ + nsAutoCString tmp; \ + nsresult rv = mURI->func(tmp); \ + if (NS_SUCCEEDED(rv)) { \ + CopyUTF8toUTF16(tmp, value); \ + } + +void +URLMainThread::GetUsername(nsAString& aUsername, ErrorResult& aRv) const +{ + URL_GETTER(aUsername, GetUsername); +} + +void +URLMainThread::SetUsername(const nsAString& aUsername, ErrorResult& aRv) +{ + mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); +} + +void +URLMainThread::GetPassword(nsAString& aPassword, ErrorResult& aRv) const +{ + URL_GETTER(aPassword, GetPassword); +} + +void +URLMainThread::SetPassword(const nsAString& aPassword, ErrorResult& aRv) +{ + mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); +} + +void +URLMainThread::GetHost(nsAString& aHost, ErrorResult& aRv) const +{ + URL_GETTER(aHost, GetHostPort); +} + +void +URLMainThread::SetHost(const nsAString& aHost, ErrorResult& aRv) +{ + mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); +} + +void +URLMainThread::UpdateURLSearchParams() +{ + if (!mSearchParams) { + return; + } + + nsAutoCString search; + nsCOMPtr url(do_QueryInterface(mURI)); + if (url) { + nsresult rv = url->GetQuery(search); + if (NS_WARN_IF(NS_FAILED(rv))) { + search.Truncate(); + } + } + + mSearchParams->ParseInput(search); +} + +void +URLMainThread::GetHostname(nsAString& aHostname, ErrorResult& aRv) const +{ + aHostname.Truncate(); + nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname); +} + +void +URLMainThread::SetHostname(const nsAString& aHostname, ErrorResult& aRv) +{ + // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname + // The return code is silently ignored + mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname)); +} + +void +URLMainThread::GetPort(nsAString& aPort, ErrorResult& aRv) const +{ + aPort.Truncate(); + + int32_t port; + nsresult rv = mURI->GetPort(&port); + if (NS_SUCCEEDED(rv) && port != -1) { + nsAutoString portStr; + portStr.AppendInt(port, 10); + aPort.Assign(portStr); + } +} + +void +URLMainThread::SetPort(const nsAString& aPort, ErrorResult& aRv) +{ + nsresult rv; + nsAutoString portStr(aPort); + int32_t port = -1; + + // nsIURI uses -1 as default value. + if (!portStr.IsEmpty()) { + port = portStr.ToInteger(&rv); + if (NS_FAILED(rv)) { + return; + } + } + + mURI->SetPort(port); +} + +void +URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const +{ + aPathname.Truncate(); + + // Do not throw! Not having a valid URI or URL should result in an empty + // string. + + nsAutoCString file; + nsresult rv = mURI->GetFilePath(file); + if (NS_SUCCEEDED(rv)) { + CopyUTF8toUTF16(file, aPathname); + } +} + +void +URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv) +{ + // Do not throw! + + mURI->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); +} + +void +URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const +{ + aSearch.Truncate(); + + // Do not throw! Not having a valid URI or URL should result in an empty + // string. + + nsAutoCString search; + nsresult rv; + + rv = mURI->GetQuery(search); + if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { + CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); + } +} + +void +URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const +{ + aHash.Truncate(); + + nsAutoCString ref; + nsresult rv = mURI->GetRef(ref); + if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { + aHash.Assign(char16_t('#')); + AppendUTF8toUTF16(ref, aHash); + } +} + +void +URLMainThread::SetHash(const nsAString& aHash, ErrorResult& aRv) +{ + mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); +} + +void +URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) +{ + // Ignore failures to be compatible with NS4. + + mURI->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); +} + +nsIURI* +URLMainThread::GetURI() const +{ + MOZ_ASSERT(NS_IsMainThread()); + return mURI; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/url/URLMainThread.h b/dom/url/URLMainThread.h new file mode 100644 index 000000000000..ca5ef7f8fa81 --- /dev/null +++ b/dom/url/URLMainThread.h @@ -0,0 +1,130 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_URLMainThread_h +#define mozilla_dom_URLMainThread_h + +#include "URL.h" + +namespace mozilla { +namespace dom { + +// The URL implementation for the main-thread +class URLMainThread final : public URL +{ +public: + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv); + + static already_AddRefed + Constructor(nsISupports* aParent, const nsAString& aURL, + const nsAString& aBase, ErrorResult& aRv); + + static already_AddRefed + Constructor(nsISupports* aParent, const nsAString& aURL, nsIURI* aBase, + ErrorResult& aRv); + + static void + CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, + nsAString& aResult, ErrorResult& aRv); + + static void + CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream, + nsAString& aResult, ErrorResult& aRv); + + static void + CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource, + nsAString& aResult, ErrorResult& aRv); + + static void + RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL, + ErrorResult& aRv); + + static bool + IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, + ErrorResult& aRv); + + URLMainThread(nsISupports* aParent, already_AddRefed aURI); + + virtual void + GetHref(nsAString& aHref, ErrorResult& aRv) const override; + + virtual void + SetHref(const nsAString& aHref, ErrorResult& aRv) override; + + virtual void + GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; + + virtual void + GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override; + + virtual void + SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override; + + virtual void + GetUsername(nsAString& aUsername, ErrorResult& aRv) const override; + + virtual void + SetUsername(const nsAString& aUsername, ErrorResult& aRv) override; + + virtual void + GetPassword(nsAString& aPassword, ErrorResult& aRv) const override; + + virtual void + SetPassword(const nsAString& aPassword, ErrorResult& aRv) override; + + virtual void + GetHost(nsAString& aHost, ErrorResult& aRv) const override; + + virtual void + SetHost(const nsAString& aHost, ErrorResult& aRv) override; + + virtual void + GetHostname(nsAString& aHostname, ErrorResult& aRv) const override; + + virtual void + SetHostname(const nsAString& aHostname, ErrorResult& aRv) override; + + virtual void + GetPort(nsAString& aPort, ErrorResult& aRv) const override; + + virtual void + SetPort(const nsAString& aPort, ErrorResult& aRv) override; + + virtual void + GetPathname(nsAString& aPathname, ErrorResult& aRv) const override; + + virtual void + SetPathname(const nsAString& aPathname, ErrorResult& aRv) override; + + virtual void + GetSearch(nsAString& aSearch, ErrorResult& aRv) const override; + + virtual void + GetHash(nsAString& aHost, ErrorResult& aRv) const override; + + virtual void + SetHash(const nsAString& aHash, ErrorResult& aRv) override; + + virtual void UpdateURLSearchParams() override; + + virtual void + SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override; + + nsIURI* + GetURI() const; + +private: + ~URLMainThread(); + + nsCOMPtr mURI; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_URLMainThread_h diff --git a/dom/url/URLWorker.cpp b/dom/url/URLWorker.cpp new file mode 100644 index 000000000000..0fc8f86d609b --- /dev/null +++ b/dom/url/URLWorker.cpp @@ -0,0 +1,933 @@ +/* -*- 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 "URLWorker.h" + +#include "mozilla/dom/Blob.h" +#include "nsHostObjectProtocolHandler.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" +#include "WorkerScope.h" + +namespace mozilla { +namespace dom { + +using namespace workers; + +// Proxy class to forward all the requests to a URLMainThread object. +class URLWorker::URLProxy final +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy) + + explicit URLProxy(already_AddRefed aURL) + : mURL(aURL) + { + MOZ_ASSERT(NS_IsMainThread()); + } + + URLMainThread* URL() + { + MOZ_ASSERT(NS_IsMainThread()); + return mURL; + } + + nsIURI* URI() + { + MOZ_ASSERT(NS_IsMainThread()); + return mURL->GetURI(); + } + + void ReleaseURI() + { + MOZ_ASSERT(NS_IsMainThread()); + mURL = nullptr; + } + +private: + // Private destructor, to discourage deletion outside of Release(): + ~URLProxy() + { + MOZ_ASSERT(!mURL); + } + + RefPtr mURL; +}; + +// This class creates an URL from a DOM Blob on the main thread. +class CreateURLRunnable : public WorkerMainThreadRunnable +{ +private: + BlobImpl* mBlobImpl; + nsAString& mURL; + +public: + CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl, + nsAString& aURL) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: CreateURL")) + , mBlobImpl(aBlobImpl) + , mURL(aURL) + { + MOZ_ASSERT(aBlobImpl); + + DebugOnly isMutable; + MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable))); + MOZ_ASSERT(!isMutable); + } + + bool + MainThreadRun() + { + using namespace mozilla::ipc; + + AssertIsOnMainThread(); + + DebugOnly isMutable; + MOZ_ASSERT(NS_SUCCEEDED(mBlobImpl->GetMutable(&isMutable))); + MOZ_ASSERT(!isMutable); + + nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); + + nsAutoCString url; + nsresult rv = + nsHostObjectProtocolHandler::AddDataEntry(mBlobImpl, principal, url); + + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add data entry for the blob!"); + SetDOMStringToNull(mURL); + return false; + } + + if (!mWorkerPrivate->IsSharedWorker() && + !mWorkerPrivate->IsServiceWorker()) { + // Walk up to top worker object. + WorkerPrivate* wp = mWorkerPrivate; + while (WorkerPrivate* parent = wp->GetParent()) { + wp = parent; + } + + nsCOMPtr sc = wp->GetScriptContext(); + // We could not have a ScriptContext in JSM code. In this case, we leak. + if (sc) { + nsCOMPtr global = sc->GetGlobalObject(); + MOZ_ASSERT(global); + + global->RegisterHostObjectURI(url); + } + } + + mURL = NS_ConvertUTF8toUTF16(url); + return true; + } +}; + +// This class revokes an URL on the main thread. +class RevokeURLRunnable : public WorkerMainThreadRunnable +{ +private: + const nsString mURL; + +public: + RevokeURLRunnable(WorkerPrivate* aWorkerPrivate, + const nsAString& aURL) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: RevokeURL")) + , mURL(aURL) + {} + + bool + MainThreadRun() + { + AssertIsOnMainThread(); + + NS_ConvertUTF16toUTF8 url(mURL); + + nsIPrincipal* urlPrincipal = + nsHostObjectProtocolHandler::GetDataEntryPrincipal(url); + + nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); + + bool subsumes; + if (urlPrincipal && + NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) && + subsumes) { + nsHostObjectProtocolHandler::RemoveDataEntry(url); + } + + if (!mWorkerPrivate->IsSharedWorker() && + !mWorkerPrivate->IsServiceWorker()) { + // Walk up to top worker object. + WorkerPrivate* wp = mWorkerPrivate; + while (WorkerPrivate* parent = wp->GetParent()) { + wp = parent; + } + + nsCOMPtr sc = wp->GetScriptContext(); + // We could not have a ScriptContext in JSM code. In this case, we leak. + if (sc) { + nsCOMPtr global = sc->GetGlobalObject(); + MOZ_ASSERT(global); + + global->UnregisterHostObjectURI(url); + } + } + + return true; + } +}; + +// This class checks if an URL is valid on the main thread. +class IsValidURLRunnable : public WorkerMainThreadRunnable +{ +private: + const nsString mURL; + bool mValid; + +public: + IsValidURLRunnable(WorkerPrivate* aWorkerPrivate, + const nsAString& aURL) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: IsValidURL")) + , mURL(aURL) + , mValid(false) + {} + + bool + MainThreadRun() + { + AssertIsOnMainThread(); + + NS_ConvertUTF16toUTF8 url(mURL); + mValid = nsHostObjectProtocolHandler::HasDataEntry(url); + + return true; + } + + bool + IsValidURL() const + { + return mValid; + } +}; + +// This class creates a URL object on the main thread. +class ConstructorRunnable : public WorkerMainThreadRunnable +{ +private: + const nsString mURL; + + nsString mBase; // IsVoid() if we have no base URI string. + + RefPtr mRetval; + +public: + ConstructorRunnable(WorkerPrivate* aWorkerPrivate, + const nsAString& aURL, const Optional& aBase) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: Constructor")) + , mURL(aURL) + { + if (aBase.WasPassed()) { + mBase = aBase.Value(); + } else { + mBase.SetIsVoid(true); + } + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool + MainThreadRun() + { + AssertIsOnMainThread(); + + ErrorResult rv; + RefPtr url; + if (!mBase.IsVoid()) { + url = URLMainThread::Constructor(nullptr, mURL, mBase, rv); + } else { + url = URLMainThread::Constructor(nullptr, mURL, nullptr, rv); + } + + if (rv.Failed()) { + rv.SuppressException(); + return true; + } + + mRetval = new URLWorker::URLProxy(url.forget()); + return true; + } + + URLWorker::URLProxy* + GetURLProxy(ErrorResult& aRv) const + { + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (!mRetval) { + aRv.ThrowTypeError(mURL); + } + + return mRetval; + } +}; + +class TeardownURLRunnable : public Runnable +{ +public: + explicit TeardownURLRunnable(URLWorker::URLProxy* aURLProxy) + : mURLProxy(aURLProxy) + { + } + + NS_IMETHOD Run() + { + AssertIsOnMainThread(); + + mURLProxy->ReleaseURI(); + mURLProxy = nullptr; + + return NS_OK; + } + +private: + RefPtr mURLProxy; +}; + +// This class is the generic getter for any URL property. +class GetterRunnable : public WorkerMainThreadRunnable +{ +public: + enum GetterType { + GetterHref, + GetterOrigin, + GetterProtocol, + GetterUsername, + GetterPassword, + GetterHost, + GetterHostname, + GetterPort, + GetterPathname, + GetterSearch, + GetterHash, + }; + + GetterRunnable(WorkerPrivate* aWorkerPrivate, + GetterType aType, nsAString& aValue, + URLWorker::URLProxy* aURLProxy) + : WorkerMainThreadRunnable(aWorkerPrivate, + // We can have telemetry keys for each getter when + // needed. + NS_LITERAL_CSTRING("URL :: getter")) + , mValue(aValue) + , mType(aType) + , mURLProxy(aURLProxy) + { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool + MainThreadRun() + { + AssertIsOnMainThread(); + ErrorResult rv; + + switch (mType) { + case GetterHref: + mURLProxy->URL()->GetHref(mValue, rv); + break; + + case GetterOrigin: + mURLProxy->URL()->GetOrigin(mValue, rv); + break; + + case GetterProtocol: + mURLProxy->URL()->GetProtocol(mValue, rv); + break; + + case GetterUsername: + mURLProxy->URL()->GetUsername(mValue, rv); + break; + + case GetterPassword: + mURLProxy->URL()->GetPassword(mValue, rv); + break; + + case GetterHost: + mURLProxy->URL()->GetHost(mValue, rv); + break; + + case GetterHostname: + mURLProxy->URL()->GetHostname(mValue, rv); + break; + + case GetterPort: + mURLProxy->URL()->GetPort(mValue, rv); + break; + + case GetterPathname: + mURLProxy->URL()->GetPathname(mValue, rv); + break; + + case GetterSearch: + mURLProxy->URL()->GetSearch(mValue, rv); + break; + + case GetterHash: + mURLProxy->URL()->GetHash(mValue, rv); + break; + } + + MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail."); + return true; + } + + void + Dispatch(ErrorResult& aRv) + { + WorkerMainThreadRunnable::Dispatch(Terminating, aRv); + } + +private: + nsAString& mValue; + GetterType mType; + RefPtr mURLProxy; +}; + +// This class is the generic setter for any URL property. +class SetterRunnable : public WorkerMainThreadRunnable +{ +public: + enum SetterType { + SetterHref, + SetterProtocol, + SetterUsername, + SetterPassword, + SetterHost, + SetterHostname, + SetterPort, + SetterPathname, + SetterSearch, + SetterHash, + }; + + SetterRunnable(WorkerPrivate* aWorkerPrivate, + SetterType aType, const nsAString& aValue, + URLWorker::URLProxy* aURLProxy) + : WorkerMainThreadRunnable(aWorkerPrivate, + // We can have telemetry keys for each setter when + // needed. + NS_LITERAL_CSTRING("URL :: setter")) + , mValue(aValue) + , mType(aType) + , mURLProxy(aURLProxy) + , mFailed(false) + { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool + MainThreadRun() + { + AssertIsOnMainThread(); + ErrorResult rv; + + switch (mType) { + case SetterHref: { + mURLProxy->URL()->SetHref(mValue, rv); + break; + } + + case SetterProtocol: + mURLProxy->URL()->SetProtocol(mValue, rv); + break; + + case SetterUsername: + mURLProxy->URL()->SetUsername(mValue, rv); + break; + + case SetterPassword: + mURLProxy->URL()->SetPassword(mValue, rv); + break; + + case SetterHost: + mURLProxy->URL()->SetHost(mValue, rv); + break; + + case SetterHostname: + mURLProxy->URL()->SetHostname(mValue, rv); + break; + + case SetterPort: + mURLProxy->URL()->SetPort(mValue, rv); + break; + + case SetterPathname: + mURLProxy->URL()->SetPathname(mValue, rv); + break; + + case SetterSearch: + mURLProxy->URL()->SetSearch(mValue, rv); + break; + + case SetterHash: + mURLProxy->URL()->SetHash(mValue, rv); + break; + } + + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + mFailed = true; + } + + return true; + } + + bool Failed() const + { + return mFailed; + } + + void + Dispatch(ErrorResult& aRv) + { + WorkerMainThreadRunnable::Dispatch(Terminating, aRv); + } + +private: + const nsString mValue; + SetterType mType; + RefPtr mURLProxy; + bool mFailed; +}; + +already_AddRefed +FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate, + ConstructorRunnable* aRunnable, ErrorResult& aRv) +{ + aRunnable->Dispatch(Terminating, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + RefPtr proxy = aRunnable->GetURLProxy(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + RefPtr url = new URLWorker(aPrivate, proxy); + return url.forget(); +} + +/* static */ already_AddRefed +URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + RefPtr runnable = + new ConstructorRunnable(workerPrivate, aURL, aBase); + + return FinishConstructor(cx, workerPrivate, runnable, aRv); +} + +/* static */ already_AddRefed +URLWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const nsAString& aBase, ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + Optional base; + base = &aBase; + + RefPtr runnable = + new ConstructorRunnable(workerPrivate, aURL, base); + + return FinishConstructor(cx, workerPrivate, runnable, aRv); +} + +/* static */ void +URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, + nsAString& aResult, mozilla::ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + RefPtr blobImpl = aBlob.Impl(); + MOZ_ASSERT(blobImpl); + + aRv = blobImpl->SetMutable(false); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + RefPtr runnable = + new CreateURLRunnable(workerPrivate, blobImpl, aResult); + + runnable->Dispatch(Terminating, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) { + WorkerGlobalScope* scope = workerPrivate->GlobalScope(); + MOZ_ASSERT(scope); + + scope->RegisterHostObjectURI(NS_ConvertUTF16toUTF8(aResult)); + } +} + +/* static */ void +URLWorker::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl, + ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + RefPtr runnable = + new RevokeURLRunnable(workerPrivate, aUrl); + + runnable->Dispatch(Terminating, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (workerPrivate->IsSharedWorker() || workerPrivate->IsServiceWorker()) { + WorkerGlobalScope* scope = workerPrivate->GlobalScope(); + MOZ_ASSERT(scope); + + scope->UnregisterHostObjectURI(NS_ConvertUTF16toUTF8(aUrl)); + } +} + +/* static */ bool +URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, + ErrorResult& aRv) +{ + JSContext* cx = aGlobal.Context(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + + RefPtr runnable = + new IsValidURLRunnable(workerPrivate, aUrl); + + runnable->Dispatch(Terminating, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return false; + } + + return runnable->IsValidURL(); +} + +URLWorker::URLWorker(WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy) + : URL(nullptr) + , mWorkerPrivate(aWorkerPrivate) + , mURLProxy(aURLProxy) +{} + +URLWorker::~URLWorker() +{ + if (mURLProxy) { + mWorkerPrivate->AssertIsOnWorkerThread(); + + RefPtr runnable = + new TeardownURLRunnable(mURLProxy); + mURLProxy = nullptr; + + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { + NS_ERROR("Failed to dispatch teardown runnable!"); + } + } +} + +void +URLWorker::GetHref(nsAString& aHref, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHref, aHref, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref, + mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (runnable->Failed()) { + aRv.ThrowTypeError(aHref); + return; + } + + UpdateURLSearchParams(); +} + +void +URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterProtocol, aProtocol, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterProtocol, + aProtocol, mURLProxy); + + runnable->Dispatch(aRv); + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetUsername(nsAString& aUsername, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterUsername, aUsername, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetUsername(const nsAString& aUsername, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterUsername, + aUsername, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetPassword(nsAString& aPassword, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPassword, aPassword, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetPassword(const nsAString& aPassword, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPassword, + aPassword, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetHost(nsAString& aHost, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHost, aHost, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetHost(const nsAString& aHost, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHost, + aHost, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetHostname(nsAString& aHostname, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHostname, aHostname, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetHostname(const nsAString& aHostname, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHostname, + aHostname, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetPort(nsAString& aPort, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPort, aPort, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetPort(const nsAString& aPort, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPort, + aPort, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetPathname(nsAString& aPathname, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPathname, + aPathname, mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetPathname(const nsAString& aPathname, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPathname, + aPathname, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::GetSearch(nsAString& aSearch, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::GetHash(nsAString& aHash, ErrorResult& aRv) const +{ + RefPtr runnable = + new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash, + mURLProxy); + + runnable->Dispatch(aRv); +} + +void +URLWorker::SetHash(const nsAString& aHash, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHash, + aHash, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) +{ + RefPtr runnable = + new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch, + aSearch, mURLProxy); + + runnable->Dispatch(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + MOZ_ASSERT(!runnable->Failed()); +} + +void +URLWorker::UpdateURLSearchParams() +{ + if (mSearchParams) { + nsAutoString search; + + ErrorResult rv; + GetSearch(search, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } + + mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1))); + } +} + +URLWorker::URLProxy* +URLWorker::GetURLProxy() const +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + return mURLProxy; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/url/URLWorker.h b/dom/url/URLWorker.h new file mode 100644 index 000000000000..f21ca45e4876 --- /dev/null +++ b/dom/url/URLWorker.h @@ -0,0 +1,126 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_URLWorker_h +#define mozilla_dom_URLWorker_h + +#include "URL.h" +#include "URLMainThread.h" + +namespace mozilla { +namespace dom { + +namespace workers { +class WorkerPrivate; +} + +// URLWorker implements the URL object in workers. +class URLWorker final : public URL +{ +public: + class URLProxy; + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const Optional& aBase, ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aURL, + const nsAString& aBase, ErrorResult& aRv); + + static void + CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, + nsAString& aResult, mozilla::ErrorResult& aRv); + + static void + RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl, + ErrorResult& aRv); + + static bool + IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl, + ErrorResult& aRv); + + URLWorker(workers::WorkerPrivate* aWorkerPrivate, URLProxy* aURLProxy); + + virtual void + GetHref(nsAString& aHref, ErrorResult& aRv) const override; + + virtual void + SetHref(const nsAString& aHref, ErrorResult& aRv) override; + + virtual void + GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override; + + virtual void + GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override; + + virtual void + SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override; + + virtual void + GetUsername(nsAString& aUsername, ErrorResult& aRv) const override; + + virtual void + SetUsername(const nsAString& aUsername, ErrorResult& aRv) override; + + virtual void + GetPassword(nsAString& aPassword, ErrorResult& aRv) const override; + + virtual void + SetPassword(const nsAString& aPassword, ErrorResult& aRv) override; + + virtual void + GetHost(nsAString& aHost, ErrorResult& aRv) const override; + + virtual void + SetHost(const nsAString& aHost, ErrorResult& aRv) override; + + virtual void + GetHostname(nsAString& aHostname, ErrorResult& aRv) const override; + + virtual void + SetHostname(const nsAString& aHostname, ErrorResult& aRv) override; + + virtual void + GetPort(nsAString& aPort, ErrorResult& aRv) const override; + + virtual void + SetPort(const nsAString& aPort, ErrorResult& aRv) override; + + virtual void + GetPathname(nsAString& aPathname, ErrorResult& aRv) const override; + + virtual void + SetPathname(const nsAString& aPathname, ErrorResult& aRv) override; + + virtual void + GetSearch(nsAString& aSearch, ErrorResult& aRv) const override; + + virtual void + GetHash(nsAString& aHost, ErrorResult& aRv) const override; + + virtual void + SetHash(const nsAString& aHash, ErrorResult& aRv) override; + + virtual void UpdateURLSearchParams() override; + + virtual void + SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override; + + URLProxy* + GetURLProxy() const; + +private: + ~URLWorker(); + + workers::WorkerPrivate* mWorkerPrivate; + RefPtr mURLProxy; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_URLWorker_h diff --git a/dom/url/moz.build b/dom/url/moz.build index ae6541d2a54b..a7d349cc3663 100644 --- a/dom/url/moz.build +++ b/dom/url/moz.build @@ -14,7 +14,9 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'URL.cpp', + 'URLMainThread.cpp', 'URLSearchParams.cpp', + 'URLWorker.cpp', ] LOCAL_INCLUDES += [ diff --git a/dom/webidl/BrowserElement.webidl b/dom/webidl/BrowserElement.webidl index 97e82f6af73e..8a683d9466b4 100644 --- a/dom/webidl/BrowserElement.webidl +++ b/dom/webidl/BrowserElement.webidl @@ -28,26 +28,6 @@ BrowserElement implements BrowserElementPrivileged; [NoInterfaceObject] interface BrowserElementCommon { - [Throws, - Pref="dom.mozBrowserFramesEnabled", - ChromeOnly] - void setVisible(boolean visible); - - [Throws, - Pref="dom.mozBrowserFramesEnabled", - ChromeOnly] - DOMRequest getVisible(); - - [Throws, - Pref="dom.mozBrowserFramesEnabled", - ChromeOnly] - void setActive(boolean active); - - [Throws, - Pref="dom.mozBrowserFramesEnabled", - ChromeOnly] - boolean getActive(); - [Throws, Pref="dom.mozBrowserFramesEnabled", ChromeOnly] diff --git a/dom/webidl/URL.webidl b/dom/webidl/URL.webidl index bab0864dff79..de2df0656c73 100644 --- a/dom/webidl/URL.webidl +++ b/dom/webidl/URL.webidl @@ -12,9 +12,7 @@ * liability, trademark and document use rules apply. */ -// [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")] -[Constructor(DOMString url, URL base), - Constructor(DOMString url, optional DOMString base), +[Constructor(USVString url, optional USVString base), Exposed=(Window,Worker,WorkerDebugger)] interface URL { // Bug 824857: no support for stringifier attributes yet. diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index 7004b441dd6a..5e928fb873e3 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -321,6 +321,7 @@ ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, RefPtr scaledFont = new ScaledFontFontconfig(cairoScaledFont, pattern, aUnscaledFont, aSize); + cairo_scaled_font_destroy(cairoScaledFont); FcPatternDestroy(pattern); return scaledFont.forget(); diff --git a/js/xpconnect/idl/xpcIJSModuleLoader.idl b/js/xpconnect/idl/xpcIJSModuleLoader.idl index 5f66b105a188..f0f58991daed 100644 --- a/js/xpconnect/idl/xpcIJSModuleLoader.idl +++ b/js/xpconnect/idl/xpcIJSModuleLoader.idl @@ -79,4 +79,12 @@ interface xpcIJSModuleLoader : nsISupports * otherwise */ boolean isModuleLoaded(in AUTF8String aResourceURI); + + // These 2 functions are for startup testing purposes. They are not expected + // to be used for production code. + void loadedModules([optional] out unsigned long length, + [retval, array, size_is(length)] out string aModules); + + void loadedComponents([optional] out unsigned long length, + [retval, array, size_is(length)] out string aComponents); }; diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index a0837ab7c37c..5f946255fb2e 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -924,6 +924,36 @@ mozJSComponentLoader::IsModuleLoaded(const nsACString& aLocation, return NS_OK; } +NS_IMETHODIMP mozJSComponentLoader::LoadedModules(uint32_t* length, + char*** aModules) +{ + char** modules = new char*[mImports.Count()]; + *length = mImports.Count(); + *aModules = modules; + + for (auto iter = mImports.Iter(); !iter.Done(); iter.Next()) { + *modules = NS_strdup(iter.Data()->location); + modules++; + } + + return NS_OK; +} + +NS_IMETHODIMP mozJSComponentLoader::LoadedComponents(uint32_t* length, + char*** aComponents) +{ + char** comp = new char*[mModules.Count()]; + *length = mModules.Count(); + *aComponents = comp; + + for (auto iter = mModules.Iter(); !iter.Done(); iter.Next()) { + *comp = NS_strdup(iter.Data()->location); + comp++; + } + + return NS_OK; +} + static JSObject* ResolveModuleObjectPropertyById(JSContext* aCx, HandleObject aModObj, HandleId id) { diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 7c4c9f27bb84..3a9aeda0332d 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -35,6 +35,8 @@ #include "mozilla/dom/IndexedDatabaseManager.h" #include "mozilla/dom/Fetch.h" #include "mozilla/dom/FileBinding.h" +#include "mozilla/dom/MessageChannelBinding.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/PromiseBinding.h" #include "mozilla/dom/RequestBinding.h" #include "mozilla/dom/ResponseBinding.h" @@ -934,6 +936,8 @@ xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj) caches = true; } else if (!strcmp(name.ptr(), "FileReader")) { fileReader = true; + } else if (!strcmp(name.ptr(), "MessageChannel")) { + messageChannel = true; } else { JS_ReportErrorUTF8(cx, "Unknown property name: %s", name.ptr()); return false; @@ -1011,6 +1015,11 @@ xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj) if (fileReader && !dom::FileReaderBinding::GetConstructorObject(cx)) return false; + if (messageChannel && + (!dom::MessageChannelBinding::GetConstructorObject(cx) || + !dom::MessagePortBinding::GetConstructorObject(cx))) + return false; + return true; } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 6e3e2de818d5..502c07e3e8ce 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2756,6 +2756,7 @@ struct GlobalProperties { bool fetch : 1; bool caches : 1; bool fileReader: 1; + bool messageChannel: 1; private: bool Define(JSContext* cx, JS::HandleObject obj); }; diff --git a/js/xpconnect/tests/unit/test_messageChannel.js b/js/xpconnect/tests/unit/test_messageChannel.js new file mode 100644 index 000000000000..ec1487baa4bd --- /dev/null +++ b/js/xpconnect/tests/unit/test_messageChannel.js @@ -0,0 +1,30 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function*() { + let Cu = Components.utils; + let sb = new Cu.Sandbox('http://www.example.com', + { wantGlobalProperties: ["MessageChannel"] }); + sb.do_check_true = do_check_true; + Cu.evalInSandbox('do_check_true((new MessageChannel()) instanceof MessageChannel);', + sb); + Cu.evalInSandbox('do_check_true((new MessageChannel()).port1 instanceof MessagePort);', + sb); + + Cu.importGlobalProperties(["MessageChannel"]); + + let mc = new MessageChannel(); + do_check_true(mc instanceof MessageChannel); + do_check_true(mc.port1 instanceof MessagePort); + do_check_true(mc.port2 instanceof MessagePort); + + mc.port1.postMessage(42); + + let result = yield new Promise(resolve => { + mc.port2.onmessage = e => { + resolve(e.data); + } + }); + + do_check_eq(result, 42); +}); diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index 44d48defebe2..7a4101f87f2f 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -108,6 +108,7 @@ skip-if = toolkit == "android" # bug 1347431 [test_url.js] [test_URLSearchParams.js] [test_fileReader.js] +[test_messageChannel.js] [test_crypto.js] [test_css.js] [test_rtcIdentityProvider.js] diff --git a/layout/base/FrameProperties.cpp b/layout/base/FrameProperties.cpp deleted file mode 100644 index 32aa2cffae0b..000000000000 --- a/layout/base/FrameProperties.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "FrameProperties.h" - -#include "mozilla/MemoryReporting.h" -#include "mozilla/ServoStyleSet.h" -#include "nsThreadUtils.h" - -namespace mozilla { - -void -FrameProperties::SetInternal(UntypedDescriptor aProperty, void* aValue, - const nsIFrame* aFrame) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aProperty, "Null property?"); - - nsTArray::index_type index = - mProperties.IndexOf(aProperty, 0, PropertyComparator()); - if (index != nsTArray::NoIndex) { - PropertyValue* pv = &mProperties.ElementAt(index); - pv->DestroyValueFor(aFrame); - pv->mValue = aValue; - return; - } - - mProperties.AppendElement(PropertyValue(aProperty, aValue)); -#ifdef DEBUG - mMaxLength = std::max(mMaxLength, mProperties.Length()); -#endif -} - -void -FrameProperties::AddInternal(UntypedDescriptor aProperty, void* aValue) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aProperty, "Null property?"); - - mProperties.AppendElement(PropertyValue(aProperty, aValue)); -#ifdef DEBUG - mMaxLength = std::max(mMaxLength, mProperties.Length()); -#endif -} - -void* -FrameProperties::RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aProperty, "Null property?"); - - nsTArray::index_type index = - mProperties.IndexOf(aProperty, 0, PropertyComparator()); - if (index == nsTArray::NoIndex) { - if (aFoundResult) { - *aFoundResult = false; - } - return nullptr; - } - - if (aFoundResult) { - *aFoundResult = true; - } - - void* result = mProperties.ElementAt(index).mValue; - mProperties.RemoveElementAt(index); - - return result; -} - -void -FrameProperties::DeleteInternal(UntypedDescriptor aProperty, - const nsIFrame* aFrame) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aProperty, "Null property?"); - - bool found; - void* v = RemoveInternal(aProperty, &found); - if (found) { - PropertyValue pv(aProperty, v); - pv.DestroyValueFor(aFrame); - } -} - -void -FrameProperties::DeleteAll(const nsIFrame* aFrame) -{ - for (uint32_t i = 0; i < mProperties.Length(); ++i) { - mProperties.ElementAt(i).DestroyValueFor(aFrame); - } - - mProperties.Clear(); -} - -size_t -FrameProperties::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const -{ - return mProperties.Length() * sizeof(PropertyValue); -} - -} // namespace mozilla diff --git a/layout/base/FrameProperties.h b/layout/base/FrameProperties.h index 885a86852dcd..cfdb1d6561e5 100644 --- a/layout/base/FrameProperties.h +++ b/layout/base/FrameProperties.h @@ -6,10 +6,12 @@ #ifndef FRAMEPROPERTIES_H_ #define FRAMEPROPERTIES_H_ +#include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" #include "mozilla/TypeTraits.h" #include "mozilla/Unused.h" #include "nsTArray.h" +#include "nsThreadUtils.h" class nsIFrame; @@ -150,15 +152,11 @@ public: using PropertyType = typename detail::FramePropertyTypeHelper::Type; explicit FrameProperties() -#ifdef DEBUG - : mMaxLength(0) -#endif { } ~FrameProperties() { - MOZ_ASSERT(mMaxLength > 0, "redundant FrameProperties!"); MOZ_ASSERT(mProperties.Length() == 0, "forgot to delete properties"); } @@ -265,9 +263,23 @@ public: /** * Remove and destroy all property values for the frame. */ - void DeleteAll(const nsIFrame* aFrame); + void DeleteAll(const nsIFrame* aFrame) { + mozilla::DebugOnly len = mProperties.Length(); + for (auto& prop : mProperties) { + prop.DestroyValueFor(aFrame); + MOZ_ASSERT(mProperties.Length() == len); + } + mProperties.Clear(); + } - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + // We currently report only the shallow size of the mProperties array. + // As for the PropertyValue entries: we don't need to measure the mProperty + // field of because it always points to static memory, and we can't measure + // mValue because the type is opaque. + // XXX Can we do better, e.g. with a method on the descriptor? + return mProperties.ShallowSizeOfExcludingThis(aMallocSizeOf); + } private: friend class ::nsIFrame; @@ -277,17 +289,21 @@ private: FrameProperties(const FrameProperties&) = delete; FrameProperties& operator=(const FrameProperties&) = delete; - void SetInternal(UntypedDescriptor aProperty, void* aValue, - const nsIFrame* aFrame); + inline void + SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame); - void AddInternal(UntypedDescriptor aProperty, void* aValue); + inline void + AddInternal(UntypedDescriptor aProperty, void* aValue); inline void* GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const; - void* RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult); + inline void* + RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult); - void DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame); + inline void + DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame); template struct ReinterpretHelper @@ -361,20 +377,17 @@ private: } }; - AutoTArray mProperties; -#ifdef DEBUG - uint32_t mMaxLength; -#endif + nsTArray mProperties; }; + inline void* FrameProperties::GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const { MOZ_ASSERT(aProperty, "Null property?"); - nsTArray::index_type index = - mProperties.IndexOf(aProperty, 0, PropertyComparator()); + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); if (index == nsTArray::NoIndex) { if (aFoundResult) { *aFoundResult = false; @@ -388,6 +401,71 @@ FrameProperties::GetInternal(UntypedDescriptor aProperty, return mProperties.ElementAt(index).mValue; } +inline void +FrameProperties::SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray::NoIndex) { + PropertyValue* pv = &mProperties.ElementAt(index); + pv->DestroyValueFor(aFrame); + pv->mValue = aValue; + return; + } + + mProperties.AppendElement(PropertyValue(aProperty, aValue)); +} + +inline void +FrameProperties::AddInternal(UntypedDescriptor aProperty, void* aValue) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProperty, "Null property?"); + + mProperties.AppendElement(PropertyValue(aProperty, aValue)); +} + +inline void* +FrameProperties::RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; + } + + if (aFoundResult) { + *aFoundResult = true; + } + + void* result = mProperties.ElementAt(index).mValue; + mProperties.RemoveElementAt(index); + + return result; +} + +inline void +FrameProperties::DeleteInternal(UntypedDescriptor aProperty, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray::NoIndex) { + mProperties.ElementAt(index).DestroyValueFor(aFrame); + mProperties.RemoveElementAt(index); + } +} + } // namespace mozilla #endif /* FRAMEPROPERTIES_H_ */ diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 73754aef2990..e1665cdde310 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -4612,12 +4612,6 @@ PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet) RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleRemoved); } -nsPlaceholderFrame* -PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const -{ - return mFrameConstructor->GetPlaceholderFrameFor(aFrame); -} - nsresult PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags, nscolor aBackgroundColor, @@ -10957,11 +10951,12 @@ PresShell::GetRootPresShell() void PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) { mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize); *aPresShellSize += aMallocSizeOf(this); @@ -10983,6 +10978,12 @@ PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf); *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf); + + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); + if (rootFrame) { + *aFramePropertiesSize += + rootFrame->SizeOfFramePropertiesForTree(aMallocSizeOf); + } } size_t diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 3132538722c1..8cc607a2ab62 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -122,7 +122,6 @@ public: virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override; virtual nsCanvasFrame* GetCanvasFrame() const override; - virtual nsPlaceholderFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const override; virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty, nsFrameState aBitToAdd, ReflowRootHandling aRootHandling = @@ -370,11 +369,12 @@ public: virtual void LoadComplete() override; void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) override; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) override; size_t SizeOfTextRuns(mozilla::MallocSizeOf aMallocSizeOf) const; // This data is stored as a content property (nsGkAtoms::scrolling) on diff --git a/layout/base/moz.build b/layout/base/moz.build index 49824bdf9847..d40a6755d583 100644 --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -87,7 +87,6 @@ UNIFIED_SOURCES += [ 'AccessibleCaret.cpp', 'AccessibleCaretEventHub.cpp', 'AccessibleCaretManager.cpp', - 'FrameProperties.cpp', 'GeckoRestyleManager.cpp', 'GeometryUtils.cpp', 'LayoutLogging.cpp', diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 7a051e34e0ac..cc93ff4b7092 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -512,7 +512,11 @@ ReparentFrames(nsCSSFrameConstructor* aFrameConstructor, static inline bool IsFramePartOfIBSplit(nsIFrame* aFrame) { - return (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0; + bool result = (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0; + MOZ_ASSERT(!result || static_cast(do_QueryFrame(aFrame)) || + static_cast(do_QueryFrame(aFrame)), + "only block/inline frames can have NS_FRAME_PART_OF_IBSPLIT"); + return result; } static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) @@ -720,10 +724,9 @@ nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock) void nsAbsoluteItems::AddChild(nsIFrame* aChild) { - NS_ASSERTION(aChild->PresContext()->FrameManager()-> - GetPlaceholderFrameFor(aChild), - "Child without placeholder being added to nsAbsoluteItems?"); aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW); + NS_ASSERTION(aChild->GetPlaceholderFrame(), + "Child without placeholder being added to nsAbsoluteItems?"); nsFrameItems::AddChild(aChild); } @@ -3087,14 +3090,12 @@ nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell, placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow); - // The placeholder frame has a pointer back to the out-of-flow frame + // Associate the placeholder/out-of-flow with each other. placeholderFrame->SetOutOfFlowFrame(aFrame); + aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame); aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW); - // Add mapping from absolutely positioned frame to its placeholder frame - aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame); - return placeholderFrame; } @@ -6789,7 +6790,7 @@ nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent, // If the frame is out-of-flow, GetPrimaryFrame() will have returned the // out-of-flow frame; we want the placeholder. if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling); + nsIFrame* placeholderFrame = sibling->GetPlaceholderFrame(); NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame"); sibling = placeholderFrame; } @@ -8216,7 +8217,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, // the placeholder frame. if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { nsPlaceholderFrame* placeholderFrame = - GetPlaceholderFrameFor(insertion.mParentFrame); + insertion.mParentFrame->GetPlaceholderFrame(); NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?"); insertion.mParentFrame = placeholderFrame->GetParent(); } else { @@ -8727,7 +8728,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // :first-letter style applies. nsIFrame* inflowChild = childFrame; if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - inflowChild = GetPlaceholderFrameFor(childFrame); + inflowChild = childFrame->GetPlaceholderFrame(); NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?"); } nsContainerFrame* containingBlock = @@ -8783,7 +8784,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // Notify the parent frame that it should delete the frame if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - childFrame = GetPlaceholderFrameFor(childFrame); + childFrame = childFrame->GetPlaceholderFrame(); NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow."); parentFrame = childFrame->GetParent(); } @@ -9425,7 +9426,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame) // are within fixed frames, because that would cause duplicates on the new // page - bug 389619) for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) { - nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed); + nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame(); if (prevPlaceholder && nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) { // We want to use the same style as the primary style frame for @@ -9691,7 +9692,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, // Now check for possibly needing to reconstruct due to a pseudo parent nsIFrame* inFlowFrame = (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ? - GetPlaceholderFrameFor(aFrame) : aFrame; + aFrame->GetPlaceholderFrame() : aFrame; MOZ_ASSERT(inFlowFrame, "How did that happen?"); MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(), "placeholder for primary frame has previous continuations?"); @@ -11890,7 +11891,7 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( } // Discover the placeholder frame for the letter frame - nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame); + nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame(); if (!placeholderFrame) { // Somethings really wrong return; diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index a93c4f34403b..1ba9d93ba10d 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -46,34 +46,9 @@ using namespace mozilla::dom; //---------------------------------------------------------------------- -struct PlaceholderMapEntry : public PLDHashEntryHdr { - // key (the out of flow frame) can be obtained through placeholder frame - nsPlaceholderFrame *placeholderFrame; -}; - -static bool -PlaceholderMapMatchEntry(const PLDHashEntryHdr *hdr, const void *key) -{ - const PlaceholderMapEntry *entry = - static_cast(hdr); - NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() != - (void*)0xdddddddd, - "Dead placeholder in placeholder map"); - return entry->placeholderFrame->GetOutOfFlowFrame() == key; -} - -static const PLDHashTableOps PlaceholderMapOps = { - PLDHashTable::HashVoidPtrKeyStub, - PlaceholderMapMatchEntry, - PLDHashTable::MoveEntryStub, - PLDHashTable::ClearEntryStub, - nullptr -}; - nsFrameManagerBase::nsFrameManagerBase() : mPresShell(nullptr) , mRootFrame(nullptr) - , mPlaceholderMap(&PlaceholderMapOps, sizeof(PlaceholderMapEntry)) , mUndisplayedMap(nullptr) , mDisplayContentsMap(nullptr) , mIsDestroyingFrames(false) @@ -142,9 +117,6 @@ nsFrameManager::Destroy() // Destroy the frame hierarchy. mPresShell->SetIgnoreFrameDestruction(true); - // Unregister all placeholders before tearing down the frame tree - nsFrameManager::ClearPlaceholderFrameMap(); - if (mRootFrame) { mRootFrame->Destroy(); mRootFrame = nullptr; @@ -160,55 +132,6 @@ nsFrameManager::Destroy() //---------------------------------------------------------------------- -// Placeholder frame functions -nsPlaceholderFrame* -nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame) -{ - NS_PRECONDITION(aFrame, "null param unexpected"); - - auto entry = static_cast - (const_cast(&mPlaceholderMap)->Search(aFrame)); - if (entry) { - return entry->placeholderFrame; - } - - return nullptr; -} - -void -nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame) -{ - MOZ_ASSERT(aPlaceholderFrame, "null param unexpected"); - MOZ_ASSERT(aPlaceholderFrame->IsPlaceholderFrame(), "unexpected frame type"); - auto entry = static_cast - (mPlaceholderMap.Add(aPlaceholderFrame->GetOutOfFlowFrame())); - MOZ_ASSERT(!entry->placeholderFrame, - "Registering a placeholder for a frame that already has a placeholder!"); - entry->placeholderFrame = aPlaceholderFrame; -} - -void -nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame) -{ - NS_PRECONDITION(aPlaceholderFrame, "null param unexpected"); - NS_PRECONDITION(aPlaceholderFrame->IsPlaceholderFrame(), - "unexpected frame type"); - - mPlaceholderMap.Remove(aPlaceholderFrame->GetOutOfFlowFrame()); -} - -void -nsFrameManager::ClearPlaceholderFrameMap() -{ - for (auto iter = mPlaceholderMap.Iter(); !iter.Done(); iter.Next()) { - auto entry = static_cast(iter.Get()); - entry->placeholderFrame->SetOutOfFlowFrame(nullptr); - } - mPlaceholderMap.Clear(); -} - -//---------------------------------------------------------------------- - static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent) { @@ -516,7 +439,7 @@ nsFrameManager::RemoveFrame(ChildListID aListID, aOldFrame->IsTextFrame(), "Must remove first continuation."); NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW && - GetPlaceholderFrameFor(aOldFrame)), + aOldFrame->GetPlaceholderFrame()), "Must call RemoveFrame on placeholder for out-of-flows."); nsContainerFrame* parentFrame = aOldFrame->GetParent(); if (parentFrame->IsAbsoluteContainer() && diff --git a/layout/base/nsFrameManager.h b/layout/base/nsFrameManager.h index 0d9184734640..5d7a2d1ed567 100644 --- a/layout/base/nsFrameManager.h +++ b/layout/base/nsFrameManager.h @@ -51,9 +51,7 @@ struct UndisplayedNode : public LinkedListElement } // namespace mozilla /** - * Frame manager interface. The frame manager serves two purposes: - * provides a service for mapping from content to frame and from - * out-of-flow frame to placeholder frame. + * Frame manager interface. The frame manager serves one purpose: * handles structural modifications to the frame model. If the frame model * lock can be acquired, then the changes are processed immediately; otherwise, * they're queued and processed later. @@ -80,13 +78,6 @@ public: */ void Destroy(); - // Placeholder frame functions - nsPlaceholderFrame* GetPlaceholderFrameFor(const nsIFrame* aFrame); - void RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame); - void UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame); - - void ClearPlaceholderFrameMap(); - // Mapping undisplayed content nsStyleContext* GetUndisplayedContent(const nsIContent* aContent) { diff --git a/layout/base/nsFrameManagerBase.h b/layout/base/nsFrameManagerBase.h index c65d29f656c8..566df3b38a56 100644 --- a/layout/base/nsFrameManagerBase.h +++ b/layout/base/nsFrameManagerBase.h @@ -51,7 +51,6 @@ protected: // weak link, because the pres shell owns us nsIPresShell* MOZ_NON_OWNING_REF mPresShell; nsIFrame* mRootFrame; - PLDHashTable mPlaceholderMap; UndisplayedMap* mUndisplayedMap; UndisplayedMap* mDisplayContentsMap; bool mIsDestroyingFrames; // The frame manager is destroying some frame(s). diff --git a/layout/base/nsFrameTraversal.cpp b/layout/base/nsFrameTraversal.cpp index 9e5d457d947d..16e25d72e046 100644 --- a/layout/base/nsFrameTraversal.cpp +++ b/layout/base/nsFrameTraversal.cpp @@ -82,6 +82,10 @@ protected: virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame); virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame); + /** + * Return the placeholder frame for aFrame if it has one, otherwise return + * aFrame itself. + */ nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame); bool IsPopupFrame(nsIFrame* aFrame); @@ -484,18 +488,11 @@ nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) { nsIFrame* nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame) { - nsIFrame* result = aFrame; - nsIPresShell *presShell = mPresContext->GetPresShell(); - if (presShell) { - nsIFrame* placeholder = presShell->GetPlaceholderFrameFor(aFrame); - if (placeholder) - result = placeholder; + if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) { + return aFrame; } - - if (result != aFrame) - result = GetPlaceholderFrame(result); - - return result; + nsIFrame* placeholder = aFrame->GetPlaceholderFrame(); + return placeholder ? placeholder : aFrame; } bool diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 8ae778f623fd..7337b37434f8 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -77,7 +77,6 @@ template class nsCOMArray; class AutoWeakFrame; class WeakFrame; class nsIScrollableFrame; -class nsPlaceholderFrame; class gfxContext; class nsIDOMEvent; class nsDisplayList; @@ -452,12 +451,6 @@ public: */ virtual nsCanvasFrame* GetCanvasFrame() const = 0; - /** - * Gets the placeholder frame associated with the specified frame. This is - * a helper frame that forwards the request to the frame manager. - */ - virtual nsPlaceholderFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const = 0; - /** * Tell the pres shell that a frame needs to be marked dirty and needs * Reflow. It's OK if this is an ancestor of the frame needing reflow as @@ -1590,11 +1583,12 @@ public: bool aFlushOnHoverChange) = 0; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) = 0; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) = 0; /** * Methods that retrieve the cached font inflation preferences. diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 181dded63566..e3f208db0e50 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4497,8 +4497,7 @@ nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame) { if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && !aFrame->GetPrevInFlow()) { - return aFrame->PresContext()->PresShell()->FrameManager()-> - GetPlaceholderFrameFor(aFrame); + return aFrame->GetProperty(nsIFrame::PlaceholderFrameProperty()); } return aFrame->GetParent(); } diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index 148013bd9ca7..76dc3d17c91c 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -1613,8 +1613,7 @@ ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext, // have been if it had been in the flow nsHypotheticalPosition hypotheticalPos; if ((iStartIsAuto && iEndIsAuto) || (bStartIsAuto && bEndIsAuto)) { - nsPlaceholderFrame* placeholderFrame = - aPresContext->PresShell()->GetPlaceholderFrameFor(mFrame); + nsPlaceholderFrame* placeholderFrame = mFrame->GetPlaceholderFrame(); MOZ_ASSERT(placeholderFrame, "no placeholder frame"); if (placeholderFrame->HasAnyStateBits( diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp index 38a7ff3bf884..df5dcfb668f6 100644 --- a/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/layout/generic/nsAbsoluteContainingBlock.cpp @@ -379,25 +379,13 @@ nsAbsoluteContainingBlock::DoMarkFramesDirty(bool aMarkAllDirty) } } -// Given an out-of-flow frame, this method returns the parent frame of -// its placeholder frame, if that parent is a nsContainerFrame. +// Given an out-of-flow frame, this method returns the parent frame of its +// placeholder frame or null if it doesn't have a placeholder for some reason. static nsContainerFrame* -GetPlaceholderContainer(nsPresContext* aPresContext, - nsIFrame* aPositionedFrame) +GetPlaceholderContainer(nsIFrame* aPositionedFrame) { - MOZ_ASSERT(aPositionedFrame, "need non-null frame"); - MOZ_ASSERT(aPositionedFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW), - "expecting abspos frame"); - MOZ_ASSERT(aPresContext && aPresContext == aPositionedFrame->PresContext(), - "need non-null pres context which matches our frame"); - - nsIFrame* placeholder = - aPresContext->PresShell()->GetPlaceholderFrameFor(aPositionedFrame); - - if (!placeholder) { - return nullptr; - } - return do_QueryFrame(placeholder->GetParent()); + nsIFrame* placeholder = aPositionedFrame->GetPlaceholderFrame(); + return placeholder ? placeholder->GetParent() : nullptr; } /** @@ -585,8 +573,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets( aOffsets->IEnd(outerWM) - aMargin.IStartEnd(outerWM) - aKidSize.ISize(outerWM); } else if (aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign) { - placeholderContainer = GetPlaceholderContainer(aPresContext, - aKidReflowInput.mFrame); + placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame); nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize, logicalCBSizeOuterWM, placeholderContainer, @@ -607,8 +594,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets( aKidSize.BSize(outerWM); } else if (aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) { if (!placeholderContainer) { - placeholderContainer = GetPlaceholderContainer(aPresContext, - aKidReflowInput.mFrame); + placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame); } nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize, logicalCBSizeOuterWM, @@ -683,8 +669,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat // due to the multiple coordinate spaces in play, we use a convenience flag // to simply have the child's ReflowInput give it a static position at its // abs.pos. CB origin, and then we'll align & offset it from there. - nsIFrame* placeholder = - aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame); + nsIFrame* placeholder = aKidFrame->GetPlaceholderFrame(); if (placeholder && placeholder->GetParent() == aDelegatingFrame) { rsFlags |= ReflowInput::STATIC_POS_IS_CB_ORIGIN; } diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index ab80c2af97c7..5605cf3bcb36 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -4413,8 +4413,7 @@ CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC) "float in a line should never be a continuation"); NS_ASSERTION(!(aFC->mFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), "float in a line should never be a pushed float"); - nsIFrame* ph = aBlock->PresContext()->FrameManager()-> - GetPlaceholderFrameFor(aFC->mFloat->FirstInFlow()); + nsIFrame* ph = aFC->mFloat->FirstInFlow()->GetPlaceholderFrame(); for (nsIFrame* f = ph; f; f = f->GetParent()) { if (f->GetParent() == aBlock) return aLine->Contains(f); @@ -5016,9 +5015,8 @@ nsBlockFrame::DrainSelfPushedFloats() if (f->GetPrevContinuation()) { // FIXME } else { - nsPlaceholderFrame *placeholder = - presContext->FrameManager()->GetPlaceholderFrameFor(f); - nsIFrame *floatOriginalParent = presContext->PresShell()-> + nsPlaceholderFrame* placeholder = f->GetPlaceholderFrame(); + nsIFrame* floatOriginalParent = presContext->PresShell()-> FrameConstructor()->GetFloatContainingBlock(placeholder); if (floatOriginalParent != this) { // This is a first continuation that was pushed from one of our @@ -5641,7 +5639,7 @@ FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame) return nullptr; if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) break; - aFindFrame = aFrame->PresContext()->FrameManager()->GetPlaceholderFrameFor(child); + aFindFrame = child->GetPlaceholderFrame(); } return child; @@ -6931,9 +6929,8 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild) AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES); } else { NS_ASSERTION(aChild->IsFloating(), "should be a float"); - nsIFrame *thisFC = FirstContinuation(); - nsIFrame *placeholderPath = - PresContext()->FrameManager()->GetPlaceholderFrameFor(aChild); + nsIFrame* thisFC = FirstContinuation(); + nsIFrame* placeholderPath = aChild->GetPlaceholderFrame(); // SVG code sometimes sends FrameNeedsReflow notifications during // frame destruction, leading to null placeholders, but we're safe // ignoring those. diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 3e0505627150..bc5f4f3a0836 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -222,6 +222,32 @@ nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot) // Destroy frames on the principal child list. mFrames.DestroyFramesFrom(aDestructRoot); + // If we have any IB split siblings, clear their references to us. + if (HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) { + // Delete previous sibling's reference to me. + nsIFrame* prevSib = GetProperty(nsIFrame::IBSplitPrevSibling()); + if (prevSib) { + NS_WARNING_ASSERTION( + this == prevSib->GetProperty(nsIFrame::IBSplitSibling()), + "IB sibling chain is inconsistent"); + prevSib->DeleteProperty(nsIFrame::IBSplitSibling()); + } + + // Delete next sibling's reference to me. + nsIFrame* nextSib = GetProperty(nsIFrame::IBSplitSibling()); + if (nextSib) { + NS_WARNING_ASSERTION( + this == nextSib->GetProperty(nsIFrame::IBSplitPrevSibling()), + "IB sibling chain is inconsistent"); + nextSib->DeleteProperty(nsIFrame::IBSplitPrevSibling()); + } + +#ifdef DEBUG + // This is just so we can assert it's not set in nsFrame::DestroyFrom. + RemoveStateBits(NS_FRAME_PART_OF_IBSPLIT); +#endif + } + // Destroy frames on the auxiliary frame lists and delete the lists. nsPresContext* pc = PresContext(); nsIPresShell* shell = pc->PresShell(); diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp index 1fd2e5d10ff9..58d02b016c3c 100644 --- a/layout/generic/nsFirstLetterFrame.cpp +++ b/layout/generic/nsFirstLetterFrame.cpp @@ -315,8 +315,7 @@ nsFirstLetterFrame::CreateContinuationForFloatingParent(nsPresContext* aPresCont *aContinuation = nullptr; nsIPresShell* presShell = aPresContext->PresShell(); - nsPlaceholderFrame* placeholderFrame = - presShell->FrameManager()->GetPlaceholderFrameFor(this); + nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrame(); nsContainerFrame* parent = placeholderFrame->GetParent(); nsIFrame* continuation = presShell->FrameConstructor()-> diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 1cdebeb04875..17e8199cb512 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -712,6 +712,8 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) "Frames should be removed before destruction."); NS_ASSERTION(aDestructRoot, "Must specify destruct root"); MOZ_ASSERT(!HasAbsolutelyPositionedChildren()); + MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT), + "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?"); nsSVGEffects::InvalidateDirectRenderingObservers(this); @@ -726,8 +728,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) nsPresContext* presContext = PresContext(); nsIPresShell* shell = presContext->GetPresShell(); if (mState & NS_FRAME_OUT_OF_FLOW) { - nsPlaceholderFrame* placeholder = - shell->FrameManager()->GetPlaceholderFrameFor(this); + nsPlaceholderFrame* placeholder = GetPlaceholderFrame(); NS_ASSERTION(!placeholder || (aDestructRoot != this), "Don't call Destroy() on OOFs, call Destroy() on the placeholder."); NS_ASSERTION(!placeholder || @@ -735,33 +736,10 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) "Placeholder relationship should have been torn down already; " "this might mean we have a stray placeholder in the tree."); if (placeholder) { - shell->FrameManager()->UnregisterPlaceholderFrame(placeholder); placeholder->SetOutOfFlowFrame(nullptr); } } - // If we have any IB split siblings, clear their references to us. - // (Note: This has to happen before we clear our Properties() table.) - if (mState & NS_FRAME_PART_OF_IBSPLIT) { - // Delete previous sibling's reference to me. - nsIFrame* prevSib = GetProperty(nsIFrame::IBSplitPrevSibling()); - if (prevSib) { - NS_WARNING_ASSERTION( - this == prevSib->GetProperty(nsIFrame::IBSplitSibling()), - "IB sibling chain is inconsistent"); - prevSib->DeleteProperty(nsIFrame::IBSplitSibling()); - } - - // Delete next sibling's reference to me. - nsIFrame* nextSib = GetProperty(nsIFrame::IBSplitSibling()); - if (nextSib) { - NS_WARNING_ASSERTION( - this == nextSib->GetProperty(nsIFrame::IBSplitPrevSibling()), - "IB sibling chain is inconsistent"); - nextSib->DeleteProperty(nsIFrame::IBSplitPrevSibling()); - } - } - bool isPrimaryFrame = (mContent && mContent->GetPrimaryFrame() == this); if (isPrimaryFrame) { // This needs to happen before we clear our Properties() table. @@ -8472,9 +8450,8 @@ int32_t nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock) { NS_ASSERTION(aFrame, "null aFrame"); - nsFrameManager* frameManager = aFrame->PresContext()->FrameManager(); - nsIFrame *blockFrame = aFrame; - nsIFrame *thisBlock; + nsIFrame* blockFrame = aFrame; + nsIFrame* thisBlock; nsAutoLineIterator it; nsresult result = NS_ERROR_FAILURE; while (NS_FAILED(result) && blockFrame) @@ -8487,7 +8464,7 @@ nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainin // abspos continuations don't have placeholders, get the fif thisBlock = thisBlock->FirstInFlow(); } - thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock); + thisBlock = thisBlock->GetPlaceholderFrame(); if (!thisBlock) return -1; } @@ -9432,7 +9409,6 @@ nsStyleContext* nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const { *aProviderFrame = nullptr; - nsFrameManager* fm = PresContext()->FrameManager(); // Handle display:contents and the root frame, when there's no parent frame // to inherit from. @@ -9449,6 +9425,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const /* if next is true then it's really a request for the table frame's parent context, see nsTable[Outer]Frame::GetParentStyleContext. */ pseudo == nsCSSAnonBoxes::tableWrapper) { + nsFrameManager* fm = PresContext()->FrameManager(); nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent); if (MOZ_UNLIKELY(sc)) { return sc; @@ -9485,7 +9462,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const // We're an out-of-flow frame. For out-of-flow frames, we must // resolve underneath the placeholder's parent. The placeholder is // reached from the first-in-flow. - nsPlaceholderFrame* placeholder = fm->GetPlaceholderFrameFor(FirstInFlow()); + nsPlaceholderFrame* placeholder = FirstInFlow()->GetPlaceholderFrame(); if (!placeholder) { NS_NOTREACHED("no placeholder frame for out-of-flow frame"); *aProviderFrame = GetCorrectedParent(this); @@ -10552,6 +10529,24 @@ nsFrame::HasCSSTransitions() return collection && collection->mAnimations.Length() > 0; } +size_t +nsIFrame::SizeOfFramePropertiesForTree(MallocSizeOf aMallocSizeOf) const +{ + size_t result = 0; + + result += mProperties.SizeOfExcludingThis(aMallocSizeOf); + + FrameChildListIterator iter(this); + while (!iter.IsDone()) { + for (const nsIFrame* f : iter.CurrentList()) { + result += f->SizeOfFramePropertiesForTree(aMallocSizeOf); + } + iter.Next(); + } + + return result; +} + // Box layout debugging #ifdef DEBUG_REFLOW int32_t gIndent2 = 0; diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index 974cfd362019..e432755c5e4e 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -140,7 +140,7 @@ FRAME_STATE_BIT(Generic, 14, NS_FRAME_INDEPENDENT_SELECTION) // If this bit is set, the frame is part of the mangled frame hierarchy // that results when an inline has been split because of a nested block. // See the comments in nsCSSFrameConstructor::ConstructInline for -// more details. +// more details. (this is only set on nsBlockFrame/nsInlineFrame frames) FRAME_STATE_BIT(Generic, 15, NS_FRAME_PART_OF_IBSPLIT) // If this bit is set, then transforms (e.g. CSS or SVG transforms) are allowed diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 5326cc7e21cc..f3ad41a90ddd 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -83,6 +83,7 @@ class nsLineList_iterator; class nsAbsoluteContainingBlock; class nsIContent; class nsContainerFrame; +class nsPlaceholderFrame; class nsStyleChangeList; struct nsPeekOffsetStruct; @@ -835,6 +836,16 @@ public: */ inline nsContainerFrame* GetInFlowParent(); + /** + * Return the placeholder for this frame (which must be out-of-flow). + * @note this will only return non-null if |this| is the first-in-flow + * although we don't assert that here for legacy reasons. + */ + inline nsPlaceholderFrame* GetPlaceholderFrame() const { + MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)); + return GetProperty(PlaceholderFrameProperty()); + } + /** * Set this frame's parent to aParent. * If the frame may have moved into or out of a scrollframe's @@ -1186,6 +1197,8 @@ public: NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData) + NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame) + mozilla::FrameBidiData GetBidiData() const { bool exists; @@ -3391,22 +3404,13 @@ public: GetProperty(FrameProperties::Descriptor aProperty, bool* aFoundResult = nullptr) const { - if (mProperties) { - return mProperties->Get(aProperty, aFoundResult); - } - if (aFoundResult) { - *aFoundResult = false; - } - return FrameProperties::ReinterpretHelper::FromPointer(nullptr); + return mProperties.Get(aProperty, aFoundResult); } template bool HasProperty(FrameProperties::Descriptor aProperty) const { - if (mProperties) { - return mProperties->Has(aProperty); - } - return false; + return mProperties.Has(aProperty); } // Add a property, or update an existing property for the given descriptor. @@ -3414,10 +3418,7 @@ public: void SetProperty(FrameProperties::Descriptor aProperty, FrameProperties::PropertyType aValue) { - if (!mProperties) { - mProperties = mozilla::MakeUnique(); - } - mProperties->Set(aProperty, aValue, this); + mProperties.Set(aProperty, aValue, this); } // Unconditionally add a property; use ONLY if the descriptor is known @@ -3426,10 +3427,7 @@ public: void AddProperty(FrameProperties::Descriptor aProperty, FrameProperties::PropertyType aValue) { - if (!mProperties) { - mProperties = mozilla::MakeUnique(); - } - mProperties->Add(aProperty, aValue); + mProperties.Add(aProperty, aValue); } template @@ -3437,30 +3435,23 @@ public: RemoveProperty(FrameProperties::Descriptor aProperty, bool* aFoundResult = nullptr) { - if (mProperties) { - return mProperties->Remove(aProperty, aFoundResult); - } - if (aFoundResult) { - *aFoundResult = false; - } - return FrameProperties::ReinterpretHelper::FromPointer(nullptr); + return mProperties.Remove(aProperty, aFoundResult); } template void DeleteProperty(FrameProperties::Descriptor aProperty) { - if (mProperties) { - mProperties->Delete(aProperty, this); - } + mProperties.Delete(aProperty, this); } void DeleteAllProperties() { - if (mProperties) { - mProperties->DeleteAll(this); - } + mProperties.DeleteAll(this); } + // Reports size of the FrameProperties for this frame and its descendants + size_t SizeOfFramePropertiesForTree(mozilla::MallocSizeOf aMallocSizeOf) const; + /** * Return true if and only if this frame obeys visibility:hidden. * if it does not, then nsContainerFrame will hide its view even though @@ -3962,10 +3953,9 @@ protected: nsFrameState mState; /** - * List of properties attached to the frame, or null if no properties have - * been set. + * List of properties attached to the frame. */ - mozilla::UniquePtr mProperties; + FrameProperties mProperties; // When there is an overflow area only slightly larger than mRect, // we store a set of four 1-byte deltas from the edges of mRect diff --git a/layout/generic/nsIFrameInlines.h b/layout/generic/nsIFrameInlines.h index 7f3d99797642..4bfcbf07e653 100644 --- a/layout/generic/nsIFrameInlines.h +++ b/layout/generic/nsIFrameInlines.h @@ -173,8 +173,8 @@ nsContainerFrame* nsIFrame::GetInFlowParent() { if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - nsFrameManager* fm = PresContext()->FrameManager(); - return fm->GetPlaceholderFrameFor(FirstContinuation())->GetParent(); + nsIFrame* ph = FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty()); + return ph->GetParent(); } return GetParent(); diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index db4e812c9e8b..bae46d7219b2 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -160,16 +160,15 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot) { nsIFrame* oof = mOutOfFlowFrame; if (oof) { - // Unregister out-of-flow frame - nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager(); - fm->UnregisterPlaceholderFrame(this); mOutOfFlowFrame = nullptr; + oof->DeleteProperty(nsIFrame::PlaceholderFrameProperty()); // If aDestructRoot is not an ancestor of the out-of-flow frame, // then call RemoveFrame on it here. // Also destroy it here if it's a popup frame. (Bug 96291) if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) || !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) { ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof); + nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager(); fm->RemoveFrame(listId, oof); } // else oof will be destroyed by its parent diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 4d0371bb06ef..1dbc6c5c2692 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -1386,8 +1386,7 @@ BuildTextRuns(DrawTarget* aDrawTarget, nsTextFrame* aForFrame, nsIFrame* lineContainerChild = aForFrame; if (!aLineContainer) { if (aForFrame->IsFloatingFirstLetterChild()) { - lineContainerChild = aForFrame->PresContext()->PresShell()-> - GetPlaceholderFrameFor(aForFrame->GetParent()); + lineContainerChild = aForFrame->GetParent()->GetPlaceholderFrame(); } aLineContainer = FindLineContainer(lineContainerChild); } else { diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index 64c8803b740b..4fdf48ae8d28 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -1418,7 +1418,7 @@ public abstract class GeckoApp extends GeckoActivity "ToggleChrome:Show", null); - Tabs.getInstance().attachToContext(this, mLayerView); + Tabs.getInstance().attachToContext(this, mLayerView, getAppEventDispatcher()); Tabs.registerOnTabsChangedListener(this); // Use global layout state change to kick off additional initialization @@ -1512,7 +1512,7 @@ public abstract class GeckoApp extends GeckoActivity // If we are doing a restore, send the parsed session data to Gecko. if (!mIsRestoringActivity) { - EventDispatcher.getInstance().dispatch("Session:Restore", restoreMessage); + getAppEventDispatcher().dispatch("Session:Restore", restoreMessage); } // Make sure sessionstore.old is either updated or deleted as necessary. @@ -2489,6 +2489,7 @@ public abstract class GeckoApp extends GeckoActivity super.onDestroy(); Tabs.unregisterOnTabsChangedListener(this); + Tabs.getInstance().detachFromContext(); if (mShutdownOnDestroy) { GeckoApplication.shutdown(!mRestartOnShutdown ? null : new Intent( diff --git a/mobile/android/base/java/org/mozilla/gecko/GlobalHistory.java b/mobile/android/base/java/org/mozilla/gecko/GlobalHistory.java index fc1a21299b36..97f8f892cb1a 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GlobalHistory.java +++ b/mobile/android/base/java/org/mozilla/gecko/GlobalHistory.java @@ -182,7 +182,7 @@ class GlobalHistory { /* protected */ void checkVisited(final String uri) { final String storedURI = ReaderModeUtils.stripAboutReaderUrl(uri); - final NotifierRunnable runnable = new NotifierRunnable(GeckoAppShell.getContext()); + final NotifierRunnable runnable = new NotifierRunnable(GeckoAppShell.getApplicationContext()); mHandler.post(new Runnable() { @Override public void run() { diff --git a/mobile/android/base/java/org/mozilla/gecko/Tabs.java b/mobile/android/base/java/org/mozilla/gecko/Tabs.java index 98a411d0e4e9..2dfa2f5b83dd 100644 --- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java +++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java @@ -101,6 +101,7 @@ public class Tabs implements BundleEventListener { private volatile boolean mInitialTabsAdded; private Context mAppContext; + private EventDispatcher mEventDispatcher; private LayerView mLayerView; private ContentObserver mBookmarksContentObserver; private PersistTabsRunnable mPersistTabsRunnable; @@ -165,18 +166,11 @@ public class Tabs implements BundleEventListener { mPrivateClearColor = Color.RED; } - public synchronized void attachToContext(Context context, LayerView layerView) { + public synchronized void attachToContext(Context context, LayerView layerView, EventDispatcher eventDispatcher) { final Context appContext = context.getApplicationContext(); - if (mAppContext == appContext) { - return; - } - - if (mAppContext != null) { - // This should never happen. - Log.w(LOGTAG, "The application context has changed!"); - } mAppContext = appContext; + mEventDispatcher = eventDispatcher; mLayerView = layerView; mPrivateClearColor = ContextCompat.getColor(context, R.color.tabs_tray_grey_pressed); mAccountManager = AccountManager.get(appContext); @@ -198,6 +192,10 @@ public class Tabs implements BundleEventListener { } } + public void detachFromContext() { + mLayerView = null; + } + /** * Gets the tab count corresponding to the category and private state of the * selected tab. @@ -332,6 +330,7 @@ public class Tabs implements BundleEventListener { // Pass a message to Gecko to update tab state in BrowserApp. final GeckoBundle data = new GeckoBundle(1); data.putInt("id", tab.getId()); + mEventDispatcher.dispatch("Tab:Selected", data); EventDispatcher.getInstance().dispatch("Tab:Selected", data); return tab; } @@ -473,7 +472,7 @@ public class Tabs implements BundleEventListener { final GeckoBundle data = new GeckoBundle(2); data.putInt("tabId", tabId); data.putBoolean("showUndoToast", showUndoToast); - EventDispatcher.getInstance().dispatch("Tab:Closed", data); + mEventDispatcher.dispatch("Tab:Closed", data); } /** Return the tab that will be selected by default after this one is closed */ @@ -1083,7 +1082,7 @@ public class Tabs implements BundleEventListener { } } - EventDispatcher.getInstance().dispatch("Tab:Load", data); + mEventDispatcher.dispatch("Tab:Load", data); if (tabToSelect == null) { return null; @@ -1277,7 +1276,7 @@ public class Tabs implements BundleEventListener { data.putInt("fromPosition", fromPosition); data.putInt("toTabId", toTabId); data.putInt("toPosition", toPosition); - EventDispatcher.getInstance().dispatch("Tab:Move", data); + mEventDispatcher.dispatch("Tab:Move", data); } /** diff --git a/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java b/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java index 4ba49e96373f..e76b4c7d7f02 100644 --- a/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java +++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java @@ -30,6 +30,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import org.mozilla.gecko.GeckoView; import org.mozilla.gecko.R; import org.mozilla.gecko.SiteIdentity; import org.mozilla.gecko.Tab; @@ -108,25 +109,24 @@ public class ActionBarPresenter { * @param url Url String to display */ public void displayUrlOnly(@NonNull final String url) { - updateCustomView(null, null, url); + updateCustomView(null, url, GeckoView.ProgressListener.STATE_IS_INSECURE); } /** - * Update appearance of CustomView of ActionBar. + * Update appearance of CustomView of ActionBar * - * @param tab a Tab instance of current web page to provide information to render ActionBar. + * @param title Title for current website. Could be null if don't want to show title. + * @param url URL for current website. At least Custom will show this url. + * @param securityStatus Security status, possible values given in GeckoView.ProgressListener */ - public void update(@NonNull final Tab tab) { - final String title = tab.getTitle(); - final String url = tab.getBaseDomain(); - + public void update(final String title, final String url, final int securityStatus) { // Do not update CustomView immediately. If this method be invoked rapidly several times, // only apply last one. mHandler.removeCallbacks(mUpdateAction); mUpdateAction = new Runnable() { @Override public void run() { - updateCustomView(tab.getSiteIdentity(), title, url); + updateCustomView(title, url, securityStatus); } }; mHandler.postDelayed(mUpdateAction, CUSTOM_VIEW_UPDATE_DELAY); @@ -220,25 +220,15 @@ public class ActionBarPresenter { * @param url URL for current website. At least Custom will show this url. */ @UiThread - private void updateCustomView(@Nullable SiteIdentity identity, - @Nullable String title, - @NonNull String url) { - // update site-info icon - if (identity == null) { - mIconView.setVisibility(View.INVISIBLE); - } else { - final SecurityModeUtil.Mode mode = SecurityModeUtil.resolve(identity); + private void updateCustomView(final String title, final String url, final int securityStatus) { + if (securityStatus == GeckoView.ProgressListener.STATE_IS_SECURE) { mIconView.setVisibility(View.VISIBLE); - mIconView.setImageLevel(mode.ordinal()); - mIdentityPopup.setSiteIdentity(identity); - - if (mode == SecurityModeUtil.Mode.LOCK_SECURE) { - // Lock-Secure is special case. Keep its original green color. - DrawableCompat.setTintList(mIconView.getDrawable(), null); - } else { - // Icon use same color as TextView. - DrawableCompat.setTint(mIconView.getDrawable(), mTextPrimaryColor); - } + mIconView.setImageLevel(SecurityModeUtil.Mode.LOCK_SECURE.ordinal()); + // Lock-Secure is special case. Keep its original green color. + DrawableCompat.setTintList(mIconView.getDrawable(), null); + } else { + mIconView.setVisibility(View.INVISIBLE); + DrawableCompat.setTint(mIconView.getDrawable(), mTextPrimaryColor); } // If no title to use, use Url as title diff --git a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java index 8407365ad9c4..ace1d38c8ed8 100644 --- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java +++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java @@ -20,7 +20,7 @@ import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v4.util.SparseArrayCompat; import android.support.v7.app.ActionBar; -import android.support.v7.view.ActionMode; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; @@ -28,17 +28,14 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.ProgressBar; import org.mozilla.gecko.EventDispatcher; +import org.mozilla.gecko.GeckoView; +import org.mozilla.gecko.GeckoViewSettings; import org.mozilla.gecko.R; -import org.mozilla.gecko.SingleTabActivity; import org.mozilla.gecko.SnackbarBuilder; -import org.mozilla.gecko.Tab; -import org.mozilla.gecko.Tabs; import org.mozilla.gecko.Telemetry; import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason; import org.mozilla.gecko.menu.GeckoMenu; import org.mozilla.gecko.menu.GeckoMenuInflater; import org.mozilla.gecko.mozglue.SafeIntent; @@ -46,14 +43,15 @@ import org.mozilla.gecko.util.Clipboard; import org.mozilla.gecko.util.ColorUtil; import org.mozilla.gecko.util.GeckoBundle; import org.mozilla.gecko.util.IntentUtils; -import org.mozilla.gecko.widget.ActionModePresenter; import org.mozilla.gecko.widget.GeckoPopupMenu; import java.util.List; -import static org.mozilla.gecko.Tabs.TabEvents; - -public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabsChangedListener { +public class CustomTabsActivity extends AppCompatActivity + implements GeckoMenu.Callback, + GeckoView.ContentListener, + GeckoView.NavigationListener, + GeckoView.ProgressListener { private static final String LOGTAG = "CustomTabsActivity"; @@ -61,21 +59,30 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs private GeckoPopupMenu popupMenu; private View doorhangerOverlay; private ActionBarPresenter actionBarPresenter; - private ProgressBar mProgressView; // A state to indicate whether this activity is finishing with customize animation private boolean usingCustomAnimation = false; private MenuItem menuItemControl; + private GeckoView mGeckoView; + + private boolean mCanGoBack = false; + private boolean mCanGoForward = false; + private boolean mCanStop = false; + private String mCurrentUrl; + private String mCurrentTitle; + private int mSecurityStatus = GeckoView.ProgressListener.STATE_IS_INSECURE; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.customtabs_activity); + final SafeIntent intent = new SafeIntent(getIntent()); doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay); - mProgressView = (ProgressBar) findViewById(R.id.page_progress); final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar); setSupportActionBar(toolbar); final ActionBar actionBar = getSupportActionBar(); @@ -85,26 +92,22 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs actionBarPresenter.displayUrlOnly(intent.getDataString()); actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(intent), getWindow()); actionBarPresenter.setTextLongClickListener(new UrlCopyListener()); - } - @Override - protected void onTabOpenFromIntent(Tab tab) { - super.onTabOpenFromIntent(tab); + mGeckoView = (GeckoView) findViewById(R.id.gecko_view); - final String host = getReferrerHost(); - recordCustomTabUsage(host); - sendTelemetry(); - } + mGeckoView.setNavigationListener(this); + mGeckoView.setProgressListener(this); + mGeckoView.setContentListener(this); - @Override - protected void onTabSelectFromIntent(Tab tab) { - super.onTabSelectFromIntent(tab); + final GeckoViewSettings settings = mGeckoView.getSettings(); + settings.setBoolean(GeckoViewSettings.USE_MULTIPROCESS, false); - // We already listen for SELECTED events, but if the activity has been destroyed and - // subsequently recreated without a different tab having been selected in Gecko in the - // meantime, our startup won't trigger a SELECTED event because the selected tab in Gecko - // doesn't actually change. - actionBarPresenter.update(tab); + if (intent != null && !TextUtils.isEmpty(intent.getDataString())) { + mGeckoView.loadUri(intent.getDataString()); + } else { + Log.w(LOGTAG, "No intend found for custom tab"); + finish(); + } } private void sendTelemetry() { @@ -154,13 +157,6 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs } } - @Override - public void onDone() { - // We're most probably running within a foreign app's task, so we have no choice what to - // call here if we want to allow the user to return to that task's previous activity. - finish(); - } - @Override public void finish() { super.finish(); @@ -176,63 +172,12 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs } @Override - protected int getNewTabFlags() { - return Tabs.LOADURL_CUSTOMTAB | super.getNewTabFlags(); - } - - @Override - public int getLayout() { - return R.layout.customtabs_activity; - } - - @Override - public View getDoorhangerOverlay() { - return doorhangerOverlay; - } - - @Override - public void onTabChanged(Tab tab, TabEvents msg, String data) { - super.onTabChanged(tab, msg, data); - - if (!Tabs.getInstance().isSelectedTab(tab) || - tab.getType() != Tab.TabType.CUSTOMTAB) { - return; + public void onBackPressed() { + if (mCanGoBack) { + mGeckoView.goBack(); + } else { + finish(); } - - if (msg == TabEvents.START - || msg == TabEvents.STOP - || msg == TabEvents.ADDED - || msg == TabEvents.LOAD_ERROR - || msg == TabEvents.LOADED - || msg == TabEvents.LOCATION_CHANGE - || msg == TabEvents.SELECTED) { - - updateProgress((tab.getState() == Tab.STATE_LOADING), - tab.getLoadProgress()); - } - - if (msg == TabEvents.LOCATION_CHANGE - || msg == TabEvents.SECURITY_CHANGE - || msg == TabEvents.TITLE - || msg == TabEvents.SELECTED) { - actionBarPresenter.update(tab); - } - - updateMenuItemForward(); - } - - @Override - public void onResume() { - super.onResume(); - mLayerView.getDynamicToolbarAnimator().setPinned(true, PinReason.CUSTOM_TAB); - actionBarPresenter.onResume(); - } - - @Override - public void onPause() { - super.onPause(); - mLayerView.getDynamicToolbarAnimator().setPinned(false, PinReason.CUSTOM_TAB); - actionBarPresenter.onPause(); } // Usually should use onCreateOptionsMenu() to initialize menu items. But GeckoApp overwrite @@ -240,7 +185,7 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs // and this.onPrepareOptionsMenu() are different instances - GeckoApp.onCreatePanelMenu() changed it. // CustomTabsActivity only use standard menu in ActionBar, so initialize menu here. @Override - public boolean onCreatePanelMenu(final int id, final Menu menu) { + public boolean onCreateOptionsMenu(final Menu menu) { // if 3rd-party app asks to add an action button SafeIntent intent = new SafeIntent(getIntent()); @@ -275,6 +220,16 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs return true; } + @Override + public boolean onMenuItemClick(MenuItem item) { + return onOptionsItemSelected(item); + } + + @Override + public boolean onMenuItemLongClick(MenuItem item) { + return false; + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -317,34 +272,11 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs performPendingIntent(intent); } - @Override - protected ActionModePresenter getTextSelectPresenter() { - return new ActionModePresenter() { - private ActionMode mMode; - - @Override - public void startActionMode(ActionMode.Callback callback) { - mMode = startSupportActionMode(callback); - } - - @Override - public void endActionMode() { - if (mMode != null) { - mMode.finish(); - } - } - }; - } - private void bindNavigationCallback(@NonNull final Toolbar toolbar) { toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - onDone(); - final Tabs tabs = Tabs.getInstance(); - final Tab tab = tabs.getSelectedTab(); - mSuppressActivitySwitch = true; - tabs.closeTab(tab); + finish(); } }); } @@ -352,8 +284,7 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs private void performPendingIntent(@NonNull PendingIntent pendingIntent) { // bug 1337771: If intent-creator haven't set data url, call send() directly won't work. final Intent additional = new Intent(); - final Tab tab = Tabs.getInstance().getSelectedTab(); - additional.setData(Uri.parse(tab.getURL())); + additional.setData(Uri.parse(mCurrentUrl)); try { pendingIntent.send(this, 0, additional); } catch (PendingIntent.CanceledException e) { @@ -435,49 +366,45 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs } final MenuItem forwardMenuItem = popupMenu.getMenu().findItem(R.id.custom_tabs_menu_forward); - final Tab tab = Tabs.getInstance().getSelectedTab(); - final boolean enabled = (tab != null && tab.canDoForward()); - forwardMenuItem.setEnabled(enabled); + forwardMenuItem.setEnabled(mCanGoForward); } /** - * Update loading progress of current page - * - * @param isLoading to indicate whether ProgressBar should be visible or not - * @param progress value of loading progress in percent, should be 0 - 100. + * Update loading status of current page */ - private void updateProgress(final boolean isLoading, final int progress) { - if (isLoading) { - mProgressView.setVisibility(View.VISIBLE); - mProgressView.setProgress(progress); - } else { - mProgressView.setVisibility(View.GONE); - } - + private void updateCanStop() { if (menuItemControl != null) { Drawable icon = menuItemControl.getIcon(); - icon.setLevel(progress); + if (mCanStop) { + icon.setLevel(0); + } else { + icon.setLevel(100); + } } } + /** + * Update the state of the action bar + */ + private void updateActionBar() { + actionBarPresenter.update(mCurrentTitle, mCurrentUrl, mSecurityStatus); + } + /** * Call this method to reload page, or stop page loading if progress not complete yet. */ private void onLoadingControlClicked() { - final Tab tab = Tabs.getInstance().getSelectedTab(); - if (tab != null) { - if (tab.getLoadProgress() == Tab.LOAD_PROGRESS_STOP) { - tab.doReload(true); - } else { - tab.doStop(); - } + if (mCanStop) { + // TODO: enable this after implementing GeckoView.stop() + //mGeckoView.stop(); + } else { + mGeckoView.reload(); } } private void onForwardClicked() { - final Tab tab = Tabs.getInstance().getSelectedTab(); - if ((tab != null) && tab.canDoForward()) { - tab.doForward(); + if (mCanGoForward) { + mGeckoView.goForward(); } } @@ -485,15 +412,11 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs * Callback for Open-in menu item. */ private void onOpenInClicked() { - final Tab tab = Tabs.getInstance().getSelectedTab(); - if (tab != null) { - // To launch default browser with url of current tab. - final Intent intent = new Intent(); - intent.setData(Uri.parse(tab.getURL())); - intent.setAction(Intent.ACTION_VIEW); - startActivity(intent); - finish(); - } + final Intent intent = new Intent(); + intent.setData(Uri.parse(mCurrentUrl)); + intent.setAction(Intent.ACTION_VIEW); + startActivity(intent); + finish(); } private void onActionButtonClicked() { @@ -507,12 +430,10 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs * Callback for Share menu item. */ private void onShareClicked() { - final String url = Tabs.getInstance().getSelectedTab().getURL(); - - if (!TextUtils.isEmpty(url)) { + if (!TextUtils.isEmpty(mCurrentUrl)) { Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_TEXT, url); + shareIntent.putExtra(Intent.EXTRA_TEXT, mCurrentUrl); Intent chooserIntent = Intent.createChooser(shareIntent, getString(R.string.share_title)); chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -526,9 +447,8 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs private class UrlCopyListener implements View.OnLongClickListener { @Override public boolean onLongClick(View v) { - final String url = Tabs.getInstance().getSelectedTab().getURL(); - if (!TextUtils.isEmpty(url)) { - Clipboard.setText(url); + if (!TextUtils.isEmpty(mCurrentUrl)) { + Clipboard.setText(mCurrentUrl); SnackbarBuilder.builder(CustomTabsActivity.this) .message(R.string.custom_tabs_hint_url_copy) .duration(Snackbar.LENGTH_SHORT) @@ -554,4 +474,59 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs } return null; } + + /* GeckoView.NavigationListener */ + @Override + public void onLocationChange(GeckoView view, String url) { + mCurrentUrl = url; + updateActionBar(); + } + + @Override + public void onCanGoBack(GeckoView view, boolean canGoBack) { + mCanGoBack = canGoBack; + } + + @Override + public void onCanGoForward(GeckoView view, boolean canGoForward) { + mCanGoForward = canGoForward; + updateMenuItemForward(); + } + + /* GeckoView.ProgressListener */ + @Override + public void onPageStart(GeckoView view, String url) { + mCurrentUrl = url; + mCanStop = true; + updateActionBar(); + updateCanStop(); + } + + @Override + public void onPageStop(GeckoView view, boolean success) { + mCanStop = false; + updateCanStop(); + } + + @Override + public void onSecurityChange(GeckoView view, int status) { + if ((status & STATE_IS_INSECURE) != 0) { + mSecurityStatus = STATE_IS_INSECURE; + } else if ((status & STATE_IS_BROKEN) != 0) { + mSecurityStatus = STATE_IS_BROKEN; + } else if ((status & STATE_IS_SECURE) != 0) { + mSecurityStatus = STATE_IS_SECURE; + } + updateActionBar(); + } + + /* GeckoView.ContentListener */ + @Override + public void onTitleChange(GeckoView view, String title) { + mCurrentTitle = title; + updateActionBar(); + } + + @Override + public void onFullScreen(GeckoView view, boolean fullScreen) {} } diff --git a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java index 77cda0940913..7558cf220ee5 100644 --- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java +++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java @@ -7,15 +7,17 @@ package org.mozilla.gecko.webapps; import java.io.File; import java.io.IOException; +import java.util.List; import android.app.ActivityManager; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; import android.support.v7.widget.Toolbar; -import android.support.v7.app.ActionBar; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -30,6 +32,8 @@ import org.json.JSONException; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.GeckoView; +import org.mozilla.gecko.GeckoViewSettings; import org.mozilla.gecko.SingleTabActivity; import org.mozilla.gecko.Telemetry; import org.mozilla.gecko.TelemetryContract; @@ -48,20 +52,22 @@ import org.mozilla.gecko.widget.AnchoredPopup; import static org.mozilla.gecko.Tabs.TabEvents; -public class WebAppActivity extends SingleTabActivity { +public class WebAppActivity extends AppCompatActivity + implements GeckoView.NavigationListener { private static final String LOGTAG = "WebAppActivity"; public static final String MANIFEST_PATH = "MANIFEST_PATH"; private static final String SAVED_INTENT = "savedIntent"; private TextView mUrlView; - private View doorhangerOverlay; + private GeckoView mGeckoView; + private Uri mScope; @Override public void onCreate(Bundle savedInstanceState) { if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 && - savedInstanceState != null) { + savedInstanceState != null) { // Even though we're a single task activity, Android's task switcher has the // annoying habit of never updating its stored intent after our initial creation, // even if we've been subsequently started with a new intent. @@ -75,73 +81,33 @@ public class WebAppActivity extends SingleTabActivity { super.onCreate(savedInstanceState); + setContentView(R.layout.customtabs_activity); + final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar); setSupportActionBar(toolbar); - final ProgressBar progressBar = (ProgressBar) findViewById(R.id.page_progress); - progressBar.setVisibility(View.GONE); - final ActionBar actionBar = getSupportActionBar(); actionBar.setCustomView(R.layout.webapps_action_bar_custom_view); actionBar.setDisplayShowCustomEnabled(true); actionBar.setDisplayShowTitleEnabled(false); actionBar.hide(); - doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay); - final View customView = actionBar.getCustomView(); mUrlView = (TextView) customView.findViewById(R.id.webapps_action_bar_url); - EventDispatcher.getInstance().registerUiThreadListener(this, - "Website:AppEntered", - "Website:AppLeft", - null); - } + mGeckoView = (GeckoView) findViewById(R.id.gecko_view); - @Override - public View getDoorhangerOverlay() { - return doorhangerOverlay; - } + mGeckoView.setNavigationListener(this); - @Override - public int getLayout() { - return R.layout.customtabs_activity; - } + final GeckoViewSettings settings = mGeckoView.getSettings(); + settings.setBoolean(GeckoViewSettings.USE_MULTIPROCESS, false); - @Override - public void handleMessage(final String event, final GeckoBundle message, - final EventCallback callback) { - super.handleMessage(event, message, callback); - - if (message == null || - !message.containsKey("tabId") || message.getInt("tabId") != mLastSelectedTabId) { - return; + final Uri u = getIntent().getData(); + if (u != null) { + mGeckoView.loadUri(u.toString()); } - switch (event) { - case "Website:AppEntered": - getSupportActionBar().hide(); - break; - - case "Website:AppLeft": - getSupportActionBar().show(); - break; - } - } - - @Override - public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) { - super.onTabChanged(tab, msg, data); - - if (tab == null || !Tabs.getInstance().isSelectedTab(tab) || - tab.getType() != Tab.TabType.WEBAPP) { - return; - } - - if (msg == TabEvents.LOCATION_CHANGE || - msg == TabEvents.SELECTED) { - mUrlView.setText(tab.getURL()); - } + loadManifest(getIntent().getStringExtra(MANIFEST_PATH)); } @Override @@ -151,75 +117,6 @@ public class WebAppActivity extends SingleTabActivity { outState.putParcelable(SAVED_INTENT, getIntent()); } - @Override - public void onDestroy() { - super.onDestroy(); - EventDispatcher.getInstance().unregisterUiThreadListener(this, - "Website:AppEntered", - "Website:AppLeft", - null); - } - - @Override - protected int getNewTabFlags() { - return Tabs.LOADURL_WEBAPP | super.getNewTabFlags(); - } - - @Override - protected void onTabOpenFromIntent(Tab tab) { - super.onTabOpenFromIntent(tab); - Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "webapp"); - loadManifest(tab.getManifestPath()); - } - - /** - * In case this activity and its tab are reused (the user has opened - * > 10 current web apps), we check that app launched is still within - * the same host as the intent has set. - * If it isn't, we reload the intent URL. - */ - @Override - protected void onTabSelectFromIntent(Tab tab) { - super.onTabSelectFromIntent(tab); - - SafeIntent intent = new SafeIntent(getIntent()); - - final String launchUrl = intent.getDataString(); - final String currentUrl = tab.getURL(); - final boolean isSameDomain = Uri.parse(currentUrl).getHost() - .equals(Uri.parse(launchUrl).getHost()); - - final String manifestPath; - if (!isSameDomain) { - Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "webapp"); - manifestPath = intent.getStringExtra(MANIFEST_PATH); - tab.setManifestUrl(manifestPath); - Tabs.getInstance().loadUrl(launchUrl); - } else { - manifestPath = tab.getManifestPath(); - } - loadManifest(manifestPath); - } - - @Override - protected ActionModePresenter getTextSelectPresenter() { - return new ActionModePresenter() { - private ActionMode mMode; - - @Override - public void startActionMode(ActionMode.Callback callback) { - mMode = startSupportActionMode(callback); - } - - @Override - public void endActionMode() { - if (mMode != null) { - mMode.finish(); - } - } - }; - } - private void loadManifest(String manifestPath) { if (TextUtils.isEmpty(manifestPath)) { Log.e(LOGTAG, "Missing manifest"); @@ -237,6 +134,7 @@ public class WebAppActivity extends SingleTabActivity { final Integer color = readColorFromManifest(manifestField); final String name = readNameFromManifest(manifestField); final Bitmap icon = readIconFromManifest(manifest); + mScope = readScopeFromManifest(manifest, manifestPath); final ActivityManager.TaskDescription taskDescription = (color == null) ? new ActivityManager.TaskDescription(name, icon) : new ActivityManager.TaskDescription(name, icon, color); @@ -282,10 +180,76 @@ public class WebAppActivity extends SingleTabActivity { return null; } final LoadFaviconResult loadIconResult = FaviconDecoder - .decodeDataURI(getContext(), iconStr); + .decodeDataURI(this, iconStr); if (loadIconResult == null) { return null; } return loadIconResult.getBestBitmap(GeckoAppShell.getPreferredIconSize()); } + + private Uri readScopeFromManifest(JSONObject manifest, String manifestPath) { + final String scopeStr = manifest.optString("scope", null); + if (scopeStr == null) { + return null; + } + + Uri res = Uri.parse(scopeStr); + if (res.isRelative()) { + // TODO: Handle this more correctly. + return null; + } + + return res; + } + + private boolean isInScope(String url) { + if (mScope == null) { + return true; + } + + final Uri uri = Uri.parse(url); + + if (!uri.getScheme().equals(mScope.getScheme())) { + return false; + } + + if (!uri.getHost().equals(mScope.getHost())) { + return false; + } + + final List scopeSegments = mScope.getPathSegments(); + final List urlSegments = uri.getPathSegments(); + + if (scopeSegments.size() > urlSegments.size()) { + return false; + } + + for (int i = 0; i < scopeSegments.size(); i++) { + if (!scopeSegments.get(i).equals(urlSegments.get(i))) { + return false; + } + } + + return true; + } + + /* GeckoView.NavigationListener */ + @Override + public void onLocationChange(GeckoView view, String url) { + if (isInScope(url)) { + getSupportActionBar().hide(); + } else { + getSupportActionBar().show(); + } + + mUrlView.setText(url); + } + + @Override + public void onCanGoBack(GeckoView view, boolean canGoBack) { + } + + @Override + public void onCanGoForward(GeckoView view, boolean canGoForward) { + } } diff --git a/mobile/android/base/resources/layout/customtabs_activity.xml b/mobile/android/base/resources/layout/customtabs_activity.xml index 60656eb81eca..9ac98ffef012 100644 --- a/mobile/android/base/resources/layout/customtabs_activity.xml +++ b/mobile/android/base/resources/layout/customtabs_activity.xml @@ -12,11 +12,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - - - - - - - - + android:scrollbars="none"/> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/dark_transparent_overlay" + android:alpha="0" + android:layerType="hardware"/> + \ No newline at end of file diff --git a/mobile/android/chrome/content/FindHelper.js b/mobile/android/chrome/content/FindHelper.js index 283414057e5e..1e7425b6ca04 100644 --- a/mobile/android/chrome/content/FindHelper.js +++ b/mobile/android/chrome/content/FindHelper.js @@ -87,7 +87,7 @@ var FindHelper = { this._initialViewport = JSON.stringify(this._targetTab.getViewport()); this._viewportChanged = false; - GlobalEventDispatcher.registerListener(this, [ + WindowEventDispatcher.registerListener(this, [ "Tab:Selected", ]); }, @@ -109,7 +109,7 @@ var FindHelper = { this._initialViewport = null; this._viewportChanged = false; - GlobalEventDispatcher.unregisterListener(this, [ + WindowEventDispatcher.unregisterListener(this, [ "Tab:Selected", ]); }, diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5040dd50c3c2..411cb29f81e9 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -389,11 +389,15 @@ var BrowserApp = { Services.androidBridge.browserApp = this; - GlobalEventDispatcher.registerListener(this, [ + WindowEventDispatcher.registerListener(this, [ + "Session:Restore", "Tab:Load", "Tab:Selected", "Tab:Closed", "Tab:Move", + ]); + + GlobalEventDispatcher.registerListener(this, [ "Browser:LoadManifest", "Browser:Quit", "Fonts:Reload", @@ -1851,6 +1855,10 @@ var BrowserApp = { break; } + case "Session:Restore": + GlobalEventDispatcher.dispatch("Session:Restore", data); + break; + case "Session:Stop": browser.stop(); break; diff --git a/mobile/android/chrome/geckoview/geckoview.xul b/mobile/android/chrome/geckoview/geckoview.xul index 8b1378b646dc..6d872b0c3285 100644 --- a/mobile/android/chrome/geckoview/geckoview.xul +++ b/mobile/android/chrome/geckoview/geckoview.xul @@ -7,7 +7,7 @@ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f3eff84798cb..9436f32ce376 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4645,7 +4645,7 @@ pref("network.tcp.keepalive.retry_interval", 1); // seconds pref("network.tcp.keepalive.probe_count", 4); #endif -pref("network.tcp.tcp_fastopen_enable", true); +pref("network.tcp.tcp_fastopen_enable", false); pref("network.tcp.tcp_fastopen_consecutive_failure_limit", 5); // Whether to disable acceleration for all widgets. diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 7cd14da012e2..956fdcf9b785 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -3145,6 +3145,11 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, newChannel->SetNotificationCallbacks(mCallbacks); newChannel->SetLoadFlags(newLoadFlags); + nsCOMPtr cos(do_QueryInterface(newChannel)); + if (cos) { + cos->SetClassFlags(mClassOfService); + } + // Try to preserve the privacy bit if it has been overridden if (mPrivateBrowsingOverriden) { nsCOMPtr newPBChannel = diff --git a/testing/web-platform/meta/html/semantics/forms/the-option-element/option-element-constructor.html.ini b/testing/web-platform/meta/html/semantics/forms/the-option-element/option-element-constructor.html.ini deleted file mode 100644 index be59f2f52dbd..000000000000 --- a/testing/web-platform/meta/html/semantics/forms/the-option-element/option-element-constructor.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[option-element-constructor.html] - type: testharness - [Option constructor handles selectedness correctly when specified with defaultSelected only] - expected: FAIL - - [Option constructor does not set dirtiness (so, manipulating the selected content attribute still updates the selected IDL attribute)] - expected: FAIL - - [Option constructor handles selectedness correctly, even when incongruous with defaultSelected] - expected: FAIL - diff --git a/testing/web-platform/meta/intersection-observer/cross-origin-iframe.html.ini b/testing/web-platform/meta/intersection-observer/cross-origin-iframe.html.ini index e2bf5de1aeed..8b9e869c5781 100644 --- a/testing/web-platform/meta/intersection-observer/cross-origin-iframe.html.ini +++ b/testing/web-platform/meta/intersection-observer/cross-origin-iframe.html.ini @@ -1,3 +1,2 @@ [cross-origin-iframe.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/disconnect.html.ini b/testing/web-platform/meta/intersection-observer/disconnect.html.ini index 45a4815aa706..05d721d3ad8e 100644 --- a/testing/web-platform/meta/intersection-observer/disconnect.html.ini +++ b/testing/web-platform/meta/intersection-observer/disconnect.html.ini @@ -1,3 +1,2 @@ [disconnect.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini b/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini index 824ee97d69c0..d491fb117dda 100644 --- a/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini +++ b/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini @@ -1,6 +1,4 @@ [edge-inclusive-intersection.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359317 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/iframe-no-root.html.ini b/testing/web-platform/meta/intersection-observer/iframe-no-root.html.ini index 8b540536f25c..1c1f955c18c3 100644 --- a/testing/web-platform/meta/intersection-observer/iframe-no-root.html.ini +++ b/testing/web-platform/meta/intersection-observer/iframe-no-root.html.ini @@ -1,6 +1,4 @@ [iframe-no-root.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/multiple-targets.html.ini b/testing/web-platform/meta/intersection-observer/multiple-targets.html.ini index 2b1b784b8226..0d7b23d23161 100644 --- a/testing/web-platform/meta/intersection-observer/multiple-targets.html.ini +++ b/testing/web-platform/meta/intersection-observer/multiple-targets.html.ini @@ -1,6 +1,4 @@ [multiple-targets.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359311 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/multiple-thresholds.html.ini b/testing/web-platform/meta/intersection-observer/multiple-thresholds.html.ini index 6abffe8b375c..12ea6a6440b4 100644 --- a/testing/web-platform/meta/intersection-observer/multiple-thresholds.html.ini +++ b/testing/web-platform/meta/intersection-observer/multiple-thresholds.html.ini @@ -1,5 +1,3 @@ [multiple-thresholds.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318 - [First rAF.] - https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/observer-without-js-reference.html.ini b/testing/web-platform/meta/intersection-observer/observer-without-js-reference.html.ini index 6b65a00e2677..f3cae9b4e79c 100644 --- a/testing/web-platform/meta/intersection-observer/observer-without-js-reference.html.ini +++ b/testing/web-platform/meta/intersection-observer/observer-without-js-reference.html.ini @@ -1,3 +1,2 @@ [observer-without-js-reference.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/remove-element.html.ini b/testing/web-platform/meta/intersection-observer/remove-element.html.ini index e65060b6b73a..797cb276875c 100644 --- a/testing/web-platform/meta/intersection-observer/remove-element.html.ini +++ b/testing/web-platform/meta/intersection-observer/remove-element.html.ini @@ -1,6 +1,4 @@ [remove-element.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1363650 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/root-margin.html.ini b/testing/web-platform/meta/intersection-observer/root-margin.html.ini index b0fb59cbb25b..edb2b6cd4c52 100644 --- a/testing/web-platform/meta/intersection-observer/root-margin.html.ini +++ b/testing/web-platform/meta/intersection-observer/root-margin.html.ini @@ -1,5 +1,3 @@ [root-margin.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318 - [First rAF.] - https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/same-document-no-root.html.ini b/testing/web-platform/meta/intersection-observer/same-document-no-root.html.ini index 703786596410..e671cf6e2311 100644 --- a/testing/web-platform/meta/intersection-observer/same-document-no-root.html.ini +++ b/testing/web-platform/meta/intersection-observer/same-document-no-root.html.ini @@ -1,5 +1,3 @@ [same-document-no-root.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318 - [First rAF.] - https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/same-document-root.html.ini b/testing/web-platform/meta/intersection-observer/same-document-root.html.ini index 58d7c0db95c5..374549420b66 100644 --- a/testing/web-platform/meta/intersection-observer/same-document-root.html.ini +++ b/testing/web-platform/meta/intersection-observer/same-document-root.html.ini @@ -1,6 +1,4 @@ [same-document-root.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1363650 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/same-document-zero-size-target.html.ini b/testing/web-platform/meta/intersection-observer/same-document-zero-size-target.html.ini index ec291157df7d..9519a5bd4579 100644 --- a/testing/web-platform/meta/intersection-observer/same-document-zero-size-target.html.ini +++ b/testing/web-platform/meta/intersection-observer/same-document-zero-size-target.html.ini @@ -1,5 +1,3 @@ [same-document-zero-size-target.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318 - [First rAF.] - https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/timestamp.html.ini b/testing/web-platform/meta/intersection-observer/timestamp.html.ini index 1715bc15a56f..b359aec876af 100644 --- a/testing/web-platform/meta/intersection-observer/timestamp.html.ini +++ b/testing/web-platform/meta/intersection-observer/timestamp.html.ini @@ -1,3 +1,2 @@ [timestamp.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini b/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini index 73336fb05974..e6325d64fcd8 100644 --- a/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini +++ b/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini @@ -1,6 +1,4 @@ [unclipped-root.html] type: testharness disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359317 - [First rAF.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/zero-area-element-hidden.html.ini b/testing/web-platform/meta/intersection-observer/zero-area-element-hidden.html.ini index c896b25c449f..7859492e594b 100644 --- a/testing/web-platform/meta/intersection-observer/zero-area-element-hidden.html.ini +++ b/testing/web-platform/meta/intersection-observer/zero-area-element-hidden.html.ini @@ -1,3 +1,2 @@ [zero-area-element-hidden.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/testing/web-platform/meta/intersection-observer/zero-area-element-visible.html.ini b/testing/web-platform/meta/intersection-observer/zero-area-element-visible.html.ini index 03e654681e00..6ddb827d31ac 100644 --- a/testing/web-platform/meta/intersection-observer/zero-area-element-visible.html.ini +++ b/testing/web-platform/meta/intersection-observer/zero-area-element-visible.html.ini @@ -1,4 +1,3 @@ [zero-area-element-visible.html] type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1335644 diff --git a/toolkit/components/browser/nsIWebBrowserChrome3.idl b/toolkit/components/browser/nsIWebBrowserChrome3.idl index 7c6b6a210d40..d23021efee18 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome3.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome3.idl @@ -79,8 +79,11 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2 * * @param aHref The URI to begin prerendering * @param aReferrer The URI of the document requesting the prerender. + * @param aTriggeringPrincipal The Principal that initiated to load aHref */ - void startPrerenderingDocument(in nsIURI aHref, in nsIURI aReferrer); + void startPrerenderingDocument(in nsIURI aHref, + in nsIURI aReferrer, + in nsIPrincipal aTriggeringPrincipal); /** * Check if there's a prerendered document which matches given URI / diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index f8a55950bcc0..2566d28306cb 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -13190,6 +13190,15 @@ "bug_numbers": [1351021], "description": "Every time we run an unlabeled runnable, this histogram records the time (in ms) since the last unlabeled runnable ran." }, + "DOCUMENT_DATA_URI_LOADS": { + "record_in_processes": ["main", "content"], + "alert_emails": ["seceng-telemetry@mozilla.com"], + "bug_numbers": [1357386], + "expires_in_version": "60", + "kind": "enumerated", + "n_values": 3, + "description": "Whether a toplevel document uses data: URI? (0=data-navigated, 1=data-typed, 2=nodata)" + }, "VFC_INVALIDATE_LOCK_WAIT_MS": { "record_in_processes": ["main", "content"], "alert_emails": ["jwwang@mozilla.com"], diff --git a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm index 737c08db6a59..deb7df811aa2 100644 --- a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm +++ b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm @@ -482,8 +482,10 @@ var TelemetryReportingPolicyImpl = { win.addEventListener("unload", removeListeners); win.gBrowser.addTabsProgressListener(progressListener); - tab = win.gBrowser.loadOneTab(firstRunPolicyURL, { inBackground: true }); - + tab = win.gBrowser.loadOneTab(firstRunPolicyURL, { + inBackground: true, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); return true; }, diff --git a/toolkit/themes/shared/icons/menubutton-dropmarker.svg b/toolkit/themes/shared/icons/menubutton-dropmarker.svg index 76af113a7bbf..0cdb04aef969 100644 --- a/toolkit/themes/shared/icons/menubutton-dropmarker.svg +++ b/toolkit/themes/shared/icons/menubutton-dropmarker.svg @@ -1,8 +1,8 @@ - - + + diff --git a/toolkit/themes/shared/popupnotification.inc.css b/toolkit/themes/shared/popupnotification.inc.css index 9f34b3676980..74152765eb98 100644 --- a/toolkit/themes/shared/popupnotification.inc.css +++ b/toolkit/themes/shared/popupnotification.inc.css @@ -124,6 +124,6 @@ width: 16px; height: 16px; list-style-image: url(chrome://global/skin/icons/menubutton-dropmarker.svg); - filter: url(chrome://global/skin/filters.svg#fill); + -moz-context-properties: fill; fill: currentColor; } diff --git a/toolkit/xre/test/win/TestDllInterceptor.cpp b/toolkit/xre/test/win/TestDllInterceptor.cpp index 359d0765e6d0..921e088e205d 100644 --- a/toolkit/xre/test/win/TestDllInterceptor.cpp +++ b/toolkit/xre/test/win/TestDllInterceptor.cpp @@ -399,16 +399,13 @@ bool TestProcessCaretEvents(void* aFunc) bool TestSetCursorPos(void* aFunc) { + // SetCursorPos has some issues in automation -- see bug 1368033. + // For that reason, we don't check the return value -- we only + // check that the method runs without producing an exception. auto patchedSetCursorPos = reinterpret_cast(aFunc); - POINT cursorPos; - BOOL ok = GetCursorPos(&cursorPos); - if (ok) { - ok = patchedSetCursorPos(cursorPos.x, cursorPos.y); - } else { - ok = patchedSetCursorPos(512, 512); - } - return ok; + patchedSetCursorPos(512, 512); + return true; } static DWORD sTlsIndex = 0; diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp index 0fafb37cf5d3..879b8f337912 100644 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp @@ -310,17 +310,13 @@ private: } /** - * Dispatch the specified memory pressure event unless a high-priority - * process is present. If a high-priority process is present then it's likely - * responding to an urgent event (an incoming call or message for example) so - * avoid wasting CPU time responding to low-memory events. + * Dispatch the specified memory pressure event. If a high-priority process is + * present then it's likely responding to an urgent event (an incoming call or + * message for example) so avoid wasting CPU time responding to low-memory + * events. */ nsresult DispatchMemoryPressure(MemoryPressureState state) { - if (ProcessPriorityManager::AnyProcessHasHighPriority()) { - return NS_OK; - } - return NS_DispatchMemoryPressure(state); } diff --git a/xpcom/ds/PLDHashTable.cpp b/xpcom/ds/PLDHashTable.cpp index 6152e90003c0..facb470d6c2b 100644 --- a/xpcom/ds/PLDHashTable.cpp +++ b/xpcom/ds/PLDHashTable.cpp @@ -253,15 +253,27 @@ PLDHashTable::Hash1(PLDHashNumber aHash0) return aHash0 >> mHashShift; } -// Double hashing needs the second hash code to be relatively prime to table -// size, so we simply make hash2 odd. void -PLDHashTable::Hash2(PLDHashNumber aHash, +PLDHashTable::Hash2(PLDHashNumber aHash0, uint32_t& aHash2Out, uint32_t& aSizeMaskOut) { uint32_t sizeLog2 = kHashBits - mHashShift; - aHash2Out = ((aHash << sizeLog2) >> mHashShift) | 1; - aSizeMaskOut = (PLDHashNumber(1) << sizeLog2) - 1; + uint32_t sizeMask = (PLDHashNumber(1) << sizeLog2) - 1; + aSizeMaskOut = sizeMask; + + // The incoming aHash0 always has the low bit unset (since we leave it + // free for the collision flag), and should have reasonably random + // data in the other 31 bits. We used the high bits of aHash0 for + // Hash1, so we use the low bits here. If the table size is large, + // the bits we use may overlap, but that's still more random than + // filling with 0s. + // + // Double hashing needs the second hash code to be relatively prime to table + // size, so we simply make hash2 odd. + // + // This also conveniently covers up the fact that we have the low bit + // unset since aHash0 has the low bit unset. + aHash2Out = (aHash0 & sizeMask) | 1; } // Reserve mKeyHash 0 for free entries and 1 for removed-entry sentinels. Note @@ -366,11 +378,9 @@ PLDHashTable::SearchTable(const void* aKey, PLDHashNumber aKeyHash) PLDHashEntryHdr* firstRemoved = nullptr; for (;;) { - if (Reason == ForAdd) { + if (Reason == ForAdd && !firstRemoved) { if (MOZ_UNLIKELY(EntryIsRemoved(entry))) { - if (!firstRemoved) { - firstRemoved = entry; - } + firstRemoved = entry; } else { entry->mKeyHash |= kCollisionFlag; } diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp index 155d30551801..d9067cea541a 100644 --- a/xpfe/appshell/nsContentTreeOwner.cpp +++ b/xpfe/appshell/nsContentTreeOwner.cpp @@ -429,7 +429,8 @@ NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(nsIDocShell* aDocShell, } NS_IMETHODIMP nsContentTreeOwner::StartPrerenderingDocument(nsIURI* aHref, - nsIURI* aReferrer) + nsIURI* aReferrer, + nsIPrincipal* aTriggeringPrincipal) { NS_WARNING("Cannot prerender a document in the parent process"); return NS_ERROR_FAILURE;
file_MultipleFrames.html
file_NestedFramesOuter.html