author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 03 Mar 2016 11:54:40 +0100 | |
changeset 286601 | 2b5237c178ea02133a777396c24dd2b713f2b8ee |
parent 286600 | 7e43bdd93e439b8c8d6e62d48d9de3e293655560 (current diff) |
parent 286536 | a269b54d4fb5f3b3bfcdf5ea87899d469f7ea552 (diff) |
child 286602 | eb9b1d97740d8b0131438177cd1ef8833fe2f530 |
child 286724 | 20d8879ac256a9c7ff81edc69748c37c3b310865 |
child 286728 | 68b6defee155efdc00bb6b4602b30bcb26da5a5a |
push id | 72832 |
push user | cbook@mozilla.com |
push date | Thu, 03 Mar 2016 10:57:50 +0000 |
treeherder | mozilla-inbound@eb9b1d97740d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 47.0a1 |
first release with | nightly linux32
2b5237c178ea
/
47.0a1
/
20160303030253
/
files
nightly linux64
2b5237c178ea
/
47.0a1
/
20160303030253
/
files
nightly mac
2b5237c178ea
/
47.0a1
/
20160303030253
/
files
nightly win32
2b5237c178ea
/
47.0a1
/
20160303030253
/
files
nightly win64
2b5237c178ea
/
47.0a1
/
20160303030253
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
47.0a1
/
20160303030253
/
pushlog to previous
nightly linux64
47.0a1
/
20160303030253
/
pushlog to previous
nightly mac
47.0a1
/
20160303030253
/
pushlog to previous
nightly win32
47.0a1
/
20160303030253
/
pushlog to previous
nightly win64
47.0a1
/
20160303030253
/
pushlog to previous
|
js/src/tests/js1_7/geniter/regress-351514.js | file | annotate | diff | comparison | revisions | |
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui.yml | file | annotate | diff | comparison | revisions | |
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_e10s.yml | file | annotate | diff | comparison | revisions | |
testing/web-platform/meta/fetch/api/policies/referrer-origin.html.ini | file | annotate | diff | comparison | revisions | |
toolkit/components/telemetry/Histograms.json | file | annotate | diff | comparison | revisions |
--- a/accessible/atk/DocAccessibleWrap.cpp +++ b/accessible/atk/DocAccessibleWrap.cpp @@ -9,18 +9,17 @@ using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // DocAccessibleWrap //////////////////////////////////////////////////////////////////////////////// DocAccessibleWrap:: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - DocAccessible(aDocument, aRootContent, aPresShell), mActivated(false) + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessible(aDocument, aPresShell), mActivated(false) { } DocAccessibleWrap::~DocAccessibleWrap() { }
--- a/accessible/atk/DocAccessibleWrap.h +++ b/accessible/atk/DocAccessibleWrap.h @@ -14,18 +14,17 @@ #include "DocAccessible.h" namespace mozilla { namespace a11y { class DocAccessibleWrap : public DocAccessible { public: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); virtual ~DocAccessibleWrap(); bool mActivated; }; } // namespace a11y } // namespace mozilla
--- a/accessible/base/DocManager.cpp +++ b/accessible/base/DocManager.cpp @@ -465,27 +465,25 @@ DocManager::CreateDocOrRootAccessible(ns NS_ASSERTION(parentDocAcc, "Can't create an accessible for the document!"); if (!parentDocAcc) return nullptr; } // We only create root accessibles for the true root, otherwise create a // doc accessible. - nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument); RefPtr<DocAccessible> docAcc = isRootDoc ? - new RootAccessibleWrap(aDocument, rootElm, presShell) : - new DocAccessibleWrap(aDocument, rootElm, presShell); + new RootAccessibleWrap(aDocument, presShell) : + new DocAccessibleWrap(aDocument, presShell); // Cache the document accessible into document cache. mDocAccessibleCache.Put(aDocument, docAcc); // Initialize the document accessible. docAcc->Init(); - docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument)); // Bind the document to the tree. if (isRootDoc) { if (!ApplicationAcc()->AppendChild(docAcc)) { docAcc->Shutdown(); return nullptr; }
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -71,19 +71,18 @@ static nsIAtom** kRelationAttrs[] = }; static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs); //////////////////////////////////////////////////////////////////////////////// // Constructor/desctructor DocAccessible:: - DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - HyperTextAccessibleWrap(aRootContent, this), + DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) : + HyperTextAccessibleWrap(nullptr, this), // XXX aaronl should we use an algorithm for the initial cache size? mAccessibleCache(kDefaultCacheLength), mNodeToAccessibleMap(kDefaultCacheLength), mDocumentNode(aDocument), mScrollPositionChangedTicks(0), mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0), mVirtualCursor(nullptr), mPresShell(aPresShell), mIPCDoc(nullptr) @@ -1460,17 +1459,17 @@ DocAccessible::DoInitialUpdate() mDocFlags |= eTabDocument; mLoadState |= eTreeConstructed; // The content element may be changed before the initial update and then we // miss the notification (since content tree change notifications are ignored // prior to initial update). Make sure the content element is valid. nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode); - if (mContent != contentElm) { + if (contentElm) { mContent = contentElm; SetRoleMapEntry(aria::GetRoleMap(mContent)); } // Build initial tree. Since its the initial tree there's no group info to // invalidate. AutoTreeMutation mut(this, false); CacheChildrenInSubtree(this);
--- a/accessible/generic/DocAccessible.h +++ b/accessible/generic/DocAccessible.h @@ -45,18 +45,17 @@ class DocAccessible : public HyperTextAc NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, Accessible) NS_DECL_NSIOBSERVER NS_DECL_NSIACCESSIBLEPIVOTOBSERVER public: - DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell); // nsIScrollPositionListener virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {} virtual void ScrollPositionDidChange(nscoord aX, nscoord aY) override; // nsIDocumentObserver NS_DECL_NSIDOCUMENTOBSERVER
--- a/accessible/generic/RootAccessible.cpp +++ b/accessible/generic/RootAccessible.cpp @@ -54,19 +54,18 @@ using namespace mozilla::dom; // nsISupports NS_IMPL_ISUPPORTS_INHERITED0(RootAccessible, DocAccessible) //////////////////////////////////////////////////////////////////////////////// // Constructor/destructor RootAccessible:: - RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - DocAccessibleWrap(aDocument, aRootContent, aPresShell) + RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessibleWrap(aDocument, aPresShell) { mType = eRootType; } RootAccessible::~RootAccessible() { }
--- a/accessible/generic/RootAccessible.h +++ b/accessible/generic/RootAccessible.h @@ -17,18 +17,17 @@ namespace mozilla { namespace a11y { class RootAccessible : public DocAccessibleWrap, public nsIDOMEventListener { NS_DECL_ISUPPORTS_INHERITED public: - RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell); // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override; // Accessible virtual void Shutdown() override; virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override; virtual Relation RelationByType(RelationType aType) override;
--- a/accessible/jsat/AccessFu.jsm +++ b/accessible/jsat/AccessFu.jsm @@ -339,17 +339,17 @@ this.AccessFu = { // jshint ignore:line case 'Accessibility:MoveByGranularity': this.Input.moveByGranularity(JSON.parse(aData)); break; case 'remote-browser-shown': case 'inprocess-browser-shown': { // Ignore notifications that aren't from a BrowserOrApp let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader); - if (!frameLoader.ownerIsBrowserOrAppFrame) { + if (!frameLoader.ownerIsMozBrowserOrAppFrame) { return; } this._handleMessageManager(frameLoader.messageManager); break; } } },
--- a/accessible/mac/DocAccessibleWrap.h +++ b/accessible/mac/DocAccessibleWrap.h @@ -9,18 +9,17 @@ #include "DocAccessible.h" namespace mozilla { namespace a11y { class DocAccessibleWrap : public DocAccessible { public: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); virtual ~DocAccessibleWrap(); }; } // namespace a11y } // namespace mozilla #endif
--- a/accessible/mac/DocAccessibleWrap.mm +++ b/accessible/mac/DocAccessibleWrap.mm @@ -5,18 +5,17 @@ #include "DocAccessibleWrap.h" #import "mozAccessible.h" using namespace mozilla::a11y; DocAccessibleWrap:: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - DocAccessible(aDocument, aRootContent, aPresShell) + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessible(aDocument, aPresShell) { } DocAccessibleWrap::~DocAccessibleWrap() { }
--- a/accessible/mac/RootAccessibleWrap.h +++ b/accessible/mac/RootAccessibleWrap.h @@ -13,18 +13,17 @@ #include "RootAccessible.h" namespace mozilla { namespace a11y { class RootAccessibleWrap : public RootAccessible { public: - RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); virtual ~RootAccessibleWrap(); Class GetNativeType (); // let's our native accessible get in touch with the // native cocoa view that is our accessible parent. void GetNativeWidget (void **aOutView); };
--- a/accessible/mac/RootAccessibleWrap.mm +++ b/accessible/mac/RootAccessibleWrap.mm @@ -11,19 +11,18 @@ #include "nsObjCExceptions.h" #include "nsIFrame.h" #include "nsView.h" #include "nsIWidget.h" using namespace mozilla::a11y; RootAccessibleWrap:: - RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - RootAccessible(aDocument, aRootContent, aPresShell) + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + RootAccessible(aDocument, aPresShell) { } RootAccessibleWrap::~RootAccessibleWrap() { } Class
--- a/accessible/tests/mochitest/events/test_valuechange.html +++ b/accessible/tests/mochitest/events/test_valuechange.html @@ -15,18 +15,16 @@ src="../common.js"></script> <script type="application/javascript" src="../events.js"></script> <script type="application/javascript" src="../value.js"></script> <script type="application/javascript"> - - /** * Do tests. */ var gQueue = null; // Value change invoker function changeARIAValue(aNodeOrID, aValuenow, aValuetext) { @@ -127,16 +125,39 @@ } this.getID = function changeRangeValue_getID() { return prettyName(aID) + " range value changed"; } } + function changeSelectValue(aID, aKey, aValue) + { + this.eventSeq = [new invokerChecker(EVENT_TEXT_VALUE_CHANGE, aID)]; + + this.invoke = function changeSelectValue_invoke() + { + getNode(aID).focus(); + synthesizeKey(aKey, {}, window); + } + + this.finalCheck = function changeSelectValue_finalCheck() + { + is(getAccessible(aID).value, aValue, "Wrong value for " + prettyName(aID)); + } + + this.getID = function changeSelectValue_getID() + { + return `${prettyName(aID)} closed select value change on '${aKey}'' key press`; + } + } + + //enableLogging("DOMEvents"); + //gA11yEventDumpToConsole = true; function doTests() { // Test initial values testValue("slider_vn", "5", 5, 0, 1000, 0); testValue("slider_vnvt", "plain", 0, 0, 5, 0); testValue("slider_vt", "hi", 0, 0, 3, 0); testValue("scrollbar", "5", 5, 0, 1000, 0); testValue("progress", "22%", 22, 0, 100, 0); @@ -150,16 +171,19 @@ gQueue.push(new changeARIAValue("slider_vnvt", "3", "sweet")); gQueue.push(new changeARIAValue("scrollbar", "6", undefined)); gQueue.push(new changeValue("combobox", "hello")); gQueue.push(new changeProgressValue("progress", "50")); gQueue.push(new changeRangeValue("range")); + gQueue.push(new changeSelectValue("select", "VK_DOWN", "2nd")); + gQueue.push(new changeSelectValue("select", "3", "3rd")); + gQueue.invoke(); // Will call SimpleTest.finish(); } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTests); </script> </head> @@ -216,10 +240,15 @@ <input id="combobox" role="combobox" aria-autocomplete="inline"> <!-- progress bar --> <progress id="progress" value="22" max="100"></progress> <!-- input@type="range" --> <input type="range" id="range" min="0" max="10" value="6"> + <select id="select"> + <option>1st</option> + <option>2nd</option> + <option>3rd</option> + </select> </body> </html>
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp +++ b/accessible/windows/msaa/DocAccessibleWrap.cpp @@ -20,19 +20,18 @@ using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // DocAccessibleWrap //////////////////////////////////////////////////////////////////////////////// DocAccessibleWrap:: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr) + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessible(aDocument, aPresShell), mHWND(nullptr) { } DocAccessibleWrap::~DocAccessibleWrap() { } IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
--- a/accessible/windows/msaa/DocAccessibleWrap.h +++ b/accessible/windows/msaa/DocAccessibleWrap.h @@ -10,18 +10,17 @@ #include "DocAccessible.h" namespace mozilla { namespace a11y { class DocAccessibleWrap : public DocAccessible { public: - DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); virtual ~DocAccessibleWrap(); DECL_IUNKNOWN_INHERITED // IAccessible // Override get_accValue to provide URL when no other value is available virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
--- a/accessible/windows/msaa/RootAccessibleWrap.cpp +++ b/accessible/windows/msaa/RootAccessibleWrap.cpp @@ -10,19 +10,18 @@ #include "nsWinUtils.h" using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // Constructor/desctructor RootAccessibleWrap:: - RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell) : - RootAccessible(aDocument, aRootContent, aPresShell) + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + RootAccessible(aDocument, aPresShell) { } RootAccessibleWrap::~RootAccessibleWrap() { } ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/windows/msaa/RootAccessibleWrap.h +++ b/accessible/windows/msaa/RootAccessibleWrap.h @@ -9,18 +9,17 @@ #include "RootAccessible.h" namespace mozilla { namespace a11y { class RootAccessibleWrap : public RootAccessible { public: - RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent, - nsIPresShell* aPresShell); + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); virtual ~RootAccessibleWrap(); // RootAccessible virtual void DocumentActivated(DocAccessible* aDocument); }; } // namespace a11y } // namespace mozilla
--- a/addon-sdk/source/lib/sdk/context-menu.js +++ b/addon-sdk/source/lib/sdk/context-menu.js @@ -62,18 +62,19 @@ const OVERFLOW_POPUP_CLASS = "addon-cont // Holds private properties for API objects var internal = ns(); // A little hacky but this is the last process ID that last opened the context // menu var lastContextProcessId = null; +var uuidModule = require('./util/uuid'); function uuid() { - return require('./util/uuid').uuid().toString(); + return uuidModule.uuid().toString(); } function getScheme(spec) { try { return URL(spec).scheme; } catch(e) { return null;
--- a/b2g/chrome/content/runapp.js +++ b/b2g/chrome/content/runapp.js @@ -52,17 +52,17 @@ function AppRunner(aName) { this._apps = []; } AppRunner.prototype = { observe: function(aSubject, aTopic, aData) { let frameLoader = aSubject; // get a ref to the app <iframe> frameLoader.QueryInterface(Ci.nsIFrameLoader); // Ignore notifications that aren't from a BrowserOrApp - if (!frameLoader.ownerIsBrowserOrAppFrame) { + if (!frameLoader.ownerIsMozBrowserOrAppFrame) { return; } let frame = frameLoader.ownerElement; if (!frame.appManifestURL) { // Ignore all frames but app frames return; }
--- a/b2g/components/AboutServiceWorkers.jsm +++ b/b2g/components/AboutServiceWorkers.jsm @@ -139,17 +139,17 @@ this.AboutServiceWorkers = { self.sendResult(message.id, true); break; case "unregister": if (!message.principal || !message.principal.origin || !message.principal.originAttributes || !message.principal.originAttributes.appId || - (message.principal.originAttributes.inBrowser == null)) { + (message.principal.originAttributes.inIsolatedMozBrowser == null)) { self.sendError(message.id, "MissingPrincipal"); return; } let principal = Services.scriptSecurityManager.createCodebasePrincipal( // TODO: Bug 1196652. use originNoSuffix Services.io.newURI(message.principal.origin, null, null), message.principal.originAttributes);
--- a/b2g/components/ErrorPage.jsm +++ b/b2g/components/ErrorPage.jsm @@ -172,16 +172,16 @@ var ErrorPage = { init: function errorPageInit() { Services.obs.addObserver(this, 'inprocess-browser-shown', false); Services.obs.addObserver(this, 'remote-browser-shown', false); }, observe: function errorPageObserve(aSubject, aTopic, aData) { let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader); // Ignore notifications that aren't from a BrowserOrApp - if (!frameLoader.ownerIsBrowserOrAppFrame) { + if (!frameLoader.ownerIsMozBrowserOrAppFrame) { return; } this._listenError(frameLoader); } }; ErrorPage.init();
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1372,16 +1372,19 @@ pref("browser.newtabpage.columns", 5); pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%"); // endpoint to send newtab click and view pings pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/"); // activates the remote-hosted newtab page pref("browser.newtabpage.remote", false); +// Toggles endpoints allowed for remote newtab communications +pref("browser.newtabpage.remote.mode", "production"); + // Enable the DOM fullscreen API. pref("full-screen-api.enabled", true); // Startup Crash Tracking // number of startup crashes that can occur before starting into safe mode automatically // (this pref has no effect if more than 6 hours have passed since the last crash) pref("toolkit.startup.max_resumed_crashes", 3); @@ -1650,8 +1653,11 @@ pref("toolkit.pageThumbs.minHeight", 190 #ifdef NIGHTLY_BUILD // Enable speech synthesis, only Nightly for now pref("media.webspeech.synth.enabled", true); #endif pref("browser.esedbreader.loglevel", "Error"); pref("browser.laterrun.enabled", false); + +// Enable browser frames for use on desktop. Only exposed to chrome callers. +pref("dom.mozBrowserFramesEnabled", true);
--- a/browser/components/newtab/NewTabPrefsProvider.jsm +++ b/browser/components/newtab/NewTabPrefsProvider.jsm @@ -13,16 +13,17 @@ Cu.import("resource://gre/modules/XPCOMU XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() { const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {}); return EventEmitter; }); // Supported prefs and data type const gPrefsMap = new Map([ ["browser.newtabpage.remote", "bool"], + ["browser.newtabpage.remote.mode", "str"], ["browser.newtabpage.enabled", "bool"], ["browser.newtabpage.enhanced", "bool"], ["browser.newtabpage.pinned", "str"], ["intl.locale.matchOS", "bool"], ["general.useragent.locale", "localized"], ]); let PrefsProvider = function PrefsProvider() {
new file mode 100644 --- /dev/null +++ b/browser/components/newtab/NewTabRemoteResources.jsm @@ -0,0 +1,13 @@ +/* exported MODE_CHANNEL_MAP */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["MODE_CHANNEL_MAP"]; + +const MODE_CHANNEL_MAP = { + "production": {origin: "https://content.cdn.mozilla.net"}, + "staging": {origin: "https://content-cdn.stage.mozaws.net"}, + "test": {origin: "https://example.com"}, + "test2": {origin: "http://mochi.test:8888"}, + "dev": {origin: "http://localhost:8888"} +};
--- a/browser/components/newtab/aboutNewTabService.js +++ b/browser/components/newtab/aboutNewTabService.js @@ -1,54 +1,60 @@ /* * 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/. */ /* globals XPCOMUtils, NewTabPrefsProvider, Services, - Locale, UpdateUtils + Locale, UpdateUtils, MODE_CHANNEL_MAP */ "use strict"; const {utils: Cu, interfaces: Ci} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider", "resource:///modules/NewTabPrefsProvider.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Locale", "resource://gre/modules/Locale.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "MODE_CHANNEL_MAP", + "resource:///modules/NewTabRemoteResources.jsm"); const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml"; -const REMOTE_NEWTAB_URL = "https://newtab.cdn.mozilla.net/" + - "v%VERSION%/%CHANNEL%/%LOCALE%/index.html"; +const REMOTE_NEWTAB_PATH = "/v%VERSION%/%CHANNEL%/%LOCALE%/index.html"; const ABOUT_URL = "about:newtab"; // Pref that tells if remote newtab is enabled const PREF_REMOTE_ENABLED = "browser.newtabpage.remote"; // The preference that tells whether to match the OS locale const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; // The preference that tells what locale the user selected const PREF_SELECTED_LOCALE = "general.useragent.locale"; +// The preference that tells what remote mode is enabled. +const PREF_REMOTE_MODE = "browser.newtabpage.remote.mode"; + const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]); const REMOTE_NEWTAB_VERSION = "0"; function AboutNewTabService() { NewTabPrefsProvider.prefs.on(PREF_REMOTE_ENABLED, this._handleToggleEvent.bind(this)); + this._updateRemoteMaybe = this._updateRemoteMaybe.bind(this); + // trigger remote change if needed, according to pref this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED)); } /* * A service that allows for the overriding, at runtime, of the newtab page's url. * Additionally, the service manages pref state between a remote and local newtab page. * @@ -119,40 +125,48 @@ AboutNewTabService.prototype = { // exit there is no change of state return false; } if (stateEnabled) { this._remoteURL = this.generateRemoteURL(); NewTabPrefsProvider.prefs.on( PREF_SELECTED_LOCALE, - this._updateRemoteMaybe.bind(this)); + this._updateRemoteMaybe); NewTabPrefsProvider.prefs.on( PREF_MATCH_OS_LOCALE, - this._updateRemoteMaybe.bind(this)); + this._updateRemoteMaybe); + NewTabPrefsProvider.prefs.on( + PREF_REMOTE_MODE, + this._updateRemoteMaybe); this._remoteEnabled = true; } else { NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateRemoteMaybe); NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateRemoteMaybe); + NewTabPrefsProvider.prefs.off(PREF_REMOTE_MODE, this._updateRemoteMaybe); this._remoteEnabled = false; } this._newTabURL = ABOUT_URL; return true; }, /* - * Generate a default url based on locale and update channel + * Generate a default url based on remote mode, version, locale and update channel */ generateRemoteURL() { let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel); - let url = REMOTE_NEWTAB_URL + let path = REMOTE_NEWTAB_PATH .replace("%VERSION%", REMOTE_NEWTAB_VERSION) .replace("%LOCALE%", Locale.getLocale()) .replace("%CHANNEL%", releaseName); - return url; + let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE, "production"); + if (!(mode in MODE_CHANNEL_MAP)) { + mode = "production"; + } + return MODE_CHANNEL_MAP[mode].origin + path; }, /* * Returns the default URL. * * This URL only depends on the browser.newtabpage.remote pref. Overriding * the newtab page has no effect on the result of this function. *
--- a/browser/components/newtab/moz.build +++ b/browser/components/newtab/moz.build @@ -7,16 +7,17 @@ BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini'] XPCSHELL_TESTS_MANIFESTS += [ 'tests/xpcshell/xpcshell.ini', ] EXTRA_JS_MODULES += [ 'NewTabPrefsProvider.jsm', + 'NewTabRemoteResources.jsm', 'NewTabURL.jsm', 'PlacesProvider.jsm' ] XPIDL_SOURCES += [ 'nsIAboutNewTabService.idl', ]
--- a/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js +++ b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js @@ -100,35 +100,50 @@ add_task(function* test_override_remote_ add_task(function* test_updates() { /* * Simulates a "cold-boot" situation, with some pref already set before testing a series * of changes. */ Preferences.set("browser.newtabpage.remote", true); aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off let notificationPromise; - let expectedHref = "https://newtab.cdn.mozilla.net" + - `/v${aboutNewTabService.remoteVersion}` + + let productionModeBaseUrl = "https://content.cdn.mozilla.net"; + let testModeBaseUrl = "https://example.com"; + let expectedPath = `/v${aboutNewTabService.remoteVersion}` + `/${aboutNewTabService.remoteReleaseName}` + "/en-GB" + "/index.html"; + let expectedHref = productionModeBaseUrl + expectedPath; Preferences.set("intl.locale.matchOS", true); Preferences.set("general.useragent.locale", "en-GB"); + Preferences.set("browser.newtabpage.remote.mode", "production"); NewTabPrefsProvider.prefs.init(); // test update checks for prefs notificationPromise = nextChangeNotificationPromise( expectedHref, "Remote href should be updated"); Preferences.set("intl.locale.matchOS", false); yield notificationPromise; notificationPromise = nextChangeNotificationPromise( DEFAULT_HREF, "Remote href changes back to default"); Preferences.set("general.useragent.locale", "en-US"); + yield notificationPromise; + // test update fires when mode is changed + expectedPath = expectedPath.replace("/en-GB/", "/en-US/"); + notificationPromise = nextChangeNotificationPromise( + testModeBaseUrl + expectedPath, "Remote href changes back to origin of test mode"); + Preferences.set("browser.newtabpage.remote.mode", "test"); + yield notificationPromise; + + // test invalid mode ends up pointing to production url + notificationPromise = nextChangeNotificationPromise( + DEFAULT_HREF, "Remote href changes back to production default"); + Preferences.set("browser.newtabpage.remote.mode", "invalid"); yield notificationPromise; // test update fires on override and reset let testURL = "https://example.com/"; notificationPromise = nextChangeNotificationPromise( testURL, "a notification occurs on override"); aboutNewTabService.newTabURL = testURL; yield notificationPromise;
--- a/browser/components/sessionstore/SessionHistory.jsm +++ b/browser/components/sessionstore/SessionHistory.jsm @@ -140,16 +140,20 @@ var SessionHistoryInternal = { entry.referrer = shEntry.referrerURI.spec; entry.referrerPolicy = shEntry.referrerPolicy; } if (shEntry.originalURI) { entry.originalURI = shEntry.originalURI.spec; } + if (shEntry.loadReplace) { + entry.loadReplace = shEntry.loadReplace; + } + if (shEntry.srcdocData) entry.srcdocData = shEntry.srcdocData; if (shEntry.isSrcdocEntry) entry.isSrcdocEntry = shEntry.isSrcdocEntry; if (shEntry.baseURI) entry.baseURI = shEntry.baseURI.spec; @@ -311,16 +315,19 @@ var SessionHistoryInternal = { shEntry.contentType = entry.contentType; if (entry.referrer) { shEntry.referrerURI = Utils.makeURI(entry.referrer); shEntry.referrerPolicy = entry.referrerPolicy; } if (entry.originalURI) { shEntry.originalURI = Utils.makeURI(entry.originalURI); } + if (entry.loadReplace) { + shEntry.loadReplace = entry.loadReplace; + } if (entry.isSrcdocEntry) shEntry.srcdocData = entry.srcdocData; if (entry.baseURI) shEntry.baseURI = Utils.makeURI(entry.baseURI); if (entry.cacheKey) { var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"]. createInstance(Ci.nsISupportsPRUint32);
--- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -31,72 +31,72 @@ namespace mozilla { using dom::URLParams; void PrincipalOriginAttributes::InheritFromDocShellToDoc(const DocShellOriginAttributes& aAttrs, const nsIURI* aURI) { mAppId = aAttrs.mAppId; - mInBrowser = aAttrs.mInBrowser; + mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; // TODO: // Bug 1225349 - PrincipalOriginAttributes should inherit mSignedPkg // accordingly by URI mSignedPkg = aAttrs.mSignedPkg; } void PrincipalOriginAttributes::InheritFromNecko(const NeckoOriginAttributes& aAttrs) { mAppId = aAttrs.mAppId; - mInBrowser = aAttrs.mInBrowser; + mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; mSignedPkg = aAttrs.mSignedPkg; } void DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs) { mAppId = aAttrs.mAppId; - mInBrowser = aAttrs.mInBrowser; + mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; // TODO: // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit // mSignedPkg accordingly by mSignedPkgInBrowser mSignedPkg = aAttrs.mSignedPkg; } void NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs) { mAppId = aAttrs.mAppId; - mInBrowser = aAttrs.mInBrowser; + mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; // TODO: // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit // mSignedPkg accordingly by mSignedPkgInBrowser } void NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs) { mAppId = aAttrs.mAppId; - mInBrowser = aAttrs.mInBrowser; + mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; // TODO: // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit // mSignedPkg accordingly by mSignedPkgInBrowser } @@ -114,17 +114,17 @@ OriginAttributes::CreateSuffix(nsACStrin // naming (see addonId below). // if (mAppId != nsIScriptSecurityManager::NO_APP_ID) { value.AppendInt(mAppId); params->Set(NS_LITERAL_STRING("appId"), value); } - if (mInBrowser) { + if (mInIsolatedMozBrowser) { params->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); } if (!mAddonId.IsEmpty()) { if (mAddonId.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) != kNotFound) { #ifdef MOZ_CRASHREPORTER CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Crash_AddonId"), NS_ConvertUTF16toUTF8(mAddonId)); @@ -186,17 +186,17 @@ public: return true; } if (aName.EqualsLiteral("inBrowser")) { if (!aValue.EqualsLiteral("1")) { return false; } - mOriginAttributes->mInBrowser = true; + mOriginAttributes->mInIsolatedMozBrowser = true; return true; } if (aName.EqualsLiteral("addonId")) { MOZ_RELEASE_ASSERT(mOriginAttributes->mAddonId.IsEmpty()); mOriginAttributes->mAddonId.Assign(aValue); return true; } @@ -464,17 +464,17 @@ BasePrincipal::GetIsSystemPrincipal(bool { *aResult = Kind() == eSystemPrincipal; return NS_OK; } NS_IMETHODIMP BasePrincipal::GetJarPrefix(nsACString& aJarPrefix) { - mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInBrowser, aJarPrefix); + mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInIsolatedMozBrowser, aJarPrefix); return NS_OK; } NS_IMETHODIMP BasePrincipal::GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) { if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) { return NS_ERROR_FAILURE; @@ -518,19 +518,19 @@ BasePrincipal::GetAppId(uint32_t* aAppId NS_IMETHODIMP BasePrincipal::GetUserContextId(uint32_t* aUserContextId) { *aUserContextId = UserContextId(); return NS_OK; } NS_IMETHODIMP -BasePrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement) +BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) { - *aIsInBrowserElement = IsInBrowserElement(); + *aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement(); return NS_OK; } NS_IMETHODIMP BasePrincipal::GetUnknownAppId(bool* aUnknownAppId) { *aUnknownAppId = AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID; return NS_OK;
--- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -25,17 +25,17 @@ namespace mozilla { // Base OriginAttributes class. This has several subclass flavors, and is not // directly constructable itself. class OriginAttributes : public dom::OriginAttributesDictionary { public: bool operator==(const OriginAttributes& aOther) const { return mAppId == aOther.mAppId && - mInBrowser == aOther.mInBrowser && + mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser && mAddonId == aOther.mAddonId && mUserContextId == aOther.mUserContextId && mSignedPkg == aOther.mSignedPkg; } bool operator!=(const OriginAttributes& aOther) const { return !(*this == aOther); } @@ -70,20 +70,20 @@ class NeckoOriginAttributes; // flavors, and a variety of InheritFrom* methods to implement the transfer // behavior. // For OriginAttributes stored on principals. class PrincipalOriginAttributes : public OriginAttributes { public: PrincipalOriginAttributes() {} - PrincipalOriginAttributes(uint32_t aAppId, bool aInBrowser) + PrincipalOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) { mAppId = aAppId; - mInBrowser = aInBrowser; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; } // Inheriting OriginAttributes from docshell to document when user navigates. // // @param aAttrs Origin Attributes of the docshell. // @param aURI The URI of the document. void InheritFromDocShellToDoc(const DocShellOriginAttributes& aAttrs, const nsIURI* aURI); @@ -92,39 +92,39 @@ public: void InheritFromNecko(const NeckoOriginAttributes& aAttrs); }; // For OriginAttributes stored on docshells / loadcontexts / browsing contexts. class DocShellOriginAttributes : public OriginAttributes { public: DocShellOriginAttributes() {} - DocShellOriginAttributes(uint32_t aAppId, bool aInBrowser) + DocShellOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) { mAppId = aAppId; - mInBrowser = aInBrowser; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; } // Inheriting OriginAttributes from document to child docshell when an // <iframe> is created. // // @param aAttrs Origin Attributes of the document. void InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs); }; // For OriginAttributes stored on Necko. class NeckoOriginAttributes : public OriginAttributes { public: NeckoOriginAttributes() {} - NeckoOriginAttributes(uint32_t aAppId, bool aInBrowser) + NeckoOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) { mAppId = aAppId; - mInBrowser = aInBrowser; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; } // Inheriting OriginAttributes from document to necko when a network request // is made. void InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs); void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs); }; @@ -154,17 +154,17 @@ public: // Performs a match of |aAttrs| against this pattern. bool Matches(const OriginAttributes& aAttrs) const { if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) { return false; } - if (mInBrowser.WasPassed() && mInBrowser.Value() != aAttrs.mInBrowser) { + if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) { return false; } if (mAddonId.WasPassed() && mAddonId.Value() != aAttrs.mAddonId) { return false; } if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) { @@ -210,33 +210,33 @@ public: NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override; NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override; NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override; NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final; NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final; NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final; NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final; NS_IMETHOD GetAppId(uint32_t* aAppStatus) final; - NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) final; + NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final; NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final; NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final; virtual bool IsOnCSSUnprefixingWhitelist() override { return false; } virtual bool IsCodebasePrincipal() const { return false; }; static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); } static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs); static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin); const PrincipalOriginAttributes& OriginAttributesRef() { return mOriginAttributes; } uint32_t AppId() const { return mOriginAttributes.mAppId; } uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; } - bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; } + bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; } enum PrincipalKind { eNullPrincipal, eCodebasePrincipal, eExpandedPrincipal, eSystemPrincipal };
--- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -298,20 +298,23 @@ interface nsIPrincipal : nsISerializable /** * Gets the id of the user context this principal is inside. If this * principal is inside the default userContext, this returns * nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID. */ [infallible] readonly attribute unsigned long userContextId; /** - * Returns true iff the principal is inside a browser element. (<iframe - * mozbrowser mozapp> does not count as a browser element.) + * Returns true iff the principal is inside an isolated mozbrowser element. + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. <iframe mozbrowser noisolation> does not count as + * isolated since isolation is disabled. Isolation can only be disabled if + * the containing document is chrome. */ - [infallible] readonly attribute boolean isInBrowserElement; + [infallible] readonly attribute boolean isInIsolatedMozBrowserElement; /** * Returns true if this principal has an unknown appId. This shouldn't * generally be used. We only expose it due to not providing the correct * appId everywhere where we construct principals. */ [infallible] readonly attribute boolean unknownAppId;
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -255,23 +255,35 @@ nsScriptSecurityManager::SecurityHashURI { return NS_SecurityHashURI(aURI); } uint16_t nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin) { uint32_t appId = aPrin->GetAppId(); - bool inMozBrowser = aPrin->GetIsInBrowserElement(); + + // After bug 1238160, the principal no longer knows how to answer "is this a + // browser element", which is really what this code path wants. Currently, + // desktop is the only platform where we intend to disable isolation on a + // browser frame, so non-desktop should be able to assume that + // inIsolatedMozBrowser is true for all mozbrowser frames. Additionally, + // apps are no longer used on desktop, so appId is always NO_APP_ID. We use + // a release assertion in nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so + // that platforms with apps can assume inIsolatedMozBrowser is true for all + // mozbrowser frames. + bool inIsolatedMozBrowser = aPrin->GetIsInIsolatedMozBrowserElement(); + NS_WARN_IF_FALSE(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID, "Asking for app status on a principal with an unknown app id"); // Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID) // and they are not inside a mozbrowser. if (appId == nsIScriptSecurityManager::NO_APP_ID || - appId == nsIScriptSecurityManager::UNKNOWN_APP_ID || inMozBrowser) + appId == nsIScriptSecurityManager::UNKNOWN_APP_ID || + inIsolatedMozBrowser) { return nsIPrincipal::APP_STATUS_NOT_INSTALLED; } nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED); nsCOMPtr<mozIApplication> app; @@ -286,17 +298,17 @@ nsScriptSecurityManager::AppStatusForPri NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin), nsIPrincipal::APP_STATUS_NOT_INSTALLED); nsCOMPtr<nsIURI> appURI; NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin), nsIPrincipal::APP_STATUS_NOT_INSTALLED); // The app could contain a cross-origin iframe - make sure that the content // is actually same-origin with the app. - MOZ_ASSERT(inMozBrowser == false, "Checked this above"); + MOZ_ASSERT(inIsolatedMozBrowser == false, "Checked this above"); PrincipalOriginAttributes attrs(appId, false); nsCOMPtr<nsIPrincipal> appPrin = BasePrincipal::CreateCodebasePrincipal(appURI, attrs); NS_ENSURE_TRUE(appPrin, nsIPrincipal::APP_STATUS_NOT_INSTALLED); return aPrin->Equals(appPrin) ? status : nsIPrincipal::APP_STATUS_NOT_INSTALLED; } /* @@ -585,17 +597,17 @@ nsScriptSecurityManager::CheckLoadURIFro * CheckLoadURIWithPrincipal means denying loading if the given URI has certain * nsIProtocolHandler flags set. * @return if success, access is allowed. Otherwise, deny access */ static nsresult DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags) { NS_PRECONDITION(aURI, "Must have URI!"); - + bool uriHasFlags; nsresult rv = NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags); NS_ENSURE_SUCCESS(rv, rv); if (uriHasFlags) { return NS_ERROR_DOM_BAD_URI; } @@ -719,17 +731,17 @@ nsScriptSecurityManager::CheckLoadURIWit } // None of our whitelisted principals worked. return NS_ERROR_DOM_BAD_URI; } NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal " "must have a URI!"); return NS_ERROR_UNEXPECTED; } - + // Automatic loads are not allowed from certain protocols. if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) { nsresult rv = DenyAccessIfURIHasFlags(sourceURI, nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT); NS_ENSURE_SUCCESS(rv, rv); } @@ -953,17 +965,17 @@ nsScriptSecurityManager::CheckLoadURIWit if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIConsoleService> console( do_GetService("@mozilla.org/consoleservice;1")); NS_ENSURE_TRUE(console, NS_ERROR_FAILURE); console->LogStringMessage(message.get()); } } - + return NS_OK; } nsresult nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag, nsIURI* aSource, nsIURI* aTarget) { nsresult rv; @@ -1165,23 +1177,23 @@ nsScriptSecurityManager::CreateExpandedP nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals); p.forget(aResult); return NS_OK; } NS_IMETHODIMP nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, - bool aInMozBrowser, + bool aInIsolatedMozBrowser, nsIPrincipal** aPrincipal) { NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID, NS_ERROR_INVALID_ARG); - PrincipalOriginAttributes attrs(aAppId, aInMozBrowser); + PrincipalOriginAttributes attrs(aAppId, aInIsolatedMozBrowser); nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsScriptSecurityManager:: GetLoadContextCodebasePrincipal(nsIURI* aURI, @@ -1561,50 +1573,50 @@ nsScriptSecurityManager::InitPrefs() Preferences::AddStrongObservers(this, kObservedPrefs); return NS_OK; } namespace mozilla { void -GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix) +GetJarPrefix(uint32_t aAppId, bool aInIsolatedMozBrowser, nsACString& aJarPrefix) { MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { aAppId = nsIScriptSecurityManager::NO_APP_ID; } aJarPrefix.Truncate(); // Fallback. - if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) { + if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInIsolatedMozBrowser) { return; } // aJarPrefix = appId + "+" + { 't', 'f' } + "+"; aJarPrefix.AppendInt(aAppId); aJarPrefix.Append('+'); - aJarPrefix.Append(aInMozBrowser ? 't' : 'f'); + aJarPrefix.Append(aInIsolatedMozBrowser ? 't' : 'f'); aJarPrefix.Append('+'); return; } } // namespace mozilla NS_IMETHODIMP nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId, - bool aInMozBrowser, + bool aInIsolatedMozBrowser, nsACString& aJarPrefix) { MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); - mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix); + mozilla::GetJarPrefix(aAppId, aInIsolatedMozBrowser, aJarPrefix); return NS_OK; } NS_IMETHODIMP nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv) { *aRv = !!mDomainPolicy; return NS_OK; @@ -1689,9 +1701,8 @@ nsScriptSecurityManager::PolicyAllowsScr rv = superExceptions->ContainsSuperDomain(aURI, &contains); NS_ENSURE_SUCCESS(rv, rv); if (contains) { *aRv = !*aRv; } return NS_OK; } -
--- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -146,14 +146,14 @@ private: static nsIStringBundle *sStrBundle; static JSRuntime *sRuntime; }; namespace mozilla { void GetJarPrefix(uint32_t aAppid, - bool aInMozBrowser, + bool aInIsolatedMozBrowser, nsACString& aJarPrefix); } // namespace mozilla #endif // nsScriptSecurityManager_h__
--- a/caps/tests/gtest/TestOriginAttributes.cpp +++ b/caps/tests/gtest/TestOriginAttributes.cpp @@ -19,19 +19,19 @@ TestSuffix(const PrincipalOriginAttribut } TEST(PrincipalOriginAttributes, Suffix_default) { PrincipalOriginAttributes attrs; TestSuffix(attrs); } -TEST(PrincipalOriginAttributes, Suffix_appId_inBrowser) +TEST(PrincipalOriginAttributes, Suffix_appId_inIsolatedMozBrowser) { PrincipalOriginAttributes attrs(1, true); TestSuffix(attrs); } -TEST(PrincipalOriginAttributes, Suffix_maxAppId_inBrowser) +TEST(PrincipalOriginAttributes, Suffix_maxAppId_inIsolatedMozBrowser) { PrincipalOriginAttributes attrs(4294967295, true); TestSuffix(attrs); }
--- a/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html +++ b/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html @@ -28,16 +28,18 @@ SimpleTest.waitForExplicitFinish(); * - app: gives the app manifest URL, will set mozapp to it on the iframe; * - origin: gives the origin of the iframe. This is the URL thas is going to * to be passed as iframe.src but also the expected principal's * origin. * - isapp: tells if the iframe is really a mozapp. If the manifest url isn't * valid, the iframe will not be considered as a mozapp. * - browser: say if the iframe should be a mozbrowser. This is implicit when * app is set. + * - isolated: if origin isolation is enabled with browser frames. Defaults to + * true if unset. * - test: an array of tests to run for this test case: * - eo-unique: the extendedOrigin of the prinicpal must be unique in the * current list. * - eo-as-last: the extendedOrigin of the principal must be the same as the * last added to the list. */ var gData = [ { @@ -225,25 +227,68 @@ var gData = [ browser: false, child: { src: "http://example.org/chrome/", isapp: false, browser: true, }, test: [ "child-has-different-eo", "child-has-same-appstatus", "child-has-same-appid" ], }, - // browser containing an iframe is part of the browser + // browser containing an iframe that is part of the browser { src: "http://example.org/", isapp: false, browser: true, child: { src: "http://example.org/chrome/", isapp: false, - inBrowser: true, + inIsolatedMozBrowser: true, + }, + test: [ "child-has-same-eo" ], + }, + // iframe containing a browser with isolation disabled + // (only chrome documents can disable isolation) + { + src: "http://example.org/", + isapp: false, + browser: false, + child: { + src: "http://example.org/chrome/", + isapp: false, + browser: true, + isolated: false, + inIsolatedMozBrowser: true, + }, + test: [ "child-has-different-eo" ], + }, + // browser with isolation disabled containing an iframe that is part of the browser + { + src: "http://example.org/", + isapp: false, + browser: true, + isolated: false, + child: { + src: "http://example.org/chrome/", + isapp: false, + inIsolatedMozBrowser: false, + }, + test: [ "child-has-same-eo" ], + }, + // iframe with isolation enabled containing an iframe with isolation disabled + // (isolated only has an effect on browsers) + { + src: "http://example.org/", + isapp: false, + browser: false, + isolated: true, + child: { + src: "http://example.org/chrome/", + isapp: false, + browser: false, + isolated: false, }, test: [ "child-has-same-eo" ], }, ]; // The list of all data ids generated by this test. var eoList = []; @@ -275,46 +320,60 @@ function checkIFrame(aFrame, data) { } } else { is(principal.appStatus, Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED, 'this should not be an installed app'); is(principal.appId, Ci.nsIScriptSecurityManager.NO_APP_ID, "principals from non-installed app should have NO_APP_ID"); } - if (!data.isapp && !data.browser) { + if (!data.isapp && !data.browser || + (data.browser && data.isolated === false)) { is(principal.jarPrefix, "", - 'jarPrefix should return an empty string for non-app and non-browsers principals'); + "jarPrefix should return an empty string for non-app, non-browsers, " + + "and browsers with isolation disabled"); } else { isnot(principal.jarPrefix, "", - 'jarPrefix should not return an empty string for apps or mozbrowsers'); + "jarPrefix should not return an empty string for apps or browsers " + + "with isolation enabled"); } if (data.test.indexOf("eo-unique") != -1) { is(eoList.indexOf(principal.jarPrefix + principal.origin), -1, "extended origin should be unique"); } if (data.test.indexOf("eo-as-last") != -1) { is(principal.jarPrefix + principal.origin, eoList[eoList.length-1], "extended origin should be the same as the last inserted one"); } - is(principal.isInBrowserElement, !!data.browser, - "check principal.isInBrowserElement"); + let isolationExpected = false; + if (data.isolated !== false) { + isolationExpected = !!data.browser; + } + is(principal.isInIsolatedMozBrowserElement, isolationExpected, + "check principal.isInIsolatedMozBrowserElement"); if (data.child) { let childPrincipal = aFrame.contentWindow.frames[0].document.nodePrincipal; if (data.child.isapp) { is(childPrincipal.appStatus, Ci.nsIPrincipal.APP_STATUS_INSTALLED, "child should be an installed app"); } - is(childPrincipal.isInBrowserElement, !!data.child.browser || !!data.child.inBrowser, - "check childPrincipal.isInBrowserElement"); + let childIsolationExpected = false; + if (data.child.isolated !== false) { + childIsolationExpected = !!data.child.browser; + } + if (data.child.inIsolatedMozBrowser !== undefined) { + childIsolationExpected = data.child.inIsolatedMozBrowser; + } + is(childPrincipal.isInIsolatedMozBrowserElement, childIsolationExpected, + "check childPrincipal.isInIsolatedMozBrowserElement"); if (data.test.indexOf("child-has-same-eo") != -1) { is(childPrincipal.jarPrefix + childPrincipal.origin, principal.jarPrefix + principal.origin, "child should have the same extended origin as parent"); is(childPrincipal.appStatus, principal.appStatus, "child should have the same appStatus if it has the same extended origin"); is(childPrincipal.appId, principal.appId, @@ -387,46 +446,55 @@ function runTest() { if (data.child.app) { childFrame.setAttribute('mozapp', data.child.app) childFrame.setAttribute('mozbrowser', ''); } else if (data.child.browser) { childFrame.setAttribute('mozbrowser', ''); } + if (data.child.isolated === false) { + childFrame.setAttribute("noisolation", ""); + } + childFrame.src = data.child.src; this.removeEventListener('load', this.addChild.bind(this)); childFrame.addEventListener('load', this.check.bind(this)); this.contentDocument.body.appendChild(childFrame); }; if (data.app) { iframe.setAttribute('mozapp', data.app); iframe.setAttribute('mozbrowser', ''); } else if (data.browser) { iframe.setAttribute('mozbrowser', ''); } + if (data.isolated === false) { + iframe.setAttribute("noisolation", ""); + } + iframe.src = data.src; if (data.child) { iframe.addEventListener('load', iframe.addChild.bind(iframe)); } else { iframe.addEventListener('load', iframe.check.bind(iframe)); } content.appendChild(iframe); yield; } } var gTestRunner = runTest(); -SpecialPowers.pushPrefEnv({'set':[["dom.mozBrowserFramesEnabled", true]]}, - function() { gTestRunner.next(); }); +SpecialPowers.pushPrefEnv({"set": [ + ["dom.mozBrowserFramesEnabled", true], +]}, function() { gTestRunner.next(); }); </script> </pre> </body> </html>
--- a/caps/tests/unit/test_origin.js +++ b/caps/tests/unit/test_origin.js @@ -19,45 +19,45 @@ function checkCrossOrigin(a, b) { do_check_false(a.subsumesConsideringDomain(b)); do_check_false(b.subsumes(a)); do_check_false(b.subsumesConsideringDomain(a)); } function checkOriginAttributes(prin, attrs, suffix) { attrs = attrs || {}; do_check_eq(prin.originAttributes.appId, attrs.appId || 0); - do_check_eq(prin.originAttributes.inBrowser, attrs.inBrowser || false); + do_check_eq(prin.originAttributes.inIsolatedMozBrowser, attrs.inIsolatedMozBrowser || false); do_check_eq(prin.originSuffix, suffix || ''); do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), suffix || ''); do_check_true(ChromeUtils.originAttributesMatchPattern(prin.originAttributes, attrs)); if (!prin.isNullPrincipal && !prin.origin.startsWith('[')) { do_check_true(ssm.createCodebasePrincipalFromOrigin(prin.origin).equals(prin)); } else { checkThrows(() => ssm.createCodebasePrincipalFromOrigin(prin.origin)); } } // utility function useful for debugging function printAttrs(name, attrs) { do_print(name + " {\n" + "\tappId: " + attrs.appId + ",\n" + "\tuserContextId: " + attrs.userContextId + ",\n" + - "\tinBrowser: " + attrs.inBrowser + ",\n" + + "\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" + "\taddonId: '" + attrs.addonId + "',\n" + "\tsignedPkg: '" + attrs.signedPkg + "'\n}"); } function checkValues(attrs, values) { values = values || {}; //printAttrs("attrs", attrs); //printAttrs("values", values); do_check_eq(attrs.appId, values.appId || 0); do_check_eq(attrs.userContextId, values.userContextId || 0); - do_check_eq(attrs.inBrowser, values.inBrowser || false); + do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false); do_check_eq(attrs.addonId, values.addonId || ''); do_check_eq(attrs.signedPkg, values.signedPkg || ''); } function run_test() { // Attributeless origins. do_check_eq(ssm.getSystemPrincipal().origin, '[System Principal]'); checkOriginAttributes(ssm.getSystemPrincipal()); @@ -94,32 +94,32 @@ function run_test() { // Just app. var exampleOrg_app = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 42}); var nullPrin_app = ssm.createNullPrincipal({appId: 42}); checkOriginAttributes(exampleOrg_app, {appId: 42}, '^appId=42'); checkOriginAttributes(nullPrin_app, {appId: 42}, '^appId=42'); do_check_eq(exampleOrg_app.origin, 'http://example.org^appId=42'); // Just browser. - var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true}); - var nullPrin_browser = ssm.createNullPrincipal({inBrowser: true}); - checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '^inBrowser=1'); - checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '^inBrowser=1'); + var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true}); + var nullPrin_browser = ssm.createNullPrincipal({inIsolatedMozBrowser: true}); + checkOriginAttributes(exampleOrg_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1'); + checkOriginAttributes(nullPrin_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1'); do_check_eq(exampleOrg_browser.origin, 'http://example.org^inBrowser=1'); // App and browser. - var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true, appId: 42}); - var nullPrin_appBrowser = ssm.createNullPrincipal({inBrowser: true, appId: 42}); - checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1'); - checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1'); + var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true, appId: 42}); + var nullPrin_appBrowser = ssm.createNullPrincipal({inIsolatedMozBrowser: true, appId: 42}); + checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); + checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org^appId=42&inBrowser=1'); // App and browser, different domain. - var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inBrowser: true}); - checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1'); + var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inIsolatedMozBrowser: true}); + checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1'); do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123^appId=42&inBrowser=1'); // Addon. var exampleOrg_addon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy'}); checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy'); do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy'); // Make sure we don't crash when serializing principals with UNKNOWN_APP_ID. @@ -156,18 +156,18 @@ function run_test() { do_check_eq(exampleOrg_userContextApp.origin, 'http://example.org^appId=24&userContextId=42'); // Just signedPkg var exampleOrg_signedPkg = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever'}); checkOriginAttributes(exampleOrg_signedPkg, { signedPkg: 'whatever' }, '^signedPkg=whatever'); do_check_eq(exampleOrg_signedPkg.origin, 'http://example.org^signedPkg=whatever'); // signedPkg and browser - var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inBrowser: true}); - checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inBrowser: true }, '^inBrowser=1&signedPkg=whatever'); + var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inIsolatedMozBrowser: true}); + checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inIsolatedMozBrowser: true }, '^inBrowser=1&signedPkg=whatever'); do_check_eq(exampleOrg_signedPkg_browser.origin, 'http://example.org^inBrowser=1&signedPkg=whatever'); // Just signedPkg (but different value from 'exampleOrg_signedPkg_app') var exampleOrg_signedPkg_another = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatup'}); // Check that all of the above are cross-origin. checkCrossOrigin(exampleOrg_app, exampleOrg); checkCrossOrigin(exampleOrg_app, nullPrin_app); @@ -207,20 +207,20 @@ function run_test() { checkValues(emptyAttrs); var uri = "http://example.org"; var tests = [ [ "", {} ], [ "^appId=5", {appId: 5} ], [ "^userContextId=3", {userContextId: 3} ], [ "^addonId=fooBar", {addonId: "fooBar"} ], - [ "^inBrowser=1", {inBrowser: true} ], + [ "^inBrowser=1", {inIsolatedMozBrowser: true} ], [ "^signedPkg=bazQux", {signedPkg: "bazQux"} ], [ "^appId=3&inBrowser=1&userContextId=6", - {appId: 3, userContextId: 6, inBrowser: true} ] ]; + {appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ]; // check that we can create an origin attributes from an origin properly tests.forEach(function(t) { let attrs = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]); checkValues(attrs, t[1]); do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]); });
--- a/devtools/client/netmonitor/test/browser.ini +++ b/devtools/client/netmonitor/test/browser.ini @@ -109,16 +109,17 @@ skip-if = e10s # Bug 1091612 [browser_net_security-warnings.js] [browser_net_send-beacon.js] [browser_net_send-beacon-other-tab.js] [browser_net_simple-init.js] [browser_net_simple-request-data.js] [browser_net_simple-request-details.js] [browser_net_simple-request.js] [browser_net_sort-01.js] +skip-if = (e10s && debug && os == 'mac') # Bug 1253037 [browser_net_sort-02.js] [browser_net_sort-03.js] [browser_net_statistics-01.js] [browser_net_statistics-02.js] [browser_net_statistics-03.js] [browser_net_status-codes.js] [browser_net_timeline_ticks.js] [browser_net_timing-division.js]
--- a/devtools/shared/layout/utils.js +++ b/devtools/shared/layout/utils.js @@ -29,17 +29,17 @@ const utilsFor = memoize( * @param {DOMWindow} win * @return {DOMWindow} */ function getTopWindow(win) { let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); - if (!docShell.isBrowserOrApp) { + if (!docShell.isMozBrowserOrApp) { return win.top; } let topDocShell = docShell.getSameTypeRootTreeItemIgnoreBrowserAndAppBoundaries(); return topDocShell ? topDocShell.contentViewer.DOMDocument.defaultView : null; @@ -89,17 +89,17 @@ function getParentWindow(win) { if (isTopWindow(win)) { return null; } let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); - if (!docShell.isBrowserOrApp) { + if (!docShell.isMozBrowserOrApp) { return win.parent; } let parentDocShell = docShell.getSameTypeParentIgnoreBrowserAndAppBoundaries(); return parentDocShell ? parentDocShell.contentViewer.DOMDocument.defaultView : null;
--- a/docshell/base/LoadContext.cpp +++ b/docshell/base/LoadContext.cpp @@ -29,17 +29,17 @@ nsILoadContext::GetOriginAttributes(mozi JSAutoCompartment ac(jsapi.cx(), obj); mozilla::DocShellOriginAttributes attrs; ok = attrs.Init(jsapi.cx(), v); NS_ENSURE_TRUE(ok, false); aAttrs = attrs; return true; } - + namespace mozilla { NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor) LoadContext::LoadContext(nsIPrincipal* aPrincipal, nsILoadContext* aOptionalBase) : mTopFrameElement(nullptr) , mNestedFrameId(0) @@ -167,23 +167,23 @@ LoadContext::SetRemoteTabs(bool aUseRemo { MOZ_ASSERT(mIsNotNull); // We shouldn't need this on parent... return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement) +LoadContext::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) { MOZ_ASSERT(mIsNotNull); - NS_ENSURE_ARG_POINTER(aIsInBrowserElement); + NS_ENSURE_ARG_POINTER(aIsInIsolatedMozBrowserElement); - *aIsInBrowserElement = mOriginAttributes.mInBrowser; + *aIsInIsolatedMozBrowserElement = mOriginAttributes.mInIsolatedMozBrowser; return NS_OK; } NS_IMETHODIMP LoadContext::GetAppId(uint32_t* aAppId) { MOZ_ASSERT(mIsNotNull);
--- a/docshell/base/LoadContext.h +++ b/docshell/base/LoadContext.h @@ -34,35 +34,35 @@ class LoadContext final : public nsILoadContext , public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS NS_DECL_NSILOADCONTEXT NS_DECL_NSIINTERFACEREQUESTOR - // AppId/inBrowser arguments override those in SerializedLoadContext provided - // by child process. + // appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext + // provided by child process. LoadContext(const IPC::SerializedLoadContext& aToCopy, dom::Element* aTopFrameElement, DocShellOriginAttributes& aAttrs) : mTopFrameElement(do_GetWeakReference(aTopFrameElement)) , mNestedFrameId(0) , mIsContent(aToCopy.mIsContent) , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing) , mUseRemoteTabs(aToCopy.mUseRemoteTabs) , mOriginAttributes(aAttrs) #ifdef DEBUG , mIsNotNull(aToCopy.mIsNotNull) #endif { } - // AppId/inBrowser arguments override those in SerializedLoadContext provided - // by child process. + // appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext + // provided by child process. LoadContext(const IPC::SerializedLoadContext& aToCopy, uint64_t aNestedFrameId, DocShellOriginAttributes& aAttrs) : mTopFrameElement(nullptr) , mNestedFrameId(aNestedFrameId) , mIsContent(aToCopy.mIsContent) , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing) , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
--- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -327,17 +327,17 @@ nsDSURIContentListener::CheckOneFrameOpt // Traverse up the parent chain and stop when we see a docshell whose // parent has a system principal, or a docshell corresponding to // <iframe mozbrowser>. while (NS_SUCCEEDED( curDocShellItem->GetParent(getter_AddRefs(parentDocShellItem))) && parentDocShellItem) { nsCOMPtr<nsIDocShell> curDocShell = do_QueryInterface(curDocShellItem); - if (curDocShell && curDocShell->GetIsBrowserOrApp()) { + if (curDocShell && curDocShell->GetIsMozBrowserOrApp()) { break; } bool system = false; topDoc = parentDocShellItem->GetDocument(); if (topDoc) { if (NS_SUCCEEDED( ssm->IsSystemPrincipal(topDoc->NodePrincipal(), &system)) &&
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -775,16 +775,17 @@ nsDocShell::nsDocShell() , mAllowContentRetargetingOnChildren(true) , mCreatingDocument(false) , mUseErrorPages(false) , mObserveErrorPages(true) , mAllowAuth(true) , mAllowKeywordFixup(false) , mIsOffScreenBrowser(false) , mIsActive(true) + , mDisableMetaRefreshWhenInactive(false) , mIsPrerendered(false) , mIsAppTab(false) , mUseGlobalHistory(false) , mInPrivateBrowsing(false) , mUseRemoteTabs(false) , mDeviceSizeIsPageSize(false) , mWindowDraggingAllowed(false) , mInFrameSwap(false) @@ -800,16 +801,17 @@ nsDocShell::nsDocShell() , mInEnsureScriptEnv(false) #endif , mAffectPrivateSessionLifetime(true) , mInvisible(false) , mHasLoadedNonBlankURI(false) , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL) , mBlankTiming(false) , mFrameType(eFrameTypeRegular) + , mIsInIsolatedMozBrowser(false) , mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID) , mUserContextId(nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) , mParentCharsetSource(0) , mJSRunToCompletionDepth(0) { mHistoryID = ++gDocshellIDCounter; if (gDocShellCount++ == 0) { NS_ASSERTION(sURIFixup == nullptr, @@ -879,26 +881,23 @@ nsresult nsDocShell::Init() { nsresult rv = nsDocLoader::Init(); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(mLoadGroup, "Something went wrong!"); mContentListener = new nsDSURIContentListener(this); - NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY); - rv = mContentListener->Init(); NS_ENSURE_SUCCESS(rv, rv); // We want to hold a strong ref to the loadgroup, so it better hold a weak // ref to us... use an InterfaceRequestorProxy to do this. nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this)); - NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY); mLoadGroup->SetNotificationCallbacks(proxy); rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this); NS_ENSURE_SUCCESS(rv, rv); // Add as |this| a progress listener to itself. A little weird, but // simpler than reproducing all the listener-notification logic in // overrides of the various methods via which nsDocLoader can be @@ -1645,17 +1644,16 @@ nsDocShell::LoadStream(nsIInputStream* a NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo) { nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo(); - NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo); localRef.forget(aLoadInfo); return NS_OK; } /* * Reset state to a new content model within the current document and the @@ -2551,17 +2549,17 @@ nsDocShell::GetFullscreenAllowed(bool* a // Otherwise, we have a parent, continue the checking for // mozFullscreenAllowed in the parent docshell's ancestors. return parent->GetFullscreenAllowed(aFullscreenAllowed); } NS_IMETHODIMP nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed) { - if (!nsIDocShell::GetIsBrowserOrApp()) { + if (!nsIDocShell::GetIsMozBrowserOrApp()) { // Only allow setting of fullscreenAllowed on content/process boundaries. // At non-boundaries the fullscreenAllowed attribute is calculated based on // whether all enclosing frames have the "mozFullscreenAllowed" attribute // set to "true". fullscreenAllowed is set at the process boundaries to // propagate the value of the parent's "mozFullscreenAllowed" attribute // across process boundaries. return NS_ERROR_UNEXPECTED; } @@ -2610,20 +2608,16 @@ nsDocShell::GetDocShellEnumerator(int32_ RefPtr<nsDocShellEnumerator> docShellEnum; if (aDirection == ENUMERATE_FORWARDS) { docShellEnum = new nsDocShellForwardsEnumerator; } else { docShellEnum = new nsDocShellBackwardsEnumerator; } - if (!docShellEnum) { - return NS_ERROR_OUT_OF_MEMORY; - } - nsresult rv = docShellEnum->SetEnumDocShellType(aItemType); if (NS_FAILED(rv)) { return rv; } rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this); if (NS_FAILED(rv)) { return rv; @@ -3359,17 +3353,17 @@ nsDocShell::SetDocLoaderParent(nsDocLoad } NS_IMETHODIMP nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent) { NS_ENSURE_ARG_POINTER(aParent); *aParent = nullptr; - if (nsIDocShell::GetIsBrowserOrApp()) { + if (nsIDocShell::GetIsMozBrowserOrApp()) { return NS_OK; } nsCOMPtr<nsIDocShellTreeItem> parent = do_QueryInterface(GetAsSupports(mParent)); if (!parent) { return NS_OK; } @@ -3495,17 +3489,18 @@ nsDocShell::CanAccessItem(nsIDocShellTre nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem); nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem); if (!targetDS || !accessingDS) { // We must be able to convert both to nsIDocShell. return false; } - if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() || + if (targetDS->GetIsInIsolatedMozBrowserElement() != + accessingDS->GetIsInIsolatedMozBrowserElement() || targetDS->GetAppId() != accessingDS->GetAppId()) { return false; } // A private document can't access a non-private one, and vice versa. if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() != static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) { return false; @@ -4010,16 +4005,17 @@ nsDocShell::AddChild(nsIDocShellTreeItem } if (aChild->ItemType() != mItemType) { return NS_OK; } aChild->SetTreeOwner(mTreeOwner); childDocShell->SetUserContextId(mUserContextId); + childDocShell->SetIsInIsolatedMozBrowserElement(mIsInIsolatedMozBrowser); nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild)); if (!childAsDocShell) { return NS_OK; } // charset, style-disabling, and zoom will be inherited in SetupNewViewer() @@ -5630,16 +5626,20 @@ nsDocShell::Create() if (!gAddedPreferencesVarCache) { Preferences::AddBoolVarCache(&sUseErrorPages, "browser.xul.error_pages.enabled", mUseErrorPages); gAddedPreferencesVarCache = true; } + mDisableMetaRefreshWhenInactive = + Preferences::GetBool("browser.meta_refresh_when_inactive.disabled", + mDisableMetaRefreshWhenInactive); + mDeviceSizeIsPageSize = Preferences::GetBool("docshell.device_size_is_page_size", mDeviceSizeIsPageSize); nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); if (serv) { const char* msg = mItemType == typeContent ? NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE; @@ -5815,20 +5815,24 @@ nsDocShell::SetPosition(int32_t aX, int3 } return NS_OK; } NS_IMETHODIMP nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY) { - // Added to nsIBaseWindow in bug 1247335; - // implement if a use-case is found. - NS_ASSERTION(false, "implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; + nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner)); + if (ownerWindow) { + return ownerWindow->SetPositionDesktopPix(aX, aY); + } + + double scale = 1.0; + GetDevicePixelsPerDesktopPixel(&scale); + return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale)); } NS_IMETHODIMP nsDocShell::GetPosition(int32_t* aX, int32_t* aY) { return GetPositionAndSize(aX, aY, nullptr, nullptr); } @@ -6119,25 +6123,34 @@ nsDocShell::SetIsActiveInternal(bool aIs // children; they handle their state separately. nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); while (iter.HasMore()) { nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); if (!docshell) { continue; } - if (!docshell->GetIsBrowserOrApp()) { + if (!docshell->GetIsMozBrowserOrApp()) { if (aIsHidden) { docshell->SetIsActive(aIsActive); } else { docshell->SetIsActiveAndForeground(aIsActive); } } } + // Restart or stop meta refresh timers if necessary + if (mDisableMetaRefreshWhenInactive) { + if (mIsActive) { + ResumeRefreshURIs(); + } else { + SuspendRefreshURIs(); + } + } + return NS_OK; } NS_IMETHODIMP nsDocShell::GetIsActive(bool* aIsActive) { *aIsActive = mIsActive; return NS_OK; @@ -6573,37 +6586,35 @@ nsDocShell::RefreshURI(nsIURI* aURI, int if (NS_FAILED(rv)) { sameURI = false; } if (!RefreshAttempted(this, aURI, aDelay, sameURI)) { return NS_OK; } nsRefreshTimer* refreshTimer = new nsRefreshTimer(); - NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY); uint32_t busyFlags = 0; GetBusyFlags(&busyFlags); nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1 refreshTimer->mDocShell = this; refreshTimer->mURI = aURI; refreshTimer->mDelay = aDelay; refreshTimer->mRepeat = aRepeat; refreshTimer->mMetaRefresh = aMetaRefresh; if (!mRefreshURIList) { NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)), NS_ERROR_FAILURE); } - if (busyFlags & BUSY_FLAGS_BUSY) { - // We are busy loading another page. Don't create the - // timer right now. Instead queue up the request and trigger the - // timer in EndPageLoad(). + if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) { + // We don't want to create the timer right now. Instead queue up the request + // and trigger the timer in EndPageLoad() or whenever we become active. mRefreshURIList->AppendElement(refreshTimer); } else { // There is no page loading going on right now. Create the // timer and fire it right away. nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1"); NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE); mRefreshURIList->AppendElement(timer); // owning timer ref @@ -7546,17 +7557,18 @@ nsDocShell::EndPageLoad(nsIWebProgress* mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory); // Clear the mLSHE reference to indicate document loading is done one // way or another. SetHistoryEntry(&mLSHE, nullptr); } // if there's a refresh header in the channel, this method // will set it up for us. - RefreshURIFromQueue(); + if (mIsActive || !mDisableMetaRefreshWhenInactive) + RefreshURIFromQueue(); // Test whether this is the top frame or a subframe bool isTopFrame = true; nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem; rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem)); if (NS_SUCCEEDED(rv) && targetParentTreeItem) { isTopFrame = false; } @@ -13881,39 +13893,32 @@ nsDocShell::SetUserContextId(uint32_t aU docshell->SetUserContextId(aUserContextId); } return NS_OK; } /* [infallible] */ NS_IMETHODIMP -nsDocShell::GetIsBrowserElement(bool* aIsBrowser) -{ - *aIsBrowser = (mFrameType == eFrameTypeBrowser); - return NS_OK; -} - -/* [infallible] */ NS_IMETHODIMP nsDocShell::GetIsApp(bool* aIsApp) { *aIsApp = (mFrameType == eFrameTypeApp); return NS_OK; } /* [infallible] */ NS_IMETHODIMP -nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp) +nsDocShell::GetIsMozBrowserOrApp(bool* aIsMozBrowserOrApp) { switch (mFrameType) { case eFrameTypeRegular: - *aIsBrowserOrApp = false; + *aIsMozBrowserOrApp = false; break; case eFrameTypeBrowser: case eFrameTypeApp: - *aIsBrowserOrApp = true; + *aIsMozBrowserOrApp = true; break; } return NS_OK; } nsDocShell::FrameType nsDocShell::GetInheritedFrameType() @@ -13929,32 +13934,52 @@ nsDocShell::GetInheritedFrameType() if (!parent) { return eFrameTypeRegular; } return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType(); } /* [infallible] */ NS_IMETHODIMP -nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement) -{ - *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser); +nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement) +{ + bool result = mFrameType == eFrameTypeBrowser && mIsInIsolatedMozBrowser; + *aIsIsolatedMozBrowserElement = result; return NS_OK; } /* [infallible] */ NS_IMETHODIMP -nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp) +nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) +{ + MOZ_ASSERT(!mIsInIsolatedMozBrowser || + (GetInheritedFrameType() == eFrameTypeBrowser), + "Isolated mozbrowser should only be true inside browser frames"); + bool result = (GetInheritedFrameType() == eFrameTypeBrowser) && + mIsInIsolatedMozBrowser; + *aIsInIsolatedMozBrowserElement = result; + return NS_OK; +} + +/* [infallible] */ NS_IMETHODIMP +nsDocShell::SetIsInIsolatedMozBrowserElement(bool aIsInIsolatedMozBrowserElement) +{ + mIsInIsolatedMozBrowser = aIsInIsolatedMozBrowserElement; + return NS_OK; +} + +/* [infallible] */ NS_IMETHODIMP +nsDocShell::GetIsInMozBrowserOrApp(bool* aIsInMozBrowserOrApp) { switch (GetInheritedFrameType()) { case eFrameTypeRegular: - *aIsInBrowserOrApp = false; + *aIsInMozBrowserOrApp = false; break; case eFrameTypeBrowser: case eFrameTypeApp: - *aIsInBrowserOrApp = true; + *aIsInMozBrowserOrApp = true; break; } return NS_OK; } /* [infallible] */ NS_IMETHODIMP nsDocShell::GetAppId(uint32_t* aAppId) @@ -13990,20 +14015,17 @@ nsDocShell::GetOriginAttributes() attrs.mSignedPkg = mSignedPkg; } if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) { attrs.mAppId = mOwnOrContainingAppId; } attrs.mUserContextId = mUserContextId; - - if (mFrameType == eFrameTypeBrowser) { - attrs.mInBrowser = true; - } + attrs.mInIsolatedMozBrowser = mIsInIsolatedMozBrowser; return attrs; } NS_IMETHODIMP nsDocShell::GetOriginAttributes(JS::MutableHandle<JS::Value> aVal) { JSContext* cx = nsContentUtils::GetCurrentJSContext();
--- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -933,16 +933,17 @@ protected: bool mAllowContentRetargetingOnChildren; bool mCreatingDocument; // (should be) debugging only bool mUseErrorPages; bool mObserveErrorPages; bool mAllowAuth; bool mAllowKeywordFixup; bool mIsOffScreenBrowser; bool mIsActive; + bool mDisableMetaRefreshWhenInactive; bool mIsPrerendered; bool mIsAppTab; bool mUseGlobalHistory; bool mInPrivateBrowsing; bool mUseRemoteTabs; bool mDeviceSizeIsPageSize; bool mWindowDraggingAllowed; bool mInFrameSwap; @@ -995,16 +996,19 @@ protected: // This flag means that mTiming has been initialized but nulled out. // We will check the innerWin's timing before creating a new one // in MaybeInitTiming() bool mBlankTiming; // Are we a regular frame, a browser frame, or an app frame? FrameType mFrameType; + // Whether we are in an isolated mozbrowser frame. + bool mIsInIsolatedMozBrowser; + // We only expect mOwnOrContainingAppId to be something other than // UNKNOWN_APP_ID if mFrameType != eFrameTypeRegular. For vanilla iframes // inside an app, we'll retrieve the containing app-id by walking up the // docshell hierarchy. // // (This needs to be the docshell's own /or containing/ app id because the // containing app frame might be in another process, in which case we won't // find it by walking up the docshell hierarchy.)
--- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -759,53 +759,64 @@ interface nsIDocShell : nsIDocShellTreeI /** * Notify all attached observers that the scroll position of some element * has changed. */ [noscript] void notifyScrollObservers(); /** - * Returns true if this docshell corresponds to an <iframe mozbrowser>. - * (<iframe mozapp mozbrowser> is not considered a browser.) - */ - [infallible] readonly attribute boolean isBrowserElement; - - /** * Returns true iff the docshell corresponds to an <iframe mozapp>. */ [infallible] readonly attribute boolean isApp; /** - * Returns isBrowserElement || isApp. + * Returns true if this docshell corresponds to an <iframe mozbrowser> or + * <iframe mozapp>. <xul:browser> returns false here. */ - [infallible] readonly attribute boolean isBrowserOrApp; + [infallible] readonly attribute boolean isMozBrowserOrApp; /** - * Returns true if this docshell corresponds to an <iframe mozbrowser> or if - * the docshell is contained in an <iframe mozbrowser>. (<iframe mozapp - * mozbrowser> does not count as a browser.) + * Returns true if this docshell corresponds to an isolated <iframe + * mozbrowser>. + * + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. <iframe mozbrowser noisolation> does not count as + * isolated since isolation is disabled. Isolation can only be disabled if + * the containing document is chrome. + */ + [infallible] readonly attribute boolean isIsolatedMozBrowserElement; + + /** + * Returns true if this docshell corresponds to an isolated <iframe + * mozbrowser> or if the docshell is contained in an isolated <iframe + * mozbrowser>. + * + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. <iframe mozbrowser noisolation> does not count as + * isolated since isolation is disabled. Isolation can only be disabled if + * the containing document is chrome. * * Our notion here of "contained in" means: Walk up the docshell hierarchy in * this process until we hit an <iframe mozapp> or <iframe mozbrowser> (or * until the hierarchy ends). Return true iff the docshell we stopped on has - * isBrowserElement == true. + * isIsolatedMozBrowserElement == true. */ - [infallible] readonly attribute boolean isInBrowserElement; + [infallible] attribute boolean isInIsolatedMozBrowserElement; /** * Returns true if this docshell corresponds to an <iframe mozbrowser> or * <iframe mozapp>, or if this docshell is contained in an <iframe mozbrowser> - * or <iframe mozapp>. + * or <iframe mozapp>. <xul:browser> returns false here. * * To compute this value, we walk up the docshell hierarchy. If we encounter - * a docshell with isBrowserElement or isApp before we hit the end of the - * hierarchy, we return true. Otherwise, we return false. + * a docshell with isMozBrowserOrApp before we hit the end of the hierarchy, + * we return true. Otherwise, we return false. */ - [infallible] readonly attribute boolean isInBrowserOrApp; + [infallible] readonly attribute boolean isInMozBrowserOrApp; /** * Indicate that this docshell corresponds to an app with the given app id. * * You may pass NO_APP_ID or UNKNOWN_APP_ID for containingAppId. If you * pass NO_APP_ID, then this docshell will return NO_APP_ID for appId. If * you pass UNKNOWN_APP_ID, then this docshell will search its hiearchy for * an app frame and use that frame's appId.
--- a/docshell/base/nsILoadContext.idl +++ b/docshell/base/nsILoadContext.idl @@ -111,19 +111,23 @@ interface nsILoadContext : nsISupports [noscript] void SetPrivateBrowsing(in boolean aInPrivateBrowsing); /** * Set the remote tabs state of the load context, meant to be used internally. */ [noscript] void SetRemoteTabs(in boolean aUseRemoteTabs); /** - * Returns true iff the load is occurring inside a browser element. + * Returns true iff the load is occurring inside an isolated mozbrowser + * element. <iframe mozbrowser mozapp> and <xul:browser> are not considered to + * be mozbrowser elements. <iframe mozbrowser noisolation> does not count as + * isolated since isolation is disabled. Isolation can only be disabled if + * the containing document is chrome. */ - readonly attribute boolean isInBrowserElement; + readonly attribute boolean isInIsolatedMozBrowserElement; /** * Returns the app id of the app the load is occurring is in. Returns * nsIScriptSecurityManager::NO_APP_ID if the load is not part of an app. */ readonly attribute unsigned long appId; /**
--- a/dom/animation/AnimationTimeline.h +++ b/dom/animation/AnimationTimeline.h @@ -86,16 +86,27 @@ public: /** * Inform this timeline that |aAnimation| which is or was observing the * timeline, has been updated. This serves as both the means to associate * AND disassociate animations with a timeline. The timeline itself will * determine if it needs to begin, continue or stop tracking this animation. */ virtual void NotifyAnimationUpdated(Animation& aAnimation); + /** + * Returns true if any CSS animations, CSS transitions or Web animations are + * currently associated with this timeline. As soon as an animation is + * applied to an element it is associated with the timeline even if it has a + * delayed start, so this includes animations that may not be active for some + * time. + */ + bool HasAnimations() const { + return !mAnimations.IsEmpty(); + } + void RemoveAnimation(Animation* aAnimation); protected: nsCOMPtr<nsIGlobalObject> mWindow; // Animations observing this timeline // // We store them in (a) a hashset for quick lookup, and (b) an array
--- a/dom/apps/AppsService.js +++ b/dom/apps/AppsService.js @@ -101,16 +101,20 @@ AppsService.prototype = { return DOMApplicationRegistry.getCoreAppsBasePath(); }, getWebAppsBasePath: function getWebAppsBasePath() { debug("getWebAppsBasePath()"); return DOMApplicationRegistry.getWebAppsBasePath(); }, + areAnyAppsInstalled: function() { + return DOMApplicationRegistry.areAnyAppsInstalled(); + }, + getAppInfo: function getAppInfo(aAppId) { debug("getAppInfo()"); return DOMApplicationRegistry.getAppInfo(aAppId); }, getRedirect: function getRedirect(aLocalId, aURI) { debug("getRedirect for " + aLocalId + " " + aURI.spec); if (this.isInvalidId(aLocalId)) {
--- a/dom/apps/AppsServiceChild.jsm +++ b/dom/apps/AppsServiceChild.jsm @@ -407,16 +407,20 @@ this.DOMApplicationRegistry = { return null; }, getWebAppsBasePath: function getWebAppsBasePath() { debug("getWebAppsBasePath() not yet supported on child!"); return null; }, + areAnyAppsInstalled: function() { + return AppsUtils.areAnyAppsInstalled(this.webapps); + }, + getAppInfo: function getAppInfo(aAppId) { return AppsUtils.getAppInfo(this.webapps, aAppId); }, updateDataStoreEntriesFromLocalId: function(aLocalId) { debug("updateDataStoreEntriesFromLocalId() not yet supported on child!"); } }
--- a/dom/apps/AppsUtils.jsm +++ b/dom/apps/AppsUtils.jsm @@ -144,26 +144,27 @@ function _setAppProperties(aObj, aApp) { this.AppsUtils = { // Clones a app, without the manifest. cloneAppObject: function(aApp) { let obj = {}; _setAppProperties(obj, aApp); return obj; }, - // Creates a nsILoadContext object with a given appId and isBrowser flag. - createLoadContext: function createLoadContext(aAppId, aIsBrowser) { + // Creates a nsILoadContext object with a given appId and inIsolatedMozBrowser + // flag. + createLoadContext: function createLoadContext(aAppId, aInIsolatedMozBrowser) { return { associatedWindow: null, topWindow : null, appId: aAppId, - isInBrowserElement: aIsBrowser, + isInIsolatedMozBrowserElement: aInIsolatedMozBrowser, originAttributes: { appId: aAppId, - inBrowser: aIsBrowser + inIsolatedMozBrowser: aInIsolatedMozBrowser }, usePrivateBrowsing: false, isContent: false, isAppOfType: function(appType) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, @@ -339,16 +340,20 @@ this.AppsUtils = { if (app.localId == aLocalId) { return app.manifestURL; } } return ""; }, + areAnyAppsInstalled: function(aApps) { + return Object.getOwnPropertyNames(aApps).length > 0; + }, + getCoreAppsBasePath: function getCoreAppsBasePath() { debug("getCoreAppsBasePath()"); try { return FileUtils.getDir("coreAppsDir", ["webapps"], false).path; } catch(e) { return null; } },
--- a/dom/apps/Webapps.js +++ b/dom/apps/Webapps.js @@ -178,17 +178,17 @@ WebappsRegistry.prototype = { categories: categories }, from: installURL, oid: this._id, topId: this._topId, requestID: requestID, appId: principal.appId, - isBrowser: principal.isInBrowserElement, + isBrowser: principal.isInIsolatedMozBrowserElement, isPackage: isPackage }; }, // mozIDOMApplicationRegistry implementation install: function(aURL, aParams) { let request = this.createRequest();
--- a/dom/apps/Webapps.jsm +++ b/dom/apps/Webapps.jsm @@ -3531,20 +3531,20 @@ this.DOMApplicationRegistry = { lastProgressTime = now; this._saveApps(); } }).bind(this), onStatus: function(aRequest, aContext, aStatus, aStatusArg) { }, // nsILoadContext appId: aOldApp.installerAppId, - isInBrowserElement: aOldApp.installerIsBrowser, + isInIsolatedMozBrowserElement: aOldApp.installerIsBrowser, originAttributes: { appId: aOldApp.installerAppId, - inBrowser: aOldApp.installerIsBrowser + inIsolatedMozBrowser: aOldApp.installerIsBrowser }, usePrivateBrowsing: false, isContent: false, associatedWindow: null, topWindow : null, isAppOfType: function(appType) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; } @@ -4794,16 +4794,20 @@ this.DOMApplicationRegistry = { getCoreAppsBasePath: function() { return AppsUtils.getCoreAppsBasePath(); }, getWebAppsBasePath: function() { return OS.Path.dirname(this.appsFile); }, + areAnyAppsInstalled: function() { + return AppsUtils.areAnyAppsInstalled(this.webapps); + }, + updateDataStoreEntriesFromLocalId: function(aLocalId) { let app = appsService.getAppByLocalId(aLocalId); if (app) { this.updateDataStoreForApp(app.id); } }, _isLaunchable: function(aApp) { @@ -4897,17 +4901,17 @@ this.DOMApplicationRegistry = { }; this._clearOriginData(appId, browserOnly); this._notifyCategoryAndObservers(subject, "webapps-clear-data", null, msg); }, _clearOriginData: function(appId, browserOnly) { let attributes = {appId: appId}; if (browserOnly) { - attributes.inBrowser = true; + attributes.inIsolatedMozBrowser = true; } this._notifyCategoryAndObservers(null, "clear-origin-data", JSON.stringify(attributes)); } }; /** * Appcache download observer */
--- a/dom/apps/tests/unit/test_moziapplication.js +++ b/dom/apps/tests/unit/test_moziapplication.js @@ -48,16 +48,16 @@ add_test(() => { "app[" + key + "] should be equal to mozapp[" + key + "]"); }); Assert.ok(mozapp.principal, "app principal should exist"); let expectedPrincipalOrigin = app.origin + "^appId=" + app.localId; Assert.equal(mozapp.principal.origin, expectedPrincipalOrigin, "app principal origin ok"); Assert.equal(mozapp.principal.appId, app.localId, "app principal appId ok"); - Assert.equal(mozapp.principal.isInBrowserElement, false, - "app principal isInBrowserElement ok"); + Assert.equal(mozapp.principal.isInIsolatedMozBrowserElement, false, + "app principal isInIsolatedMozBrowserElement ok"); run_next_test(); }); function run_test() { run_next_test(); }
--- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -103,15 +103,15 @@ ChromeUtils::CreateOriginAttributesFromD /* static */ bool ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA, const dom::OriginAttributesDictionary& aB) { return aA.mAddonId == aB.mAddonId && aA.mAppId == aB.mAppId && - aA.mInBrowser == aB.mInBrowser && + aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser && aA.mSignedPkg == aB.mSignedPkg && aA.mUserContextId == aB.mUserContextId; } } // namespace dom } // namespace mozilla
--- a/dom/base/PerformanceObserver.cpp +++ b/dom/base/PerformanceObserver.cpp @@ -130,38 +130,39 @@ PerformanceObserver::QueueEntry(Performa aEntry->GetEntryType(entryType); if (!mEntryTypes.Contains<nsString>(entryType)) { return; } mQueuedEntries.AppendElement(aEntry); } -static nsString sValidTypeNames[7] = { - NS_LITERAL_STRING("composite"), - NS_LITERAL_STRING("mark"), - NS_LITERAL_STRING("measure"), - NS_LITERAL_STRING("navigation"), - NS_LITERAL_STRING("render"), - NS_LITERAL_STRING("resource"), - NS_LITERAL_STRING("server") +static const char16_t* sValidTypeNames[7] = { + MOZ_UTF16("composite"), + MOZ_UTF16("mark"), + MOZ_UTF16("measure"), + MOZ_UTF16("navigation"), + MOZ_UTF16("render"), + MOZ_UTF16("resource"), + MOZ_UTF16("server") }; void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions, ErrorResult& aRv) { if (aOptions.mEntryTypes.IsEmpty()) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return; } nsTArray<nsString> validEntryTypes; - for (const nsString& validTypeName : sValidTypeNames) { + for (const char16_t* name : sValidTypeNames) { + nsDependentString validTypeName(name); if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) && !validEntryTypes.Contains<nsString>(validTypeName)) { validEntryTypes.AppendElement(validTypeName); } } if (validEntryTypes.IsEmpty()) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
--- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -344,19 +344,20 @@ AutoJSAPI::InitInternal(JSObject* aGloba // be necessary. JS::Rooted<JSObject*> global(JS_GetRuntime(aCx), aGlobal); mCxPusher.emplace(mCx); mAutoNullableCompartment.emplace(mCx, global); } else { mAutoNullableCompartment.emplace(mCx, aGlobal); } + JSRuntime* rt = JS_GetRuntime(aCx); + mOldErrorReporter.emplace(JS_GetErrorReporter(rt)); + if (aIsMainThread) { - JSRuntime* rt = JS_GetRuntime(aCx); - mOldErrorReporter.emplace(JS_GetErrorReporter(rt)); JS_SetErrorReporter(rt, xpc::SystemErrorReporter); } } AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, JSContext* aCx) : mOwnErrorReporting(false) @@ -460,18 +461,31 @@ AutoJSAPI::InitWithLegacyErrorReporting( // reports to the JSErrorReporter as soon as they are generated. These go // directly to the console, so we can handle them easily here. // // Eventually, SpiderMonkey will have a special-purpose callback for warnings // only. void WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep) { - MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags)); + if (!NS_IsMainThread()) { + // Reporting a warning on workers is a bit complicated because we have to + // climb our parent chain until we get to the main thread. So go ahead and + // just go through the worker ReportError codepath here. + // + // That said, it feels like we should be able to short-circuit things a bit + // here by posting an appropriate runnable to the main thread directly... + // Worth looking into sometime. + workers::WorkerPrivate* worker = workers::GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(worker); + + worker->ReportError(aCx, aMessage, aRep); + return; + } RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport(); nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx); xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(), win ? win->AsInner()->WindowID() : 0); xpcReport->LogToConsole(); } @@ -479,23 +493,17 @@ void AutoJSAPI::TakeOwnershipOfErrorReporting() { MOZ_ASSERT(!mOwnErrorReporting); mOwnErrorReporting = true; JSRuntime *rt = JS_GetRuntime(cx()); mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting(); JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true); - // Workers have their own error reporting mechanism which deals with warnings - // as well, so don't change the worker error reporter for now. Once we switch - // all of workers to TakeOwnershipOfErrorReporting(), we will just make the - // default worker error reporter assert that it only sees warnings. - if (mIsMainThread) { - JS_SetErrorReporter(rt, WarningOnlyErrorReporter); - } + JS_SetErrorReporter(rt, WarningOnlyErrorReporter); } void AutoJSAPI::ReportException() { MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!"); if (!HasException()) { return; @@ -543,16 +551,17 @@ AutoJSAPI::ReportException() // to get hold of it. After we invoke ReportError, clear the exception on // cx(), just in case ReportError didn't. JS_SetPendingException(cx(), exn); worker->ReportError(cx(), jsReport.message(), jsReport.report()); ClearException(); } } else { NS_WARNING("OOMed while acquiring uncaught exception from JSAPI"); + ClearException(); } } bool AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal) { MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop()); MOZ_ASSERT(HasException());
--- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -417,17 +417,17 @@ nsFrameLoader::ReallyStartLoadingInterna } } loadInfo->SetReferrerPolicy(referrerPolicy); // Default flags: int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE; // Flags for browser frame: - if (OwnerIsBrowserFrame()) { + if (OwnerIsMozBrowserFrame()) { flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER; } // Kick off the load... bool tmpState = mNeedsAsyncDestroy; mNeedsAsyncDestroy = true; nsCOMPtr<nsIURI> uriToLoad = mURIToLoad; @@ -1195,18 +1195,18 @@ nsFrameLoader::SwapWithOtherLoader(nsFra NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document"); nsIPresShell* ourShell = ourDoc->GetShell(); nsIPresShell* otherShell = otherDoc->GetShell(); if (!ourShell || !otherShell) { return NS_ERROR_NOT_IMPLEMENTED; } - if (ourDocshell->GetIsBrowserElement() != - otherDocshell->GetIsBrowserElement() || + if (ourDocshell->GetIsIsolatedMozBrowserElement() != + otherDocshell->GetIsIsolatedMozBrowserElement() || ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) { return NS_ERROR_NOT_IMPLEMENTED; } if (mInSwap || aOther->mInSwap) { return NS_ERROR_NOT_IMPLEMENTED; } AutoResetInFrameSwap autoFrameSwap(this, aOther, ourDocshell, otherDocshell, @@ -1572,27 +1572,27 @@ nsFrameLoader::SetOwnerContent(Element* if (RenderFrameParent* rfp = GetCurrentRenderFrame()) { rfp->OwnerContentChanged(aContent); } ResetPermissionManagerStatus(); } bool -nsFrameLoader::OwnerIsBrowserOrAppFrame() +nsFrameLoader::OwnerIsMozBrowserOrAppFrame() { nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false; } // The xpcom getter version NS_IMETHODIMP -nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult) +nsFrameLoader::GetOwnerIsMozBrowserOrAppFrame(bool* aResult) { - *aResult = OwnerIsBrowserOrAppFrame(); + *aResult = OwnerIsMozBrowserOrAppFrame(); return NS_OK; } bool nsFrameLoader::OwnerIsWidget() { nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); return browserFrame ? browserFrame->GetReallyIsWidget() : false; @@ -1610,19 +1610,76 @@ nsFrameLoader::GetOwnerIsWidget(bool* aR bool nsFrameLoader::OwnerIsAppFrame() { nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); return browserFrame ? browserFrame->GetReallyIsApp() : false; } bool -nsFrameLoader::OwnerIsBrowserFrame() +nsFrameLoader::OwnerIsMozBrowserFrame() +{ + return OwnerIsMozBrowserOrAppFrame() && !OwnerIsAppFrame(); +} + +bool +nsFrameLoader::OwnerIsIsolatedMozBrowserFrame() { - return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame(); + nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); + if (!browserFrame) { + return false; + } + + if (!OwnerIsMozBrowserFrame()) { + return false; + } + + bool isolated = browserFrame->GetIsolated(); + if (isolated) { + return true; + } + + // After bug 1238160, which allows isolation to be disabled on mozbrowser + // frames, we no longer have a way to tell from the principal alone if + // something "is a mozbrowser". Instead, we now only know "is an isolated + // mozbrowser". The following code paths would return invalid results if it + // were possible to have apps *and* isolation could be disabled: + // * CheckPermission in AppProcessChecker.cpp + // * nsScriptSecurityManager::AppStatusForPrincipal + // * init() in SystemMessageManager.js + // Currently, desktop is the only platform where we intend to disable + // isolation on a browser frame, so non-desktop should be able to assume that + // inIsolatedMozBrowser is true for all mozbrowser frames. To enforce these + // assumptions, we assert that there are no apps installed if we have tried + // to disable isolation. + nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); + if (!appsService) { + // If the apps service is not present, we assume this means there can't be + // any apps at all, so there is no problem. + return false; + } + bool appsInstalled; + nsresult rv = appsService->AreAnyAppsInstalled(&appsInstalled); + if (NS_WARN_IF(NS_FAILED(rv))) { + // The apps service exists, but it threw an error when checking if there are + // any apps, so we don't know if we have them or not. + return false; + } +#ifdef MOZ_B2G + MOZ_RELEASE_ASSERT(!appsInstalled, + "Disabling mozbrowser isolation is not currently " + "allowed when apps are installed."); +#else + if (appsInstalled) { + NS_WARNING("Disabling mozbrowser isolation is not currently allowed when " + "apps are installed."); + } +#endif + + return false; } void nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut) { aOut.Truncate(); nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); if (browserFrame) { @@ -1687,25 +1744,25 @@ nsFrameLoader::ShouldUseRemoteProcess() if (XRE_IsContentProcess() && !(PR_GetEnv("MOZ_NESTED_OOP_TABS") || Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) { return false; } // If we're an <iframe mozbrowser> and we don't have a "remote" attribute, // fall back to the default. - if (OwnerIsBrowserOrAppFrame() && + if (OwnerIsMozBrowserOrAppFrame() && !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) { return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false); } // Otherwise, we're remote if we have "remote=true" and we're either a // browser frame or a XUL element. - return (OwnerIsBrowserOrAppFrame() || + return (OwnerIsMozBrowserOrAppFrame() || mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) && mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote, nsGkAtoms::_true, eCaseMatters); } bool @@ -1878,42 +1935,43 @@ nsFrameLoader::MaybeCreateDocShell() NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell)); webNav->SetSessionHistory(sessionHistory); } if (OwnerIsAppFrame()) { // You can't be both an app and a browser frame. - MOZ_ASSERT(!OwnerIsBrowserFrame()); + MOZ_ASSERT(!OwnerIsMozBrowserFrame()); nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); MOZ_ASSERT(ownApp); uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID; if (ownApp) { NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE); } mDocShell->SetIsApp(ownAppId); } - if (OwnerIsBrowserFrame()) { + if (OwnerIsMozBrowserFrame()) { // You can't be both a browser and an app frame. MOZ_ASSERT(!OwnerIsAppFrame()); nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID; if (containingApp) { NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId), NS_ERROR_FAILURE); } mDocShell->SetIsBrowserInsideApp(containingAppId); + mDocShell->SetIsInIsolatedMozBrowserElement(OwnerIsIsolatedMozBrowserFrame()); } - if (OwnerIsBrowserOrAppFrame()) { + if (OwnerIsMozBrowserOrAppFrame()) { // For inproc frames, set the docshell properties. nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell); nsAutoString name; if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) { item->SetName(name); } mDocShell->SetFullscreenAllowed( mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) || @@ -2244,17 +2302,17 @@ nsFrameLoader::TryRemoteBrowser() if (openingTab && openingTab->Manager() && openingTab->Manager()->IsContentParent()) { openerContentParent = openingTab->Manager()->AsContentParent(); } // <iframe mozbrowser> gets to skip these checks. - if (!OwnerIsBrowserOrAppFrame()) { + if (!OwnerIsMozBrowserOrAppFrame()) { if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) { return false; } if (!mOwnerContent->IsXULElement()) { return false; } @@ -2561,17 +2619,17 @@ nsFrameLoader::EnsureMessageManager() { NS_ENSURE_STATE(mOwnerContent); if (mMessageManager) { return NS_OK; } if (!mIsTopLevelContent && - !OwnerIsBrowserOrAppFrame() && + !OwnerIsMozBrowserOrAppFrame() && !IsRemoteFrame() && !(mOwnerContent->IsXULElement() && mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::forcemessagemanager, nsGkAtoms::_true, eCaseMatters))) { return NS_OK; } @@ -2667,17 +2725,17 @@ nsFrameLoader::SwapRemoteBrowser(nsITabP RefPtr<TabParent> newParent = TabParent::GetFrom(aTabParent); if (!newParent || !mRemoteBrowser) { return NS_ERROR_DOM_INVALID_STATE_ERR; } if (!IsRemoteFrame()) { NS_WARNING("Switching from in-process to out-of-process is not supported."); return NS_ERROR_NOT_IMPLEMENTED; } - if (!OwnerIsBrowserOrAppFrame()) { + if (!OwnerIsMozBrowserOrAppFrame()) { NS_WARNING("Switching process for non-mozbrowser/app frame is not supported."); return NS_ERROR_NOT_IMPLEMENTED; } if (newParent == mRemoteBrowser) { return NS_OK; } MaybeUpdatePrimaryTabParent(eTabParentRemoved); @@ -2818,27 +2876,27 @@ nsFrameLoader::ResetPermissionManagerSta // Finding the new app Id: // . first we check if the owner is an app frame // . second, we check if the owner is a browser frame // in both cases we populate the appId variable. uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; if (OwnerIsAppFrame()) { // You can't be both an app and a browser frame. - MOZ_ASSERT(!OwnerIsBrowserFrame()); + MOZ_ASSERT(!OwnerIsMozBrowserFrame()); nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); MOZ_ASSERT(ownApp); uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID; if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) { appId = ownAppId; } } - if (OwnerIsBrowserFrame()) { + if (OwnerIsMozBrowserFrame()) { // You can't be both a browser and an app frame. MOZ_ASSERT(!OwnerIsAppFrame()); nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID; if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) { appId = containingAppId; } @@ -2966,17 +3024,17 @@ nsFrameLoader::GetLoadContext(nsILoadCon } loadContext.forget(aLoadContext); return NS_OK; } void nsFrameLoader::InitializeBrowserAPI() { - if (OwnerIsBrowserOrAppFrame()) { + if (OwnerIsMozBrowserOrAppFrame()) { if (!IsRemoteFrame()) { nsresult rv = EnsureMessageManager(); if (NS_WARN_IF(NS_FAILED(rv))) { return; } if (mMessageManager) { mMessageManager->LoadFrameScript( NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"), @@ -3061,17 +3119,17 @@ nsFrameLoader::MaybeUpdatePrimaryTabPare nsresult nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext, nsIURI* aURI, const nsACString& aPackageId) { nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); DocShellOriginAttributes attrs; - attrs.mInBrowser = OwnerIsBrowserFrame(); + attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame(); nsCString signedPkgOrigin; if (!aPackageId.IsEmpty()) { // Only when aPackageId is not empty would signed package origin // be meaningful. nsPrincipal::GetOriginForURI(aURI, signedPkgOrigin); } @@ -3102,13 +3160,17 @@ nsFrameLoader::GetNewTabContext(MutableT if (!userContextIdStr.IsEmpty()) { nsresult err; uint32_t userContextId = userContextIdStr.ToInteger(&err); NS_ENSURE_SUCCESS(err, err); attrs.mUserContextId = userContextId; } bool tabContextUpdated = - aTabContext->SetTabContext(ownApp, containingApp, attrs, signedPkgOrigin); + aTabContext->SetTabContext(OwnerIsMozBrowserFrame(), + ownApp, + containingApp, + attrs, + signedPkgOrigin); NS_ENSURE_STATE(tabContextUpdated); return NS_OK; }
--- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -138,17 +138,17 @@ public: * Return the primary frame for our owning content, or null if it * can't be found. */ nsIFrame* GetPrimaryFrameOfOwningContent() const { return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr; } - /** + /** * Return the document that owns this, or null if we don't have * an owner. */ nsIDocument* GetOwnerDoc() const { return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr; } PBrowserParent* GetRemoteBrowser() const; @@ -189,17 +189,17 @@ public: /** * Stashes a detached view on the frame loader. We do this when we're * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is * being reframed we'll restore the detached view when it's recreated, * otherwise we'll discard the old presentation and set the detached * subdoc view to null. aContainerDoc is the document containing the * the subdoc frame. This enables us to detect when the containing - * document has changed during reframe, so we can discard the presentation + * document has changed during reframe, so we can discard the presentation * in that case. */ void SetDetachedSubdocView(nsView* aDetachedView, nsIDocument* aContainerDoc); /** * Retrieves the detached view and the document containing the view, * as set by SetDetachedSubdocView(). @@ -237,35 +237,46 @@ private: * Return true if the frame is a remote frame. Return false otherwise */ bool IsRemoteFrame(); /** * Is this a frameloader for a bona fide <iframe mozbrowser> or * <iframe mozapp>? (I.e., does the frame return true for * nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?) + * <xul:browser> is not a mozbrowser or app, so this is false for that case. */ - bool OwnerIsBrowserOrAppFrame(); + bool OwnerIsMozBrowserOrAppFrame(); /** * Is this a frameloader for a bona fide <iframe mozwidget>? (I.e., does the * frame return true for nsIMozBrowserFrame::GetReallyIsWidget()?) */ bool OwnerIsWidget(); /** * Is this a frameloader for a bona fide <iframe mozapp>? (I.e., does the * frame return true for nsIMozBrowserFrame::GetReallyIsApp()?) */ bool OwnerIsAppFrame(); /** * Is this a frame loader for a bona fide <iframe mozbrowser>? + * <xul:browser> is not a mozbrowser, so this is false for that case. */ - bool OwnerIsBrowserFrame(); + bool OwnerIsMozBrowserFrame(); + + /** + * Is this a frame loader for an isolated <iframe mozbrowser>? + * + * By default, mozbrowser frames are isolated. Isolation can be disabled by + * setting the frame's noisolation attribute. Disabling isolation is + * only allowed if the containing document is chrome. + */ + bool OwnerIsIsolatedMozBrowserFrame(); /** * Get our owning element's app manifest URL, or return the empty string if * our owning element doesn't have an app manifest URL. */ void GetOwnerAppManifestURL(nsAString& aOut); /**
--- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -652,16 +652,17 @@ GK_ATOM(noautohide, "noautohide") GK_ATOM(norolluponanchor, "norolluponanchor") GK_ATOM(nobr, "nobr") GK_ATOM(node, "node") GK_ATOM(nodefaultsrc, "nodefaultsrc") GK_ATOM(nodeSet, "node-set") GK_ATOM(noembed, "noembed") GK_ATOM(noframes, "noframes") GK_ATOM(nohref, "nohref") +GK_ATOM(noisolation, "noisolation") GK_ATOM(nonce, "nonce") GK_ATOM(none, "none") GK_ATOM(noresize, "noresize") GK_ATOM(normal, "normal") GK_ATOM(normalizeSpace, "normalize-space") GK_ATOM(noscript, "noscript") GK_ATOM(noshade, "noshade") GK_ATOM(novalidate, "novalidate")
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -452,18 +452,16 @@ nsGlobalWindow::DOMMinTimeoutValue() con } \ return GetCurrentInnerWindowInternal()->method args; \ } \ PR_END_MACRO // CIDs static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID); -static const char sPopStatePrefStr[] = "browser.history.allowPopState"; - #define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload") #define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload") /** * An indirect observer object that means we don't have to implement nsIObserver * on nsGlobalWindow, where any script could see it. */ class nsGlobalWindowObserver final : public nsIObserver, @@ -1153,16 +1151,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW mFullscreenMode(false), mIsClosed(false), mInClose(false), mHavePendingClose(false), mHadOriginalOpener(false), mIsPopupSpam(false), mBlockScriptedClosingFlag(false), mWasOffline(false), + mHasHadSlowScript(false), mNotifyIdleObserversIdleOnThaw(false), mNotifyIdleObserversActiveOnThaw(false), mCreatingInnerWindow(false), mIsChrome(false), mCleanMessageManager(false), mNeedsFocus(true), mHasFocus(false), #if defined(XP_MACOSX) @@ -3796,17 +3795,17 @@ nsGlobalWindow::GetParentOuter() { MOZ_RELEASE_ASSERT(IsOuterWindow()); if (!mDocShell) { return nullptr; } nsCOMPtr<nsPIDOMWindowOuter> parent; - if (mDocShell->GetIsBrowserOrApp()) { + if (mDocShell->GetIsMozBrowserOrApp()) { parent = AsOuter(); } else { parent = GetParent(); } return parent.forget(); } @@ -3962,17 +3961,17 @@ nsGlobalWindow::GetContentInternal(Error nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetChildWindow(NS_LITERAL_STRING("content")); if (domWindow) { return domWindow.forget(); } // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then // GetContent is the same as window.top. - if (mDocShell && mDocShell->GetIsInBrowserOrApp()) { + if (mDocShell && mDocShell->GetIsInMozBrowserOrApp()) { return GetTopOuter(); } nsCOMPtr<nsIDocShellTreeItem> primaryContent; if (aUnprivilegedCaller) { // If we're called by non-chrome code, make sure we don't return // the primary content window if the calling tab is hidden. In // such a case we return the same-type root in the hidden tab, @@ -7170,17 +7169,17 @@ void nsGlobalWindow::ResizeToOuter(int32_t aWidth, int32_t aHeight, ErrorResult& aError, bool aCallerIsChrome) { MOZ_RELEASE_ASSERT(IsOuterWindow()); /* * If caller is a browser-element then dispatch a resize event to * the embedder. */ - if (mDocShell && mDocShell->GetIsBrowserOrApp()) { + if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) { CSSIntSize size(aWidth, aHeight); if (!DispatchResizeEvent(size)) { // The embedder chose to prevent the default action for this // event, so let's not resize this window after all... return; } } @@ -7220,17 +7219,17 @@ nsGlobalWindow::ResizeByOuter(int32_t aW ErrorResult& aError, bool aCallerIsChrome) { MOZ_RELEASE_ASSERT(IsOuterWindow()); /* * If caller is a browser-element then dispatch a resize event to * parent. */ - if (mDocShell && mDocShell->GetIsBrowserOrApp()) { + if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) { CSSIntSize size; if (NS_FAILED(GetInnerSize(size))) { return; } size.width += aWidthDif; size.height += aHeightDif; @@ -8169,17 +8168,17 @@ nsGlobalWindow::CanClose() } void nsGlobalWindow::CloseOuter(bool aTrustedCaller) { MOZ_RELEASE_ASSERT(IsOuterWindow()); if (!mDocShell || IsInModalState() || - (IsFrame() && !mDocShell->GetIsBrowserOrApp())) { + (IsFrame() && !mDocShell->GetIsMozBrowserOrApp())) { // window.close() is called on a frame in a frameset, on a window // that's already closed, or on a window for which there's // currently a modal dialog open. Ignore such calls. return; } if (mHavePendingClose) { // We're going to be closed anyway; do nothing since we don't want @@ -8696,17 +8695,17 @@ nsGlobalWindow::CacheXBLPrototypeHandler mCachedXBLPrototypeHandlers->Put(aKey, aHandler); } Element* nsGlobalWindow::GetFrameElementOuter() { MOZ_RELEASE_ASSERT(IsOuterWindow()); - if (!mDocShell || mDocShell->GetIsBrowserOrApp()) { + if (!mDocShell || mDocShell->GetIsMozBrowserOrApp()) { return nullptr; } // Per HTML5, the frameElement getter returns null in cross-origin situations. Element* element = GetRealFrameElementOuter(); if (!element) { return nullptr; } @@ -9911,21 +9910,16 @@ nsGlobalWindow::FireHashchange(const nsA nsresult nsGlobalWindow::DispatchSyncPopState() { MOZ_RELEASE_ASSERT(IsInnerWindow()); NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Must be safe to run script here."); - // Check that PopState hasn't been pref'ed off. - if (!Preferences::GetBool(sPopStatePrefStr, false)) { - return NS_OK; - } - nsresult rv = NS_OK; // Bail if the window is frozen. if (IsFrozen()) { return NS_OK; } // Get the document's pending state object -- it contains the data we're @@ -10657,16 +10651,23 @@ nsGlobalWindow::ShowSlowScriptDialog() return KillSlowScript; } // Check if we should offer the option to debug JS::UniqueChars filename; unsigned lineno; bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno); + // Record the slow script event if we haven't done so already for this inner window + // (which represents a particular page to the user). + if (!mHasHadSlowScript) { + Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1); + } + mHasHadSlowScript = true; + if (XRE_IsContentProcess() && ProcessHangMonitor::Get()) { ProcessHangMonitor::SlowScriptAction action; RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get(); nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell()); action = monitor->NotifySlowScript(child, filename.get(), lineno);
--- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1686,16 +1686,21 @@ protected: bool mIsPopupSpam : 1; // Indicates whether scripts are allowed to close this window. bool mBlockScriptedClosingFlag : 1; // Window offline status. Checked to see if we need to fire offline event bool mWasOffline : 1; + // Represents whether the inner window's page has had a slow script notice. + // Only used by inner windows; will always be false for outer windows. + // This is used to implement Telemetry measures such as SLOW_SCRIPT_PAGE_COUNT. + bool mHasHadSlowScript : 1; + // Track what sorts of events we need to fire when thawed bool mNotifyIdleObserversIdleOnThaw : 1; bool mNotifyIdleObserversActiveOnThaw : 1; // Indicates whether we're in the middle of creating an initializing // a new inner window object. bool mCreatingInnerWindow : 1;
--- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -20,21 +20,16 @@ #include "nsContentUtils.h" #include "nsISHistory.h" #include "nsISHistoryInternal.h" #include "mozilla/Preferences.h" using namespace mozilla; using namespace mozilla::dom; -static const char* sAllowPushStatePrefStr = - "browser.history.allowPushState"; -static const char* sAllowReplaceStatePrefStr = - "browser.history.allowReplaceState"; - // // History class implementation // NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsHistory) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHistory) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHistory) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHistory) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY @@ -299,22 +294,16 @@ nsHistory::PushOrReplaceState(JSContext* } if (!win->HasActiveDocument()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } - // Check that PushState hasn't been pref'ed off. - if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr : - sAllowPushStatePrefStr, false)) { - return; - } - // AddState might run scripts, so we need to hold a strong reference to the // docShell here to keep it from going away. nsCOMPtr<nsIDocShell> docShell = win->GetDocShell(); if (!docShell) { aRv.Throw(NS_ERROR_FAILURE); return;
--- a/dom/base/nsIFrameLoader.idl +++ b/dom/base/nsIFrameLoader.idl @@ -145,17 +145,17 @@ interface nsIFrameLoader : nsISupports * the child content process when these events are targeted to * the remote browser element. * * Used primarly for input events (mouse, keyboard) */ const unsigned long EVENT_MODE_NORMAL_DISPATCH = 0x00000000; /** - * With this event mode, it's the application's responsability to + * With this event mode, it's the application's responsability to * convert and forward events to the content process */ const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001; attribute unsigned long eventMode; /** * If false, then the subdocument is not clipped to its CSS viewport, and the @@ -191,24 +191,25 @@ interface nsIFrameLoader : nsISupports * * 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 browser or app frame - * Especially, a widget frame is regarded as an app frame. + * Find out whether the owner content really is a mozbrowser or app frame + * Especially, a widget frame is regarded as an app frame. <xul:browser> is + * not considered to be a mozbrowser frame. */ - readonly attribute boolean ownerIsBrowserOrAppFrame; + readonly attribute boolean ownerIsMozBrowserOrAppFrame; /** * Find out whether the owner content really is a widget. If this attribute - * returns true, |ownerIsBrowserOrAppFrame| must return true. + * returns true, |ownerIsMozBrowserOrAppFrame| must return true. */ readonly attribute boolean ownerIsWidget; }; %{C++ class nsFrameLoader; %}
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1432,16 +1432,21 @@ TimeUntilNow(TimeStamp start) if (start.IsNull()) { return 0; } return TimeBetween(start, TimeStamp::Now()); } struct CycleCollectorStats { + MOZ_CONSTEXPR CycleCollectorStats() : + mMaxGCDuration(0), mRanSyncForgetSkippable(false), mSuspected(0), + mMaxSkippableDuration(0), mMaxSliceTime(0), mMaxSliceTimeSinceClear(0), + mTotalSliceTime(0), mAnyLockedOut(false), mExtraForgetSkippableCalls(0) {} + void Init() { Clear(); mMaxSliceTimeSinceClear = 0; } void Clear() {
--- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -254,16 +254,17 @@ support-files = test_performance_observer.js performance_observer.html test_anonymousContent_style_csp.html^headers^ file_explicit_user_agent.sjs referrer_change_server.sjs file_change_policy_redirect.html file_bug1198095.js file_bug1250148.sjs + mozbrowser_api_utils.js [test_anonymousContent_api.html] [test_anonymousContent_append_after_reflow.html] [test_anonymousContent_canvas.html] skip-if = buildapp == 'b2g' # Requires webgl support [test_anonymousContent_insert.html] [test_anonymousContent_manipulate_content.html] [test_anonymousContent_style_csp.html] @@ -867,9 +868,11 @@ skip-if = e10s || os != 'linux' || build [test_explicit_user_agent.html] [test_change_policy.html] skip-if = buildapp == 'b2g' #no ssl support [test_document.all_iteration.html] [test_bug1198095.html] [test_bug1187157.html] [test_bug769117.html] [test_bug1250148.html] -[test_bug1240471.html] \ No newline at end of file +[test_bug1240471.html] +[test_mozbrowser_apis_allowed.html] +[test_mozbrowser_apis_blocked.html]
new file mode 100644 --- /dev/null +++ b/dom/base/test/mozbrowser_api_utils.js @@ -0,0 +1,72 @@ +const FRAME_URL = "http://example.org/"; + +const METHODS = { + setVisible: {}, + getVisible: {}, + setActive: {}, + getActive: {}, + addNextPaintListener: {}, + removeNextPaintListener: {}, + sendMouseEvent: {}, + sendTouchEvent: {}, + goBack: {}, + goForward: {}, + reload: {}, + stop: {}, + download: {}, + purgeHistory: {}, + getScreenshot: {}, + zoom: {}, + getCanGoBack: {}, + getCanGoForward: {}, + getContentDimensions: {}, + setInputMethodActive: { alwaysFails: true }, // needs input-manage + setNFCFocus: { alwaysFails: true }, // needs nfc-manager + findAll: {}, + findNext: {}, + clearMatch: {}, + executeScript: { alwaysFails: true }, // needs browser:universalxss + getStructuredData: {}, + getWebManifest: {}, + mute: {}, + unmute: {}, + getMuted: {}, + setVolume: {}, + getVolume: {}, +}; + +const ATTRIBUTES = [ + "allowedAudioChannels", +]; + +function once(target, eventName, useCapture = false) { + info("Waiting for event: '" + eventName + "' on " + target + "."); + + return new Promise(resolve => { + for (let [add, remove] of [ + ["addEventListener", "removeEventListener"], + ["addMessageListener", "removeMessageListener"], + ]) { + if ((add in target) && (remove in target)) { + target[add](eventName, function onEvent(...aArgs) { + info("Got event: '" + eventName + "' on " + target + "."); + target[remove](eventName, onEvent, useCapture); + resolve(aArgs); + }, useCapture); + break; + } + } + }); +} + +function* loadFrame(attributes = {}) { + let iframe = document.createElement("iframe"); + iframe.setAttribute("src", FRAME_URL); + for (let key in attributes) { + iframe.setAttribute(key, attributes[key]); + } + let loaded = once(iframe, "load"); + document.body.appendChild(iframe); + yield loaded; + return iframe; +}
--- a/dom/base/test/test_messagemanager_principal.html +++ b/dom/base/test/test_messagemanager_principal.html @@ -29,18 +29,18 @@ sendAsyncMessage(message.name, "principal: " + (message.principal ? "OK" : "KO")); sendAsyncMessage(message.name, "principal.appId: " + ("appId" in message.principal ? "OK" : "KO")); sendAsyncMessage(message.name, "principal.origin: " + ("origin" in message.principal ? "OK" : "KO")); - sendAsyncMessage(message.name, "principal.isInBrowserElement: " + - ("isInBrowserElement" in message.principal ? "OK" : "KO")); + sendAsyncMessage(message.name, "principal.isInIsolatedMozBrowserElement: " + + ("isInIsolatedMozBrowserElement" in message.principal ? "OK" : "KO")); sendAsyncMessage(message.name, "DONE"); }); } function runTests() { ok("Browser prefs set.");
--- a/dom/base/test/test_messagemanager_send_principal.html +++ b/dom/base/test/test_messagemanager_send_principal.html @@ -33,18 +33,18 @@ (message.data instanceof Ci.nsIPrincipal ? "OK" : "KO")); sendAsyncMessage("test:result", "principal.appId: " + ("appId" in message.data ? "OK" : "KO")); sendAsyncMessage("test:result", "principal.origin: " + ("origin" in message.data ? "OK" : "KO")); - sendAsyncMessage("test:result", "principal.isInBrowserElement: " + - ("isInBrowserElement" in message.data ? "OK" : "KO")); + sendAsyncMessage("test:result", "principal.isInIsolatedMozBrowserElement: " + + ("isInIsolatedMozBrowserElement" in message.data ? "OK" : "KO")); }); addMessageListener("test:system", function(message) { sendAsyncMessage("test:result", "isSystemPrincipal: " + (secMan.isSystemPrincipal(message.data) ? "OK" : "KO")); }); addMessageListener("test:ep", function(message) {
--- a/dom/base/test/test_messagemanager_targetchain.html +++ b/dom/base/test/test_messagemanager_targetchain.html @@ -105,17 +105,17 @@ SpecialPowers.pushPermissions([ { type: "browser", allow: 1, context: { url: principal.URI.spec, originAttributes: { appId: principal.appId }}}, { type: "browser", allow: 1, context: { url: principal.URI.spec, originAttributes: { appId: principal.appId, - inBrowser: true }}} + inIsolatedMozBrowser: true }}} ], () => { SpecialPowers.pushPrefEnv({ set: [ ["dom.mozBrowserFramesEnabled", true], ["dom.ipc.browser_frames.oop_by_default", false], ] }, runTests); });
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_mozbrowser_apis_allowed.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Verify mozbrowser APIs are allowed with browser permission</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <script type="text/javascript" src="mozbrowser_api_utils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> +<script type="application/javascript;version=1.8"> + add_task(function*() { + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv( + { "set": [["dom.mozBrowserFramesEnabled", true]] }, + resolve); + }); + }); + + add_task(function*() { + yield new Promise(resolve => { + SpecialPowers.pushPermissions([ + { "type": "browser", "allow": 1, "context": document } + ], resolve); + }); + }); + + add_task(function*() { + // Create <iframe mozbrowser> + let frame = yield loadFrame({ + mozbrowser: "true" + }); + + // Verify that mozbrowser APIs are accessible + for (let method in METHODS) { + let { alwaysFails } = METHODS[method]; + if (alwaysFails) { + ok(!(method in frame), `frame does not have method ${method}, ` + + `needs more permissions`); + } else { + ok(method in frame, `frame has method ${method}`); + } + } + for (let attribute of ATTRIBUTES) { + ok(attribute in frame, `frame has attribute ${attribute}`); + } + }); +</script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_mozbrowser_apis_blocked.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Verify mozbrowser APIs are blocked without browser permission</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <script type="text/javascript" src="mozbrowser_api_utils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> +<script type="application/javascript;version=1.8"> + add_task(function*() { + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv( + { "set": [["dom.mozBrowserFramesEnabled", true]] }, + resolve); + }); + }); + + add_task(function*() { + // Create <iframe mozbrowser> + let frame = yield loadFrame({ + mozbrowser: "true" + }); + + // Verify that mozbrowser APIs are not accessible + for (let method in METHODS) { + ok(!(method in frame), `frame does not have method ${method}`); + } + for (let attribute of ATTRIBUTES) { + ok(!(attribute in frame), `frame does not have attribute ${attribute}`); + } + }); +</script> +</body> +</html>
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -12182,16 +12182,25 @@ class CGDictionary(CGThing): return self.structs.define() def base(self): if self.dictionary.parent: return self.makeClassName(self.dictionary.parent) return "DictionaryBase" def initMethod(self): + """ + This function outputs the body of the Init() method for the dictionary. + + For the most part, this is some bookkeeping for our atoms so + we can avoid atomizing strings all the time, then we just spit + out the getMemberConversion() output for each member, + separated by newlines. + + """ body = dedent(""" // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets MOZ_ASSERT_IF(!cx, val.isNull()); """) if self.needToInitIds: body += fill( @@ -12499,16 +12508,35 @@ class CGDictionary(CGThing): # We can't handle having a holderType here assert conversionInfo.holderType is None declType = conversionInfo.declType if conversionInfo.dealWithOptional: declType = CGTemplatedType("Optional", declType) return declType.define() def getMemberConversion(self, memberInfo): + """ + A function that outputs the initialization of a single dictionary + member from the given dictionary value. + + We start with our conversionInfo, which tells us how to + convert a JS::Value to whatever type this member is. We + substiture the template from the conversionInfo with values + that point to our "temp" JS::Value and our member (which is + the C++ value we want to produce). The output is a string of + code to do the conversion. We store this string in + conversionReplacements["convert"]. + + Now we have three different ways we might use (or skip) this + string of code, depending on whether the value is required, + optional with default value, or optional without default + value. We set up a template in the 'conversion' variable for + exactly how to do this, then substitute into it from the + conversionReplacements dictionary. + """ member, conversionInfo = memberInfo replacements = { "val": "temp.ref()", "declName": self.makeMemberName(member.identifier.name), # We need a holder name for external interfaces, but # it's scoped down to the conversion so we can just use # anything we want. "holderName": "holder",
--- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -56,16 +56,17 @@ MSG_DEF(MSG_INVALID_READ_SIZE, 0, JSEXN_ MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, JSEXN_TYPEERR, "Headers are immutable and cannot be modified.") MSG_DEF(MSG_INVALID_HEADER_NAME, 1, JSEXN_TYPEERR, "{0} is an invalid header name.") MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header value.") MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.") MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.") MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.") MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.") MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.") +MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.") MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.") MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.") MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.") MSG_DEF(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD, 0, JSEXN_TYPEERR, "HEAD or GET Request cannot have a body.") MSG_DEF(MSG_RESPONSE_NULL_STATUS_WITH_BODY, 0, JSEXN_TYPEERR, "Response body is given with a null body status.") MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW, 0, JSEXN_TYPEERR, "Not allowed to define a non-configurable property on the WindowProxy object") MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.") MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
--- a/dom/browser-element/BrowserElementChild.js +++ b/dom/browser-element/BrowserElementChild.js @@ -21,17 +21,17 @@ function parentDocShell(docshell) { } let treeitem = docshell.QueryInterface(Ci.nsIDocShellTreeItem); return treeitem.parent ? treeitem.parent.QueryInterface(Ci.nsIDocShell) : null; } function isTopBrowserElement(docShell) { while (docShell) { docShell = parentDocShell(docShell); - if (docShell && docShell.isBrowserOrApp) { + if (docShell && docShell.isMozBrowserOrApp) { return false; } } return true; } if (!('BrowserElementIsPreloaded' in this)) { if (isTopBrowserElement(docShell)) {
--- a/dom/browser-element/BrowserElementCopyPaste.js +++ b/dom/browser-element/BrowserElementCopyPaste.js @@ -84,17 +84,17 @@ var CopyPasteAssistent = { detail.rect.bottom += currentRect.top; detail.rect.left += currentRect.left; detail.rect.right += currentRect.left; currentWindow = currentWindow.realFrameElement.ownerDocument.defaultView; let targetDocShell = currentWindow .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation); - if(targetDocShell.isBrowserOrApp) { + if(targetDocShell.isMozBrowserOrApp) { break; } } sendAsyncMsg('caretstatechanged', detail); }, };
--- a/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js +++ b/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js @@ -18,17 +18,17 @@ function runTest() { iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { is(e.detail.message == 'app', true, e.detail.message); SimpleTest.finish(); }); document.body.appendChild(iframe); var context = {url: 'http://example.org', - originAttributes: {inBrowser: true}}; + originAttributes: {inIsolatedMozBrowser: true}}; SpecialPowers.pushPermissions([ {type: 'browser', allow: 1, context: context}, {type: 'embed-apps', allow: 1, context: context} ], function() { iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AllowEmbedAppsInNestedOOIframe.html'; }); }
--- a/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js +++ b/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js @@ -57,17 +57,17 @@ function runTests() { } iframe.addEventListener('mozbrowserloadend', audio_loadend); iframe.addEventListener('mozbrowsershowmodalprompt', listener, false); document.body.appendChild(iframe); var context = { 'url': 'http://example.org', 'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID, - 'isInBrowserElement': true }; + 'isInIsolatedMozBrowserElement': true }; SpecialPowers.pushPermissions([ {'type': 'browser', 'allow': 1, 'context': context}, {'type': 'embed-apps', 'allow': 1, 'context': context} ], function() { iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html'; }); }
--- a/dom/browser-element/mochitest/browserElement_Auth.js +++ b/dom/browser-element/mochitest/browserElement_Auth.js @@ -167,17 +167,17 @@ function testAuthJarNoInterfere(e) { // Set a bunch of auth data that should not conflict with the correct auth data already // stored in the cache. var attrs = {appId: 1}; var principal = secMan.createCodebasePrincipal(uri, attrs); authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm', 'tests/dom/browser-element/mochitest/file_http_401_response.sjs', '', 'httpuser', 'wrongpass', false, principal); - attrs = {appId: 1, inBrowser: true}; + attrs = {appId: 1, inIsolatedMozBrowser: true}; principal = secMan.createCodebasePrincipal(uri, attrs); authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm', 'tests/dom/browser-element/mochitest/file_http_401_response.sjs', '', 'httpuser', 'wrongpass', false, principal); principal = secMan.createCodebasePrincipal(uri, {}); authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm', 'tests/dom/browser-element/mochitest/file_http_401_response.sjs', '', 'httpuser', 'wrongpass', false, principal); @@ -202,17 +202,17 @@ function testAuthJarInterfere(e) { .getService(SpecialPowers.Ci.nsIHttpAuthManager); var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(SpecialPowers.Ci.nsIScriptSecurityManager); var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"] .getService(SpecialPowers.Ci.nsIIOService); var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null); // Set some auth data that should overwrite the successful stored details. - var principal = secMan.createCodebasePrincipal(uri, {inBrowser: true}); + var principal = secMan.createCodebasePrincipal(uri, {inIsolatedMozBrowser: true}); authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm', 'tests/dom/browser-element/mochitest/file_http_401_response.sjs', '', 'httpuser', 'wrongpass', false, principal); // Will authenticate with correct password, prompt should not be // called again. var gotusernamepasswordrequired = false; function onUserNameAndPasswordRequired() {
--- a/dom/browser-element/mochitest/browserElement_CopyPaste.js +++ b/dom/browser-element/mochitest/browserElement_CopyPaste.js @@ -324,16 +324,16 @@ function testCut2(e) { mm.loadFrameScript(getScriptForGetContent(), false); } // Give our origin permission to open browsers, and remove it when the test is complete. var principal = SpecialPowers.wrap(document).nodePrincipal; var context = { url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true }}; + inIsolatedMozBrowser: true }}; addEventListener('testready', function() { SpecialPowers.pushPermissions([ {type: 'browser', allow: 1, context: context} ], runTest); });
--- a/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js +++ b/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js @@ -24,17 +24,17 @@ function runTest() { iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { is(e.detail.message == 'app', canEmbedApp, e.detail.message); SimpleTest.finish(); }); document.body.appendChild(iframe); var context = {url: 'http://example.org', - originAttributes: {inBrowser: true}}; + originAttributes: {inIsolatedMozBrowser: true}}; SpecialPowers.pushPermissions([ {type: 'browser', allow: 1, context: context}, {type: 'embed-apps', allow: 1, context: context} ], function() { iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_DisallowEmbedAppsInOOP.html'; }); }
--- a/dom/browser-element/mochitest/browserElement_Proxy.js +++ b/dom/browser-element/mochitest/browserElement_Proxy.js @@ -10,26 +10,26 @@ browserElementTestHelpers.addPermission( function runTest() { let frameUrl = SimpleTest.getTestFileURL('/file_empty.html'); SpecialPowers.pushPermissions([{ type: 'browser:embedded-system-app', allow: true, context: { url: frameUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } },{ type: 'browser', allow: true, context: { url: frameUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], createFrame); } var frame; var mm;
--- a/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js +++ b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js @@ -88,17 +88,17 @@ function createFrames() { function setPermissions() { let permissions = [{ type: 'input', allow: true, context: { url: SimpleTest.getTestFileURL('/file_empty.html'), originAttributes: { appId: currentAppId, - inBrowser: true + inIsolatedMozBrowser: true } } }]; if (inApp) { // The current document would also need to be given access for IPC to // recognize our permission (why)? permissions.push({
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js +++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js @@ -16,17 +16,17 @@ browserElementTestHelpers.addPermission( var iframe; function runTest() { var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); iframe = document.createElement('iframe'); iframe.setAttribute('mozbrowser', 'true'); // Our test involves three <iframe mozbrowser>'s, parent, child1, and child2. // child1 and child2 are contained inside parent. child1 is visibile, and // child2 is not. @@ -75,17 +75,17 @@ function finish() { // expected, but if we don't remove our listener, then we'll end up causing // the /next/ test to fail! iframe.removeEventListener('mozbrowsershowmodalprompt', checkMessage); var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); SimpleTest.finish(); } var expectedMsg = null; var expectedMsgCallback = null; function expectMessage(msg, next) { expectedMsg = msg;
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js +++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js @@ -10,17 +10,17 @@ SimpleTest.waitForExplicitFinish(); browserElementTestHelpers.setEnabledPref(true); browserElementTestHelpers.addPermission(); function runTest() { var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); 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; @@ -56,15 +56,15 @@ function runTest() { document.body.appendChild(iframe); } function finish() { var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); SimpleTest.finish(); } addEventListener('testready', runTest);
--- a/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html +++ b/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html @@ -20,25 +20,25 @@ browserElementTestHelpers.addPermission( browserElementTestHelpers.enableProcessPriorityManager(); SpecialPowers.addPermission("embed-apps", true, document); // Give our origin permission to open browsers, and remove it when the test is complete. var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); addEventListener('unload', function() { var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); }); function runTest() { var iframe = document.createElement('iframe'); iframe.setAttribute('mozbrowser', true); iframe.setAttribute('expecting-system-message', true); iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
--- a/dom/browser-element/mochitest/priority/test_NestedFrames.html +++ b/dom/browser-element/mochitest/priority/test_NestedFrames.html @@ -19,25 +19,25 @@ browserElementTestHelpers.setEnabledPref browserElementTestHelpers.addPermission(); browserElementTestHelpers.enableProcessPriorityManager(); // Give our origin permission to open browsers, and remove it when the test is complete. var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); addEventListener('unload', function() { var principal = SpecialPowers.wrap(document).nodePrincipal; SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec, originAttributes: { appId: principal.appId, - inBrowser: true + inIsolatedMozBrowser: true }}); }); function runTest() { // Set up the following hierarchy of frames: // // <iframe mozbrowser remote=false src='file_NestedFramesOuter.html'> // <iframe mozbrowser remote=true src='file_empty.html'>
--- a/dom/cache/DBSchema.cpp +++ b/dom/cache/DBSchema.cpp @@ -2394,17 +2394,17 @@ Validate(mozIStorageConnection* aConn) // ----- // Schema migration code // ----- typedef nsresult (*MigrationFunc)(mozIStorageConnection*); struct Migration { - Migration(int32_t aFromVersion, MigrationFunc aFunc) + MOZ_CONSTEXPR Migration(int32_t aFromVersion, MigrationFunc aFunc) : mFromVersion(aFromVersion) , mFunc(aFunc) { } int32_t mFromVersion; MigrationFunc mFunc; }; // Declare migration functions here. Each function should upgrade
--- a/dom/canvas/test/crossorigin/mochitest.ini +++ b/dom/canvas/test/crossorigin/mochitest.ini @@ -1,9 +1,10 @@ [DEFAULT] +skip-if = e10s && debug && os == 'mac' # Bug 1252348 support-files = image-allow-credentials.png image-allow-credentials.png^headers^ image-allow-star.png image-allow-star.png^headers^ image.png video.sjs
--- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -1,10 +1,10 @@ [DEFAULT] -skip-if = e10s && debug && os == 'win' # Bug 1252677 +skip-if = e10s && debug && (os == 'win' || os == 'mac') # Bug 1252677 for Windows, Bug 1252348 for Mac support-files = android.json file_drawImage_document_domain.html image_anim-gr.gif image_anim-gr.png image_anim-poster-gr.png image_broken.png image_error-early.png
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -1505,17 +1505,17 @@ EventStateManager::FireContextClick() allowedToDispatch = false; } } } else if (mGestureDownContent->IsHTMLElement()) { nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent)); if (formCtrl) { - allowedToDispatch = formCtrl->IsTextControl(false) || + allowedToDispatch = formCtrl->IsTextOrNumberControl(/*aExcludePassword*/ false) || formCtrl->GetType() == NS_FORM_INPUT_FILE; } else if (mGestureDownContent->IsAnyOfHTMLElements(nsGkAtoms::applet, nsGkAtoms::embed, nsGkAtoms::object)) { allowedToDispatch = false; } }
--- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -86,28 +86,38 @@ Request::RequestCacheEnabled(JSContext* already_AddRefed<InternalRequest> Request::GetInternalRequest() { RefPtr<InternalRequest> r = mRequest; return r.forget(); } namespace { -void -GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput, - nsAString& aRequestURL, ErrorResult& aRv) +already_AddRefed<nsIURI> +ParseURLFromDocument(nsIDocument* aDocument, const nsAString& aInput, + ErrorResult& aRv) { MOZ_ASSERT(aDocument); MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIURI> baseURI = aDocument->GetBaseURI(); nsCOMPtr<nsIURI> resolvedURI; aRv = NS_NewURI(getter_AddRefs(resolvedURI), aInput, nullptr, baseURI); if (NS_WARN_IF(aRv.Failed())) { aRv.ThrowTypeError<MSG_INVALID_URL>(aInput); + } + return resolvedURI.forget(); +} + +void +GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput, + nsAString& aRequestURL, ErrorResult& aRv) +{ + nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv); + if (aRv.Failed()) { return; } // This fails with URIs with weird protocols, even when they are valid, // so we ignore the failure nsAutoCString credentials; Unused << resolvedURI->GetUserPass(credentials); if (!credentials.IsEmpty()) { @@ -127,26 +137,35 @@ GetRequestURLFromDocument(nsIDocument* a aRv = resolvedURIClone->GetSpec(spec); if (NS_WARN_IF(aRv.Failed())) { return; } CopyUTF8toUTF16(spec, aRequestURL); } -void -GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL, - ErrorResult& aRv) +already_AddRefed<nsIURI> +ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIURI> uri; aRv = NS_NewURI(getter_AddRefs(uri), aInput, nullptr, nullptr); if (NS_WARN_IF(aRv.Failed())) { aRv.ThrowTypeError<MSG_INVALID_URL>(aInput); + } + return uri.forget(); +} + +void +GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL, + ErrorResult& aRv) +{ + nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv); + if (aRv.Failed()) { return; } // This fails with URIs with weird protocols, even when they are valid, // so we ignore the failure nsAutoCString credentials; Unused << uri->GetUserPass(credentials); if (!credentials.IsEmpty()) { @@ -166,29 +185,39 @@ GetRequestURLFromChrome(const nsAString& aRv = uriClone->GetSpec(spec); if (NS_WARN_IF(aRv.Failed())) { return; } CopyUTF8toUTF16(spec, aRequestURL); } -void -GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput, - nsAString& aRequestURL, ErrorResult& aRv) +already_AddRefed<workers::URL> +ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput, + ErrorResult& aRv) { workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref); RefPtr<workers::URL> url = workers::URL::Constructor(aGlobal, aInput, baseURL, aRv); if (NS_WARN_IF(aRv.Failed())) { aRv.ThrowTypeError<MSG_INVALID_URL>(aInput); + } + return url.forget(); +} + +void +GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput, + nsAString& aRequestURL, ErrorResult& aRv) +{ + RefPtr<workers::URL> url = ParseURLFromWorker(aGlobal, aInput, aRv); + if (aRv.Failed()) { return; } nsString username; url->GetUsername(username, aRv); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -210,16 +239,48 @@ GetRequestURLFromWorker(const GlobalObje } url->Stringify(aRequestURL, aRv); if (NS_WARN_IF(aRv.Failed())) { return; } } +class ReferrerSameOriginChecker final : public workers::WorkerMainThreadRunnable +{ +public: + ReferrerSameOriginChecker(workers::WorkerPrivate* aWorkerPrivate, + const nsAString& aReferrerURL, + nsresult& aResult) + : workers::WorkerMainThreadRunnable(aWorkerPrivate), + mReferrerURL(aReferrerURL), + mResult(aResult) + { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + bool + MainThreadRun() override + { + nsCOMPtr<nsIURI> uri; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mReferrerURL))) { + nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal(); + if (principal) { + mResult = principal->CheckMayLoad(uri, /* report */ false, + /* allowIfInheritsPrincipal */ false); + } + } + return true; + } + +private: + const nsString mReferrerURL; + nsresult& mResult; +}; + } // namespace /*static*/ already_AddRefed<Request> Request::Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv) { nsCOMPtr<nsIInputStream> temporaryBody; @@ -285,16 +346,84 @@ Request::Constructor(const GlobalObject& : fallbackCredentials; if (mode == RequestMode::Navigate || (aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate)) { aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>(NS_LITERAL_STRING("navigate")); return nullptr; } + if (aInit.IsAnyMemberPresent()) { + request->SetReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR)); + } + if (aInit.mReferrer.WasPassed()) { + const nsString& referrer = aInit.mReferrer.Value(); + if (referrer.IsEmpty()) { + request->SetReferrer(NS_LITERAL_STRING("")); + } else { + nsAutoString referrerURL; + if (NS_IsMainThread()) { + nsIDocument* doc = GetEntryDocument(); + nsCOMPtr<nsIURI> uri; + if (doc) { + uri = ParseURLFromDocument(doc, referrer, aRv); + } else { + // If we don't have a document, we must assume that this is a full URL. + uri = ParseURLFromChrome(referrer, aRv); + } + if (NS_WARN_IF(aRv.Failed())) { + aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer); + return nullptr; + } + nsAutoCString spec; + uri->GetSpec(spec); + CopyUTF8toUTF16(spec, referrerURL); + if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) { + nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull(); + if (principal) { + nsresult rv = principal->CheckMayLoad(uri, /* report */ false, + /* allowIfInheritsPrincipal */ false); + if (NS_FAILED(rv)) { + aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer); + return nullptr; + } + } + } + } else { + RefPtr<workers::URL> url = ParseURLFromWorker(aGlobal, referrer, aRv); + if (NS_WARN_IF(aRv.Failed())) { + aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer); + return nullptr; + } + url->Stringify(referrerURL, aRv); + if (NS_WARN_IF(aRv.Failed())) { + aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer); + return nullptr; + } + if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) { + workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate(); + nsresult rv = NS_OK; + // ReferrerSameOriginChecker uses a sync loop to get the main thread + // to perform the same-origin check. Overall, on Workers this method + // can create 3 sync loops (two for constructing URLs and one here) so + // in the future we may want to optimize it all by off-loading all of + // this work in a single sync loop. + RefPtr<ReferrerSameOriginChecker> checker = + new ReferrerSameOriginChecker(worker, referrerURL, rv); + checker->Dispatch(aRv); + if (aRv.Failed() || NS_FAILED(rv)) { + aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer); + return nullptr; + } + } + } + request->SetReferrer(referrerURL); + } + } + if (mode != RequestMode::EndGuard_) { request->ClearCreatedByFetchEvent(); request->SetMode(mode); } if (credentials != RequestCredentials::EndGuard_) { request->ClearCreatedByFetchEvent(); request->SetCredentialsMode(credentials);
--- a/dom/html/nsBrowserElement.cpp +++ b/dom/html/nsBrowserElement.cpp @@ -49,25 +49,25 @@ nsBrowserElement::IsNotWidgetOrThrow(Err } aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); return false; } void nsBrowserElement::InitBrowserElementAPI() { - bool isBrowserOrApp; + bool isMozBrowserOrApp; nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader(); NS_ENSURE_TRUE_VOID(frameLoader); - nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp); + nsresult rv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp); NS_ENSURE_SUCCESS_VOID(rv); rv = frameLoader->GetOwnerIsWidget(&mOwnerIsWidget); NS_ENSURE_SUCCESS_VOID(rv); - if (!isBrowserOrApp) { + if (!isMozBrowserOrApp) { return; } if (!mBrowserElementAPI) { mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1"); if (NS_WARN_IF(!mBrowserElementAPI)) { return; } @@ -505,23 +505,23 @@ nsBrowserElement::GetAllowedAudioChannel // If empty, it means that this is the first call of this method. if (mBrowserElementAudioChannels.IsEmpty()) { nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader(); if (NS_WARN_IF(!frameLoader)) { return; } - bool isBrowserOrApp; - aRv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp); + bool isMozBrowserOrApp; + aRv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp); if (NS_WARN_IF(aRv.Failed())) { return; } - if (!isBrowserOrApp) { + if (!isMozBrowserOrApp) { return; } nsCOMPtr<nsIDOMElement> frameElement; aRv = frameLoader->GetOwnerElement(getter_AddRefs(frameElement)); if (NS_WARN_IF(aRv.Failed())) { return; }
--- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -2366,17 +2366,17 @@ nsGenericHTMLFormElement::IntrinsicState NS_ASSERTION(IsSubmitControl(), "Default submit element that isn't a submit control."); // We are the default submit element (:default) state |= NS_EVENT_STATE_DEFAULT; } // Make the text controls read-write if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) && - IsTextControl(false)) { + IsTextOrNumberControl(/*aExcludePassword*/ false)) { bool roState = GetBoolAttr(nsGkAtoms::readonly); if (!roState) { state |= NS_EVENT_STATE_MOZ_READWRITE; state &= ~NS_EVENT_STATE_MOZ_READONLY; } }
--- a/dom/html/nsGenericHTMLFrameElement.cpp +++ b/dom/html/nsGenericHTMLFrameElement.cpp @@ -546,16 +546,30 @@ nsGenericHTMLFrameElement::GetReallyIsWi GetManifestURLByType(nsGkAtoms::mozwidget, widgetManifestURL); bool isWidget = !widgetManifestURL.IsEmpty(); *aOut = isWidget && !isApp; return NS_OK; } /* [infallible] */ NS_IMETHODIMP +nsGenericHTMLFrameElement::GetIsolated(bool *aOut) +{ + *aOut = true; + + if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) { + return NS_OK; + } + + // Isolation is only disabled if the attribute is present + *aOut = !HasAttr(kNameSpaceID_None, nsGkAtoms::noisolation); + return NS_OK; +} + +/* [infallible] */ NS_IMETHODIMP nsGenericHTMLFrameElement::GetIsExpectingSystemMessage(bool *aOut) { *aOut = false; if (!nsIMozBrowserFrame::GetReallyIsApp()) { return NS_OK; } @@ -700,9 +714,8 @@ nsGenericHTMLFrameElement::InitializeBro } void nsGenericHTMLFrameElement::SwapFrameLoaders(nsXULElement& aOtherOwner, ErrorResult& aError) { aError.Throw(NS_ERROR_NOT_IMPLEMENTED); } -
--- a/dom/html/nsIFormControl.h +++ b/dom/html/nsIFormControl.h @@ -171,17 +171,24 @@ public: */ inline bool IsSubmitControl() const; /** * Returns whether this is a text control. * @param aExcludePassword to have NS_FORM_INPUT_PASSWORD returning false. * @return whether this is a text control. */ - inline bool IsTextControl(bool aExcludePassword) const ; + inline bool IsTextControl(bool aExcludePassword) const; + + /** + * Returns true if this is a text control or a number control. + * @param aExcludePassword to have NS_FORM_INPUT_PASSWORD returning false. + * @return true if this is a text control or a number control. + */ + inline bool IsTextOrNumberControl(bool aExcludePassword) const; /** * Returns whether this is a single line text control. * @param aExcludePassword to have NS_FORM_INPUT_PASSWORD returning false. * @return whether this is a single line text control. */ inline bool IsSingleLineTextControl(bool aExcludePassword) const; @@ -231,16 +238,22 @@ bool nsIFormControl::IsTextControl(bool aExcludePassword) const { uint32_t type = GetType(); return type == NS_FORM_TEXTAREA || IsSingleLineTextControl(aExcludePassword, type); } bool +nsIFormControl::IsTextOrNumberControl(bool aExcludePassword) const +{ + return IsTextControl(aExcludePassword) || GetType() == NS_FORM_INPUT_NUMBER; +} + +bool nsIFormControl::IsSingleLineTextControl(bool aExcludePassword) const { return IsSingleLineTextControl(aExcludePassword, GetType()); } /*static*/ bool nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
--- a/dom/indexedDB/test/unit/test_defaultStorageUpgrade.js +++ b/dom/indexedDB/test/unit/test_defaultStorageUpgrade.js @@ -42,21 +42,21 @@ function testSteps() // This one lives in storage/default/file++++c++Users+joe+index.html { url: "file:///c:/Users/joe/index.html", dbName: "dbK", dbVersion: 1 }, // This one lives in storage/permanent/chrome { dbName: "dbL", dbVersion: 1 }, // This one lives in storage/default/1007+f+app+++system.gaiamobile.org - { appId: 1007, inMozBrowser: false, url: "app://system.gaiamobile.org", + { appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org", dbName: "dbM", dbVersion: 1 }, // This one lives in storage/default/1007+t+https+++developer.cdn.mozilla.net - { appId: 1007, inMozBrowser: true, url: "https://developer.cdn.mozilla.net", + { appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net", dbName: "dbN", dbVersion: 1 }, // This one lives in storage/default/http+++127.0.0.1 { url: "http://127.0.0.1", dbName: "dbO", dbVersion: 1 }, // This one lives in storage/default/file++++ { url: "file:///", dbName: "dbP", dbVersion: 1 }, @@ -88,17 +88,17 @@ function testSteps() function openDatabase(params) { let request; if ("url" in params) { let uri = ios.newURI(params.url, null, null); let principal = ssm.createCodebasePrincipal(uri, {appId: params.appId || ssm.NO_APPID, - inBrowser: params.inMozBrowser}); + inIsolatedMozBrowser: params.inIsolatedMozBrowser}); if ("dbVersion" in params) { request = indexedDB.openForPrincipal(principal, params.dbName, params.dbVersion); } else { request = indexedDB.openForPrincipal(principal, params.dbName, params.dbOptions); } } else {
--- a/dom/inputmethod/Keyboard.jsm +++ b/dom/inputmethod/Keyboard.jsm @@ -146,17 +146,17 @@ this.Keyboard = { type: 'inputmethod-contextchange', inputType: 'blur' }); this.formMM = null; } } else { // Ignore notifications that aren't from a BrowserOrApp - if (!frameLoader.ownerIsBrowserOrAppFrame) { + if (!frameLoader.ownerIsMozBrowserOrAppFrame) { return; } this.initFormsFrameScript(mm); } }, initFormsFrameScript: function(mm) { mm.addMessageListener('Forms:Focus', this);
--- a/dom/inputmethod/mochitest/test_bug1043828.html +++ b/dom/inputmethod/mochitest/test_bug1043828.html @@ -87,17 +87,17 @@ function runTest() { let imeUrl = basePath + '/file_blank.html'; SpecialPowers.pushPermissions([{ type: 'input', allow: true, context: { url: imeUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], function() { keyboardA.src = imeUrl; keyboardB.src = imeUrl; var handler = { handleEvent: function(){
--- a/dom/inputmethod/mochitest/test_bug944397.html +++ b/dom/inputmethod/mochitest/test_bug944397.html @@ -74,17 +74,17 @@ function runTest() { let imeUrl = basePath + '/file_inputmethod.html#data'; SpecialPowers.pushPermissions([{ type: 'input', allow: true, context: { url: imeUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], function() { // STEP 2c: Tell Gecko to use this iframe as its keyboard app let req = keyboard.setInputMethodActive(true); req.onsuccess = function() { ok(true, 'setInputMethodActive succeeded.');
--- a/dom/inputmethod/mochitest/test_focus_blur_manage_events.html +++ b/dom/inputmethod/mochitest/test_focus_blur_manage_events.html @@ -137,17 +137,17 @@ function setupInputAppFrame() { document.body.appendChild(inputAppFrame); SpecialPowers.pushPermissions([{ type: 'input', allow: true, context: { url: imeUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], function() { let mm = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame); inputAppFrame.addEventListener('mozbrowserloadend', function() { mm.addMessageListener('text:appEvent', function(msg) { ok(false, 'Input app should not receive ' + msg.data.type + ' event.'); });
--- a/dom/inputmethod/mochitest/test_input_registry_events.html +++ b/dom/inputmethod/mochitest/test_input_registry_events.html @@ -66,17 +66,17 @@ function setupInputAppFrame() { document.body.appendChild(inputAppFrame); SpecialPowers.pushPermissions([{ type: 'input', allow: true, context: { url: imeUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], function() { let mm = appFrameMM = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame); inputAppFrame.addEventListener('mozbrowserloadend', function() { mm.addMessageListener('test:appEvent', function(msg) {
--- a/dom/inputmethod/mochitest/test_simple_manage_events.html +++ b/dom/inputmethod/mochitest/test_simple_manage_events.html @@ -99,17 +99,17 @@ function setupInputAppFrame() { document.body.appendChild(inputAppFrame); SpecialPowers.pushPermissions([{ type: 'input', allow: true, context: { url: imeUrl, originAttributes: { - inBrowser: true + inIsolatedMozBrowser: true } } }], function() { let mm = appFrameMM = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame); inputAppFrame.addEventListener('mozbrowserloadend', function() { mm.addMessageListener('test:appEvent', function(msg) {
--- a/dom/interfaces/apps/nsIAppsService.idl +++ b/dom/interfaces/apps/nsIAppsService.idl @@ -61,16 +61,21 @@ interface nsIAppsService : nsISupports */ DOMString getCoreAppsBasePath(); /** * Returns the basepath for regular packaged apps */ DOMString getWebAppsBasePath(); + /** + * Returns true if at least one app is in the registry. + */ + boolean areAnyAppsInstalled(); + jsval getAppInfo(in DOMString appId); /** * Returns a URI to redirect to when we get a redirection to 'uri'. * Returns null if no redirection is declared for this uri. */ nsIURI getRedirect(in unsigned long localId, in nsIURI uri);
--- a/dom/interfaces/html/nsIMozBrowserFrame.idl +++ b/dom/interfaces/html/nsIMozBrowserFrame.idl @@ -39,16 +39,30 @@ interface nsIMozBrowserFrame : nsIDOMMoz * In order to really be a frame, this frame must really be a browser * frame (this requirement will go away eventually), the frame's mozwidget * attribute must point to the manifest of a valid app, and the src should * be in the |widgetPages| specified by the manifest. */ [infallible] readonly attribute boolean reallyIsWidget; /** + * Gets whether this frame is an isolated frame. + * + * By default, browser frames are isolated, meaning they have a principal + * where OriginAttributes.mIsInIsolatedMozBrowser == true. This isolates + * storage and other origin related items from non-browser apps, xul:browsers, + * etc. + * + * Isolation can be disabled by setting the frame's isolated attribute to + * false. Disabling isolation is only allowed if the containing document has + * browser permission (or equivalent access). + */ + [infallible] readonly attribute boolean isolated; + + /** * This corresponds to the expecting-system-message attribute, which tells us * whether we should expect that this frame will receive a system message once * it starts up. * * It's the embedder's job to set this attribute on a frame. Its presence * might cause us to increase the priority of the frame's process. */ [infallible] readonly attribute boolean isExpectingSystemMessage;
--- a/dom/ipc/AppProcessChecker.cpp +++ b/dom/ipc/AppProcessChecker.cpp @@ -86,17 +86,17 @@ AssertAppProcess(PBrowserParent* aActor, if (!aActor) { NS_WARNING("Testing process capability for null actor"); return false; } TabParent* tab = TabParent::GetFrom(aActor); nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp(); - return CheckAppTypeHelper(app, aType, aCapability, tab->IsBrowserElement()); + return CheckAppTypeHelper(app, aType, aCapability, tab->IsMozBrowserElement()); } static bool CheckAppStatusHelper(mozIApplication* aApp, unsigned short aStatus) { bool valid = false; @@ -168,17 +168,17 @@ AssertAppProcess(TabContext& aContext, // Do a origin-based permission check if the TabContext owns a signed package. if (!aContext.SignedPkgOriginNoSuffix().IsEmpty() && (ASSERT_APP_HAS_PERMISSION == aType || ASSERT_APP_PROCESS_PERMISSION == aType)) { nsCString origin = aContext.SignedPkgOriginNoSuffix() + suffix; return CheckOriginPermission(origin, aCapability); } nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp(); - return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement()); + return CheckAppTypeHelper(app, aType, aCapability, aContext.IsMozBrowserElement()); } bool AssertAppStatus(TabContext& aContext, unsigned short aStatus) { nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp(); @@ -244,26 +244,26 @@ AssertAppPrincipal(PContentParent* aActo { if (!aPrincipal) { NS_WARNING("Principal is invalid, killing app process"); static_cast<ContentParent*>(aActor)->KillHard("AssertAppPrincipal"); return false; } uint32_t principalAppId = aPrincipal->GetAppId(); - bool inBrowserElement = aPrincipal->GetIsInBrowserElement(); + bool inIsolatedBrowser = aPrincipal->GetIsInIsolatedMozBrowserElement(); // Check if the permission's appId matches a child we manage. nsTArray<TabContext> contextArray = static_cast<ContentParent*>(aActor)->GetManagedTabContext(); for (uint32_t i = 0; i < contextArray.Length(); ++i) { if (contextArray[i].OwnOrContainingAppId() == principalAppId) { - // If the child only runs inBrowserElement content and the principal claims - // it's not in a browser element, it's lying. - if (!contextArray[i].IsBrowserElement() || inBrowserElement) { + // If the child only runs isolated browser content and the principal + // claims it's not in an isolated browser element, it's lying. + if (!contextArray[i].IsIsolatedMozBrowserElement() || inIsolatedBrowser) { return true; } break; } } NS_WARNING("Principal is invalid, killing app process"); static_cast<ContentParent*>(aActor)->KillHard("AssertAppPrincipal"); @@ -314,18 +314,27 @@ CheckPermission(PContentParent* aActor, NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION); if (permission == nsIPermissionManager::UNKNOWN_ACTION || permission == nsIPermissionManager::DENY_ACTION) { return permission; } // For browser content (and if the app hasn't explicitly denied this), // consider the requesting origin, not the app. + // After bug 1238160, the principal no longer knows how to answer "is this a + // browser element", which is really what this code path wants. Currently, + // desktop is the only platform where we intend to disable isolation on a + // browser frame, so non-desktop should be able to assume that + // inIsolatedMozBrowser is true for all mozbrowser frames. This code path is + // currently unused on desktop, since MOZ_CHILD_PERMISSIONS is only set for + // MOZ_B2G. We use a release assertion in + // nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so that platforms with apps + // can assume inIsolatedMozBrowser is true for all mozbrowser frames. if (appPerm == nsIPermissionManager::PROMPT_ACTION && - aPrincipal->GetIsInBrowserElement()) { + aPrincipal->GetIsInIsolatedMozBrowserElement()) { return permission; } // Setting to "prompt" in the settings UI should prompt everywhere in // non-browser content. if (appPerm == nsIPermissionManager::PROMPT_ACTION || permission == nsIPermissionManager::PROMPT_ACTION) { return nsIPermissionManager::PROMPT_ACTION;
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -801,17 +801,17 @@ ContentChild::ProvideWindowCommon(TabChi nsAutoPtr<IPCTabContext> ipcContext; TabId openerTabId = TabId(0); if (aTabOpener) { PopupIPCTabContext context; openerTabId = aTabOpener->GetTabId(); context.opener() = openerTabId; - context.isBrowserElement() = aTabOpener->IsBrowserElement(); + context.isMozBrowserElement() = aTabOpener->IsMozBrowserElement(); ipcContext = new IPCTabContext(context); } else { // It's possible to not have a TabChild opener in the case // of ServiceWorker::OpenWindow. UnsafeIPCTabContext unsafeTabContext; ipcContext = new IPCTabContext(unsafeTabContext); }
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -62,16 +62,17 @@ #include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/bluetooth/PBluetoothParent.h" #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h" #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h" #include "mozilla/dom/icc/IccParent.h" #include "mozilla/dom/mobileconnection/MobileConnectionParent.h" #include "mozilla/dom/mobilemessage/SmsParent.h" #include "mozilla/dom/power/PowerManagerService.h" +#include "mozilla/dom/Permissions.h" #include "mozilla/dom/PresentationParent.h" #include "mozilla/dom/PPresentationParent.h" #include "mozilla/dom/quota/QuotaManagerService.h" #include "mozilla/dom/telephony/TelephonyParent.h" #include "mozilla/dom/time/DateCacheCleaner.h" #include "mozilla/dom/voicemail/VoicemailParent.h" #include "mozilla/embedding/printingui/PrintingParent.h" #include "mozilla/hal_sandbox/PHalParent.h" @@ -1049,16 +1050,24 @@ ContentParent::RecvUngrabPointer(const u return false; #else gdk_pointer_ungrab(aTime); return true; #endif } bool +ContentParent::RecvRemovePermission(const IPC::Principal& aPrincipal, + const nsCString& aPermissionType, + nsresult* aRv) { + *aRv = Permissions::RemovePermission(aPrincipal, aPermissionType.get()); + return true; +} + +bool ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv) { *aRv = NS_OK; // We don't need to get the run ID for the plugin, since we already got it // in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy // pointer and just throw it away. uint32_t dummy = 0; return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv, &dummy); @@ -1117,29 +1126,29 @@ ContentParent::CreateBrowserOrApp(const TabId tabId; nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement); TabId openerTabId; if (docShell) { openerTabId = TabParent::GetTabIdFrom(docShell); } - if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) { + if (aContext.IsMozBrowserElement() || !aContext.HasOwnApp()) { RefPtr<TabParent> tp; RefPtr<nsIContentParent> constructorSender; if (isInContentProcess) { - MOZ_ASSERT(aContext.IsBrowserElement()); + MOZ_ASSERT(aContext.IsMozBrowserElement()); constructorSender = CreateContentBridgeParent(aContext, initialPriority, openerTabId, &tabId); } else { if (aOpenerContentParent) { constructorSender = aOpenerContentParent; } else { constructorSender = - GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(), + GetNewOrUsedBrowserProcess(aContext.IsMozBrowserElement(), initialPriority); if (!constructorSender) { return nullptr; } } tabId = AllocateTabId(openerTabId, aContext.AsIPCTabContext(), constructorSender->ChildID()); @@ -5329,17 +5338,17 @@ ContentParent::RecvCreateWindow(PBrowser return false; } TabParent* thisTabParent = nullptr; if (aThisTab) { thisTabParent = TabParent::GetFrom(aThisTab); } - if (NS_WARN_IF(thisTabParent && thisTabParent->IsBrowserOrApp())) { + if (NS_WARN_IF(thisTabParent && thisTabParent->IsMozBrowserOrApp())) { return false; } nsCOMPtr<nsPIWindowWatcher> pwwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult); if (NS_WARN_IF(NS_FAILED(*aResult))) { return true;
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -208,16 +208,20 @@ public: virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch, nsresult* aRv, nsTArray<PluginTag>* aPlugins, uint32_t* aNewPluginEpoch) override; virtual bool RecvUngrabPointer(const uint32_t& aTime) override; + virtual bool RecvRemovePermission(const IPC::Principal& aPrincipal, + const nsCString& aPermissionType, + nsresult* aRv) override; + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_NSIOBSERVER NS_DECL_NSIDOMGEOPOSITIONCALLBACK NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK /**
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -1185,15 +1185,17 @@ parent: /** * Tells the parent to ungrab the pointer on the default display. * * This is for GTK platforms where we have to ensure the pointer ungrab happens in the * chrome process as that's the process that receives the pointer event. */ sync UngrabPointer(uint32_t time); + + sync RemovePermission(Principal principal, nsCString permissionType) returns (nsresult rv); both: async AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal); }; } }
--- a/dom/ipc/PTabContext.ipdlh +++ b/dom/ipc/PTabContext.ipdlh @@ -8,45 +8,50 @@ include protocol PBrowser; include PBrowserOrId; namespace mozilla { namespace dom { // An IPCTabContext which corresponds to a PBrowser opened by a child when it // receives window.open(). // -// If isBrowserElement is false, this PopupIPCTabContext corresponds to an app -// frame, and the frame's app-id and app-frame-owner-app-id will be equal to the -// opener's values. +// If isMozBrowserElement is false, this PopupIPCTabContext is either a +// <xul:browser> or an app frame. The frame's app-id and app-frame-owner-app-id +// will be equal to the opener's values. For a <xul:browser>, those app IDs +// will be NO_APP_ID. // -// If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal -// to the opener's app-id. +// If isMozBrowserElement is true, the frame's browserFrameOwnerAppId will be +// equal to the opener's app-id. // -// It's an error to set isBrowserElement == false if opener is a browser +// It's an error to set isMozBrowserElement == false if opener is a mozbrowser // element. Such a PopupIPCTabContext should be rejected by code which receives // it. struct PopupIPCTabContext { PBrowserOrId opener; - bool isBrowserElement; + bool isMozBrowserElement; }; // An IPCTabContext which corresponds to an app, browser, or normal frame. struct FrameIPCTabContext { // The stringified originAttributes dictionary. nsCString originSuffix; // The ID of the app containing this app/browser frame, if applicable. uint32_t frameOwnerAppId; // The origin without originAttribute suffix for a signed package. // This value would be empty if the TabContext doesn't own a signed // package. nsCString signedPkgOriginNoSuffix; + + // Whether this is a mozbrowser frame. <iframe mozbrowser mozapp> and + // <xul:browser> are not considered to be mozbrowser frames. + bool isMozBrowserElement; }; // XXXcatalinb: This is only used by ServiceWorkerClients::OpenWindow. // Because service workers don't have an associated TabChild // we can't satisfy the security constraints on b2g. As such, the parent // process will accept this tab context only on desktop. struct UnsafeIPCTabContext { };
--- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -864,19 +864,19 @@ ParticularProcessPriorityManager::OnRemo NS_ENSURE_TRUE_VOID(tp); MOZ_ASSERT(XRE_IsParentProcess()); if (tp->Manager() != mContentParent) { return; } // Ignore notifications that aren't from a BrowserOrApp - bool isBrowserOrApp; - fl->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp); - if (isBrowserOrApp) { + bool isMozBrowserOrApp; + fl->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp); + if (isMozBrowserOrApp) { ResetPriority(); } nsCOMPtr<nsIObserverService> os = services::GetObserverService(); if (os) { os->RemoveObserver(this, "remote-browser-shown"); } }
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -544,17 +544,17 @@ TabChild::PreloadSlowThings() /*static*/ already_AddRefed<TabChild> TabChild::Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext &aContext, uint32_t aChromeFlags) { if (sPreallocatedTab && sPreallocatedTab->mChromeFlags == aChromeFlags && - aContext.IsBrowserOrApp()) { + aContext.IsMozBrowserOrApp()) { RefPtr<TabChild> child = sPreallocatedTab.get(); sPreallocatedTab = nullptr; MOZ_ASSERT(!child->mTriedBrowserInit); child->mManager = aManager; child->SetTabId(aTabId); @@ -860,18 +860,19 @@ void TabChild::NotifyTabContextUpdated() { nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); if (docShell) { // nsDocShell will do the right thing if we pass NO_APP_ID or // UNKNOWN_APP_ID for aOwnOrContainingAppId. - if (IsBrowserElement()) { + if (IsMozBrowserElement()) { docShell->SetIsBrowserInsideApp(BrowserOwnerAppId()); + docShell->SetIsInIsolatedMozBrowserElement(IsIsolatedMozBrowserElement()); } else { docShell->SetIsApp(OwnAppId()); } OriginAttributes attrs = OriginAttributesRef(); docShell->SetIsSignedPackage(attrs.mSignedPkg); docShell->SetUserContextId(attrs.mUserContextId); } @@ -1105,17 +1106,17 @@ TabChild::ProvideWindow(mozIDOMWindowPro mozIDOMWindowProxy** aReturn) { *aReturn = nullptr; // If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this // isn't a request to open a modal-type window, we're going to create a new // <iframe mozbrowser/mozapp> and return its window here. nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent); - bool iframeMoz = (docshell && docshell->GetIsInBrowserOrApp() && + bool iframeMoz = (docshell && docshell->GetIsInMozBrowserOrApp() && !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | nsIWebBrowserChrome::CHROME_OPENAS_CHROME))); if (!iframeMoz) { int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter::From(aParent), aChromeFlags, aCalledFromJS, @@ -1498,17 +1499,17 @@ TabChild::ApplyShowInfo(const ShowInfo& // Once we've got one ShowInfo from parent, no need to update the values // anymore. mDidSetRealShowInfo = true; } nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); if (docShell) { nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell); - if (IsBrowserOrApp()) { + if (IsMozBrowserOrApp()) { // B2G allows window.name to be set by changing the name attribute on the // <iframe mozbrowser> element. window.open calls cause this attribute to // be set to the correct value. A normal <xul:browser> element has no such // attribute. The data we get here comes from reading the attribute, so we // shouldn't trust it for <xul:browser> elements. item->SetName(aInfo.name()); } docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed()); @@ -1535,17 +1536,17 @@ TabChild::ApplyShowInfo(const ShowInfo& } #ifdef MOZ_WIDGET_GONK void TabChild::MaybeRequestPreinitCamera() { // Check if this tab is an app (not a browser frame) and will use the // `camera` permission, - if (IsBrowserElement()) { + if (IsIsolatedMozBrowserElement()) { return; } nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1"); if (NS_WARN_IF(!appsService)) { return; } @@ -2520,17 +2521,17 @@ TabChild::InitTabChildGlobal(FrameScript NS_ENSURE_TRUE(root, false); root->SetParentTarget(scope); } if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) { mTriedBrowserInit = true; // Initialize the child side of the browser element machinery, // if appropriate. - if (IsBrowserOrApp()) { + if (IsMozBrowserOrApp()) { RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true); } } return true; } bool
--- a/dom/ipc/TabContext.cpp +++ b/dom/ipc/TabContext.cpp @@ -17,31 +17,38 @@ using namespace mozilla::dom::ipc; using namespace mozilla::layout; namespace mozilla { namespace dom { TabContext::TabContext() : mInitialized(false) + , mIsMozBrowserElement(false) , mContainingAppId(NO_APP_ID) , mOriginAttributes() { } bool -TabContext::IsBrowserElement() const +TabContext::IsMozBrowserElement() const { - return mOriginAttributes.mInBrowser; + return mIsMozBrowserElement; } bool -TabContext::IsBrowserOrApp() const +TabContext::IsIsolatedMozBrowserElement() const { - return HasOwnApp() || IsBrowserElement(); + return mOriginAttributes.mInIsolatedMozBrowser; +} + +bool +TabContext::IsMozBrowserOrApp() const +{ + return HasOwnApp() || IsMozBrowserElement(); } uint32_t TabContext::OwnAppId() const { return mOriginAttributes.mAppId; } @@ -57,27 +64,27 @@ TabContext::HasOwnApp() const { nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); return !!ownApp; } uint32_t TabContext::BrowserOwnerAppId() const { - if (IsBrowserElement()) { + if (IsMozBrowserElement()) { return mContainingAppId; } return NO_APP_ID; } already_AddRefed<mozIApplication> TabContext::GetBrowserOwnerApp() const { nsCOMPtr<mozIApplication> ownerApp; - if (IsBrowserElement()) { + if (IsMozBrowserElement()) { ownerApp = mContainingApp; } return ownerApp.forget(); } bool TabContext::HasBrowserOwnerApp() const { @@ -160,17 +167,18 @@ TabContext::OriginAttributesRef() const const nsACString& TabContext::SignedPkgOriginNoSuffix() const { return mSignedPkgOriginNoSuffix; } bool -TabContext::SetTabContext(mozIApplication* aOwnApp, +TabContext::SetTabContext(bool aIsMozBrowserElement, + mozIApplication* aOwnApp, mozIApplication* aAppFrameOwnerApp, const DocShellOriginAttributes& aOriginAttributes, const nsACString& aSignedPkgOriginNoSuffix) { NS_ENSURE_FALSE(mInitialized, false); // Get ids for both apps and only write to our member variables after we've // verified that this worked. @@ -189,32 +197,34 @@ TabContext::SetTabContext(mozIApplicatio } // Veryify that app id matches mAppId passed in originAttributes MOZ_RELEASE_ASSERT((aOwnApp && aOriginAttributes.mAppId == ownAppId) || (aAppFrameOwnerApp && aOriginAttributes.mAppId == containingAppId) || aOriginAttributes.mAppId == NO_APP_ID); mInitialized = true; + mIsMozBrowserElement = aIsMozBrowserElement; mOriginAttributes = aOriginAttributes; mContainingAppId = containingAppId; mOwnApp = aOwnApp; mContainingApp = aAppFrameOwnerApp; mSignedPkgOriginNoSuffix = aSignedPkgOriginNoSuffix; return true; } IPCTabContext TabContext::AsIPCTabContext() const { nsAutoCString originSuffix; mOriginAttributes.CreateSuffix(originSuffix); return IPCTabContext(FrameIPCTabContext(originSuffix, mContainingAppId, - mSignedPkgOriginNoSuffix)); + mSignedPkgOriginNoSuffix, + mIsMozBrowserElement)); } static already_AddRefed<mozIApplication> GetAppForId(uint32_t aAppId) { nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); NS_ENSURE_TRUE(appsService, nullptr); @@ -222,29 +232,31 @@ GetAppForId(uint32_t aAppId) appsService->GetAppByLocalId(aAppId, getter_AddRefs(app)); return app.forget(); } MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams) : mInvalidReason(nullptr) { + bool isMozBrowserElement = false; uint32_t containingAppId = NO_APP_ID; DocShellOriginAttributes originAttributes; nsAutoCString originSuffix; nsAutoCString signedPkgOriginNoSuffix; switch(aParams.type()) { case IPCTabContext::TPopupIPCTabContext: { const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext(); TabContext *context; if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) { context = TabParent::GetFrom(ipcContext.opener().get_PBrowserParent()); - if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) { + if (context->IsMozBrowserElement() && + !ipcContext.isMozBrowserElement()) { // If the TabParent corresponds to a browser element, then it can only // open other browser elements, for security reasons. We should have // checked this before calling the TabContext constructor, so this is // a fatal error. mInvalidReason = "Child is-browser process tried to " "open a non-browser tab."; return; } @@ -264,28 +276,30 @@ MaybeInvalidTabContext::MaybeInvalidTabC // Browser elements can't nest other browser elements. So if // our opener is browser element, we must be a new DOM window // opened by it. In that case we inherit our containing app ID // (if any). // // Otherwise, we're a new app window and we inherit from our // opener app. + isMozBrowserElement = ipcContext.isMozBrowserElement(); originAttributes = context->mOriginAttributes; - if (ipcContext.isBrowserElement()) { + if (isMozBrowserElement) { containingAppId = context->OwnOrContainingAppId(); } else { containingAppId = context->mContainingAppId; } break; } case IPCTabContext::TFrameIPCTabContext: { const FrameIPCTabContext &ipcContext = aParams.get_FrameIPCTabContext(); + isMozBrowserElement = ipcContext.isMozBrowserElement(); containingAppId = ipcContext.frameOwnerAppId(); signedPkgOriginNoSuffix = ipcContext.signedPkgOriginNoSuffix(); originSuffix = ipcContext.originSuffix(); originAttributes.PopulateFromSuffix(originSuffix); break; } case IPCTabContext::TUnsafeIPCTabContext: { // XXXcatalinb: This used *only* by ServiceWorkerClients::OpenWindow. @@ -305,34 +319,35 @@ MaybeInvalidTabContext::MaybeInvalidTabC break; } default: { MOZ_CRASH(); } } nsCOMPtr<mozIApplication> ownApp; - if (!originAttributes.mInBrowser) { - // mAppId corresponds to OwnOrContainingAppId; if mInBrowser is + if (!isMozBrowserElement) { + // mAppId corresponds to OwnOrContainingAppId; if isMozBrowserElement is // false then it's ownApp otherwise it's containingApp ownApp = GetAppForId(originAttributes.mAppId); if ((ownApp == nullptr) != (originAttributes.mAppId == NO_APP_ID)) { mInvalidReason = "Got an ownAppId that didn't correspond to an app."; return; } } nsCOMPtr<mozIApplication> containingApp = GetAppForId(containingAppId); if ((containingApp == nullptr) != (containingAppId == NO_APP_ID)) { mInvalidReason = "Got a containingAppId that didn't correspond to an app."; return; } bool rv; - rv = mTabContext.SetTabContext(ownApp, + rv = mTabContext.SetTabContext(isMozBrowserElement, + ownApp, containingApp, originAttributes, signedPkgOriginNoSuffix); if (!rv) { mInvalidReason = "Couldn't initialize TabContext."; } }
--- a/dom/ipc/TabContext.h +++ b/dom/ipc/TabContext.h @@ -37,47 +37,61 @@ public: /** * Generates IPCTabContext of type BrowserFrameIPCTabContext or * AppFrameIPCTabContext from this TabContext's information. */ IPCTabContext AsIPCTabContext() const; /** - * Does this TabContext correspond to a mozbrowser? (<iframe mozbrowser - * mozapp> is not a browser.) + * Does this TabContext correspond to a mozbrowser? * - * If IsBrowserElement() is true, HasOwnApp() and HasAppOwnerApp() are + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. + * + * If IsMozBrowserElement() is true, HasOwnApp() and HasAppOwnerApp() are * guaranteed to be false. * - * If IsBrowserElement() is false, HasBrowserOwnerApp() is guaranteed to be + * If IsMozBrowserElement() is false, HasBrowserOwnerApp() is guaranteed to be * false. */ - bool IsBrowserElement() const; + bool IsMozBrowserElement() const; + + /** + * Does this TabContext correspond to an isolated mozbrowser? + * + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. <iframe mozbrowser noisolation> does not count as + * isolated since isolation is disabled. Isolation can only be disabled by + * chrome pages. + */ + bool IsIsolatedMozBrowserElement() const; /** * Does this TabContext correspond to a mozbrowser or mozapp? This is - * equivalent to IsBrowserElement() || HasOwnApp(). + * equivalent to IsMozBrowserElement() || HasOwnApp(). Returns false for + * <xul:browser>, which is neither a mozbrowser nor a mozapp. */ - bool IsBrowserOrApp() const; + bool IsMozBrowserOrApp() const; /** * OwnAppId() returns the id of the app which directly corresponds to this * context's frame. GetOwnApp() returns the corresponding app object, and * HasOwnApp() returns true iff GetOwnApp() would return a non-null value. * - * If HasOwnApp() is true, IsBrowserElement() is guaranteed to be false. + * If HasOwnApp() is true, IsMozBrowserElement() is guaranteed to be + * false. */ uint32_t OwnAppId() const; already_AddRefed<mozIApplication> GetOwnApp() const; bool HasOwnApp() const; /** * BrowserOwnerAppId() gets the ID of the app which contains this browser - * frame. If this is not a browser frame (i.e., if !IsBrowserElement()), then + * frame. If this is not a mozbrowser frame (if !IsMozBrowserElement()), then * BrowserOwnerAppId() is guaranteed to return NO_APP_ID. * * Even if we are a browser frame, BrowserOwnerAppId() may still return * NO_APP_ID, if this browser frame is not contained inside an app. */ uint32_t BrowserOwnerAppId() const; already_AddRefed<mozIApplication> GetBrowserOwnerApp() const; bool HasBrowserOwnerApp() const; @@ -135,37 +149,46 @@ protected: /** * Set the TabContext for this frame. This can either be: * - an app frame (with the given own app) inside the given owner app. Either * apps can be null. * - a browser frame inside the given owner app (which may be null). * - a non-browser, non-app frame. Both own app and owner app should be null. */ - bool SetTabContext(mozIApplication* aOwnApp, + bool SetTabContext(bool aIsMozBrowserElement, + mozIApplication* aOwnApp, mozIApplication* aAppFrameOwnerApp, const DocShellOriginAttributes& aOriginAttributes, const nsACString& aSignedPkgOriginNoSuffix); private: /** * Has this TabContext been initialized? If so, mutator methods will fail. */ bool mInitialized; /** + * Whether this TabContext corresponds to a mozbrowser. + * + * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. + */ + bool mIsMozBrowserElement; + + /** * This TabContext's own app. If this is non-null, then this - * TabContext corresponds to an app, and mIsBrowser must be false. + * TabContext corresponds to an app, and mIsMozBrowserElement must be false. */ nsCOMPtr<mozIApplication> mOwnApp; /** - * This TabContext's containing app. If mIsBrowser, this corresponds to the - * app which contains the browser frame; otherwise, this corresponds to the - * app which contains the app frame. + * This TabContext's containing app. If mIsMozBrowserElement, this + * corresponds to the app which contains the browser frame; otherwise, this + * corresponds to the app which contains the app frame. */ nsCOMPtr<mozIApplication> mContainingApp; /* * Cache of mContainingApp->GetLocalId(). */ uint32_t mContainingAppId; @@ -192,22 +215,24 @@ class MutableTabContext : public TabCont { public: bool SetTabContext(const TabContext& aContext) { return TabContext::SetTabContext(aContext); } bool - SetTabContext(mozIApplication* aOwnApp, + SetTabContext(bool aIsMozBrowserElement, + mozIApplication* aOwnApp, mozIApplication* aAppFrameOwnerApp, const DocShellOriginAttributes& aOriginAttributes, const nsACString& aSignedPkgOriginNoSuffix = EmptyCString()) { - return TabContext::SetTabContext(aOwnApp, + return TabContext::SetTabContext(aIsMozBrowserElement, + aOwnApp, aAppFrameOwnerApp, aOriginAttributes, aSignedPkgOriginNoSuffix); } }; /** * MaybeInvalidTabContext is a simple class that lets you transform an
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3098,17 +3098,17 @@ public: return NS_OK; } NS_IMETHOD GetNestedFrameId(uint64_t*) NO_IMPL NS_IMETHOD IsAppOfType(uint32_t, bool*) NO_IMPL NS_IMETHOD GetIsContent(bool*) NO_IMPL NS_IMETHOD GetUsePrivateBrowsing(bool*) NO_IMPL NS_IMETHOD SetUsePrivateBrowsing(bool) NO_IMPL NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL - NS_IMETHOD GetIsInBrowserElement(bool*) NO_IMPL + NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL NS_IMETHOD GetAppId(uint32_t*) NO_IMPL NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL NS_IMETHOD SetRemoteTabs(bool) NO_IMPL #undef NO_IMPL protected: ~FakeChannel() {}
--- a/dom/ipc/nsIContentParent.cpp +++ b/dom/ipc/nsIContentParent.cpp @@ -89,20 +89,20 @@ nsIContentParent::CanOpenBrowser(const I } auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent()); if (!opener) { ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent."); return false; } - // Popup windows of isBrowser frames must be isBrowser if the parent - // isBrowser. Allocating a !isBrowser frame with same app ID would allow - // the content to access data it's not supposed to. - if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) { + // Popup windows of isMozBrowserElement frames must be isMozBrowserElement if + // the parent isMozBrowserElement. Allocating a !isMozBrowserElement frame with + // same app ID would allow the content to access data it's not supposed to. + if (!popupContext.isMozBrowserElement() && opener->IsMozBrowserElement()) { ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent."); return false; } } MaybeInvalidTabContext tc(aContext); if (!tc.IsValid()) { NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
--- a/dom/media/TextTrack.cpp +++ b/dom/media/TextTrack.cpp @@ -1,14 +1,15 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 et tw=78: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/AsyncEventDispatcher.h" #include "mozilla/dom/TextTrack.h" #include "mozilla/dom/TextTrackBinding.h" #include "mozilla/dom/TextTrackList.h" #include "mozilla/dom/TextTrackCue.h" #include "mozilla/dom/TextTrackCueList.h" #include "mozilla/dom/TextTrackRegion.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/HTMLTrackElement.h" @@ -143,41 +144,56 @@ TextTrack::UpdateActiveCueList() return; } HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement(); if (!mediaElement) { return; } + // Flag that indicates whether or not this call of UpdateActiveCueList has + // changed the activeCueList. + bool hasChanged = false; + // If we are dirty, i.e. an event happened that may cause the sorted mCueList // to have changed like a seek or an insert for a cue, than we need to rebuild // the active cue list from scratch. if (mDirty) { mCuePos = 0; mDirty = false; mActiveCueList->RemoveAll(); } double playbackTime = mediaElement->CurrentTime(); // Remove all the cues from the active cue list whose end times now occur // earlier then the current playback time. for (uint32_t i = mActiveCueList->Length(); i > 0; i--) { if ((*mActiveCueList)[i - 1]->EndTime() < playbackTime) { mActiveCueList->RemoveCueAt(i - 1); + hasChanged = true; } } // Add all the cues, starting from the position of the last cue that was // added, that have valid start and end times for the current playback time. // We can stop iterating safely once we encounter a cue that does not have // a valid start time as the cue list is sorted. for (; mCuePos < mCueList->Length() && (*mCueList)[mCuePos]->StartTime() <= playbackTime; mCuePos++) { if ((*mCueList)[mCuePos]->EndTime() >= playbackTime) { mActiveCueList->AddCue(*(*mCueList)[mCuePos]); + hasChanged = true; + } + } + + if (hasChanged) { + RefPtr<AsyncEventDispatcher> asyncDispatcher = + new AsyncEventDispatcher(this, NS_LITERAL_STRING("cuechange"), false); + asyncDispatcher->PostDOMEvent(); + if (mTrackElement) { + mTrackElement->DispatchTrackRunnable(NS_LITERAL_STRING("cuechange")); } } } TextTrackCueList* TextTrack::GetActiveCues() { if (mMode != TextTrackMode::Disabled) { UpdateActiveCueList();
--- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -572,16 +572,22 @@ MediaKeySystemAccess::GetSupportedConfig /* static */ void MediaKeySystemAccess::NotifyObservers(nsPIDOMWindowInner* aWindow, const nsAString& aKeySystem, MediaKeySystemStatus aStatus) { + if (aStatus == MediaKeySystemStatus::Cdm_not_supported) { + // Ignore, since there's nothing the user can do to rectify this, and we + // don't want the prompt to confuse them. + // TODO: Remove places that call with this entirely. + return; + } RequestMediaKeySystemAccessNotification data; data.mKeySystem = aKeySystem; data.mStatus = aStatus; nsAutoString json; data.ToJSON(json); EME_LOG("MediaKeySystemAccess::NotifyObservers() %s", NS_ConvertUTF16toUTF8(json).get()); nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (obs) {
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp +++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp @@ -12,16 +12,17 @@ #include "mozilla/Preferences.h" #include "mozilla/DebugOnly.h" #include "mozilla/Services.h" #include "WMFMediaDataDecoder.h" #include "nsIWindowsRegKey.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsIGfxInfo.h" +#include "nsWindowsHelpers.h" #include "GfxDriverInfo.h" #include "gfxWindowsPlatform.h" #include "MediaInfo.h" #include "prsystem.h" #include "mozilla/Maybe.h" #include "mozilla/StaticMutex.h" namespace mozilla { @@ -158,19 +159,55 @@ CanCreateWMFDecoder() StaticMutexAutoLock lock(sMutex); static Maybe<bool> result; if (result.isNothing()) { result.emplace(CanCreateMFTDecoder(aGuid)); } return result.value(); } +static bool +IsH264DecoderBlacklisted() +{ +#ifdef _WIN64 + WCHAR systemPath[MAX_PATH + 1]; + if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) { + // Cannot build path -> Assume it's not the blacklisted DLL. + return false; + } + + DWORD zero; + DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero); + if (infoSize == 0) { + // Can't get file info -> Assume we don't have the blacklisted DLL. + return false; + } + auto infoData = MakeUnique<unsigned char[]>(infoSize); + VS_FIXEDFILEINFO *vInfo; + UINT vInfoLen; + if (GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) && + VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)) + { + if ((vInfo->dwFileVersionMS == ((12u << 16) | 0u)) + && ((vInfo->dwFileVersionLS == ((9200u << 16) | 16426u)) + || (vInfo->dwFileVersionLS == ((9200u << 16) | 17037u)))) { + // 12.0.9200.16426 & .17037 are blacklisted on Win64, see bug 1242343. + return true; + } + } +#endif // _WIN64 + return false; +} + /* static */ bool WMFDecoderModule::HasH264() { + if (IsH264DecoderBlacklisted()) { + return false; + } return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>(); } /* static */ bool WMFDecoderModule::HasAAC() { return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>(); }
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -483,16 +483,17 @@ support-files = seek.ogv seek.ogv^headers^ seek.webm seek.webm^headers^ seek.yuv seek_support.js seekLies.sjs seek_with_sound.ogg^headers^ + sequential.vtt short-cenc.mp4 sine.webm sine.webm^headers^ short.mp4 short.mp4^headers^ short-video.ogv short-video.ogv^headers^ small-shot-mp3.mp4 @@ -836,16 +837,17 @@ tags=msg capturestream [test_streams_individual_pause.html] tags=msg [test_streams_srcObject.html] tags=msg capturestream [test_streams_tracks.html] tags=msg capturestream [test_texttrack.html] [test_texttrackcue.html] +[test_texttrackevents_video.html] [test_texttracklist.html] [test_texttrackregion.html] [test_timeupdate_small_files.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_trackelementevent.html] [test_trackevent.html] [test_unseekable.html] skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only and bug 1128845 on gonk
new file mode 100644 --- /dev/null +++ b/dom/media/test/sequential.vtt @@ -0,0 +1,10 @@ +WEBVTT + +00:01.000 --> 00:02.000 +This + +00:03.000 --> 00:04.000 +Is + +00:05.000 --> 00:06.000 +A Test
--- a/dom/media/test/test_eme_request_notifications.html +++ b/dom/media/test/test_eme_request_notifications.html @@ -70,21 +70,16 @@ var tests = [ }, { keySystem: CLEARKEY_ID, shouldPass: false, expectedStatus: 'cdm-disabled', prefs: [["media.eme.enabled", true], ["media.eme.clearkey.enabled", false]] }, { - keySystem: 'unsupported-keysystem', - shouldPass: false, - expectedStatus: 'cdm-not-supported' - }, - { keySystem: CLEARKEY_ID + '.10000' , // A stupendously high min CDM version, presumably not installed. shouldPass: false, expectedStatus: 'cdm-insufficient-version', prefs: [["media.eme.enabled", true], ["media.eme.clearkey.enabled", true]] }, { keySystem: CLEARKEY_ID, shouldPass: true,
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_texttrackevents_video.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Tests for TextTrack DOM Events</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]}, + function() { + var video = document.createElement("video"); + video.src = "vp9cake.webm"; + video.preload = "auto"; + video.controls = true; + var trackElement = document.createElement("track"); + trackElement.src = "sequential.vtt"; + trackElement.kind = "subtitles"; + trackElement.default = true; + document.getElementById("content").appendChild(video); + video.appendChild(trackElement); + + var trackElementCueChangeCount = 0; + var trackCueChangeCount = 0; + + video.addEventListener("loadedmetadata", function run_tests() { + // Re-queue run_tests() at the end of the event loop until the track + // element has loaded its data. + if (trackElement.readyState == 1) { + return setTimeout(run_tests, 0); + } + is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED."); + ok('oncuechange' in trackElement.track, "Track::OnCueChange should exist."); + + trackElement.track.oncuechange = function() { + ++trackElementCueChangeCount; + }; + + trackElement.addEventListener("cuechange", function() { + ++trackCueChangeCount; + }); + + video.play(); + }); + + video.addEventListener('ended', function() { + // Should be fired 6 times, as there are 3 cues, with a change event + // for when it is activated/deactivated (6 events total) + is(trackElementCueChangeCount, 6, "TrackElement should fire cue change 6 times."); + is(trackCueChangeCount, 6, "TrackElement.track should fire cue change 6 times."); + SimpleTest.finish() + }) + } +); +</script> +</pre> +</body> +</html>
--- a/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html +++ b/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html @@ -7,63 +7,77 @@ <pre id="test"> <script type="application/javascript;version=1.8"> createHTML({ bug: "1244913", title: "Scale resolution down on a PeerConnection", visible: true }); - var pc1 = new RTCPeerConnection(); - var pc2 = new RTCPeerConnection(); - - var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed); - pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback()); - pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback()); - - pc1.onnegotiationneeded = e => - pc1.createOffer().then(d => pc1.setLocalDescription(d)) - .then(() => pc2.setRemoteDescription(pc1.localDescription)) - .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d)) - .then(() => pc1.setRemoteDescription(pc2.localDescription)) - .catch(generateErrorCallback()); - var mustRejectWith = (msg, reason, f) => f().then(() => ok(false, msg), e => is(e.name, reason, msg)); - var v1, v2; + + var removeVP8 = d => (d.sdp = d.sdp.replace("a=rtpmap:120 VP8/90000\r\n", ""), d); + + function testScale(codec) { + var pc1 = new RTCPeerConnection(); + var pc2 = new RTCPeerConnection(); + + var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed); + pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback()); + pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback()); + + info("testing scaling with " + codec); - runNetworkTest(function() { - v1 = createMediaElement('video', 'v1'); - v2 = createMediaElement('video', 'v2'); + pc1.onnegotiationneeded = e => + pc1.createOffer() + .then(d => pc1.setLocalDescription(codec == "VP8" ? d : removeVP8(d))) + .then(() => pc2.setRemoteDescription(pc1.localDescription)) + .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d)) + .then(() => pc1.setRemoteDescription(pc2.localDescription)) + .catch(generateErrorCallback()); - is(v2.currentTime, 0, "v2.currentTime is zero at outset"); + return navigator.mediaDevices.getUserMedia({ video: true }) + .then(stream => { + var v1 = createMediaElement('video', 'v1'); + var v2 = createMediaElement('video', 'v2'); - navigator.mediaDevices.getUserMedia({ video: true }) - .then(stream => { + is(v2.currentTime, 0, "v2.currentTime is zero at outset"); + v1.srcObject = stream; var sender = pc1.addTrack(stream.getVideoTracks()[0], stream); return mustRejectWith("Invalid scaleResolutionDownBy must reject", "RangeError", () => sender.setParameters({ encodings: [{ scaleResolutionDownBy: 0.5 } ] })) .then(() => sender.setParameters({ encodings: [{ maxBitrate: 60000, - scaleResolutionDownBy: 2 }] })) + scaleResolutionDownBy: 2 }] })) + .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e))) + .then(e => v2.srcObject = e.streams[0]) + .then(() => new Promise(resolve => v2.onloadedmetadata = resolve)) + .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0)) + .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")")) + .then(() => wait(3000)) // TODO: Bug 1248154 + .then(() => { + ok(v1.videoWidth > 0, "source width is positive"); + ok(v1.videoHeight > 0, "source height is positive"); + if (v2.videoWidth == 640 && v2.videoHeight == 480) { // TODO: Bug 1248154 + info("Skipping test due to Bug 1248154"); + } else { + is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source"); + is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source"); + } + }) + .then(() => { + stream.getTracks().forEach(track => track.stop()); + v1.srcObject = v2.srcObject = null; + }) }) - .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e))) - .then(e => v2.srcObject = e.streams[0]) - .then(() => new Promise(resolve => v2.onloadedmetadata = resolve)) - .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0)) - .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")")) - .then(() => wait(1000)) // TODO: Bug 1248154 - .then(() => { - ok(v1.videoWidth > 0, "source width is positive"); - ok(v1.videoHeight > 0, "source height is positive"); - is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source"); - is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source"); - }) - .catch(generateErrorCallback()) - .then(networkTestFinished); - }); + .catch(generateErrorCallback()); + } + + runNetworkTest(() => testScale("VP8").then(() => testScale("H264")) + .then(networkTestFinished)); </script> </pre> </body> </html>
--- a/dom/media/webaudio/FFTBlock.h +++ b/dom/media/webaudio/FFTBlock.h @@ -116,20 +116,17 @@ public: AudioBufferCopyWithScale(mOutputBuffer.Elements()->f, 2.0f, aDataOut, mFFTSize); aDataOut[1] = 2.0f * mOutputBuffer[mFFTSize/2].r; // Packed Nyquist av_rdft_calc(mAvIRDFT, aDataOut); } #else #ifdef BUILD_ARM_NEON if (mozilla::supports_neon()) { - omxSP_FFTInv_CCSToR_F32_Sfs(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT); - // There is no function that computes de inverse FFT without scaling, so - // we have to scale back up here. Bug 1158741. - AudioBufferInPlaceScale(aDataOut, mFFTSize, mFFTSize); + omxSP_FFTInv_CCSToR_F32_Sfs_unscaled(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT); } else #endif { kiss_fftri(mKissIFFT, &(mOutputBuffer.Elements()->c), aDataOut); } #endif }
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp @@ -2,16 +2,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaEngineTabVideoSource.h" #include "mozilla/gfx/2D.h" #include "mozilla/RefPtr.h" +#include "mozilla/UniquePtrExtensions.h" #include "nsGlobalWindow.h" #include "nsIDOMClientRect.h" #include "nsIDocShell.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "gfxContext.h" #include "gfx2DGlue.h" #include "ImageContainer.h" @@ -242,17 +243,17 @@ MediaEngineTabVideoSource::Draw() { } } gfxImageFormat format = SurfaceFormat::X8R8G8B8_UINT32; uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width); if (mDataSize < static_cast<size_t>(stride * size.height)) { mDataSize = stride * size.height; - mData = static_cast<unsigned char*>(malloc(mDataSize)); + mData = MakeUniqueFallible<unsigned char[]>(mDataSize); } if (!mData) { return; } nsCOMPtr<nsIPresShell> presShell; { RefPtr<nsPresContext> presContext; @@ -273,17 +274,17 @@ MediaEngineTabVideoSource::Draw() { nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX), nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY), nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth), nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight)); RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer(); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, - mData.rwget(), + mData.get(), size, stride, SurfaceFormat::B8G8R8X8); if (!dt) { return; } RefPtr<gfxContext> context = new gfxContext(dt); context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth),
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ b/dom/media/webrtc/MediaEngineTabVideoSource.h @@ -2,16 +2,17 @@ * 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 "nsIDOMEventListener.h" #include "MediaEngine.h" #include "ImageContainer.h" #include "nsITimer.h" #include "mozilla/Monitor.h" +#include "mozilla/UniquePtr.h" #include "nsITabSource.h" namespace mozilla { class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventListener, nsITimerCallback { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIDOMEVENTLISTENER @@ -80,17 +81,17 @@ private: int32_t mBufHeightMax; int64_t mWindowId; bool mScrollWithPage; int32_t mViewportOffsetX; int32_t mViewportOffsetY; int32_t mViewportWidth; int32_t mViewportHeight; int32_t mTimePerFrame; - ScopedFreePtr<unsigned char> mData; + UniquePtr<unsigned char[]> mData; size_t mDataSize; nsCOMPtr<nsPIDOMWindowOuter> mWindow; RefPtr<layers::SourceSurfaceImage> mImage; nsCOMPtr<nsITimer> mTimer; Monitor mMonitor; nsCOMPtr<nsITabSource> mTabSource; }; }
--- a/dom/messages/SystemMessageManager.js +++ b/dom/messages/SystemMessageManager.js @@ -327,17 +327,27 @@ SystemMessageManager.prototype = { // nsIDOMGlobalPropertyInitializer implementation. init: function(aWindow) { debug("init"); this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message", "SystemMessageManager:GetPendingMessages:Return"]); let principal = aWindow.document.nodePrincipal; - this._isInBrowserElement = principal.isInBrowserElement; + + // After bug 1238160, the principal no longer knows how to answer "is this a + // browser element", which is really what this code path wants. Currently, + // desktop is the only platform where we intend to disable isolation on a + // browser frame, so non-desktop should be able to assume that + // inIsolatedMozBrowser is true for all mozbrowser frames. Additionally, + // this system message API is disabled on desktop behind the pref + // "dom.sysmsg.enabled". We use a release assertion in + // nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so that platforms with apps + // can assume inIsolatedMozBrowser is true for all mozbrowser frames. + this._isInBrowserElement = principal.isInIsolatedMozBrowserElement; this._pageURL = principal.URI.spec; let appsService = Cc["@mozilla.org/AppsService;1"] .getService(Ci.nsIAppsService); this._manifestURL = appsService.getManifestURLByLocalId(principal.appId); // Two cases are valid to register the manifest URL for the current process: // 1. This is asked by a child process (parent process must be ready).
--- a/dom/network/NetworkStatsService.jsm +++ b/dom/network/NetworkStatsService.jsm @@ -733,19 +733,19 @@ this.NetworkStatsService = { aCallback(true, "OK"); } }); }, /* * Function responsible for receiving stats which are not from netd. */ - saveStats: function saveStats(aAppId, aIsInBrowser, aServiceType, aNetworkInfo, - aTimeStamp, aRxBytes, aTxBytes, aIsAccumulative, - aCallback) { + saveStats: function saveStats(aAppId, aIsInIsolatedMozBrowser, aServiceType, + aNetworkInfo, aTimeStamp, aRxBytes, aTxBytes, + aIsAccumulative, aCallback) { let netId = this.convertNetworkInfo(aNetworkInfo); if (!netId) { if (aCallback) { aCallback(false, "Invalid network type"); } return; } @@ -756,17 +756,17 @@ this.NetworkStatsService = { // b. Both |aAppId| is zero and |aServiceType| is empty. if (!this._networks[netId] || (aAppId && aServiceType) || (!aAppId && !aServiceType)) { debug("Invalid network interface, appId or serviceType"); return; } let stats = { appId: aAppId, - isInBrowser: aIsInBrowser, + isInBrowser: aIsInIsolatedMozBrowser, serviceType: aServiceType, networkId: this._networks[netId].network.id, networkType: this._networks[netId].network.type, date: new Date(aTimeStamp), rxBytes: aRxBytes, txBytes: aTxBytes, isAccumulative: aIsAccumulative };
--- a/dom/network/NetworkStatsServiceProxy.js +++ b/dom/network/NetworkStatsServiceProxy.js @@ -24,37 +24,37 @@ function NetworkStatsServiceProxy() { } } NetworkStatsServiceProxy.prototype = { /* * Function called in the protocol layer (HTTP, FTP, WebSocket ...etc) * to pass the per-app stats to NetworkStatsService. */ - saveAppStats: function saveAppStats(aAppId, aIsInBrowser, aNetworkInfo, aTimeStamp, + saveAppStats: function saveAppStats(aAppId, aIsInIsolatedMozBrowser, aNetworkInfo, aTimeStamp, aRxBytes, aTxBytes, aIsAccumulative, aCallback) { if (!aNetworkInfo) { if (DEBUG) { debug("|aNetworkInfo| is not specified. Failed to save stats. Returning."); } return; } if (DEBUG) { - debug("saveAppStats: " + aAppId + " " + aIsInBrowser + " " + + debug("saveAppStats: " + aAppId + " " + aIsInIsolatedMozBrowser + " " + aNetworkInfo.type + " " + aTimeStamp + " " + aRxBytes + " " + aTxBytes + " " + aIsAccumulative); } if (aCallback) { aCallback = aCallback.notify; } - NetworkStatsService.saveStats(aAppId, aIsInBrowser, "", aNetworkInfo, + NetworkStatsService.saveStats(aAppId, aIsInIsolatedMozBrowser, "", aNetworkInfo, aTimeStamp, aRxBytes, aTxBytes, aIsAccumulative, aCallback); }, /* * Function called in the points of different system services * to pass the per-service stats to NetworkStatsService. */
--- a/dom/network/TCPServerSocket.cpp +++ b/dom/network/TCPServerSocket.cpp @@ -143,17 +143,17 @@ TCPServerSocket::FireEvent(const nsAStri NS_IMETHODIMP TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport) { nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); RefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers); if (mServerBridgeParent) { socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(), - mServerBridgeParent->GetInBrowser()); + mServerBridgeParent->GetInIsolatedMozBrowser()); } FireEvent(NS_LITERAL_STRING("connect"), socket); return NS_OK; } NS_IMETHODIMP TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus) {
--- a/dom/network/TCPServerSocketParent.cpp +++ b/dom/network/TCPServerSocketParent.cpp @@ -70,22 +70,22 @@ TCPServerSocketParent::GetAppId() TabParent *tab = TabParent::GetFrom(browser); return tab->OwnAppId(); } else { return nsIScriptSecurityManager::UNKNOWN_APP_ID; } } bool -TCPServerSocketParent::GetInBrowser() +TCPServerSocketParent::GetInIsolatedMozBrowser() { const PContentParent *content = Manager()->Manager(); if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) { TabParent *tab = TabParent::GetFrom(browser); - return tab->IsBrowserElement(); + return tab->IsIsolatedMozBrowserElement(); } else { return false; } } nsresult TCPServerSocketParent::SendCallbackAccept(TCPSocketParent *socket) { @@ -145,17 +145,17 @@ TCPServerSocketParent::RecvRequestDelete mozilla::Unused << Send__delete__(this); return true; } void TCPServerSocketParent::OnConnect(TCPServerSocketEvent* event) { RefPtr<TCPSocket> socket = event->Socket(); - socket->SetAppIdAndBrowser(GetAppId(), GetInBrowser()); + socket->SetAppIdAndBrowser(GetAppId(), GetInIsolatedMozBrowser()); RefPtr<TCPSocketParent> socketParent = new TCPSocketParent(); socketParent->SetSocket(socket); socket->SetSocketBridgeParent(socketParent); SendCallbackAccept(socketParent); }
--- a/dom/network/TCPServerSocketParent.h +++ b/dom/network/TCPServerSocketParent.h @@ -30,17 +30,17 @@ public: uint16_t aBacklog, bool aUseArrayBuffers); void Init(); virtual bool RecvClose() override; virtual bool RecvRequestDelete() override; uint32_t GetAppId(); - bool GetInBrowser(); + bool GetInIsolatedMozBrowser(); void AddIPDLReference(); void ReleaseIPDLReference(); void OnConnect(TCPServerSocketEvent* event); private: ~TCPServerSocketParent();
--- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -161,17 +161,17 @@ TCPSocket::TCPSocket(nsIGlobalObject* aG , mBufferedAmount(0) , mSuspendCount(0) , mTrackingNumber(0) , mWaitingForStartTLS(false) #ifdef MOZ_WIDGET_GONK , mTxBytes(0) , mRxBytes(0) , mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID) - , mInBrowser(false) + , mInIsolatedMozBrowser(false) #endif { if (aGlobal) { nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); if (window) { mInnerWindowID = window->WindowID(); } } @@ -1095,21 +1095,21 @@ TCPSocket::OnStopRequest(nsIRequest* aRe void TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent) { mSocketBridgeParent = aBridgeParent; } void -TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser) +TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInIsolatedMozBrowser) { #ifdef MOZ_WIDGET_GONK mAppId = aAppId; - mInBrowser = aInBrowser; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; #endif } NS_IMETHODIMP TCPSocket::UpdateReadyState(uint32_t aReadyState) { MOZ_ASSERT(mSocketBridgeChild); mReadyState = static_cast<TCPReadyState>(aReadyState); @@ -1150,18 +1150,18 @@ TCPSocket::SaveNetworkStats(bool aEnforc } nsCOMPtr<nsINetworkStatsServiceProxy> nssProxy = do_GetService("@mozilla.org/networkstatsServiceProxy;1"); if (!nssProxy) { return; } - nssProxy->SaveAppStats(mAppId, mInBrowser, mActiveNetworkInfo, PR_Now(), - mRxBytes, mTxBytes, false, nullptr); + nssProxy->SaveAppStats(mAppId, mInIsolatedMozBrowser, mActiveNetworkInfo, + PR_Now(), mRxBytes, mTxBytes, false, nullptr); // Reset the counters once the statistics is saved to NetworkStatsServiceProxy. mTxBytes = mRxBytes = 0; } #endif NS_IMETHODIMP TCPSocket::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
--- a/dom/network/TCPSocket.h +++ b/dom/network/TCPSocket.h @@ -237,18 +237,18 @@ private: #ifdef MOZ_WIDGET_GONK // Number of bytes sent. uint32_t mTxBytes; // Number of bytes received. uint32_t mRxBytes; // The app that owns this socket. uint32_t mAppId; - // Was this socket created inside of a mozbrowser frame? - bool mInBrowser; + // Was this socket created inside of an isolated browser frame? + bool mInIsolatedMozBrowser; // The name of the active network used by this socket. nsCOMPtr<nsINetworkInfo> mActiveNetworkInfo; #endif }; } // namespace dom } // namespace mozilla
--- a/dom/network/TCPSocketParent.cpp +++ b/dom/network/TCPSocketParent.cpp @@ -72,22 +72,22 @@ TCPSocketParent::GetAppId() TabParent *tab = TabParent::GetFrom(browser); return tab->OwnAppId(); } else { return nsIScriptSecurityManager::UNKNOWN_APP_ID; } }; bool -TCPSocketParent::GetInBrowser() +TCPSocketParent::GetInIsolatedMozBrowser() { const PContentParent *content = Manager()->Manager(); if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) { TabParent *tab = TabParent::GetFrom(browser); - return tab->IsBrowserElement(); + return tab->IsIsolatedMozBrowserElement(); } else { return false; } } nsresult TCPSocketParent::OfflineNotification(nsISupports *aSubject) { @@ -150,26 +150,26 @@ TCPSocketParent::RecvOpen(const nsString if (net::UsingNeckoIPCSecurity() && !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) { FireInteralError(this, __LINE__); return true; } // Obtain App ID uint32_t appId = GetAppId(); - bool inBrowser = GetInBrowser(); + bool inIsolatedMozBrowser = GetInIsolatedMozBrowser(); if (NS_IsAppOffline(appId)) { NS_ERROR("Can't open socket because app is offline"); FireInteralError(this, __LINE__); return true; } mSocket = new TCPSocket(nullptr, aHost, aPort, aUseSSL, aUseArrayBuffers); - mSocket->SetAppIdAndBrowser(appId, inBrowser); + mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser); mSocket->SetSocketBridgeParent(this); NS_ENSURE_SUCCESS(mSocket->Init(), true); return true; } bool TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost, const uint16_t& aRemotePort, @@ -216,28 +216,28 @@ TCPSocketParent::RecvOpenBind(const nsCS rv = socketTransport->Bind(&addr); if (NS_FAILED(rv)) { FireInteralError(this, __LINE__); return true; } // Obtain App ID uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; - bool inBrowser = false; + bool inIsolatedMozBrowser = false; const PContentParent *content = Manager()->Manager(); if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) { // appId's are for B2G only currently, where managees.Count() == 1 // This is not guaranteed currently in Desktop, so skip this there. TabParent *tab = TabParent::GetFrom(browser); appId = tab->OwnAppId(); - inBrowser = tab->IsBrowserElement(); + inIsolatedMozBrowser = tab->IsIsolatedMozBrowserElement(); } mSocket = new TCPSocket(nullptr, NS_ConvertUTF8toUTF16(aRemoteHost), aRemotePort, aUseSSL, aUseArrayBuffers); - mSocket->SetAppIdAndBrowser(appId, inBrowser); + mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser); mSocket->SetSocketBridgeParent(this); rv = mSocket->InitWithUnconnectedTransport(socketTransport); NS_ENSURE_SUCCESS(rv, true); return true; } bool TCPSocketParent::RecvStartTLS()
--- a/dom/network/TCPSocketParent.h +++ b/dom/network/TCPSocketParent.h @@ -63,17 +63,17 @@ public: virtual bool RecvSuspend() override; virtual bool RecvResume() override; virtual bool RecvClose() override; virtual bool RecvData(const SendableData& aData, const uint32_t& aTrackingNumber) override; virtual bool RecvRequestDelete() override; virtual nsresult OfflineNotification(nsISupports *) override; virtual uint32_t GetAppId() override; - bool GetInBrowser(); + bool GetInIsolatedMozBrowser(); void FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState); void FireEvent(const nsAString& aType, TCPReadyState aReadyState); void FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState); void FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState); void SetSocket(TCPSocket *socket); nsresult GetHost(nsAString& aHost);
--- a/dom/network/interfaces/nsINetworkStatsServiceProxy.idl +++ b/dom/network/interfaces/nsINetworkStatsServiceProxy.idl @@ -17,26 +17,31 @@ interface nsINetworkStatsServiceProxyCal }; [scriptable, uuid(f4f3e901-e102-499d-9d37-dc9951f52df7)] interface nsINetworkStatsServiceProxy : nsISupports { /* * An interface used to record per-app traffic data. * @param aAppId app id - * @param aIsInBrowser true if the iframe element is mozbrowser + * @param aIsInIsolatedMozBrowser + * true if the frame is an isolated mozbrowser element. <iframe + * mozbrowser mozapp> and <xul:browser> are not considered to be + * mozbrowser elements. <iframe mozbrowser noisolation> does not count + * as isolated since isolation is disabled. Isolation can only be + * disabled if the containing document is chrome. * @param aNetworkInterface network * @param aTimeStamp time stamp * @param aRxBytes received data amount * @param aTxBytes transmitted data amount * @param aIsAccumulative is stats accumulative * @param aCallback an optional callback */ void saveAppStats(in unsigned long aAppId, - in boolean aIsInBrowser, + in boolean aIsInIsolatedMozBrowser, in nsINetworkInfo aNetworkInfo, in unsigned long long aTimeStamp, in unsigned long long aRxBytes, in unsigned long long aTxBytes, in boolean aIsAccumulative, [optional] in nsINetworkStatsServiceProxyCallback aCallback); /*
--- a/dom/payment/Payment.jsm +++ b/dom/payment/Payment.jsm @@ -231,17 +231,17 @@ var PaymentManager = { }; #ifdef MOZ_B2G // Let this payment provider access the firefox-accounts API when // it's loaded in the trusted UI. if (systemAppId != Ci.nsIScriptSecurityManager.NO_APP_ID) { this.LOG("Granting firefox-accounts permission to " + provider.uri); let uri = Services.io.newURI(provider.uri, null, null); - let attrs = {appId: systemAppId, inBrowser: true}; + let attrs = {appId: systemAppId, inIsolatedMozBrowser: true}; let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs); Services.perms.addFromPrincipal(principal, "firefox-accounts", Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION); } #endif
--- a/dom/permission/PermissionSettings.js +++ b/dom/permission/PermissionSettings.js @@ -37,17 +37,17 @@ PermissionSettings.prototype = { get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) { // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag); let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {appId: appID, - inBrowser: aBrowserFlag}); + inIsolatedMozBrowser: aBrowserFlag}); let result = Services.perms.testExactPermanentPermission(principal, aPermName); switch (result) { case Ci.nsIPermissionManager.UNKNOWN_ACTION: return "unknown"; case Ci.nsIPermissionManager.ALLOW_ACTION: return "allow"; @@ -63,17 +63,17 @@ PermissionSettings.prototype = { isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin, aBrowserFlag) { // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin); let uri = Services.io.newURI(aOrigin, null, null); let app = appsService.getAppByManifestURL(aManifestURL); let principal = Services.scriptSecurityManager - .createCodebasePrincipal(uri, {appId: app.localId, inBrowser: aBrowserFlag}); + .createCodebasePrincipal(uri, {appId: app.localId, inIsolatedMozBrowser: aBrowserFlag}); return isExplicitInPermissionsTable(aPermName, principal.appStatus); }, set: function set(aPermName, aPermValue, aManifestURL, aOrigin, aBrowserFlag) { debug("Set called with: " + aPermName + ", " + aManifestURL + ", " + @@ -104,17 +104,17 @@ PermissionSettings.prototype = { remove: function remove(aPermName, aManifestURL, aOrigin) { // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {appId: appID, - inBrowser: true}); + inIsolatedMozBrowser: true}); if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) { let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" + " is installed or permission is implicit, cannot remove '" + aPermName + "'."; Cu.reportError(errorMsg); throw new Components.Exception(errorMsg); }
--- a/dom/permission/PermissionSettings.jsm +++ b/dom/permission/PermissionSettings.jsm @@ -77,17 +77,17 @@ this.PermissionSettingsModule = { Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aData.origin); app = {localId: principal.appId}; } else { app = appsService.getAppByManifestURL(aData.manifestURL); let uri = Services.io.newURI(aData.origin, null, null); principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {appId: app.localId, - inBrowser: aData.browserFlag}); + inIsolatedMozBrowser: aData.browserFlag}); } let action; switch (aData.value) { case "unknown": action = Ci.nsIPermissionManager.UNKNOWN_ACTION; break; @@ -126,17 +126,17 @@ this.PermissionSettingsModule = { principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aOrigin); } else { let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {appId: appID, - inBrowser: aBrowserFlag}); + inIsolatedMozBrowser: aBrowserFlag}); } let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName); switch (result) { case Ci.nsIPermissionManager.UNKNOWN_ACTION: return "unknown"; case Ci.nsIPermissionManager.ALLOW_ACTION: return "allow";
--- a/dom/permission/Permissions.cpp +++ b/dom/permission/Permissions.cpp @@ -1,16 +1,17 @@ /* -*- 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 "mozilla/dom/Permissions.h" +#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/PermissionsBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/Services.h" #include "nsIPermissionManager.h" #include "PermissionUtils.h" namespace mozilla { namespace dom { @@ -116,10 +117,88 @@ Permissions::Query(JSContext* aCx, promise->MaybeReject(aRv); } else { MOZ_ASSERT(status); promise->MaybeResolve(status); } return promise.forget(); } +/* static */ nsresult +Permissions::RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType); +} + +already_AddRefed<Promise> +Permissions::Revoke(JSContext* aCx, + JS::Handle<JSObject*> aPermission, + ErrorResult& aRv) +{ + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + PermissionDescriptor permission; + JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + RefPtr<Promise> promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr<nsIDocument> document = mWindow->GetExtantDoc(); + if (!document) { + promise->MaybeReject(NS_ERROR_UNEXPECTED); + return promise.forget(); + } + + nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + + const char* permissionType = PermissionNameToType(permission.mName); + + nsresult rv; + if (XRE_IsParentProcess()) { + rv = RemovePermission(document->NodePrincipal(), permissionType); + } else { + // Permissions can't be removed from the content process. Send a message + // to the parent; `ContentParent::RecvRemovePermission` will call + // `RemovePermission`. + ContentChild::GetSingleton()->SendRemovePermission( + IPC::Principal(document->NodePrincipal()), nsDependentCString(permissionType), &rv); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(rv); + return promise.forget(); + } + + RefPtr<PermissionStatus> status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + promise->MaybeReject(aRv); + } else { + MOZ_ASSERT(status); + promise->MaybeResolve(status); + } + return promise.forget(); +} + } // namespace dom } // namespace mozilla
--- a/dom/permission/Permissions.h +++ b/dom/permission/Permissions.h @@ -33,16 +33,22 @@ public: JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; already_AddRefed<Promise> Query(JSContext* aCx, JS::Handle<JSObject*> aPermission, ErrorResult& aRv); + static nsresult RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType); + + already_AddRefed<Promise> Revoke(JSContext* aCx, + JS::Handle<JSObject*> aPermission, + ErrorResult& aRv); + private: ~Permissions(); nsCOMPtr<nsPIDOMWindowInner> mWindow; }; } // namespace dom } // namespace mozilla
--- a/dom/permission/moz.build +++ b/dom/permission/moz.build @@ -45,8 +45,10 @@ if CONFIG['MOZ_WEBSMS_BACKEND']: if CONFIG['MOZ_TIME_MANAGER']: MOCHITEST_MANIFESTS += ['tests/mochitest-time.ini'] FINAL_LIBRARY = 'xul' if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wshadow'] + +include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/permission/tests/test_permissions_api.html +++ b/dom/permission/tests/test_permissions_api.html @@ -37,27 +37,49 @@ function setPermissions(action) { }); return new Promise((resolve, reject) => { SpecialPowers.popPermissions(() => { SpecialPowers.pushPermissions(permissions, resolve); }); }); } +function revokePermissions(action) { + return Promise.all(PERMISSIONS.map(x => + navigator.permissions.revoke({ name: x.name }).then( + result => is(result.state, "prompt", `correct state for '${x.name}'`), + error => ok(false, `revoke should not have rejected for '${x.name}'`)) + )); +} + +function revokeUnsupportedPermissions() { + return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => + navigator.permissions.revoke({ name: name }).then( + result => ok(false, `revoke should not have resolved for '${name}'`), + error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)) + )); +} + +function revokeUserVisiblePushPermission() { + return navigator.permissions.revoke({ name: 'push', userVisible: true }).then( + result => ok(false, `revoke should not have resolved for userVisible push`), + error => ok(true, `revoke should have rejected for userVisible push`)); +} + function checkPermissions(state) { return Promise.all(PERMISSIONS.map(x => { return navigator.permissions.query({ name: x.name }).then( result => is(result.state, state, `correct state for '${x.name}'`), error => ok(false, `query should not have rejected for '${x.name}'`)); })); } function checkUnsupportedPermissions() { return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => { - return navigator.permissions.query({ name }).then( + return navigator.permissions.query({ name: name }).then( result => ok(false, `query should not have resolved for '${name}'`), error => { is(error.name, 'TypeError', `query should have thrown TypeError for '${name}'`); }); })); } @@ -97,29 +119,40 @@ function testStatusOnChange() { } function testInvalidQuery() { navigator.permissions.query({ name: 'invalid' }).then( result => ok(false, 'invalid query should not have resolved'), error => ok(true, 'invalid query should have rejected')); } +function testInvalidRevoke() { + navigator.permissions.revoke({ name: 'invalid' }).then( + result => ok(false, 'invalid revoke should not have resolved'), + error => ok(true, 'invalid revoke should have rejected')); +} + function runTests() { checkUnsupportedPermissions() .then(checkUserVisiblePushPermission) .then(() => setPermissions(UNKNOWN_ACTION)) .then(() => checkPermissions('prompt')) .then(() => setPermissions(PROMPT_ACTION)) .then(() => checkPermissions('prompt')) .then(() => setPermissions(ALLOW_ACTION)) .then(() => checkPermissions('granted')) .then(() => setPermissions(DENY_ACTION)) .then(() => checkPermissions('denied')) .then(testStatusOnChange) .then(testInvalidQuery) + .then(revokeUnsupportedPermissions) + .then(revokeUserVisiblePushPermission) + .then(revokePermissions) + .then(() => checkPermissions('prompt')) + .then(testInvalidRevoke) .then(SimpleTest.finish) .catch ((e) => { ok(false, 'Unexpected error ' + e); SimpleTest.finish(); }); } </script> </pre>
--- a/dom/push/test/xpcshell/head.js +++ b/dom/push/test/xpcshell/head.js @@ -502,16 +502,16 @@ var tearDownServiceInParent = Task.async originAttributes: '', }); ok(record.pushEndpoint.startsWith('https://example.org/push'), 'Wrong push endpoint in subscription record'); record = yield db.getByIdentifiers({ scope: 'https://example.net/scope/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: 1, inBrowser: true }), + { appId: 1, inIsolatedMozBrowser: true }), }); ok(record.pushEndpoint.startsWith('https://example.org/push'), 'Wrong push endpoint in app record'); record = yield db.getByKeyID('3a414737-2fd0-44c0-af05-7efc172475fc'); ok(!record, 'Unsubscribed record should not exist'); });
--- a/dom/push/test/xpcshell/test_clear_origin_data.js +++ b/dom/push/test/xpcshell/test_clear_origin_data.js @@ -46,41 +46,41 @@ function run_test() { add_task(function* test_webapps_cleardata() { let db = PushServiceWebSocket.newPushDB(); do_register_cleanup(() => {return db.drop().then(_ => db.close());}); let testRecords = [{ scope: 'https://example.org/1', originAttributes: { appId: 1 }, - clearIf: { appId: 1, inBrowser: false }, + clearIf: { appId: 1, inIsolatedMozBrowser: false }, }, { scope: 'https://example.org/1', - originAttributes: { appId: 1, inBrowser: true }, + originAttributes: { appId: 1, inIsolatedMozBrowser: true }, clearIf: { appId: 1 }, }, { scope: 'https://example.org/1', - originAttributes: { appId: 2, inBrowser: true }, - clearIf: { appId: 2, inBrowser: true }, + originAttributes: { appId: 2, inIsolatedMozBrowser: true }, + clearIf: { appId: 2, inIsolatedMozBrowser: true }, }, { scope: 'https://example.org/2', originAttributes: { appId: 1 }, - clearIf: { appId: 1, inBrowser: false }, + clearIf: { appId: 1, inIsolatedMozBrowser: false }, }, { scope: 'https://example.org/2', - originAttributes: { appId: 2, inBrowser: true }, - clearIf: { appId: 2, inBrowser: true }, + originAttributes: { appId: 2, inIsolatedMozBrowser: true }, + clearIf: { appId: 2, inIsolatedMozBrowser: true }, }, { scope: 'https://example.org/3', - originAttributes: { appId: 3, inBrowser: true }, - clearIf: { inBrowser: true }, + originAttributes: { appId: 3, inIsolatedMozBrowser: true }, + clearIf: { inIsolatedMozBrowser: true }, }, { scope: 'https://example.org/3', - originAttributes: { appId: 4, inBrowser: true }, - clearIf: { inBrowser: true }, + originAttributes: { appId: 4, inIsolatedMozBrowser: true }, + clearIf: { inIsolatedMozBrowser: true }, }]; let unregisterDone; let unregisterPromise = new Promise(resolve => unregisterDone = after(testRecords.length, resolve)); PushService.init({ serverURI: "wss://push.example.org", @@ -118,25 +118,25 @@ add_task(function* test_webapps_cleardat PushService.register({ scope: test.scope, originAttributes: ChromeUtils.originAttributesToSuffix( test.originAttributes), }) )); // Removes records for all scopes with the same app ID. Excludes records - // where `inBrowser` is true. - yield clearForPattern(testRecords, { appId: 1, inBrowser: false }); + // where `inIsolatedMozBrowser` is true. + yield clearForPattern(testRecords, { appId: 1, inIsolatedMozBrowser: false }); - // Removes the remaining record for app ID 1, where `inBrowser` is true. + // Removes the remaining record for app ID 1, where `inIsolatedMozBrowser` is true. yield clearForPattern(testRecords, { appId: 1 }); // Removes all records for all scopes with the same app ID, where - // `inBrowser` is true. - yield clearForPattern(testRecords, { appId: 2, inBrowser: true }); + // `inIsolatedMozBrowser` is true. + yield clearForPattern(testRecords, { appId: 2, inIsolatedMozBrowser: true }); - // Removes all records where `inBrowser` is true. - yield clearForPattern(testRecords, { inBrowser: true }); + // Removes all records where `inIsolatedMozBrowser` is true. + yield clearForPattern(testRecords, { inIsolatedMozBrowser: true }); equal(testRecords.length, 0, 'Should remove all test records'); yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, 'Timed out waiting for unregister'); });
--- a/dom/push/test/xpcshell/test_notification_http2.js +++ b/dom/push/test/xpcshell/test_notification_http2.js @@ -75,17 +75,17 @@ add_task(function* test_pushNotification d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM', ext: true, key_ops: ["deriveBits"], kty: "EC", x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM', y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA' }, originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, systemRecord: true, }, { subscriptionUri: serverURL + '/pushNotifications/subscription2', pushEndpoint: serverURL + '/pushEndpoint2', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2', scope: 'https://example.com/page/2', p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E', @@ -94,17 +94,17 @@ add_task(function* test_pushNotification d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4', ext: true, key_ops: ["deriveBits"], kty: 'EC', x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE', y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E' }, originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, systemRecord: true, }, { subscriptionUri: serverURL + '/pushNotifications/subscription3', pushEndpoint: serverURL + '/pushEndpoint3', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3', scope: 'https://example.com/page/3', p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI', @@ -113,17 +113,17 @@ add_task(function* test_pushNotification d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8', ext: true, key_ops: ["deriveBits"], kty: 'EC', x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po', y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI' }, originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, systemRecord: true, }]; for (let record of records) { yield db.put(record); }
--- a/dom/push/test/xpcshell/test_reconnect_retry.js +++ b/dom/push/test/xpcshell/test_reconnect_retry.js @@ -53,22 +53,22 @@ add_task(function* test_reconnect_retry( } }); } }); let registration = yield PushService.register({ scope: 'https://example.com/page/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); let retryEndpoint = 'https://example.org/push/' + channelID; equal(registration.endpoint, retryEndpoint, 'Wrong endpoint for retried request'); registration = yield PushService.register({ scope: 'https://example.com/page/2', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); notEqual(registration.endpoint, retryEndpoint, 'Wrong endpoint for new request') equal(registers, 3, 'Wrong registration count'); });
--- a/dom/push/test/xpcshell/test_register_5xxCode_http2.js +++ b/dom/push/test/xpcshell/test_register_5xxCode_http2.js @@ -76,17 +76,17 @@ add_task(function* test1() { PushService.init({ serverURI: serverURL + "/subscribe5xxCode", db }); let originAttributes = ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, - inBrowser: false, + inIsolatedMozBrowser: false, }); let newRecord = yield PushService.register({ scope: 'https://example.com/retry5xxCode', originAttributes: originAttributes, }); var subscriptionUri = serverURL + '/subscription'; var pushEndpoint = serverURL + '/pushEndpoint';
--- a/dom/push/test/xpcshell/test_register_case.js +++ b/dom/push/test/xpcshell/test_register_case.js @@ -42,17 +42,17 @@ add_task(function* test_register_case() }); } }); let newRecord = yield waitForPromise( PushService.register({ scope: 'https://example.net/case', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), DEFAULT_TIMEOUT, 'Mixed-case register response timed out' ); equal(newRecord.endpoint, 'https://example.com/update/case', 'Wrong push endpoint in registration record'); let record = yield db.getByPushEndpoint('https://example.com/update/case');
--- a/dom/push/test/xpcshell/test_register_error_http2.js +++ b/dom/push/test/xpcshell/test_register_error_http2.js @@ -40,17 +40,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionNoConnection/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for not being able to establish connecion.' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, "Should not store records when connection couldn't be established."); PushService.uninit(); }); @@ -80,17 +80,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionMissingLocation/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for the missing location header.' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, 'Should not store records when the location header is missing.'); PushService.uninit(); }); @@ -106,17 +106,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionMissingLink/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for the missing link header.' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, 'Should not store records when a link header is missing.'); PushService.uninit(); }); @@ -132,17 +132,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionMissingLink1/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for the missing push endpoint.' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, 'Should not store records when the push endpoint is missing.'); PushService.uninit(); }); @@ -158,17 +158,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionLocationBogus/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for the bogus location' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, 'Should not store records when location header is bogus.'); PushService.uninit(); }); @@ -184,17 +184,17 @@ add_task(function* test_pushSubscription serverURI: serverURL + "/pushSubscriptionNot201Code/subscribe", db }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-response', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for not 201 responce code.' ); let record = yield db.getAllKeyIDs(); ok(record.length === 0, 'Should not store records when respons code is not 201.'); });
--- a/dom/push/test/xpcshell/test_register_invalid_channel.js +++ b/dom/push/test/xpcshell/test_register_invalid_channel.js @@ -43,16 +43,16 @@ add_task(function* test_register_invalid }); } }); yield rejects( PushService.register({ scope: 'https://example.com/invalid-channel', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for invalid channel ID' ); let record = yield db.getByKeyID(channelID); ok(!record, 'Should not store records for error responses'); });
--- a/dom/push/test/xpcshell/test_register_invalid_endpoint.js +++ b/dom/push/test/xpcshell/test_register_invalid_endpoint.js @@ -44,16 +44,16 @@ add_task(function* test_register_invalid }); } }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-endpoint', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for invalid endpoint' ); let record = yield db.getByKeyID(channelID); ok(!record, 'Should not store records with invalid endpoints'); });
--- a/dom/push/test/xpcshell/test_register_invalid_json.js +++ b/dom/push/test/xpcshell/test_register_invalid_json.js @@ -44,17 +44,17 @@ add_task(function* test_register_invalid }); } }); yield rejects( PushService.register({ scope: 'https://example.net/page/invalid-json', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for invalid JSON response' ); yield waitForPromise(helloPromise, DEFAULT_TIMEOUT, 'Reconnect after invalid JSON response timed out'); equal(registers, 1, 'Wrong register count'); });
--- a/dom/push/test/xpcshell/test_register_no_id.js +++ b/dom/push/test/xpcshell/test_register_no_id.js @@ -48,17 +48,17 @@ add_task(function* test_register_no_id() }); } }); yield rejects( PushService.register({ scope: 'https://example.com/incomplete', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for incomplete register response' ); yield waitForPromise(helloPromise, DEFAULT_TIMEOUT, 'Reconnect after incomplete register response timed out'); equal(registers, 1, 'Wrong register count'); });
--- a/dom/push/test/xpcshell/test_register_request_queue.js +++ b/dom/push/test/xpcshell/test_register_request_queue.js @@ -40,22 +40,22 @@ add_task(function* test_register_request } }); } }); let firstRegister = PushService.register({ scope: 'https://example.com/page/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); let secondRegister = PushService.register({ scope: 'https://example.com/page/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); yield waitForPromise(Promise.all([ rejects(firstRegister, 'Should time out the first request'), rejects(secondRegister, 'Should time out the second request') ]), DEFAULT_TIMEOUT, 'Queued requests did not time out'); yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
--- a/dom/push/test/xpcshell/test_register_rollback.js +++ b/dom/push/test/xpcshell/test_register_rollback.js @@ -70,17 +70,17 @@ add_task(function* test_register_rollbac } }); // Should return a rejected promise if storage fails. yield rejects( PushService.register({ scope: 'https://example.com/storage-error', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for unregister database failure' ); // Should send an out-of-band unregister request. yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, 'Unregister request timed out'); equal(handshakes, 1, 'Wrong handshake count');
--- a/dom/push/test/xpcshell/test_register_success.js +++ b/dom/push/test/xpcshell/test_register_success.js @@ -51,17 +51,17 @@ add_task(function* test_register_success } }); } }); let newRecord = yield PushService.register({ scope: 'https://example.org/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); equal(newRecord.endpoint, 'https://example.com/update/1', 'Wrong push endpoint in registration record'); let record = yield db.getByKeyID(channelID); equal(record.channelID, channelID, 'Wrong channel ID in database record'); equal(record.pushEndpoint, 'https://example.com/update/1',
--- a/dom/push/test/xpcshell/test_register_success_http2.js +++ b/dom/push/test/xpcshell/test_register_success_http2.js @@ -60,17 +60,17 @@ add_task(function* test_pushSubscription PushService.init({ serverURI: serverURL + "/pushSubscriptionSuccess/subscribe", db }); let newRecord = yield PushService.register({ scope: 'https://example.org/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); var subscriptionUri = serverURL + '/pushSubscriptionSuccesss'; var pushEndpoint = serverURL + '/pushEndpointSuccess'; var pushReceiptEndpoint = serverURL + '/receiptPushEndpointSuccess'; equal(newRecord.endpoint, pushEndpoint, 'Wrong push endpoint in registration record'); @@ -95,17 +95,17 @@ add_task(function* test_pushSubscription PushService.init({ serverURI: serverURL + "/pushSubscriptionMissingLink2/subscribe", db }); let newRecord = yield PushService.register({ scope: 'https://example.org/no_receiptEndpoint', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); var subscriptionUri = serverURL + '/subscriptionMissingLink2'; var pushEndpoint = serverURL + '/pushEndpointMissingLink2'; var pushReceiptEndpoint = ''; equal(newRecord.endpoint, pushEndpoint, 'Wrong push endpoint in registration record');
--- a/dom/push/test/xpcshell/test_register_timeout.js +++ b/dom/push/test/xpcshell/test_register_timeout.js @@ -70,17 +70,17 @@ add_task(function* test_register_timeout }); } }); yield rejects( PushService.register({ scope: 'https://example.net/page/timeout', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for request timeout' ); let record = yield db.getByKeyID(channelID); ok(!record, 'Should not store records for timed-out responses'); yield waitForPromise(
--- a/dom/push/test/xpcshell/test_register_wrong_id.js +++ b/dom/push/test/xpcshell/test_register_wrong_id.js @@ -54,17 +54,17 @@ add_task(function* test_register_wrong_i }); } }); yield rejects( PushService.register({ scope: 'https://example.com/mismatched', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for mismatched register reply' ); yield waitForPromise(helloPromise, DEFAULT_TIMEOUT, 'Reconnect after mismatched register reply timed out'); equal(registers, 1, 'Wrong register count'); });
--- a/dom/push/test/xpcshell/test_register_wrong_type.js +++ b/dom/push/test/xpcshell/test_register_wrong_type.js @@ -48,17 +48,17 @@ add_task(function* test_register_wrong_t }); } }); yield rejects( PushService.register({ scope: 'https://example.com/mistyped', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for non-string channel ID' ); yield waitForPromise(helloPromise, DEFAULT_TIMEOUT, 'Reconnect after sending non-string channel ID timed out'); equal(registers, 1, 'Wrong register count'); });
--- a/dom/push/test/xpcshell/test_registration_error.js +++ b/dom/push/test/xpcshell/test_registration_error.js @@ -29,16 +29,16 @@ add_task(function* test_registrations_er return new MockWebSocket(uri); } }); yield rejects( PushService.registration({ scope: 'https://example.net/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), function(error) { return error == 'Database error'; }, 'Wrong message' ); });
--- a/dom/push/test/xpcshell/test_registration_error_http2.js +++ b/dom/push/test/xpcshell/test_registration_error_http2.js @@ -23,16 +23,16 @@ add_task(function* test_registrations_er } }), }); yield rejects( PushService.registration({ scope: 'https://example.net/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), function(error) { return error == 'Database error'; }, 'Wrong message' ); });
--- a/dom/push/test/xpcshell/test_registration_none.js +++ b/dom/push/test/xpcshell/test_registration_none.js @@ -21,12 +21,12 @@ add_task(function* test_registration_non makeWebSocket(uri) { return new MockWebSocket(uri); } }); let registration = yield PushService.registration({ scope: 'https://example.net/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); ok(!registration, 'Should not open a connection without registration'); });
--- a/dom/push/test/xpcshell/test_registration_success.js +++ b/dom/push/test/xpcshell/test_registration_success.js @@ -31,17 +31,17 @@ add_task(function* test_registration_suc { appId: 42 }), version: 10, quota: Infinity, }, { channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728', pushEndpoint: 'https://example.org/update/different-manifest', scope: 'https://example.org/c', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: 42, inBrowser: true }), + { appId: 42, inIsolatedMozBrowser: true }), version: 15, quota: Infinity, }]; for (let record of records) { yield db.put(record); } let handshakeDone;
--- a/dom/push/test/xpcshell/test_registration_success_http2.js +++ b/dom/push/test/xpcshell/test_registration_success_http2.js @@ -41,48 +41,48 @@ add_task(function* test_pushNotification var serverURL = "https://localhost:" + serverPort; let records = [{ subscriptionUri: serverURL + '/subscriptionA', pushEndpoint: serverURL + '/pushEndpointA', pushReceiptEndpoint: serverURL + '/pushReceiptEndpointA', scope: 'https://example.net/a', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, }, { subscriptionUri: serverURL + '/subscriptionB', pushEndpoint: serverURL + '/pushEndpointB', pushReceiptEndpoint: serverURL + '/pushReceiptEndpointB', scope: 'https://example.net/b', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, }, { subscriptionUri: serverURL + '/subscriptionC', pushEndpoint: serverURL + '/pushEndpointC', pushReceiptEndpoint: serverURL + '/pushReceiptEndpointC', scope: 'https://example.net/c', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, }]; for (let record of records) { yield db.put(record); } PushService.init({ serverURI: serverURL, db }); let registration = yield PushService.registration({ scope: 'https://example.net/a', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); equal( registration.endpoint, serverURL + '/pushEndpointA', 'Wrong push endpoint for scope' ); });
--- a/dom/push/test/xpcshell/test_unregister_empty_scope.js +++ b/dom/push/test/xpcshell/test_unregister_empty_scope.js @@ -27,13 +27,13 @@ add_task(function* test_unregister_empty }); } }); yield rejects( PushService.unregister({ scope: '', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }), 'Expected error for empty endpoint' ); });
--- a/dom/push/test/xpcshell/test_unregister_invalid_json.js +++ b/dom/push/test/xpcshell/test_unregister_invalid_json.js @@ -70,17 +70,17 @@ add_task(function* test_unregister_inval }); let record = yield db.getByKeyID( '87902e90-c57e-4d18-8354-013f4a556559'); ok(!record, 'Failed to delete unregistered record'); yield PushService.unregister({ scope: 'https://example.net/page/1', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); record = yield db.getByKeyID( '057caa8f-9b99-47ff-891c-adad18ce603e'); ok(!record, 'Failed to delete unregistered record after receiving invalid JSON'); yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, 'Timed out waiting for unregister');
--- a/dom/push/test/xpcshell/test_unregister_not_found.js +++ b/dom/push/test/xpcshell/test_unregister_not_found.js @@ -26,12 +26,12 @@ add_task(function* test_unregister_not_f } }); } }); let result = yield PushService.unregister({ scope: 'https://example.net/nonexistent', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); ok(result === false, "unregister should resolve with false for nonexistent scope"); });
--- a/dom/push/test/xpcshell/test_unregister_success_http2.js +++ b/dom/push/test/xpcshell/test_unregister_success_http2.js @@ -61,29 +61,29 @@ add_task(function* test_pushUnsubscripti var serverURL = "https://localhost:" + serverPort; yield db.put({ subscriptionUri: serverURL + '/subscriptionUnsubscriptionSuccess', pushEndpoint: serverURL + '/pushEndpointUnsubscriptionSuccess', pushReceiptEndpoint: serverURL + '/receiptPushEndpointUnsubscriptionSuccess', scope: 'https://example.com/page/unregister-success', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), quota: Infinity, }); PushService.init({ serverURI: serverURL, db }); yield PushService.unregister({ scope: 'https://example.com/page/unregister-success', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); let record = yield db.getByKeyID(serverURL + '/subscriptionUnsubscriptionSuccess'); ok(!record, 'Unregister did not remove record'); }); add_task(function* test_complete() { prefs.setBoolPref("network.http.spdy.enforce-tls-profile", tlsProfile);
--- a/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_ws.js +++ b/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_ws.js @@ -66,17 +66,17 @@ add_task(function* test_with_data_enable } }); }, }); let newRecord = yield PushService.register({ scope: 'https://example.com/page/3', originAttributes: ChromeUtils.originAttributesToSuffix( - { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), + { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }), }); ok(newRecord.p256dhKey, 'Should generate public keys for new records'); let record = yield db.getByKeyID('eb18f12a-cc42-4f14-accb-3bfc1227f1aa'); ok(record.p256dhPublicKey, 'Should add public key to partial record'); ok(record.p256dhPrivateKey, 'Should add private key to partial record'); record = yield db.getByKeyID('0d8886b9-8da1-4778-8f5d-1cf93a877ed6');
--- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1350,29 +1350,29 @@ class MOZ_STACK_CLASS OriginParser final nsCString mSchema; nsCString mHost; Nullable<uint32_t> mPort; nsTArray<nsCString> mPathnameComponents; nsCString mHandledTokens; SchemaType mSchemaType; State mState; - bool mInMozBrowser; + bool mInIsolatedMozBrowser; bool mMaybeDriveLetter; bool mError; public: explicit OriginParser(const nsACString& aOrigin) : mOrigin(aOrigin) , mTokenizer(aOrigin, '+') , mAppId(kNoAppId) , mPort() , mSchemaType(eNone) , mState(eExpectingAppIdOrSchema) - , mInMozBrowser(false) + , mInIsolatedMozBrowser(false) , mMaybeDriveLetter(false) , mError(false) { } static bool ParseOrigin(const nsACString& aOrigin, nsCString& aSpec, PrincipalOriginAttributes* aAttrs); @@ -5708,17 +5708,17 @@ OriginClearOp::DoInitOnMainThread() if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } const mozilla::PrincipalOriginAttributes& attrs = mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef(); nsAutoCString pattern; - QuotaManager::GetOriginPatternString(attrs.mAppId, attrs.mInBrowser, origin, + QuotaManager::GetOriginPatternString(attrs.mAppId, attrs.mInIsolatedMozBrowser, origin, pattern); mOriginScope.SetFromPattern(pattern); return NS_OK; } void @@ -6261,17 +6261,17 @@ OriginParser::Parse(nsACString& aSpec, P QM_WARNING("Origin '%s' failed to parse, handled tokens: %s", mOrigin.get(), mHandledTokens.get()); return false; } MOZ_ASSERT(mState == eComplete || mState == eHandledTrailingSeparator); - *aAttrs = PrincipalOriginAttributes(mAppId, mInMozBrowser); + *aAttrs = PrincipalOriginAttributes(mAppId, mInIsolatedMozBrowser); nsAutoCString spec(mSchema); if (mSchemaType == eFile) { spec.AppendLiteral("://"); for (uint32_t count = mPathnameComponents.Length(), index = 0; index < count; @@ -6386,19 +6386,19 @@ OriginParser::HandleToken(const nsDepend QM_WARNING("'%d' is not a valid length for the inMozBrowser flag!", aToken.Length()); mError = true; return; } if (aToken.First() == 't') { - mInMozBrowser = true; + mInIsolatedMozBrowser = true; } else if (aToken.First() == 'f') { - mInMozBrowser = false; + mInIsolatedMozBrowser = false; } else { QM_WARNING("'%s' is not a valid value for the inMozBrowser flag!", nsCString(aToken).get()); mError = true; return; }
--- a/dom/requestsync/RequestSyncManager.js +++ b/dom/requestsync/RequestSyncManager.js @@ -53,37 +53,37 @@ RequestSyncManager.prototype = { }); }, registrations: function() { debug('registrations'); return this.sendMessage("RequestSyncManager:Registrations", {}); }, - setPolicy: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement, + setPolicy: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement, aState, aOverwrittenMinInterval) { debug('setPolicy'); return this.sendMessage("RequestSyncManager:SetPolicy", { task: aTask, origin: aOrigin, manifestURL: aManifestURL, - isInBrowserElement: aIsInBrowserElement, + isInBrowserElement: aIsInIsolatedMozBrowserElement, state: aState, overwrittenMinInterval: aOverwrittenMinInterval }); }, - runTask: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement) { + runTask: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement) { debug('runTask'); return this.sendMessage("RequestSyncManager:RunTask", { task: aTask, origin: aOrigin, manifestURL: aManifestURL, - isInBrowserElement: aIsInBrowserElement }); + isInBrowserElement: aIsInIsolatedMozBrowserElement }); }, registrationsResult: function(aData) { debug("registrationsResult"); let results = new this._window.Array(); for (let i = 0; i < aData.length; ++i) { if (!("app" in aData[i])) {
--- a/dom/requestsync/RequestSyncService.jsm +++ b/dom/requestsync/RequestSyncService.jsm @@ -518,17 +518,17 @@ this.RequestSyncService = { let toSave = null; let self = this; this.forEachRegistration(function(aObj) { if (aObj.data.task != aData.task) { return; } - if (aObj.principal.isInBrowserElement != aData.isInBrowserElement || + if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement || aObj.principal.originNoSuffix != aData.origin) { return; } let app = appsService.getAppByLocalId(aObj.principal.appId); if (app && app.manifestURL != aData.manifestURL || (!app && aData.manifestURL != "")) { return; @@ -567,17 +567,17 @@ this.RequestSyncService = { debug("runTask"); let task = null; this.forEachRegistration(function(aObj) { if (aObj.data.task != aData.task) { return; } - if (aObj.principal.isInBrowserElement != aData.isInBrowserElement || + if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement || aObj.principal.originNoSuffix != aData.origin) { return; } let app = appsService.getAppByLocalId(aObj.principal.appId); if (app && app.manifestURL != aData.manifestURL || (!app && aData.manifestURL != "")) { return; @@ -614,17 +614,17 @@ this.RequestSyncService = { data: aObj.data }; }, createFullTaskObject: function(aObj) { let obj = this.createPartialTaskObject(aObj); obj.app = { manifestURL: '', origin: aObj.principal.originNoSuffix, - isInBrowserElement: aObj.principal.isInBrowserElement }; + isInBrowserElement: aObj.principal.isInIsolatedMozBrowserElement }; let app = appsService.getAppByLocalId(aObj.principal.appId); if (app) { obj.app.manifestURL = app.manifestURL; } obj.state = aObj.state; obj.overwrittenMinInterval = aObj.overwrittenMinInterval;
--- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -53,31 +53,31 @@ Scheme0Scope(DOMStorageCacheBridge* aCac nsCString suffix = aCache->OriginSuffix(); PrincipalOriginAttributes oa; if (!suffix.IsEmpty()) { oa.PopulateFromSuffix(suffix); } - if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID || oa.mInBrowser) { + if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID || oa.mInIsolatedMozBrowser) { result.AppendInt(oa.mAppId); result.Append(':'); - result.Append(oa.mInBrowser ? 't' : 'f'); + result.Append(oa.mInIsolatedMozBrowser ? 't' : 'f'); result.Append(':'); } // If there is more than just appid and/or inbrowser stored in origin // attributes, put it to the schema 0 scope as well. We must do that // to keep the scope column unique (same resolution as schema 1 has // with originAttributes and originKey columns) so that switch between // schema 1 and 0 always works in both ways. nsAutoCString remaining; oa.mAppId = 0; - oa.mInBrowser = false; + oa.mInIsolatedMozBrowser = false; oa.CreateSuffix(remaining); if (!remaining.IsEmpty()) { MOZ_ASSERT(!suffix.IsEmpty()); if (result.IsEmpty()) { // Must contain the old prefix, otherwise we won't search for the whole // origin attributes suffix. result.Append(NS_LITERAL_CSTRING("0:f:"));
--- a/dom/storage/DOMStorageDBUpdater.cpp +++ b/dom/storage/DOMStorageDBUpdater.cpp @@ -62,83 +62,83 @@ nsReverseStringSQLFunction::OnFunctionCa class ExtractOriginData : protected mozilla::Tokenizer { public: ExtractOriginData(const nsACString& scope, nsACString& suffix, nsACString& origin) : mozilla::Tokenizer(scope) { using mozilla::OriginAttributes; - // Parse optional appId:isInBrowserElement: string, in case + // Parse optional appId:isInIsolatedMozBrowserElement: string, in case // we don't find it, the scope is our new origin key and suffix // is empty. suffix.Truncate(); origin.Assign(scope); // Bail out if it isn't appId. uint32_t appId; if (!ReadInteger(&appId)) { return; } // Should be followed by a colon. if (!CheckChar(':')) { return; } - // Bail out if it isn't 'browserFlag'. - nsDependentCSubstring browserFlag; - if (!ReadWord(browserFlag)) { + // Bail out if it isn't 'isolatedBrowserFlag'. + nsDependentCSubstring isolatedBrowserFlag; + if (!ReadWord(isolatedBrowserFlag)) { return; } - bool inBrowser = browserFlag == "t"; - bool notInBrowser = browserFlag == "f"; - if (!inBrowser && !notInBrowser) { + bool inIsolatedMozBrowser = isolatedBrowserFlag == "t"; + bool notInIsolatedBrowser = isolatedBrowserFlag == "f"; + if (!inIsolatedMozBrowser && !notInIsolatedBrowser) { return; } // Should be followed by a colon. if (!CheckChar(':')) { return; } - // OK, we have found appId and inBrowser flag, create the suffix from it - // and take the rest as the origin key. + // OK, we have found appId and inIsolatedMozBrowser flag, create the suffix + // from it and take the rest as the origin key. // If the profile went through schema 1 -> schema 0 -> schema 1 switching // we may have stored the full attributes origin suffix when there were - // more than just appid and inbrowser set on storage principal's + // more than just appId and inIsolatedMozBrowser set on storage principal's // OriginAttributes. // // To preserve full uniqueness we store this suffix to the scope key. // Schema 0 code will just ignore it while keeping the scoping unique. // // The whole scope string is in one of the following forms (when we are here): // // "1001:f:^appId=1001&inBrowser=false&addonId=101:gro.allizom.rxd.:https:443" // "1001:f:gro.allizom.rxd.:https:443" // | // +- the parser cursor position. // // If there is '^', the full origin attributes suffix follows. We search // for ':' since it is the delimiter used in the scope string and is never - // contained in the origin attributes suffix. Remaning string after + // contained in the origin attributes suffix. Remaining string after // the comma is the reversed-domain+schema+port tuple. Record(); if (CheckChar('^')) { Token t; while (Next(t)) { if (t.Equals(Token::Char(':'))) { Claim(suffix); break; } } } else { - PrincipalOriginAttributes attrs(appId, inBrowser); + PrincipalOriginAttributes attrs(appId, inIsolatedMozBrowser); attrs.CreateSuffix(suffix); } // Consume the rest of the input as "origin". origin.Assign(Substring(mCursor, mEnd)); } };
--- a/dom/webidl/ChromeUtils.webidl +++ b/dom/webidl/ChromeUtils.webidl @@ -82,19 +82,19 @@ interface ChromeUtils : ThreadSafeChrome * (1) Add them to both dictionaries. * (2) Update the methods on mozilla::OriginAttributes, including equality, * serialization, deserialization, and inheritance. * (3) Update the methods on mozilla::OriginAttributesPattern, including matching. */ dictionary OriginAttributesDictionary { unsigned long appId = 0; unsigned long userContextId = 0; - boolean inBrowser = false; + boolean inIsolatedMozBrowser = false; DOMString addonId = ""; DOMString signedPkg = ""; }; dictionary OriginAttributesPatternDictionary { unsigned long appId; unsigned long userContextId; - boolean inBrowser; + boolean inIsolatedMozBrowser; DOMString addonId; DOMString signedPkg; };
--- a/dom/webidl/Permissions.webidl +++ b/dom/webidl/Permissions.webidl @@ -21,9 +21,11 @@ dictionary PermissionDescriptor { dictionary PushPermissionDescriptor : PermissionDescriptor { boolean userVisible = false; }; [Exposed=(Window)] interface Permissions { [Throws] Promise<PermissionStatus> query(object permission); + [Throws] + Promise<PermissionStatus> revoke(object permission); };
--- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -34,16 +34,17 @@ interface Request { void setContentPolicyType(nsContentPolicyType context); }; Request implements Body; dictionary RequestInit { ByteString method; HeadersInit headers; BodyInit? body; + USVString referrer; RequestMode mode; RequestCredentials credentials; RequestCache cache; RequestRedirect redirect; }; // Gecko currently does not ship RequestContext, so please don't use it in IDL // that is exposed to script.
--- a/dom/webidl/TextTrack.webidl +++ b/dom/webidl/TextTrack.webidl @@ -34,16 +34,16 @@ interface TextTrack : EventTarget { readonly attribute TextTrackCueList? cues; readonly attribute TextTrackCueList? activeCues; void addCue(VTTCue cue); [Throws] void removeCue(VTTCue cue); - //(Not implemented)attribute EventHandler oncuechange; + attribute EventHandler oncuechange; }; // Mozilla Extensions partial interface TextTrack { [ChromeOnly] readonly attribute TextTrackList? textTrackList; };
--- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -554,25 +554,16 @@ LoadJSGCMemoryOptions(const char* aPrefN nsAutoCString message("Workers don't support the 'mem."); message.Append(memPrefName); message.AppendLiteral("' preference!"); NS_WARNING(message.get()); #endif } } -void -ErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aReport) -{ - WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); - MOZ_ASSERT(worker); - - return worker->ReportError(aCx, aMessage, aReport); -} - bool InterruptCallback(JSContext* aCx) { WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(worker); // Now is a good time to turn on profiling if it's pending. profiler_js_operation_callback(); @@ -807,18 +798,16 @@ CreateJSContextForWorker(WorkerPrivate* JS::SetAsmJSCacheOps(aRuntime, &asmJSCacheOps); JSContext* workerCx = JS_NewContext(aRuntime, 0); if (!workerCx) { NS_WARNING("Could not create new context!"); return nullptr; } - JS_SetErrorReporter(aRuntime, ErrorReporter); - JS_SetInterruptCallback(aRuntime, InterruptCallback); js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback); JS::ContextOptionsRef(workerCx) = kRequiredContextOptions; #ifdef JS_GC_ZEAL JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency); @@ -1661,16 +1650,19 @@ RuntimeService::UnregisterWorker(JSConte if (windowArray->IsEmpty()) { mWindowMap.Remove(window); } } if (queuedWorker && !ScheduleWorker(aCx, queuedWorker)) { UnregisterWorker(aCx, queuedWorker); + // There's nowhere sane to report the exception from ScheduleWorker, if any, + // here. + JS_ClearPendingException(aCx); } } bool RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { if (!aWorkerPrivate->Start()) { // This is ok, means that we didn't need to make a thread for this worker.
--- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -302,16 +302,19 @@ public: private: ~ScriptExecutorRunnable() { } virtual bool IsDebuggerRunnable() const override; virtual bool + PreRun(WorkerPrivate* aWorkerPrivate) override; + + virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) override; NS_DECL_NSICANCELABLERUNNABLE @@ -1719,16 +1722,51 @@ ScriptExecutorRunnable::IsDebuggerRunnab { // ScriptExecutorRunnable is used to execute both worker and debugger scripts. // In the latter case, the runnable needs to be dispatched to the debugger // queue. return mScriptLoader.mWorkerScriptType == DebuggerScript; } bool +ScriptExecutorRunnable::PreRun(WorkerPrivate* aWorkerPrivate) +{ + aWorkerPrivate->AssertIsOnWorkerThread(); + + if (!mIsWorkerScript) { + return true; + } + + if (!aWorkerPrivate->GetJSContext()) { + return false; + } + + MOZ_ASSERT(mFirstIndex == 0); + MOZ_ASSERT(!mScriptLoader.mRv.Failed()); + + AutoJSAPI jsapi; + jsapi.Init(); + jsapi.TakeOwnershipOfErrorReporting(); + + WorkerGlobalScope* globalScope = + aWorkerPrivate->GetOrCreateGlobalScope(jsapi.cx()); + if (NS_WARN_IF(!globalScope)) { + NS_WARNING("Failed to make global!"); + // There's no way to report the exception on jsapi right now, because there + // is no way to even enter a compartment on this thread anymore. Just clear + // the exception. We'll report some sort of error to our caller thread in + // ShutdownScriptLoader. + jsapi.ClearException(); + return false; + } + + return true; +} + +bool ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { aWorkerPrivate->AssertIsOnWorkerThread(); nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos; // Don't run if something else has already failed. for (uint32_t index = 0; index < mFirstIndex; index++) { @@ -1740,42 +1778,21 @@ ScriptExecutorRunnable::WorkerRun(JSCont if (!loadInfo.mExecutionResult) { return true; } } // If nothing else has failed, our ErrorResult better not be a failure either. MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?"); - JS::Rooted<JSObject*> global(aCx); - - if (mIsWorkerScript) { - WorkerGlobalScope* globalScope = - aWorkerPrivate->GetOrCreateGlobalScope(aCx); - if (NS_WARN_IF(!globalScope)) { - NS_WARNING("Failed to make global!"); - // There's no way to report the exception on aCx right now, because there - // is no way to even enter a compartment on this thread anymore. Just - // clear the exception. We'll report some sort of error to our caller - // thread in ShutdownScriptLoader. - JS_ClearPendingException(aCx); - return false; - } - - global.set(globalScope->GetWrapper()); - } else { - // XXXbz Icky action at a distance... Would be better to capture this state - // in mScriptLoader! - global.set(JS::CurrentGlobalOrNull(aCx)); - } - + // Slightly icky action at a distance, but there's no better place to stash + // this value, really. + JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); MOZ_ASSERT(global); - JSAutoCompartment ac(aCx, global); - for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) { ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index); NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!"); NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!"); NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!"); MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
--- a/dom/workers/ServiceWorkerManagerService.cpp +++ b/dom/workers/ServiceWorkerManagerService.cpp @@ -58,22 +58,22 @@ public: if (NS_IsMainThread()) { for (uint32_t i = 0; i < mData->Length(); ++i) { NotifySoftUpdateData& data = mData->ElementAt(i); nsTArray<TabContext> contextArray = data.mContentParent->GetManagedTabContext(); // mContentParent needs to be released in the main thread. data.mContentParent = nullptr; // We only send the notification about the soft update to the - // tabs/apps with the same appId and inBrowser values. + // tabs/apps with the same appId and inIsolatedMozBrowser values. // Sending a notification to the wrong process will make the process // to be killed. for (uint32_t j = 0; j < contextArray.Length(); ++j) { if ((contextArray[j].OwnOrContainingAppId() == mOriginAttributes.mAppId) && - (contextArray[j].IsBrowserElement() == mOriginAttributes.mInBrowser)) { + (contextArray[j].IsIsolatedMozBrowserElement() == mOriginAttributes.mInIsolatedMozBrowser)) { continue; } // Array entries with no mParent won't receive any notification. data.mParent = nullptr; } } nsresult rv = mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL); MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
--- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -271,20 +271,17 @@ public: result.SuppressException(); return; } RefPtr<Promise> waitUntilPromise = aEvent->GetPromise(); if (!waitUntilPromise) { waitUntilPromise = Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result); - if (NS_WARN_IF(result.Failed())) { - result.SuppressException(); - return; - } + MOZ_RELEASE_ASSERT(!result.Failed()); } MOZ_ASSERT(waitUntilPromise); RefPtr<KeepAliveHandler> keepAliveHandler = new KeepAliveHandler(mKeepAliveToken); waitUntilPromise->AppendNativeHandler(keepAliveHandler); if (aWaitUntilPromise) {
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -493,35 +493,39 @@ class CompileScriptRunnable final : publ public: explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aScriptURL) : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount), mScriptURL(aScriptURL) { } private: + // We can't implement PreRun effectively, because at the point when that would + // run we have not yet done our load so don't know things like our final + // principal and whatnot. + virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); ErrorResult rv; scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL, WorkerScript, rv); rv.WouldReportJSException(); // Explicitly ignore NS_BINDING_ABORTED on rv. Or more precisely, still // return false and don't SetWorkerScriptExecutedSuccessfully() in that // case, but don't throw anything on aCx. The idea is to not dispatch error // events if our load is canceled with that error code. if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) { rv.SuppressException(); return false; } - // Make sure to propagate exceptions from rv onto aCx, so that our PostRun - // can report it. We do this for all failures on rv, because now we're - // using rv to track all the state we care about. + // Make sure to propagate exceptions from rv onto aCx, so that they will get + // reported after we return. We do this for all failures on rv, because now + // we're using rv to track all the state we care about. // // This is a little dumb, but aCx is in the null compartment here because we // set it up that way in our Run(), since we had not created the global at // that point yet. So we need to enter the compartment of our global, // because setting a pending exception on aCx involves wrapping into its // current compartment. Luckily we have a global now (else how would we // have a JS exception?) so we can just enter its compartment. JSAutoCompartment ac(aCx, @@ -569,19 +573,19 @@ private: // Explicitly ignore NS_BINDING_ABORTED on rv. Or more precisely, still // return false and don't SetWorkerScriptExecutedSuccessfully() in that // case, but don't throw anything on aCx. The idea is to not dispatch error // events if our load is canceled with that error code. if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) { rv.SuppressException(); return false; } - // Make sure to propagate exceptions from rv onto aCx, so that our PostRun - // can report it. We do this for all failures on rv, because now we're - // using rv to track all the state we care about. + // Make sure to propagate exceptions from rv onto aCx, so that they will get + // reported after we return. We do this for all failures on rv, because now + // we're using rv to track all the state we care about. if (rv.MaybeSetPendingException(aCx)) { return false; } return true; } }; @@ -1226,18 +1230,18 @@ private: virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); JS::Rooted<JS::Value> callable(aCx, JS::ObjectValue(*mHandler->Callable())); JS::HandleValueArray args = JS::HandleValueArray::empty(); JS::Rooted<JS::Value> rval(aCx); - if (!JS_CallFunctionValue(aCx, global, callable, args, &rval) && - !JS_ReportPendingException(aCx)) { + if (!JS_CallFunctionValue(aCx, global, callable, args, &rval)) { + // Just return false; WorkerRunnable::Run will report the exception. return false; } return true; } }; void @@ -3139,16 +3143,24 @@ WorkerPrivateParent<Derived>::BroadcastE const nsAString& aFilename, const nsAString& aLine, uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aFlags) { AssertIsOnMainThread(); + if (JSREPORT_IS_WARNING(aFlags)) { + // Don't fire any events anywhere. Just log to console. + // XXXbz should we log to all the consoles of all the relevant windows? + LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, + aFlags, 0); + return; + } + AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers; GetAllSharedWorkers(sharedWorkers); if (sharedWorkers.IsEmpty()) { return; } AutoTArray<WindowAction, 10> windowActions; @@ -4665,16 +4677,18 @@ WorkerPrivate::ShutdownGCTimers() mIdleGCTimerRunning = false; } bool WorkerPrivate::InterruptCallback(JSContext* aCx) { AssertIsOnWorkerThread(); + MOZ_ASSERT(!JS_IsExceptionPending(aCx)); + bool mayContinue = true; bool scheduledIdleGC = false; for (;;) { // Run all control events now. mayContinue = ProcessAllControlRunnables(); bool mayFreeze = mFrozen;
--- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -150,16 +150,22 @@ WorkerRunnable::PostDispatch(WorkerPriva if (!aDispatchResult) { if (mBehavior == WorkerThreadModifyBusyCount) { aWorkerPrivate->ModifyBusyCount(false); } } } +bool +WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate) +{ + return true; +} + void WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWorkerPrivate); #ifdef DEBUG @@ -179,20 +185,16 @@ WorkerRunnable::PostRun(JSContext* aCx, default: MOZ_ASSERT_UNREACHABLE("Unknown behavior!"); } #endif if (mBehavior == WorkerThreadModifyBusyCount) { aWorkerPrivate->ModifyBusyCountFromWorker(false); } - - if (!aRunResult) { - JS_ReportPendingException(aCx); - } } // static WorkerRunnable* WorkerRunnable::FromRunnable(nsIRunnable* aRunnable) { MOZ_ASSERT(aRunnable); @@ -255,62 +257,83 @@ WorkerRunnable::Run() MOZ_ASSERT(mCallingCancelWithinRun); mCallingCancelWithinRun = false; MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!"); return NS_OK; } - // Track down the appropriate global to use for the AutoJSAPI/AutoEntryScript. + bool result = PreRun(mWorkerPrivate); + if (!result) { + MOZ_ASSERT(targetIsWorkerThread, + "The only PreRun implementation that can fail is " + "ScriptExecutorRunnable"); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate->GetJSContext())); + // We can't enter a useful compartment on the JSContext here; just pass it + // in as-is. + PostRun(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false); + return NS_ERROR_FAILURE; + } + + // Track down the appropriate global, if any, to use for the AutoEntryScript. nsCOMPtr<nsIGlobalObject> globalObject; bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent(); MOZ_ASSERT(isMainThread == NS_IsMainThread()); RefPtr<WorkerPrivate> kungFuDeathGrip; if (targetIsWorkerThread) { JSContext* cx = GetCurrentThreadJSContext(); if (NS_WARN_IF(!cx)) { return NS_ERROR_FAILURE; } JSObject* global = JS::CurrentGlobalOrNull(cx); if (global) { globalObject = GetGlobalObjectForGlobal(global); } else { globalObject = DefaultGlobalObject(); } + + // We may still not have a globalObject here: in the case of + // CompileScriptRunnable, we don't actually create the global object until + // we have the script data, which happens in a syncloop under + // CompileScriptRunnable::WorkerRun, so we can't assert that it got created + // in the PreRun call above. } else { kungFuDeathGrip = mWorkerPrivate; if (isMainThread) { globalObject = nsGlobalWindow::Cast(mWorkerPrivate->GetWindow()); } else { globalObject = mWorkerPrivate->GetParent()->GlobalScope(); } } // We might run script as part of WorkerRun, so we need an AutoEntryScript. // This is part of the HTML spec for workers at: // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker // If we don't have a globalObject we have to use an AutoJSAPI instead, but // this is OK as we won't be running script in these circumstances. - // It's important that aes is declared after jsapi, because if WorkerRun - // creates a global then we construct aes before PostRun and we need them to - // be destroyed in the correct order. - mozilla::dom::AutoJSAPI jsapi; + Maybe<mozilla::dom::AutoJSAPI> maybeJSAPI; Maybe<mozilla::dom::AutoEntryScript> aes; JSContext* cx; + AutoJSAPI* jsapi; if (globalObject) { aes.emplace(globalObject, "Worker runnable", isMainThread, isMainThread ? nullptr : GetCurrentThreadJSContext()); + jsapi = aes.ptr(); cx = aes->cx(); } else { - jsapi.Init(); - cx = jsapi.cx(); + maybeJSAPI.emplace(); + maybeJSAPI->Init(); + jsapi = maybeJSAPI.ptr(); + cx = jsapi->cx(); } + jsapi->TakeOwnershipOfErrorReporting(); // Note that we can't assert anything about mWorkerPrivate->GetWrapper() // existing, since it may in fact have been GCed (and we may be one of the // runnables cleaning up the worker as a result). // If we are on the parent thread and that thread is not the main thread, // then we must be a dedicated worker (because there are no // Shared/ServiceWorkers whose parent is itself a worker) and then we @@ -343,27 +366,44 @@ WorkerRunnable::Run() js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == js::GetContextCompartment(cx), "Must either be in the null compartment or in our reflector " "compartment"); ac.emplace(cx, mWorkerPrivate->GetWrapper()); } - bool result = WorkerRun(cx, mWorkerPrivate); + MOZ_ASSERT(!jsapi->HasException()); + result = WorkerRun(cx, mWorkerPrivate); + MOZ_ASSERT_IF(result, !jsapi->HasException()); + jsapi->ReportException(); + + // We can't even assert that this didn't create our global, since in the case + // of CompileScriptRunnable it _does_. - // In the case of CompileScriptRunnnable, WorkerRun above can cause us to - // lazily create a global, so we construct aes here before calling PostRun. - if (targetIsWorkerThread && !aes && DefaultGlobalObject()) { - aes.emplace(DefaultGlobalObject(), "worker runnable", - false, GetCurrentThreadJSContext()); - cx = aes->cx(); - } - + // It would be nice to avoid passing a JSContext to PostRun, but in the case + // of ScriptExecutorRunnable we need to know the current compartment on the + // JSContext (the one we set up based on the global returned from PreRun) so + // that we can sanely do exception reporting. In particular, we want to make + // sure that we do our JS_SetPendingException while still in that compartment, + // because otherwise we might end up trying to create a cross-compartment + // wrapper when we try to move the JS exception from our runnable's + // ErrorResult to the JSContext, and that's not desirable in this case. + // + // We _could_ skip passing a JSContext here and then in + // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate + // and looking at its current compartment. But that seems like slightly weird + // action-at-a-distance... + // + // In any case, we do NOT try to change the compartment on the JSContext at + // this point; in the one case in which we could do that + // (CompileScriptRunnable) it actually doesn't matter which compartment we're + // in for PostRun. PostRun(cx, mWorkerPrivate, result); + MOZ_ASSERT(!jsapi->HasException()); return result ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP WorkerRunnable::Cancel() { uint32_t canceledCount = ++mCanceled;
--- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -117,41 +117,57 @@ protected: virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate); // By default asserts that Dispatch() is being called on the right thread // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult); + // May be implemented by subclasses if desired if they need to do some sort of + // setup before we try to set up our JSContext and compartment for real. + // Typically the only thing that should go in here is creation of the worker's + // global. + // + // If false is returned, WorkerRun will not be called at all. PostRun will + // still be called, with false passed for aRunResult. + virtual bool + PreRun(WorkerPrivate* aWorkerPrivate); + // Must be implemented by subclasses. Called on the target thread. The return // value will be passed to PostRun(). The JSContext passed in here comes from // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of // mWorkerPrivate's reflector (i.e. the worker object in the parent thread), // unless that reflector is null, in which case it's in the compartment of the // parent global (which is the compartment reflector would have been in), or // in the null compartment if there is no parent global. For other mBehavior // values, we're running on the worker thread and aCx is in whatever // compartment GetCurrentThreadJSContext() was in when nsIRunnable::Run() got - // called (XXXbz: Why is this a sane thing to be doing now that we have - // multiple globals per worker???). If it wasn't in a compartment, aCx will - // be in either the debugger global's compartment or the worker's global's - // compartment depending on whether IsDebuggerRunnable() is true. + // called. This is actually important for cases when a runnable spins a + // syncloop and wants everything that happens during the syncloop to happen in + // the compartment that runnable set up (which may, for example, be a debugger + // sandbox compartment!). If aCx wasn't in a compartment to start with, aCx + // will be in either the debugger global's compartment or the worker's + // global's compartment depending on whether IsDebuggerRunnable() is true. + // + // Immediately after WorkerRun returns, the caller will assert that either it + // returns false or there is no exception pending on aCx. Then it will report + // any pending exceptions on aCx. virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; // By default asserts that Run() (and WorkerRun()) were called on the correct // thread. Also sends an asynchronous message to the ParentThread if the // busy count was previously modified in PreDispatch(). // // The aCx passed here is the same one as was passed to WorkerRun and is - // still in the same compartment. If aRunResult is false, any failures on - // aCx are reported. Otherwise failures are left to linger on the JSContext - // and maim later code (XXXbz: Aiming to fix that in bug 1072144). + // still in the same compartment. PostRun implementations must NOT leave an + // exception on the JSContext and must not run script, because the incoming + // JSContext may be in the null compartment. virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); virtual bool DispatchInternal(); // Calling Run() directly is not supported. Just call Dispatch() and // WorkerRun() will be called on the correct thread automatically.
--- a/dom/workers/test/sharedWorker_sharedWorker.js +++ b/dom/workers/test/sharedWorker_sharedWorker.js @@ -67,16 +67,21 @@ onconnect = function(event) { } if (!(event.ports[0] == event.source)) { throw new Error("'connect' event source property is incorrect!"); } if (event.data) { throw new Error("'connect' event has data: " + event.data); } + // "".contains("") should trigger a warning in debug builds, but NOT fire + // error events at us. If we ever actually remove contains() we'll need + // something else to test this case. + "".contains(""); + event.ports[0].onmessage = function(event) { if (!(event instanceof MessageEvent)) { throw new Error("'message' event is not a MessageEvent!"); } if (!("ports" in event)) { throw new Error("'message' event doesn't have a 'ports' property!"); } if (event.ports === null) {
--- a/dom/workers/test/test_sharedWorker.html +++ b/dom/workers/test/test_sharedWorker.html @@ -17,17 +17,17 @@ <script class="testbody"> "use strict"; const href = window.location.href; const filename = "sharedWorker_sharedWorker.js"; const sentMessage = "ping"; const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) + filename; - const errorLine = 86; + const errorLine = 91; const errorColumn = 0; var worker = new SharedWorker(filename); ok(worker instanceof SharedWorker, "Got SharedWorker instance"); ok(!("postMessage" in worker), "SharedWorker has no 'postMessage'"); ok(worker.port instanceof MessagePort, "Shared worker has MessagePort");
--- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -6470,17 +6470,20 @@ nsHTMLEditRules::ReturnInParagraph(Selec int32_t offset; nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aNode, &offset); NS_ENSURE_STATE(mHTMLEditor); bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(); bool newBRneeded = false; + bool newSelNode = false; nsCOMPtr<nsIDOMNode> sibling; + nsCOMPtr<nsIDOMNode> selNode = aNode; + int32_t selOffset = aOffset; NS_ENSURE_STATE(mHTMLEditor); if (aNode == aPara && doesCRCreateNewP) { // we are at the edges of the block, newBRneeded not needed! sibling = aNode; } else if (mHTMLEditor->IsTextNode(aNode)) { nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aNode); uint32_t strLength; @@ -6508,58 +6511,65 @@ nsHTMLEditRules::ReturnInParagraph(Selec newBRneeded = true; offset++; } } else { if (doesCRCreateNewP) { nsCOMPtr<nsIDOMNode> tmp; res = mEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp)); NS_ENSURE_SUCCESS(res, res); - aNode = tmp; + selNode = tmp; } newBRneeded = true; offset++; } } else { // not in a text node. // is there a BR prior to it? - nsCOMPtr<nsIDOMNode> nearNode, selNode = aNode; + nsCOMPtr<nsIDOMNode> nearNode; NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) { // is there a BR after it? NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || nsTextEditUtils::HasMozAttr(nearNode)) { newBRneeded = true; + parent = aNode; + offset = 0; + newSelNode = true; } } if (!newBRneeded) { sibling = nearNode; } } if (newBRneeded) { // if CR does not create a new P, default to BR creation NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK); nsCOMPtr<nsIDOMNode> brNode; NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->CreateBR(parent, offset, address_of(brNode)); sibling = brNode; - } - nsCOMPtr<nsIDOMNode> selNode = aNode; + if (newSelNode) { + // We split the parent after the br we've just inserted. + selNode = parent; + selOffset = 1; + } + } *aHandled = true; - return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &aOffset); + return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &selOffset); } /////////////////////////////////////////////////////////////////////////// // SplitParagraph: split a paragraph at selection point, possibly deleting a br // nsresult nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, nsIDOMNode *aBRNode,
--- a/editor/libeditor/tests/chrome.ini +++ b/editor/libeditor/tests/chrome.ini @@ -25,16 +25,17 @@ skip-if = buildapp == 'mulet' [test_bug1102906.html] [test_bug1101392.html] [test_bug1140105.html] [test_bug1140617.xul] [test_bug1153237.html] [test_bug1154791.html] [test_bug1248128.html] [test_bug1248185.html] +[test_bug1250010.html] [test_composition_event_created_in_chrome.html] [test_contenteditable_text_input_handling.html] [test_dragdrop.html] skip-if = buildapp == 'mulet' [test_htmleditor_keyevent_handling.html] [test_selection_move_commands.xul] [test_texteditor_keyevent_handling.html] skip-if = (debug && os=='win') || (os == 'linux') # Bug 1116205, leaks on windows debug, fails delete key on linux
new file mode 100644 --- /dev/null +++ b/editor/libeditor/tests/test_bug1250010.html @@ -0,0 +1,53 @@ +<!DOCTYPE> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1250010 +--> +<head> + <title>Test for Bug 1250010</title> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> + <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> +</head> +<body> +<div id="display"> +</div> + +<div id="content" contenteditable><p><b><font color="red">1234567890</font></b></p></div> + +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> + +/** Test for Bug 1250010 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var div = document.getElementById("content"); + div.focus(); + synthesizeMouseAtCenter(div, {}); + + var sel = window.getSelection(); + var selRange = sel.getRangeAt(0); + is(selRange.endContainer.nodeName, "#text", "selection should be at the end of text node"); + is(selRange.endOffset, 10, "offset should be 10"); + + synthesizeKey("VK_RETURN", {}); + synthesizeKey("VK_RETURN", {}); + synthesizeKey("b", {}); + synthesizeKey("VK_UP", {}); + synthesizeKey("a", {}); + + is(div.innerHTML, "<p><b><font color=\"red\">1234567890</font></b></p>" + + "<p><b><font color=\"red\">a<br></font></b></p>" + + "<p><b><font color=\"red\">b<br></font></b></p>", + "unexpected HTML"); + + SimpleTest.finish(); + +}); + +</script> +</body> + +</html>
--- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -568,20 +568,23 @@ nsDocShellTreeOwner::GetDevicePixelsPerD *aScale = 1.0; return NS_OK; } NS_IMETHODIMP nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY) { - // Added to nsIBaseWindow in bug 1247335; - // implement if a use-case is found. - NS_ASSERTION(false, "implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; + if (mWebBrowser) { + return mWebBrowser->SetPositionDesktopPix(aX, aY); + } + + double scale = 1.0; + GetDevicePixelsPerDesktopPixel(&scale); + return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale)); } NS_IMETHODIMP nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY) { nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); if (ownerWin) { return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
--- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -1300,20 +1300,26 @@ nsWebBrowser::GetDevicePixelsPerDesktopP *aScale = mParentWidget ? mParentWidget->GetDesktopToDeviceScale().scale : 1.0; return NS_OK; } NS_IMETHODIMP nsWebBrowser::SetPositionDesktopPix(int32_t aX, int32_t aY) { - // Added to nsIBaseWindow in bug 1247335; - // implement if a use-case is found. - NS_ASSERTION(false, "implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; + // XXX jfkthame + // It's not clear to me whether this will be fully correct across + // potential multi-screen, mixed-DPI configurations for all platforms; + // we might need to add code paths that make it possible to pass the + // desktop-pix parameters all the way through to the native widget, + // to avoid the risk of device-pixel coords mapping to the wrong + // display on OS X with mixed retina/non-retina screens. + double scale = 1.0; + GetDevicePixelsPerDesktopPixel(&scale); + return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale)); } NS_IMETHODIMP nsWebBrowser::SetPosition(int32_t aX, int32_t aY) { int32_t cx = 0; int32_t cy = 0;
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp @@ -1694,17 +1694,17 @@ nsWindowWatcher::CalculateChromeFlags(mo if (!(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) { // Remove the dependent flag if we're not opening as chrome chromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT; } // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>. // It's up to the embedder to interpret what dialog=1 means. nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent); - if (docshell && docshell->GetIsInBrowserOrApp()) { + if (docshell && docshell->GetIsInMozBrowserOrApp()) { chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG; } return chromeFlags; } // static int32_t
--- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -118,20 +118,20 @@ GetPrincipalFromOrigin(const nsACString& nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs); principal.forget(aPrincipal); return NS_OK; } nsresult -GetPrincipal(nsIURI* aURI, uint32_t aAppId, bool aIsInBrowserElement, nsIPrincipal** aPrincipal) +GetPrincipal(nsIURI* aURI, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement, nsIPrincipal** aPrincipal) { // TODO: Bug 1165267 - Use OriginAttributes for nsCookieService - mozilla::PrincipalOriginAttributes attrs(aAppId, aIsInBrowserElement); + mozilla::PrincipalOriginAttributes attrs(aAppId, aIsInIsolatedMozBrowserElement); nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); principal.forget(aPrincipal); return NS_OK; } nsresult @@ -358,17 +358,17 @@ private: nsCOMPtr<mozIStorageConnection> mDBConn; int64_t* mID; }; nsresult UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime, uint32_t aAppId, bool aIsInBrowserElement, + int64_t aModificationTime, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement, UpgradeHostToOriginHelper* aHelper) { if (aHost.EqualsLiteral("<file>")) { // We no longer support the magic host <file> NS_WARNING("The magic host <file> is no longer supported. " "It is being removed from the permissions database."); return NS_OK; } @@ -382,17 +382,17 @@ UpgradeHostToOriginAndInsert(const nsACS // these useless database entries bool nullpScheme = false; if (NS_SUCCEEDED(uri->SchemeIs("moz-nullprincipal", &nullpScheme)) && nullpScheme) { NS_WARNING("A moz-nullprincipal: permission is being discarded."); return NS_OK; } nsCOMPtr<nsIPrincipal> principal; - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString origin; rv = principal->GetOrigin(origin); NS_ENSURE_SUCCESS(rv, rv); return aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); @@ -490,17 +490,17 @@ UpgradeHostToOriginAndInsert(const nsACS if (NS_WARN_IF(NS_FAILED(rv))) continue; // Use the provided host - this URI may be for a subdomain, rather than the host we care about. rv = uri->SetHost(aHost); if (NS_WARN_IF(NS_FAILED(rv))) continue; // We now have a URI which we can make a nsIPrincipal out of nsCOMPtr<nsIPrincipal> principal; - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); if (NS_WARN_IF(NS_FAILED(rv))) continue; nsAutoCString origin; rv = principal->GetOrigin(origin); if (NS_WARN_IF(NS_FAILED(rv))) continue; // Ensure that we don't insert the same origin repeatedly if (insertedOrigins.Contains(origin)) { @@ -536,30 +536,30 @@ UpgradeHostToOriginAndInsert(const nsACS } else { hostSegment.Assign(aHost); } // http:// URI default rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + hostSegment); NS_ENSURE_SUCCESS(rv, rv); - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); rv = principal->GetOrigin(origin); NS_ENSURE_SUCCESS(rv, rv); aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); // https:// URI default rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment); NS_ENSURE_SUCCESS(rv, rv); - rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal)); + rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); rv = principal->GetOrigin(origin); NS_ENSURE_SUCCESS(rv, rv); aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, aModificationTime); }
--- a/extensions/cookie/test/channel_utils.js +++ b/extensions/cookie/test/channel_utils.js @@ -161,24 +161,24 @@ ChannelListener.prototype = { } } }; /** * Class that implements nsILoadContext. Use it as callbacks for channel when * test needs it. */ -function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) { +function LoadContextCallback(appId, inIsolatedMozBrowser, isPrivate, isContent) { this.appId = appId; - this.isInBrowserElement = inBrowserElement; + this.isInIsolatedMozBrowserElement = inIsolatedMozBrowser; this.usePrivateBrowsing = isPrivate; this.isContent = isContent; this.originAttributes = { appId: appId, - inBrowser: inBrowserElement + inIsolatedMozBrowser: inIsolatedMozBrowser }; } LoadContextCallback.prototype = { associatedWindow: null, topWindow : null, isAppOfType: function(appType) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
--- a/extensions/cookie/test/test_app_uninstall_permissions.html +++ b/extensions/cookie/test/test_app_uninstall_permissions.html @@ -75,17 +75,17 @@ function onInstall() { var attrs = {appId: testAppId}; var principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null), attrs); permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION); permManager.addFromPrincipal(principal, "foo", Ci.nsIPermissionManager.DENY_ACTION); permManager.addFromPrincipal(principal, "bar", Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION, 0); - attrs = {appId: testAppId, inBrowser: true}; + attrs = {appId: testAppId, inIsolatedMozBrowser: true}; principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null), attrs); permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION); attrs = {appId: testAppId}; principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.org", null, null), attrs); permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
--- a/extensions/cookie/test/unit/test_permmanager_cleardata.js +++ b/extensions/cookie/test/unit/test_permmanager_cleardata.js @@ -49,20 +49,20 @@ function run_test() { do_get_profile(); pm = Cc["@mozilla.org/permissionmanager;1"] .getService(Ci.nsIPermissionManager); let entries = [ { origin: 'http://example.com', originAttributes: { appId: 1 } }, - { origin: 'http://example.com', originAttributes: { appId: 1, inBrowser: true } }, + { origin: 'http://example.com', originAttributes: { appId: 1, inIsolatedMozBrowser: true } }, { origin: 'http://example.com', originAttributes: {} }, { origin: 'http://example.com', originAttributes: { appId: 2 } }, ]; // In that case, all permissions from app 1 should be removed but not the other ones. test(entries, getData({appId: 1}), [ pm.UNKNOWN_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]); // In that case, only the permissions of app 1 related to a browserElement should be removed. // All the other permissions should stay. - test(entries, getData({appId: 1, inBrowser: true}), [ pm.ALLOW_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]); + test(entries, getData({appId: 1, inIsolatedMozBrowser: true}), [ pm.ALLOW_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]); }
--- a/extensions/cookie/test/unit/test_permmanager_defaults.js +++ b/extensions/cookie/test/unit/test_permmanager_defaults.js @@ -51,17 +51,17 @@ add_task(function* do_test() { getService(Ci.nsIPermissionManager); // test the default permission was applied. let principal = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN, {}); let principalHttps = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_HTTPS, {}); let principal2 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_2, {}); let principal3 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_3, {}); - let attrs = {appId: 1000, inBrowser: true}; + let attrs = {appId: 1000, inIsolatedMozBrowser: true}; let principal4 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN, attrs); let principal5 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_3, attrs); do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION, pm.testPermissionFromPrincipal(principal, TEST_PERMISSION)); do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION, pm.testPermissionFromPrincipal(principalHttps, TEST_PERMISSION)); do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
--- a/extensions/cookie/test/unit/test_permmanager_matches.js +++ b/extensions/cookie/test/unit/test_permmanager_matches.js @@ -48,33 +48,33 @@ function run_test() { let attrs = {appId: 1000}; let uri0_1000_n = secMan.createCodebasePrincipal(uri0, attrs); let uri1_1000_n = secMan.createCodebasePrincipal(uri1, attrs); let uri2_1000_n = secMan.createCodebasePrincipal(uri2, attrs); let uri3_1000_n = secMan.createCodebasePrincipal(uri3, attrs); let uri4_1000_n = secMan.createCodebasePrincipal(uri4, attrs); let uri5_1000_n = secMan.createCodebasePrincipal(uri5, attrs); - attrs = {appId: 1000, inBrowser: true}; + attrs = {appId: 1000, inIsolatedMozBrowser: true}; let uri0_1000_y = secMan.createCodebasePrincipal(uri0, attrs); let uri1_1000_y = secMan.createCodebasePrincipal(uri1, attrs); let uri2_1000_y = secMan.createCodebasePrincipal(uri2, attrs); let uri3_1000_y = secMan.createCodebasePrincipal(uri3, attrs); let uri4_1000_y = secMan.createCodebasePrincipal(uri4, attrs); let uri5_1000_y = secMan.createCodebasePrincipal(uri5, attrs); attrs = {appId: 2000}; let uri0_2000_n = secMan.createCodebasePrincipal(uri0, attrs); let uri1_2000_n = secMan.createCodebasePrincipal(uri1, attrs); let uri2_2000_n = secMan.createCodebasePrincipal(uri2, attrs); let uri3_2000_n = secMan.createCodebasePrincipal(uri3, attrs); let uri4_2000_n = secMan.createCodebasePrincipal(uri4, attrs); let uri5_2000_n = secMan.createCodebasePrincipal(uri5, attrs); - attrs = {appId: 2000, inBrowser: true}; + attrs = {appId: 2000, inIsolatedMozBrowser: true}; let uri0_2000_y = secMan.createCodebasePrincipal(uri0, attrs); let uri1_2000_y = secMan.createCodebasePrincipal(uri1, attrs); let uri2_2000_y = secMan.createCodebasePrincipal(uri2, attrs); let uri3_2000_y = secMan.createCodebasePrincipal(uri3, attrs); let uri4_2000_y = secMan.createCodebasePrincipal(uri4, attrs); let uri5_2000_y = secMan.createCodebasePrincipal(uri5, attrs); pm.addFromPrincipal(uri0_n_n, "test/matches", pm.ALLOW_ACTION);
--- a/extensions/cookie/test/unit/test_permmanager_removeforapp.js +++ b/extensions/cookie/test/unit/test_permmanager_removeforapp.js @@ -1,19 +1,19 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ function run_test() { // initialize the permission manager service let ssm = Services.scriptSecurityManager; let pm = Services.perms; - function mkPrin(uri, appId, inBrowser) { + function mkPrin(uri, appId, inIsolatedMozBrowser) { return ssm.createCodebasePrincipal(Services.io.newURI(uri, null, null), - {appId: appId, inBrowser: inBrowser}); + {appId: appId, inIsolatedMozBrowser: inIsolatedMozBrowser}); } function checkPerms(perms) { perms.forEach((perm) => { // Look up the expected permission do_check_eq(pm.getPermissionObject(mkPrin(perm[0], perm[1], perm[2]), perm[3], true).capability, perm[4], "Permission is expected in the permission database"); @@ -88,12 +88,12 @@ function run_test() { ['http://google.com', 1011, false, 'a', 1], ['http://google.com', 1011, false, 'b', 1], ['http://mozilla.com', 1011, false, 'b', 1], ['http://mozilla.com', 1011, false, 'a', 1], ]; attrs = { appId: 1001, - inBrowser: true }; + inIsolatedMozBrowser: true }; pm.removePermissionsWithAttributes(JSON.stringify(attrs)); checkPerms(remove_true_perms); }
--- a/gfx/layers/apz/test/reftest/reftest.list +++ b/gfx/layers/apz/test/reftest/reftest.list @@ -1,16 +1,16 @@ # The following tests test the async positioning of the scrollbars. # Basic root-frame scrollbar with async scrolling -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html -skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html +fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html # Different async zoom levels. Since the scrollthumb gets async-scaled in the # compositor, the border-radius ends of the scrollthumb are going to be a little # off, hence the fuzzy-if clauses. skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html # Meta-viewport tag support
--- a/image/SVGDocumentWrapper.cpp +++ b/image/SVGDocumentWrapper.cpp @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SVGDocumentWrapper.h" +#include "mozilla/dom/DocumentTimeline.h" #include "mozilla/dom/Element.h" #include "nsICategoryManager.h" #include "nsIChannel.h" #include "nsIContentViewer.h" #include "nsIDocument.h" #include "nsIDocumentLoaderFactory.h" #include "nsIDOMSVGLength.h" #include "nsIHttpChannel.h" @@ -110,18 +111,31 @@ SVGDocumentWrapper::FlushImageTransformI FlushLayout(); mIgnoreInvalidation = false; } bool SVGDocumentWrapper::IsAnimated() { nsIDocument* doc = mViewer->GetDocument(); - return doc && doc->HasAnimationController() && - doc->GetAnimationController()->HasRegisteredAnimations(); + if (!doc) { + return false; + } + if (doc->Timeline()->HasAnimations()) { + // CSS animations (technically HasAnimations() also checks for CSS + // transitions and Web animations but since SVG-as-an-image doesn't run + // script they will never run in the document that we wrap). + return true; + } + if (doc->HasAnimationController() && + doc->GetAnimationController()->HasRegisteredAnimations()) { + // SMIL animations + return true; + } + return false; } void SVGDocumentWrapper::StartAnimation() { // Can be called for animated images during shutdown, after we've // already Observe()'d XPCOM shutdown and cleared out our mViewer pointer. if (!mViewer) {
--- a/ipc/glue/CrossProcessMutex.h +++ b/ipc/glue/CrossProcessMutex.h @@ -4,17 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_CrossProcessMutex_h #define mozilla_CrossProcessMutex_h #include "base/process.h" #include "mozilla/Mutex.h" -#if defined(OS_LINUX) || defined(XP_DARWIN) +#if !defined(OS_WIN) && !defined(OS_NETBSD) && !defined(OS_OPENBSD) #include <pthread.h> #include "SharedMemoryBasic.h" #include "mozilla/Atomics.h" #include "nsAutoPtr.h" #endif namespace IPC { template<typename T> @@ -29,17 +29,17 @@ struct ParamTraits; // properly locked and unlocked // // Using CrossProcessMutexAutoLock/CrossProcessMutexAutoUnlock is MUCH // preferred to making bare calls to CrossProcessMutex.Lock and Unlock. // namespace mozilla { #if defined(OS_WIN) typedef HANDLE CrossProcessMutexHandle; -#elif defined(OS_LINUX) || defined(OS_MACOSX) +#elif !defined(OS_NETBSD) && !defined(OS_OPENBSD) typedef mozilla::ipc::SharedMemoryBasic::Handle CrossProcessMutexHandle; #else // Stub for other platforms. We can't use uintptr_t here since different // processes could disagree on its size. typedef uintptr_t CrossProcessMutexHandle; #endif class CrossProcessMutex @@ -95,17 +95,17 @@ private: friend struct IPC::ParamTraits<CrossProcessMutex>; CrossProcessMutex(); CrossProcessMutex(const CrossProcessMutex&); CrossProcessMutex &operator=(const CrossProcessMutex&); #if defined(OS_WIN) HANDLE mMutex; -#elif defined(OS_LINUX) || defined(OS_MACOSX) +#elif !defined(OS_NETBSD) && !defined(OS_OPENBSD) RefPtr<mozilla::ipc::SharedMemoryBasic> mSharedBuffer; pthread_mutex_t* mMutex; mozilla::Atomic<int32_t>* mCount; #endif }; typedef BaseAutoLock<CrossProcessMutex> CrossProcessMutexAutoLock; typedef BaseAutoUnlock<CrossProcessMutex> CrossProcessMutexAutoUnlock;
--- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -56,17 +56,17 @@ else: 'SharedMemory_posix.cpp', 'Transport_posix.cpp', ] if CONFIG['OS_ARCH'] == 'WINNT': SOURCES += [ 'CrossProcessMutex_windows.cpp', ] -elif CONFIG['OS_ARCH'] in ('Linux', 'Darwin'): +elif not CONFIG['OS_ARCH'] in ('NetBSD', 'OpenBSD'): UNIFIED_SOURCES += [ 'CrossProcessMutex_posix.cpp', ] else: UNIFIED_SOURCES += [ 'CrossProcessMutex_unimplemented.cpp', ]
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7470,20 +7470,16 @@ Parser<ParseHandler>::expr(InHandling in return null(); if (!matched) return pn; Node seq = handler.newCommaExpressionList(pn); if (!seq) return null(); while (true) { - if (handler.isUnparenthesizedYieldExpression(pn)) { - report(ParseError, false, pn, JSMSG_BAD_YIELD_SYNTAX); - return null(); - } pn = assignExpr(inHandling, yieldHandling, tripledotHandling); if (!pn) return null(); handler.addList(seq, pn); if (!tokenStream.matchToken(&matched, TOK_COMMA)) return null(); @@ -8452,26 +8448,16 @@ Parser<ParseHandler>::argumentList(Yield if (!argNode) return false; if (spread) { argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode); if (!argNode) return false; } - if (handler.isUnparenthesizedYieldExpression(argNode)) { - TokenKind tt; - if (!tokenStream.peekToken(&tt)) - return false; - if (tt == TOK_COMMA) { - report(ParseError, false, argNode, JSMSG_BAD_YIELD_SYNTAX); - return false; - } - } - handler.addList(listNode, argNode); bool matched; if (!tokenStream.matchToken(&matched, TOK_COMMA)) return false; if (!matched) break; }
--- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -112,24 +112,16 @@ class SyntaxParseHandler // Legacy generator expressions of the form |(expr for (...))| and // array comprehensions of the form |[expr for (...)]|) don't permit // |expr| to be a comma expression. Thus we need this to treat // |(a(), b for (x in []))| as a syntax error and // |((a(), b) for (x in []))| as a generator that calls |a| and then // yields |b| each time it's resumed. NodeUnparenthesizedCommaExpr, - // Yield expressions currently (but not in ES6 -- a SpiderMonkey bug to - // fix) must generally be parenthesized. (See the uses of - // isUnparenthesizedYieldExpression in Parser.cpp for the rare - // exceptions.) Thus we need this to treat |yield 1, 2;| as a syntax - // error and |(yield 1), 2;| as a comma expression that will yield 1, - // then evaluate to 2. - NodeUnparenthesizedYieldExpr, - // Assignment expressions in condition contexts could be typos for // equality checks. (Think |if (x = y)| versus |if (x == y)|.) Thus // we need this to treat |if (x = y)| as a possible typo and // |if ((x = y))| as a deliberate assignment within a condition. // // (Technically this isn't needed, as these are *only* extraWarnings // warnings, and parsing with that option disables syntax parsing. But // it seems best to be consistent, and perhaps the syntax parser will @@ -283,17 +275,17 @@ class SyntaxParseHandler Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } Node newSuperBase(Node thisName, const TokenPos& pos) { return NodeSuperBase; } bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } bool addShorthand(Node literal, Node name, Node expr) { return true; } bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } - Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } + Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } // Statements Node newStatementList(unsigned blockid, const TokenPos& pos) { return NodeGeneric; } void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {} void addCaseStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {} bool prependInitialYield(Node stmtList, Node gen) { return true; } @@ -478,20 +470,16 @@ class SyntaxParseHandler Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs, ParseContext<SyntaxParseHandler>* pc, JSOp op) { if (kind == PNK_ASSIGN) return NodeUnparenthesizedAssignment; return newBinary(kind, lhs, rhs, op); } - bool isUnparenthesizedYieldExpression(Node node) { - return node == NodeUnparenthesizedYieldExpr; - } - bool isUnparenthesizedCommaExpression(Node node) { return node == NodeUnparenthesizedCommaExpr; } bool isUnparenthesizedAssignment(Node node) { return node == NodeUnparenthesizedAssignment; } @@ -529,17 +517,16 @@ class SyntaxParseHandler return NodeParenthesizedArray; if (node == NodeUnparenthesizedObject) return NodeParenthesizedObject; // Other nodes need not be recognizable after parenthesization; convert // them to a generic node. if (node == NodeUnparenthesizedString || node == NodeUnparenthesizedCommaExpr || - node == NodeUnparenthesizedYieldExpr || node == NodeUnparenthesizedAssignment) { return NodeGeneric; } // In all other cases, the parenthesized form of |node| is equivalent // to the unparenthesized form: return |node| unchanged. return node;
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2105,16 +2105,17 @@ js::TenuringTracer::insertIntoFixupList( tail = &entry->nextRef(); *tail = nullptr; } JSObject* js::TenuringTracer::moveToTenured(JSObject* src) { MOZ_ASSERT(IsInsideNursery(src)); + MOZ_ASSERT(!src->zone()->usedByExclusiveThread); AllocKind dstKind = src->allocKindForTenure(nursery()); Zone* zone = src->zone(); TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind)); if (!t) { zone->arenas.checkEmptyFreeList(dstKind); AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
--- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -505,16 +505,24 @@ void MacroAssembler::branchTestNeedsIncrementalBarrier(Condition cond, Label* label) { MOZ_ASSERT(cond == Zero || cond == NonZero); CompileZone* zone = GetJitContext()->compartment->zone(); AbsoluteAddress needsBarrierAddr(zone->addressOfNeedsIncrementalBarrier()); branchTest32(cond, needsBarrierAddr, Imm32(0x1), label); } +void +MacroAssembler::branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why, + Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + branchTestValue(cond, val, MagicValue(why), label); +} + //}}} check_macroassembler_style // =============================================================== #ifndef JS_CODEGEN_ARM64 template <typename T> void MacroAssembler::branchTestStackPtr(Condition cond, T t, Label* label)
--- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -916,27 +916,148 @@ class MacroAssembler : public MacroAssem // might actually be that type. void branchEqualTypeIfNeeded(MIRType type, MDefinition* maybeDef, Register tag, Label* label); template <typename T> inline void branchKey(Condition cond, const T& length, const Int32Key& key, Label* label); inline void branchTestNeedsIncrementalBarrier(Condition cond, Label* label); - inline void branchTestInt32(Condition cond, Register tag, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); - inline void branchTestInt32(Condition cond, const Address& address, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); - inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) - DEFINED_ON(arm, arm64, mips_shared, x86, x64); - inline void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) PER_ARCH; + // Perform a type-test on a tag of a Value (32bits boxing), or the tagged + // value (64bits boxing). + inline void branchTestUndefined(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestInt32(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestDouble(Condition cond, Register tag, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + inline void branchTestNumber(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestBoolean(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestString(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestSymbol(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestNull(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestObject(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestPrimitive(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + inline void branchTestMagic(Condition cond, Register tag, Label* label) PER_SHARED_ARCH; + + // Perform a type-test on a Value, addressed by Address or BaseIndex, or + // loaded into ValueOperand. + // BaseIndex and ValueOperand variants clobber the ScratchReg on x64. + // All Variants clobber the ScratchReg on arm64. + inline void branchTestUndefined(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestUndefined(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestUndefined(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestInt32(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestInt32(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestDouble(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestDouble(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestDouble(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestNumber(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestBoolean(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestString(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestString(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestSymbol(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestSymbol(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestNull(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestNull(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestNull(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + // Clobbers the ScratchReg on x64. + inline void branchTestObject(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestObject(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + inline void branchTestObject(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestGCThing(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestGCThing(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; - inline void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) + inline void branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestMagic(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH; + inline void branchTestMagic(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH; + template <class L> + inline void branchTestMagic(Condition cond, const ValueOperand& value, L label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + + inline void branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why, + Label* label); + + void branchTestValue(Condition cond, const ValueOperand& lhs, + const Value& rhs, Label* label) PER_ARCH; + + // Checks if given Value is evaluated to true or false in a condition. + // The type of the value should match the type of the method. + inline void branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) PER_SHARED_ARCH; + inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH; + inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label) DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + private: + + // Implementation for branch* methods. + template <typename T, typename S> + inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Label* label) + DEFINED_ON(x86_shared); + + template <typename T> + inline void branchTestUndefinedImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestInt32Impl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestDoubleImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestNumberImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestBooleanImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestStringImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestSymbolImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestNullImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestObjectImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestGCThingImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T> + inline void branchTestPrimitiveImpl(Condition cond, const T& t, Label* label) + DEFINED_ON(arm, arm64, x86_shared); + template <typename T, class L> + inline void branchTestMagicImpl(Condition cond, const T& t, L label) + DEFINED_ON(arm, arm64, x86_shared); + //}}} check_macroassembler_style public: // Emits a test of a value against all types in a TypeSet. A scratch // register is required. template <typename Source> void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -795,16 +795,48 @@ MacroAssembler::branchTest64(Condition c ma_orr(lhs.low, lhs.high, ScratchRegister); branchTestPtr(cond, ScratchRegister, ScratchRegister, label); } else { MOZ_CRASH("Unsupported condition"); } } void +MacroAssembler::branchTestUndefined(Condition cond, Register tag, Label* label) +{ + branchTestUndefinedImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestUndefined(Condition cond, const Address& address, Label* label) +{ + branchTestUndefinedImpl(cond, address, label); +} + +void +MacroAssembler::branchTestUndefined(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestUndefinedImpl(cond, address, label); +} + +void +MacroAssembler::branchTestUndefined(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestUndefinedImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestUndefinedImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testUndefined(cond, t); + ma_b(label, c); +} + +void MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) { branchTestInt32Impl(cond, tag, label); } void MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) { @@ -813,28 +845,330 @@ MacroAssembler::branchTestInt32(Conditio void MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) { branchTestInt32Impl(cond, address, label); } void -MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label) +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestInt32Impl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestInt32Impl(Condition cond, const T& t, Label* label) +{ + Condition c = testInt32(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label) +{ + Condition c = testInt32Truthy(truthy, value); + ma_b(label, c); +} + +void +MacroAssembler::branchTestDouble(Condition cond, Register tag, Label* label) +{ + branchTestDoubleImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestDouble(Condition cond, const Address& address, Label* label) +{ + branchTestDoubleImpl(cond, address, label); +} + +void +MacroAssembler::branchTestDouble(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestDoubleImpl(cond, address, label); +} + +void +MacroAssembler::branchTestDouble(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestDoubleImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestDoubleImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testDouble(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) +{ + Condition c = testDoubleTruthy(truthy, reg); + ma_b(label, c); +} + +void +MacroAssembler::branchTestNumber(Condition cond, Register tag, Label* label) +{ + branchTestNumberImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestNumber(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestNumberImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestNumberImpl(Condition cond, const T& t, Label* label) { - branchTestInt32Impl(cond, src, label); + cond = testNumber(cond, t); + ma_b(label, cond); +} + +void +MacroAssembler::branchTestBoolean(Condition cond, Register tag, Label* label) +{ + branchTestBooleanImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestBoolean(Condition cond, const Address& address, Label* label) +{ + branchTestBooleanImpl(cond, address, label); +} + +void +MacroAssembler::branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestBooleanImpl(cond, address, label); +} + +void +MacroAssembler::branchTestBoolean(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestBooleanImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestBooleanImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testBoolean(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) +{ + Condition c = testBooleanTruthy(truthy, value); + ma_b(label, c); +} + +void +MacroAssembler::branchTestString(Condition cond, Register tag, Label* label) +{ + branchTestStringImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestString(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestStringImpl(cond, address, label); +} + +void +MacroAssembler::branchTestString(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestStringImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestStringImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testString(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label) +{ + Condition c = testStringTruthy(truthy, value); + ma_b(label, c); } void -MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) +MacroAssembler::branchTestSymbol(Condition cond, Register tag, Label* label) +{ + branchTestSymbolImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestSymbol(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestSymbolImpl(cond, address, label); +} + +void +MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestSymbolImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestSymbolImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testSymbol(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestNull(Condition cond, Register tag, Label* label) +{ + branchTestNullImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestNull(Condition cond, const Address& address, Label* label) +{ + branchTestNullImpl(cond, address, label); +} + +void +MacroAssembler::branchTestNull(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestNullImpl(cond, address, label); +} + +void +MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestNullImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestNullImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testNull(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestObject(Condition cond, Register tag, Label* label) +{ + branchTestObjectImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestObject(Condition cond, const Address& address, Label* label) +{ + branchTestObjectImpl(cond, address, label); +} + +void +MacroAssembler::branchTestObject(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestObjectImpl(cond, address, label); +} + +void +MacroAssembler::branchTestObject(Condition cond, const ValueOperand& value, Label* label) { - Condition c = testInt32Truthy(truthy, operand); + branchTestObjectImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestObjectImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testObject(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestGCThing(Condition cond, const Address& address, Label* label) +{ + branchTestGCThingImpl(cond, address, label); +} + +void +MacroAssembler::branchTestGCThing(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestGCThingImpl(cond, address, label); +} + +template <typename T> +void +MacroAssembler::branchTestGCThingImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testGCThing(cond, t); ma_b(label, c); } +void +MacroAssembler::branchTestPrimitive(Condition cond, Register tag, Label* label) +{ + branchTestPrimitiveImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label) +{ + branchTestPrimitiveImpl(cond, value, label); +} + +template <typename T> +void +MacroAssembler::branchTestPrimitiveImpl(Condition cond, const T& t, Label* label) +{ + Condition c = testPrimitive(cond, t); + ma_b(label, c); +} + +void +MacroAssembler::branchTestMagic(Condition cond, Register tag, Label* label) +{ + branchTestMagicImpl(cond, tag, label); +} + +void +MacroAssembler::branchTestMagic(Condition cond, const Address& address, Label* label) +{ + branchTestMagicImpl(cond, address, label); +} + +void +MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestMagicImpl(cond, address, label); +} + +template <class L> +void +MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value, L label) +{ + branchTestMagicImpl(cond, value, label); +} + +template <typename T, class L> +void +MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label) +{ + cond = testMagic(cond, t); + ma_b(label, cond); +} + //}}} check_macroassembler_style // =============================================================== void MacroAssemblerARMCompat::incrementInt32Value(const Address& addr) { asMasm().add32(Imm32(1), ToPayload(addr)); }
--- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2848,63 +2848,16 @@ MacroAssemblerARMCompat::testGCThing(Con { MOZ_ASSERT(cond == Equal || cond == NotEqual); ScratchRegisterScope scratch(asMasm()); extractTag(address, scratch); ma_cmp(scratch, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); return cond == Equal ? AboveOrEqual : Below; } -void