author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Tue, 11 Oct 2016 12:01:35 +0200 | |
changeset 317401 | 7ae377917236 |
parent 317379 | 8f4c28b59a8c (current diff) |
parent 317400 | 3b920f1c673a (diff) |
child 317438 | 51dc2ac80cf1 |
child 317502 | 8654fba1417d |
child 317511 | 6e861a1843cb |
push id | 30804 |
push user | cbook@mozilla.com |
push date | Tue, 11 Oct 2016 10:01:46 +0000 |
treeherder | mozilla-central@7ae377917236 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/newtab/dragDataHelper.js +++ b/browser/base/content/newtab/dragDataHelper.js @@ -6,17 +6,17 @@ var gDragDataHelper = { get mimeType() { return "text/x-moz-url"; }, getLinkFromDragEvent: function DragDataHelper_getLinkFromDragEvent(aEvent) { let dt = aEvent.dataTransfer; - if (!dt || !dt.types.contains(this.mimeType)) { + if (!dt || !dt.types.includes(this.mimeType)) { return null; } let data = dt.getData(this.mimeType) || ""; let [url, title] = data.split(/[\r\n]+/); return {url: url, title: title}; } };
--- a/browser/base/content/test/general/browser_clipboard_pastefile.js +++ b/browser/base/content/test/general/browser_clipboard_pastefile.js @@ -39,17 +39,17 @@ add_task(function*() { searchbar.focus(); yield new Promise((resolve, reject) => { searchbar.addEventListener("paste", function copyEvent(event) { searchbar.removeEventListener("paste", copyEvent, true); let dt = event.clipboardData; is(dt.types.length, 3, "number of types"); - ok(dt.types.contains("text/plain"), "text/plain exists in types"); + ok(dt.types.includes("text/plain"), "text/plain exists in types"); ok(dt.mozTypesAt(0).contains("text/plain"), "text/plain exists in mozTypesAt"); is(dt.getData("text/plain"), "Alternate", "text/plain returned in getData"); is(dt.mozGetDataAt("text/plain", 0), "Alternate", "text/plain returned in mozGetDataAt"); resolve(); }, true); EventUtils.synthesizeKey("v", { accelKey: true });
--- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -651,20 +651,20 @@ file, You can obtain one at http://mozil this.inputField.removeAttribute("tooltiptext"); ]]></body> </method> <method name="onDragOver"> <parameter name="aEvent"/> <body> var types = aEvent.dataTransfer.types; - if (types.contains("application/x-moz-file") || - types.contains("text/x-moz-url") || - types.contains("text/uri-list") || - types.contains("text/unicode")) + if (types.includes("application/x-moz-file") || + types.includes("text/x-moz-url") || + types.includes("text/uri-list") || + types.includes("text/unicode")) aEvent.preventDefault(); </body> </method> <method name="onDrop"> <parameter name="aEvent"/> <body><![CDATA[ let links = browserDragAndDrop.dropLinks(aEvent);
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js +++ b/browser/components/downloads/content/allDownloadsViewOverlay.js @@ -1386,19 +1386,19 @@ DownloadsPlacesView.prototype = { dt.setData("text/uri-list", url); dt.setData("text/plain", url); dt.effectAllowed = "copyMove"; dt.addElement(selectedItem); }, onDragOver(aEvent) { let types = aEvent.dataTransfer.types; - if (types.contains("text/uri-list") || - types.contains("text/x-moz-url") || - types.contains("text/plain")) { + if (types.includes("text/uri-list") || + types.includes("text/x-moz-url") || + types.includes("text/plain")) { aEvent.preventDefault(); } }, onDrop(aEvent) { let dt = aEvent.dataTransfer; // If dragged item is from our source, do not try to // redownload already downloaded file.
--- a/browser/components/originattributes/test/browser/test.html +++ b/browser/components/originattributes/test/browser/test.html @@ -7,19 +7,14 @@ <script> window.onmessage = function (evt) { if (evt.data != "HI") { return; } window.parent.postMessage("OK", "http://mochi.test:8888"); }; - - setTimeout(function() { - window.parent.postMessage("KO", "http://mochi.test:8888"); - }, 1000); - </script> </head> <body> Hello World. </body> </html>
--- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -851,17 +851,17 @@ <handler event="keypress" keycode="VK_UP" modifiers="alt" phase="capturing" action="return this.openSearch();"/> <handler event="dragover"> <![CDATA[ var types = event.dataTransfer.types; - if (types.contains("text/plain") || types.contains("text/x-moz-text-internal")) + if (types.includes("text/plain") || types.includes("text/x-moz-text-internal")) event.preventDefault(); ]]> </handler> <handler event="drop"> <![CDATA[ var dataTransfer = event.dataTransfer; var data = dataTransfer.getData("text/plain");
--- a/dom/base/Location.h +++ b/dom/base/Location.h @@ -39,184 +39,183 @@ public: void SetDocShell(nsIDocShell *aDocShell); nsIDocShell *GetDocShell(); // nsIDOMLocation NS_DECL_NSIDOMLOCATION #define THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME() { \ - MOZ_ASSERT(aSubjectPrincipal.isSome()); \ - if (!CallerSubsumes(aSubjectPrincipal.value())) { \ + if (!CallerSubsumes(&aSubjectPrincipal)) { \ aError.Throw(NS_ERROR_DOM_SECURITY_ERR); \ return; \ } \ } // WebIDL API: void Assign(const nsAString& aUrl, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Assign(aUrl); } void Replace(const nsAString& aUrl, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { aError = Replace(aUrl); } void Reload(bool aForceget, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Reload(aForceget); } void GetHref(nsAString& aHref, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHref(aHref); } void SetHref(const nsAString& aHref, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { aError = SetHref(aHref); } void GetOrigin(nsAString& aOrigin, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetOrigin(aOrigin); } void GetProtocol(nsAString& aProtocol, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetProtocol(aProtocol); } void SetProtocol(const nsAString& aProtocol, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetProtocol(aProtocol); } void GetHost(nsAString& aHost, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHost(aHost); } void SetHost(const nsAString& aHost, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHost(aHost); } void GetHostname(nsAString& aHostname, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHostname(aHostname); } void SetHostname(const nsAString& aHostname, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHostname(aHostname); } void GetPort(nsAString& aPort, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPort(aPort); } void SetPort(const nsAString& aPort, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPort(aPort); } void GetPathname(nsAString& aPathname, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPathname(aPathname); } void SetPathname(const nsAString& aPathname, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPathname(aPathname); } void GetSearch(nsAString& aSeach, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetSearch(aSeach); } void SetSearch(const nsAString& aSeach, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetSearch(aSeach); } void GetHash(nsAString& aHash, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHash(aHash); } void SetHash(const nsAString& aHash, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHash(aHash); } void Stringify(nsAString& aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { // GetHref checks CallerSubsumes. GetHref(aRetval, aSubjectPrincipal, aError); } nsPIDOMWindowInner* GetParentObject() const {
--- a/dom/base/contentAreaDropListener.js +++ b/dom/base/contentAreaDropListener.js @@ -133,21 +133,21 @@ ContentAreaDropListener.prototype = canDropLink: function(aEvent, aAllowSameDocument) { if (this._eventTargetIsDisabled(aEvent)) return false; let dataTransfer = aEvent.dataTransfer; let types = dataTransfer.types; - if (!types.contains("application/x-moz-file") && - !types.contains("text/x-moz-url") && - !types.contains("text/uri-list") && - !types.contains("text/x-moz-text-internal") && - !types.contains("text/plain")) + if (!types.includes("application/x-moz-file") && + !types.includes("text/x-moz-url") && + !types.includes("text/uri-list") && + !types.includes("text/x-moz-text-internal") && + !types.includes("text/plain")) return false; if (aAllowSameDocument) return true; let sourceNode = dataTransfer.mozSourceNode; if (!sourceNode) return true;
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -6238,16 +6238,24 @@ nsDocument::LoadBindingDocument(const ns ? Some(nsContentUtils::SubjectPrincipal()) : Nothing(), rv); return rv.StealNSResult(); } void nsIDocument::LoadBindingDocument(const nsAString& aURI, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& rv) +{ + LoadBindingDocument(aURI, Some(&aSubjectPrincipal), rv); +} + +void +nsIDocument::LoadBindingDocument(const nsAString& aURI, const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& rv) { nsCOMPtr<nsIURI> uri; rv = NS_NewURI(getter_AddRefs(uri), aURI, mCharacterSet.get(), GetDocBaseURI()); if (rv.Failed()) {
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -6812,23 +6812,22 @@ nsGlobalWindow::CanMoveResizeWindows(boo } } return true; } bool nsGlobalWindow::AlertOrConfirm(bool aAlert, const nsAString& aMessage, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { // XXX This method is very similar to nsGlobalWindow::Prompt, make // sure any modifications here don't need to happen over there! MOZ_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); if (!AreDialogsEnabled()) { // Just silently return. In the case of alert(), the return value is // ignored. In the case of confirm(), returning false is the same thing as // would happen if the user cancels. return false; } @@ -6837,17 +6836,17 @@ nsGlobalWindow::AlertOrConfirm(bool aAle // the whole time a modal dialog is open. nsAutoPopupStatePusher popupStatePusher(openAbused, true); // Before bringing up the window, unsuppress painting and flush // pending reflows. EnsureReflowFlushAndPaint(); nsAutoString title; - MakeScriptDialogTitle(title, aSubjectPrincipal.value()); + MakeScriptDialogTitle(title, &aSubjectPrincipal); // Remove non-terminating null characters from the // string. See bug #310037. nsAutoString final; nsContentUtils::StripNullChars(aMessage, final); nsresult rv; nsCOMPtr<nsIPromptFactory> promptFac = @@ -6890,55 +6889,55 @@ nsGlobalWindow::AlertOrConfirm(bool aAle prompt->Alert(title.get(), final.get()) : prompt->Confirm(title.get(), final.get(), &result); } return result; } void -nsGlobalWindow::Alert(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +nsGlobalWindow::Alert(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_ASSERT(IsInnerWindow()); Alert(EmptyString(), aSubjectPrincipal, aError); } void nsGlobalWindow::AlertOuter(const nsAString& aMessage, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError); } void nsGlobalWindow::Alert(const nsAString& aMessage, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(AlertOuter, (aMessage, aSubjectPrincipal, aError), aError, ); } bool nsGlobalWindow::ConfirmOuter(const nsAString& aMessage, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal, aError); } bool nsGlobalWindow::Confirm(const nsAString& aMessage, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(ConfirmOuter, (aMessage, aSubjectPrincipal, aError), aError, false); } already_AddRefed<Promise> nsGlobalWindow::Fetch(const RequestOrUSVString& aInput, @@ -6946,23 +6945,22 @@ nsGlobalWindow::Fetch(const RequestOrUSV { return FetchRequest(this, aInput, aInit, aRv); } void nsGlobalWindow::PromptOuter(const nsAString& aMessage, const nsAString& aInitial, nsAString& aReturn, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make // sure any modifications here don't need to happen over there! MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); SetDOMStringToNull(aReturn); if (!AreDialogsEnabled()) { // Return null, as if the user just canceled the prompt. return; } @@ -6971,17 +6969,17 @@ nsGlobalWindow::PromptOuter(const nsAStr // the whole time a modal dialog is open. nsAutoPopupStatePusher popupStatePusher(openAbused, true); // Before bringing up the window, unsuppress painting and flush // pending reflows. EnsureReflowFlushAndPaint(); nsAutoString title; - MakeScriptDialogTitle(title, aSubjectPrincipal.value()); + MakeScriptDialogTitle(title, &aSubjectPrincipal); // Remove non-terminating null characters from the // string. See bug #310037. nsAutoString fixedMessage, fixedInitial; nsContentUtils::StripNullChars(aMessage, fixedMessage); nsContentUtils::StripNullChars(aInitial, fixedInitial); nsresult rv; @@ -7032,17 +7030,17 @@ nsGlobalWindow::PromptOuter(const nsAStr if (ok && outValue) { aReturn.Assign(outValue); } } void nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial, nsAString& aReturn, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(PromptOuter, (aMessage, aInitial, aReturn, aSubjectPrincipal, aError), aError, ); } @@ -8278,21 +8276,20 @@ nsGlobalWindow::CallerInnerWindow() nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global); return nsGlobalWindow::Cast(win); } void nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, JS::Handle<JS::Value> aTransfer, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); // // Window.postMessage is an intentional subversion of the same-origin policy. // As such, this code must be particularly careful in the information it // exposes to calling code. // // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html // @@ -8365,17 +8362,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo } if (NS_FAILED(originURI->SetUserPass(EmptyCString())) || NS_FAILED(originURI->SetPath(EmptyCString()))) { return; } PrincipalOriginAttributes attrs = - BasePrincipal::Cast(aSubjectPrincipal.value())->OriginAttributesRef(); + BasePrincipal::Cast(&aSubjectPrincipal)->OriginAttributesRef(); // Create a nsIPrincipal inheriting the app/browser attributes from the // caller. providedPrincipal = BasePrincipal::CreateCodebasePrincipal(originURI, attrs); if (NS_WARN_IF(!providedPrincipal)) { return; } } @@ -8403,30 +8400,30 @@ nsGlobalWindow::PostMessageMozOuter(JSCo aError = NS_DispatchToCurrentThread(event); } void nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, JS::Handle<JS::Value> aTransfer, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(PostMessageMozOuter, (aCx, aMessage, aTargetOrigin, aTransfer, aSubjectPrincipal, aError), aError, ); } void nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, const Optional<Sequence<JS::Value>>& aTransfer, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); if (aTransfer.WasPassed()) { const Sequence<JS::Value >& values = aTransfer.Value(); // The input sequence only comes from the generated bindings code, which // ensures it is rooted. @@ -9044,41 +9041,39 @@ nsGlobalWindow::CacheXBLPrototypeHandler mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>(); PreserveWrapper(ToSupports(this)); } mCachedXBLPrototypeHandlers->Put(aKey, aHandler); } Element* -nsGlobalWindow::GetFrameElementOuter(const Maybe<nsIPrincipal*>& aSubjectPrincipal) +nsGlobalWindow::GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); if (!mDocShell || mDocShell->GetIsMozBrowserOrApp()) { return nullptr; } // Per HTML5, the frameElement getter returns null in cross-origin situations. Element* element = GetRealFrameElementOuter(); if (!element) { return nullptr; } - if (!aSubjectPrincipal.value()-> - SubsumesConsideringDomain(element->NodePrincipal())) { + if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) { return nullptr; } return element; } Element* -nsGlobalWindow::GetFrameElement(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +nsGlobalWindow::GetFrameElement(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetFrameElementOuter, (aSubjectPrincipal), aError, nullptr); } Element* nsGlobalWindow::GetRealFrameElementOuter() @@ -9247,33 +9242,32 @@ nsGlobalWindow::ConvertDialogOptions(con } } } already_AddRefed<nsIVariant> nsGlobalWindow::ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgument, const nsAString& aOptions, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); if (mDoc) { mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog); } if (!IsShowModalDialogEnabled()) { aError.Throw(NS_ERROR_NOT_AVAILABLE); return nullptr; } RefPtr<DialogValueHolder> argHolder = - new DialogValueHolder(aSubjectPrincipal.value(), aArgument); + new DialogValueHolder(&aSubjectPrincipal, aArgument); // Before bringing up the window/dialog, unsuppress painting and flush // pending reflows. EnsureReflowFlushAndPaint(); if (!AreDialogsEnabled()) { // We probably want to keep throwing here; silently doing nothing is a bit // weird given the typical use cases of showModalDialog(). @@ -9320,30 +9314,30 @@ nsGlobalWindow::ShowModalDialogOuter(con MOZ_ASSERT(!aError.Failed()); return retVal.forget(); } already_AddRefed<nsIVariant> nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument, const nsAString& aOptions, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(ShowModalDialogOuter, (aUrl, aArgument, aOptions, aSubjectPrincipal, aError), aError, nullptr); } void nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl, JS::Handle<JS::Value> aArgument, const nsAString& aOptions, JS::MutableHandle<JS::Value> aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_ASSERT(IsInnerWindow()); nsCOMPtr<nsIVariant> args; aError = nsContentUtils::XPConnect()->JSToVariant(aCx, aArgument, getter_AddRefs(args)); @@ -10582,27 +10576,27 @@ nsGlobalWindow::GetSessionStorage(ErrorR if (MOZ_LOG_TEST(gDOMLeakPRLog, LogLevel::Debug)) { PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get()); } return mSessionStorage; } DOMStorage* -nsGlobalWindow::GetLocalStorage(const Maybe<nsIPrincipal*>& aSubjectPrincipal, - ErrorResult& aError) +nsGlobalWindow::GetLocalStorage(ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsInnerWindow()); if (!Preferences::GetBool(kStorageEnabled)) { return nullptr; } if (!mLocalStorage) { - if (!DOMStorage::CanUseStorage(AsInner(), aSubjectPrincipal)) { + if (nsContentUtils::StorageAllowedForWindow(AsInner()) == + nsContentUtils::StorageAccess::eDeny) { aError.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } nsIPrincipal *principal = GetPrincipal(); if (!principal) { return nullptr; } @@ -11658,20 +11652,17 @@ nsGlobalWindow::CloneStorageEvent(const aEvent->GetNewValue(dict.mNewValue); aEvent->GetUrl(dict.mUrl); RefPtr<DOMStorage> storageArea = aEvent->GetStorageArea(); MOZ_ASSERT(storageArea); RefPtr<DOMStorage> storage; if (storageArea->GetType() == DOMStorage::LocalStorage) { - storage = GetLocalStorage(nsContentUtils::GetCurrentJSContext() - ? Some(nsContentUtils::SubjectPrincipal()) - : Nothing(), - aRv); + storage = GetLocalStorage(aRv); } else { MOZ_ASSERT(storageArea->GetType() == DOMStorage::SessionStorage); storage = GetSessionStorage(aRv); } if (aRv.Failed() || !storage) { return nullptr; } @@ -13996,42 +13987,40 @@ NS_INTERFACE_MAP_END_INHERITING(nsGlobal NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow) NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow) void nsGlobalWindow::GetDialogArgumentsOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); MOZ_ASSERT(IsModalContentWindow(), "This should only be called on modal windows!"); if (!mDialogArguments) { MOZ_ASSERT(mIsClosed, "This window should be closed!"); aRetval.setUndefined(); return; } // This does an internal origin check, and returns undefined if the subject // does not subsumes the origin of the arguments. JS::Rooted<JSObject*> wrapper(aCx, GetWrapper()); JSAutoCompartment ac(aCx, wrapper); - mDialogArguments->Get(aCx, wrapper, aSubjectPrincipal.value(), - aRetval, aError); + mDialogArguments->Get(aCx, wrapper, &aSubjectPrincipal, aRetval, aError); } void nsGlobalWindow::GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetDialogArgumentsOuter, (aCx, aRetval, aSubjectPrincipal, aError), aError, ); } /* static */ already_AddRefed<nsGlobalModalWindow> @@ -14065,38 +14054,36 @@ void nsGlobalWindow::InitWasOffline() { mWasOffline = NS_IsOffline() || NS_IsAppOffline(GetPrincipal()); } void nsGlobalWindow::GetReturnValueOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); MOZ_ASSERT(IsModalContentWindow(), "This should only be called on modal windows!"); if (mReturnValue) { JS::Rooted<JSObject*> wrapper(aCx, GetWrapper()); JSAutoCompartment ac(aCx, wrapper); - mReturnValue->Get(aCx, wrapper, aSubjectPrincipal.value(), - aReturnValue, aError); + mReturnValue->Get(aCx, wrapper, &aSubjectPrincipal, aReturnValue, aError); } else { aReturnValue.setUndefined(); } } void nsGlobalWindow::GetReturnValue(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetReturnValueOuter, (aCx, aReturnValue, aSubjectPrincipal, aError), aError, ); } NS_IMETHODIMP @@ -14110,38 +14097,36 @@ nsGlobalModalWindow::GetReturnValue(nsIV return NS_OK; } return mReturnValue->Get(nsContentUtils::SubjectPrincipal(), aRetVal); } void nsGlobalWindow::SetReturnValueOuter(JSContext* aCx, JS::Handle<JS::Value> aReturnValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(aSubjectPrincipal.isSome()); MOZ_ASSERT(IsModalContentWindow(), "This should only be called on modal windows!"); nsCOMPtr<nsIVariant> returnValue; aError = nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue, getter_AddRefs(returnValue)); if (!aError.Failed()) { - mReturnValue = new DialogValueHolder(aSubjectPrincipal.value(), - returnValue); + mReturnValue = new DialogValueHolder(&aSubjectPrincipal, returnValue); } } void nsGlobalWindow::SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(SetReturnValueOuter, (aCx, aReturnValue, aSubjectPrincipal, aError), aError, ); } NS_IMETHODIMP
--- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -932,19 +932,19 @@ public: void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener, mozilla::ErrorResult& aError); already_AddRefed<nsPIDOMWindowOuter> GetParentOuter(); already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError); already_AddRefed<nsPIDOMWindowOuter> GetParent() override; nsPIDOMWindowOuter* GetScriptableParent() override; nsPIDOMWindowOuter* GetScriptableParentOrNull() override; mozilla::dom::Element* - GetFrameElementOuter(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal); + GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal); mozilla::dom::Element* - GetFrameElement(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + GetFrameElement(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); already_AddRefed<nsIDOMElement> GetFrameElement() override; already_AddRefed<nsPIDOMWindowOuter> OpenOuter(const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, mozilla::ErrorResult& aError); already_AddRefed<nsPIDOMWindowOuter> @@ -977,58 +977,58 @@ public: static bool TokenizeDialogOptions(nsAString& aToken, nsAString::const_iterator& aIter, nsAString::const_iterator aEnd); static void ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult); protected: bool AlertOrConfirm(bool aAlert, const nsAString& aMessage, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); public: - void Alert(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + void Alert(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void AlertOuter(const nsAString& aMessage, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void Alert(const nsAString& aMessage, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); bool ConfirmOuter(const nsAString& aMessage, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); bool Confirm(const nsAString& aMessage, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void PromptOuter(const nsAString& aMessage, const nsAString& aInitial, nsAString& aReturn, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void Prompt(const nsAString& aMessage, const nsAString& aInitial, nsAString& aReturn, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); already_AddRefed<mozilla::dom::cache::CacheStorage> GetCaches(mozilla::ErrorResult& aRv); already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrUSVString& aInput, const mozilla::dom::RequestInit& aInit, mozilla::ErrorResult& aRv); void PrintOuter(mozilla::ErrorResult& aError); void Print(mozilla::ErrorResult& aError); void ShowModalDialog(JSContext* aCx, const nsAString& aUrl, JS::Handle<JS::Value> aArgument, const nsAString& aOptions, JS::MutableHandle<JS::Value> aRetval, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction, int32_t aTimeout, const mozilla::dom::Sequence<JS::Value>& aArguments, mozilla::ErrorResult& aError); int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler, int32_t aTimeout, const mozilla::dom::Sequence<JS::Value>& /* unused */, @@ -1044,18 +1044,17 @@ public: mozilla::ErrorResult& aError); void ClearInterval(int32_t aHandle); void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData, mozilla::ErrorResult& aError); void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String, mozilla::ErrorResult& aError); mozilla::dom::DOMStorage* GetSessionStorage(mozilla::ErrorResult& aError); mozilla::dom::DOMStorage* - GetLocalStorage(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, - mozilla::ErrorResult& aError); + GetLocalStorage(mozilla::ErrorResult& aError); mozilla::dom::Selection* GetSelectionOuter(); mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError); already_AddRefed<nsISelection> GetSelection() override; mozilla::dom::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError); already_AddRefed<nsICSSDeclaration> GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt, mozilla::ErrorResult& aError) override; already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(const nsAString& aQuery); @@ -1265,32 +1264,32 @@ public: nsIMessageBroadcaster* GetMessageManager(mozilla::ErrorResult& aError); nsIMessageBroadcaster* GetGroupMessageManager(const nsAString& aGroup, mozilla::ErrorResult& aError); void BeginWindowMove(mozilla::dom::Event& aMouseDownEvent, mozilla::dom::Element* aPanel, mozilla::ErrorResult& aError); void GetDialogArgumentsOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void GetReturnValueOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void GetReturnValue(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void SetReturnValueOuter(JSContext* aCx, JS::Handle<JS::Value> aReturnValue, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void GetInterface(JSContext* aCx, nsIJSID* aIID, JS::MutableHandle<JS::Value> aRetval, mozilla::ErrorResult& aError); already_AddRefed<nsWindowRoot> GetWindowRootOuter(); already_AddRefed<nsWindowRoot> GetWindowRoot(mozilla::ErrorResult& aError); @@ -1703,34 +1702,34 @@ protected: // Returns CSS pixels based on primary screen. Outer windows only. mozilla::CSSIntPoint GetScreenXY(mozilla::ErrorResult& aError); nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError); void PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, JS::Handle<JS::Value> aTransfer, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, JS::Handle<JS::Value> aTransfer, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); already_AddRefed<nsIVariant> ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgument, const nsAString& aOptions, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); already_AddRefed<nsIVariant> ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument, const nsAString& aOptions, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); // Ask the user if further dialogs should be blocked, if dialogs are currently // being abused. This is used in the cases where we have no modifiable UI to // show, in that case we show a separate dialog to ask this question. bool ConfirmDialogIfNeeded(); // Helper called after moving/resizing, to update docShell's presContext
--- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2683,16 +2683,19 @@ public: // QuerySelector and QuerySelectorAll already defined on nsINode nsINodeList* GetAnonymousNodes(Element& aElement); Element* GetAnonymousElementByAttribute(Element& aElement, const nsAString& aAttrName, const nsAString& aAttrValue); Element* GetBindingParent(nsINode& aNode); void LoadBindingDocument(const nsAString& aURI, + nsIPrincipal& aSubjectPrincipal, + mozilla::ErrorResult& rv); + void LoadBindingDocument(const nsAString& aURI, const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, mozilla::ErrorResult& rv); mozilla::dom::XPathExpression* CreateExpression(const nsAString& aExpression, mozilla::dom::XPathNSResolver* aResolver, mozilla::ErrorResult& rv); nsINode* CreateNSResolver(nsINode& aNodeResolver); already_AddRefed<mozilla::dom::XPathResult>
--- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -3532,34 +3532,32 @@ nsObjectLoadingContent::ShouldPlay(Fallb return true; case nsIPluginTag::STATE_CLICKTOPLAY: return false; } MOZ_CRASH("Unexpected enabledState"); } nsIDocument* -nsObjectLoadingContent::GetContentDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) +nsObjectLoadingContent::GetContentDocument(nsIPrincipal& aSubjectPrincipal) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); if (!thisContent->IsInComposedDoc()) { return nullptr; } nsIDocument *sub_doc = thisContent->OwnerDoc()->GetSubDocumentFor(thisContent); if (!sub_doc) { return nullptr; } // Return null for cross-origin contentDocument. - if (!aSubjectPrincipal.value()->SubsumesConsideringDomain(sub_doc->NodePrincipal())) { + if (!aSubjectPrincipal.SubsumesConsideringDomain(sub_doc->NodePrincipal())) { return nullptr; } return sub_doc; } void nsObjectLoadingContent::LegacyCall(JSContext* aCx,
--- a/dom/base/nsObjectLoadingContent.h +++ b/dom/base/nsObjectLoadingContent.h @@ -175,17 +175,17 @@ class nsObjectLoadingContent : public ns // id. If in doubt, return true. static bool MayResolve(jsid aId); // Helper for WebIDL enumeration void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& /* unused */, mozilla::ErrorResult& aRv); // WebIDL API - nsIDocument* GetContentDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal); + nsIDocument* GetContentDocument(nsIPrincipal& aSubjectPrincipal); void GetActualType(nsAString& aType) const { CopyUTF8toUTF16(mContentType, aType); } uint32_t DisplayedType() const { return mType; }
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -6902,23 +6902,23 @@ class CGCallGenerator(CGThing): isFallible is a boolean indicating whether the call should be fallible. resultVar: If the returnType is not void, then the result of the call is stored in a C++ variable named by resultVar. The caller is responsible for declaring the result variable. If the caller doesn't care about the result value, resultVar can be omitted. """ def __init__(self, isFallible, needsSubjectPrincipal, arguments, argsPre, - returnType, extendedAttributes, descriptorProvider, + returnType, extendedAttributes, descriptor, nativeMethodName, static, object="self", argsPost=[], resultVar=None): CGThing.__init__(self) result, resultOutParam, resultRooter, resultArgs, resultConversion = \ - getRetvalDeclarationForType(returnType, descriptorProvider) + getRetvalDeclarationForType(returnType, descriptor) args = CGList([CGGeneric(arg) for arg in argsPre], ", ") for a, name in arguments: arg = CGGeneric(name) # Now constify the things that need it def needsConst(a): if a.type.isDictionary(): @@ -7003,26 +7003,42 @@ class CGCallGenerator(CGThing): elif result is not None: assert resultOutParam is None call = CGWrapper(call, pre=resultVar + " = ") call = CGWrapper(call, post=";\n") self.cgRoot.append(call) if needsSubjectPrincipal: - self.cgRoot.prepend(CGGeneric(dedent( - """ - Maybe<nsIPrincipal*> subjectPrincipal; - if (NS_IsMainThread()) { - JSCompartment* compartment = js::GetContextCompartment(cx); - MOZ_ASSERT(compartment); - JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment); - subjectPrincipal.emplace(nsJSPrincipals::get(principals)); - } - """))) + getPrincipal = dedent( + """ + JSCompartment* compartment = js::GetContextCompartment(cx); + MOZ_ASSERT(compartment); + JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment); + """) + + if descriptor.interface.isExposedInAnyWorker(): + self.cgRoot.prepend(CGGeneric(fill( + """ + Maybe<nsIPrincipal*> subjectPrincipal; + if (NS_IsMainThread()) { + $*{getPrincipal} + subjectPrincipal.emplace(nsJSPrincipals::get(principals)); + } + """, + getPrincipal=getPrincipal))) + else: + self.cgRoot.prepend(CGGeneric(fill( + """ + $*{getPrincipal} + // Initializing a nonnull is pretty darn annoying... + NonNull<nsIPrincipal> subjectPrincipal; + subjectPrincipal = static_cast<nsIPrincipal*>(nsJSPrincipals::get(principals)); + """, + getPrincipal=getPrincipal))) if isFallible: self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n")) self.cgRoot.append(CGGeneric(dedent( """ if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) { return false; } @@ -13988,17 +14004,17 @@ class CGNativeMember(ClassMethod): "aRetVal")) elif returnType.isAny(): args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal")) elif returnType.isObject() or returnType.isSpiderMonkeyInterface(): args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal")) # And the nsIPrincipal if self.member.getExtendedAttribute('NeedsSubjectPrincipal'): - args.append(Argument("const Maybe<nsIPrincipal*>&", "aPrincipal")) + args.append(Argument("nsIPrincipal&", "aPrincipal")) # And the ErrorResult if 'infallible' not in self.extendedAttrs: # Use aRv so it won't conflict with local vars named "rv" args.append(Argument("ErrorResult&", "aRv")) # The legacycaller thisval if self.member.isMethod() and self.member.isLegacycaller(): # If it has an identifier, we can't deal with it yet assert self.member.isIdentifierLess()
--- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -928,16 +928,19 @@ public: void SetJsonifierShouldSkipThis3(TestCallbackInterface&); void ThrowingMethod(ErrorResult& aRv); bool GetThrowingAttr(ErrorResult& aRv) const; void SetThrowingAttr(bool arg, ErrorResult& aRv); bool GetThrowingGetterAttr(ErrorResult& aRv) const; void SetThrowingGetterAttr(bool arg); bool ThrowingSetterAttr() const; void SetThrowingSetterAttr(bool arg, ErrorResult& aRv); + void NeedsSubjectPrincipalMethod(nsIPrincipal&); + bool NeedsSubjectPrincipalAttr(nsIPrincipal&); + void SetNeedsSubjectPrincipalAttr(bool, nsIPrincipal&); int16_t LegacyCall(const JS::Value&, uint32_t, TestInterface&); void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&, TestInterface*, const Dict&, double, const Optional<float>&); void SetDashed_attribute(int8_t); int8_t Dashed_attribute(); void Dashed_method();
--- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -938,16 +938,18 @@ interface TestInterface { void passRenamedInterface(TestRenamedInterface arg); [PutForwards=writableByte] readonly attribute TestInterface putForwardsAttr; [PutForwards=writableByte, LenientThis] readonly attribute TestInterface putForwardsAttr2; [PutForwards=writableByte, ChromeOnly] readonly attribute TestInterface putForwardsAttr3; [Throws] void throwingMethod(); [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; + [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); + [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, optional Dict arg3, optional double arg4 = 5.0, optional float arg5); attribute any jsonifierShouldSkipThis; attribute TestParentInterface jsonifierShouldSkipThis2;
--- a/dom/bindings/test/TestJSImplGen.webidl +++ b/dom/bindings/test/TestJSImplGen.webidl @@ -789,16 +789,20 @@ interface TestJSImplInterface { void passRenamedInterface(TestRenamedInterface arg); [PutForwards=writableByte] readonly attribute TestJSImplInterface putForwardsAttr; [PutForwards=writableByte, LenientThis] readonly attribute TestJSImplInterface putForwardsAttr2; [PutForwards=writableByte, ChromeOnly] readonly attribute TestJSImplInterface putForwardsAttr3; [Throws] void throwingMethod(); [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; + // NeedsSubjectPrincipal not supported on JS-implemented things for + // now, because we always pass in the caller principal anyway. + // [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); + // [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; // legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, optional Dict arg3, optional double arg4 = 5.0, optional float arg5); attribute any jsonifierShouldSkipThis; attribute TestParentInterface jsonifierShouldSkipThis2; attribute TestCallbackInterface jsonifierShouldSkipThis3;
--- a/dom/events/ClipboardEvent.cpp +++ b/dom/events/ClipboardEvent.cpp @@ -71,17 +71,17 @@ ClipboardEvent::Constructor(const Global if (e->mEventIsInternal) { InternalClipboardEvent* event = e->mEvent->AsClipboardEvent(); if (event) { // Always create a clipboardData for the copy event. If this is changed to // support other types of events, make sure that read/write privileges are // checked properly within DataTransfer. clipboardData = new DataTransfer(ToSupports(e), eCopy, false, -1); clipboardData->SetData(aParam.mDataType, aParam.mData, - Some(aGlobal.GetSubjectPrincipal()), aRv); + *aGlobal.GetSubjectPrincipal(), aRv); NS_ENSURE_TRUE(!aRv.Failed(), nullptr); } } e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable, clipboardData); e->SetTrusted(trusted); e->SetComposed(aParam.mComposed);
--- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -279,21 +279,20 @@ DataTransfer::SetEffectAllowedInt(uint32 NS_IMETHODIMP DataTransfer::GetMozUserCancelled(bool* aUserCancelled) { *aUserCancelled = MozUserCancelled(); return NS_OK; } already_AddRefed<FileList> -DataTransfer::GetFiles(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DataTransfer::GetFiles(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - return mItems->Files(aSubjectPrincipal.value()); + return mItems->Files(&aSubjectPrincipal); } NS_IMETHODIMP DataTransfer::GetFiles(nsIDOMFileList** aFileList) { if (!aFileList) { return NS_ERROR_FAILURE; } @@ -305,93 +304,68 @@ DataTransfer::GetFiles(nsIDOMFileList** // This code is also called from C++ code, which expects it to have a System // Principal, and thus the SubjectPrincipal cannot be used. RefPtr<FileList> files = mItems->Files(nsContentUtils::GetSystemPrincipal()); files.forget(aFileList); return NS_OK; } -already_AddRefed<DOMStringList> -DataTransfer::GetTypes(ErrorResult& aRv) const +void +DataTransfer::GetTypes(nsTArray<nsString>& aTypes, + nsIPrincipal& aSubjectPrincipal) const { - RefPtr<DOMStringList> types = new DOMStringList(); - + // When called from bindings, aTypes will be empty, but since we might have + // Gecko-internal callers too, clear it to be safe. + aTypes.Clear(); + const nsTArray<RefPtr<DataTransferItem>>* items = mItems->MozItemsAt(0); if (NS_WARN_IF(!items)) { - return types.forget(); + return; } for (uint32_t i = 0; i < items->Length(); i++) { DataTransferItem* item = items->ElementAt(i); MOZ_ASSERT(item); - if (item->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { + if (item->ChromeOnly() && !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) { continue; } nsAutoString type; item->GetType(type); if (item->Kind() == DataTransferItem::KIND_STRING || type.EqualsASCII(kFileMime)) { // If the entry has kind KIND_STRING, we want to add it to the list. - if (NS_WARN_IF(!types->Add(type))) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } + aTypes.AppendElement(type); } } for (uint32_t i = 0; i < mItems->Length(); ++i) { - ErrorResult rv; bool found = false; - DataTransferItem* item = mItems->IndexedGetter(i, found, rv); - if (!found || rv.Failed() || item->Kind() != DataTransferItem::KIND_FILE) { - rv.SuppressException(); + DataTransferItem* item = mItems->IndexedGetter(i, found); + MOZ_ASSERT(found); + if (item->Kind() != DataTransferItem::KIND_FILE) { continue; } - if (NS_WARN_IF(!types->Add(NS_LITERAL_STRING("Files")))) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } + aTypes.AppendElement(NS_LITERAL_STRING("Files")); break; } - - return types.forget(); -} - -NS_IMETHODIMP -DataTransfer::GetTypes(nsISupports** aTypes) -{ - if (NS_WARN_IF(!aTypes)) { - return NS_ERROR_FAILURE; - } - - ErrorResult rv; - RefPtr<DOMStringList> types = GetTypes(rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - types.forget(aTypes); - return NS_OK; } void DataTransfer::GetData(const nsAString& aFormat, nsAString& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - // return an empty string if data for the format was not found aData.Truncate(); nsCOMPtr<nsIVariant> data; nsresult rv = - GetDataAtInternal(aFormat, 0, aSubjectPrincipal.value(), + GetDataAtInternal(aFormat, 0, &aSubjectPrincipal, getter_AddRefs(data)); if (NS_FAILED(rv)) { if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) { aRv.Throw(rv); } return; } @@ -429,44 +403,32 @@ DataTransfer::GetData(const nsAString& a } } else { aData = stringdata; } } } -NS_IMETHODIMP -DataTransfer::GetData(const nsAString& aFormat, nsAString& aData) -{ - ErrorResult rv; - GetData(aFormat, aData, Some(nsContentUtils::SubjectPrincipal()), rv); - return rv.StealNSResult(); -} - void DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - RefPtr<nsVariantCC> variant = new nsVariantCC(); variant->SetAsAString(aData); - aRv = SetDataAtInternal(aFormat, variant, 0, aSubjectPrincipal.value()); + aRv = SetDataAtInternal(aFormat, variant, 0, &aSubjectPrincipal); } void DataTransfer::ClearData(const Optional<nsAString>& aFormat, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } if (MozItemCount() == 0) { return; } @@ -643,23 +605,21 @@ DataTransfer::GetDataAtInternal(const ns data.forget(aData); return NS_OK; } void DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat, uint32_t aIndex, JS::MutableHandle<JS::Value> aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - nsCOMPtr<nsIVariant> data; - aRv = GetDataAtInternal(aFormat, aIndex, aSubjectPrincipal.value(), + aRv = GetDataAtInternal(aFormat, aIndex, &aSubjectPrincipal, getter_AddRefs(data)); if (aRv.Failed()) { return; } if (!data) { aRetval.setNull(); return; @@ -688,16 +648,22 @@ DataTransfer::PrincipalMaySetData(const aType.EqualsASCII(kFilePromiseMime)) { NS_WARNING("Disallowing adding x-moz-file or x-moz-file-promize types to DataTransfer"); return false; } } return true; } +void +DataTransfer::TypesListMayHaveChanged() +{ + DataTransferBinding::ClearCachedTypesValue(this); +} + nsresult DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal) { if (aFormat.IsEmpty()) { return NS_OK; } @@ -729,36 +695,32 @@ DataTransfer::SetDataAtInternal(const ns } return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal); } void DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat, JS::Handle<JS::Value> aData, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - nsCOMPtr<nsIVariant> data; aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, getter_AddRefs(data)); if (!aRv.Failed()) { - aRv = SetDataAtInternal(aFormat, data, aIndex, aSubjectPrincipal.value()); + aRv = SetDataAtInternal(aFormat, data, aIndex, &aSubjectPrincipal); } } void DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } if (aIndex >= MozItemCount()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; @@ -783,25 +745,24 @@ DataTransfer::MozClearDataAt(const nsASt if (aIndex == 0 && mItems->MozItemCount() > 1 && mItems->MozItemsAt(0)->Length() == 0) { mItems->PopIndexZero(); } } void DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { MOZ_ASSERT(!mReadOnly); MOZ_ASSERT(aIndex < MozItemCount()); MOZ_ASSERT(aIndex == 0 || (mEventMessage != eCut && mEventMessage != eCopy && mEventMessage != ePaste)); - MOZ_ASSERT(aSubjectPrincipal.isSome()); nsAutoString format; GetRealFormat(aFormat, format); mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv); } void @@ -825,21 +786,19 @@ DataTransfer::SetDragImage(nsIDOMElement nsCOMPtr<Element> image = do_QueryInterface(aImage); if (image) { SetDragImage(*image, aX, aY, rv); } return rv.StealNSResult(); } already_AddRefed<Promise> -DataTransfer::GetFilesAndDirectories(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DataTransfer::GetFilesAndDirectories(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - nsCOMPtr<nsINode> parentNode = do_QueryInterface(mParent); if (!parentNode) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsIGlobalObject> global = parentNode->OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); @@ -848,17 +807,17 @@ DataTransfer::GetFilesAndDirectories(con return nullptr; } RefPtr<Promise> p = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - RefPtr<FileList> files = mItems->Files(aSubjectPrincipal.value()); + RefPtr<FileList> files = mItems->Files(&aSubjectPrincipal); if (NS_WARN_IF(!files)) { return nullptr; } Sequence<RefPtr<File>> filesSeq; files->ToSequence(filesSeq, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; @@ -866,17 +825,17 @@ DataTransfer::GetFilesAndDirectories(con p->MaybeResolve(filesSeq); return p.forget(); } already_AddRefed<Promise> DataTransfer::GetFiles(bool aRecursiveFlag, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { // Currently we don't support directories. return GetFilesAndDirectories(aSubjectPrincipal, aRv); } void DataTransfer::AddElement(Element& aElement, ErrorResult& aRv) @@ -1470,18 +1429,18 @@ DataTransfer::FillAllExternalData() } } void DataTransfer::FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal) { RefPtr<DataTransferItem> item = new DataTransferItem(this, - NS_LITERAL_STRING(kCustomTypesMime)); - item->SetKind(DataTransferItem::KIND_STRING); + NS_LITERAL_STRING(kCustomTypesMime), + DataTransferItem::KIND_STRING); item->SetIndex(aIndex); nsCOMPtr<nsIVariant> variant = item->DataNoSecurityCheck(); if (!variant) { return; } FillInExternalCustomTypes(variant, aIndex, aPrincipal);
--- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -131,41 +131,42 @@ public: } else { aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]); } } void SetDragImage(Element& aElement, int32_t aX, int32_t aY, ErrorResult& aRv); - already_AddRefed<DOMStringList> GetTypes(ErrorResult& rv) const; + void GetTypes(nsTArray<nsString>& aTypes, + nsIPrincipal& aSubjectPrincipal) const; void GetData(const nsAString& aFormat, nsAString& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void SetData(const nsAString& aFormat, const nsAString& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void ClearData(const mozilla::dom::Optional<nsAString>& aFormat, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); already_AddRefed<FileList> - GetFiles(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + GetFiles(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); already_AddRefed<Promise> - GetFilesAndDirectories(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + GetFilesAndDirectories(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); already_AddRefed<Promise> GetFiles(bool aRecursiveFlag, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void AddElement(Element& aElement, mozilla::ErrorResult& aRv); uint32_t MozItemCount() const; void GetMozCursor(nsString& aCursor) @@ -176,27 +177,27 @@ public: aCursor.AssignLiteral("auto"); } } already_AddRefed<DOMStringList> MozTypesAt(uint32_t aIndex, mozilla::ErrorResult& aRv) const; void MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); void MozSetDataAt(JSContext* aCx, const nsAString& aFormat, JS::Handle<JS::Value> aData, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); void MozGetDataAt(JSContext* aCx, const nsAString& aFormat, uint32_t aIndex, JS::MutableHandle<JS::Value> aRetval, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); bool MozUserCancelled() const { return mUserCancelled; } already_AddRefed<nsINode> GetMozSourceNode(); @@ -284,16 +285,21 @@ public: // converts some formats used for compatibility in aInFormat into aOutFormat. // Text and text/unicode become text/plain, and URL becomes text/uri-list void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) const; static bool PrincipalMaySetData(const nsAString& aFormat, nsIVariant* aData, nsIPrincipal* aPrincipal); + // Notify the DataTransfer that the list returned from GetTypes may have + // changed. This can happen due to items we care about for purposes of + // GetTypes being added or removed or changing item kinds. + void TypesListMayHaveChanged(); + protected: // caches text and uri-list data formats that exist in the drag service or // clipboard for retrieval later. nsresult CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal, bool aHidden); // caches the formats that exist in the drag service that were added by an @@ -316,17 +322,17 @@ protected: void FillAllExternalData(); void FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal); void FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal); void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); nsCOMPtr<nsISupports> mParent; // the drop effect and effect allowed uint32_t mDropEffect; uint32_t mEffectAllowed;
--- a/dom/events/DataTransferItem.cpp +++ b/dom/events/DataTransferItem.cpp @@ -69,22 +69,16 @@ DataTransferItem::Clone(DataTransfer* aD it->mData = mData; it->mPrincipal = mPrincipal; it->mChromeOnly = mChromeOnly; return it.forget(); } void -DataTransferItem::SetType(const nsAString& aType) -{ - mType = aType; -} - -void DataTransferItem::SetData(nsIVariant* aData) { // Invalidate our file cache, we will regenerate it with the new data mCachedFile = nullptr; if (!aData) { // We are holding a temporary null which will later be filled. // These are provided by the system, and have guaranteed properties about @@ -225,36 +219,33 @@ DataTransferItem::FillInExternalData() supportscstr->GetData(str); variant->SetAsACString(str); } } } SetData(variant); -#ifdef DEBUG if (oldKind != Kind()) { NS_WARNING("Clipboard data provided by the OS does not match predicted kind"); + mDataTransfer->TypesListMayHaveChanged(); } -#endif } already_AddRefed<File> -DataTransferItem::GetAsFile(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DataTransferItem::GetAsFile(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (mKind != KIND_FILE) { return nullptr; } // This is done even if we have an mCachedFile, as it performs the necessary // permissions checks to ensure that we are allowed to access this type. - nsCOMPtr<nsIVariant> data = Data(aSubjectPrincipal.value(), aRv); + nsCOMPtr<nsIVariant> data = Data(&aSubjectPrincipal, aRv); if (NS_WARN_IF(!data || aRv.Failed())) { return nullptr; } // Generate the dom::File from the stored data, caching it so that the // same object is returned in the future. if (!mCachedFile) { nsCOMPtr<nsISupports> supports; @@ -278,21 +269,19 @@ DataTransferItem::GetAsFile(const Maybe< } } RefPtr<File> file = mCachedFile; return file.forget(); } already_AddRefed<FileSystemEntry> -DataTransferItem::GetAsEntry(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DataTransferItem::GetAsEntry(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - RefPtr<File> file = GetAsFile(aSubjectPrincipal, aRv); if (NS_WARN_IF(aRv.Failed()) || !file) { return nullptr; } nsCOMPtr<nsIGlobalObject> global; // This is annoying, but DataTransfer may have various things as parent. nsCOMPtr<EventTarget> target = @@ -381,29 +370,27 @@ DataTransferItem::CreateFileFromInputStr } return File::CreateMemoryFile(mDataTransfer, data, available, fileName, mType, PR_Now()); } void DataTransferItem::GetAsString(FunctionStringCallback* aCallback, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (!aCallback || mKind != KIND_STRING) { return; } // Theoretically this should be done inside of the runnable, as it might be an // expensive operation on some systems, however we wouldn't get access to the // NS_ERROR_DOM_SECURITY_ERROR messages which may be raised by this method. - nsCOMPtr<nsIVariant> data = Data(aSubjectPrincipal.value(), aRv); + nsCOMPtr<nsIVariant> data = Data(&aSubjectPrincipal, aRv); if (NS_WARN_IF(!data || aRv.Failed())) { return; } nsAutoString stringData; nsresult rv = data->GetAsAString(stringData); if (NS_WARN_IF(NS_FAILED(rv))) { return;
--- a/dom/events/DataTransferItem.h +++ b/dom/events/DataTransferItem.h @@ -30,33 +30,33 @@ public: // we can have other kinds then just FILE and STRING. These others are simply // marked as "other" and can only be produced throug the Moz* APIs. enum eKind { KIND_FILE, KIND_STRING, KIND_OTHER, }; - DataTransferItem(DataTransfer* aDataTransfer, const nsAString& aType) + DataTransferItem(DataTransfer* aDataTransfer, const nsAString& aType, + eKind aKind = KIND_OTHER) : mIndex(0) , mChromeOnly(false) - , mKind(KIND_OTHER) + , mKind(aKind) , mType(aType) , mDataTransfer(aDataTransfer) { MOZ_ASSERT(mDataTransfer, "Must be associated with a DataTransfer"); } already_AddRefed<DataTransferItem> Clone(DataTransfer* aDataTransfer) const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - // NOTE: This accesses the subject principal, and should not be called from C++ void GetAsString(FunctionStringCallback* aCallback, - const Maybe<nsIPrincipal*>& aPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void GetKind(nsAString& aKind) const { switch (mKind) { case KIND_FILE: aKind = NS_LITERAL_STRING("file"); return; @@ -68,32 +68,27 @@ public: return; } } void GetType(nsAString& aType) const { aType = mType; } - void SetType(const nsAString& aType); eKind Kind() const { return mKind; } - void SetKind(eKind aKind) - { - mKind = aKind; - } already_AddRefed<File> - GetAsFile(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); + GetAsFile(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); already_AddRefed<FileSystemEntry> - GetAsEntry(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); + GetAsEntry(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); DataTransfer* GetParentObject() const { return mDataTransfer; } nsIPrincipal* Principal() const { @@ -101,16 +96,19 @@ public: } void SetPrincipal(nsIPrincipal* aPrincipal) { mPrincipal = aPrincipal; } already_AddRefed<nsIVariant> DataNoSecurityCheck(); already_AddRefed<nsIVariant> Data(nsIPrincipal* aPrincipal, ErrorResult& aRv); + + // Note: This can modify the mKind. Callers of this method must let the + // relevant DataTransfer know, because its types list can change as a result. void SetData(nsIVariant* aData); uint32_t Index() const { return mIndex; } void SetIndex(uint32_t aIndex) { @@ -133,17 +131,17 @@ private: ~DataTransferItem() {} already_AddRefed<File> CreateFileFromInputStream(nsIInputStream* aStream); // The index in the 2d mIndexedItems array uint32_t mIndex; bool mChromeOnly; eKind mKind; - nsString mType; + const nsString mType; nsCOMPtr<nsIVariant> mData; nsCOMPtr<nsIPrincipal> mPrincipal; RefPtr<DataTransfer> mDataTransfer; // File cache for nsIFile application/x-moz-file entries. RefPtr<File> mCachedFile; };
--- a/dom/events/DataTransferItemList.cpp +++ b/dom/events/DataTransferItemList.cpp @@ -77,36 +77,34 @@ DataTransferItemList::Clone(DataTransfer list->mItems[i] = list->mIndexedItems[index][subIndex]; } return list.forget(); } void DataTransferItemList::Remove(uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (mDataTransfer->IsReadOnly()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (aIndex >= Length()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } ClearDataHelper(mItems[aIndex], aIndex, -1, aSubjectPrincipal, aRv); } DataTransferItem* -DataTransferItemList::IndexedGetter(uint32_t aIndex, bool& aFound, ErrorResult& aRv) const +DataTransferItemList::IndexedGetter(uint32_t aIndex, bool& aFound) const { if (aIndex >= mItems.Length()) { aFound = false; return nullptr; } MOZ_ASSERT(mItems[aIndex]); aFound = true; @@ -121,21 +119,19 @@ DataTransferItemList::MozItemCount() con // if it is empty, scripts using the moz* APIs should see it as not existing. if (length == 1 && mIndexedItems[0].IsEmpty()) { return 0; } return length; } void -DataTransferItemList::Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DataTransferItemList::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return; } uint32_t count = Length(); for (uint32_t i = 0; i < count; i++) { // We always remove the last item first, to avoid moving items around in // memory as much @@ -144,81 +140,75 @@ DataTransferItemList::Clear(const Maybe< } MOZ_ASSERT(Length() == 0); } DataTransferItem* DataTransferItemList::Add(const nsAString& aData, const nsAString& aType, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return nullptr; } nsCOMPtr<nsIVariant> data(new storage::TextVariant(aData)); nsAutoString format; mDataTransfer->GetRealFormat(aType, format); - if (!DataTransfer::PrincipalMaySetData(format, data, - aSubjectPrincipal.value())) { + if (!DataTransfer::PrincipalMaySetData(format, data, &aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } // We add the textual data to index 0. We set aInsertOnly to true, as we don't // want to update an existing entry if it is already present, as per the spec. RefPtr<DataTransferItem> item = - SetDataWithPrincipal(format, data, 0, aSubjectPrincipal.value(), + SetDataWithPrincipal(format, data, 0, &aSubjectPrincipal, /* aInsertOnly = */ true, /* aHidden = */ false, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE); return item; } DataTransferItem* DataTransferItemList::Add(File& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (mDataTransfer->IsReadOnly()) { return nullptr; } nsCOMPtr<nsISupports> supports = do_QueryObject(&aData); nsCOMPtr<nsIWritableVariant> data = new nsVariant(); data->SetAsISupports(supports); nsAutoString type; aData.GetType(type); - if (!DataTransfer::PrincipalMaySetData(type, data, - aSubjectPrincipal.value())) { + if (!DataTransfer::PrincipalMaySetData(type, data, &aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } // We need to add this as a new item, as multiple files can't exist in the // same item in the Moz DataTransfer layout. It will be appended at the end of // the internal specced layout. uint32_t index = mIndexedItems.Length(); RefPtr<DataTransferItem> item = - SetDataWithPrincipal(type, data, index, aSubjectPrincipal.value(), + SetDataWithPrincipal(type, data, index, &aSubjectPrincipal, /* aInsertOnly = */ true, /* aHidden = */ false, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE); @@ -267,21 +257,19 @@ DataTransferItemList::Files(nsIPrincipal files = mFiles; return files.forget(); } void DataTransferItemList::MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - if (NS_WARN_IF(mDataTransfer->IsReadOnly() || aIndex >= mIndexedItems.Length())) { return; } bool removeAll = aType.IsEmpty(); nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex]; @@ -365,16 +353,20 @@ DataTransferItemList::SetDataWithPrincip || !subsumes))) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } item->SetPrincipal(aPrincipal); DataTransferItem::eKind oldKind = item->Kind(); item->SetData(aData); + if (oldKind != item->Kind()) { + // Types list may have changed, even if aIndex == 0. + mDataTransfer->TypesListMayHaveChanged(); + } if (aIndex != 0) { // If the item changes from being a file to not a file or vice-versa, // its presence in the mItems array may need to change. if (item->Kind() == DataTransferItem::KIND_FILE && oldKind != DataTransferItem::KIND_FILE) { // not file => file mItems.AppendElement(item); @@ -428,19 +420,25 @@ DataTransferItemList::AppendNewItem(uint item->SetChromeOnly(aHidden); mIndexedItems[aIndex].AppendElement(item); // We only want to add the item to the main mItems list if the index we are // adding to is 0, or the item we are adding is a file. If we add an item // which is not a file to a non-zero index, invariants could be broken. // (namely the invariant that there are not 2 non-file entries in the items - // array with the same type) - if (!aHidden && (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0)) { - mItems.AppendElement(item); + // array with the same type). + // + // We also want to update our DataTransfer's type list any time we're adding a + // KIND_FILE item, or an item at index 0. + if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) { + if (!aHidden) { + mItems.AppendElement(item); + } + mDataTransfer->TypesListMayHaveChanged(); } return item; } const nsTArray<RefPtr<DataTransferItem>>* DataTransferItemList::MozItemsAt(uint32_t aIndex) // -- INDEXED { @@ -470,60 +468,60 @@ DataTransferItemList::PopIndexZero() void DataTransferItemList::ClearAllItems() { // We always need to have index 0, so don't delete that one mItems.Clear(); mIndexedItems.Clear(); mIndexedItems.SetLength(1); + mDataTransfer->TypesListMayHaveChanged(); // Re-generate files (into an empty list) RegenerateFiles(); } void DataTransferItemList::ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint, uint32_t aMozOffsetHint, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { MOZ_ASSERT(aItem); if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return; } - if (aItem->Principal() && aSubjectPrincipal.isSome() && - !aSubjectPrincipal.value()->Subsumes(aItem->Principal())) { + if (aItem->Principal() && !aSubjectPrincipal.Subsumes(aItem->Principal())) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } // Check if the aIndexHint is actually the index, and then remove the item // from aItems - ErrorResult rv; bool found; - if (IndexedGetter(aIndexHint, found, rv) == aItem) { + if (IndexedGetter(aIndexHint, found) == aItem) { mItems.RemoveElementAt(aIndexHint); } else { mItems.RemoveElement(aItem); } - rv.SuppressException(); // Check if the aMozIndexHint and aMozOffsetHint are actually the index and // offset, and then remove them from mIndexedItems MOZ_ASSERT(aItem->Index() < mIndexedItems.Length()); nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aItem->Index()]; if (aMozOffsetHint < items.Length() && aItem == items[aMozOffsetHint]) { items.RemoveElementAt(aMozOffsetHint); } else { items.RemoveElement(aItem); } + mDataTransfer->TypesListMayHaveChanged(); + // Check if we should remove the index. We never remove index 0. if (items.Length() == 0 && aItem->Index() != 0) { mIndexedItems.RemoveElementAt(aItem->Index()); // Update the index of every element which has now been shifted for (uint32_t i = aItem->Index(); i < mIndexedItems.Length(); i++) { nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i]; for (uint32_t j = 0; j < items.Length(); j++) { @@ -559,25 +557,23 @@ DataTransferItemList::RegenerateFiles() void DataTransferItemList::GenerateFiles(FileList* aFiles, nsIPrincipal* aFilesPrincipal) { MOZ_ASSERT(aFiles); MOZ_ASSERT(aFilesPrincipal); uint32_t count = Length(); for (uint32_t i = 0; i < count; i++) { - ErrorResult rv; bool found; - RefPtr<DataTransferItem> item = IndexedGetter(i, found, rv); - if (NS_WARN_IF(!found || rv.Failed())) { - continue; - } + RefPtr<DataTransferItem> item = IndexedGetter(i, found); + MOZ_ASSERT(found); if (item->Kind() == DataTransferItem::KIND_FILE) { - RefPtr<File> file = item->GetAsFile(Some(aFilesPrincipal), rv); + IgnoredErrorResult rv; + RefPtr<File> file = item->GetAsFile(*aFilesPrincipal, rv); if (NS_WARN_IF(rv.Failed() || !file)) { continue; } aFiles->Append(file); } } }
--- a/dom/events/DataTransferItemList.h +++ b/dom/events/DataTransferItemList.h @@ -46,76 +46,86 @@ public: JS::Handle<JSObject*> aGivenProto) override; uint32_t Length() const { return mItems.Length(); }; DataTransferItem* Add(const nsAString& aData, const nsAString& aType, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& rv); DataTransferItem* Add(File& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void Remove(uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); - DataTransferItem* IndexedGetter(uint32_t aIndex, bool& aFound, - ErrorResult& aRv) const; + DataTransferItem* IndexedGetter(uint32_t aIndex, bool& aFound) const; DataTransfer* GetParentObject() const { return mDataTransfer; } - void Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); + void Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); already_AddRefed<DataTransferItem> SetDataWithPrincipal(const nsAString& aType, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal, bool aInsertOnly, bool aHidden, ErrorResult& aRv); already_AddRefed<FileList> Files(nsIPrincipal* aPrincipal); // Moz-style helper methods for interacting with the stored data void MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); DataTransferItem* MozItemByTypeAt(const nsAString& aType, uint32_t aIndex); const nsTArray<RefPtr<DataTransferItem>>* MozItemsAt(uint32_t aIndex); uint32_t MozItemCount() const; // Causes everything in indexes above 0 to shift down one index. void PopIndexZero(); // Delete every item in the DataTransferItemList, without checking for // permissions or read-only status (for internal use only). void ClearAllItems(); private: void ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint, uint32_t aMozOffsetHint, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); DataTransferItem* AppendNewItem(uint32_t aIndex, const nsAString& aType, nsIVariant* aData, nsIPrincipal* aPrincipal, bool aHidden); void RegenerateFiles(); void GenerateFiles(FileList* aFiles, nsIPrincipal* aFilesPrincipal); ~DataTransferItemList() {} RefPtr<DataTransfer> mDataTransfer; bool mIsExternal; RefPtr<FileList> mFiles; // The principal for which mFiles is cached nsCOMPtr<nsIPrincipal> mFilesPrincipal; + // mItems is the list of items that corresponds to the spec concept of a + // DataTransferItemList. That is, this is the thing the spec's indexed getter + // operates on. The items in here are a subset of the items present in the + // arrays that live in mIndexedItems. nsTArray<RefPtr<DataTransferItem>> mItems; + // mIndexedItems represents all our items. For any given index, all items at + // that index have different types in the GetType() sense. That means that + // representing multiple items with the same type (e.g. multiple files) + // requires using multiple indices. + // + // There is always a (possibly empty) list of items at index 0, so + // mIndexedItems.Length() >= 1 at all times. nsTArray<nsTArray<RefPtr<DataTransferItem>>> mIndexedItems; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_DataTransferItemList_h
--- a/dom/events/test/test_dragstart.html +++ b/dom/events/test/test_dragstart.html @@ -113,17 +113,17 @@ function doDragStartSelection(event) is(event.pageX, 14, "dragstart pageX"); is(event.pageY, 14, "dragstart pageY"); var dt = event.dataTransfer; ok(dt instanceof DataTransfer, "dataTransfer is DataTransfer"); gDataTransfer = dt; var types = dt.types; - is(types instanceof DOMStringList, true, "initial types is a DOMStringList"); + ok(Array.isArray(types), "initial types is an Array"); checkTypes(dt, ["text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial selection"); is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain"); is(dt.getData("text/html"), "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>", "initial selection text/html"); // text/unicode and Text are available for compatibility. They retrieve the // text/plain data @@ -143,17 +143,17 @@ function doDragStartSelection(event) setTimeout(afterDragTests, 0); } function test_DataTransfer(dt) { is(dt.mozItemCount, 0, "empty itemCount"); var types = dt.types; - is(types instanceof DOMStringList, true, "empty types is a DOMStringList"); + ok(Array.isArray(types), "empty types is an Array"); checkTypes(dt, [], 0, "empty"); is(dt.getData("text/plain"), "", "empty data is empty"); // calling setDataAt requires an index that is 0 <= index <= dt.itemCount expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 1), "IndexSizeError", "setDataAt index too high"); is(dt.mozUserCancelled, false, "userCancelled");
--- a/dom/html/HTMLIFrameElement.h +++ b/dom/html/HTMLIFrameElement.h @@ -163,17 +163,17 @@ public: { SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError); } void GetReferrerPolicy(nsAString& aReferrer) { GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer); } nsIDocument* - GetSVGDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) + GetSVGDocument(nsIPrincipal& aSubjectPrincipal) { return GetContentDocument(aSubjectPrincipal); } bool Mozbrowser() const { return GetBoolAttr(nsGkAtoms::mozbrowser); } void SetMozbrowser(bool aAllow, ErrorResult& aError)
--- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -2836,21 +2836,19 @@ NS_IMETHODIMP HTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult) { *aResult = MozIsTextField(aExcludePassword); return NS_OK; } void HTMLInputElement::SetUserInput(const nsAString& aInput, - const mozilla::Maybe<nsIPrincipal*>& aPrincipal) { - MOZ_ASSERT(aPrincipal.isSome()); - + nsIPrincipal& aSubjectPrincipal) { if (mType == NS_FORM_INPUT_FILE && - !nsContentUtils::IsSystemPrincipal(aPrincipal.value())) { + !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) { return; } SetUserInput(aInput); } NS_IMETHODIMP HTMLInputElement::SetUserInput(const nsAString& aValue)
--- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -816,17 +816,17 @@ public: return mNumberControlSpinnerIsSpinning && !mNumberControlSpinnerSpinsUp; } bool MozIsTextField(bool aExcludePassword); nsIEditor* GetEditor(); void SetUserInput(const nsAString& aInput, - const mozilla::Maybe<nsIPrincipal*>& aPrincipal); + nsIPrincipal& aSubjectPrincipal); // XPCOM GetPhonetic() is OK /** * If aValue contains a valid floating-point number in the format specified * by the HTML 5 spec: * * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#floating-point-numbers
--- a/dom/html/HTMLObjectElement.cpp +++ b/dom/html/HTMLObjectElement.cpp @@ -461,23 +461,23 @@ HTMLObjectElement::TabIndexDefault() } NS_IMETHODIMP HTMLObjectElement::GetContentDocument(nsIDOMDocument **aContentDocument) { NS_ENSURE_ARG_POINTER(aContentDocument); nsCOMPtr<nsIDOMDocument> domDoc = - do_QueryInterface(GetContentDocument(Some(nsContentUtils::SubjectPrincipal()))); + do_QueryInterface(GetContentDocument(*nsContentUtils::SubjectPrincipal())); domDoc.forget(aContentDocument); return NS_OK; } nsPIDOMWindowOuter* -HTMLObjectElement::GetContentWindow(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) +HTMLObjectElement::GetContentWindow(nsIPrincipal& aSubjectPrincipal) { nsIDocument* doc = GetContentDocument(aSubjectPrincipal); if (doc) { return doc->GetWindow(); } return nullptr; }
--- a/dom/html/HTMLObjectElement.h +++ b/dom/html/HTMLObjectElement.h @@ -153,17 +153,17 @@ public: } void SetHeight(const nsAString& aValue, ErrorResult& aRv) { SetHTMLAttr(nsGkAtoms::height, aValue, aRv); } using nsObjectLoadingContent::GetContentDocument; nsPIDOMWindowOuter* - GetContentWindow(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal); + GetContentWindow(nsIPrincipal& aSubjectPrincipal); using nsIConstraintValidation::CheckValidity; using nsIConstraintValidation::ReportValidity; using nsIConstraintValidation::GetValidationMessage; void GetAlign(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::align, aValue); } @@ -234,17 +234,17 @@ public: GetHTMLAttr(nsGkAtoms::border, aValue); } void SetBorder(const nsAString& aValue, ErrorResult& aRv) { SetHTMLAttr(nsGkAtoms::border, aValue, aRv); } nsIDocument* - GetSVGDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) + GetSVGDocument(nsIPrincipal& aSubjectPrincipal) { return GetContentDocument(aSubjectPrincipal); } private: /** * Calls LoadObject with the correct arguments to start the plugin load. */
--- a/dom/html/HTMLSharedObjectElement.h +++ b/dom/html/HTMLSharedObjectElement.h @@ -183,17 +183,17 @@ public: { SetHTMLAttr(nsGkAtoms::type, aValue, aRv); } // width covered by <applet> // height covered by <applet> // align covered by <applet> // name covered by <applet> nsIDocument* - GetSVGDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) + GetSVGDocument(nsIPrincipal& aSubjectPrincipal) { return GetContentDocument(aSubjectPrincipal); } /** * Calls LoadObject with the correct arguments to start the plugin load. */ void StartObjectLoad(bool aNotify, bool aForceLoad);
--- a/dom/html/nsGenericHTMLFrameElement.cpp +++ b/dom/html/nsGenericHTMLFrameElement.cpp @@ -75,37 +75,36 @@ nsGenericHTMLFrameElement::~nsGenericHTM } } nsresult nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument) { NS_PRECONDITION(aContentDocument, "Null out param"); nsCOMPtr<nsIDOMDocument> document = - do_QueryInterface(GetContentDocument(Some(nsContentUtils::SubjectPrincipal()))); + do_QueryInterface(GetContentDocument(*nsContentUtils::SubjectPrincipal())); document.forget(aContentDocument); return NS_OK; } nsIDocument* -nsGenericHTMLFrameElement::GetContentDocument(const Maybe<nsIPrincipal*>& aSubjectPrincipal) +nsGenericHTMLFrameElement::GetContentDocument(nsIPrincipal& aSubjectPrincipal) { nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindow(); if (!win) { return nullptr; } nsIDocument *doc = win->GetDoc(); if (!doc) { return nullptr; } // Return null for cross-origin contentDocument. - if (!aSubjectPrincipal.value() - ->SubsumesConsideringDomain(doc->NodePrincipal())) { + if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) { return nullptr; } return doc; } already_AddRefed<nsPIDOMWindowOuter> nsGenericHTMLFrameElement::GetContentWindow() {
--- a/dom/html/nsGenericHTMLFrameElement.h +++ b/dom/html/nsGenericHTMLFrameElement.h @@ -97,18 +97,17 @@ public: protected: virtual ~nsGenericHTMLFrameElement(); // This doesn't really ensure a frame loader in all cases, only when // it makes sense. void EnsureFrameLoader(); nsresult LoadSrc(); - nsIDocument* - GetContentDocument(const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal); + nsIDocument* GetContentDocument(nsIPrincipal& aSubjectPrincipal); nsresult GetContentDocument(nsIDOMDocument** aContentDocument); already_AddRefed<nsPIDOMWindowOuter> GetContentWindow(); RefPtr<nsFrameLoader> mFrameLoader; /** * True when the element is created by the parser using the * NS_FROM_PARSER_NETWORK flag.
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2838,20 +2838,28 @@ nsHTMLDocument::SetDesignMode(const nsAS SetDesignMode(aDesignMode, nsContentUtils::GetCurrentJSContext() ? Some(nsContentUtils::SubjectPrincipal()) : Nothing(), rv); return rv.StealNSResult(); } void nsHTMLDocument::SetDesignMode(const nsAString& aDesignMode, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& rv) +{ + SetDesignMode(aDesignMode, Some(&aSubjectPrincipal), rv); +} + +void +nsHTMLDocument::SetDesignMode(const nsAString& aDesignMode, const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& rv) { - if (!nsContentUtils::LegacyIsCallerNativeCode() && + if (aSubjectPrincipal.isSome() && !aSubjectPrincipal.value()->Subsumes(NodePrincipal())) { rv.Throw(NS_ERROR_DOM_PROP_ACCESS_DENIED); return; } bool editableMode = HasFlag(NODE_IS_EDITABLE); if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) { SetEditableFlag(!editableMode);
--- a/dom/html/nsHTMLDocument.h +++ b/dom/html/nsHTMLDocument.h @@ -206,21 +206,24 @@ public: bool aReplace, mozilla::ErrorResult& rv); void Close(mozilla::ErrorResult& rv); void Write(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText, mozilla::ErrorResult& rv); void Writeln(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText, mozilla::ErrorResult& rv); void GetDesignMode(nsAString& aDesignMode, - const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal) + nsIPrincipal& aSubjectPrincipal) { GetDesignMode(aDesignMode); } void SetDesignMode(const nsAString& aDesignMode, + nsIPrincipal& aSubjectPrincipal, + mozilla::ErrorResult& rv); + void SetDesignMode(const nsAString& aDesignMode, const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal, mozilla::ErrorResult& rv); bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI, const nsAString& aValue, mozilla::ErrorResult& rv); bool QueryCommandEnabled(const nsAString& aCommandID, mozilla::ErrorResult& rv); bool QueryCommandIndeterm(const nsAString& aCommandID, mozilla::ErrorResult& rv);
--- a/dom/interfaces/events/nsIDOMDataTransfer.idl +++ b/dom/interfaces/events/nsIDOMDataTransfer.idl @@ -62,29 +62,16 @@ interface nsIDOMDataTransfer : nsISuppor /** * Holds a list of all the local files available on this data transfer. * A dataTransfer containing no files will return an empty list, and an * invalid index access on the resulting file list will return null. */ readonly attribute nsIDOMFileList files; /** - * Holds a list of the format types of the data that is stored for the first - * item, in the same order the data was added. An empty list will be - * returned if no data was added. - */ - readonly attribute nsISupports types; - - /** - * Retrieves the data for a given format, or an empty string if data for - * that format does not exist or the data transfer contains no data. - */ - DOMString getData(in DOMString format); - - /** * Set the image to be used for dragging if a custom one is desired. Most of * the time, this would not be set, as a default image is created from the * node that was dragged. * * If the node is an HTML img element, an HTML canvas element or a XUL image * element, the image data is used. Otherwise, image should be a visible * node and the drag image will be created from this. If image is null, any * custom drag image is cleared and the default is used instead.
--- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -302,17 +302,18 @@ HangMonitorChild::InterruptCallback() forcePaintEpoch = mForcePaintEpoch; mForcePaint = false; } if (forcePaint) { RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab); if (tabChild) { - JS::AutoAssertOnGC aaogc(mContext); + JS::AutoAssertOnGC nogc(mContext); + JS::AutoAssertOnBarrier nobarrier(mContext); tabChild->ForcePaint(forcePaintEpoch); } } } void HangMonitorChild::Shutdown() { @@ -384,16 +385,17 @@ HangMonitorChild::RecvForcePaint(const T { MonitorAutoLock lock(mMonitor); mForcePaint = true; mForcePaintTab = aTabId; mForcePaintEpoch = aLayerObserverEpoch; } JS_RequestInterruptCallback(mContext); + JS::RequestGCInterruptCallback(mContext); return true; } void HangMonitorChild::Open(Transport* aTransport, ProcessId aPid, MessageLoop* aIOLoop) { @@ -1182,16 +1184,17 @@ mozilla::CreateHangMonitorParent(Content PProcessHangMonitorChild* mozilla::CreateHangMonitorChild(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherPid) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); JSContext* cx = danger::GetJSContext(); JS_AddInterruptCallback(cx, InterruptCallback); + JS::AddGCInterruptCallback(cx, InterruptCallback); ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate(); HangMonitorChild* child = new HangMonitorChild(monitor); monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod <mozilla::ipc::Transport*, base::ProcessId, MessageLoop*>(child,
new file mode 100644 --- /dev/null +++ b/dom/media/test/crashtests/1223670.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> +<script> + +function boom() +{ + + var ac = new window.AudioContext("publicnotification"); + + setTimeout(function() { + document.documentElement.removeAttribute("class"); + var htmlAudio = new Audio(); + var stream = htmlAudio.mozCaptureStreamUntilEnded(); + ac.createMediaStreamSource(stream); + }, 0); +} + +</script> +</head> +<body onload="boom();"> +</body> +</html>
--- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -76,16 +76,17 @@ load 1041466.html load 1045650.html load 1080986.html load 1122218.html load 1127188.html load 1157994.html skip-if(!B2G) load 1158427.html load 1185176.html load 1185192.html +load 1223670.html load 1228484.html load 1304948.html load analyser-channels-1.html load audiocontext-double-suspend.html load buffer-source-duration-1.html load buffer-source-ended-1.html load buffer-source-resampling-start-1.html load doppler-1.html
--- a/dom/storage/DOMStorage.cpp +++ b/dom/storage/DOMStorage.cpp @@ -62,69 +62,61 @@ DOMStorage::~DOMStorage() /* virtual */ JSObject* DOMStorage::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return StorageBinding::Wrap(aCx, this, aGivenProto); } uint32_t -DOMStorage::GetLength(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DOMStorage::GetLength(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return 0; } uint32_t length; aRv = mCache->GetLength(this, &length); return length; } void DOMStorage::Key(uint32_t aIndex, nsAString& aResult, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } aRv = mCache->GetKey(this, aIndex, aResult); } void DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } aRv = mCache->GetItem(this, aKey, aResult); } void DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } nsString data; bool ok = data.Assign(aData, fallible); if (!ok) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); @@ -139,44 +131,40 @@ DOMStorage::SetItem(const nsAString& aKe if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) { BroadcastChangeNotification(aKey, old, aData); } } void DOMStorage::RemoveItem(const nsAString& aKey, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } nsAutoString old; aRv = mCache->RemoveItem(this, aKey, old); if (aRv.Failed()) { return; } if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) { BroadcastChangeNotification(aKey, old, NullString()); } } void -DOMStorage::Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +DOMStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (!CanUseStorage(nullptr, aSubjectPrincipal, this)) { + if (!CanUseStorage(aSubjectPrincipal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } aRv = mCache->Clear(this); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -240,47 +228,34 @@ DOMStorage::BroadcastChangeNotification( ? u"localStorage" : u"sessionStorage"); NS_DispatchToMainThread(r); } static const char kPermissionType[] = "cookie"; static const char kStorageEnabled[] = "dom.storage.enabled"; -// static, public bool -DOMStorage::CanUseStorage(nsPIDOMWindowInner* aWindow, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, - DOMStorage* aStorage) +DOMStorage::CanUseStorage(nsIPrincipal& aSubjectPrincipal) { // This method is responsible for correct setting of mIsSessionOnly. if (!mozilla::Preferences::GetBool(kStorageEnabled)) { return false; } - nsContentUtils::StorageAccess access = nsContentUtils::StorageAccess::eDeny; - if (aWindow) { - access = nsContentUtils::StorageAllowedForWindow(aWindow); - } else if (aStorage) { - access = nsContentUtils::StorageAllowedForPrincipal(aStorage->mPrincipal); - } + nsContentUtils::StorageAccess access = + nsContentUtils::StorageAllowedForPrincipal(mPrincipal); if (access == nsContentUtils::StorageAccess::eDeny) { return false; } - if (aStorage) { - aStorage->mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped; - - MOZ_ASSERT(aSubjectPrincipal.isSome()); - return aStorage->CanAccess(aSubjectPrincipal.value()); - } - - return true; + mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped; + return CanAccess(&aSubjectPrincipal); } DOMStorage::StorageType DOMStorage::GetType() const { return mManager->Type(); } @@ -315,18 +290,17 @@ bool DOMStorage::CanAccess(nsIPrincipal* aPrincipal) { return !aPrincipal || aPrincipal->Subsumes(mPrincipal); } void DOMStorage::GetSupportedNames(nsTArray<nsString>& aKeys) { - if (!CanUseStorage(nullptr, Some(nsContentUtils::SubjectPrincipal()), - this)) { + if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) { // return just an empty array aKeys.Clear(); return; } mCache->GetKeys(this, aKeys); }
--- a/dom/storage/DOMStorage.h +++ b/dom/storage/DOMStorage.h @@ -65,84 +65,83 @@ public: // WebIDL JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; nsPIDOMWindowInner* GetParentObject() const { return mWindow; } - uint32_t GetLength(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + uint32_t GetLength(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void Key(uint32_t aIndex, nsAString& aResult, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void GetItem(const nsAString& aKey, nsAString& aResult, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void GetSupportedNames(nsTArray<nsString>& aKeys); void NamedGetter(const nsAString& aKey, bool& aFound, nsAString& aResult, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { GetItem(aKey, aResult, aSubjectPrincipal, aRv); aFound = !aResult.IsVoid(); } void SetItem(const nsAString& aKey, const nsAString& aValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void NamedSetter(const nsAString& aKey, const nsAString& aValue, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { SetItem(aKey, aValue, aSubjectPrincipal, aRv); } void RemoveItem(const nsAString& aKey, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void NamedDeleter(const nsAString& aKey, bool& aFound, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { RemoveItem(aKey, aSubjectPrincipal, aRv); aFound = !aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION); } - void Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + void Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); - // The method checks whether the caller can use a storage. - // CanUseStorage is called before any DOM initiated operation - // on a storage is about to happen and ensures that the storage's - // session-only flag is properly set according the current settings. - // It is an optimization since the privileges check and session only - // state determination are complex and share the code (comes hand in - // hand together). - static bool CanUseStorage(nsPIDOMWindowInner* aWindow, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, - DOMStorage* aStorage = nullptr); - bool IsPrivate() const; bool IsSessionOnly() const { return mIsSessionOnly; } bool IsForkOf(const DOMStorage* aOther) const { MOZ_ASSERT(aOther); return mCache == aOther->mCache; } +protected: + // The method checks whether the caller can use a storage. + // CanUseStorage is called before any DOM initiated operation + // on a storage is about to happen and ensures that the storage's + // session-only flag is properly set according the current settings. + // It is an optimization since the privileges check and session only + // state determination are complex and share the code (comes hand in + // hand together). + bool CanUseStorage(nsIPrincipal& aSubjectPrincipal); + private: ~DOMStorage(); friend class DOMStorageManager; friend class DOMStorageCache; nsCOMPtr<nsPIDOMWindowInner> mWindow; RefPtr<DOMStorageManager> mManager;
--- a/dom/webidl/DataTransfer.webidl +++ b/dom/webidl/DataTransfer.webidl @@ -12,18 +12,18 @@ interface DataTransfer { attribute DOMString dropEffect; attribute DOMString effectAllowed; readonly attribute DataTransferItemList items; [Throws] void setDragImage(Element image, long x, long y); - [Throws] - readonly attribute DOMStringList types; + [Pure, Cached, Frozen, NeedsSubjectPrincipal] + readonly attribute sequence<DOMString> types; [Throws, NeedsSubjectPrincipal] DOMString getData(DOMString format); [Throws, NeedsSubjectPrincipal] void setData(DOMString format, DOMString data); [Throws, NeedsSubjectPrincipal] void clearData(optional DOMString format); [Throws, NeedsSubjectPrincipal] readonly attribute FileList? files;
--- a/dom/webidl/DataTransferItemList.webidl +++ b/dom/webidl/DataTransferItemList.webidl @@ -4,17 +4,16 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is: * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitemlist-interface */ interface DataTransferItemList { readonly attribute unsigned long length; - [Throws] getter DataTransferItem (unsigned long index); [Throws, NeedsSubjectPrincipal] DataTransferItem? add(DOMString data, DOMString type); [Throws, NeedsSubjectPrincipal] DataTransferItem? add(File data); [Throws, NeedsSubjectPrincipal] void remove(unsigned long index); [Throws, NeedsSubjectPrincipal]
--- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -104,17 +104,17 @@ interface WindowSessionStorage { //[Throws] readonly attribute Storage sessionStorage; [Throws] readonly attribute Storage? sessionStorage; }; Window implements WindowSessionStorage; // http://www.whatwg.org/specs/web-apps/current-work/ [NoInterfaceObject] interface WindowLocalStorage { - [Throws, NeedsSubjectPrincipal] readonly attribute Storage? localStorage; + [Throws] readonly attribute Storage? localStorage; }; Window implements WindowLocalStorage; // http://www.whatwg.org/specs/web-apps/current-work/ partial interface Window { void captureEvents(); void releaseEvents(); };
--- a/editor/libeditor/EditorEventListener.cpp +++ b/editor/libeditor/EditorEventListener.cpp @@ -929,29 +929,26 @@ EditorEventListener::CanDrop(nsIDOMDragE return false; } nsCOMPtr<nsIDOMDataTransfer> domDataTransfer; aEvent->GetDataTransfer(getter_AddRefs(domDataTransfer)); nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(domDataTransfer); NS_ENSURE_TRUE(dataTransfer, false); - ErrorResult err; - RefPtr<DOMStringList> types = dataTransfer->GetTypes(err); - if (NS_WARN_IF(err.Failed())) { - return false; - } + nsTArray<nsString> types; + dataTransfer->GetTypes(types, *nsContentUtils::GetSystemPrincipal()); // Plaintext editors only support dropping text. Otherwise, HTML and files // can be dropped as well. - if (!types->Contains(NS_LITERAL_STRING(kTextMime)) && - !types->Contains(NS_LITERAL_STRING(kMozTextInternal)) && + if (!types.Contains(NS_LITERAL_STRING(kTextMime)) && + !types.Contains(NS_LITERAL_STRING(kMozTextInternal)) && (mEditorBase->IsPlaintextEditor() || - (!types->Contains(NS_LITERAL_STRING(kHTMLMime)) && - !types->Contains(NS_LITERAL_STRING(kFileMime))))) { + (!types.Contains(NS_LITERAL_STRING(kHTMLMime)) && + !types.Contains(NS_LITERAL_STRING(kFileMime))))) { return false; } // If there is no source node, this is probably an external drag and the // drop is allowed. The later checks rely on checking if the drag target // is the same as the drag source. nsCOMPtr<nsIDOMNode> sourceNode; dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
--- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -479,39 +479,40 @@ IsGenerationalGCEnabled(JSRuntime* rt); * Returns the GC's "number". This does not correspond directly to the number * of GCs that have been run, but is guaranteed to be monotonically increasing * with GC activity. */ extern JS_PUBLIC_API(size_t) GetGCNumber(); /** - * Assert if a GC occurs while this class is live. This class does not disable - * the static rooting hazard analysis. + * Pass a subclass of this "abstract" class to callees to require that they + * never GC. Subclasses can use assertions or the hazard analysis to ensure no + * GC happens. */ -class JS_PUBLIC_API(AutoAssertOnGC) +class JS_PUBLIC_API(AutoRequireNoGC) { -#ifdef DEBUG + protected: + AutoRequireNoGC() {} + ~AutoRequireNoGC() {} +}; + +/** + * Release assert if a GC occurs while this class is live. This class does + * not disable the static rooting hazard analysis. + */ +class JS_PUBLIC_API(AutoAssertOnGC) : public AutoRequireNoGC +{ js::gc::GCRuntime* gc; size_t gcNumber; public: AutoAssertOnGC(); explicit AutoAssertOnGC(JSContext* cx); ~AutoAssertOnGC(); - - static void VerifyIsSafeToGC(JSRuntime* rt); -#else - public: - AutoAssertOnGC() {} - explicit AutoAssertOnGC(JSContext* cx) {} - ~AutoAssertOnGC() {} - - static void VerifyIsSafeToGC(JSRuntime* rt) {} -#endif }; /** * Assert if an allocation of a GC thing occurs while this class is live. This * class does not disable the static rooting hazard analysis. */ class JS_PUBLIC_API(AutoAssertNoAlloc) { @@ -527,16 +528,30 @@ class JS_PUBLIC_API(AutoAssertNoAlloc) public: AutoAssertNoAlloc() {} explicit AutoAssertNoAlloc(JSContext* cx) {} void disallowAlloc(JSRuntime* rt) {} #endif }; /** + * Assert if a GC barrier is invoked while this class is live. This class does + * not disable the static rooting hazard analysis. + */ +class JS_PUBLIC_API(AutoAssertOnBarrier) +{ + JSContext* context; + bool prev; + + public: + explicit AutoAssertOnBarrier(JSContext* cx); + ~AutoAssertOnBarrier(); +}; + +/** * Disable the static rooting hazard analysis in the live region and assert if * any allocation that could potentially trigger a GC occurs while this guard * object is live. This is most useful to help the exact rooting hazard analysis * in complex regions, since it cannot understand dataflow. * * Note: GC behavior is unpredictable even when deterministic and is generally * non-deterministic in practice. The fact that this guard has not * asserted is not a guarantee that a GC cannot happen in the guarded @@ -570,23 +585,34 @@ class JS_PUBLIC_API(AutoAssertGCCallback * Place AutoCheckCannotGC in scopes that you believe can never GC. These * annotations will be verified both dynamically via AutoAssertOnGC, and * statically with the rooting hazard analysis (implemented by making the * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore * complain if it is live across a GC call.) It is useful when dealing with * internal pointers to GC things where the GC thing itself may not be present * for the static analysis: e.g. acquiring inline chars from a JSString* on the * heap. + * + * We only do the assertion checking in DEBUG builds. */ +#ifdef DEBUG class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC { public: AutoCheckCannotGC() : AutoAssertOnGC() {} explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertOnGC(cx) {} } JS_HAZ_GC_INVALIDATED; +#else +class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC +{ + public: + AutoCheckCannotGC() {} + explicit AutoCheckCannotGC(JSContext* cx) {} +} JS_HAZ_GC_INVALIDATED; +#endif /** * Unsets the gray bit for anything reachable from |thing|. |kind| should not be * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates * if anything was unmarked. */ extern JS_FRIEND_API(bool) UnmarkGrayGCThingRecursively(GCCellPtr thing); @@ -604,26 +630,28 @@ ExposeGCThingToActiveJS(JS::GCCellPtr th /* * GC things residing in the nursery cannot be gray: they have no mark bits. * All live objects in the nursery are moved to tenured at the beginning of * each GC slice, so the gray marker never sees nursery things. */ if (IsInsideNursery(thing.asCell())) return; JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); else if (JS::GCThingIsMarkedGray(thing)) JS::UnmarkGrayGCThingRecursively(thing); } static MOZ_ALWAYS_INLINE void MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) { JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); /* * Any object in the nursery will not be freed during any GC running at that time. */ if (IsInsideNursery(thing.asCell())) return; if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); } @@ -671,11 +699,23 @@ extern JS_FRIEND_API(void) PokeGC(JSContext* cx); /* * Internal to Firefox. */ extern JS_FRIEND_API(void) NotifyDidPaint(JSContext* cx); +// GC Interrupt callbacks are run during GC. You should not run JS code or use +// the JS engine at all while the callback is running. Otherwise they resemble +// normal JS interrupt callbacks. +typedef bool +(* GCInterruptCallback)(JSContext* cx); + +extern JS_FRIEND_API(bool) +AddGCInterruptCallback(JSContext* cx, GCInterruptCallback callback); + +extern JS_FRIEND_API(void) +RequestGCInterruptCallback(JSContext* cx); + } /* namespace JS */ #endif /* js_GCAPI_h */
--- a/js/public/SliceBudget.h +++ b/js/public/SliceBudget.h @@ -2,16 +2,18 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef js_SliceBudget_h #define js_SliceBudget_h +#include "mozilla/Atomics.h" + #include <stdint.h> namespace js { struct JS_PUBLIC_API(TimeBudget) { int64_t budget; @@ -31,57 +33,82 @@ struct JS_PUBLIC_API(WorkBudget) * to run for unlimited time, and others are bounded. To reduce the number of * gettimeofday calls, we only check the time every 1000 operations. */ class JS_PUBLIC_API(SliceBudget) { static const int64_t unlimitedDeadline = INT64_MAX; static const intptr_t unlimitedStartCounter = INTPTR_MAX; - bool checkOverBudget(); + bool checkOverBudget(JSContext* maybeCx); SliceBudget(); public: // Memory of the originally requested budget. If isUnlimited, neither of // these are in use. If deadline==0, then workBudget is valid. Otherwise // timeBudget is valid. TimeBudget timeBudget; WorkBudget workBudget; int64_t deadline; /* in microseconds */ - intptr_t counter; + mozilla::Atomic<intptr_t, mozilla::Relaxed> counter; static const intptr_t CounterReset = 1000; static const int64_t UnlimitedTimeBudget = -1; static const int64_t UnlimitedWorkBudget = -1; /* Use to create an unlimited budget. */ static SliceBudget unlimited() { return SliceBudget(); } /* Instantiate as SliceBudget(TimeBudget(n)). */ explicit SliceBudget(TimeBudget time); /* Instantiate as SliceBudget(WorkBudget(n)). */ explicit SliceBudget(WorkBudget work); + // Need an explicit copy constructor because Atomic fails to provide one. + SliceBudget(const SliceBudget& other) + : timeBudget(other.timeBudget), + workBudget(other.workBudget), + deadline(other.deadline), + counter(other.counter) + {} + + // Need an explicit operator= because Atomic fails to provide one. + SliceBudget& operator=(const SliceBudget& other) { + timeBudget = other.timeBudget; + workBudget = other.workBudget; + deadline = other.deadline; + counter = intptr_t(other.counter); + return *this; + } + void makeUnlimited() { deadline = unlimitedDeadline; counter = unlimitedStartCounter; } + // Request that checkOverBudget be called the next time isOverBudget is + // called. + void requestFullCheck() { + counter = 0; + } + void step(intptr_t amt = 1) { counter -= amt; } - bool isOverBudget() { + // Only need to pass maybeCx if the GC interrupt callback should be checked + // (and possibly invoked). + bool isOverBudget(JSContext* maybeCx = nullptr) { if (counter > 0) return false; - return checkOverBudget(); + return checkOverBudget(maybeCx); } bool isWorkBudget() const { return deadline == 0; } bool isTimeBudget() const { return deadline > 0 && !isUnlimited(); } bool isUnlimited() const { return deadline == unlimitedDeadline; } int describe(char* buffer, size_t maxlen) const; };
--- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -185,17 +185,17 @@ template bool js::ToSimdConstant<Int16x8 template bool js::ToSimdConstant<Int32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); template bool js::ToSimdConstant<Float32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); template bool js::ToSimdConstant<Bool8x16>(JSContext* cx, HandleValue v, jit::SimdConstant* out); template bool js::ToSimdConstant<Bool16x8>(JSContext* cx, HandleValue v, jit::SimdConstant* out); template bool js::ToSimdConstant<Bool32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); template<typename Elem> static Elem -TypedObjectMemory(HandleValue v, const JS::AutoAssertOnGC& nogc) +TypedObjectMemory(HandleValue v, const JS::AutoRequireNoGC& nogc) { TypedObject& obj = v.toObject().as<TypedObject>(); return reinterpret_cast<Elem>(obj.typedMem(nogc)); } static const ClassOps SimdTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */
--- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -544,24 +544,24 @@ class TypedObject : public ShapedObject } TypeDescr& typeDescr() const { return group()->typeDescr(); } int32_t offset() const; int32_t length() const; - uint8_t* typedMem(const JS::AutoAssertOnGC&) const { return typedMem(); } + uint8_t* typedMem(const JS::AutoRequireNoGC&) const { return typedMem(); } bool isAttached() const; int32_t size() const { return typeDescr().size(); } - uint8_t* typedMem(size_t offset, const JS::AutoAssertOnGC& nogc) const { + uint8_t* typedMem(size_t offset, const JS::AutoRequireNoGC& nogc) const { // It seems a bit surprising that one might request an offset // == size(), but it can happen when taking the "address of" a // 0-sized value. (In other words, we maintain the invariant // that `offset + size <= size()` -- this is always checked in // the caller's side.) MOZ_ASSERT(offset <= (size_t) size()); return typedMem(nogc) + offset; } @@ -699,17 +699,17 @@ class InlineTypedObject : public TypedOb static gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr) { size_t nbytes = descr->size(); MOZ_ASSERT(nbytes <= MaximumSize); return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject)); } - uint8_t* inlineTypedMem(const JS::AutoAssertOnGC&) const { + uint8_t* inlineTypedMem(const JS::AutoRequireNoGC&) const { return inlineTypedMem(); } uint8_t* inlineTypedMemForGC() const { return inlineTypedMem(); } static void obj_trace(JSTracer* trace, JSObject* object);
--- a/js/src/gc/Allocator.cpp +++ b/js/src/gc/Allocator.cpp @@ -198,17 +198,17 @@ GCRuntime::checkAllocatorState(JSContext kind == AllocKind::JITCODE || kind == AllocKind::SCOPE); MOZ_ASSERT(!rt->isHeapBusy()); MOZ_ASSERT(isAllocAllowed()); #endif // Crash if we perform a GC action when it is not safe. if (allowGC && !rt->mainThread.suppressGC) - JS::AutoAssertOnGC::VerifyIsSafeToGC(rt); + rt->gc.verifyIsSafeToGC(); // For testing out of memory conditions if (js::oom::ShouldFailWithOOM()) { // If we are doing a fallible allocation, percolate up the OOM // instead of reporting it. if (allowGC) ReportOutOfMemory(cx); return false;
--- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -19,16 +19,17 @@ #include "gc/StoreBuffer.h" #include "gc/Tracer.h" #include "js/GCAnnotations.h" namespace js { class AutoLockGC; class AutoLockHelperThreadState; +class SliceBudget; class VerifyPreTracer; namespace gc { typedef Vector<JS::Zone*, 4, SystemAllocPolicy> ZoneVector; using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>; class AutoMaybeStartBackgroundAllocation; @@ -716,30 +717,35 @@ class GCRuntime bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; } void disallowNurseryAlloc() { ++noNurseryAllocationCheck; } void allowNurseryAlloc() { MOZ_ASSERT(!isNurseryAllocAllowed()); --noNurseryAllocationCheck; } + bool isStrictProxyCheckingEnabled() { return disableStrictProxyCheckingCount == 0; } + void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; } + void enableStrictProxyChecking() { + MOZ_ASSERT(disableStrictProxyCheckingCount > 0); + --disableStrictProxyCheckingCount; + } +#endif // DEBUG + bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; } void enterUnsafeRegion() { ++inUnsafeRegion; } void leaveUnsafeRegion() { MOZ_ASSERT(inUnsafeRegion > 0); --inUnsafeRegion; } - bool isStrictProxyCheckingEnabled() { return disableStrictProxyCheckingCount == 0; } - void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; } - void enableStrictProxyChecking() { - MOZ_ASSERT(disableStrictProxyCheckingCount > 0); - --disableStrictProxyCheckingCount; + void verifyIsSafeToGC() { + MOZ_DIAGNOSTIC_ASSERT(!isInsideUnsafeRegion(), + "[AutoAssertOnGC] possible GC in GC-unsafe region"); } -#endif // DEBUG void setAlwaysPreserveCode() { alwaysPreserveCode = true; } bool isIncrementalGCAllowed() const { return incrementalAllowed; } void disallowIncrementalGC() { incrementalAllowed = false; } bool isIncrementalGCEnabled() const { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; } bool isIncrementalGCInProgress() const { return state() != State::NotActive; } @@ -853,16 +859,29 @@ class GCRuntime void startVerifyPreBarriers(); void endVerifyPreBarriers(); void finishVerifier(); bool isVerifyPreBarriersEnabled() const { return !!verifyPreData; } #else bool isVerifyPreBarriersEnabled() const { return false; } #endif + // GC interrupt callbacks. + bool addInterruptCallback(JS::GCInterruptCallback callback); + void requestInterruptCallback(); + + bool checkInterruptCallback(JSContext* cx) { + if (interruptCallbackRequested) { + invokeInterruptCallback(cx); + return true; + } + return false; + } + void invokeInterruptCallback(JSContext* cx); + // Free certain LifoAlloc blocks when it is safe to do so. void freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo); void freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo); void freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo); // Queue a thunk to run after the next minor GC. void callAfterMinorGC(void (*thunk)(void* data), void* data) { nursery.queueSweepAction(thunk, data); @@ -1065,16 +1084,23 @@ class GCRuntime mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_; /* * Number of the committed arenas in all GC chunks including empty chunks. */ mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted; VerifyPreTracer* verifyPreData; + // GC interrupt callbacks. + using GCInterruptCallbackVector = js::Vector<JS::GCInterruptCallback, 2, js::SystemAllocPolicy>; + GCInterruptCallbackVector interruptCallbacks; + + mozilla::Atomic<bool, mozilla::Relaxed> interruptCallbackRequested; + SliceBudget* currentBudget; + private: bool chunkAllocationSinceLastGC; int64_t lastGCTime; JSGCMode mode; mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters; @@ -1339,25 +1365,25 @@ class GCRuntime * collector. */ CallbackVector<JSTraceDataOp> blackRootTracers; Callback<JSTraceDataOp> grayRootTracer; /* Always preserve JIT code during GCs, for testing. */ bool alwaysPreserveCode; -#ifdef DEBUG /* * Some regions of code are hard for the static rooting hazard analysis to * understand. In those cases, we trade the static analysis for a dynamic * analysis. When this is non-zero, we should assert if we trigger, or * might trigger, a GC. */ int inUnsafeRegion; +#ifdef DEBUG size_t noGCOrAllocationCheck; size_t noNurseryAllocationCheck; bool arenasEmptyAtShutdown; #endif /* Synchronize GC heap access between main thread and GCHelperState. */ friend class js::AutoLockGC;
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1540,23 +1540,25 @@ bool GCMarker::drainMarkStack(SliceBudget& budget) { #ifdef DEBUG MOZ_ASSERT(!strictCompartmentChecking); strictCompartmentChecking = true; auto acc = mozilla::MakeScopeExit([&] {strictCompartmentChecking = false;}); #endif - if (budget.isOverBudget()) + JSContext* cx = runtime()->contextFromMainThread(); + + if (budget.isOverBudget(cx)) return false; for (;;) { while (!stack.isEmpty()) { processMarkStackTop(budget); - if (budget.isOverBudget()) { + if (budget.isOverBudget(cx)) { saveValueRanges(); return false; } } if (!hasDelayedChildren()) break; @@ -1621,16 +1623,18 @@ GCMarker::processMarkStackTop(SliceBudge HeapSlot* end; JSObject* obj; // Decode uintptr_t addr = stack.pop(); uintptr_t tag = addr & StackTagMask; addr &= ~StackTagMask; + JSContext* cx = runtime()->contextFromMainThread(); + // Dispatch switch (tag) { case ValueArrayTag: { JS_STATIC_ASSERT(ValueArrayTag == 0); MOZ_ASSERT(!(addr & CellMask)); obj = reinterpret_cast<JSObject*>(addr); uintptr_t addr2 = stack.pop(); uintptr_t addr3 = stack.pop(); @@ -1674,17 +1678,17 @@ GCMarker::processMarkStackTop(SliceBudge default: MOZ_CRASH("Invalid tag in mark stack"); } return; scan_value_array: MOZ_ASSERT(vp <= end); while (vp != end) { budget.step(); - if (budget.isOverBudget()) { + if (budget.isOverBudget(cx)) { pushValueArray(obj, vp, end); return; } const Value& v = *vp++; if (v.isString()) { traverseEdge(obj, v.toString()); } else if (v.isObject()) { @@ -1704,17 +1708,17 @@ GCMarker::processMarkStackTop(SliceBudge } return; scan_obj: { AssertZoneIsMarking(obj); budget.step(); - if (budget.isOverBudget()) { + if (budget.isOverBudget(cx)) { repush(obj); return; } markImplicitEdges(obj); ObjectGroup* group = obj->groupFromGC(); traverseEdge(obj, group); @@ -2152,17 +2156,17 @@ GCMarker::markDelayedChildren(SliceBudge unmarkedArenaStackTop = arena->getNextDelayedMarking(); arena->unsetDelayedMarking(); #ifdef DEBUG markLaterArenas--; #endif markDelayedChildren(arena); budget.step(150); - if (budget.isOverBudget()) + if (budget.isOverBudget(runtime()->contextFromMainThread())) return false; } while (unmarkedArenaStackTop); MOZ_ASSERT(!markLaterArenas); return true; } template<typename T>
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -183,16 +183,17 @@ #include "jsgcinlines.h" #include "mozilla/ArrayUtils.h" #include "mozilla/DebugOnly.h" #include "mozilla/MacroForEach.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/ScopeExit.h" #include <ctype.h> #include <string.h> #ifndef XP_WIN # include <sys/mman.h> # include <unistd.h> #endif @@ -501,30 +502,32 @@ FinalizeTypedArenas(FreeOp* fop, // During background sweeping free arenas are released later on in // sweepBackgroundThings(). MOZ_ASSERT_IF(!fop->onMainThread(), keepArenas == ArenaLists::KEEP_ARENAS); size_t thingSize = Arena::thingSize(thingKind); size_t thingsPerArena = Arena::thingsPerArena(thingKind); + JSContext* cx = fop->onMainThread() ? fop->runtime()->contextFromMainThread() : nullptr; + while (Arena* arena = *src) { *src = arena->next; size_t nmarked = arena->finalize<T>(fop, thingKind, thingSize); size_t nfree = thingsPerArena - nmarked; if (nmarked) dest.insertAt(arena, nfree); else if (keepArenas == ArenaLists::KEEP_ARENAS) arena->chunk()->recycleArena(arena, dest, thingsPerArena); else fop->runtime()->gc.releaseArena(arena, maybeLock.ref()); budget.step(thingsPerArena); - if (budget.isOverBudget()) + if (budget.isOverBudget(cx)) return false; } return true; } /* * Finalize the list. On return, |al|'s cursor points to the first non-empty @@ -803,16 +806,18 @@ GCRuntime::GCRuntime(JSRuntime* rt) : stats(rt), marker(rt), usage(nullptr), mMemProfiler(rt), maxMallocBytes(0), nextCellUniqueId_(LargestTaggedNullCellPointer + 1), // Ensure disjoint from null tagged pointers. numArenasFreeCommitted(0), verifyPreData(nullptr), + interruptCallbackRequested(false), + currentBudget(nullptr), chunkAllocationSinceLastGC(false), lastGCTime(PRMJ_Now()), mode(JSGC_MODE_INCREMENTAL), numActiveZoneIters(0), cleanUpEverything(false), grayBufferState(GCRuntime::GrayBufferState::Unused), grayBitsValid(false), majorGCTriggerReason(JS::gcreason::NO_REASON), @@ -859,18 +864,18 @@ GCRuntime::GCRuntime(JSRuntime* rt) : nextScheduled(0), deterministicOnly(false), incrementalLimit(0), #endif fullCompartmentChecks(false), mallocBytesUntilGC(0), mallocGCTriggered(false), alwaysPreserveCode(false), + inUnsafeRegion(0), #ifdef DEBUG - inUnsafeRegion(0), noGCOrAllocationCheck(0), noNurseryAllocationCheck(0), arenasEmptyAtShutdown(true), #endif allocTask(rt, emptyChunks_), decommitTask(rt), helperState(rt) { @@ -2928,18 +2933,21 @@ SliceBudget::describe(char* buffer, size return snprintf(buffer, maxlen, "unlimited"); else if (isWorkBudget()) return snprintf(buffer, maxlen, "work(%" PRId64 ")", workBudget.budget); else return snprintf(buffer, maxlen, "%" PRId64 "ms", timeBudget.budget); } bool -SliceBudget::checkOverBudget() -{ +SliceBudget::checkOverBudget(JSContext* cx) +{ + if (cx) + cx->gc.checkInterruptCallback(cx); + bool over = PRMJ_Now() >= deadline; if (!over) counter = CounterReset; return over; } void js::MarkCompartmentActive(InterpreterFrame* fp) @@ -5476,17 +5484,17 @@ GCRuntime::compactPhase(JS::gcreason::Re Zone* zone = zonesToMaybeCompact.front(); MOZ_ASSERT(zone->isGCFinished()); zone->setGCState(Zone::Compact); if (relocateArenas(zone, reason, relocatedArenas, sliceBudget)) updatePointersToRelocatedCells(zone, lock); zone->setGCState(Zone::Finished); zonesToMaybeCompact.removeFront(); - if (sliceBudget.isOverBudget()) + if (sliceBudget.isOverBudget(rt->contextFromMainThread())) break; } if (ShouldProtectRelocatedArenas(reason)) protectAndHoldArenas(relocatedArenas); else releaseRelocatedArenas(relocatedArenas); @@ -5882,17 +5890,17 @@ GCRuntime::incrementalCollectSlice(Slice incrementalState = State::Sweep; /* * This runs to completion, but we don't continue if the budget is * now exhasted. */ beginSweepPhase(destroyingRuntime, lock); - if (budget.isOverBudget()) + if (budget.isOverBudget(rt->contextFromMainThread())) break; /* * Always yield here when running in incremental multi-slice zeal * mode, so RunDebugGC can reset the slice buget. */ if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalMultipleSlices)) break; @@ -6128,17 +6136,17 @@ GCRuntime::gcCycle(bool nonincrementalBy if (!isIncrementalGCInProgress()) incMajorGcNumber(); // It's ok if threads other than the main thread have suppressGC set, as // they are operating on zones which will not be collected from here. MOZ_ASSERT(!rt->mainThread.suppressGC); // Assert if this is a GC unsafe region. - JS::AutoAssertOnGC::VerifyIsSafeToGC(rt); + verifyIsSafeToGC(); { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); // Background finalization and decommit are finished by defininition // before we can start a new GC session. if (!isIncrementalGCInProgress()) { assertBackgroundSweepingFinished(); @@ -6289,16 +6297,21 @@ GCRuntime::collect(bool nonincrementalBy { // Checks run for each request, even if we do not actually GC. checkCanCallAPI(); // Check if we are allowed to GC at this time before proceeding. if (!checkIfGCAllowedInCurrentState(reason)) return; + currentBudget = &budget; + auto guard = mozilla::MakeScopeExit([&] { + currentBudget = nullptr; + }); + AutoTraceLog logGC(TraceLoggerForMainThread(rt), TraceLogger_GC); AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason)); AutoEnqueuePendingParseTasksAfterGC aept(*this); AutoScheduleZonesForGC asz(rt); bool repeat = false; do { poked = false; @@ -6969,17 +6982,16 @@ JS::GetGCNumber() { JSRuntime* rt = js::TlsPerThreadData.get()->runtimeFromMainThread(); if (!rt) return 0; return rt->gc.gcNumber(); } #endif -#ifdef DEBUG JS::AutoAssertOnGC::AutoAssertOnGC() : gc(nullptr), gcNumber(0) { js::PerThreadData* data = js::TlsPerThreadData.get(); if (data) { /* * GC's from off-thread will always assert, so off-thread is implicitly * AutoAssertOnGC. We still need to allow AutoAssertOnGC to be used in @@ -7009,23 +7021,30 @@ JS::AutoAssertOnGC::~AutoAssertOnGC() /* * The following backstop assertion should never fire: if we bumped the * gcNumber, we should have asserted because inUnsafeRegion was true. */ MOZ_ASSERT(gcNumber == gc->gcNumber(), "GC ran inside an AutoAssertOnGC scope."); } } -/* static */ void -JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime* rt) -{ - if (rt->gc.isInsideUnsafeRegion()) - MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region"); -} - +JS::AutoAssertOnBarrier::AutoAssertOnBarrier(JSContext* cx) + : context(cx), + prev(cx->runtime()->allowGCBarriers()) +{ + context->runtime()->allowGCBarriers_ = false; +} + +JS::AutoAssertOnBarrier::~AutoAssertOnBarrier() +{ + MOZ_ASSERT(!context->runtime()->allowGCBarriers_); + context->runtime()->allowGCBarriers_ = prev; +} + +#ifdef DEBUG JS::AutoAssertNoAlloc::AutoAssertNoAlloc(JSContext* cx) : gc(nullptr) { disallowAlloc(cx); } void JS::AutoAssertNoAlloc::disallowAlloc(JSRuntime* rt) { @@ -7657,8 +7676,46 @@ js::gc::Cell::dump(FILE* fp) const // For use in a debugger. void js::gc::Cell::dump() const { dump(stderr); } #endif + +bool +JS::AddGCInterruptCallback(JSContext* cx, GCInterruptCallback callback) +{ + return cx->runtime()->gc.addInterruptCallback(callback); +} + +void +JS::RequestGCInterruptCallback(JSContext* cx) +{ + cx->runtime()->gc.requestInterruptCallback(); +} + +bool +GCRuntime::addInterruptCallback(JS::GCInterruptCallback callback) +{ + return interruptCallbacks.append(callback); +} + +void +GCRuntime::requestInterruptCallback() +{ + if (currentBudget) { + interruptCallbackRequested = true; + currentBudget->requestFullCheck(); + } +} + +void +GCRuntime::invokeInterruptCallback(JSContext* cx) +{ + JS::AutoAssertOnGC nogc(cx); + JS::AutoAssertOnBarrier nobarrier(cx); + JS::AutoSuppressGCAnalysis suppress; + for (JS::GCInterruptCallback callback : interruptCallbacks) { + (*callback)(cx); + } +}
--- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -126,16 +126,17 @@ namespace gc { class AutoTraceSession; class StoreBuffer; } // namespace gc } // namespace js namespace JS { class JS_PUBLIC_API(AutoEnterCycleCollection); +class JS_PUBLIC_API(AutoAssertOnBarrier); struct PropertyDescriptor; typedef void (*OffThreadCompileCallback)(void* token, void* callbackData); enum class HeapState { Idle, // doing nothing with the GC heap Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() MajorCollecting, // doing a GC of the major heap @@ -148,32 +149,40 @@ namespace shadow { struct Runtime { protected: // Allow inlining of heapState checks. friend class js::gc::AutoTraceSession; friend class JS::AutoEnterCycleCollection; JS::HeapState heapState_; + // In some cases, invoking GC barriers (incremental or otherwise) will break + // things. These barriers assert if this flag is set. + bool allowGCBarriers_; + friend class JS::AutoAssertOnBarrier; + js::gc::StoreBuffer* gcStoreBufferPtr_; public: Runtime() : heapState_(JS::HeapState::Idle) + , allowGCBarriers_(true) , gcStoreBufferPtr_(nullptr) {} bool isHeapBusy() const { return heapState_ != JS::HeapState::Idle; } bool isHeapMajorCollecting() const { return heapState_ == JS::HeapState::MajorCollecting; } bool isHeapMinorCollecting() const { return heapState_ == JS::HeapState::MinorCollecting; } bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); } bool isCycleCollecting() const { return heapState_ == JS::HeapState::CycleCollecting; } + bool allowGCBarriers() const { return allowGCBarriers_; } + js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; } static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) { return reinterpret_cast<JS::shadow::Runtime*>(rt); } protected: void setGCStoreBufferPtr(js::gc::StoreBuffer* storeBuffer) {
--- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1493,17 +1493,17 @@ ArrayBufferViewObject::notifyBufferDetac return; as<TypedArrayObject>().notifyBufferDetached(cx, newData); } else { as<OutlineTypedObject>().notifyBufferDetached(newData); } } uint8_t* -ArrayBufferViewObject::dataPointerUnshared(const JS::AutoAssertOnGC& nogc) +ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc) { if (is<DataViewObject>()) return static_cast<uint8_t*>(as<DataViewObject>().dataPointer()); if (is<TypedArrayObject>()) { MOZ_ASSERT(!as<TypedArrayObject>().isSharedMemory()); return static_cast<uint8_t*>(as<TypedArrayObject>().viewDataUnshared()); } return as<TypedObject>().typedMem(nogc);
--- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -435,17 +435,17 @@ class ArrayBufferViewObject : public JSO void notifyBufferDetached(JSContext* cx, void* newData); #ifdef DEBUG bool isSharedMemory(); #endif // By construction we only need unshared variants here. See // comments in ArrayBufferObject.cpp. - uint8_t* dataPointerUnshared(const JS::AutoAssertOnGC&); + uint8_t* dataPointerUnshared(const JS::AutoRequireNoGC&); void setDataPointerUnshared(uint8_t* data); static void trace(JSTracer* trc, JSObject* obj); }; bool ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out);
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -358,17 +358,17 @@ ExecuteState::pushInterpreterFrame(JSCon # pragma optimize("g", off) #endif bool js::RunScript(JSContext* cx, RunState& state) { JS_CHECK_RECURSION(cx, return false); // Since any script can conceivably GC, make sure it's safe to do so. - JS::AutoAssertOnGC::VerifyIsSafeToGC(cx->runtime()); + cx->runtime()->gc.verifyIsSafeToGC(); if (!Debugger::checkNoExecute(cx, state.script())) return false; #if defined(MOZ_HAVE_RDTSC) js::AutoStopwatch stopwatch(cx); #endif // defined(MOZ_HAVE_RDTSC)
--- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -374,24 +374,20 @@ nsFileControlFrame::DnDListener::GetBlob bool nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDataTransfer* aDOMDataTransfer) { nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer); NS_ENSURE_TRUE(dataTransfer, false); // We only support dropping files onto a file upload control - ErrorResult rv; - RefPtr<DOMStringList> types = dataTransfer->GetTypes(rv); - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - return false; - } + nsTArray<nsString> types; + dataTransfer->GetTypes(types, *nsContentUtils::GetSystemPrincipal()); - return types->Contains(NS_LITERAL_STRING("Files")); + return types.Contains(NS_LITERAL_STRING("Files")); } bool nsFileControlFrame::DnDListener::CanDropTheseFiles(nsIDOMDataTransfer* aDOMDataTransfer, bool aSupportsMultiple) { nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer); NS_ENSURE_TRUE(dataTransfer, false);
--- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -1621,22 +1621,20 @@ void CSSStyleSheet::DidDirty() { MOZ_ASSERT(!mInner->mComplete || mDirty, "caller must have called WillDirty()"); ClearRuleCascades(); } void -CSSStyleSheet::SubjectSubsumesInnerPrincipal(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +CSSStyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { - MOZ_ASSERT(aSubjectPrincipal.isSome()); - - if (aSubjectPrincipal.value()->Subsumes(mInner->mPrincipal)) { + if (aSubjectPrincipal.Subsumes(mInner->mPrincipal)) { return; } // Allow access only if CORS mode is not NONE if (GetCORSMode() == CORS_NONE) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } @@ -1654,17 +1652,17 @@ CSSStyleSheet::SubjectSubsumesInnerPrinc // anyway if not complete, so we can just do that here too. if (!mInner->mComplete) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } WillDirty(); - mInner->mPrincipal = aSubjectPrincipal.value(); + mInner->mPrincipal = &aSubjectPrincipal; DidDirty(); } nsresult CSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule) { if (!mInner->mNameSpaceMap) { @@ -1777,23 +1775,23 @@ CSSStyleSheet::GetDOMOwnerRule() const return mOwnerRule ? mOwnerRule->GetDOMRule() : nullptr; } NS_IMETHODIMP CSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules) { ErrorResult rv; nsCOMPtr<nsIDOMCSSRuleList> rules = - GetCssRules(Some(nsContentUtils::SubjectPrincipal()), rv); + GetCssRules(*nsContentUtils::SubjectPrincipal(), rv); rules.forget(aCssRules); return rv.StealNSResult(); } CSSRuleList* -CSSStyleSheet::GetCssRules(const Maybe<nsIPrincipal*>& aSubjectPrincipal, +CSSStyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { // No doing this on incomplete sheets! if (!mInner->mComplete) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return nullptr; } @@ -1814,23 +1812,23 @@ CSSStyleSheet::GetCssRules(const Maybe<n NS_IMETHODIMP CSSStyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex, uint32_t* aReturn) { ErrorResult rv; *aReturn = - InsertRule(aRule, aIndex, Some(nsContentUtils::SubjectPrincipal()), rv); + InsertRule(aRule, aIndex, *nsContentUtils::SubjectPrincipal(), rv); return rv.StealNSResult(); } uint32_t CSSStyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { //-- Security check: Only scripts whose principal subsumes that of the // style sheet can modify rule collections. SubjectSubsumesInnerPrincipal(aSubjectPrincipal, aRv); if (NS_WARN_IF(aRv.Failed())) { return 0; } @@ -1972,23 +1970,23 @@ CSSStyleSheet::InsertRuleInternal(const return aIndex; } NS_IMETHODIMP CSSStyleSheet::DeleteRule(uint32_t aIndex) { ErrorResult rv; - DeleteRule(aIndex, Some(nsContentUtils::SubjectPrincipal()), rv); + DeleteRule(aIndex, *nsContentUtils::SubjectPrincipal(), rv); return rv.StealNSResult(); } void CSSStyleSheet::DeleteRule(uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { // No doing this if the sheet is not complete! if (!mInner->mComplete) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; }
--- a/layout/style/CSSStyleSheet.h +++ b/layout/style/CSSStyleSheet.h @@ -241,24 +241,24 @@ public: bool Disabled() const { return mDisabled; } // The XPCOM SetDisabled is fine for WebIDL // WebIDL CSSStyleSheet API // Can't be inline because we can't include ImportRule here. And can't be // called GetOwnerRule because that would be ambiguous with the ImportRule // version. nsIDOMCSSRule* GetDOMOwnerRule() const; - dom::CSSRuleList* GetCssRules(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); void DeleteRule(uint32_t aIndex, - const Maybe<nsIPrincipal*>& aSubjectPrincipal, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); // WebIDL miscellaneous bits dom::ParentObject GetParentObject() const { if (mOwningNode) { return dom::ParentObject(mOwningNode); } @@ -286,17 +286,17 @@ protected: virtual ~CSSStyleSheet(); void ClearRuleCascades(); // Return success if the subject principal subsumes the principal of our // inner, error otherwise. This will also succeed if the subject has // UniversalXPConnect or if access is allowed by CORS. In the latter case, // it will set the principal of the inner to the subject principal. - void SubjectSubsumesInnerPrincipal(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); // Add the namespace mapping from this @namespace rule to our namespace map nsresult RegisterNamespaceRule(css::Rule* aRule); // Drop our reference to mRuleCollection void DropRuleCollection();
--- a/layout/style/ServoBindingList.h +++ b/layout/style/ServoBindingList.h @@ -33,23 +33,23 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_AddR RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSheet_Release, void, RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool, RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned) SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set) SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void, - RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet) + RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void, - RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet) + RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void, - RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet) + RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet) SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void, - RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet, + RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet, RawServoStyleSheetBorrowed reference) // Animations API SERVO_BINDING_FUNC(Servo_ParseProperty, ServoDeclarationBlockStrong, const uint8_t* property_bytes, uint32_t property_length, const uint8_t* value_bytes, @@ -91,22 +91,22 @@ SERVO_BINDING_FUNC(Servo_CSSSupports, bo const uint8_t* value, uint32_t value_length) // Computed style data SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong, RawGeckoNodeBorrowed node) SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox, ServoComputedValuesStrong, ServoComputedValuesBorrowedOrNull parent_style_or_null, - nsIAtom* pseudoTag, RawServoStyleSetBorrowedMut set) + nsIAtom* pseudoTag, RawServoStyleSetBorrowed set) SERVO_BINDING_FUNC(Servo_ComputedValues_GetForPseudoElement, ServoComputedValuesStrong, ServoComputedValuesBorrowed parent_style, RawGeckoElementBorrowed match_element, nsIAtom* pseudo_tag, - RawServoStyleSetBorrowedMut set, bool is_probe) + RawServoStyleSetBorrowed set, bool is_probe) SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong, ServoComputedValuesBorrowedOrNull parent_style) SERVO_BINDING_FUNC(Servo_ComputedValues_AddRef, void, ServoComputedValuesBorrowed computed_values) SERVO_BINDING_FUNC(Servo_ComputedValues_Release, void, ServoComputedValuesBorrowed computed_values) // Initialize Servo components. Should be called exactly once at startup. @@ -116,17 +116,17 @@ SERVO_BINDING_FUNC(Servo_Shutdown, void) // Restyle hints SERVO_BINDING_FUNC(Servo_ComputeRestyleHint, nsRestyleHint, RawGeckoElementBorrowed element, ServoElementSnapshot* snapshot, RawServoStyleSetBorrowed set) // Restyle the given subtree. SERVO_BINDING_FUNC(Servo_RestyleSubtree, void, - RawGeckoNodeBorrowed node, RawServoStyleSetBorrowedMut set) + RawGeckoNodeBorrowed node, RawServoStyleSetBorrowed set) // Style-struct management. #define STYLE_STRUCT(name, checkdata_cb) \ struct nsStyle##name; \ SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*, \ ServoComputedValuesBorrowedOrNull computed_values) #include "nsStyleStructList.h" #undef STYLE_STRUCT
--- a/netwerk/protocol/http/nsHttpHeaderArray.h +++ b/netwerk/protocol/http/nsHttpHeaderArray.h @@ -105,33 +105,45 @@ public: uint32_t Count() const { return mHeaders.Length(); } const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header) const; void Clear(); // Must be copy-constructable and assignable +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) +#pragma pack(1) +#endif struct nsEntry { nsHttpAtom header; +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) + char padding[4096 - + sizeof(nsTArrayHeader) - + sizeof(nsHttpAtom) - + sizeof(void*)]; +#endif nsCString value; HeaderVariety variety = eVarietyUnknown; struct MatchHeader { bool Equals(const nsEntry &aEntry, const nsHttpAtom &aHeader) const { return aEntry.header == aHeader; } }; bool operator==(const nsEntry& aOther) const { return header == aOther.header && value == aOther.value; } }; +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) +#pragma pack() +#endif bool operator==(const nsHttpHeaderArray& aOther) const { return mHeaders == aOther.mHeaders; } private: // LookupEntry function will never return eVarietyResponseNetOriginal.
--- a/netwerk/protocol/http/nsHttpRequestHead.cpp +++ b/netwerk/protocol/http/nsHttpRequestHead.cpp @@ -11,29 +11,57 @@ //----------------------------------------------------------------------------- // nsHttpRequestHead //----------------------------------------------------------------------------- namespace mozilla { namespace net { +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) +void nsHttpRequestHead::DbgReentrantMonitorAutoEnter::Protect(bool aOn) +{ + if (XRE_GetProcessType() == GeckoProcessType_Content && + mInst.mHeaders.Count()) { + DWORD oldProtect; + LPVOID hdr = reinterpret_cast<PUINT8>(mInst.mHeaders.mHeaders.Elements()) - + sizeof(nsTArrayHeader); + if (aOn) { + VirtualProtect(hdr, 4096, PAGE_READONLY, &oldProtect); + } else { + VirtualProtect(hdr, 4096, PAGE_READWRITE, &oldProtect); + } + } +} + +#define ReentrantMonitorAutoEnter DbgReentrantMonitorAutoEnter +#define mon(x) mon(*this) +#endif + nsHttpRequestHead::nsHttpRequestHead() : mMethod(NS_LITERAL_CSTRING("GET")) , mVersion(NS_HTTP_VERSION_1_1) , mParsedMethod(kMethod_Get) , mHTTPS(false) , mReentrantMonitor("nsHttpRequestHead.mReentrantMonitor") , mInVisitHeaders(false) { MOZ_COUNT_CTOR(nsHttpRequestHead); } nsHttpRequestHead::~nsHttpRequestHead() { +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) + if (XRE_GetProcessType() == GeckoProcessType_Content && mHeaders.Count()) { + DWORD oldProtect; + LPVOID hdr = reinterpret_cast<PUINT8>(mHeaders.mHeaders.Elements()) - + sizeof(nsTArrayHeader); + VirtualProtect(hdr, 4096, PAGE_READWRITE, &oldProtect); + } +#endif MOZ_COUNT_DTOR(nsHttpRequestHead); } // Don't use this function. It is only used by HttpChannelParent to avoid // copying of request headers!!! const nsHttpHeaderArray & nsHttpRequestHead::Headers() const { @@ -360,10 +388,15 @@ nsHttpRequestHead::Flatten(nsACString &b buf.AppendLiteral("1.0"); } buf.AppendLiteral("\r\n"); mHeaders.Flatten(buf, pruneProxyHeaders, false); } +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) +#undef ReentrantMonitorAutoEnter +#undef mon +#endif + } // namespace net } // namespace mozilla
--- a/netwerk/protocol/http/nsHttpRequestHead.h +++ b/netwerk/protocol/http/nsHttpRequestHead.h @@ -115,14 +115,36 @@ private: bool mHTTPS; // We are using ReentrantMonitor instead of a Mutex because VisitHeader // function calls nsIHttpHeaderVisitor::VisitHeader while under lock. ReentrantMonitor mReentrantMonitor; // During VisitHeader we sould not allow cal to SetHeader. bool mInVisitHeaders; + +#if defined(XP_WIN) && (defined(_M_IX86) || defined(_M_X64)) + class DbgReentrantMonitorAutoEnter : ReentrantMonitorAutoEnter + { + public: + explicit DbgReentrantMonitorAutoEnter(nsHttpRequestHead& aInst) + : ReentrantMonitorAutoEnter(aInst.mReentrantMonitor), + mInst(aInst) + { + Protect(false); + } + ~DbgReentrantMonitorAutoEnter(void) + { + Protect(true); + } + + private: + void Protect(bool aOn); + + nsHttpRequestHead& mInst; + }; +#endif }; } // namespace net } // namespace mozilla #endif // nsHttpRequestHead_h__
--- a/toolkit/components/viewsource/content/viewSource.js +++ b/toolkit/components/viewsource/content/viewSource.js @@ -510,17 +510,17 @@ ViewSourceChrome.prototype = { /** * Called when the user drags something over the content browser. */ onDragOver(event) { // For drags that appear to be internal text (for example, tab drags), // set the dropEffect to 'none'. This prevents the drop even if some // other listener cancelled the event. let types = event.dataTransfer.types; - if (types.contains("text/x-moz-text-internal") && !types.contains("text/plain")) { + if (types.includes("text/x-moz-text-internal") && !types.includes("text/plain")) { event.dataTransfer.dropEffect = "none"; event.stopPropagation(); event.preventDefault(); } let linkHandler = Cc["@mozilla.org/content/dropped-link-handler;1"] .getService(Ci.nsIDroppedLinkHandler);
--- a/toolkit/content/customizeToolbar.js +++ b/toolkit/content/customizeToolbar.js @@ -650,17 +650,17 @@ function onToolbarDragStart(aEvent) function onToolbarDragOver(aEvent) { if (isUnwantedDragEvent(aEvent)) { return; } var documentId = gToolboxDocument.documentElement.id; - if (!aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/" + documentId.toLowerCase())) + if (!aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase())) return; var toolbar = aEvent.target; var dropTarget = aEvent.target; while (toolbar && toolbar.localName != "toolbar") { dropTarget = toolbar; toolbar = toolbar.parentNode; } @@ -779,17 +779,17 @@ function onToolbarDrop(aEvent) } function onPaletteDragOver(aEvent) { if (isUnwantedDragEvent(aEvent)) { return; } var documentId = gToolboxDocument.documentElement.id; - if (aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/" + documentId.toLowerCase())) + if (aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase())) aEvent.preventDefault(); } function onPaletteDrop(aEvent) { if (isUnwantedDragEvent(aEvent)) { return; }
--- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -1440,17 +1440,17 @@ <![CDATA[ if (!this.droppedLinkHandler || event.defaultPrevented) return; // For drags that appear to be internal text (for example, tab drags), // set the dropEffect to 'none'. This prevents the drop even if some // other listener cancelled the event. var types = event.dataTransfer.types; - if (types.contains("text/x-moz-text-internal") && !types.contains("text/plain")) { + if (types.includes("text/x-moz-text-internal") && !types.includes("text/plain")) { event.dataTransfer.dropEffect = "none"; event.stopPropagation(); event.preventDefault(); } // No need to handle "dragover" in e10s, since nsDocShellTreeOwner.cpp in the child process // handles that case using "@mozilla.org/content/dropped-link-handler;1" service. if (this.isRemoteBrowser)
--- a/toolkit/content/widgets/findbar.xml +++ b/toolkit/content/widgets/findbar.xml @@ -134,17 +134,17 @@ <handler event="compositionend"><![CDATA[ let findbar = this.findbar; findbar._isIMEComposing = false; if (findbar._findMode != findbar.FIND_NORMAL) findbar._setFindCloseTimeout(); ]]></handler> <handler event="dragover"><![CDATA[ - if (event.dataTransfer.types.contains("text/plain")) + if (event.dataTransfer.types.includes("text/plain")) event.preventDefault(); ]]></handler> <handler event="drop"><![CDATA[ let value = event.dataTransfer.getData("text/plain"); this.value = value; this.findbar._find(value); event.stopPropagation();
--- a/toolkit/mozapps/downloads/content/downloads.js +++ b/toolkit/mozapps/downloads/content/downloads.js @@ -656,19 +656,19 @@ var gDownloadDNDObserver = dt.setData("text/plain", url); dt.effectAllowed = "copyMove"; dt.addElement(dl); }, onDragOver: function (aEvent) { var types = aEvent.dataTransfer.types; - if (types.contains("text/uri-list") || - types.contains("text/x-moz-url") || - types.contains("text/plain")) + if (types.includes("text/uri-list") || + types.includes("text/x-moz-url") || + types.includes("text/plain")) aEvent.preventDefault(); }, onDrop: function(aEvent) { var dt = aEvent.dataTransfer; // If dragged item is from our source, do not try to // redownload already downloaded file.
--- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -3815,19 +3815,19 @@ var gUpdatesView = { if (aProperties.indexOf("applyBackgroundUpdates") != -1) this.updateAvailableCount(); } }; var gDragDrop = { onDragOver: function(aEvent) { var types = aEvent.dataTransfer.types; - if (types.contains("text/uri-list") || - types.contains("text/x-moz-url") || - types.contains("application/x-moz-file")) + if (types.includes("text/uri-list") || + types.includes("text/x-moz-url") || + types.includes("application/x-moz-file")) aEvent.preventDefault(); }, onDrop: function(aEvent) { var dataTransfer = aEvent.dataTransfer; var urls = []; // Convert every dropped item into a url
--- a/widget/gtk/nsGtkKeyUtils.cpp +++ b/widget/gtk/nsGtkKeyUtils.cpp @@ -14,16 +14,17 @@ #include <gdk/gdk.h> #include <gdk/gdkx.h> #if (MOZ_WIDGET_GTK == 3) #include <gdk/gdkkeysyms-compat.h> #endif #include <X11/XKBlib.h> #include "WidgetUtils.h" #include "keysym2ucs.h" +#include "nsContentUtils.h" #include "nsGtkUtils.h" #include "nsIBidiKeyboard.h" #include "nsServiceManagerUtils.h" #include "mozilla/ArrayUtils.h" #include "mozilla/MouseEvents.h" #include "mozilla/TextEvents.h" @@ -36,17 +37,16 @@ LazyLogModule gKeymapWrapperLog("KeymapW ((('a' <= key) && (key <= 'z')) || (('A' <= key) && (key <= 'Z'))) #define MOZ_MODIFIER_KEYS "MozKeymapWrapper" KeymapWrapper* KeymapWrapper::sInstance = nullptr; guint KeymapWrapper::sLastRepeatableHardwareKeyCode = 0; KeymapWrapper::RepeatState KeymapWrapper::sRepeatState = KeymapWrapper::NOT_PRESSED; -nsIBidiKeyboard* sBidiKeyboard = nullptr; static const char* GetBoolName(bool aBool) { return aBool ? "TRUE" : "FALSE"; } /* static */ const char* KeymapWrapper::GetModifierName(Modifier aModifier) @@ -165,16 +165,18 @@ KeymapWrapper::KeymapWrapper() : { MOZ_LOG(gKeymapWrapperLog, LogLevel::Info, ("%p Constructor, mGdkKeymap=%p", this, mGdkKeymap)); g_object_ref(mGdkKeymap); g_signal_connect(mGdkKeymap, "keys-changed", (GCallback)OnKeysChanged, this); + g_signal_connect(mGdkKeymap, "direction-changed", + (GCallback)OnDirectionChanged, this); if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) InitXKBExtension(); Init(); } void @@ -437,18 +439,19 @@ KeymapWrapper::InitBySystemSettings() XFree(xkeymap); } KeymapWrapper::~KeymapWrapper() { gdk_window_remove_filter(nullptr, FilterEvents, this); g_signal_handlers_disconnect_by_func(mGdkKeymap, FuncToGpointer(OnKeysChanged), this); + g_signal_handlers_disconnect_by_func(mGdkKeymap, + FuncToGpointer(OnDirectionChanged), this); g_object_unref(mGdkKeymap); - NS_IF_RELEASE(sBidiKeyboard); MOZ_LOG(gKeymapWrapperLog, LogLevel::Info, ("%p Destructor", this)); } /* static */ GdkFilterReturn KeymapWrapper::FilterEvents(GdkXEvent* aXEvent, GdkEvent* aGdkEvent, gpointer aData) @@ -514,38 +517,62 @@ KeymapWrapper::FilterEvents(GdkXEvent* a } break; } } return GDK_FILTER_CONTINUE; } +static void +ResetBidiKeyboard() +{ + // Reset the bidi keyboard settings for the new GdkKeymap + nsCOMPtr<nsIBidiKeyboard> bidiKeyboard = nsContentUtils::GetBidiKeyboard(); + if (bidiKeyboard) { + bidiKeyboard->Reset(); + } + WidgetUtils::SendBidiKeyboardInfoToContent(); +} + /* static */ void KeymapWrapper::OnKeysChanged(GdkKeymap *aGdkKeymap, KeymapWrapper* aKeymapWrapper) { MOZ_LOG(gKeymapWrapperLog, LogLevel::Info, ("OnKeysChanged, aGdkKeymap=%p, aKeymapWrapper=%p", aGdkKeymap, aKeymapWrapper)); MOZ_ASSERT(sInstance == aKeymapWrapper, "This instance must be the singleton instance"); // We cannot reintialize here becasue we don't have GdkWindow which is using // the GdkKeymap. We'll reinitialize it when next GetInstance() is called. sInstance->mInitialized = false; + ResetBidiKeyboard(); +} - // Reset the bidi keyboard settings for the new GdkKeymap - if (!sBidiKeyboard) { - CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard); - } - if (sBidiKeyboard) { - sBidiKeyboard->Reset(); - } +// static +void +KeymapWrapper::OnDirectionChanged(GdkKeymap *aGdkKeymap, + KeymapWrapper* aKeymapWrapper) +{ + // XXX + // A lot of diretion-changed signal might be fired on switching bidi + // keyboard when using both ibus (with arabic layout) and fcitx (with IME). + // See https://github.com/fcitx/fcitx/issues/257 + // + // Also, when using ibus, switching to IM might not cause this signal. + // See https://github.com/ibus/ibus/issues/1848 + + MOZ_LOG(gKeymapWrapperLog, LogLevel::Info, + ("OnDirectionChanged, aGdkKeymap=%p, aKeymapWrapper=%p", + aGdkKeymap, aKeymapWrapper)); + + ResetBidiKeyboard(); } /* static */ guint KeymapWrapper::GetCurrentModifierState() { GdkModifierType modifiers; gdk_display_get_pointer(gdk_display_get_default(), nullptr, nullptr, nullptr, &modifiers);
--- a/widget/gtk/nsGtkKeyUtils.h +++ b/widget/gtk/nsGtkKeyUtils.h @@ -252,16 +252,18 @@ protected: * Otherwise, false. */ bool IsAutoRepeatableKey(guint aHardwareKeyCode); /** * Signal handlers. */ static void OnKeysChanged(GdkKeymap* aKeymap, KeymapWrapper* aKeymapWrapper); + static void OnDirectionChanged(GdkKeymap *aGdkKeymap, + KeymapWrapper* aKeymapWrapper); /** * GetCharCodeFor() Computes what character is inputted by the key event * with aModifierState and aGroup. * * @param aGdkKeyEvent Native key event, must not be nullptr. * @param aModifierState Combination of GdkModifierType which you * want to test with aGdkKeyEvent.