author | Ciure Andrei <aciure@mozilla.com> |
Wed, 26 Sep 2018 00:49:06 +0300 | |
changeset 438185 | 2e3e89c9c68cd6b09d1853dc5426df3c04971c29 |
parent 438142 | 17254f49a52ed09cecfdae4cc5d6821156e439d4 (current diff) |
parent 438184 | eddaf25ccc76bb608b24845081e8d3acdb8833f2 (diff) |
child 438207 | abfb04c8c3b4ff9d87dbfec23bfe5df3d9020a85 |
child 438251 | da5a32b2a22f8c4ac0036576935b77a91029f8ee |
push id | 34711 |
push user | aciure@mozilla.com |
push date | Tue, 25 Sep 2018 21:49:34 +0000 |
treeherder | mozilla-central@2e3e89c9c68c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 64.0a1 |
first release with | nightly linux32
2e3e89c9c68c
/
64.0a1
/
20180925220052
/
files
nightly linux64
2e3e89c9c68c
/
64.0a1
/
20180925220052
/
files
nightly mac
2e3e89c9c68c
/
64.0a1
/
20180925220052
/
files
nightly win32
2e3e89c9c68c
/
64.0a1
/
20180925220052
/
files
nightly win64
2e3e89c9c68c
/
64.0a1
/
20180925220052
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
64.0a1
/
20180925220052
/
pushlog to previous
nightly linux64
64.0a1
/
20180925220052
/
pushlog to previous
nightly mac
64.0a1
/
20180925220052
/
pushlog to previous
nightly win32
64.0a1
/
20180925220052
/
pushlog to previous
nightly win64
64.0a1
/
20180925220052
/
pushlog to previous
|
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js +++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js @@ -32,17 +32,17 @@ class Sidebar extends PureComponent { renderDevices() { const { dispatch, runtimes, selectedPage } = this.props; if (!runtimes.networkRuntimes.length && !runtimes.usbRuntimes.length) { return Localized( { id: "about-debugging-sidebar-no-devices" }, dom.span( { - className: "sidebar__devices__no-devices-message" + className: "sidebar__devices__no-devices-message js-sidebar-no-devices" }, "No devices discovered" ) ); } return [ ...runtimes.networkRuntimes.map(runtime => {
--- a/devtools/client/aboutdebugging-new/src/modules/usb-runtimes.js +++ b/devtools/client/aboutdebugging-new/src/modules/usb-runtimes.js @@ -1,15 +1,14 @@ /* 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/. */ "use strict"; -const { check } = require("devtools/shared/adb/adb-running-checker"); const { ADBScanner } = require("devtools/shared/adb/adb-scanner"); const { GetAvailableAddons } = require("devtools/client/webide/modules/addons"); /** * This module provides a collection of helper methods to detect USB runtimes whom Firefox * is running on. */ function addUSBRuntimesObserver(listener) { @@ -19,17 +18,17 @@ exports.addUSBRuntimesObserver = addUSBR function disableUSBRuntimes() { ADBScanner.disable(); } exports.disableUSBRuntimes = disableUSBRuntimes; async function enableUSBRuntimes() { const { adb } = GetAvailableAddons(); - if (adb.status === "uninstalled" || !(await check())) { + if (adb.status !== "installed") { console.error("ADB extension is not installed"); return; } ADBScanner.enable(); } exports.enableUSBRuntimes = enableUSBRuntimes;
--- a/devtools/client/aboutdebugging-new/test/browser/browser.ini +++ b/devtools/client/aboutdebugging-new/test/browser/browser.ini @@ -2,12 +2,14 @@ tags = devtools subsuite = devtools support-files = debug-target-pane_collapsibilities_head.js head.js !/devtools/client/shared/test/shared-head.js !/devtools/client/shared/test/telemetry-test-helpers.js +[browser_aboutdebugging_connect_networklocations.js] [browser_aboutdebugging_debug-target-pane_collapsibilities_interaction.js] [browser_aboutdebugging_debug-target-pane_collapsibilities_preference.js] +[browser_aboutdebugging_navigate.js] +[browser_aboutdebugging_sidebar_network_runtimes.js] [browser_aboutdebugging_thisfirefox.js] -[browser_aboutdebugging_connect_networklocations.js]
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_debug-target-pane_collapsibilities_interaction.js +++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_debug-target-pane_collapsibilities_interaction.js @@ -1,21 +1,17 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -/* import-globals-from debug-target-pane_collapsibilities_head.js */ "use strict"; /** * Test that collapsibilities of DebugTargetPane on RuntimePage by mouse clicking. */ -Services.scriptloader.loadSubScript( - CHROME_URL_ROOT + "debug-target-pane_collapsibilities_head.js", this); - add_task(async function() { prepareCollapsibilitiesTest(); const { document, tab } = await openAboutDebugging(); for (const { title } of TARGET_PANES) { const debugTargetPaneEl = getDebugTargetPane(title, document);
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_debug-target-pane_collapsibilities_preference.js +++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_debug-target-pane_collapsibilities_preference.js @@ -1,21 +1,17 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -/* import-globals-from debug-target-pane_collapsibilities_head.js */ "use strict"; /** * Test for preference of DebugTargetPane collapsibilities. */ -Services.scriptloader.loadSubScript( - CHROME_URL_ROOT + "debug-target-pane_collapsibilities_head.js", this); - add_task(async function() { prepareCollapsibilitiesTest(); const { document, tab } = await openAboutDebugging(); info("Collapse all pane"); for (const { title } of TARGET_PANES) { const debugTargetPaneEl = getDebugTargetPane(title, document);
new file mode 100644 --- /dev/null +++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_navigate.js @@ -0,0 +1,79 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Check that navigating from This Firefox to Connect and back to This Firefox works and + * does not leak. + */ + +const TAB_URL_1 = "data:text/html,<title>TAB1</title>"; +const TAB_URL_2 = "data:text/html,<title>TAB2</title>"; + +add_task(async function() { + info("Force all debug target panes to be expanded"); + prepareCollapsibilitiesTest(); + + const { document, tab } = await openAboutDebugging(); + + const connectSidebarItem = findSidebarItemByText("Connect", document); + ok(connectSidebarItem, "Found the Connect sidebar item"); + + const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document); + ok(thisFirefoxSidebarItem, "Found the ThisFirefox sidebar item"); + ok(isSidebarItemSelected(thisFirefoxSidebarItem), + "ThisFirefox sidebar item is selected by default"); + + info("Open a new background tab TAB1"); + const backgroundTab1 = await addTab(TAB_URL_1, { background: true }); + + info("Wait for the tab to appear in the debug targets with the correct name"); + await waitUntil(() => findDebugTargetByText("TAB1", document)); + + info("Click on the Connect item in the sidebar"); + connectSidebarItem.click(); + + info("Wait until Connect page is displayed"); + await waitUntil(() => document.querySelector(".js-connect-page")); + ok(isSidebarItemSelected(connectSidebarItem), "Connect sidebar item is selected"); + ok(!document.querySelector(".js-runtime-page"), "Runtime page no longer rendered"); + + info("Open a new tab which should be listed when we go back to This Firefox"); + const backgroundTab2 = await addTab(TAB_URL_2, { background: true }); + + info("Click on the ThisFirefox item in the sidebar"); + thisFirefoxSidebarItem.click(); + + info("Wait until ThisFirefox page is displayed"); + await waitUntil(() => document.querySelector(".js-runtime-page")); + ok(isSidebarItemSelected(thisFirefoxSidebarItem), + "ThisFirefox sidebar item is selected again"); + ok(!document.querySelector(".js-connect-page"), "Connect page no longer rendered"); + + info("TAB2 should already be displayed in the debug targets"); + await waitUntil(() => findDebugTargetByText("TAB2", document)); + + info("Remove first background tab"); + await removeTab(backgroundTab1); + + info("Check TAB1 disappears, meaning ThisFirefox client is correctly connected"); + await waitUntil(() => !findDebugTargetByText("TAB1", document)); + + info("Remove second background tab"); + await removeTab(backgroundTab2); + + info("Check TAB2 disappears, meaning ThisFirefox client is correctly connected"); + await waitUntil(() => !findDebugTargetByText("TAB2", document)); + + await removeTab(tab); +}); + +function isSidebarItemSelected(item) { + return item.classList.contains("js-sidebar-item-selected"); +} + +function findDebugTargetByText(text, document) { + const targets = [...document.querySelectorAll(".js-debug-target-item")]; + return targets.find(target => target.textContent.includes(text)); +}
new file mode 100644 --- /dev/null +++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_network_runtimes.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const networkLocationsModule = + require("devtools/client/aboutdebugging-new/src/modules/network-locations.js"); + +/** + * Test the sidebar is updated correctly when network runtimes are added/removed. + */ + +add_task(async function() { + registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.aboutdebugging.network-locations"); + }); + + const { document, tab } = await openAboutDebugging(); + + const noDevicesElement = document.querySelector(".js-sidebar-no-devices"); + ok(noDevicesElement, "Sidebar shows the 'no devices' element"); + + info("Add a network location"); + networkLocationsModule.addNetworkLocation("localhost:6080"); + + info("Wait for 'no devices' element to disappear"); + waitUntil(() => !document.querySelector(".js-sidebar-no-devices")); + ok(findSidebarItemByText("localhost:6080", document), + "Found a sidebar item for localhost:6080"); + + info("Remove the network location"); + networkLocationsModule.removeNetworkLocation("localhost:6080"); + + info("Wait for 'no devices' element to reappear"); + waitUntil(() => document.querySelector(".js-sidebar-no-devices")); + ok(!findSidebarItemByText("localhost:6080", document), + "Sidebar item for localhost:6080 removed"); + + await removeTab(tab); +});
--- a/devtools/client/aboutdebugging-new/test/browser/head.js +++ b/devtools/client/aboutdebugging-new/test/browser/head.js @@ -1,22 +1,27 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /* eslint-env browser */ /* eslint no-unused-vars: [2, {"vars": "local"}] */ /* import-globals-from ../../../shared/test/shared-head.js */ +/* import-globals-from debug-target-pane_collapsibilities_head.js */ "use strict"; // Load the shared-head file first. Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js", this); +// Load collapsibilities helpers +Services.scriptloader.loadSubScript( + CHROME_URL_ROOT + "debug-target-pane_collapsibilities_head.js", this); + /** * Enable the new about:debugging panel. */ async function enableNewAboutDebugging() { await pushPref("devtools.aboutdebugging.new-enabled", true); } async function openAboutDebugging(page, win) { @@ -31,8 +36,15 @@ async function openAboutDebugging(page, info("Wait until the main about debugging container is available"); await waitUntil(() => document.querySelector(".app")); info("Wait until the client connection was established"); await waitUntil(() => document.querySelector(".js-runtime-page")); return { tab, document, window }; } + +function findSidebarItemByText(text, document) { + const sidebarItems = document.querySelectorAll(".js-sidebar-item"); + return [...sidebarItems].find(element => { + return element.textContent.includes(text); + }); +}
--- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -2894,24 +2894,30 @@ nsINode::WrapObject(JSContext *aCx, JS:: // Event handling is possible only if (1). If (2) event handling is // prevented. // If the document has never had a script handling object, untrusted // scripts (3) shouldn't touch it! bool hasHadScriptHandlingObject = false; if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) && !hasHadScriptHandlingObject && !nsContentUtils::IsSystemCaller(aCx)) { + if (IsDocument()) { + MOZ_CRASH("Looks like bug 1488480/1405521, with a document that lost its script handling object"); + } Throw(aCx, NS_ERROR_UNEXPECTED); return nullptr; } JS::Rooted<JSObject*> obj(aCx, WrapNode(aCx, aGivenProto)); MOZ_ASSERT_IF(obj && ChromeOnlyAccess(), xpc::IsInContentXBLScope(obj) || !xpc::UseContentXBLScope(JS::GetObjectRealmOrNull(obj))); + if (!obj && IsDocument()) { + MOZ_CRASH("Looks like bug 1488480/1405521, with WrapNode on a document returning null"); + } return obj; } already_AddRefed<nsINode> nsINode::CloneNode(bool aDeep, ErrorResult& aError) { return nsNodeUtils::CloneNodeImpl(this, aDeep, aError); }
--- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -39,27 +39,25 @@ #include "xpcpublic.h" #include "nsIVariant.h" #include "mozilla/dom/FakeString.h" #include "nsWrapperCacheInlines.h" class nsGenericHTMLElement; class nsIJSID; -class nsIDocument; namespace mozilla { enum UseCounter : int16_t; namespace dom { class CustomElementReactionsStack; class MessageManagerGlobal; template<typename KeyType, typename ValueType> class Record; -class Location; nsresult UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg); nsresult UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src, nsPIDOMWindowOuter** ppArg); @@ -1057,40 +1055,18 @@ struct CheckWrapperCacheTracing<T, true> wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant); wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper); } }; void AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector, JS::Handle<JSObject*> aGivenProto); - #endif // DEBUG -template <class T> -MOZ_ALWAYS_INLINE void -CrashIfDocumentOrLocationWrapFailed() -{ - // Do nothing. -} - -template<> -MOZ_ALWAYS_INLINE void -CrashIfDocumentOrLocationWrapFailed<nsIDocument>() -{ - MOZ_CRASH("Looks like bug 1488480/1405521, with WrapObject() on nsIDocument throwing"); -} - -template<> -MOZ_ALWAYS_INLINE void -CrashIfDocumentOrLocationWrapFailed<Location>() -{ - MOZ_CRASH("Looks like bug 1488480/1405521, with WrapObject() on Location throwing"); -} - template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior> MOZ_ALWAYS_INLINE bool DoGetOrCreateDOMReflector(JSContext* cx, T* value, JS::Handle<JSObject*> givenProto, JS::MutableHandle<JS::Value> rval) { MOZ_ASSERT(value); MOZ_ASSERT_IF(givenProto, js::IsObjectInContextCompartment(givenProto, cx)); @@ -1103,17 +1079,16 @@ DoGetOrCreateDOMReflector(JSContext* cx, obj = value->GetWrapper(); #endif } else { obj = value->WrapObject(cx, givenProto); if (!obj) { // At this point, obj is null, so just return false. // Callers seem to be testing JS_IsExceptionPending(cx) to // figure out whether WrapObject() threw. - CrashIfDocumentOrLocationWrapFailed<T>(); return false; } #ifdef DEBUG if (IsBaseOf<nsWrapperCache, T>::value) { CheckWrapperCacheTracing<T>::Check(value); } #endif @@ -1133,45 +1108,29 @@ DoGetOrCreateDOMReflector(JSContext* cx, MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value)); MOZ_ASSERT(CheckWrapperCacheCast<T>::Check()); } #endif rval.set(JS::ObjectValue(*obj)); if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) { - if (!TypeNeedsOuterization<T>::value) { - return true; - } - if (TryToOuterize(rval)) { - return true; - } - - return false; + return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true; } if (wrapBehavior == eDontWrapIntoContextCompartment) { if (TypeNeedsOuterization<T>::value) { JSAutoRealm ar(cx, obj); - if (TryToOuterize(rval)) { - return true; - } - - return false; + return TryToOuterize(rval); } return true; } - if (JS_WrapValue(cx, rval)) { - return true; - } - - MOZ_CRASH("Looks like bug 1488480/1405521, with JS_WrapValue failing"); - return false; + return JS_WrapValue(cx, rval); } } // namespace binding_detail // Create a JSObject wrapping "value", if there isn't one already, and store it // in rval. "value" must be a concrete class that implements a // GetWrapperPreserveColor() which can return its existing wrapper, if any, and // a WrapObject() which will try to create a wrapper. Typically, this is done by
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3491,17 +3491,17 @@ class CGConstructorEnabled(CGAbstractMet reindent=True) else: conditionsWrapper = CGGeneric("return true;\n") body.append(conditionsWrapper) return body.define() -def CreateBindingJSObject(descriptor, properties): +def CreateBindingJSObject(descriptor, properties, failureCode = ""): objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType # We don't always need to root obj, but there are a variety # of cases where we do, so for simplicity, just always root it. if descriptor.proxy: if descriptor.interface.getExtendedAttribute('OverrideBuiltins'): create = dedent( """ @@ -3516,22 +3516,24 @@ def CreateBindingJSObject(descriptor, pr creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(), proto, aObject, JS::UndefinedHandleValue, aReflector); """) else: create = dedent( """ creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); """) - return objDecl + create + dedent( + return objDecl + create + fill( """ if (!aReflector) { + $*{failureCode} return false; } - """) + """, + failureCode=failureCode) def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode, holderName="unforgeableHolder"): """ Define the unforgeable properties on the unforgeable holder for the interface represented by descriptor. @@ -3691,41 +3693,45 @@ def SetImmutablePrototype(descriptor, fa MOZ_ASSERT(succeeded, "Making a fresh reflector instance have an immutable " "prototype can internally fail, but it should never be " "unsuccessful"); """, failureCode=failureCode) -def DeclareProto(): +def DeclareProto(noProto = "", wrapFail = ""): """ Declare the canonicalProto and proto we have for our wrapping operation. """ - return dedent( + return fill( """ JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { + $*{noProto} return false; } JS::Rooted<JSObject*> proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { + $*{wrapFail} return false; } } } else { proto = canonicalProto; } - """) + """, + noProto=noProto, + wrapFail=wrapFail) class CGWrapWithCacheMethod(CGAbstractMethod): """ Create a wrapper JSObject for a given native that implements nsWrapperCache. properties should be a PropertyArrays instance. """ @@ -3742,31 +3748,73 @@ class CGWrapWithCacheMethod(CGAbstractMe def definition_body(self): failureCode = dedent( """ aCache->ReleaseWrapper(aObject); aCache->ClearWrapper(); return false; """) + isDocument = False + iface = self.descriptor.interface + while iface: + if iface.identifier.name == "Document": + isDocument = True + break + iface = iface.parent + + if isDocument: + noGlobal = fill( + """ + MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} not having a global"); + """, + name = self.descriptor.name) + noProto = fill( + """ + MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} not having a proto"); + """, + name = self.descriptor.name) + protoWrapFail = fill( + """ + MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to wrap a custom proto"); + """, + name = self.descriptor.name) + createObjectFailed = fill( + """ + MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to CreateObject/CreateProxyObject"); + """, + name = self.descriptor.name) + expandoAllocFail = fill( + """ + MOZ_CRASH("Looks like bug 1488480/1405521, with ${name} failing to EnsureExpandoObject or JS_InitializePropertiesFromCompatibleNativeObject"); + """, + name = self.descriptor.name) + else: + noGlobal = "" + noProto = "" + protoWrapFail = "" + createObjectFailed = "" + expandoAllocFail = "" + return fill( """ static_assert(!IsBaseOf<NonRefcountedDOMObject, ${nativeType}>::value, "Shouldn't have wrappercached things that are not refcounted."); $*{assertInheritance} MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { + $*{noGlobal} return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); MOZ_ASSERT(JS::ObjectIsNotGray(global)); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); @@ -3797,21 +3845,24 @@ class CGWrapWithCacheMethod(CGAbstractMe // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; """, + noGlobal=noGlobal, nativeType=self.descriptor.nativeType, assertInheritance=AssertInheritanceChain(self.descriptor), - declareProto=DeclareProto(), - createObject=CreateBindingJSObject(self.descriptor, self.properties), + declareProto=DeclareProto(noProto, protoWrapFail), + createObject=CreateBindingJSObject(self.descriptor, self.properties, + createObjectFailed), unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor, + expandoAllocFail + failureCode), slots=InitMemberSlots(self.descriptor, failureCode), setImmutablePrototype=SetImmutablePrototype(self.descriptor, failureCode)) class CGWrapMethod(CGAbstractMethod): def __init__(self, descriptor): @@ -4017,39 +4068,29 @@ class CGClearCachedValueMethod(CGAbstrac if self.member.getExtendedAttribute("StoreInSlot"): # We have to root things and save the old value in case # regetting fails, so we can restore it. declObj = "JS::Rooted<JSObject*> obj(aCx);\n" noopRetval = " true" saveMember = ( "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" % slotIndex) - if self.descriptor.name == "Document" or self.descriptor.name == "Location": - maybeCrash = dedent( - """ - MOZ_CRASH("Looks like bug 1488480/1405521, with the getter failing"); - """) - else: - maybeCrash = "" - regetMember = fill( """ JS::Rooted<JS::Value> temp(aCx); JSJitGetterCallArgs args(&temp); JSAutoRealm ar(aCx, obj); if (!get_${name}(aCx, obj, aObject, args)) { js::SetReservedSlot(obj, ${slotIndex}, oldValue); - $*{maybeCrash} return false; } return true; """, name=self.member.identifier.name, - slotIndex=slotIndex, - maybeCrash=maybeCrash) + slotIndex=slotIndex) else: declObj = "JSObject* obj;\n" noopRetval = "" saveMember = "" regetMember = "" if self.descriptor.wantsXrays: clearXrayExpandoSlots = fill( @@ -6693,21 +6734,16 @@ def getWrapTemplateForType(type, descrip wrapArgs = "cx, ${obj}, %s, ${jsvalHandle}" % result if isConstructorRetval: wrapArgs += ", desiredProto" wrap = "%s(%s)" % (wrapMethod, wrapArgs) # Can only fail to wrap as a new-binding object if they already # threw an exception. failed = ("MOZ_ASSERT(JS_IsExceptionPending(cx));\n" + exceptionCode) - - if descriptor.name == "Document" or descriptor.name == "Location": - failed = ( - 'MOZ_CRASH("Looks like bug 1488480/1405521, with getting the reflector failing");\n' + - failed) else: if descriptor.notflattened: getIID = "&NS_GET_IID(%s), " % descriptor.nativeType else: getIID = "" wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID) failed = None @@ -7853,38 +7889,28 @@ class CGPerSignatureCall(CGThing): "if (!JS_FreezeObject(cx, rvalObj)) {\n" " return false;\n" "}\n") if self.idlNode.type.nullable(): freezeValue = CGIfWrapper(freezeValue, "args.rval().isObject()") postConversionSteps += freezeValue.define() - if self.descriptor.name == "Window": - maybeCrash = dedent( - """ - MOZ_CRASH("Looks like bug 1488480/1405521, with the other MaybeWrap failing"); - """) - else: - maybeCrash = "" - # slotStorageSteps are steps that run once we have entered the # slotStorage compartment. slotStorageSteps= fill( """ // Make a copy so that we don't do unnecessary wrapping on args.rval(). JS::Rooted<JS::Value> storedVal(cx, args.rval()); if (!${maybeWrap}(cx, &storedVal)) { - $*{maybeCrash} return false; } js::SetReservedSlot(slotStorage, slotIndex, storedVal); """, - maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type), - maybeCrash=maybeCrash) + maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type)) checkForXray = mayUseXrayExpandoSlots(self.descriptor, self.idlNode) # For the case of Cached attributes, go ahead and preserve our # wrapper if needed. We need to do this because otherwise the # wrapper could get garbage-collected and the cached value would # suddenly disappear, but the whole premise of cached values is that # they never change without explicit action on someone's part. We @@ -7912,51 +7938,38 @@ class CGPerSignatureCall(CGThing): if checkForXray: # In the Xray case we use the current global as conversion # scope, as explained in the big compartment/conversion comment # above. conversionScope = "isXray ? JS::CurrentGlobalOrNull(cx) : slotStorage" else: conversionScope = "slotStorage" - if self.descriptor.name == "Window": - maybeCrash = dedent( - """ - MOZ_CRASH("Looks like bug 1488480/1405521, with the third MaybeWrap failing"); - """) - else: - maybeCrash = "" - wrapCode = fill( """ { JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope}); JSAutoRealm ar(cx, conversionScope); do { // block we break out of when done wrapping $*{wrapCode} } while (false); $*{postConversionSteps} } { // And now store things in the realm of our slotStorage. JSAutoRealm ar(cx, slotStorage); $*{slotStorageSteps} } // And now make sure args.rval() is in the caller realm. - if (${maybeWrap}(cx, args.rval())) { - return true; - } - $*{maybeCrash} - return false; + return ${maybeWrap}(cx, args.rval()); """, conversionScope=conversionScope, wrapCode=wrapCode, postConversionSteps=postConversionSteps, slotStorageSteps=slotStorageSteps, - maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type), - maybeCrash=maybeCrash) + maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type)) return wrapCode def define(self): return (self.cgRoot.define() + self.wrap_return_value()) class CGSwitch(CGList): """ @@ -8978,45 +8991,32 @@ class CGSpecializedGetter(CGAbstractStat """ // Have to either root across the getter call or reget after. JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false)); MOZ_ASSERT(IsDOMObject(slotStorage)); const size_t slotIndex = ${slotIndex}; """, slotIndex=memberReservedSlot(self.attr, self.descriptor)) - if self.descriptor.name == "Window": - maybeCrash = dedent( - """ - MOZ_CRASH("Looks like bug 1488480/1405521, with cached value wrapping failing"); - """) - else: - maybeCrash = "" - prefix += fill( """ MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(js::GetObjectClass(slotStorage)) > slotIndex); { // Scope for cachedVal JS::Value cachedVal = js::GetReservedSlot(slotStorage, slotIndex); if (!cachedVal.isUndefined()) { args.rval().set(cachedVal); // The cached value is in the compartment of slotStorage, // so wrap into the caller compartment as needed. - if (${maybeWrap}(cx, args.rval())) { - return true; - } - $*{maybeCrash} - return false; + return ${maybeWrap}(cx, args.rval()); } } """, - maybeWrap=getMaybeWrapValueFuncForType(self.attr.type), - maybeCrash=maybeCrash) + maybeWrap=getMaybeWrapValueFuncForType(self.attr.type)) else: prefix = "" if self.attr.navigatorObjectGetter: cgGetterCall = CGNavigatorGetterCall else: cgGetterCall = CGGetterCall return (prefix +
--- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -195,17 +195,21 @@ ImageDocument::Init() mFirstResize = true; return NS_OK; } JSObject* ImageDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { - return ImageDocument_Binding::Wrap(aCx, this, aGivenProto); + JSObject* obj = ImageDocument_Binding::Wrap(aCx, this, aGivenProto); + if (!obj) { + MOZ_CRASH("Looks like bug 1488480/1405521, with ImageDocument::WrapNode failing"); + } + return obj; } nsresult ImageDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup, nsISupports* aContainer, nsIStreamListener** aDocListener,
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -197,17 +197,21 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHTM NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsHTMLDocument, nsDocument, nsIHTMLDocument) JSObject* nsHTMLDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { - return HTMLDocument_Binding::Wrap(aCx, this, aGivenProto); + JSObject* obj = HTMLDocument_Binding::Wrap(aCx, this, aGivenProto); + if (!obj) { + MOZ_CRASH("Looks like bug 1488480/1405521, with nsHTMLDocument::WrapNode failing"); + } + return obj; } nsresult nsHTMLDocument::Init() { nsresult rv = nsDocument::Init(); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -10,16 +10,17 @@ #include "ReportInternalError.h" #include "nsCharSeparatedTokenizer.h" #include "nsJSUtils.h" #include "nsPrintfCString.h" #include "xpcpublic.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h" namespace mozilla { namespace dom { namespace indexedDB { namespace { @@ -96,42 +97,97 @@ GetJSValFromKeyPathString(JSContext* aCx while (tokenizer.hasMoreTokens()) { const nsDependentSubstring& token = tokenizer.nextToken(); NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath"); const char16_t* keyPathChars = token.BeginReading(); const size_t keyPathLen = token.Length(); - bool hasProp; if (!targetObject) { // We're still walking the chain of existing objects // http://w3c.github.io/IndexedDB/#evaluate-a-key-path-on-a-value // step 4 substep 1: check for .length on a String value. if (currentVal.isString() && !tokenizer.hasMoreTokens() && token.EqualsLiteral("length")) { aKeyJSVal->setNumber(double(JS_GetStringLength(currentVal.toString()))); break; } if (!currentVal.isObject()) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } obj = ¤tVal.toObject(); - bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen, - &hasProp); + // We call JS_GetOwnUCPropertyDescriptor on purpose (as opposed to + // JS_GetUCPropertyDescriptor) to avoid searching the prototype chain. + JS::Rooted<JS::PropertyDescriptor> desc(aCx); + bool ok = JS_GetOwnUCPropertyDescriptor(aCx, obj, keyPathChars, + keyPathLen, &desc); IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + JS::Rooted<JS::Value> intermediate(aCx); + bool hasProp = false; + + if (desc.object()) { + intermediate = desc.value(); + hasProp = true; + } else { + // If we get here it means the object doesn't have the property or the + // property is available throuch a getter. We don't want to call any + // getters to avoid potential re-entrancy. + // The blob object is special since its properties are available + // only through getters but we still want to support them for key + // extraction. So they need to be handled manually. + Blob* blob; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) { + if (token.EqualsLiteral("size")) { + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(size); + hasProp = true; + } else if (token.EqualsLiteral("type")) { + nsString type; + blob->GetType(type); + + JSString* string = + JS_NewUCStringCopyN(aCx, type.get(), type.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else { + RefPtr<File> file = blob->ToFile(); + if (file) { + if (token.EqualsLiteral("name")) { + nsString name; + file->GetName(name); + + JSString* string = + JS_NewUCStringCopyN(aCx, name.get(), name.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else if (token.EqualsLiteral("lastModified")) { + ErrorResult rv; + int64_t lastModifiedDate = file->GetLastModified(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(lastModifiedDate); + hasProp = true; + } + // The spec also lists "lastModifiedDate", but we deprecated and + // removed support for it. + } + } + } + } + if (hasProp) { - // Get if the property exists... - JS::Rooted<JS::Value> intermediate(aCx); - bool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &intermediate); - IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - // Treat explicitly undefined as an error. if (intermediate.isUndefined()) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } if (tokenizer.hasMoreTokens()) { // ...and walk to it if there are more steps... currentVal = intermediate; }
--- a/dom/xbl/nsXBLBinding.cpp +++ b/dom/xbl/nsXBLBinding.cpp @@ -979,17 +979,18 @@ nsXBLBinding::DoInitJSClass(JSContext *c js::AssertSameCompartment(holder, xblScope); JSAutoRealm ar(cx, holder); // Look up the class on the property holder. The only properties on the // holder should be class objects. If we don't find the class object, we need // to create and define it. JS::Rooted<JSObject*> proto(cx); JS::Rooted<JS::PropertyDescriptor> desc(cx); - if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) { + if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), + aClassName.Length(), &desc)) { return NS_ERROR_OUT_OF_MEMORY; } *aNew = !desc.object(); if (desc.object()) { proto = &desc.value().toObject(); DebugOnly<nsXBLPrototypeBinding*> cachedBinding = GetProtoBindingFromClassObject(js::UncheckedUnwrap(proto)); MOZ_ASSERT(cachedBinding == aProtoBinding);
--- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -91,37 +91,42 @@ nsXBLProtoImpl::InstallImplementation(ns // // Note: If |targetIsNew| is false, we'll early-return above. However, that only // tells us if the content-side object is new, which may be the case even if // we've already set up the binding on the XBL side. For example, if we apply // a binding #foo to a <span> when we've already applied it to a <div>, we'll // end up with a different content prototype, but we'll already have a property // holder called |foo| in the XBL scope. Check for that to avoid wasteful and // weird property holder duplication. - const char16_t* className = aPrototypeBinding->ClassName().get(); + const nsString& className = aPrototypeBinding->ClassName(); + const char16_t* classNameChars = className.get(); + const size_t classNameLen = className.Length(); + JS::Rooted<JSObject*> propertyHolder(cx); JS::Rooted<JS::PropertyDescriptor> existingHolder(cx); if (scopeObject != globalObject && - !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) { + !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, classNameChars, + classNameLen, &existingHolder)) { return NS_ERROR_FAILURE; } bool propertyHolderIsNew = !existingHolder.object() || !existingHolder.value().isObject(); if (!propertyHolderIsNew) { propertyHolder = &existingHolder.value().toObject(); } else if (scopeObject != globalObject) { // This is just a property holder, so it doesn't need any special JSClass. propertyHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr); NS_ENSURE_TRUE(propertyHolder, NS_ERROR_OUT_OF_MEMORY); // Define it as a property on the scopeObject, using the same name used on // the content side. - bool ok = JS_DefineUCProperty(cx, scopeObject, className, -1, propertyHolder, - JSPROP_PERMANENT | JSPROP_READONLY); + bool ok = + JS_DefineUCProperty(cx, scopeObject, classNameChars, classNameLen, + propertyHolder, JSPROP_PERMANENT | JSPROP_READONLY); NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); } else { propertyHolder = targetClassObject; } // Walk our member list and install each one in turn on the XBL scope object. if (propertyHolderIsNew) { for (nsXBLProtoImplMember* curr = mMembers;
--- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -622,17 +622,22 @@ XMLDocument::Clone(dom::NodeInfo* aNodeI clone->mIsPlainDocument = mIsPlainDocument; return CallQueryInterface(clone.get(), aResult); } JSObject* XMLDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) { + JSObject* obj; if (mIsPlainDocument) { - return Document_Binding::Wrap(aCx, this, aGivenProto); + obj = Document_Binding::Wrap(aCx, this, aGivenProto); + } else { + obj = XMLDocument_Binding::Wrap(aCx, this, aGivenProto); } - - return XMLDocument_Binding::Wrap(aCx, this, aGivenProto); + if (!obj) { + MOZ_CRASH("Looks like bug 1488480/1405521, with XMLDocument::WrapNode failing"); + } + return obj; } } // namespace dom } // namespace mozilla
--- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -2501,13 +2501,17 @@ XULDocument::DirectionChanged(const char if (aDoc) { aDoc->ResetDocumentDirection(); } } JSObject* XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) { - return XULDocument_Binding::Wrap(aCx, this, aGivenProto); + JSObject* obj = XULDocument_Binding::Wrap(aCx, this, aGivenProto); + if (!obj) { + MOZ_CRASH("Looks like bug 1488480/1405521, with XULDocument_Binding::Wrap failing"); + } + return obj; } } // namespace dom } // namespace mozilla
--- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -415,17 +415,17 @@ public: */ virtual void *GetNativeSurface(NativeSurfaceType aType) { return nullptr; } void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { mUserData.Add(key, userData, destroy); } - void *GetUserData(UserDataKey *key) { + void *GetUserData(UserDataKey *key) const { return mUserData.Get(key); } void RemoveUserData(UserDataKey *key) { mUserData.RemoveAndDestroy(key); } protected: friend class DrawTargetCaptureImpl; @@ -582,17 +582,18 @@ public: virtual already_AddRefed<DataSourceSurface> GetDataSurface() override; /** * Add the size of the underlying data buffer to the aggregate. */ virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const { } /** * Returns whether or not the data was allocated on the heap. This should * be used to determine if the memory needs to be cleared to 0. */ virtual bool OnHeap() const
--- a/gfx/2d/SourceSurfaceRawData.cpp +++ b/gfx/2d/SourceSurfaceRawData.cpp @@ -78,15 +78,16 @@ SourceSurfaceAlignedRawData::Init(const return mArray != nullptr; } void SourceSurfaceAlignedRawData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const { aHeapSizeOut += mArray.HeapSizeOfExcludingThis(aMallocSizeOf); } } // namespace gfx } // namespace mozilla
--- a/gfx/2d/SourceSurfaceRawData.h +++ b/gfx/2d/SourceSurfaceRawData.h @@ -126,17 +126,18 @@ public: virtual SurfaceType GetType() const override { return SurfaceType::DATA; } virtual IntSize GetSize() const override { return mSize; } virtual SurfaceFormat GetFormat() const override { return mFormat; } void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const override; + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const override; virtual bool Map(MapType, MappedSurface *aMappedSurface) override { aMappedSurface->mData = GetData(); aMappedSurface->mStride = Stride(); bool success = !!aMappedSurface->mData; if (success) { mMapCount++;
--- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -17,16 +17,17 @@ #include "mozilla/Assertions.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/MemoryReportRequest.h" #include "mozilla/dom/VideoDecoderManagerChild.h" #include "mozilla/dom/VideoDecoderManagerParent.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/gfxVars.h" +#include "mozilla/image/ImageMemoryReporter.h" #include "mozilla/ipc/CrashReporterClient.h" #include "mozilla/ipc/ProcessChild.h" #include "mozilla/layers/APZInputBridgeParent.h" #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/APZUtils.h" // for apz::InitializeGlobalState #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorManagerParent.h" #include "mozilla/layers/CompositorThread.h" @@ -263,16 +264,17 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett MOZ_ASSERT(library); Factory::SetFTLibrary(library); } #endif // Make sure to do this *after* we update gfxVars above. if (gfxVars::UseWebRender()) { wr::RenderThread::Start(); + image::ImageMemoryReporter::InitForWebRender(); } VRManager::ManagerInit(); // Send a message to the UI process that we're done. GPUDeviceData data; RecvGetDeviceStatus(&data); Unused << SendInitComplete(data); @@ -533,16 +535,18 @@ GPUParent::ActorDestroy(ActorDestroyReas CompositorThreadHolder::Shutdown(); VRListenerThreadHolder::Shutdown(); // There is a case that RenderThread exists when gfxVars::UseWebRender() is false. // This could happen when WebRender was fallbacked to compositor. if (wr::RenderThread::Get()) { wr::RenderThread::ShutDown(); } + image::ImageMemoryReporter::ShutdownForWebRender(); + // Shut down the default GL context provider. gl::GLContextProvider::Shutdown(); #if defined(XP_WIN) // The above shutdown calls operate on the available context providers on // most platforms. Windows is a "special snowflake", though, and has three // context providers available, so we have to shut all of them down. // We should only support the default GL provider on Windows; then, this
--- a/gfx/layers/SourceSurfaceSharedData.cpp +++ b/gfx/layers/SourceSurfaceSharedData.cpp @@ -92,25 +92,30 @@ SourceSurfaceSharedData::GuaranteePersis { // Shared memory is not unmapped until we release SourceSurfaceSharedData. } void SourceSurfaceSharedData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const { MutexAutoLock lock(mMutex); if (mBuf) { aNonHeapSizeOut += GetAlignedDataLength(); } if (!mClosed) { ++aExtHandlesOut; } + Maybe<wr::ExternalImageId> extId = SharedSurfacesChild::GetExternalId(this); + if (extId) { + aExtIdOut = wr::AsUint64(extId.ref()); + } } uint8_t* SourceSurfaceSharedData::GetDataInternal() const { mMutex.AssertCurrentThreadOwns(); // If we have an old buffer lingering, it is because we get reallocated to
--- a/gfx/layers/SourceSurfaceSharedData.h +++ b/gfx/layers/SourceSurfaceSharedData.h @@ -38,16 +38,17 @@ class SourceSurfaceSharedDataWrapper fin public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper, override) SourceSurfaceSharedDataWrapper() : mStride(0) , mConsumers(0) , mFormat(SurfaceFormat::UNKNOWN) , mCreatorPid(0) + , mCreatorRef(true) { } bool Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat, const SharedMemoryBasic::Handle& aHandle, base::ProcessId aCreatorPid); @@ -74,22 +75,40 @@ public: return false; } bool AddConsumer() { return ++mConsumers == 1; } - bool RemoveConsumer() + bool RemoveConsumer(bool aForCreator) { MOZ_ASSERT(mConsumers > 0); + if (aForCreator) { + if (!mCreatorRef) { + MOZ_ASSERT_UNREACHABLE("Already released creator reference!"); + return false; + } + mCreatorRef = false; + } return --mConsumers == 0; } + uint32_t GetConsumers() const + { + MOZ_ASSERT(mConsumers > 0); + return mConsumers; + } + + bool HasCreatorRef() const + { + return mCreatorRef; + } + private: size_t GetDataLength() const { return static_cast<size_t>(mStride) * mSize.height; } size_t GetAlignedDataLength() const { @@ -97,16 +116,17 @@ private: } int32_t mStride; uint32_t mConsumers; IntSize mSize; RefPtr<SharedMemoryBasic> mBuf; SurfaceFormat mFormat; base::ProcessId mCreatorPid; + bool mCreatorRef; }; /** * This class is used to wrap shared (as in process) data buffers used by a * source surface. */ class SourceSurfaceSharedData final : public DataSourceSurface { @@ -150,17 +170,18 @@ public: IntSize GetSize() const override { return mSize; } SurfaceFormat GetFormat() const override { return mFormat; } void GuaranteePersistance() override; void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const override; + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const override; bool OnHeap() const override { return false; } /** * Although Map (and Moz2D in general) isn't normally threadsafe,
--- a/gfx/layers/SourceSurfaceVolatileData.cpp +++ b/gfx/layers/SourceSurfaceVolatileData.cpp @@ -37,17 +37,18 @@ SourceSurfaceVolatileData::GuaranteePers { MOZ_ASSERT_UNREACHABLE("Should use SourceSurfaceRawData wrapper!"); } void SourceSurfaceVolatileData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const { if (mVBuf) { aHeapSizeOut += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf); aNonHeapSizeOut += mVBuf->NonHeapSizeOfExcludingThis(); #ifdef ANDROID if (!mVBuf->OnHeap()) { // Volatile buffers keep a file handle open on Android. ++aExtHandlesOut;
--- a/gfx/layers/SourceSurfaceVolatileData.h +++ b/gfx/layers/SourceSurfaceVolatileData.h @@ -48,17 +48,18 @@ public: IntSize GetSize() const override { return mSize; } SurfaceFormat GetFormat() const override { return mFormat; } void GuaranteePersistance() override; void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const override; + size_t& aExtHandlesOut, + uint64_t& aExtIdOut) const override; bool OnHeap() const override { return mVBuf->OnHeap(); } // Althought Map (and Moz2D in general) isn't normally threadsafe, // we want to allow it for SourceSurfaceVolatileData since it should
--- a/gfx/layers/ipc/CompositorManagerParent.cpp +++ b/gfx/layers/ipc/CompositorManagerParent.cpp @@ -285,16 +285,25 @@ CompositorManagerParent::RecvAddSharedSu mozilla::ipc::IPCResult CompositorManagerParent::RecvRemoveSharedSurface(const wr::ExternalImageId& aId) { SharedSurfacesParent::Remove(aId); return IPC_OK(); } mozilla::ipc::IPCResult +CompositorManagerParent::RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&& aResolver) +{ + SharedSurfacesMemoryReport report; + SharedSurfacesParent::AccumulateMemoryReport(OtherPid(), report); + aResolver(std::move(report)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult CompositorManagerParent::RecvNotifyMemoryPressure() { nsTArray<PCompositorBridgeParent*> compositorBridges; ManagedPCompositorBridgeParent(compositorBridges); for (auto bridge : compositorBridges) { static_cast<CompositorBridgeParentBase*>(bridge)->NotifyMemoryPressure(); } return IPC_OK();
--- a/gfx/layers/ipc/CompositorManagerParent.h +++ b/gfx/layers/ipc/CompositorManagerParent.h @@ -38,16 +38,17 @@ public: CreateSameProcessWidgetCompositorBridge(CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize); mozilla::ipc::IPCResult RecvAddSharedSurface(const wr::ExternalImageId& aId, const SurfaceDescriptorShared& aDesc) override; mozilla::ipc::IPCResult RecvRemoveSharedSurface(const wr::ExternalImageId& aId) override; + mozilla::ipc::IPCResult RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&&) override; virtual mozilla::ipc::IPCResult RecvNotifyMemoryPressure() override; virtual mozilla::ipc::IPCResult RecvReportMemory(ReportMemoryResolver&&) override; void BindComplete(); void ActorDestroy(ActorDestroyReason aReason) override;
--- a/gfx/layers/ipc/PCompositorManager.ipdl +++ b/gfx/layers/ipc/PCompositorManager.ipdl @@ -13,16 +13,17 @@ include "mozilla/layers/WebRenderMessage using struct mozilla::void_t from "ipc/IPCMessageUtils.h"; using mozilla::TimeDuration from "mozilla/TimeStamp.h"; using mozilla::CSSToLayoutDeviceScale from "Units.h"; using mozilla::gfx::IntSize from "mozilla/gfx/2D.h"; using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h"; using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h"; using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::MemoryReport from "mozilla/webrender/WebRenderTypes.h"; +using mozilla::layers::SharedSurfacesMemoryReport from "mozilla/layers/SharedSurfacesMemoryReport.h"; namespace mozilla { namespace layers { struct WidgetCompositorOptions { CSSToLayoutDeviceScale scale; TimeDuration vsyncRate; CompositorOptions options; @@ -71,16 +72,17 @@ parent: * - A "same process widget" PCompositorBridge is requested by the combined * GPU/UI process for each "top level browser window" as above. * See gfx/layers/ipc/PCompositorBridge.ipdl for more details. */ async PCompositorBridge(CompositorBridgeOptions options); async AddSharedSurface(ExternalImageId aId, SurfaceDescriptorShared aDesc); async RemoveSharedSurface(ExternalImageId aId); + async ReportSharedSurfacesMemory() returns (SharedSurfacesMemoryReport aReport); async NotifyMemoryPressure(); async ReportMemory() returns (MemoryReport aReport); }; } // layers } // mozilla
--- a/gfx/layers/ipc/SharedSurfacesChild.cpp +++ b/gfx/layers/ipc/SharedSurfacesChild.cpp @@ -14,16 +14,18 @@ #include "mozilla/layers/WebRenderLayerManager.h" #include "mozilla/SystemGroup.h" // for SystemGroup namespace mozilla { namespace layers { using namespace mozilla::gfx; +/* static */ UserDataKey SharedSurfacesChild::sSharedKey; + class SharedSurfacesChild::ImageKeyData final { public: ImageKeyData(WebRenderLayerManager* aManager, const wr::ImageKey& aImageKey) : mManager(aManager) , mImageKey(aImageKey) { } @@ -219,17 +221,16 @@ SharedSurfacesChild::ShareInternal(Sourc // We cannot try to share the surface, most likely because the GPU process // crashed. Ideally, we would retry when it is ready, but the handles may be // a scarce resource, which can cause much more serious problems if we run // out. Better to copy into a fresh buffer later. aSurface->FinishedSharing(); return NS_ERROR_NOT_INITIALIZED; } - static UserDataKey sSharedKey; SharedUserData* data = static_cast<SharedUserData*>(aSurface->GetUserData(&sSharedKey)); if (!data) { data = new SharedUserData(manager->GetNextExternalImageId()); aSurface->AddUserData(&sSharedKey, data, DestroySharedUserData); } else if (!manager->OwnsExternalImageId(data->Id())) { // If the id isn't owned by us, that means the bridge was reinitialized, due // to the GPU process crashing. All previous mappings have been released. @@ -450,10 +451,25 @@ SharedSurfacesChild::Unshare(const wr::E // Only attempt to release current mappings in the GPU process. It is // possible we had a surface that was previously shared, the GPU process // crashed / was restarted, and then we freed the surface. In that case // we know the mapping has already been freed. manager->SendRemoveSharedSurface(aId); } } +/* static */ Maybe<wr::ExternalImageId> +SharedSurfacesChild::GetExternalId(const SourceSurfaceSharedData* aSurface) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aSurface); + + SharedUserData* data = + static_cast<SharedUserData*>(aSurface->GetUserData(&sSharedKey)); + if (!data || !data->IsShared()) { + return Nothing(); + } + + return Some(data->Id()); +} + } // namespace layers } // namespace mozilla
--- a/gfx/layers/ipc/SharedSurfacesChild.h +++ b/gfx/layers/ipc/SharedSurfacesChild.h @@ -5,18 +5,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_SHAREDSURFACESCHILD_H #define MOZILLA_GFX_SHAREDSURFACESCHILD_H #include <stddef.h> // for size_t #include <stdint.h> // for uint32_t, uint64_t #include "mozilla/Attributes.h" // for override +#include "mozilla/Maybe.h" // for Maybe #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/StaticPtr.h" // for StaticRefPtr +#include "mozilla/gfx/UserData.h" // for UserDataKey #include "mozilla/webrender/WebRenderTypes.h" // for wr::ImageKey namespace mozilla { namespace gfx { class SourceSurfaceSharedData; } // namespace gfx namespace wr { @@ -66,26 +68,35 @@ public: * used to share the image data for this particular container, it will return * NS_ERROR_NOT_IMPLEMENTED. This must be called from the main thread. */ static nsresult Share(ImageContainer* aContainer, WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey); + /** + * Get the external ID, if any, bound to the shared surface. Used for memory + * reporting purposes. + */ + static Maybe<wr::ExternalImageId> + GetExternalId(const gfx::SourceSurfaceSharedData* aSurface); + private: SharedSurfacesChild() = delete; ~SharedSurfacesChild() = delete; class ImageKeyData; class SharedUserData; static nsresult ShareInternal(gfx::SourceSurfaceSharedData* aSurface, SharedUserData** aUserData); static void Unshare(const wr::ExternalImageId& aId, nsTArray<ImageKeyData>& aKeys); static void DestroySharedUserData(void* aClosure); + + static gfx::UserDataKey sSharedKey; }; } // namespace layers } // namespace mozilla #endif
new file mode 100644 --- /dev/null +++ b/gfx/layers/ipc/SharedSurfacesMemoryReport.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H +#define MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H + +#include <cstdint> // for uint32_t +#include <unordered_map> +#include "ipc/IPCMessageUtils.h" +#include "mozilla/gfx/Point.h" // for IntSize + +namespace mozilla { +namespace layers { + +class SharedSurfacesMemoryReport final +{ +public: + class SurfaceEntry final { + public: + base::ProcessId mCreatorPid; + gfx::IntSize mSize; + int32_t mStride; + uint32_t mConsumers; + bool mCreatorRef; + }; + + std::unordered_map<uint64_t, SurfaceEntry> mSurfaces; +}; + +} // namespace layers +} // namespace mozilla + +namespace IPC { + +template<> +struct ParamTraits<mozilla::layers::SharedSurfacesMemoryReport> +{ + typedef mozilla::layers::SharedSurfacesMemoryReport paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mSurfaces); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, &aResult->mSurfaces); + } +}; + +template<> +struct ParamTraits<mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry> + : public PlainOldDataSerializer<mozilla::layers::SharedSurfacesMemoryReport::SurfaceEntry> +{ +}; + +template<class KeyType, class DataType> +struct ParamTraits<std::unordered_map<KeyType, DataType>> +{ + typedef std::unordered_map<KeyType, DataType> paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.size()); + for (auto i = aParam.begin(); i != aParam.end(); ++i) { + WriteParam(aMsg, i->first); + WriteParam(aMsg, i->second); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + size_t count; + if (!ReadParam(aMsg, aIter, &count)) { + return false; + } + for (; count > 0; --count) { + KeyType k; + DataType v; + if (!ReadParam(aMsg, aIter, &k) || + !ReadParam(aMsg, aIter, &v)) { + return false; + } + aResult->insert(std::make_pair(std::move(k), std::move(v))); + } + return true; + } +}; + +} // namespace IPC + +#endif
--- a/gfx/layers/ipc/SharedSurfacesParent.cpp +++ b/gfx/layers/ipc/SharedSurfacesParent.cpp @@ -1,16 +1,18 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SharedSurfacesParent.h" #include "mozilla/DebugOnly.h" +#include "mozilla/gfx/GPUProcessManager.h" +#include "mozilla/layers/SharedSurfacesMemoryReport.h" #include "mozilla/layers/SourceSurfaceSharedData.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/webrender/RenderSharedSurfaceTextureHost.h" #include "mozilla/webrender/RenderThread.h" namespace mozilla { namespace layers { @@ -80,31 +82,31 @@ SharedSurfacesParent::Acquire(const wr:: if (surface) { DebugOnly<bool> rv = surface->AddConsumer(); MOZ_ASSERT(!rv); } return surface.forget(); } /* static */ bool -SharedSurfacesParent::Release(const wr::ExternalImageId& aId) +SharedSurfacesParent::Release(const wr::ExternalImageId& aId, bool aForCreator) { StaticMutexAutoLock lock(sMutex); if (!sInstance) { return false; } uint64_t id = wr::AsUint64(aId); RefPtr<SourceSurfaceSharedDataWrapper> surface; sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface)); if (!surface) { return false; } - if (surface->RemoveConsumer()) { + if (surface->RemoveConsumer(aForCreator)) { wr::RenderThread::Get()->UnregisterExternalImage(id); sInstance->mSurfaces.Remove(id); } return true; } /* static */ void @@ -138,32 +140,34 @@ SharedSurfacesParent::AddSameProcess(con sInstance->mSurfaces.Put(id, surface); } /* static */ void SharedSurfacesParent::RemoveSameProcess(const wr::ExternalImageId& aId) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); - Release(aId); + Release(aId, /* aForCreator */ true); } /* static */ void SharedSurfacesParent::DestroyProcess(base::ProcessId aPid) { StaticMutexAutoLock lock(sMutex); if (!sInstance) { return; } // Note that the destruction of a parent may not be cheap if it still has a // lot of surfaces still bound that require unmapping. for (auto i = sInstance->mSurfaces.Iter(); !i.Done(); i.Next()) { SourceSurfaceSharedDataWrapper* surface = i.Data(); - if (surface->GetCreatorPid() == aPid && surface->RemoveConsumer()) { + if (surface->GetCreatorPid() == aPid && + surface->HasCreatorRef() && + surface->RemoveConsumer(/* aForCreator */ true)) { wr::RenderThread::Get()->UnregisterExternalImage(i.Key()); i.Remove(); } } } /* static */ void SharedSurfacesParent::Add(const wr::ExternalImageId& aId, @@ -195,14 +199,62 @@ SharedSurfacesParent::Add(const wr::Exte surface->AddConsumer(); sInstance->mSurfaces.Put(id, surface.forget()); } /* static */ void SharedSurfacesParent::Remove(const wr::ExternalImageId& aId) { - DebugOnly<bool> rv = Release(aId); + DebugOnly<bool> rv = Release(aId, /* aForCreator */ true); MOZ_ASSERT(rv); } +/* static */ void +SharedSurfacesParent::AccumulateMemoryReport(base::ProcessId aPid, + SharedSurfacesMemoryReport& aReport) +{ + StaticMutexAutoLock lock(sMutex); + if (!sInstance) { + return; + } + + for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) { + SourceSurfaceSharedDataWrapper* surface = i.Data(); + if (surface->GetCreatorPid() == aPid) { + aReport.mSurfaces.insert(std::make_pair(i.Key(), + SharedSurfacesMemoryReport::SurfaceEntry { + aPid, surface->GetSize(), surface->Stride(), + surface->GetConsumers(), surface->HasCreatorRef() })); + } + } +} + +/* static */ bool +SharedSurfacesParent::AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport) +{ + if (XRE_IsParentProcess()) { + GPUProcessManager* gpm = GPUProcessManager::Get(); + if (!gpm || gpm->GPUProcessPid() != -1) { + return false; + } + } else if (!XRE_IsGPUProcess()) { + return false; + } + + StaticMutexAutoLock lock(sMutex); + if (!sInstance) { + return true; + } + + for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) { + SourceSurfaceSharedDataWrapper* surface = i.Data(); + aReport.mSurfaces.insert(std::make_pair(i.Key(), + SharedSurfacesMemoryReport::SurfaceEntry { + surface->GetCreatorPid(), surface->GetSize(), surface->Stride(), + surface->GetConsumers(), surface->HasCreatorRef() })); + } + + return true; +} + } // namespace layers } // namespace mozilla
--- a/gfx/layers/ipc/SharedSurfacesParent.h +++ b/gfx/layers/ipc/SharedSurfacesParent.h @@ -24,41 +24,48 @@ namespace gfx { class DataSourceSurface; class SourceSurfaceSharedData; class SourceSurfaceSharedDataWrapper; } // namespace gfx namespace layers { class SharedSurfacesChild; +class SharedSurfacesMemoryReport; class SharedSurfacesParent final { public: static void Initialize(); static void Shutdown(); // Get without increasing the consumer count. static already_AddRefed<gfx::DataSourceSurface> Get(const wr::ExternalImageId& aId); // Get but also increase the consumer count. Must call Release after finished. static already_AddRefed<gfx::DataSourceSurface> Acquire(const wr::ExternalImageId& aId); - static bool Release(const wr::ExternalImageId& aId); + static bool Release(const wr::ExternalImageId& aId, + bool aForCreator = false); static void Add(const wr::ExternalImageId& aId, const SurfaceDescriptorShared& aDesc, base::ProcessId aPid); static void Remove(const wr::ExternalImageId& aId); static void DestroyProcess(base::ProcessId aPid); + static void AccumulateMemoryReport(base::ProcessId aPid, + SharedSurfacesMemoryReport& aReport); + + static bool AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport); + ~SharedSurfacesParent(); private: friend class SharedSurfacesChild; SharedSurfacesParent(); static void AddSameProcess(const wr::ExternalImageId& aId,
--- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -191,16 +191,17 @@ EXPORTS.mozilla.layers += [ 'ipc/LayerTransactionParent.h', 'ipc/LayerTreeOwnerTracker.h', 'ipc/RefCountedShmem.h', 'ipc/RemoteContentController.h', 'ipc/ShadowLayers.h', 'ipc/SharedPlanarYCbCrImage.h', 'ipc/SharedRGBImage.h', 'ipc/SharedSurfacesChild.h', + 'ipc/SharedSurfacesMemoryReport.h', 'ipc/SharedSurfacesParent.h', 'ipc/SynchronousTask.h', 'ipc/TextureForwarder.h', 'ipc/UiCompositorControllerChild.h', 'ipc/UiCompositorControllerMessageTypes.h', 'ipc/UiCompositorControllerParent.h', 'ipc/VideoBridgeChild.h', 'ipc/VideoBridgeParent.h',
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1,14 +1,15 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/FontPropertyTypes.h" +#include "mozilla/image/ImageMemoryReporter.h" #include "mozilla/layers/CompositorManagerChild.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter #include "mozilla/webrender/RenderThread.h" #include "mozilla/webrender/WebRenderAPI.h" #include "mozilla/webrender/webrender_ffi.h" #include "mozilla/layers/PaintThread.h" @@ -1139,16 +1140,17 @@ gfxPlatform::InitLayersIPC() if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) { layers::PaintThread::Start(); } } if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) { if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && gfxVars::UseWebRender()) { wr::RenderThread::Start(); + image::ImageMemoryReporter::InitForWebRender(); } layers::CompositorThreadHolder::Start(); gfx::VRListenerThreadHolder::Start(); } } /* static */ void @@ -1172,16 +1174,17 @@ gfxPlatform::ShutdownLayersIPC() } } else if (XRE_IsParentProcess()) { gfx::VRManagerChild::ShutDown(); layers::CompositorManagerChild::Shutdown(); layers::ImageBridgeChild::ShutDown(); // This has to happen after shutting down the child protocols. layers::CompositorThreadHolder::Shutdown(); gfx::VRListenerThreadHolder::Shutdown(); + image::ImageMemoryReporter::ShutdownForWebRender(); // There is a case that RenderThread exists when gfxVars::UseWebRender() is false. // This could happen when WebRender was fallbacked to compositor. if (wr::RenderThread::Get()) { wr::RenderThread::ShutDown(); Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF); }
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -552,16 +552,17 @@ private: DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false); DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true); DECL_GFX_PREF(Live, "image.infer-src-animation.threshold-ms", ImageInferSrcAnimationThresholdMS, uint32_t, 2000); DECL_GFX_PREF(Live, "image.layout_network_priority", ImageLayoutNetworkPriority, bool, true); DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time", ImageMemDecodeBytesAtATime, uint32_t, 200000); DECL_GFX_PREF(Live, "image.mem.discardable", ImageMemDiscardable, bool, false); DECL_GFX_PREF(Once, "image.mem.animated.discardable", ImageMemAnimatedDiscardable, bool, false); DECL_GFX_PREF(Live, "image.mem.animated.use_heap", ImageMemAnimatedUseHeap, bool, false); + DECL_GFX_PREF(Live, "image.mem.debug-reporting", ImageMemDebugReporting, bool, false); DECL_GFX_PREF(Live, "image.mem.shared", ImageMemShared, bool, true); DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1); DECL_GFX_PREF(Once, "image.mem.surfacecache.max_size_kb", ImageMemSurfaceCacheMaxSizeKB, uint32_t, 100 * 1024); DECL_GFX_PREF(Once, "image.mem.surfacecache.min_expiration_ms", ImageMemSurfaceCacheMinExpirationMS, uint32_t, 60*1000); DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor", ImageMemSurfaceCacheSizeFactor, uint32_t, 64); DECL_GFX_PREF(Live, "image.mem.volatile.min_threshold_kb", ImageMemVolatileMinThresholdKB, int32_t, -1); DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit", ImageMTDecodingLimit, int32_t, -1); DECL_GFX_PREF(Once, "image.multithreaded_decoding.idle_timeout", ImageMTDecodingIdleTimeout, int32_t, -1);
--- a/gfx/webrender/res/cs_border_segment.glsl +++ b/gfx/webrender/res/cs_border_segment.glsl @@ -147,17 +147,17 @@ vec4[2] get_colors_for_side(vec4 color, return result; } void main(void) { int segment = aFlags & 0xff; int style0 = (aFlags >> 8) & 0xff; int style1 = (aFlags >> 16) & 0xff; - int clip_mode = (aFlags >> 24) & 0xff; + int clip_mode = (aFlags >> 24) & 0x0f; vec2 outer_scale = get_outer_corner_scale(segment); vec2 outer = outer_scale * aRect.zw; vec2 clip_sign = 1.0 - 2.0 * outer_scale; // Set some flags used by the FS to determine the // orientation of the two edges in this corner. ivec2 edge_axis = ivec2(0, 0);
--- a/gfx/webrender/res/cs_border_solid.glsl +++ b/gfx/webrender/res/cs_border_solid.glsl @@ -1,14 +1,18 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include shared,ellipse +#define DONT_MIX 0 +#define MIX_AA 1 +#define MIX_NO_AA 2 + // For edges, the colors are the same. For corners, these // are the colors of each edge making up the corner. flat varying vec4 vColor0; flat varying vec4 vColor1; // A point + tangent defining the line where the edge // transition occurs. Used for corners only. flat varying vec4 vColorLine; @@ -65,31 +69,32 @@ vec2 get_outer_corner_scale(int segment) break; } return p; } void main(void) { int segment = aFlags & 0xff; + bool do_aa = ((aFlags >> 24) & 0xf0) != 0; vec2 outer_scale = get_outer_corner_scale(segment); vec2 outer = outer_scale * aRect.zw; vec2 clip_sign = 1.0 - 2.0 * outer_scale; int mix_colors; switch (segment) { case SEGMENT_TOP_LEFT: case SEGMENT_TOP_RIGHT: case SEGMENT_BOTTOM_RIGHT: case SEGMENT_BOTTOM_LEFT: - mix_colors = 1; + mix_colors = do_aa ? MIX_AA : MIX_NO_AA; break; default: - mix_colors = 0; + mix_colors = DONT_MIX; break; } vMixColors = mix_colors; vPos = aRect.zw * aPosition.xy; vColor0 = aColor0; vColor1 = aColor1; @@ -99,31 +104,36 @@ void main(void) { gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0); } #endif #ifdef WR_FRAGMENT_SHADER void main(void) { float aa_range = compute_aa_range(vPos); + bool do_aa = vMixColors != MIX_NO_AA; float mix_factor = 0.0; - if (vMixColors != 0) { + if (vMixColors != DONT_MIX) { float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos); - mix_factor = distance_aa(aa_range, -d_line); + if (do_aa) { + mix_factor = distance_aa(aa_range, -d_line); + } else { + mix_factor = d_line + EPSILON >= 0. ? 1.0 : 0.0; + } } // Check if inside corner clip-region vec2 clip_relative_pos = vPos - vClipCenter_Sign.xy; bool in_clip_region = all(lessThan(vClipCenter_Sign.zw * clip_relative_pos, vec2(0.0))); float d = -1.0; if (in_clip_region) { float d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy, aa_range); float d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw, aa_range); d = max(d_radii_a, -d_radii_b); } - float alpha = distance_aa(aa_range, d); + float alpha = do_aa ? distance_aa(aa_range, d) : 1.0; vec4 color = mix(vColor0, vColor1, mix_factor); oFragColor = color * alpha; } #endif
--- a/gfx/webrender/src/border.rs +++ b/gfx/webrender/src/border.rs @@ -98,16 +98,17 @@ impl From<BorderSide> for BorderSideAu { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BorderCacheKey { pub left: BorderSideAu, pub right: BorderSideAu, pub top: BorderSideAu, pub bottom: BorderSideAu, pub radius: BorderRadiusAu, pub widths: SideOffsets2D<Au>, + pub do_aa: bool, pub scale: Au, } impl BorderCacheKey { pub fn new(border: &NormalBorder, widths: &LayoutSideOffsets) -> Self { BorderCacheKey { left: border.left.into(), top: border.top.into(), @@ -115,16 +116,17 @@ impl BorderCacheKey { bottom: border.bottom.into(), widths: SideOffsets2D::new( Au::from_f32_px(widths.top), Au::from_f32_px(widths.right), Au::from_f32_px(widths.bottom), Au::from_f32_px(widths.left), ), radius: border.radius.into(), + do_aa: border.do_aa, scale: Au(0), } } } pub fn ensure_no_corner_overlap( radius: &mut BorderRadius, rect: &LayoutRect, @@ -569,16 +571,17 @@ bitflags! { /// `available_size_dependence` is non-empty, which is effectively just dashed /// and dotted borders for now, since the spacing between the dash and dots /// changes depending on that size. #[derive(Debug)] pub struct BorderRenderTaskInfo { pub border_segments: Vec<BorderSegmentInfo>, pub size: DeviceIntSize, pub available_size_dependence: AvailableSizeDependence, + do_aa: bool, } #[derive(PartialEq, Eq)] enum DependsOnAvailableSize { No, Yes, } @@ -956,16 +959,17 @@ impl BorderRenderTaskInfo { &mut border_segments, brush_segments, ); Some(BorderRenderTaskInfo { border_segments, size: size.to_i32(), available_size_dependence: size_dependence, + do_aa: border.do_aa, }) } /// Returns the cache key size for this task, based on our available size /// dependence computed earlier. #[inline] pub fn cache_key_size( &self, @@ -1021,16 +1025,17 @@ impl BorderRenderTaskInfo { style0, style1, color0, color1, info.segment, &mut instances, info.widths, info.radius, + self.do_aa, ); } instances } /// Computes the maximum scale that we allow for this set of border parameters. /// capping the scale will result in rendering very large corners at a lower @@ -1089,20 +1094,22 @@ fn add_segment( style0: BorderStyle, style1: BorderStyle, color0: ColorF, color1: ColorF, segment: BorderSegment, instances: &mut Vec<BorderInstance>, widths: DeviceSize, radius: DeviceSize, + do_aa: bool, ) { let base_flags = (segment as i32) | ((style0 as i32) << 8) | - ((style1 as i32) << 16); + ((style1 as i32) << 16) | + ((do_aa as i32) << 28); let base_instance = BorderInstance { task_origin: DevicePoint::zero(), local_rect: task_rect, flags: base_flags, color0: color0.premultiplied(), color1: color1.premultiplied(), widths,
--- a/gfx/webrender_api/src/display_item.rs +++ b/gfx/webrender_api/src/display_item.rs @@ -257,33 +257,55 @@ pub struct TextDisplayItem { #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct NormalBorder { pub left: BorderSide, pub right: BorderSide, pub top: BorderSide, pub bottom: BorderSide, pub radius: BorderRadius, + /// Whether to apply anti-aliasing on the border corners. + /// + /// Note that for this to be `false` and work, this requires the borders to + /// be solid, and no border-radius. + pub do_aa: bool, } impl NormalBorder { // Construct a border based upon self with color pub fn with_color(&self, color: ColorF) -> Self { let mut b = *self; b.left.color = color; b.right.color = color; b.top.color = color; b.bottom.color = color; b } + fn can_disable_antialiasing(&self) -> bool { + fn is_valid(style: BorderStyle) -> bool { + style == BorderStyle::Solid || style == BorderStyle::None + } + + self.radius.is_zero() && + is_valid(self.top.style) && + is_valid(self.left.style) && + is_valid(self.bottom.style) && + is_valid(self.right.style) + } + /// Normalizes a border so that we don't render disallowed stuff, like inset /// borders that are less than two pixels wide. #[inline] pub fn normalize(&mut self, widths: &LayoutSideOffsets) { + debug_assert!( + self.do_aa || self.can_disable_antialiasing(), + "Unexpected disabled-antialising in a border, likely won't work or will be ignored" + ); + #[inline] fn renders_small_border_solid(style: BorderStyle) -> bool { match style { BorderStyle::Groove | BorderStyle::Ridge => true, _ => false, } }
--- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1,1 +1,1 @@ -b83ec3fd994b69f31e9c6b6ffa19426b2b98c66a +2549b791abb3a24c115d03616ddd82e14727b5a1
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2184,16 +2184,17 @@ pub extern "C" fn wr_dp_push_border(stat debug_assert!(unsafe { is_in_main_thread() }); let border_details = BorderDetails::Normal(NormalBorder { left: left.into(), right: right.into(), top: top.into(), bottom: bottom.into(), radius: radius.into(), + do_aa: true, }); let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into()); prim_info.is_backface_visible = is_backface_visible; prim_info.tag = state.current_tag; state.frame_builder .dl_builder .push_border(&prim_info, widths,
--- a/gfx/wrench/src/yaml_frame_reader.rs +++ b/gfx/wrench/src/yaml_frame_reader.rs @@ -865,22 +865,24 @@ impl YamlFrameReader { let bottom = BorderSide { color: colors[2], style: styles[2], }; let left = BorderSide { color: colors[3], style: styles[3], }; + let do_aa = item["do_aa"].as_bool().unwrap_or(true); Some(BorderDetails::Normal(NormalBorder { top, left, bottom, right, radius, + do_aa, })) } "image" | "gradient" | "radial-gradient" => { let image_width = item["image-width"] .as_i64() .unwrap_or(info.rect.size.width as i64); let image_height = item["image-height"] .as_i64()
--- a/gfx/wrench/src/yaml_frame_writer.rs +++ b/gfx/wrench/src/yaml_frame_writer.rs @@ -864,16 +864,17 @@ impl YamlFrameWriter { BorderStyle::Groove => "groove", }.to_owned() }) .collect(); yaml_node(&mut v, "width", f32_vec_yaml(&widths, true)); str_node(&mut v, "border-type", "normal"); yaml_node(&mut v, "color", string_vec_yaml(&colors, true)); yaml_node(&mut v, "style", string_vec_yaml(&styles, true)); + bool_node(&mut v, "do_aa", details.do_aa); if let Some(radius_node) = maybe_radius_yaml(&details.radius) { yaml_node(&mut v, "radius", radius_node); } } BorderDetails::NinePatch(ref details) => { let widths: Vec<f32> = vec![ item.widths.top, item.widths.right,
--- a/gfx/wrench/src/yaml_helper.rs +++ b/gfx/wrench/src/yaml_helper.rs @@ -41,16 +41,17 @@ pub trait YamlHelper { fn string_to_color(color: &str) -> Option<ColorF> { match color { "red" => Some(ColorF::new(1.0, 0.0, 0.0, 1.0)), "green" => Some(ColorF::new(0.0, 1.0, 0.0, 1.0)), "blue" => Some(ColorF::new(0.0, 0.0, 1.0, 1.0)), "white" => Some(ColorF::new(1.0, 1.0, 1.0, 1.0)), "black" => Some(ColorF::new(0.0, 0.0, 0.0, 1.0)), "yellow" => Some(ColorF::new(1.0, 1.0, 0.0, 1.0)), + "transparent" => Some(ColorF::new(1.0, 1.0, 1.0, 0.0)), s => { let items: Vec<f32> = s.split_whitespace() .map(|s| f32::from_str(s).unwrap()) .collect(); if items.len() == 3 { Some(ColorF::new( items[0] / 255.0, items[1] / 255.0,
--- a/image/AnimationSurfaceProvider.cpp +++ b/image/AnimationSurfaceProvider.cpp @@ -201,29 +201,33 @@ AnimationSurfaceProvider::LogicalSizeInB // animation has, so we really can't do better here. This will become correct // once bug 1289954 is complete. IntSize size = GetSurfaceKey().Size(); return 3 * size.width * size.height * sizeof(uint32_t); } void AnimationSurfaceProvider::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, - size_t& aHeapSizeOut, - size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) + const AddSizeOfCb& aCallback) { // Note that the surface cache lock is already held here, and then we acquire // mFramesMutex. For this method, this ordering is unavoidable, which means // that we must be careful to always use the same ordering elsewhere. MutexAutoLock lock(mFramesMutex); + size_t i = 0; for (const RawAccessFrameRef& frame : mFrames.Frames()) { + ++i; if (frame) { - frame->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, - aNonHeapSizeOut, aExtHandlesOut); + frame->AddSizeOfExcludingThis(aMallocSizeOf, + [&](AddSizeOfCbData& aMetadata) { + aMetadata.index = i; + aCallback(aMetadata); + } + ); } } } void AnimationSurfaceProvider::Run() { MutexAutoLock lock(mDecodingMutex);
--- a/image/AnimationSurfaceProvider.h +++ b/image/AnimationSurfaceProvider.h @@ -44,19 +44,17 @@ public: // We use the ISurfaceProvider constructor of DrawableSurface to indicate that // our surfaces are computed lazily. DrawableSurface Surface() override { return DrawableSurface(WrapNotNull(this)); } bool IsFinished() const override; bool IsFullyDecoded() const override; size_t LogicalSizeInBytes() const override; void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, - size_t& aHeapSizeOut, - size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) override; + const AddSizeOfCb& aCallback) override; void Reset() override; void Advance(size_t aFrame) override; protected: DrawableFrameRef DrawableRef(size_t aFrame) override; RawAccessFrameRef RawAccessRef(size_t aFrame) override; // Animation frames are always locked. This is because we only want to release
--- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -556,30 +556,34 @@ DoCollectSizeOfCompositingSurfaces(const nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) { // Concoct a SurfaceKey for this surface. SurfaceKey key = RasterSurfaceKey(aSurface->GetImageSize(), DefaultSurfaceFlags(), PlaybackType::eStatic); - // Create a counter for this surface. - SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, - /* aCannotSubstitute */ false, - /* aIsFactor2 */ false, aType); + // Extract the surface's memory usage information. + aSurface->AddSizeOfExcludingThis(aMallocSizeOf, + [&](imgFrame::AddSizeOfCbData& aMetadata) { + // Create a counter for this surface. + SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, + /* aCannotSubstitute */ false, + /* aIsFactor2 */ false, aType); - // Extract the surface's memory usage information. - size_t heap = 0, nonHeap = 0, handles = 0; - aSurface->AddSizeOfExcludingThis(aMallocSizeOf, heap, nonHeap, handles); - counter.Values().SetDecodedHeap(heap); - counter.Values().SetDecodedNonHeap(nonHeap); - counter.Values().SetExternalHandles(handles); + // Record it. + counter.Values().SetDecodedHeap(aMetadata.heap); + counter.Values().SetDecodedNonHeap(aMetadata.nonHeap); + counter.Values().SetExternalHandles(aMetadata.handles); + counter.Values().SetFrameIndex(aMetadata.index); + counter.Values().SetExternalId(aMetadata.externalId); - // Record it. - aCounters.AppendElement(counter); + aCounters.AppendElement(counter); + } + ); } void FrameAnimator::CollectSizeOfCompositingSurfaces( nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) const { if (mCompositingFrame) {
--- a/image/ISurfaceProvider.h +++ b/image/ISurfaceProvider.h @@ -60,31 +60,31 @@ public: virtual bool IsFullyDecoded() const { return IsFinished(); } /// @return the number of bytes of memory this ISurfaceProvider is expected to /// require. Optimizations may result in lower real memory usage. Trivial /// overhead is ignored. Because this value is used in bookkeeping, it's /// important that it be constant over the lifetime of this object. virtual size_t LogicalSizeInBytes() const = 0; + typedef imgFrame::AddSizeOfCbData AddSizeOfCbData; + typedef imgFrame::AddSizeOfCb AddSizeOfCb; + /// @return the actual number of bytes of memory this ISurfaceProvider is /// using. May vary over the lifetime of the ISurfaceProvider. The default /// implementation is appropriate for static ISurfaceProviders. virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, - size_t& aHeapSizeOut, - size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) + const AddSizeOfCb& aCallback) { DrawableFrameRef ref = DrawableRef(/* aFrame = */ 0); if (!ref) { return; } - ref->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, - aNonHeapSizeOut, aExtHandlesOut); + ref->AddSizeOfExcludingThis(aMallocSizeOf, aCallback); } virtual void Reset() { } virtual void Advance(size_t aFrame) { } /// @return the availability state of this ISurfaceProvider, which indicates /// whether DrawableRef() could successfully return a surface. Should only be /// called from SurfaceCache code as it relies on SurfaceCache for
--- a/image/Image.h +++ b/image/Image.h @@ -31,41 +31,49 @@ class Image; struct MemoryCounter { MemoryCounter() : mSource(0) , mDecodedHeap(0) , mDecodedNonHeap(0) , mExternalHandles(0) + , mFrameIndex(0) + , mExternalId(0) { } void SetSource(size_t aCount) { mSource = aCount; } size_t Source() const { return mSource; } void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; } size_t DecodedHeap() const { return mDecodedHeap; } void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; } size_t DecodedNonHeap() const { return mDecodedNonHeap; } void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; } size_t ExternalHandles() const { return mExternalHandles; } + void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; } + size_t FrameIndex() const { return mFrameIndex; } + void SetExternalId(uint64_t aId) { mExternalId = aId; } + uint64_t ExternalId() const { return mExternalId; } MemoryCounter& operator+=(const MemoryCounter& aOther) { mSource += aOther.mSource; mDecodedHeap += aOther.mDecodedHeap; mDecodedNonHeap += aOther.mDecodedNonHeap; mExternalHandles += aOther.mExternalHandles; return *this; } private: size_t mSource; size_t mDecodedHeap; size_t mDecodedNonHeap; size_t mExternalHandles; + size_t mFrameIndex; + uint64_t mExternalId; }; enum class SurfaceMemoryCounterType { NORMAL, COMPOSITING, COMPOSITING_PREV };
new file mode 100644 --- /dev/null +++ b/image/ImageMemoryReporter.cpp @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ImageMemoryReporter.h" +#include "Image.h" +#include "mozilla/layers/SharedSurfacesParent.h" +#include "nsIMemoryReporter.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace image { + +ImageMemoryReporter::WebRenderReporter* ImageMemoryReporter::sWrReporter; + +class ImageMemoryReporter::WebRenderReporter final : public nsIMemoryReporter +{ +public: + NS_DECL_ISUPPORTS + + WebRenderReporter() + { } + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) override + { + layers::SharedSurfacesMemoryReport report; + layers::SharedSurfacesParent::AccumulateMemoryReport(report); + ReportSharedSurfaces(aHandleReport, aData, /* aIsForCompositor */ true, report); + return NS_OK; + } + +private: + virtual ~WebRenderReporter() + { } +}; + +NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter, nsIMemoryReporter) + +/* static */ void +ImageMemoryReporter::InitForWebRender() +{ + MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); + if (!sWrReporter) { + sWrReporter = new WebRenderReporter(); + RegisterStrongMemoryReporter(sWrReporter); + } +} + +/* static */ void +ImageMemoryReporter::ShutdownForWebRender() +{ + MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); + if (sWrReporter) { + UnregisterStrongMemoryReporter(sWrReporter); + sWrReporter = nullptr; + } +} + +/* static */ void +ImageMemoryReporter::ReportSharedSurfaces(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces) +{ + ReportSharedSurfaces(aHandleReport, aData, + /* aIsForCompositor */ false, + aSharedSurfaces); +} + +/* static */ void +ImageMemoryReporter::ReportSharedSurfaces(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + bool aIsForCompositor, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces) +{ + MOZ_ASSERT_IF(aIsForCompositor, XRE_IsParentProcess() || XRE_IsGPUProcess()); + MOZ_ASSERT_IF(!aIsForCompositor, + XRE_IsParentProcess() || XRE_IsContentProcess()); + + for (auto i = aSharedSurfaces.mSurfaces.begin(); + i != aSharedSurfaces.mSurfaces.end(); ++i) { + ReportSharedSurface(aHandleReport, aData, aIsForCompositor, i->first, i->second); + } +} + +/* static */ void +ImageMemoryReporter::ReportSharedSurface(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + bool aIsForCompositor, + uint64_t aExternalId, + const layers::SharedSurfacesMemoryReport::SurfaceEntry& aEntry) +{ + nsAutoCString path; + if (aIsForCompositor) { + path.AppendLiteral("gfx/webrender/images/mapped_from_owner/"); + } else { + path.AppendLiteral("gfx/webrender/images/owner_cache_missing/"); + } + + if (aIsForCompositor) { + path.AppendLiteral("pid="); + path.AppendInt(uint32_t(aEntry.mCreatorPid)); + path.AppendLiteral("/"); + } + + if (gfxPrefs::ImageMemDebugReporting()) { + path.AppendInt(aExternalId, 16); + path.AppendLiteral("/"); + } + + path.AppendLiteral("image("); + path.AppendInt(aEntry.mSize.width); + path.AppendLiteral("x"); + path.AppendInt(aEntry.mSize.height); + path.AppendLiteral(", compositor_ref:"); + path.AppendInt(aEntry.mConsumers); + path.AppendLiteral(", creator_ref:"); + path.AppendInt(aEntry.mCreatorRef); + path.AppendLiteral(")/decoded-nonheap"); + + size_t surfaceSize = + mozilla::ipc::SharedMemory::PageAlignedSize(aEntry.mSize.height * + aEntry.mStride); + + // If this memory has already been reported elsewhere (e.g. as part of our + // explicit section in the surface cache), we don't want report it again as + // KIND_NONHEAP and have it counted again. + bool sameProcess = aEntry.mCreatorPid == base::GetCurrentProcId(); + int32_t kind = aIsForCompositor && !sameProcess + ? nsIMemoryReporter::KIND_NONHEAP + : nsIMemoryReporter::KIND_OTHER; + + NS_NAMED_LITERAL_CSTRING(desc, "Decoded image data stored in shared memory."); + aHandleReport->Callback(EmptyCString(), path, kind, + nsIMemoryReporter::UNITS_BYTES, + surfaceSize, desc, aData); +} + +/* static */ void +ImageMemoryReporter::AppendSharedSurfacePrefix(nsACString& aPathPrefix, + const SurfaceMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) +{ + uint64_t extId = aCounter.Values().ExternalId(); + if (extId) { + auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); + + if (gfxPrefs::ImageMemDebugReporting()) { + aPathPrefix.AppendLiteral(", external_id:"); + aPathPrefix.AppendInt(extId, 16); + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + aPathPrefix.AppendLiteral(", compositor_ref:"); + aPathPrefix.AppendInt(gpuEntry->second.mConsumers); + } else { + aPathPrefix.AppendLiteral(", compositor_ref:missing"); + } + } + + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + MOZ_ASSERT(gpuEntry->second.mCreatorRef); + aSharedSurfaces.mSurfaces.erase(gpuEntry); + } + } +} + +/* static */ void +ImageMemoryReporter::TrimSharedSurfaces(const ImageMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) +{ + if (aSharedSurfaces.mSurfaces.empty()) { + return; + } + + for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) { + uint64_t extId = counter.Values().ExternalId(); + if (extId) { + auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + MOZ_ASSERT(gpuEntry->second.mCreatorRef); + aSharedSurfaces.mSurfaces.erase(gpuEntry); + } + } + } +} + +} // image +} // mozilla
new file mode 100644 --- /dev/null +++ b/image/ImageMemoryReporter.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_image_ImageMemoryReporter_h +#define mozilla_image_ImageMemoryReporter_h + +#include <cstdint> +#include "nsString.h" +#include "mozilla/layers/SharedSurfacesMemoryReport.h" + +class nsISupports; +class nsIHandleReportCallback; + +namespace mozilla { +namespace image { +struct ImageMemoryCounter; +struct SurfaceMemoryCounter; + +class ImageMemoryReporter final +{ +public: + /** + * Initializes image related memory reporting in the compositor process when + * using WebRender. + */ + static void InitForWebRender(); + + /** + * Tears down image related memory reporting in the compositor process when + * using WebRender. + */ + static void ShutdownForWebRender(); + + /** + * Report all remaining entries in the shared surface's memory report. This + * should be used by the content or main process to allow reporting any + * entries that is was unable to cross reference with the local surface cache. + * These are candidates for having been leaked. This should be used in + * conjunction with AppendSharedSurfacePrefix and/or TrimSharedSurfaces to + * produce the expected result. + */ + static void ReportSharedSurfaces(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces); + + /** + * Adjust the path prefix for a surface to include any additional metadata for + * the shared surface, if any. It will also remove any corresponding entries + * in the given memory report. + */ + static void AppendSharedSurfacePrefix(nsACString& aPathPrefix, + const SurfaceMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces); + + /** + * Remove all entries in the memory report for the given set of surfaces for + * an image. This is useful when we aren't reporting on a particular image + * because it isn't notable. + */ + static void TrimSharedSurfaces(const ImageMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces); + +private: + /** + * Report all remaining entries in the shared surface's memory report. + * + * aIsForCompositor controls how to intepret what remains in the report. If + * true, this should mirror exactly what is currently in + * SharedSurfacesParent's cache. This will report entries that are currently + * mapped into the compositor process. If false, then we are in a content or + * main process, and it should have removed entries that also exist in its + * local surface cache -- thus any remaining entries are those that are + * candidates for leaks. + */ + static void ReportSharedSurfaces(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + bool aIsForCompositor, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces); + + static void ReportSharedSurface(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + bool aIsForCompositor, + uint64_t aExternalId, + const layers::SharedSurfacesMemoryReport::SurfaceEntry& aEntry); + + class WebRenderReporter; + static WebRenderReporter* sWrReporter; +}; + +} // image +} // mozilla + +#endif // mozilla_image_ImageMemoryReporter_h
--- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -183,39 +183,40 @@ public: SurfaceMemoryReport(nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) : mCounters(aCounters) , mMallocSizeOf(aMallocSizeOf) { } void Add(NotNull<CachedSurface*> aCachedSurface, bool aIsFactor2) { - SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(), - aCachedSurface->IsLocked(), - aCachedSurface->CannotSubstitute(), - aIsFactor2); - if (aCachedSurface->IsPlaceholder()) { return; } // Record the memory used by the ISurfaceProvider. This may not have a // straightforward relationship to the size of the surface that // DrawableRef() returns if the surface is generated dynamically. (i.e., // for surfaces with PlaybackType::eAnimated.) - size_t heap = 0; - size_t nonHeap = 0; - size_t handles = 0; - aCachedSurface->mProvider - ->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap, handles); - counter.Values().SetDecodedHeap(heap); - counter.Values().SetDecodedNonHeap(nonHeap); - counter.Values().SetExternalHandles(handles); + aCachedSurface->mProvider->AddSizeOfExcludingThis(mMallocSizeOf, + [&](ISurfaceProvider::AddSizeOfCbData& aMetadata) { + SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(), + aCachedSurface->IsLocked(), + aCachedSurface->CannotSubstitute(), + aIsFactor2); - mCounters.AppendElement(counter); + counter.Values().SetDecodedHeap(aMetadata.heap); + counter.Values().SetDecodedNonHeap(aMetadata.nonHeap); + counter.Values().SetExternalHandles(aMetadata.handles); + counter.Values().SetFrameIndex(aMetadata.index); + counter.Values().SetExternalId(aMetadata.externalId); + + mCounters.AppendElement(counter); + } + ); } private: nsTArray<SurfaceMemoryCounter>& mCounters; MallocSizeOf mMallocSizeOf; }; private:
--- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -937,32 +937,34 @@ void imgFrame::SetCompositingFailed(bool val) { MOZ_ASSERT(NS_IsMainThread()); mCompositingFailed = val; } void imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, - size_t& aHeapSizeOut, - size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const + const AddSizeOfCb& aCallback) const { MonitorAutoLock lock(mMonitor); + AddSizeOfCbData metadata; if (mPalettedImageData) { - aHeapSizeOut += aMallocSizeOf(mPalettedImageData); + metadata.heap += aMallocSizeOf(mPalettedImageData); } if (mLockedSurface) { - aHeapSizeOut += aMallocSizeOf(mLockedSurface); + metadata.heap += aMallocSizeOf(mLockedSurface); } if (mOptSurface) { - aHeapSizeOut += aMallocSizeOf(mOptSurface); + metadata.heap += aMallocSizeOf(mOptSurface); } if (mRawSurface) { - aHeapSizeOut += aMallocSizeOf(mRawSurface); - mRawSurface->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, - aNonHeapSizeOut, aExtHandlesOut); + metadata.heap += aMallocSizeOf(mRawSurface); + mRawSurface->AddSizeOfExcludingThis(aMallocSizeOf, metadata.heap, + metadata.nonHeap, metadata.handles, + metadata.externalId); } + + aCallback(metadata); } } // namespace image } // namespace mozilla
--- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -201,19 +201,32 @@ public: bool GetCompositingFailed() const; void SetCompositingFailed(bool val); void SetOptimizable(); void FinalizeSurface(); already_AddRefed<SourceSurface> GetSourceSurface(); - void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, - size_t& aNonHeapSizeOut, - size_t& aExtHandlesOut) const; + struct AddSizeOfCbData { + AddSizeOfCbData() + : heap(0), nonHeap(0), handles(0), index(0), externalId(0) + { } + + size_t heap; + size_t nonHeap; + size_t handles; + size_t index; + uint64_t externalId; + }; + + typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb; + + void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, + const AddSizeOfCb& aCallback) const; private: // methods ~imgFrame(); /** * Used when the caller desires raw access to the underlying frame buffer. * If the locking succeeds, the data pointer to the start of the buffer is
--- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -41,16 +41,18 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIFileURL.h" #include "nsIFile.h" #include "nsCRT.h" #include "nsINetworkPredictor.h" #include "nsReadableUtils.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/nsMixedContentBlocker.h" +#include "mozilla/image/ImageMemoryReporter.h" +#include "mozilla/layers/CompositorManagerChild.h" #include "nsIApplicationCache.h" #include "nsIApplicationCacheContainer.h" #include "nsIMemoryReporter.h" #include "DecoderFactory.h" #include "Image.h" #include "gfxPrefs.h" @@ -76,16 +78,44 @@ class imgMemoryReporter final : public n ~imgMemoryReporter() = default; public: NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) override { + MOZ_ASSERT(NS_IsMainThread()); + + layers::CompositorManagerChild* manager = CompositorManagerChild::GetInstance(); + if (!manager || !gfxPrefs::ImageMemDebugReporting()) { + layers::SharedSurfacesMemoryReport sharedSurfaces; + FinishCollectReports(aHandleReport, aData, aAnonymize, sharedSurfaces); + return NS_OK; + } + + RefPtr<imgMemoryReporter> self(this); + nsCOMPtr<nsIHandleReportCallback> handleReport(aHandleReport); + nsCOMPtr<nsISupports> data(aData); + manager->SendReportSharedSurfacesMemory( + [=](layers::SharedSurfacesMemoryReport aReport) { + self->FinishCollectReports(handleReport, data, aAnonymize, aReport); + }, + [=](mozilla::ipc::ResponseRejectReason aReason) { + layers::SharedSurfacesMemoryReport sharedSurfaces; + self->FinishCollectReports(handleReport, data, aAnonymize, sharedSurfaces); + } + ); + return NS_OK; + } + + void FinishCollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) + { nsTArray<ImageMemoryCounter> chrome; nsTArray<ImageMemoryCounter> content; nsTArray<ImageMemoryCounter> uncached; for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) { for (auto iter = mKnownLoaders[i]->mChromeCache.Iter(); !iter.Done(); iter.Next()) { imgCacheEntry* entry = iter.UserData(); RefPtr<imgRequest> req = entry->GetRequest(); @@ -103,26 +133,35 @@ public: nsPtrHashKey<imgRequest>* entry = iter.Get(); RefPtr<imgRequest> req = entry->GetKey(); RecordCounterForRequest(req, &uncached, req->HasConsumers()); } } // Note that we only need to anonymize content image URIs. - ReportCounterArray(aHandleReport, aData, chrome, "images/chrome"); + ReportCounterArray(aHandleReport, aData, chrome, "images/chrome", + /* aAnonymize */ false, aSharedSurfaces); ReportCounterArray(aHandleReport, aData, content, "images/content", - aAnonymize); + aAnonymize, aSharedSurfaces); // Uncached images may be content or chrome, so anonymize them. ReportCounterArray(aHandleReport, aData, uncached, "images/uncached", - aAnonymize); - - return NS_OK; + aAnonymize, aSharedSurfaces); + + // Report any shared surfaces that were not merged with the surface cache. + ImageMemoryReporter::ReportSharedSurfaces(aHandleReport, aData, + aSharedSurfaces); + + nsCOMPtr<nsIMemoryReporterManager> imgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (imgr) { + imgr->EndReport(); + } } static int64_t ImagesContentUsedUncompressedDistinguishedAmount() { size_t n = 0; for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) { for (auto iter = imgLoader::sMemReporter->mKnownLoaders[i]->mCache.Iter(); @@ -201,17 +240,18 @@ private: MemoryCounter mUnusedVectorCounter; }; // Reports all images of a single kind, e.g. all used chrome images. void ReportCounterArray(nsIHandleReportCallback* aHandleReport, nsISupports* aData, nsTArray<ImageMemoryCounter>& aCounterArray, const char* aPathPrefix, - bool aAnonymize = false) + bool aAnonymize, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) { MemoryTotal summaryTotal; MemoryTotal nonNotableTotal; // Report notable images, and compute total and non-notable aggregate sizes. for (uint32_t i = 0; i < aCounterArray.Length(); i++) { ImageMemoryCounter& counter = aCounterArray[i]; @@ -225,36 +265,39 @@ private: counter.URI().Truncate(max); counter.URI().AppendLiteral(" (truncated)"); } counter.URI().ReplaceChar('/', '\\'); } summaryTotal += counter; - if (counter.IsNotable()) { - ReportImage(aHandleReport, aData, aPathPrefix, counter); + if (counter.IsNotable() || gfxPrefs::ImageMemDebugReporting()) { + ReportImage(aHandleReport, aData, aPathPrefix, + counter, aSharedSurfaces); } else { + ImageMemoryReporter::TrimSharedSurfaces(counter, aSharedSurfaces); nonNotableTotal += counter; } } // Report non-notable images in aggregate. ReportTotal(aHandleReport, aData, /* aExplicit = */ true, aPathPrefix, "<non-notable images>/", nonNotableTotal); // Report a summary in aggregate, outside of the explicit tree. ReportTotal(aHandleReport, aData, /* aExplicit = */ false, aPathPrefix, "", summaryTotal); } static void ReportImage(nsIHandleReportCallback* aHandleReport, nsISupports* aData, const char* aPathPrefix, - const ImageMemoryCounter& aCounter) + const ImageMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) { nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/")); pathPrefix.Append(aPathPrefix); pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER ? "/raster/" : "/vector/"); pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/"); pathPrefix.AppendLiteral("image("); @@ -266,25 +309,26 @@ private: if (aCounter.URI().IsEmpty()) { pathPrefix.AppendLiteral("<unknown URI>"); } else { pathPrefix.Append(aCounter.URI()); } pathPrefix.AppendLiteral(")/"); - ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter); + ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter, aSharedSurfaces); ReportSourceValue(aHandleReport, aData, pathPrefix, aCounter.Values()); } static void ReportSurfaces(nsIHandleReportCallback* aHandleReport, nsISupports* aData, const nsACString& aPathPrefix, - const ImageMemoryCounter& aCounter) + const ImageMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) { for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) { nsAutoCString surfacePathPrefix(aPathPrefix); if (counter.IsLocked()) { surfacePathPrefix.AppendLiteral("locked/"); } else { surfacePathPrefix.AppendLiteral("unlocked/"); } @@ -295,25 +339,33 @@ private: surfacePathPrefix.AppendLiteral("cannot_substitute/"); } surfacePathPrefix.AppendLiteral("surface("); surfacePathPrefix.AppendInt(counter.Key().Size().width); surfacePathPrefix.AppendLiteral("x"); surfacePathPrefix.AppendInt(counter.Key().Size().height); if (counter.Values().ExternalHandles() > 0) { - surfacePathPrefix.AppendLiteral(", external:"); + surfacePathPrefix.AppendLiteral(", handles:"); surfacePathPrefix.AppendInt(uint32_t(counter.Values().ExternalHandles())); } + ImageMemoryReporter::AppendSharedSurfacePrefix(surfacePathPrefix, counter, + aSharedSurfaces); + if (counter.Type() == SurfaceMemoryCounterType::NORMAL) { PlaybackType playback = counter.Key().Playback(); - surfacePathPrefix.Append(playback == PlaybackType::eAnimated - ? " (animation)" - : ""); + if (playback == PlaybackType::eAnimated) { + if (gfxPrefs::ImageMemDebugReporting()) { + surfacePathPrefix.AppendPrintf(" (animation %4u)", + uint32_t(counter.Values().FrameIndex())); + } else { + surfacePathPrefix.AppendLiteral(" (animation)"); + } + } if (counter.Key().Flags() != DefaultSurfaceFlags()) { surfacePathPrefix.AppendLiteral(", flags:"); surfacePathPrefix.AppendInt(uint32_t(counter.Key().Flags()), /* aRadix = */ 16); } if (counter.Key().SVGContext()) { @@ -1354,17 +1406,17 @@ imgLoader::GetCacheQueue(const ImageCach void imgLoader::GlobalInit() { sCacheTimeWeight = gfxPrefs::ImageCacheTimeWeight() / 1000.0; int32_t cachesize = gfxPrefs::ImageCacheSize(); sCacheMaxSize = cachesize > 0 ? cachesize : 0; sMemReporter = new imgMemoryReporter(); - RegisterStrongMemoryReporter(sMemReporter); + RegisterStrongAsyncMemoryReporter(sMemReporter); RegisterImagesContentUsedUncompressedDistinguishedAmount( imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount); Telemetry::ScalarSet(Telemetry::ScalarID::IMAGES_WEBP_PROBE_OBSERVED, false); Telemetry::ScalarSet(Telemetry::ScalarID::IMAGES_WEBP_CONTENT_OBSERVED, false); } void imgLoader::ShutdownMemoryReporter()
--- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -35,16 +35,17 @@ #include "plstr.h" // PL_strcasestr(...) #include "prtime.h" // for PR_Now #include "nsNetUtil.h" #include "nsIProtocolHandler.h" #include "imgIRequest.h" #include "nsProperties.h" #include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizeOfState.h" #include "mozilla/Telemetry.h" using namespace mozilla; using namespace mozilla::image; #define LOG_TEST(level) (MOZ_LOG_TEST(gImgLog, (level))) NS_IMPL_ISUPPORTS(imgRequest,
--- a/image/moz.build +++ b/image/moz.build @@ -48,31 +48,36 @@ EXPORTS += [ 'imgLoader.h', 'imgRequest.h', 'imgRequestProxy.h', 'IProgressObserver.h', 'Orientation.h', 'SurfaceCacheUtils.h', ] +EXPORTS.mozilla.image += [ + 'ImageMemoryReporter.h', +] + UNIFIED_SOURCES += [ 'AnimationFrameBuffer.cpp', 'AnimationSurfaceProvider.cpp', 'ClippedImage.cpp', 'DecodedSurfaceProvider.cpp', 'DecodePool.cpp', 'Decoder.cpp', 'DecoderFactory.cpp', 'DynamicImage.cpp', 'FrameAnimator.cpp', 'FrozenImage.cpp', 'IDecodingTask.cpp', 'Image.cpp', 'ImageCacheKey.cpp', 'ImageFactory.cpp', + 'ImageMemoryReporter.cpp', 'ImageOps.cpp', 'ImageWrapper.cpp', 'imgFrame.cpp', 'imgLoader.cpp', 'imgRequest.cpp', 'imgRequestProxy.cpp', 'imgTools.cpp', 'MultipartImage.cpp',
--- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1413,26 +1413,38 @@ GlobalObject::initTypedObjectModule(JSCo return false; JS_FOR_EACH_REFERENCE_TYPE_REPR(BINARYDATA_REFERENCE_DEFINE) #undef BINARYDATA_REFERENCE_DEFINE // Tuck away descriptors we will use for wasm. RootedValue typeDescr(cx); - MOZ_ALWAYS_TRUE(JS_GetProperty(cx, module, "int32", &typeDescr)); + // The lookups should fail only from atomization-related OOM in + // JS_GetProperty(). The properties themselves will always exist on the + // object. + + if (!JS_GetProperty(cx, module, "int32", &typeDescr)) { + return false; + } module->initReservedSlot(TypedObjectModuleObject::Int32Desc, typeDescr); - MOZ_ALWAYS_TRUE(JS_GetProperty(cx, module, "float32", &typeDescr)); + if (!JS_GetProperty(cx, module, "float32", &typeDescr)) { + return false; + } module->initReservedSlot(TypedObjectModuleObject::Float32Desc, typeDescr); - MOZ_ALWAYS_TRUE(JS_GetProperty(cx, module, "float64", &typeDescr)); + if (!JS_GetProperty(cx, module, "float64", &typeDescr)) { + return false; + } module->initReservedSlot(TypedObjectModuleObject::Float64Desc, typeDescr); - MOZ_ALWAYS_TRUE(JS_GetProperty(cx, module, "Object", &typeDescr)); + if (!JS_GetProperty(cx, module, "Object", &typeDescr)) { + return false; + } module->initReservedSlot(TypedObjectModuleObject::ObjectDesc, typeDescr); // ArrayType. RootedObject arrayType(cx); arrayType = DefineMetaTypeDescr<ArrayMetaTypeDescr>( cx, "ArrayType", global, module, TypedObjectModuleObject::ArrayTypePrototype); if (!arrayType) {
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2072,20 +2072,20 @@ JS_GetOwnPropertyDescriptor(JSContext* c if (!atom) { return false; } RootedId id(cx, AtomToId(atom)); return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); } JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, +JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, MutableHandle<PropertyDescriptor> desc) { - JSAtom* atom = AtomizeChars(cx, name, js_strlen(name)); + JSAtom* atom = AtomizeChars(cx, name, namelen); if (!atom) { return false; } RootedId id(cx, AtomToId(atom)); return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc); } JS_PUBLIC_API(bool) @@ -2100,17 +2100,29 @@ JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, MutableHandle<PropertyDescriptor> desc) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } RootedId id(cx, AtomToId(atom)); - return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc); + return JS_GetPropertyDescriptorById(cx, obj, id, desc); +} + +JS_PUBLIC_API(bool) +JS_GetUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, + MutableHandle<PropertyDescriptor> desc) +{ + JSAtom* atom = AtomizeChars(cx, name, namelen); + if (!atom) { + return false; + } + RootedId id(cx, AtomToId(atom)); + return JS_GetPropertyDescriptorById(cx, obj, id, desc); } static bool DefinePropertyByDescriptor(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc, ObjectOpResult& result) { AssertHeapIsIdle(); CHECK_THREAD(cx);
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2174,33 +2174,37 @@ extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle<JS::PropertyDescriptor> desc); extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle<JS::PropertyDescriptor> desc); extern JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, +JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle<JS::PropertyDescriptor> desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain * if no own property is found directly on obj. The object on which the * property is found is returned in desc.object(). If the property is not found * on the prototype chain, this returns true with desc.object() set to null. */ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle<JS::PropertyDescriptor> desc); extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle<JS::PropertyDescriptor> desc); +extern JS_PUBLIC_API(bool) +JS_GetUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle<JS::PropertyDescriptor> desc); + /** * Define a property on obj. * * This function uses JS::ObjectOpResult to indicate conditions that ES6 * specifies as non-error failures. This is inconvenient at best, so use this * function only if you are implementing a proxy handler's defineProperty() * method. For all other purposes, use one of the many DefineProperty functions * below that throw an exception in all failure cases.
--- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -1145,20 +1145,23 @@ ParseDate(const CharT* s, size_t length, int year = -1; int mon = -1; int mday = -1; int hour = -1; int min = -1; int sec = -1; int tzOffset = -1; + // One of '+', '-', ':', '/', or 0 (the default value). int prevc = 0; bool seenPlusMinus = false; bool seenMonthName = false; + bool seenFullYear = false; + bool negativeYear = false; size_t i = 0; while (i < length) { int c = s[i]; i++; if (c <= ' ' || c == ',' || c == '-') { if (c == '-' && '0' <= s[i] && s[i] <= '9') { prevc = c; @@ -1176,44 +1179,58 @@ ParseDate(const CharT* s, size_t length, if (--depth <= 0) { break; } } } continue; } if ('0' <= c && c <= '9') { + size_t partStart = i - 1; int n = c - '0'; while (i < length && '0' <= (c = s[i]) && c <= '9') { n = n * 10 + c - '0'; i++; } + size_t partLength = i - partStart; /* * Allow TZA before the year, so 'Wed Nov 05 21:49:11 GMT-0800 1997' * works. * * Uses of seenPlusMinus allow ':' in TZA, so Java no-timezone style * of GMT+4:30 works. */ - if ((prevc == '+' || prevc == '-')/* && year>=0 */) { + if (prevc == '-' && (tzOffset != 0 || seenPlusMinus) && partLength >= 4 && year < 0) { + // Parse as a negative, possibly zero-padded year if + // 1. the preceding character is '-', + // 2. the TZA is not 'GMT' (tested by |tzOffset != 0|), + // 3. or a TZA was already parsed |seenPlusMinus == true|, + // 4. the part length is at least 4 (to parse '-08' as a TZA), + // 5. and we did not already parse a year |year < 0|. + year = n; + seenFullYear = true; + negativeYear = true; + } else if ((prevc == '+' || prevc == '-')/* && year>=0 */) { /* Make ':' case below change tzOffset. */ seenPlusMinus = true; /* offset */ if (n < 24) { n = n * 60; /* EG. "GMT-3" */ } else { n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ } if (prevc == '+') /* plus means east of GMT */ n = -n; + // Reject if not preceded by 'GMT' or if a time zone offset + // was already parsed. if (tzOffset != 0 && tzOffset != -1) { return false; } tzOffset = n; } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { if (c <= ' ' || c == ',' || c == '/' || i >= length) { year = n; @@ -1253,16 +1270,17 @@ ParseDate(const CharT* s, size_t length, } else if (prevc == ':' && min >= 0 && sec < 0) { sec = /*byte*/ n; } else if (mon < 0) { mon = /*byte*/n; } else if (mon >= 0 && mday < 0) { mday = /*byte*/ n; } else if (mon >= 0 && mday >= 0 && year < 0) { year = n; + seenFullYear = partLength >= 4; } else { return false; } prevc = 0; } else if (c == '/' || c == ':' || c == '+' || c == '-') { prevc = c; } else { size_t st = i - 1; @@ -1343,70 +1361,70 @@ ParseDate(const CharT* s, size_t length, /* * Case 1. The input string contains an English month name. * The form of the string can be month f l, or f month l, or * f l month which each evaluate to the same date. * If f and l are both greater than or equal to 100 the date * is invalid. * * The year is taken to be either the greater of the values f, l or - * whichever is set to zero. If the year is greater than or equal to - * 50 and less than 100, it is considered to be the number of years - * after 1900. If the year is less than 50 it is considered to be the - * number of years after 2000, otherwise it is considered to be the - * number of years after 0. + * whichever is set to zero. * * Case 2. The input string is of the form "f/m/l" where f, m and l are * integers, e.g. 7/16/45. mon, mday and year values are adjusted * to achieve Chrome compatibility. * * a. If 0 < f <= 12 and 0 < l <= 31, f/m/l is interpreted as * month/day/year. - * i. If year < 50, it is the number of years after 2000 - * ii. If year >= 50, it is the number of years after 1900. - * iii. If year >= 100, it is the number of years after 0. * b. If 31 < f and 0 < m <= 12 and 0 < l <= 31 f/m/l is * interpreted as year/month/day - * i. If year < 50, it is the number of years after 2000 - * ii. If year >= 50, it is the number of years after 1900. - * iii. If year >= 100, it is the number of years after 0. */ if (seenMonthName) { if (mday >= 100 && mon >= 100) { return false; } - if (year > 0 && (mday == 0 || mday > year)) { + if (year > 0 && (mday == 0 || mday > year) && !seenFullYear) { int temp = year; year = mday; mday = temp; } if (mday <= 0 || mday > 31) { return false; } } else if (0 < mon && mon <= 12 && 0 < mday && mday <= 31) { /* (a) month/day/year */ } else { /* (b) year/month/day */ - if (mon > 31 && mday <= 12 && year <= 31) { + if (mon > 31 && mday <= 12 && year <= 31 && !seenFullYear) { int temp = year; year = mon; mon = mday; mday = temp; } else { return false; } } - if (year < 50) { - year += 2000; - } else if (year >= 50 && year < 100) { - year += 1900; + // If the year is greater than or equal to 50 and less than 100, it is + // considered to be the number of years after 1900. If the year is less + // than 50 it is considered to be the number of years after 2000, + // otherwise it is considered to be the number of years after 0. + if (!seenFullYear) { + if (year < 50) { + year += 2000; + } else if (year >= 50 && year < 100) { + year += 1900; + } + } + + if (negativeYear) { + year = -year; } mon -= 1; /* convert month to 0-based */ if (sec < 0) { sec = 0; } if (min < 0) { min = 0;
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -797,16 +797,19 @@ ShellInterruptCallback(JSContext* cx) } else { result = false; } } else { result = false; } if (!result && sc->exitCode == 0) { + static const char msg[] = "Script terminated by interrupt handler.\n"; + fputs(msg, stderr); + sc->exitCode = EXITCODE_TIMEOUT; } return result; } /* * Some UTF-8 files, notably those written using Notepad, have a Unicode @@ -4240,21 +4243,16 @@ KillWorkerThreads(JSContext* cx) } static void CancelExecution(JSContext* cx) { ShellContext* sc = GetShellContext(cx); sc->serviceInterrupt = true; JS_RequestInterruptCallback(cx); - - if (sc->haveInterruptFunc) { - static const char msg[] = "Script runs for too long, terminating.\n"; - fputs(msg, stderr); - } } static bool SetTimeoutValue(JSContext* cx, double t) { if (mozilla::IsNaN(t)) { JS_ReportErrorASCII(cx, "timeout is not a number"); return false; @@ -8340,36 +8338,40 @@ JS_FN_HELP("parseBin", BinParse, 1, 0, "runOffThreadDecodedScript([jobID])", " Wait for off-thread decoding to complete. The job ID can be ommitted if there\n" " is only one job pending. If an error occurred, throw the appropriate\n" " exception; otherwise, run the script and return its value."), JS_FN_HELP("timeout", Timeout, 1, 0, "timeout([seconds], [func])", " Get/Set the limit in seconds for the execution time for the current context.\n" -" A negative value (default) means that the execution time is unlimited.\n" -" If a second argument is provided, it will be invoked when the timer elapses.\n" -" Calling this function will replace any callback set by |setInterruptCallback|.\n"), +" When the timeout expires the current interrupt callback is invoked.\n" +" The timeout is used just once. If the callback returns a falsy value, the\n" +" script is aborted. A negative value for seconds (this is the default) cancels\n" +" any pending timeout.\n" +" If a second argument is provided, it is installed as the interrupt handler,\n" +" exactly as if by |setInterruptCallback|.\n"), JS_FN_HELP("interruptIf", InterruptIf, 1, 0, "interruptIf(cond)", " Requests interrupt callback if cond is true. If a callback function is set via\n" " |timeout| or |setInterruptCallback|, it will be called. No-op otherwise."), JS_FN_HELP("invokeInterruptCallback", InvokeInterruptCallbackWrapper, 0, 0, "invokeInterruptCallback(fun)", " Forcefully set the interrupt flag and invoke the interrupt handler. If a\n" " callback function is set via |timeout| or |setInterruptCallback|, it will\n" " be called. Before returning, fun is called with the return value of the\n" " interrupt handler."), JS_FN_HELP("setInterruptCallback", SetInterruptCallback, 1, 0, "setInterruptCallback(func)", " Sets func as the interrupt callback function.\n" -" Calling this function will replace any callback set by |timeout|.\n"), +" Calling this function will replace any callback set by |timeout|.\n" +" If the callback returns a falsy value, the script is aborted.\n"), JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0, "setJitCompilerOption(<option>, <number>)", " Set a compiler option indexed in JSCompileOption enum to a number.\n"), JS_FN_HELP("enableLastWarning", EnableLastWarning, 0, 0, "enableLastWarning()", " Enable storing the last warning."),
new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/Date/parse-from-tostring-methods.js @@ -0,0 +1,24 @@ +let dates = [ + "0041-09-23", "+000041-09-23", "-000041-09-23", + "0091-09-23", "+000091-09-23", "-000091-09-23", + "0217-09-23", "+000217-09-23", "-000217-09-23", + "2017-09-23", "+002017-09-23", "-002017-09-23", + "+022017-09-23", "-022017-09-23", + "+202017-09-23", "-202017-09-23", +]; + +for (let date of dates) { + let d = new Date(date); + let timeValue = d.valueOf(); + + assertEq(Number.isNaN(timeValue), false, `Cannot parse "${date}" as ISO date-only form`); + + // Ensure parsing the results of toString(), toUTCString(), and toISOString() + // gives the same time value as required by 20.3.3.2 Date.parse. + assertEq(Date.parse(d.toString()), timeValue, `Cannot parse from toString() of "${date}"`); + assertEq(Date.parse(d.toUTCString()), timeValue, `Cannot parse from toUTCString() of "${date}"`); + assertEq(Date.parse(d.toISOString()), timeValue, `Cannot parse from toISOString() of "${date}"`); +} + +if (typeof reportCompare === "function") + reportCompare(true, true);
--- a/js/src/vm/Compartment-inl.h +++ b/js/src/vm/Compartment-inl.h @@ -87,19 +87,16 @@ JS::Compartment::wrap(JSContext* cx, JS: #else vp.set(p->value().get()); return true; #endif } JS::RootedObject obj(cx, &vp.toObject()); if (!wrap(cx, &obj)) { - if (js::UncheckedUnwrap(&vp.toObject())->getClass()->isDOMClass()) { - MOZ_CRASH("Looks like bug 1488480/1405521, with the object version of Compartment::wrap failing"); - } return false; } vp.setObject(*obj); MOZ_ASSERT_IF(cacheResult, obj == cacheResult); return true; } #endif /* vm_Compartment_inl_h */
--- a/js/src/vm/Compartment.cpp +++ b/js/src/vm/Compartment.cpp @@ -232,27 +232,21 @@ Compartment::getNonWrapperObjectForCurre // Invoke the prewrap callback. The prewrap callback is responsible for // doing similar reification as above, but can account for any additional // embedder requirements. // // We're a bit worried about infinite recursion here, so we do a check - // see bug 809295. auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap; if (!CheckSystemRecursionLimit(cx)) { - if (obj->getClass()->isDOMClass()) { - MOZ_CRASH("Looks like bug 1488480/1405521, with system recursion limit failing in getNonWrapperObjectForCurrentCompartment"); - } return false; } if (preWrap) { preWrap(cx, cx->global(), obj, objectPassedToWrap, obj); if (!obj) { - if (UncheckedUnwrap(objectPassedToWrap)->getClass()->isDOMClass()) { - MOZ_CRASH("Looks like bug 1488480/1405521, with preWrap failing in getNonWrapperObjectForCurrentCompartment"); - } return false; } } MOZ_ASSERT(!IsWindow(obj)); return true; } @@ -270,38 +264,32 @@ Compartment::getOrCreateWrapper(JSContex // Ensure that the wrappee is exposed in case we are creating a new wrapper // for a gray object. ExposeObjectToActiveJS(obj); // Create a new wrapper for the object. auto wrap = cx->runtime()->wrapObjectCallbacks->wrap; RootedObject wrapper(cx, wrap(cx, existing, obj)); if (!wrapper) { - if (key.toObject().getClass()->isDOMClass()) { - MOZ_CRASH("Looks like bug 1488480/1405521, with wrap() call failing in Compartment::getOrCreateWrapper"); - } return false; } // We maintain the invariant that the key in the cross-compartment wrapper // map is always directly wrapped by the value. MOZ_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject()); if (!putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*wrapper))) { // Enforce the invariant that all cross-compartment wrapper object are // in the map by nuking the wrapper if we couldn't add it. // Unfortunately it's possible for the wrapper to still be marked if we // took this path, for example if the object metadata callback stashes a // reference to it. if (wrapper->is<CrossCompartmentWrapperObject>()) { NukeCrossCompartmentWrapper(cx, wrapper); } - if (obj->getClass()->isDOMClass()) { - MOZ_CRASH("Looks like bug 1488480/1405521, with hashtable ops failing in Compartment::getOrCreateWrapper"); - } return false; } obj.set(wrapper); return true; } bool
--- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -5731,17 +5731,16 @@ class BaseCompiler final : public BaseCo void trap(Trap t) const { masm.wasmTrap(t, bytecodeOffset()); } //////////////////////////////////////////////////////////// // // Object support. -#ifdef ENABLE_WASM_GC // This emits a GC pre-write barrier. The pre-barrier is needed when we // replace a member field with a new value, and the previous field value // might have no other referents, and incremental GC is ongoing. The field // might belong to an object or be a stack slot or a register or a heap // allocated value. // // let obj = { field: previousValue }; // obj.field = newValue; // previousValue must be marked with a pre-barrier. @@ -5844,17 +5843,16 @@ class BaseCompiler final : public BaseCo RegPtr otherScratch = needRef(); emitPostBarrierGuard(object, otherScratch, value, &skipBarrier); freeRef(otherScratch); emitPostBarrier(valueAddr); masm.bind(&skipBarrier); } -#endif // ENABLE_WASM_GC //////////////////////////////////////////////////////////// // // Machinery for optimized conditional branches. // // To disable this optimization it is enough always to return false from // sniffConditionalControl{Cmp,Eqz}. @@ -6159,22 +6157,20 @@ class BaseCompiler final : public BaseCo MOZ_MUST_USE bool emitAtomicXchg(ValType type, Scalar::Type viewType); void emitAtomicXchg64(MemoryAccessDesc* access, ValType type, WantResult wantResult); #ifdef ENABLE_WASM_BULKMEM_OPS MOZ_MUST_USE bool emitMemOrTableCopy(bool isMem); MOZ_MUST_USE bool emitMemOrTableDrop(bool isMem); MOZ_MUST_USE bool emitMemFill(); MOZ_MUST_USE bool emitMemOrTableInit(bool isMem); #endif -#ifdef ENABLE_WASM_GC MOZ_MUST_USE bool emitStructNew(); MOZ_MUST_USE bool emitStructGet(); MOZ_MUST_USE bool emitStructSet(); MOZ_MUST_USE bool emitStructNarrow(); -#endif }; void BaseCompiler::emitAddI32() { int32_t c; if (popConstI32(&c)) { RegI32 r = popI32(); @@ -8678,31 +8674,29 @@ BaseCompiler::emitSetGlobal() } case ValType::F64: { RegF64 rv = popF64(); ScratchI32 tmp(*this); masm.storeDouble(rv, addressOfGlobalVar(global, tmp)); freeF64(rv); break; } -#ifdef ENABLE_WASM_GC case ValType::Ref: case ValType::AnyRef: { RegPtr valueAddr(PreBarrierReg); needRef(valueAddr); { ScratchI32 tmp(*this); masm.computeEffectiveAddress(addressOfGlobalVar(global, tmp), valueAddr); } RegPtr rv = popRef(); emitBarrieredStore(Nothing(), valueAddr, rv); // Consumes valueAddr freeRef(rv); break; } -#endif default: MOZ_CRASH("Global variable type"); break; } return true; } // Bounds check elimination. @@ -9754,17 +9748,16 @@ BaseCompiler::emitMemOrTableInit(bool is masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok); trap(Trap::ThrowReported); masm.bind(&ok); return true; } #endif -#ifdef ENABLE_WASM_GC bool BaseCompiler::emitStructNew() { uint32_t lineOrBytecode = readCallSiteLineOrBytecode(); uint32_t typeIndex; BaseOpIter::ValueVector args; if (!iter_.readStructNew(&typeIndex, &args)) { @@ -9983,25 +9976,23 @@ BaseCompiler::emitStructSet() const StructType& structType = env_.types[typeIndex].structType(); RegI32 ri; RegI64 rl; RegF32 rf; RegF64 rd; RegPtr rr; -#ifdef ENABLE_WASM_GC // Reserve this register early if we will need it so that it is not taken by // rr or rp. RegPtr valueAddr; if (structType.fields_[fieldIndex].type.isRefOrAnyRef()) { valueAddr = RegPtr(PreBarrierReg); needRef(valueAddr); } -#endif switch (structType.fields_[fieldIndex].type.code()) { case ValType::I32: ri = popI32(); break; case ValType::I64: rl = popI64(); break; @@ -10047,24 +10038,22 @@ BaseCompiler::emitStructSet() freeF32(rf); break; } case ValType::F64: { masm.storeDouble(rd, Address(rp, offs)); freeF64(rd); break; } -#ifdef ENABLE_WASM_GC case ValType::Ref: case ValType::AnyRef: masm.computeEffectiveAddress(Address(rp, offs), valueAddr); emitBarrieredStore(Some(rp), valueAddr, rr);// Consumes valueAddr freeRef(rr); break; -#endif default: { MOZ_CRASH("Unexpected field type"); } } freeRef(rp); return true; @@ -10114,17 +10103,16 @@ BaseCompiler::emitStructNarrow() pushI32(outputStruct.moduleIndex_); pushRef(rp); emitInstanceCall(lineOrBytecode, SigPIIP_, ExprType::AnyRef, SymbolicAddress::StructNarrow); masm.bind(&done); return true; } -#endif bool BaseCompiler::emitBody() { if (!iter_.readFunctionStart(funcType().ret())) { return false; }
--- a/js/src/wasm/WasmBuiltins.cpp +++ b/js/src/wasm/WasmBuiltins.cpp @@ -683,21 +683,19 @@ AddressOf(SymbolicAddress imm, ABIFuncti *abiType = Args_General4; return FuncCast(Instance::tableCopy, *abiType); case SymbolicAddress::TableDrop: *abiType = Args_General2; return FuncCast(Instance::tableDrop, *abiType); case SymbolicAddress::TableInit: *abiType = Args_General5; return FuncCast(Instance::tableInit, *abiType); -#ifdef ENABLE_WASM_GC case SymbolicAddress::PostBarrier: *abiType = Args_General2; return FuncCast(Instance::postBarrier, *abiType); -#endif case SymbolicAddress::StructNew: *abiType = Args_General2; return FuncCast(Instance::structNew, *abiType); case SymbolicAddress::StructNarrow: *abiType = Args_General4; return FuncCast(Instance::structNarrow, *abiType); #if defined(JS_CODEGEN_MIPS32) case SymbolicAddress::js_jit_gAtomic64Lock: @@ -775,19 +773,17 @@ wasm::NeedsBuiltinThunk(SymbolicAddress case SymbolicAddress::ReportInt64JSCall: case SymbolicAddress::MemCopy: case SymbolicAddress::MemDrop: case SymbolicAddress::MemFill: case SymbolicAddress::MemInit: case SymbolicAddress::TableCopy: case SymbolicAddress::TableDrop: case SymbolicAddress::TableInit: -#ifdef ENABLE_WASM_GC case SymbolicAddress::PostBarrier: -#endif case SymbolicAddress::StructNew: case SymbolicAddress::StructNarrow: return true; case SymbolicAddress::Limit: break; } MOZ_CRASH("unexpected symbolic address");
--- a/js/src/wasm/WasmConstants.h +++ b/js/src/wasm/WasmConstants.h @@ -34,19 +34,17 @@ enum class SectionId Table = 4, Memory = 5, Global = 6, Export = 7, Start = 8, Elem = 9, Code = 10, Data = 11, -#ifdef ENABLE_WASM_GC GcFeatureOptIn = 42 // Arbitrary, but fits in 7 bits -#endif }; enum class TypeCode { I32 = 0x7f, // SLEB128(-0x01) I64 = 0x7e, // SLEB128(-0x02) F32 = 0x7d, // SLEB128(-0x03) F64 = 0x7c, // SLEB128(-0x04)
--- a/js/src/wasm/WasmFrameIter.cpp +++ b/js/src/wasm/WasmFrameIter.cpp @@ -1396,20 +1396,18 @@ ThunkedNativeToDescription(SymbolicAddre case SymbolicAddress::MemInit: return "call to native memory.init function"; case SymbolicAddress::TableCopy: return "call to native table.copy function"; case SymbolicAddress::TableDrop: return "call to native table.drop function"; case SymbolicAddress::TableInit: return "call to native table.init function"; -#ifdef ENABLE_WASM_GC case SymbolicAddress::PostBarrier: return "call to native GC postbarrier (in wasm)"; -#endif case SymbolicAddress::StructNew: return "call to native struct.new (in wasm)"; case SymbolicAddress::StructNarrow: return "call to native struct.narrow (in wasm)"; #if defined(JS_CODEGEN_MIPS32) case SymbolicAddress::js_jit_gAtomic64Lock: MOZ_CRASH(); #endif
--- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -682,24 +682,22 @@ Instance::tableInit(Instance* instance, return 0; } } JS_ReportErrorNumberASCII(TlsContext.get(), GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS); return -1; } -#ifdef ENABLE_WASM_GC /* static */ void Instance::postBarrier(Instance* instance, gc::Cell** location) { MOZ_ASSERT(location); TlsContext.get()->runtime()->gc.storeBuffer().putCell(location); } -#endif // ENABLE_WASM_GC // The typeIndex is an index into the structTypeDescrs_ table in the instance. // That table holds TypeDescr objects. // // When we fail to allocate we return a nullptr; the wasm side must check this // and propagate it as an error. /* static */ void* @@ -802,20 +800,18 @@ Instance::Instance(JSContext* cx, #ifndef WASM_HUGE_MEMORY tlsData()->boundsCheckLimit = memory ? memory->buffer().wasmBoundsCheckLimit() : 0; #endif tlsData()->instance = this; tlsData()->realm = realm_; tlsData()->cx = cx; tlsData()->resetInterrupt(cx); tlsData()->jumpTable = code_->tieringJumpTable(); -#ifdef ENABLE_WASM_GC tlsData()->addressOfNeedsIncrementalBarrier = (uint8_t*)cx->compartment()->zone()->addressOfNeedsIncrementalBarrier(); -#endif Tier callerTier = code_->bestTier(); for (size_t i = 0; i < metadata(callerTier).funcImports.length(); i++) { HandleFunction f = funcImports[i]; const FuncImport& fi = metadata(callerTier).funcImports[i]; FuncImportTls& import = funcImportTls(fi); import.fun = f; if (!isAsmJS() && IsExportedWasmFunction(f)) { @@ -933,19 +929,17 @@ Instance::init(JSContext* cx, } JitRuntime* jitRuntime = cx->runtime()->getJitRuntime(cx); if (!jitRuntime) { return false; } jsJitArgsRectifier_ = jitRuntime->getArgumentsRectifier(); jsJitExceptionHandler_ = jitRuntime->getExceptionTail(); -#ifdef ENABLE_WASM_GC preBarrierCode_ = jitRuntime->preBarrier(MIRType::Object); -#endif if (!passiveDataSegments_.resize(dataSegments.length())) { return false; } for (size_t i = 0; i < dataSegments.length(); i++) { if (!dataSegments[i]->active()) { passiveDataSegments_[i] = dataSegments[i]; } @@ -1028,26 +1022,24 @@ Instance::tracePrivate(JSTracer* trc) for (const FuncImport& fi : metadata(code().stableTier()).funcImports) { TraceNullableEdge(trc, &funcImportTls(fi).fun, "wasm import"); } for (const SharedTable& table : tables_) { table->trace(trc); } -#ifdef ENABLE_WASM_GC for (const GlobalDesc& global : code().metadata().globals) { // Indirect anyref global get traced by the owning WebAssembly.Global. if (!global.type().isRefOrAnyRef() || global.isConstant() || global.isIndirect()) { continue; } GCPtrObject* obj = (GCPtrObject*)(globalData() + global.offset()); TraceNullableEdge(trc, obj, "wasm ref/anyref global"); } -#endif TraceNullableEdge(trc, &memory_, "wasm buffer"); structTypeDescrs_.trace(trc); } void Instance::trace(JSTracer* trc) {
--- a/js/src/wasm/WasmInstance.h +++ b/js/src/wasm/WasmInstance.h @@ -43,19 +43,17 @@ namespace wasm { // their code. class Instance { JS::Realm* const realm_; ReadBarrieredWasmInstanceObject object_; jit::TrampolinePtr jsJitArgsRectifier_; jit::TrampolinePtr jsJitExceptionHandler_; -#ifdef ENABLE_WASM_GC jit::TrampolinePtr preBarrierCode_; -#endif const SharedCode code_; const UniqueTlsData tlsData_; GCPtrWasmMemoryObject memory_; const SharedTableVector tables_; DataSegmentVector passiveDataSegments_; ElemSegmentVector passiveElemSegments_; const UniqueDebugState maybeDebug_; StructTypeDescrVector structTypeDescrs_; @@ -113,21 +111,19 @@ class Instance const StructTypeVector& structTypes() const { return code_->structTypes(); } static constexpr size_t offsetOfJSJitArgsRectifier() { return offsetof(Instance, jsJitArgsRectifier_); } static constexpr size_t offsetOfJSJitExceptionHandler() { return offsetof(Instance, jsJitExceptionHandler_); } -#ifdef ENABLE_WASM_GC static constexpr size_t offsetOfPreBarrierCode() { return offsetof(Instance, preBarrierCode_); } -#endif // This method returns a pointer to the GC object that owns this Instance. // Instances may be reached via weak edges (e.g., Realm::instances_) // so this perform a read-barrier on the returned object unless the barrier // is explicitly waived. WasmInstanceObject* object() const; WasmInstanceObject* objectUnbarriered() const; @@ -191,19 +187,17 @@ class Instance static int32_t memDrop(Instance* instance, uint32_t segIndex); static int32_t memFill(Instance* instance, uint32_t byteOffset, uint32_t value, uint32_t len); static int32_t memInit(Instance* instance, uint32_t dstOffset, uint32_t srcOffset, uint32_t len, uint32_t segIndex); static int32_t tableCopy(Instance* instance, uint32_t dstOffset, uint32_t srcOffset, uint32_t len); static int32_t tableDrop(Instance* instance, uint32_t segIndex); static int32_t tableInit(Instance* instance, uint32_t dstOffset, uint32_t srcOffset, uint32_t len, uint32_t segIndex); -#ifdef ENABLE_WASM_GC static void postBarrier(Instance* instance, gc::Cell** location); -#endif static void* structNew(Instance* instance, uint32_t typeIndex); static void* structNarrow(Instance* instance, uint32_t mustUnboxAnyref, uint32_t outputTypeIndex, void* ptr); }; typedef UniquePtr<Instance> UniqueInstance; } // namespace wasm } // namespace js
--- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -3553,21 +3553,23 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitReinterpret(f, ValType::I32, ValType::F32, MIRType::Int32)); case uint16_t(Op::I64ReinterpretF64): CHECK(EmitReinterpret(f, ValType::I64, ValType::F64, MIRType::Int64)); case uint16_t(Op::F32ReinterpretI32): CHECK(EmitReinterpret(f, ValType::F32, ValType::I32, MIRType::Float32)); case uint16_t(Op::F64ReinterpretI64): CHECK(EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double)); - // GC types are NYI in Ion. +#ifdef ENABLE_WASM_GC case uint16_t(Op::RefEq): case uint16_t(Op::RefNull): case uint16_t(Op::RefIsNull): + // Not yet supported return f.iter().unrecognizedOpcode(&op); +#endif // Sign extensions case uint16_t(Op::I32Extend8S): CHECK(EmitSignExtend(f, 1, 4)); case uint16_t(Op::I32Extend16S): CHECK(EmitSignExtend(f, 2, 4)); case uint16_t(Op::I64Extend8S): CHECK(EmitSignExtend(f, 1, 8));
--- a/js/src/wasm/WasmOpIter.cpp +++ b/js/src/wasm/WasmOpIter.cpp @@ -235,20 +235,25 @@ wasm::Classify(OpBytes op) case Op::Else: return OpKind::Else; case Op::End: return OpKind::End; case Op::CurrentMemory: return OpKind::CurrentMemory; case Op::GrowMemory: return OpKind::GrowMemory; +#ifdef ENABLE_WASM_GC case Op::RefNull: return OpKind::RefNull; +#endif case Op::MiscPrefix: { switch (MiscOp(op.b1)) { + case MiscOp::Limit: + // Reject Limit for MiscPrefix encoding + break; #ifdef ENABLE_WASM_SATURATING_TRUNC_OPS case MiscOp::I32TruncSSatF32: case MiscOp::I32TruncUSatF32: case MiscOp::I32TruncSSatF64: case MiscOp::I32TruncUSatF64: case MiscOp::I64TruncSSatF32: case MiscOp::I64TruncUSatF32: case MiscOp::I64TruncSSatF64: @@ -273,18 +278,16 @@ wasm::Classify(OpBytes op) return OpKind::StructNew; case MiscOp::StructGet: return OpKind::StructGet; case MiscOp::StructSet: return OpKind::StructSet; case MiscOp::StructNarrow: return OpKind::StructNarrow; #endif - default: - break; } break; } case Op::ThreadPrefix: { #ifdef ENABLE_WASM_THREAD_OPS switch (ThreadOp(op.b1)) { case ThreadOp::Limit: // Reject Limit for ThreadPrefix encoding
--- a/js/src/wasm/WasmOpIter.h +++ b/js/src/wasm/WasmOpIter.h @@ -1714,24 +1714,24 @@ OpIter<Policy>::readReferenceType(ValTyp { uint8_t code; uint32_t refTypeIndex; if (!d_.readValType(&code, &refTypeIndex)) { return fail_ctx("invalid reference type for %s", context); } - if (code == uint8_t(TypeCode::Ref)) { + if (code == uint8_t(ValType::Code::Ref)) { if (refTypeIndex >= env_.types.length()) { return fail_ctx("invalid reference type for %s", context); } if (!env_.types[refTypeIndex].isStructType()) { return fail_ctx("reference to struct required for %s", context); } - } else if (code != uint8_t(TypeCode::AnyRef)) { + } else if (code != uint8_t(ValType::Code::AnyRef)) { return fail_ctx("invalid reference type for %s", context); } *type = ValType(ValType::Code(code), refTypeIndex); return true; }
--- a/js/src/wasm/WasmTypes.h +++ b/js/src/wasm/WasmTypes.h @@ -1887,19 +1887,17 @@ enum class SymbolicAddress Wake, MemCopy, MemDrop, MemFill, MemInit, TableCopy, TableDrop, TableInit, -#ifdef ENABLE_WASM_GC PostBarrier, -#endif StructNew, StructNarrow, #if defined(JS_CODEGEN_MIPS32) js_jit_gAtomic64Lock, #endif Limit }; @@ -1996,19 +1994,17 @@ struct TlsData // Usually equal to cx->stackLimitForJitCode(JS::StackForUntrustedScript), // but can be racily set to trigger immediate trap as an opportunity to // CheckForInterrupt without an additional branch. Atomic<uintptr_t, mozilla::Relaxed> stackLimit; // Set to 1 when wasm should call CheckForInterrupt. Atomic<uint32_t, mozilla::Relaxed> interrupt; -#ifdef ENABLE_WASM_GC uint8_t* addressOfNeedsIncrementalBarrier; -#endif // Methods to set, test and clear the above two fields. Both interrupt // fields are Relaxed and so no consistency/ordering can be assumed. void setInterrupt(); bool isInterrupted() const; void resetInterrupt(JSContext* cx); // Pointer that should be freed (due to padding before the TlsData).
--- a/layout/svg/SVGObserverUtils.cpp +++ b/layout/svg/SVGObserverUtils.cpp @@ -667,22 +667,55 @@ SVGObserverUtils::GetTextPathsReferenced } void SVGObserverUtils::RemoveTextPathObserver(nsIFrame* aTextPathFrame) { aTextPathFrame->DeleteProperty(HrefAsTextPathProperty()); } -SVGTemplateElementObserver* -SVGObserverUtils::GetTemplateElementObserver(URLAndReferrerInfo* aURI, - nsIFrame* aFrame, - const mozilla::FramePropertyDescriptor<SVGTemplateElementObserver>* aProperty) +nsIFrame* +SVGObserverUtils::GetTemplateFrame(nsIFrame* aFrame, + HrefToTemplateCallback aGetHref) { - return GetEffectProperty(aURI, aFrame, aProperty); + SVGTemplateElementObserver* observer = + aFrame->GetProperty(SVGObserverUtils::HrefToTemplateProperty()); + + if (!observer) { + nsAutoString href; + aGetHref(href); + if (href.IsEmpty()) { + return nullptr; // no URL + } + + // Convert href to an nsIURI + nsIContent* content = aFrame->GetContent(); + nsCOMPtr<nsIURI> targetURI; + nsCOMPtr<nsIURI> base = content->GetBaseURI(); + nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, + content->GetUncomposedDoc(), base); + + // There's no clear refererer policy spec about non-CSS SVG resource + // references. Bug 1415044 to investigate which referrer we should use. + RefPtr<URLAndReferrerInfo> target = + new URLAndReferrerInfo(targetURI, + content->OwnerDoc()->GetDocumentURI(), + content->OwnerDoc()->GetReferrerPolicy()); + + observer = GetEffectProperty(target, aFrame, + SVGObserverUtils::HrefToTemplateProperty()); + } + + return observer ? observer->GetReferencedFrame() : nullptr; +} + +void +SVGObserverUtils::RemoveTemplateObserver(nsIFrame* aFrame) +{ + aFrame->DeleteProperty(SVGObserverUtils::HrefToTemplateProperty()); } nsSVGPaintingProperty* SVGObserverUtils::GetPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame, const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty) { return GetEffectProperty(aURI, aFrame, aProperty); }
--- a/layout/svg/SVGObserverUtils.h +++ b/layout/svg/SVGObserverUtils.h @@ -13,16 +13,17 @@ #include "mozilla/dom/Element.h" #include "nsHashKeys.h" #include "nsID.h" #include "nsIFrame.h" #include "nsIMutationObserver.h" #include "nsInterfaceHashtable.h" #include "nsISupportsBase.h" #include "nsISupportsImpl.h" +#include "nsStringFwd.h" #include "nsStubMutationObserver.h" #include "nsSVGUtils.h" #include "nsTHashtable.h" #include "nsURIHashKey.h" #include "nsCycleCollectionParticipant.h" class nsAtom; class nsIPresShell; @@ -738,19 +739,35 @@ public: /** * Make aTextPathFrame stop observing rendering changes to the * SVGGeometryElement that it references, if any. */ static void RemoveTextPathObserver(nsIFrame* aTextPathFrame); - static SVGTemplateElementObserver* - GetTemplateElementObserver(URLAndReferrerInfo* aURI, nsIFrame* aFrame, - const mozilla::FramePropertyDescriptor<SVGTemplateElementObserver>* aProperty); + using HrefToTemplateCallback = const std::function<void(nsAString&)>&; + /** + * Gets the nsIFrame of a referenced SVG "template" element, if any, and + * makes aFrame start observing rendering changes to the template element. + * + * Template elements: some elements like gradients, pattern or filter can + * reference another element of the same type using their 'href' attribute, + * and use that element as a template that provides attributes or content + * that is missing from the referring element. + * + * The frames that this function is called for do not have a common base + * class, which is why it is necessary to pass in a function that can be + * used as a callback to lazily get the href value, if necessary. + */ + static nsIFrame* + GetTemplateFrame(nsIFrame* aFrame, HrefToTemplateCallback aGetHref); + + static void + RemoveTemplateObserver(nsIFrame* aFrame); /** * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary */ static nsSVGPaintingProperty* GetPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame, const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty); /**
--- a/layout/svg/nsSVGFilterFrame.cpp +++ b/layout/svg/nsSVGFilterFrame.cpp @@ -106,70 +106,47 @@ nsSVGFilterFrame::GetFilterContent(nsICo } nsSVGFilterFrame *next = GetReferencedFilter(); return next ? next->GetFilterContent(aDefault) : static_cast<SVGFilterElement*>(aDefault); } -nsSVGFilterFrame * +nsSVGFilterFrame* nsSVGFilterFrame::GetReferencedFilter() { - if (mNoHRefURI) + if (mNoHRefURI) { return nullptr; + } - SVGTemplateElementObserver* observer = - GetProperty(SVGObserverUtils::HrefToTemplateProperty()); - - if (!observer) { - // Fetch our Filter element's href or xlink:href attribute - SVGFilterElement *filter = static_cast<SVGFilterElement *>(GetContent()); - nsAutoString href; + auto GetHref = [this] (nsAString& aHref) { + SVGFilterElement* filter = static_cast<SVGFilterElement*>(GetContent()); if (filter->mStringAttributes[SVGFilterElement::HREF].IsExplicitlySet()) { filter->mStringAttributes[SVGFilterElement::HREF] - .GetAnimValue(href, filter); + .GetAnimValue(aHref, filter); } else { filter->mStringAttributes[SVGFilterElement::XLINK_HREF] - .GetAnimValue(href, filter); + .GetAnimValue(aHref, filter); } - - if (href.IsEmpty()) { - mNoHRefURI = true; - return nullptr; // no URL - } + this->mNoHRefURI = aHref.IsEmpty(); + }; - // Convert href to an nsIURI - nsCOMPtr<nsIURI> targetURI; - nsCOMPtr<nsIURI> base = mContent->GetBaseURI(); - nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, - mContent->GetUncomposedDoc(), base); - - // There's no clear refererer policy spec about non-CSS SVG resource references - // Bug 1415044 to investigate which referrer we should use - RefPtr<URLAndReferrerInfo> target = - new URLAndReferrerInfo(targetURI, - mContent->OwnerDoc()->GetDocumentURI(), - mContent->OwnerDoc()->GetReferrerPolicy()); - observer = SVGObserverUtils::GetTemplateElementObserver(target, this, - SVGObserverUtils::HrefToTemplateProperty()); - if (!observer) { - return nullptr; + nsIFrame* tframe = SVGObserverUtils::GetTemplateFrame(this, GetHref); + if (tframe) { + LayoutFrameType frameType = tframe->Type(); + if (frameType == LayoutFrameType::SVGFilter) { + return static_cast<nsSVGFilterFrame*>(tframe); } + // We don't call SVGObserverUtils::RemoveTemplateObserver and set + // `mNoHRefURI = false` here since we want to be invalidated if the ID + // specified by our href starts resolving to a different/valid element. } - nsIFrame* result = observer->GetReferencedFrame(); - if (!result) - return nullptr; - - LayoutFrameType frameType = result->Type(); - if (frameType != LayoutFrameType::SVGFilter) - return nullptr; - - return static_cast<nsSVGFilterFrame*>(result); + return nullptr; } nsresult nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType) { if (aNameSpaceID == kNameSpaceID_None && @@ -179,17 +156,17 @@ nsSVGFilterFrame::AttributeChanged(int32 aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::filterUnits || aAttribute == nsGkAtoms::primitiveUnits)) { SVGObserverUtils::InvalidateDirectRenderingObservers(this); } else if ((aNameSpaceID == kNameSpaceID_XLink || aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - DeleteProperty(SVGObserverUtils::HrefToTemplateProperty()); + SVGObserverUtils::RemoveTemplateObserver(this); mNoHRefURI = false; // And update whoever references us SVGObserverUtils::InvalidateDirectRenderingObservers(this); } return nsSVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); }
--- a/layout/svg/nsSVGFilterFrame.h +++ b/layout/svg/nsSVGFilterFrame.h @@ -53,20 +53,22 @@ public: #ifdef DEBUG virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) override; #endif private: - // Parse our xlink:href and set up our nsSVGPaintingProperty if we - // reference another filter and we don't have a property. Return - // the referenced filter's frame if available, null otherwise. friend class nsSVGFilterInstance; + + /** + * Parses this frame's href and - if it references another filter - returns + * it. It also makes this frame a rendering observer of the specified ID. + */ nsSVGFilterFrame* GetReferencedFilter(); // Accessors to lookup filter attributes uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault); uint16_t GetEnumValue(uint32_t aIndex) { return GetEnumValue(aIndex, mContent); }
--- a/layout/svg/nsSVGGradientFrame.cpp +++ b/layout/svg/nsSVGGradientFrame.cpp @@ -51,17 +51,17 @@ nsSVGGradientFrame::AttributeChanged(int (aAttribute == nsGkAtoms::gradientUnits || aAttribute == nsGkAtoms::gradientTransform || aAttribute == nsGkAtoms::spreadMethod)) { SVGObserverUtils::InvalidateDirectRenderingObservers(this); } else if ((aNameSpaceID == kNameSpaceID_XLink || aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - DeleteProperty(SVGObserverUtils::HrefToTemplateProperty()); + SVGObserverUtils::RemoveTemplateObserver(this); mNoHRefURI = false; // And update whoever references us SVGObserverUtils::InvalidateDirectRenderingObservers(this); } return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); } @@ -331,74 +331,50 @@ nsSVGGradientFrame::GetPaintServerPatter gradient->AddColorStop(offset, stopColor2); } return gradient.forget(); } // Private (helper) methods -nsSVGGradientFrame * +nsSVGGradientFrame* nsSVGGradientFrame::GetReferencedGradient() { - if (mNoHRefURI) + if (mNoHRefURI) { return nullptr; - - SVGTemplateElementObserver* observer = - GetProperty(SVGObserverUtils::HrefToTemplateProperty()); + } - if (!observer) { - // Fetch our gradient element's href or xlink:href attribute + auto GetHref = [this] (nsAString& aHref) { dom::SVGGradientElement* grad = - static_cast<dom::SVGGradientElement*>(GetContent()); - nsAutoString href; + static_cast<dom::SVGGradientElement*>(this->GetContent()); if (grad->mStringAttributes[dom::SVGGradientElement::HREF] .IsExplicitlySet()) { grad->mStringAttributes[dom::SVGGradientElement::HREF] - .GetAnimValue(href, grad); + .GetAnimValue(aHref, grad); } else { grad->mStringAttributes[dom::SVGGradientElement::XLINK_HREF] - .GetAnimValue(href, grad); + .GetAnimValue(aHref, grad); } - - if (href.IsEmpty()) { - mNoHRefURI = true; - return nullptr; // no URL - } + this->mNoHRefURI = aHref.IsEmpty(); + }; - // Convert href to an nsIURI - nsCOMPtr<nsIURI> targetURI; - nsCOMPtr<nsIURI> base = mContent->GetBaseURI(); - nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, - mContent->GetUncomposedDoc(), base); - - // There's no clear refererer policy spec about non-CSS SVG resource references - // Bug 1415044 to investigate which referrer we should use - RefPtr<URLAndReferrerInfo> target = - new URLAndReferrerInfo(targetURI, - mContent->OwnerDoc()->GetDocumentURI(), - mContent->OwnerDoc()->GetReferrerPolicy()); - - observer = SVGObserverUtils::GetTemplateElementObserver(target, this, - SVGObserverUtils::HrefToTemplateProperty()); - if (!observer) { - return nullptr; + nsIFrame* tframe = SVGObserverUtils::GetTemplateFrame(this, GetHref); + if (tframe) { + LayoutFrameType frameType = tframe->Type(); + if (frameType == LayoutFrameType::SVGLinearGradient || + frameType == LayoutFrameType::SVGRadialGradient) { + return static_cast<nsSVGGradientFrame*>(tframe); } + // We don't call SVGObserverUtils::RemoveTemplateObserver and set + // `mNoHRefURI = false` here since we want to be invalidated if the ID + // specified by our href starts resolving to a different/valid element. } - nsIFrame* result = observer->GetReferencedFrame(); - if (!result) - return nullptr; - - LayoutFrameType frameType = result->Type(); - if (frameType != LayoutFrameType::SVGLinearGradient && - frameType != LayoutFrameType::SVGRadialGradient) - return nullptr; - - return static_cast<nsSVGGradientFrame*>(result); + return nullptr; } void nsSVGGradientFrame::GetStopFrames(nsTArray<nsIFrame*>* aStopFrames) { nsIFrame *stopFrame = nullptr; for (stopFrame = mFrames.FirstChild(); stopFrame; stopFrame = stopFrame->GetNextSibling()) {
--- a/layout/svg/nsSVGGradientFrame.h +++ b/layout/svg/nsSVGGradientFrame.h @@ -24,20 +24,16 @@ namespace mozilla { class nsSVGAnimatedTransformList; namespace dom { class SVGLinearGradientElement; class SVGRadialGradientElement; } // namespace dom } // namespace mozilla -/** - * Gradients can refer to other gradients. We create an nsSVGPaintingProperty - * with property type nsGkAtoms::href to track the referenced gradient. - */ class nsSVGGradientFrame : public nsSVGPaintServerFrame { typedef mozilla::gfx::ExtendMode ExtendMode; protected: nsSVGGradientFrame(ComputedStyle* aStyle, ClassID aID); public: @@ -61,20 +57,20 @@ public: #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("SVGGradient"), aResult); } #endif // DEBUG private: - - // Parse our xlink:href and set up our nsSVGPaintingProperty if we - // reference another gradient and we don't have a property. Return - // the referenced gradient's frame if available, null otherwise. + /** + * Parses this frame's href and - if it references another gradient - returns + * it. It also makes this frame a rendering observer of the specified ID. + */ nsSVGGradientFrame* GetReferencedGradient(); // Optionally get a stop frame (returns stop index/count) void GetStopFrames(nsTArray<nsIFrame*>* aStopFrames); const mozilla::nsSVGAnimatedTransformList* GetGradientTransformList( nsIContent* aDefault); // Will be singular for gradientUnits="objectBoundingBox" with an empty bbox.
--- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -65,17 +65,17 @@ nsSVGPatternFrame::AttributeChanged(int3 aAttribute == nsGkAtoms::viewBox)) { SVGObserverUtils::InvalidateDirectRenderingObservers(this); } if ((aNameSpaceID == kNameSpaceID_XLink || aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - DeleteProperty(SVGObserverUtils::HrefToTemplateProperty()); + SVGObserverUtils::RemoveTemplateObserver(this); mNoHRefURI = false; // And update whoever references us SVGObserverUtils::InvalidateDirectRenderingObservers(this); } return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); } @@ -567,71 +567,49 @@ nsSVGPatternFrame::GetLengthValue(uint32 } nsSVGPatternFrame *next = GetReferencedPattern(); return next ? next->GetLengthValue(aIndex, aDefault) : &static_cast<SVGPatternElement *>(aDefault)->mLengthAttributes[aIndex]; } // Private (helper) methods -nsSVGPatternFrame * + +nsSVGPatternFrame* nsSVGPatternFrame::GetReferencedPattern() { - if (mNoHRefURI) + if (mNoHRefURI) { return nullptr; + } - SVGTemplateElementObserver* observer = - GetProperty(SVGObserverUtils::HrefToTemplateProperty()); - - if (!observer) { - // Fetch our pattern element's href or xlink:href attribute - SVGPatternElement *pattern = static_cast<SVGPatternElement *>(GetContent()); - nsAutoString href; + auto GetHref = [this] (nsAString& aHref) { + SVGPatternElement* pattern = + static_cast<SVGPatternElement*>(this->GetContent()); if (pattern->mStringAttributes[SVGPatternElement::HREF].IsExplicitlySet()) { pattern->mStringAttributes[SVGPatternElement::HREF] - .GetAnimValue(href, pattern); + .GetAnimValue(aHref, pattern); } else { pattern->mStringAttributes[SVGPatternElement::XLINK_HREF] - .GetAnimValue(href, pattern); + .GetAnimValue(aHref, pattern); } - - if (href.IsEmpty()) { - mNoHRefURI = true; - return nullptr; // no URL - } + this->mNoHRefURI = aHref.IsEmpty(); + }; - // Convert href to an nsIURI - nsCOMPtr<nsIURI> targetURI; - nsCOMPtr<nsIURI> base = mContent->GetBaseURI(); - nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, - mContent->GetUncomposedDoc(), base); - - // There's no clear refererer policy spec about non-CSS SVG resource references - // Bug 1415044 to investigate which referrer we should use - RefPtr<URLAndReferrerInfo> target = - new URLAndReferrerInfo(targetURI, - mContent->OwnerDoc()->GetDocumentURI(), - mContent->OwnerDoc()->GetReferrerPolicy()); - - observer = SVGObserverUtils::GetTemplateElementObserver(target, this, - SVGObserverUtils::HrefToTemplateProperty()); - if (!observer) { - return nullptr; + nsIFrame* tframe = SVGObserverUtils::GetTemplateFrame(this, GetHref); + if (tframe) { + LayoutFrameType frameType = tframe->Type(); + if (frameType == LayoutFrameType::SVGPattern) { + return static_cast<nsSVGPatternFrame*>(tframe); } + // We don't call SVGObserverUtils::RemoveTemplateObserver and set + // `mNoHRefURI = false` here since we want to be invalidated if the ID + // specified by our href starts resolving to a different/valid element. } - nsIFrame* result = observer->GetReferencedFrame(); - if (!result) - return nullptr; - - LayoutFrameType frameType = result->Type(); - if (frameType != LayoutFrameType::SVGPattern) - return nullptr; - - return static_cast<nsSVGPatternFrame*>(result); + return nullptr; } gfxRect nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits, const gfxRect &aTargetBBox, const Matrix &aTargetCTM, nsIFrame *aTarget) {
--- a/layout/svg/nsSVGPatternFrame.h +++ b/layout/svg/nsSVGPatternFrame.h @@ -19,20 +19,16 @@ class nsSVGLength2; class nsSVGViewBox; namespace mozilla { class SVGAnimatedPreserveAspectRatio; class SVGGeometryFrame; class nsSVGAnimatedTransformList; } // namespace mozilla -/** - * Patterns can refer to other patterns. We create an nsSVGPaintingProperty - * with property type nsGkAtoms::href to track the referenced pattern. - */ class nsSVGPatternFrame final : public nsSVGPaintServerFrame { typedef mozilla::gfx::SourceSurface SourceSurface; public: NS_DECL_FRAMEARENA_HELPERS(nsSVGPatternFrame) friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell, @@ -70,17 +66,20 @@ public: #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("SVGPattern"), aResult); } #endif // DEBUG protected: - // Internal methods for handling referenced patterns + /** + * Parses this frame's href and - if it references another pattern - returns + * it. It also makes this frame a rendering observer of the specified ID. + */ nsSVGPatternFrame* GetReferencedPattern(); // Accessors to lookup pattern attributes uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault); uint16_t GetEnumValue(uint32_t aIndex) { return GetEnumValue(aIndex, mContent); }
--- a/modules/brotli/README.mozilla +++ b/modules/brotli/README.mozilla @@ -6,9 +6,9 @@ Upstream code can be viewed at and cloned by git clone https://github.com/google/brotli The in-tree copy is updated by running sh update.sh from within the modules/brotli directory. -Current version: [commit b601fe817bd3217cb144bbb380a43cae8e847388]. +Current version: [commit 6eba239a5bb553fd557b7d78f7da8f0059618b9e].
--- a/modules/brotli/common/platform.h +++ b/modules/brotli/common/platform.h @@ -182,17 +182,24 @@ OR: #if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \ (defined(M_ARM) && (M_ARM == 7)) #define BROTLI_TARGET_ARMV7 #endif /* ARMv7 */ #if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \ defined(__aarch64__) || defined(__ARM64_ARCH_8__) -#define BROTLI_TARGET_ARMV8 +#define BROTLI_TARGET_ARMV8_ANY + +#if defined(__ARM_32BIT_STATE) +#define BROTLI_TARGET_ARMV8_32 +#elif defined(__ARM_64BIT_STATE) +#define BROTLI_TARGET_ARMV8_64 +#endif + #endif /* ARMv8 */ #if defined(__i386) || defined(_M_IX86) #define BROTLI_TARGET_X86 #endif #if defined(__x86_64__) || defined(_M_X64) #define BROTLI_TARGET_X64 @@ -205,17 +212,17 @@ OR: #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 #define BROTLI_TARGET_RISCV64 #endif #if defined(BROTLI_BUILD_64_BIT) #define BROTLI_64_BITS 1 #elif defined(BROTLI_BUILD_32_BIT) #define BROTLI_64_BITS 0 -#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8) || \ +#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \ defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) #define BROTLI_64_BITS 1 #else #define BROTLI_64_BITS 0 #endif #if (BROTLI_64_BITS) #define brotli_reg_t uint64_t @@ -256,17 +263,17 @@ OR: #undef BROTLI_X_BYTE_ORDER #undef BROTLI_X_LITTLE_ENDIAN #undef BROTLI_X_BIG_ENDIAN #endif #if defined(BROTLI_BUILD_PORTABLE) #define BROTLI_ALIGNED_READ (!!1) #elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ - defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8) || \ + defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \ defined(BROTLI_TARGET_RISCV64) /* Allow unaligned read only for white-listed CPUs. */ #define BROTLI_ALIGNED_READ (!!0) #else #define BROTLI_ALIGNED_READ (!!1) #endif #if BROTLI_ALIGNED_READ @@ -286,41 +293,83 @@ static BROTLI_INLINE uint64_t BrotliUnal memcpy(&t, p, sizeof t); return t; } static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { memcpy(p, &v, sizeof v); } #else /* BROTLI_ALIGNED_READ */ /* Unaligned memory access is allowed: just cast pointer to requested type. */ +#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \ + defined(MEMORY_SANITIZER) +/* Consider we have an unaligned load/store of 4 bytes from address 0x...05. + AddressSanitizer will treat it as a 3-byte access to the range 05:07 and + will miss a bug if 08 is the first unaddressable byte. + ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will + miss a race between this access and some other accesses to 08. + MemorySanitizer will correctly propagate the shadow on unaligned stores + and correctly report bugs on unaligned loads, but it may not properly + update and report the origin of the uninitialized memory. + For all three tools, replacing an unaligned access with a tool-specific + callback solves the problem. */ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + uint16_t __sanitizer_unaligned_load16(const void* p); + uint32_t __sanitizer_unaligned_load32(const void* p); + uint64_t __sanitizer_unaligned_load64(const void* p); + void __sanitizer_unaligned_store64(void* p, uint64_t v); +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* __cplusplus */ +#define BrotliUnalignedRead16 __sanitizer_unaligned_load16 +#define BrotliUnalignedRead32 __sanitizer_unaligned_load32 +#define BrotliUnalignedRead64 __sanitizer_unaligned_load64 +#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64 +#else static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { return *(const uint16_t*)p; } static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) { return *(const uint32_t*)p; } #if (BROTLI_64_BITS) static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { return *(const uint64_t*)p; } static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { *(uint64_t*)p = v; } #else /* BROTLI_64_BITS */ /* Avoid emitting LDRD / STRD, which require properly aligned address. */ +/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */ + +#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) +typedef __attribute__((aligned(1))) uint64_t brotli_unaligned_uint64_t; + static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { - const uint32_t* dwords = (const uint32_t*)p; - return dwords[0] | ((uint64_t)dwords[1] << 32); + return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0]; } static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { - uint32_t* dwords = (uint32_t *)p; - dwords[0] = (uint32_t)v; - dwords[1] = (uint32_t)(v >> 32); + brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p; + dwords[0] = (brotli_unaligned_uint64_t) v; } +#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */ +static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { + uint64_t v; + memcpy(&v, p, sizeof(uint64_t)); + return v; +} + +static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { + memcpy(p, &v, sizeof(uint64_t)); +} +#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */ #endif /* BROTLI_64_BITS */ +#endif /* ASAN / TSAN / MSAN */ #endif /* BROTLI_ALIGNED_READ */ #if BROTLI_LITTLE_ENDIAN /* Straight endianness. Just read / write values. */ #define BROTLI_UNALIGNED_LOAD16LE BrotliUnalignedRead16 #define BROTLI_UNALIGNED_LOAD32LE BrotliUnalignedRead32 #define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64 #define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64 @@ -395,17 +444,17 @@ static BROTLI_INLINE void BROTLI_UNALIGN /* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */ #if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) #define BROTLI_IS_CONSTANT(x) (!!__builtin_constant_p(x)) #else #define BROTLI_IS_CONSTANT(x) (!!0) #endif -#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8) +#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) #define BROTLI_HAS_UBFX (!!1) #else #define BROTLI_HAS_UBFX (!!0) #endif #if defined(BROTLI_ENABLE_LOG) #define BROTLI_DCHECK(x) assert(x) #define BROTLI_LOG(x) printf x @@ -422,17 +471,17 @@ static BROTLI_INLINE void BrotliDump(con #define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__) #else #define BROTLI_DUMP() (void)(0) #endif /* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */ #if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \ !defined(BROTLI_BUILD_NO_RBIT) -#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8) +#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) /* TODO: detect ARMv6T2 and enable this code for it. */ static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) { brotli_reg_t output; __asm__("rbit %0, %1\n" : "=r"(output) : "r"(input)); return output; } #define BROTLI_RBIT(x) BrotliRBit(x) #endif /* armv7 / armv8 */
--- a/modules/brotli/common/version.h +++ b/modules/brotli/common/version.h @@ -9,18 +9,18 @@ #ifndef BROTLI_COMMON_VERSION_H_ #define BROTLI_COMMON_VERSION_H_ /* This macro should only be used when library is compiled together with client. If library is dynamically linked, use BrotliDecoderVersion and BrotliEncoderVersion methods. */ /* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */ -#define BROTLI_VERSION 0x1000005 +#define BROTLI_VERSION 0x1000006 /* This macro is used by build system to produce Libtool-friendly soname. See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ /* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */ -#define BROTLI_ABI_VERSION 0x1005000 +#define BROTLI_ABI_VERSION 0x1006000 #endif /* BROTLI_COMMON_VERSION_H_ */
--- a/modules/brotli/enc/metablock.c +++ b/modules/brotli/enc/metablock.c @@ -176,17 +176,18 @@ void BrotliBuildMetaBlock(MemoryManager* if (ndirect_msb > 0) ndirect_msb--; ndirect_msb /= 2; } if (check_orig) { double dist_cost; ComputeDistanceCost(cmds, num_commands, &orig_params.dist, &orig_params.dist, &dist_cost); if (dist_cost < best_dist_cost) { - best_dist_cost = dist_cost; + /* NB: currently unused; uncomment when more param tuning is added. */ + /* best_dist_cost = dist_cost; */ params->dist = orig_params.dist; } } RecomputeDistancePrefixes(cmds, num_commands, &orig_params.dist, ¶ms->dist); BrotliSplitBlock(m, cmds, num_commands, ringbuffer, pos, mask, params,
--- a/modules/brotli/update.sh +++ b/modules/brotli/update.sh @@ -1,17 +1,17 @@ #!/bin/sh # Script to update the mozilla in-tree copy of the Brotli library. # Run this within the /modules/brotli directory of the source tree. MY_TEMP_DIR=`mktemp -d -t brotli_update.XXXXXX` || exit 1 git clone https://github.com/google/brotli ${MY_TEMP_DIR}/brotli -git -C ${MY_TEMP_DIR}/brotli checkout v1.0.5 +git -C ${MY_TEMP_DIR}/brotli checkout v1.0.6 COMMIT=$(git -C ${MY_TEMP_DIR}/brotli rev-parse HEAD) perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README.mozilla; DIRS="common dec enc include tools" for d in $DIRS; do rm -rf $d
--- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -647,27 +647,21 @@ VARCACHE_PREF( // Should the :visited selector ever match (otherwise :link matches instead)? VARCACHE_PREF( "layout.css.visited_links_enabled", layout_css_visited_links_enabled, bool, true ) // Is the '-webkit-appearance' alias for '-moz-appearance' enabled? -#ifdef EARLY_BETA_OR_EARLIER -#define PREF_VALUE true -#else -#define PREF_VALUE false -#endif VARCACHE_PREF( "layout.css.webkit-appearance.enabled", layout_css_webkit_appearance_enabled, - bool, PREF_VALUE + bool, true ) -#undef PREF_VALUE // Pref to control whether @-moz-document rules are enabled in content pages. VARCACHE_PREF( "layout.css.moz-document.content.enabled", layout_css_moz_document_content_enabled, bool, false )
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4675,16 +4675,19 @@ pref("image.mem.animated.discardable", t // Whether the heap should be used for frames from animated images. On Android, // volatile memory keeps file handles open for each buffer. #if defined(ANDROID) pref("image.mem.animated.use_heap", true); #else pref("image.mem.animated.use_heap", false); #endif +// Enable extra information for debugging in the image memory reports. +pref("image.mem.debug-reporting", false); + // Decodes images into shared memory to allow direct use in separate // rendering processes. Only applicable with WebRender. pref("image.mem.shared", true); // Allows image locking of decoded image data in content processes. pref("image.mem.allow_locking_in_content_processes", true); // Chunk size for calls to the image decoders
--- a/testing/geckodriver/src/capabilities.rs +++ b/testing/geckodriver/src/capabilities.rs @@ -43,19 +43,19 @@ impl<'a> FirefoxCapabilities<'a> { } } fn set_binary(&mut self, capabilities: &Map<String, Value>) { self.chosen_binary = capabilities .get("moz:firefoxOptions") .and_then(|x| x.get("binary")) .and_then(|x| x.as_str()) - .map(|x| PathBuf::from(x)) + .map(PathBuf::from) .or_else(|| self.fallback_binary.map(|x| x.clone())) - .or_else(|| firefox_default_path()) + .or_else(firefox_default_path) } fn version(&mut self) -> Option<String> { if let Some(ref binary) = self.chosen_binary { if let Some(value) = self.version_cache.get(binary) { return Some((*value).clone()); } debug!("Trying to read firefox version from ini files");
--- a/testing/geckodriver/src/main.rs +++ b/testing/geckodriver/src/main.rs @@ -155,17 +155,17 @@ fn run() -> ProgramResult { Ok(x) => x, Err(_) => return Err((ExitCode::Usage, "invalid WebDriver port".into())), }; let addr = match IpAddr::from_str(host) { Ok(addr) => SocketAddr::new(addr, port), Err(_) => return Err((ExitCode::Usage, "invalid host address".into())), }; - let binary = matches.value_of("binary").map(|x| PathBuf::from(x)); + let binary = matches.value_of("binary").map(PathBuf::from); let marionette_port = match matches.value_of("marionette_port") { Some(x) => match u16::from_str(x) { Ok(x) => Some(x), Err(_) => return Err((ExitCode::Usage, "invalid Marionette port".into())), }, None => None, };
deleted file mode 100644 --- a/testing/web-platform/meta/IndexedDB/keypath-exceptions.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[keypath-exceptions.htm] - [Key path evaluation: Exceptions from non-enumerable getters on prototype] - expected: FAIL - - [Key path evaluation: Exceptions from enumerable getters on prototype] - expected: FAIL
--- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -188778,16 +188778,100 @@ [ "/svg/path/property/priority-ref.svg", "==" ] ], {} ] ], + "svg/pservers/reftests/meshgradient-basic-001.svg": [ + [ + "/svg/pservers/reftests/meshgradient-basic-001.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-basic-001-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-002.svg": [ + [ + "/svg/pservers/reftests/meshgradient-basic-002.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-basic-002-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-003.svg": [ + [ + "/svg/pservers/reftests/meshgradient-basic-003.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-basic-003-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-004.svg": [ + [ + "/svg/pservers/reftests/meshgradient-basic-004.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-basic-004-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-005.svg": [ + [ + "/svg/pservers/reftests/meshgradient-basic-005.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-basic-005-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-bicubic-001.svg": [ + [ + "/svg/pservers/reftests/meshgradient-bicubic-001.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-bicubic-001-ref.png", + "==" + ] + ], + {} + ] + ], + "svg/pservers/reftests/meshgradient-complex-001.svg": [ + [ + "/svg/pservers/reftests/meshgradient-complex-001.svg", + [ + [ + "/svg/pservers/reftests/meshgradient-complex-001-ref.png", + "==" + ] + ], + {} + ] + ], "svg/pservers/reftests/radialgradient-basic-002.svg": [ [ "/svg/pservers/reftests/radialgradient-basic-002.svg", [ [ "/svg/pservers/reftests/radialgradient-basic-002-ref.svg", "==" ] @@ -305168,16 +305252,51 @@ {} ] ], "svg/path/property/resources/interpolation-test-common.js": [ [ {} ] ], + "svg/pservers/reftests/meshgradient-basic-001-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-002-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-003-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-004-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-basic-005-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-bicubic-001-ref.png": [ + [ + {} + ] + ], + "svg/pservers/reftests/meshgradient-complex-001-ref.png": [ + [ + {} + ] + ], "svg/pservers/reftests/radialgradient-basic-002-ref.svg": [ [ {} ] ], "svg/render/reftests/blending-001-ref.svg": [ [ {} @@ -344666,16 +344785,22 @@ ] ], "dom/events/Event-type.html": [ [ "/dom/events/Event-type.html", {} ] ], + "dom/events/EventListener-addEventListener.sub.window.js": [ + [ + "/dom/events/EventListener-addEventListener.sub.window.html", + {} + ] + ], "dom/events/EventListener-handleEvent.html": [ [ "/dom/events/EventListener-handleEvent.html", {} ] ], "dom/events/EventListener-incumbent-global-1.sub.html": [ [ @@ -356546,16 +356671,34 @@ "/fetch/api/basic/stream-response.any.html", {} ], [ "/fetch/api/basic/stream-response.any.worker.html", {} ] ], + "fetch/api/basic/stream-safe-creation.any.js": [ + [ + "/fetch/api/basic/stream-safe-creation.any.html", + {} + ], + [ + "/fetch/api/basic/stream-safe-creation.any.serviceworker.html", + {} + ], + [ + "/fetch/api/basic/stream-safe-creation.any.sharedworker.html", + {} + ], + [ + "/fetch/api/basic/stream-safe-creation.any.worker.html", + {} + ] + ], "fetch/api/basic/text-utf8.html": [ [ "/fetch/api/basic/text-utf8.html", {} ] ], "fetch/api/cors/cors-basic.any.js": [ [ @@ -592323,16 +592466,20 @@ "dom/events/Event-type-empty.html": [ "225b85a613a6557c581a5989c7ed54c5641576ab", "testharness" ], "dom/events/Event-type.html": [ "22792f5c6c7883c97e71c7adec1c2d873cf608b8", "testharness" ], + "dom/events/EventListener-addEventListener.sub.window.js": [ + "b658140eea871f8790e9494ccbb8e8b845fe800e", + "testharness" + ], "dom/events/EventListener-handleEvent.html": [ "b33b030a641dd0d2a4e1319f366e3db975e9dc3f", "testharness" ], "dom/events/EventListener-incumbent-global-1.sub.html": [ "9d941385cbc483adab3e74c5518ec3d0291b730a", "testharness" ], @@ -597371,16 +597518,20 @@ "fetch/api/basic/scheme-others.sub.any.js": [ "5f9848ff4c297d662a82aa9e847f548371c33d19", "testharness" ], "fetch/api/basic/stream-response.any.js": [ "5b11018eb31648f5503eba1b1e71a616e219b375", "testharness" ], + "fetch/api/basic/stream-safe-creation.any.js": [ + "180d338659021fed3d29e08ccea415cc5852fed2", + "testharness" + ], "fetch/api/basic/text-utf8.html": [ "e5c567b9c4531113c12a3c56d0f5d9c1517589a2", "testharness" ], "fetch/api/cors/cors-basic.any.js": [ "0b3d7aac584ecd6c84916acecd94fca3534aea9f", "testharness" ], @@ -651115,16 +651266,72 @@ "svg/path/property/resources/interpolation-test-common.js": [ "b7f8cd308d7cbcf1aaa4ab686179e456f61c7d6f", "support" ], "svg/path/property/serialization.svg": [ "297f8ede687a28a12ced98a4b89051dd9ddf5090", "testharness" ], + "svg/pservers/reftests/meshgradient-basic-001-ref.png": [ + "691bff6244cd0abe046536efc0a100329b62d407", + "support" + ], + "svg/pservers/reftests/meshgradient-basic-001.svg": [ + "24290d40d6c37583d86aae4a098293c6cb8a6653", + "reftest" + ], + "svg/pservers/reftests/meshgradient-basic-002-ref.png": [ + "691bff6244cd0abe046536efc0a100329b62d407", + "support" + ], + "svg/pservers/reftests/meshgradient-basic-002.svg": [ + "2391135200207810cc770c961e72f77adb9b22c0", + "reftest" + ], + "svg/pservers/reftests/meshgradient-basic-003-ref.png": [ + "39c36a150fb1c9f98fcbd118a14589885527034b", + "support" + ], + "svg/pservers/reftests/meshgradient-basic-003.svg": [ + "84db2ea1260da1712381a334f9a99646a6418841", + "reftest" + ], + "svg/pservers/reftests/meshgradient-basic-004-ref.png": [ + "39c36a150fb1c9f98fcbd118a14589885527034b", + "support" + ], + "svg/pservers/reftests/meshgradient-basic-004.svg": [ + "c7e750199373bc3229d155fbd2d17f25b457aadf", + "reftest" + ], + "svg/pservers/reftests/meshgradient-basic-005-ref.png": [ + "3cd5164b776717ed1c9d487430682ee4ecd00a84", + "support" + ], + "svg/pservers/reftests/meshgradient-basic-005.svg": [ + "59a6c2500a17588f0c926d625f028a400bda71d8", + "reftest" + ], + "svg/pservers/reftests/meshgradient-bicubic-001-ref.png": [ + "551345d732c4f93e9f220d303f4823b5007d7605", + "support" + ], + "svg/pservers/reftests/meshgradient-bicubic-001.svg": [ + "8c3c219f1829694c002cd4c4026ed00202f51b3f", + "reftest" + ], + "svg/pservers/reftests/meshgradient-complex-001-ref.png": [ + "4ce893b827cabc5e4627060f3e5334c1b829bd30", + "support" + ], + "svg/pservers/reftests/meshgradient-complex-001.svg": [ + "625fae59ea53c96080ce3105e247bda46e7ed4c8", + "reftest" + ], "svg/pservers/reftests/radialgradient-basic-002-ref.svg": [ "26f4f508f35855ffd35baffb1aff129fe1ebf1be", "support" ], "svg/pservers/reftests/radialgradient-basic-002.svg": [ "04d8d3025ee0f039a05bdd439f2dc02c13f49a23", "reftest" ], @@ -661004,17 +661211,17 @@ "d6238a9cd367b00137027735fd0ff7d3c3aae3b7", "support" ], "webaudio/the-audio-api/the-analysernode-interface/.gitkeep": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "support" ], "webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html": [ - "4e27f842ddeda3e2bdd78da7b8ee3f67062d1a9f", + "a9aa4831516c6a5cefa7c8b4f67f3ef246d24777", "testharness" ], "webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-basic.html": [ "e176d6111e81fbff6ce75d63bec563bede61de6b", "testharness" ], "webaudio/the-audio-api/the-analysernode-interface/realtimeanalyser-fft-scaling.html": [ "6a0ab7d06eda5a67ca4262ea1ded49b03cc356b9", @@ -661036,17 +661243,17 @@ "ecd216e82c225f3160f2d586d9cbfbb8384a718f", "testharness" ], "webaudio/the-audio-api/the-analysernode-interface/test-analyser-scale.html": [ "04fe48096459dd0bbf4b3b0fd206c90c0bcae0f0", "testharness" ], "webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html": [ - "52d3829cff3dfceef64a34669bc8e0d6e08883a9", + "a8b5a7154e94479460c1085c6b5cb584e9b6976c", "testharness" ], "webaudio/the-audio-api/the-audiobuffer-interface/.gitkeep": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "support" ], "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html": [ "e0359953d2e909f69066885515f4a3f3cc00ff02",
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/images3/object-position-svg-002o.html.ini +++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/images3/object-position-svg-002o.html.ini @@ -1,4 +1,2 @@ [object-position-svg-002o.html] - expected: - if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): PASS - FAIL + expected: FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/dom/events/EventListener-incumbent-global-1.sub.html.ini @@ -0,0 +1,9 @@ +[EventListener-incumbent-global-1.sub.html] + expected: + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT + [Check the incumbent global EventListeners are called with] + expected: + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): TIMEOUT +
deleted file mode 100644 --- a/testing/web-platform/meta/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[update.https.html] - [Update a registration on ServiceWorkerGlobalScope] - expected: - if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL -
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-basic-001.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-basic-001.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-basic-002.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-basic-002.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-basic-003.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-basic-003.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-basic-004.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-basic-004.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-basic-005.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-basic-005.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-bicubic-001.svg.ini @@ -0,0 +1,11 @@ +[meshgradient-bicubic-001.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/svg/pservers/reftests/meshgradient-complex-001.svg.ini @@ -0,0 +1,12 @@ +[meshgradient-complex-001.svg] + expected: + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and not webrender and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL + if not debug and not webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): FAIL + if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL + restart-after: true \ No newline at end of file
--- a/testing/web-platform/meta/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html.ini @@ -6,8 +6,14 @@ expected: FAIL [X node1 = new AnalyserNode(c, {"fftSize":32,"maxDecibels":1,"minDecibels":-13,"smoothingTimeConstant":0.125}) incorrectly threw IndexSizeError: "Index or size is negative or greater than the allowed amount".] expected: FAIL [X node1 instanceof AnalyserNode is not equal to true. Got false.] expected: FAIL + [X node0.channelCount is not equal to 2. Got 1.] + expected: FAIL + + [# AUDIT TASK RUNNER FINISHED: 1 out of 7 tasks were failed.] + expected: FAIL +
new file mode 100644 --- /dev/null +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html.ini @@ -0,0 +1,7 @@ +[test-analysernode.html] + [Test AnalyserNode's ctor API] + expected: FAIL + + [Test AnalyserNode API] + expected: FAIL +
--- a/testing/web-platform/meta/webauthn/__dir__.ini +++ b/testing/web-platform/meta/webauthn/__dir__.ini @@ -1,2 +1,2 @@ prefs: [security.webauth.webauthn:true] -lsan-allowed: [Alloc, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::alloc::h5a1f0db41e296502, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::alloc::hd3c140e687e2a935, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::realloc::hfdaa883bde7dcfa7, mozilla::dom::DOMException::Create, mozilla::dom::Navigator::Credentials, mozilla::dom::Performance::CreateForMainThread] +lsan-allowed: [Alloc, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::alloc::h5a1f0db41e296502, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::alloc::hd3c140e687e2a935, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::realloc::h5c6d61654badfe59, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::realloc::hfdaa883bde7dcfa7, mozilla::dom::DOMException::Create, mozilla::dom::Navigator::Credentials, mozilla::dom::Performance::CreateForMainThread]
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-addEventListener.sub.window.js @@ -0,0 +1,9 @@ +async_test(function(t) { + let crossOriginFrame = document.createElement('iframe'); + crossOriginFrame.src = 'https://{{hosts[alt][]}}/common/blank.html'; + document.body.appendChild(crossOriginFrame); + crossOriginFrame.addEventListener('load', t.step_func_done(function() { + let crossOriginWindow = crossOriginFrame.contentWindow; + window.addEventListener('click', crossOriginWindow); + })); +}, "EventListener.addEventListener doesn't throw when a cross origin object is passed in.");
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/stream-safe-creation.any.js @@ -0,0 +1,54 @@ +// META: global=worker + +// These tests verify that stream creation is not affected by changes to +// Object.prototype. + +const creationCases = { + fetch: async () => fetch(location.href), + request: () => new Request(location.href, {method: 'POST', body: 'hi'}), + response: () => new Response('bye'), + consumeEmptyResponse: () => new Response().text(), + consumeNonEmptyResponse: () => new Response(new Uint8Array([64])).text(), + consumeEmptyRequest: () => new Request(location.href).text(), + consumeNonEmptyRequest: () => new Request(location.href, + {method: 'POST', body: 'yes'}).arrayBuffer(), +}; + +for (creationCase of Object.keys(creationCases)) { + for (accessorName of ['start', 'type', 'size', 'highWaterMark']) { + promise_test(async t => { + Object.defineProperty(Object.prototype, accessorName, { + get() { throw Error(`Object.prototype.${accessorName} was accessed`); }, + configurable: true + }); + t.add_cleanup(() => { + delete Object.prototype[accessorName]; + return Promise.resolve(); + }); + await creationCases[creationCase](); + }, `throwing Object.prototype.${accessorName} accessor should not affect ` + + `stream creation by '${creationCase}'`); + + promise_test(async t => { + // -1 is a convenient value which is invalid, and should cause the + // constructor to throw, for all four fields. + Object.prototype[accessorName] = -1; + t.add_cleanup(() => { + delete Object.prototype[accessorName]; + return Promise.resolve(); + }); + await creationCases[creationCase](); + }, `Object.prototype.${accessorName} accessor returning invalid value ` + + `should not affect stream creation by '${creationCase}'`); + } + + promise_test(async t => { + Object.prototype.start = controller => controller.error(new Error('start')); + t.add_cleanup(() => { + delete Object.prototype.start; + return Promise.resolve(); + }); + await creationCases[creationCase](); + }, `Object.prototype.start function which errors the stream should not ` + + `affect stream creation by '${creationCase}'`); +}
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..691bff6244cd0abe046536efc0a100329b62d407 GIT binary patch literal 15882 zc%1FK`8(8Y_&!cjNy!otQe?@RJhp@<(Ik7etdk`pGlL;UmeE3X5{fKSma^~0G8oCe zO|s9#lx>8un_<TA9eTf?@8=Kr{P=kt$C$&*F}Lf!U*~<E=XG88M41``&Yr$_nu&?& zto}XS2TV-NzZfs~QzsaA5>%xwGv3&|@7ee=F>!o5d@*-=<-0O&3Ov<&_|)9X?J3;J z=P?r;4wrx83HEhy@_sDu<pWAzxpk3==`xeP?rn>J3{ocEXXaKJ^iL^$KcO)Yxc7<W zHqYgI!m<?AyD7cgQ9O^0KP0|g8D;u^*Z;c?ua)0^h_(Y7et!=LF2i6Hg0i;z$KSdP zklFm+<kXC@e$e3AqBRPc6uc55LFoG!rB^khSs|Y=zejKfTECGqqX{{i#n>#Q{fvch z%Eg5E5l8gN%}}KLqvKRPjEwRn;iXUu3^9~B^iiwV26d(i>`~G*aNatvL*QWI=G$h| zGgW>T9=Bel-NbFS?{j@uV0@|;*3Z9YgP!RD`<$fTH0TQ5UxhbH%5$t<#KuCk(`{e{ zOJ9Qd_@kWmJxb{1yal6FAPYU4kk)MW_r@-O5i#;PHj>Mzx=M0C|8*bGC^c<Q57x** zHQ;MYISp1hfIw3&7OwC6{r!jQ8K4&4^a<hhLD0R9gX&DU)8Key=_5jMlQwpvm@0$3 ztvSTr4T+DwmvV5%!|>qZ0zW<4cPr>DlFk;;-dxj=%IASw4wTuSlGv#5v-WXSOffOg z&E5m~Y>l&|zcJ$w2^Ej1T_4MvuIl0m3%<BuO&f2JQLjwx`SOWykd4sZJX42%tm0tG zn!Z-EapsB7n1ik1Z~zawfYrkSSyO==>~sFzsZoAS?s8MXBQfH`H)8bmB(5s<fAdDY z7;^`11qmY2teWL);dWe8SkVfe)@ivCB~Rd4muf4XnJ&*qRXmSem!N&?Pqf(@+Z2j* zYs6LltT=LwXH@X)Q<1L+|1Lupu+^5&kP^2jHT;lIpOa=;F3`>fPXV;2%&j_zrMnAF zX&0D{<~aB5NGqOH?zxb7AcawtvC+J+6@v&VE#@1HM=bq>vo}yCR1_`|9P1~yxzR(G zn2+){L>ol-*hcn-Pi=W}$a%DK)0>BOb6|S*t*J6(;rO7?CgRn20nk~@sIsA1m@!(@ zS!z=(4RLIMn%%9rmPQ5}nYiOWcT_C!pT?qSGw<t4c;*(qgj3-N$Ddh`V*hwK-u08+ zISb#I8e>F_Bncx3OpGZlP*hezPRQaMc~B3k0ls~*XFP68bqIENLgfLj1m7*J7*Azp zq%^_{-npS-GdyadhqvGe=YAj_v2D|Bwr;L<GzzK&8I39sI=w|}0kz2R5QxxleRXdA zf8KefZ{eG_M9xQg{2`GiaUaOu*)im6znj{OwF)Hn0PMPU9!tLCINtrhe1xTmYx<n2 z78`JvH5Q>7vH&N%Mqp>MKrQsV{ae3h9mp%{!&0GJwtHgxLy*wYxjv-6A#nw19hwjZ z!6!q(>k0{xD)kG;_lHm{JsKde-7gsogqH!tK)bQSk=C`D71(t~e&7%w;bDi#7hkYZ zjdjT-&?=ON5c!4%(gEW2MWVQ0V27r1?d|0Q&&0J(gpmHvMTLOm&cwTHkffgn!~EB& zbSUi^0Mj~}AQlyaP#)7_St$#5SXogw1NR;iS!uD8Q8;hD`!?M5y;8Yd57DI{`1Zi> zsxM|j-@Fr_)n_*LJOLAw8`fF<ARhcsC(>!8LQla)2n!=jf8Uu`h_c@<wI2;a(!3L< zBm|=rqh}TcPA_*N?nff}=s&EEtK~mllsxq~eY*fWgohwA<xvEzn1&nSOPJuB==?e+ zi|`#kVBIAKJ_c8zw>J2;+(FMeN_|rA#63R$je_5t5Yk?Cil0)zwdxBD-^67a&zZt( z)3Lwf6?&bF9vAf{PMoKToMSvuE#o^F>-9vt@2e;Qn)9t|D^b9%x?=4@sJK5EwinL{ zsbfi?8fL6LGhL-@UgoY}z|T_DA();)7s=gk2s^vh#Qidw&RxvH7<t=#DF$IOGa4G{ z@|1l(nN4VxgJw5`?lUn7R^HvKDTmQ(PER+bH<c;e*;($mRoG8st#7Ts)uFUGX=_&R z3h|U8@^_b?2Y$eo1-Q8g6^gI;NHDLb2zak9`J07a{kd#oN)877@ETG@ziFHfclUd7 zQH%fnA{)OX{tLtwPutJv)$7cn)=inr;&$t2es5;Bn2_=0uuniMZ0$?LU|GTv{rl>Z z;CX@aav3^bPM0G0P%;pVziCAup0$MWV74YqWFo<{#3f%57isw#&Qq8{1=tySFlIw3 zWJu%D!9+h*Z!(df`W(TaiKaMO7Be7Z^lmlg*ui9*HTI1aJvzqVN#_#v{(8p2T77cQ zpmsucD!Lnjr`3zuXB5-9F!!#rT!H%NA`%zqL=f1VoJ2}sWia-XCuwk1{MNj-%Y|m? z{i)AL%8$EA6T7|L%QLR(#U|cyuhC!Kr}53Q5fq;6DF4piRUa=8JmmmZiS$O-Nvjvr zT?s?SgKsjxl}&gMuT)27udDQR2x;~OaVX5UmHvRc16CkzKDxC9+3n7Y0zXF7ZSe~E zTCe+`(1J5HM<aZ0U1UJ1tZVRl*>slOcO8g~%1~=bv}Ab*&2aAyQ*XAVNU-Y?Rp&)* z)4#34h<^}-FOahl@IPs!0aJSg!8;QxmGwAF+ONhR6lHC;93W$`UJ~Hhly=*okD^iM zg^}d(cb-m<Q7`IR@it~5i6sd<BcHW$Ji!C15>um@UXYwX%h<$w(kKtuseACYa23nm zq{I2Zc}~(BE-X+iJkhMe#yhW28&*So&;oW(rve9$CnrhJD*Hs}!G%hDEl-vGXz1E5 zEz?`-qO$zsqBg0GFq9^;q{agbj_fdV54v@<IOQZr7KO)qZe;8DcGBgl6rQIYs2l6h z#;#Gvo7#!V?j_KKwDHeqzjVo6p^(@ou!+>sQAc<R0R?dRP%Wp;{s1Kn|FOT#Kqx<* znmWoyzcfDuYAM6~LH-jqU9cw*R#Or=IFgfvxA5=$Q}xCDt(*GW)Ze6n7ptG_U{msi zWq3Dr1a646#ZiU}IPXnNS4nXhRjHg%J|1KCoqUfW!f`%()j5RCon`Gdvl^^KGG~tk zhoF~41SOs8F{Ny$z@WI}F}|dv$Ehr?CaS}0N$u^OIF~mw<(v+Eg>|!@H$OVll#jyu zi-c7HZ*UDE+X7*kC`i~MKafam9Y9c)3rMWMo-cf_Ju+D_aj8GI$D;;-W%ClDu0-F5 z+AbQw<lMc=i;YO0r;injr=kryRVT;+jNo`Tndy$-=4wAi)aC`+jbLllE8f$o>jJgq zZuFNb8e9g7!TX8GPd;{qH`46DwDy*EWBRht8p7=CD7L*+i^3M_@o;-nSqkIDbg0!u zbopOZm@s9qNc#fp^!ks<eBq9l0k%9z4~AV`x*c5fk`aBQ*w;^Y0n^fx9?^?t^*OMK zKv9gD=IyNS*fAGu2;NZh)n+~^@gu=VctQ07KUFh4sQEcv!AaNOa<GZ4;VI5HSGz>1 z%`U7huf#RpJFUYpgEJ_awsOW@a4R0sn<s%fr?tuVh8HjH1ZLyxr`!i+*klDvW(7w_ z@x!3xww=>Q#^{MAXd^9@{brTSDKFo_mqH`>dy|s%=fk-|Bc3jG<310h%?f=*YCDUD zOFNbmpl2+<bc@4h(wV-RoYDeF$cy8oUiW;OCgYM)J!EgJ8pa;ZpCBbq)y$+FoOyD$ z*q=CwD>M21Y$%_geFrypPvW3QDZ9s+Gdkz(H`-o#dNt3?J^uI<A#DU&D1HMfm;Q~c z$KERC`0g8Jcd7EtOybAGJ!hak@N43L69C5R=f<-q-Qc}VF;k?ySsu3+HfW9W$q$6= zdoC?rn0#rAdl7{Hx{Z^)x*xb305y^5F^bdKNx_?$D_5h?ZdDq@Xsp<62B`xTM9N6F zG2ovxRtWOSZm5nt?%6qKx0jjRRXZntsiGlQ-c@?@4Md2-L_^1hv|oP>fY;~P>m=X# zif(8$`6J0}nb1`u2*;Z@Pd*06>^UG~weyLCj9`}*bueSFCI0e;0JJ_gTiu^?TIpft z&hX|rwql7Fg4Q<nS_r)zO-G6!&-HXu^BGf}f5voA!;%6N_MD*Yn}1-s^)GR59s;{s zM<VDo4p*UQvJ6lq+EwrvpY&@r+XwcJ;EM4;U~Ns3>(%(;_^Tk5=0Ukz6JA<Vkcuvd zDlxI7up4)mJ)A$Qflmu`JzlJJfQp%qxxhfC6Iwk1GPwGWNYIH}-2GQ7PGC~aDvTtX z5A+fc89RPK*VKrTP*R>HYRY7ya6KP(UKisk(;*J+7kZ0ovYUtomsj}_i%=$<E02#J zj5%KE8Ck(e?sUVLVnd!~ru`59<ec<?3f80txIpd4f^!QY`!nk`G?&MMyZy7A{!a0- z^SOi}pIe8MW5Is`F9~kb((Jy|>uLzyw>Fee58M|;*zfKC<5aB?-_{riUf#NpJ!-I- zhRqTBh9kRJ!xupprdA4fn$Af;M%D|DBy07aouxJlbtIT9GQ9@X4BO~+jyb1m^e!>< zaV4Ov2b%G_L=C)@K-z}QT*SF`RwYe1&a~Xc;lTFA*LVZO?`};TS3akQ4vY)Ox-hU| zJ&{c?2-uTb=${p$bKhg6C{2}BeFH^^-??#oOyH$Xq*2?WR+BMnfin87Hqa%~MvmV6 z8c93|>X7xvenQP^I;!Ewf-I;O(;$})Soh-p4CT8VFykmJWqJAqi?vV>A;(Cv8u!$) zD9pnC{<0Xd%gZhCp_(z4zjOT`W+VsW!_yZSgyfRNjFccxBQMB`Q0l^k(A}wQ9^~<P z3w6XP$#*qud@*@M4e3s1%pBGwc_w$p64`m^1|rdm5eVO`%`-c)%-Z4r@TY)Y4L}e? z0p_Y&b?PAvvFw{a!{V%cbA6R_td?!(Y4dHn1vr?H5W?XXix9~p7+{{i_Yc?B_(g%? zjSZK~qjt3pq9|Ew<bXUY%i5xvN*80Wr61A^Tz#*&jlP~#`(t>08pJQ}e$qF&ZLHHR zK?Ye?wkoK0=VX+`5y@ceL)jZ@Ysh>9w1D|-9-^`Uz;U>$eSIdhunW?M2(}WkBSQM; zbF`|HD6mSG(9DpGlvLFG!iT=LG&RION1VU4V_1q|ox~%i=*G~iH<v;KrgzWHbsZnj zHRDBVb97u-sqC+4EO~3VH;M>XQFg*|o6g}ZW_D8B)xKp0h#$1B=P;fvT%3dIFr9;8 zrF+OV8i}_T^F_28+fI4fa+P)O@)^G=s%APqeQ|#EnO(ZbtNzu5nBANx?HccTwLcs` zDImq+fZ<dY!sNKshGb{L$)l_+9pSZmj6*MV$2EJ>q3>&35V7)@)Ua*Z&JASAlgiP- zm7Oz*LJcL=((;O>aXa{TMrh1CB&W0K(ihf4A21Ywh(ii8=zTyF`&_bZ!ZFkU!<jgj zzx<paGM!5>J?@cx;@N$j!kz74uP@!1d(pt5Y21Vx!Y#O$Jt|IdEh*;7yF2zdBdou` z&0&M9=u2C8A8jSAEp&&UHZ#QqZ^gL=ZUq=M-s?hLs$r3z<J2n3cJD!rsfb;+wzE0q zxaV=@I%2TK7@o3t^D0>kpC+V~Ei`{&#I9@ouiCneU8w+IHh<FKE#aA9sYO=2DO0yn z?%=>P_w;QIyEz_e`chDI3CRnSJy2SEzB86VK8|CFB_((~&YqFJnr$heiTMZXM|9ye zwCY#;(Jm(Zb6aMl@kCdY%SO@U%D_P<qE5+J0!82jO<VG)@;;BV>C(p4$S~)JKe_un zo%{k?$29Ju?Z!Jax=brc5b>4J3hJ*+o%-U=umr7)AWxtcD8USPXmWeD8yh}S|6?KS zag4IhXYxoq8UoV~e<Yb%)!&i0;t_<YiYx8Z_>BCX_UOb|K+=#1K10-PoG_D*)3ehL zNb|0`sf0EQ{XuqT0C!tmudf`_X;u@1I%q(6HL*HyKl*`eH`5U&8K*3?3KLy3GEHQn zgOkhB4LjJD{`mJyA&TW!-LL3xvLcQAPBs?++6==#j6i3O)6HX^{~uOOYt!rYIY{om z=ul4L98FZi3|uE>yr{1?(dK&EqkkH*tg9IzvCqtGv|0((!t>3UhiD;tewUeXf@-~m z<CF#&o@Mm_H&`|R!e<8;Vu|MJd&;M$_Y9~_%L3)NvtDh=RF>c|NxiFkKv951%k@qZ z!t#Jkv{F9SWJL_UDBIa5S|u1!GBoiJSg)Za7O}cH)`xnAHheBd@W8+95;;qqq&Dm^ zqRr|CWieBlUl`RT`Pb{f&^rphMOK&qu&O<%!ocLolCUyeuB~n%y4uF}Zj%G2YCkfn zA72#Z$hleC-%&nh>X2?03%PRNLtAto@CtD-He&RBwM>)Y4ibL8e8<x)<yvE&0<#;! zT$!*95=ZYr01bFy6IrHj4z-!jr9BOFZES@2sKaf>aID$SDG)T+o*-EY@Vk<}B3Lt_ zu2_DK|2bLw2w6ijO1pbXzxqJKgzB{+HW`l^(e+)&W{xD^+DCO6d4X26<?B>5KYFoO z_uAg;>{#laUo<rvwxeQcJ^a3=WVqq2<lpDhP`5z2Nq5|bxA=hehTgOJ_`TQMq7@9T zCP!%enwqCNzPk8Y12hN1TkTcCgx9NFYN5?u9c89O`GlzYf~G|fDZAMQbHAC)`oD+| zIS~F7P%t?k+ogn@9I%d*pCn0hN$i65RCv@YmB)N>Wu~=1jRMVz>|Y5DAqGI^G3XOc zQ1WC4Og$Gk%)hI*9i0lK%;7H{NlJx!dIEyknyRAnl#FIC37f-{cE1Wa0eM6|cU|F6 z)``Ej{Aa+dJ&Fp!CkmxBOGQv9S^!_EgI^9KsKtXr+;9wfm7Jqrn*Lz-z2wPlw-6;A z6j7%b?U2bG)3pR2Rf5f~Z2g-NXKFz>XAaB$x%y~5K3F2Y*kOBHMFcxG110U?6cl)5 zw%Dd2d#{8{CiRe~|JGsXj+;E*p%fhp(x5JO`l^mKN#XGq9~C9$w`$*nYonB^e5c~j zwYyrXp9eiB<Moa2bGfKGI-$D@rc<&0?nOQ)$6#0IKShR1(bhKx0$a(04D&0r1@5@f z6@?(yllZFn6LHKzq4gSPr={`vCotw#yJB{XpEY_K#A|lIm?ym*W|iAD`N3j|Sou?l zkMz!nmzzHKRJ565#*Xt5a!?EiGV<HAQ0zPz)S@u>dHIH!a3zU2g(9_kNp^N%@P!vr zz~5btlh7*SPq|$5BRwHvuy73<@$V3`ie|GjmPMpZ#XUcW&Tz_w)-TC~CIB?y1VaTt zj1+TdwF&!N&+f6LCO1d|qA=iYola_*bLAtU15ZD@ODbV?-e|t9si69~`qIe$W(CJm z0V>@$t#h77k>IkZm{E4#r237ThD}7m?~d6`E53xku^KI@Cj}vy%c}Jh@s1E5=O7JW z5p<KsA?n9S)x_CAk+H0(r$jHDzs3MtVwZ3kcS%UXqLunflsiD0<kn_sb3J)nuXtm? zc9^G~N>zBYMZ*(ujA1p?v3mk<y}&g6ru63nSbS!pOEr_LdJ!7;Abxr~fDK(Bl!K!J zJn&)|DWZTnwH{h)Zd{GWF1W`}P-KZS3?=2KPkkoz9*7s)Tmh&QJi_lz$MVJBy9$cl zG!?>6VWGD|<@bWm{;n~rh*tL}rsWs9ER)EMJ5vb&(W%{=>E8#oHTf9(gI)dms`^g~ z=F0A-4AeL_lf<XW9$B+QluIk8+wV?luIDt6p4Ivi={pPZ=D2Ij1vnne)4u78%g5C= zme$#8Lfa23TAE&rcpQreG_TtU17d@bn^GMB|5EEVb(v6Z)k$HKS$%$P!6GDFBec2h zjVx_qv&-u|Xqx_?DAfR4a(oFY0%94#GWC+!q0B;UFXv+*81>ow7&e8V`?FtJb^O-v z+0s$lf)bySz105Q2_5v}(Eu7scejEfgZ9t-AvQLA)6jdKbCG(rXCTS;i*9qO*p?FA ze7dXc?Xa|qu6l4LV^yC~z<1w>cI1aXNvxntm-atvrR5y0=jT<BPq#@6I!0ZrF<b4u z#IljPWBbmW(EP>E>V2T{j2ue(W?VucC^_e>u4<6Hj}Z4r*TI*AsAF1(<<wWcTR~cs z$(Q7i6gGtJY`2b&?sIdEHRPtb{|~v;@{v8WTT4oHm!4=wc|Yzq+wXan@W<uM24z#+ z?40htN$@V}^%35tu=7;A@8kfTy17j6>GU~UZp#W4o29N%qR0qeh60Hkx_sw%BraF# zZfmzL-yCH<h|u=TW_Hx7=^Wpu&}jokl0o<-M9;!*A8^0ZycAVRM??bJF5##<EVRj! znR3S`>WhrXX*(LfgMi>Au(^w|N71QOVT`y=@o5FYs%^98#h)}+KX%NpzfQ6feVWc7 z0lGSaU*_qCT4Z<&BHL9oAuLw{dNpGR3Jq0J0oK-TyWD90mg&p$k_VNd_ql;795r~s z0_ctC8Xa?<g0uhYW*5gZj@W+h1wPW>Svo_1Su?ifa6REI<o;9DB*`^AilVIP6moVb z2|ri7TnXR_RW){^q0C`{4jn3ePpIF(9+3C#$~>K;IglJRdE&hcg;3!(+TV?^&jM_b zj9gD?OVpS!BYYKl@bJF7!^gCek~>>X#y#t&_oUUOcOS<~Ncj52wn{n(=^_(+^S#!Z ze^3rx26TZUPuJRD511%>B+0tu5h{*IZ*K9bWAXRvnq2s}`gkK^x`I7yGiX<93AA*c zh@N~hOVpc!O3+lYE!9tiI8Ca2Dfvd*#ff5c@P`47Z8y;y`dvk+arJa<7gLQXQ*WIN z1t)a+u%i$!MvJR)O_zi+VRIP=;oj49NlsHQfHt#MvMD<#g-yXNs7Jw04Xa|H6W^Zb z3pY{3k!Jyt;LOO-6Oeddv*r@J^Ly5%>4F`P+9g`+#S<>o8jnUml2$e!$>TAm+uJ+x z9r!X4yq4-+g^cU3*J7L@63rzeqe<JAdPUABl*9aOkbjl7@WKLxdj-u(qAk}iZ1TV* zFX2JUAl6hi&HjS0tJ9xDUQEh^MkPx}+$oNQ_zs_4K#cyw^q7i9meq>Bpa!OAp8%qc zHnPFO6VAiUOk3y@kwYqmOHh8kM0M&6-`6FNhvwg3xSwHD>|n3)+wf<mJH!}l9i<^w z`Qq2RX`B{6+-j|a)ZP#^5*E3qOomwkISo2^wQhKNZIW;Adw-SM3K{ud(6p^UR_a-y z3E|Jpku4HDf3`#i5!%;N?yOYi2$jaa?@E+AT_y{t_1(Uky-a>^UPj$^NIeW2)Jolx z29ymEz5PGcS>A%%5Bv^s^F2fTpY(89J01J;<-Yn9Th5b;T=tjiiAgs(dyO;NZGrN@ z>Y1rIPG#MiK!TVC@gL(~RaFTcKSM|r2}86DqlQz*V+M@ts<LbSot+Y=tLnw@i^sk* zR-wo@@*)FNnmtfpi<NyzK*mZSOCn|ucD|E+bOIEk^DrWgCu*Q}dugV<G#+}kRW&YY zZpHt$CL-IbGzFuzc(YI~`*nHNN|{d(x}{kfB{2Azu21+&P>6N@^3d1A1o~B96%Rnc zbbj~Es_Rm>o7+>Ou5i0@1K4B*0SyN5^;wwUsq%}2_9#Aq`d(CX_c|UZTm;iy&w-7r ziCR~MltQoer6Ig%hlMvw*w6p{^T7<YX<wk+!;bS4x1;{JSyt3VRdu_h&h))$TV0JO z;-yb3*!W&grW#!ex+N5W{nPP}xURxQZ3K@b_ngER?f5o1+}&e_V1=D?{BcLFP*5m` zu({iJaPntD4npB|wzp-Y`<F%dt0$qZ=~0cfdM^z;ws%1uM)3N@hqBW5??phY`I*2n zr7lvR{~ZVDIr6Qv9D0yA5yr!6CK+b!vf7s$v7V2-)^i2Q-r6hiehX}5qAUL6SAf)t z4Stl2=w5$Y@=W`VeIZE}7S0~2!2xAgzjT&LuhGM#yD;eay*A6cY@bdU)cZMat-%4s zpH6mmzg1m=I!aaST>X!ogX9rnNrOU0k&S_x_OXeiy8%5|5fhx&|FlD>A!L)|rs@<X zCgGUFvj8pGC8DDibx`BytK?iQWoCHii;^w#n&aDfsPGJf>EhX1R1R!+X7qIpgi43K zBZ%<R;N)z%o8&{+;)x4EFowm>!hkJeSFC0N%$gG<eeSZq_z?EQSX|n-X*kR>X25-# zb}QslG+&f#=*@LY<M+VRGCT!PBv;nD;Jn2ypp(@pAwC43^S^!|;m}nC?IN5s&ZosB zod$6NM&{dZ)@X1{yK3x8xyiIuLv4hR+A%!svD4$-^6(Mkhd1277?nw2yMQdj;8;nt zrQE;W>qjg$>h40t8EI1;W|Tr-=i-hfl7buh2i0_b-v8GoV{Wp(@Kfcz9h@!xQd!#* ze0TBmL!^VylGpS@7-=I)MLaeCwS$oA>+A7QxJzV*4|)Cnr|P8a58N$WSLox7_OV)n zVqXh{^RN^jSn0U10in-vHsEZqE!gh2;XHnLakJ*7TFI%Z;K`28^=6c&%{?9DVuh_# z82xa@V^nJJSw@DW32Z?*2!s6FQHg6)ooTC=#|DL-?4vSUN@_ylJw=2C(Quk;y!UN0 zb%av#@#-p>`8Am8v}rc1W*k*`PmK99``z^&2F|XZWZ(?sOHlf?e<`xml}L4DCDdki zrA2)=o-NGm|KuO60`d}BseJViJ-OZ@AC0cms0|ry{ty~?Qb_jSf`t&{)tSv0-?Y%y zgQezRyE}*TmFNWd_L{U5n7(Shm!V}PG0+pQ&TTv~utjPs)RkL&kW?<3J6t+eFSX$T zv~ewglJ3Ubk)Rr8c)(5#e6#I`)#cY+K;P<iUU&b#>U9W1y#b}&pK=RG%3~NP#3l=o zwWX)Ly!^5mVpgs`5|-(3>UB)mg`6@=qX!~)<ZUM<d2Tz!qSwh6P!c=_<j0*~FPJ-7 zJ0I^9Lm&Fv)!7S!t2afOSV;uBE>>4%^2>7Hv#U3iVf5oE+Z=ntYGSuJSWTDHCxvO? z%QV}ekfup;P16PQE4yG$`-8sK$x^<wj}i($`yUpD>|d-_U}g|C**tm`yg-4h(3EoT z6Ivwj>Y)9^kKdXR&EJXewJ9vsn(s{<azT*ve56f*Ho@j#-_jGJLismYZXG<}rF4l0 zT>Y;r0;OPgd_Rg|m=8Ce_7-cgM43jJ;ZEWs_%XY_#P)UeuK92L(`VorIr_-9v>vkx zxwdZqi4v%u6#PeyP<C1Jx5i;27n>G0(F57{iHhTYju<S9OWOWK_!d0N9za>aRc0>5 zj)VML%A(W|?=#xho#P;YZHNTWzlmB=5y$t*+nNOS4*B8#y*9ne|HWE}DDfWW6QIO> znEfB@03d|1gIA7<eMNs{OP`(ii8F0XyB>k+ko=$~hL>Fla+Z^4szN2Isq)xQkT=`> zi9s#?e(y`Bcbl)n!RDxx_A6C2DpM*vpb_$+iM7igqI@DKm+rFFVI;GwSIgK$uKhsl z`8smH?;=4%f@^%Y*&|D?*xBcLX|I$SE__DyjV7p9ro^;;Trs`+RV}+)uJgjqz_{ne z`9%hoG(0!?-|CpiroqGeLN*!q)KVIA*t|ldQI(;0>&%vK??d3!l>~{EdyO6NYK^Hj zZd6_{3X8PXRV^IBec0KzXM@8_<Kv7{%R-nLNWN*e6_kl6Yhs-wG^u5ivmd3b_N}PI zKEaV(i&t)`DhBVbU@pH-%Us>s{g{<_IYd_ZcQ5<%N~l~v5XY82p6IP~uyv~|G$P;- zB}b7l#)3|%YB&>+yH|-->dB7)=$SMj$LbtmZ&Uyz>>wR_4d4#!`z^WeNdZe##98-O zaJ`TIv<FSMyZ&K4g*`etaVt;#h6rr`P{>FMTS4^*?NIi>*`zHQ#f<tS1P!2wK9~)| z`d1Ip%{Ye2!YX-;O=-V3^^tkDq=1l>DWYRD^dY!*v*xUG(XFFQGDz#sD+IA_n|&vb z8jMM}!bqyvWJ-B|)4HpQ<RWwUUJf1;<3D3fGfr+Yl9MWdF5UNt<I8ft@_~!NzKtKA zd6i<>^(S_gE|(ePStWtY(S_n_W#hWr+I(Ar3D+WLXbg{E;)7NC^~-_nTIToZTRg^k z&y}|G^+k+ueO^yJXBg(UD)26P#1eB~v!F}tN>pI*!9Dvz>}qAouUw?NNG4Ex%HUsy zcZp<Z2N4Bo8KES8w1$5k5niFGal0n)?xrE;R12@!UJdT&#SDtVUIWhqq8?i{uJ+DP z@3gzkj>TePb9|y08Q9e|8P@-4?J67`YrfycLZIjw?`3B`RS`(nRCW2eBOqw^in3Yn zkI)bD&zgHkE}FHkF50P?4;wS!Eqh=*SM}?ChxEASVT+gDe}N)&X_r-~Sz*V*KU7Km z#wSa@aCo$yBFO&+0L7VUiubOF@kxE}k<OJ@Tyhcf-EloLYTNy&J`LPs-P=5)Z?rfy zWl!rEs18q3;)?I%8XuS)-;E}x35~*stat&=l&tIWZqME?LG^;3os{heo|o4+{~f}i z?J20#V_qLWzs<|oN$IoyVu%|P$mjhP-2RI*lI2yF&KVA}u7*h9I7hphi=gaPgfk#X zsRzSzyCN&+n2?<P@A@F+AcSs4bC!Fo4FZ-maWtbt!Ke4}dylHFMM=1CIdVb7ktBBb zN}(L*5MILO)ZJYGYQxs%;89}vj9IJTh&1aUy$Z%=C;nqn`P4>@#G=Rq#|HM4nn%z- z3vl<t@oaulK=<fsslkJ^=#md>J(3^R3Rm8~F|yMaV!=B=V^9+-4@cg{=eQSnjBlld zLnPm{Sgm+us=-lT4MsC3?(W_Qx<c(ds!KE(VJLKg2ijyJFEU3(iT!qrB(*1guUbzh zPLkV~uhRqqgSJk>-VHfwi)iErN%}uta+F3iuvn`DP&Na(C8EoWaa30iv-Sc)kk{=Z z)T6f+d!R6vko&N=&G)2~V0*dI)ZCEkqbX_{%ynw_nIilL$SJd?+hMSVgu;;ypD`De z_(GXDo@&No*+n0UiNGx)yV_Ef2*fPeCf@L;O?*CfOk}0S2#E4c@b3|<Fq$7X`qeG8 zf6)sUI3^XbkTlKvOo^G~vjdB?*3S(mKfTR{W4N`yrL3ugGXcXWDQcSVT7H=*$Frij z=W3s6+(Bu0cF<RBf^RL0)(;Tmoii2N*_f?Z!0Ob1o#%pjFb5uXD@wNn((_XHHx<i5 zZ7}Z-jzc70hf;Vde(<x2FITM_pWhv1{nsI>KVI=qZ&-8sY*C1_P@&0+E{LkDSyEfn z{DL5|E)X`|b6g$&g^wd~^S?5MX6;83EUyfQdL+Vj)xp%Z(Y;H{SBTADwLUmb$9_WI zzaT4D!S>(QKsTyAzEpt=xQRev<!7e=BQ6SGbqLjKc!mzC(*LgdlGklj&2G20fY06# zO)+K*stOO_lp$#aKE0zpW%OLP?g=tl@^~ugT~)hiVQr%ZhX=T%Mmro=*{p2_ZT6%+ zfH@F?K$jW|L;mZ8lpQGLib3y(y_hV;?l5$AM6VU62Q!G#eSq%K79*P>L|m#lcb9B= z5q0A`d*r;*FOd~?b$wtZPhk3b|MAq*m|vkOhtjb!eK=ss5#3`)&>Hfj%2y~z?Je#f zL5caNZQ9I|8f4Y*TAaoVukxlyeJ>!d4E@?E9wFbc{^iX~0%kzeu@>L1=-;dUv#5V- z0z3QXKYMk+U+x~Go8upzqc#ygw$hd3kf&({^B3_J^{+2~crX#(i2^upsM~Ai*e0)8 zYWZchszrT-yZEU~!~AQa)l`628#3cKH>8a7R*%}fGam`PTS2`_zXn&-d7pmQ#=$@@ zL(fiIgh3L-61&6oX17GmW4;;3W~1_fae%p>_UTvSZQHVOkA<w!%M_TsodsS*#C*r1 z)N-e<t9>d?v3HD-#>F52FniJhJaZ|F8Sf%)C|<0>>GlcOt}RNA>whGaRtL$5BQf6B zLZE-L#eJx-F1BlYQBUD3zEm|&p$Sn=dBe~BZ{<!^Y6naNq{Z<QyU3^i_7#u74QHnk z1Fj~=Is71e*x^)K$IZCH){@i;2`1U5YOPjreyaMD%3Wbf8EXThjxmskrB2}y)t_fi zvIA7!c>`|c>uKHL&W4h2Jrr8@D~Yb&z`r}pD8RZ5Q#_H`ec0kLU==uRbIQ|I@btAv zad>*vf)d`HC?IDwaa>>}xPLvi<h;vQ6`oqm{NQ$fn>zPwG*o&(V6bQ`H-E%=J>c(| z%|Db;yYEAtIy=1hPiy@Z=iR^h*ZHa_$NA`@7#sZZ9oRV^3*CIaX|wq9OSIE`v_W~* zpP5D07D11S+ES@kQ4Cyq9#%V{r6fa74C|z==sQboF0l`;X@vP!N>uU=36h>wjDVL) zfM;vdn2d!If%?x!5wrZWea8iNA1j}Q5AYy<mnhISko6np3cva1ua}iE(Lc}VFjmn} zYlGGPCP!PPx<XqJYv+xGNP6_%+lyjf&*<G0^Bi)V;4&e#IE4JUAX7t)Dmng3`=pZ~ zTW%C(^l7s<V42_GAlfIPZN*3P&{V%t%qDEs69v3|?0F+J5xX-{w-#AQq@0XF*ZkOT zq2r5n)7BHP!gkQ?Qm0u3w!^GoOyNXHT4+ycs&;gJlzBjn+x{C2FZ@S)YJbgt;?YDD zSc~fP04z&FQ5vNkTb<?_ApE7d^U7azq87OnLHtn=AsfxbFL6I|&++w-w0F>`ti=sG zB<D-P$`nNSk%c38iZp#+ePVy$b(>$p5bRgsTH((ll`17>_6#VVYhf`Odb!IiqssqB zp1$xlD|>hBzjt8+<LdbJFW5KIF|p6K1ITqoJAXYxy8q!(tl?Dv=6N2_H%WaXof8#} zZg}L{`mnG!s!qB`wwa$+xK`C5^U`Bwe43wGV5m9UmXxZ8U$e{)s#=JgF*&{S^!uv4 z1B1XW{hGl(AIUZCOk+~fO=`IARB1cVux;Ki65aR#B#IH4ffT3Bkg0Yw7g|z>JN!o; zq1d7<3YO;r0Un<B>{g^|zF#`*O3PisM`arO%)CD>-^*(_FChWgx)Se!-`0zX#iB0{ z{P4505#ku{27fTzv0Q(*jPQA<=g1qp5qN7swFEjA!B}bLtW8$?>fW|FJ@ZLsq$SwG zM8Y2k|ED?4R&|EF&d>MKXi{r`Rym&UGraUyU`lwhy>)0DeLE33(Oq_^re0R*82JSX z=V9@dC?k5Y?G4XpMuNmEoDuGV^w{F`8@3UX#f|ut{LBl!j}xCo;jsBLD8+-}{m$AZ z1f0BRA~dYv8%)Qr#vu%9au~dMf+5X6cta#R*LW=1Zt|d4dvym-gba$FAGxKu!ZLQ{ zCo|#NcQc@c*Y{chbO6DD#dq1acGQ2jlzZ*ZA*E5juliBx%W?~YySyQ)vjI`fhOr7n zemU+>-hI0TqIC_cL%WjvVGjtuw*T9yRP8$(os!#4-1y9UVbF2VK$Tizi$#2j8kyxB zd_o_n9G{tNmSIFN6v9uTcnF>PUU}lM&uuANB%k8u6Vr%W3-I@cN4$%+f@n&=a*}Xa z*3hc%L{he`^AhbtLW*Ia;8NGlK(nz-%&R698(;vv-Oqp(7C{Ox`_GXeciA3pVGWBn z<jD)qzFLjU(Q<#4Wd!pO|3Gg5Hy3VQ*pz#j&gJSXb8vQI47jWCX9qaHhB@vNaU?lZ z##EZ_V<^GQ*euDA_c6oOmJ$IHZKEAL!Tw*@hzRB=4^oZ2c<N%dU}lk>)jpkD5pA7p z5GPZj7<F*yBhPyDcDzK4)sgw0f*%C`VO2NFn9wZ@9xsWC@^jYI1lD93s-?Yw(3`V* zcCg$g)f)8Sda7^Oz8B8Q|C`L=G<vrg%O8{sJ~;Cyb~CZx-TDb+IU>L+ZX$bDvL8(t zDKF|I8d4JsX9q6~g^#vL%^8#$RM+ibHx`^#aoY+0y-FJE=)cD$3pZyQJ`()ocaOzu ztu5vjXIM*&l)t_$tm3A!{uw@zq+Ypc7GIG1BJQG{Ub2$<UG^#DE9a0V6gDuMa_zSK zY`|fKR-WNy!9OWy#%oJXsg+LzkH@gzY2ZBXviyS&Ug5-HiFdaq!lPc<0%A-h+7`$k zwSiol`KTOrooc%*+sK#J22&#EsC1|f=G%n@%7t1j77qLg6_05YnfA4`t;8@@cEwwi zZz+xU{-4GRs<^YXx^GdzzvZch>Dp<8wxzBC+JDXmihT}DGx}94xE8&Zp4F$cJK|b8 z`yOVmNe=cCGM~P5%4XNHL(%r?XS!|%#6CqWL<lrIQ#SVHa4}R9W)>@mMKk|m4jkx? z2=+kBx<6OX>;)cx2fa2O&!=sqa{=bxJ49Hm2|7e1A{&HJct3t{m#5g-@R_pqmxLnT ztUKam+G3c?qpDggsMVv4#Vhc{vX@hh6;G*$xyp-7<aka%PE<<!hwUnVCr6@&SmB6+ z(=&cs&e=r0M=Hd7?j-U3x@M`-Nu*+N^sN8}>kE#)Ml98QB3v9Jyv%|WogOsF`XN{L zO5HI@T_uS;EtDt)5IqYv@QL-5RDLg3+&?RPI=AjoMwZL8<@(=7wa{Us8nJ>AdrHdF zU&7H(o^RhulJ0eZMyMMaYIBL=jX12o^yf&7x>vqVx|#pvS*PG!!AhY6&AWDyKO=W# zQsJTD@&H`p*T<|41+PYO=;+$vc9t8CM__+XDLfh^-++3E${Yw(1aX0MAUr649X*to zVk3b?abXtLmsrC6s-%V$)sH{NCmKpGY!$&peaLNT_Y;tpn(|!Rm?=9fT*{CRx7Ev_ zEauwJ;W9WS{9sk4rwqJj0Chuu?xe*y3?M2LrFIb@u`<}!*TKcsHujDLk%7r*%tV*a zC5fUzXkSmcgSi+Ryb|K#5h$&2e2~G_EXIhSkP+0BvWv)geA^^0U@*W4N7Zw_s%wci zj`SE?@hFhz*1%uByO7hi?9s=^sxjb@@d%Cx_{xnmYKY8OV=%Zi?$Bn2BUUl2a@66I z3sAAaZuaCz#fC`4F}LmIECuoHSY5u5@*L1VDpvmNfDt9-Ct|lxiC88y@Y%%nY+l`6 zp3g&Gd0a6YZ$B<OGUKzygMH4Tu~p=I*cY7U0=Af?XVz&9>2TBp_4*Xcay$NGW0Zq` zJR;=yP`cC8>6HJHMko(pj_lVImVo`lcgC`){|bLxYbyOhrQS7kX<^ogwQt2yP9lGj z+GLD*ugNmSE9;-hYj&;hC4Pj<u+ja+DaqI+d}EPA_5yzV{Ko2WPQwA&P(Mn>c9ZQI z;Vmz<b?>uRZPD3{1P?({WmU6PS4A==g!w<Zr6nSt%S_9*^OF+ug9z?UX02A!6T@I? z@`5GMQde#%CQP(rnRWvsCQ6ty^yw$dDF|t=x7rycmK!zpAk|_$A3I$6HFO)Zpt^pC zk@yzdeSf8;P+ZWgV<_I}?$osh3EKH2j!@Z`S-`h*91qG>;6{_oo0US)>u0Fh;i5}L z^4HCpa+=e|W^VuI5JEy<58KM)azmwZbFqlJ5iP-@jf}@bqd*(vp9G1{#L4vsz$>7e z_15qnK=34owZn`6a2s?6KwaTHQZSj0XhhlID)Hb<0bF>YmdD%o((C~B8@upwBz=|= z0^nx@;!8Uq@a4s<Kbw9uErpj3NP+idcya;Gnols)!HtjA(r#SRL!V#Ll9t4XOY3i3 z&;wy7@Mh~q(l8}O7YeazPt)XIq-!9rVh+}-@VfpwyLAAGy+nP7KksMK@~_~z60%qe ztjQ5Oi|=n(`FGk7thHGDiAVh5Tffa-x9ozJaLJGPhr3}>gw1Szr=q*9l&{#K(X~^U zEwGk}?e^-11p7?yRs?%Of#sa3VrfsJyu9e$WQ7>TVBWuHD3dN&&+U{gQl>yHnS-Uc ziRFfuYWLM9<#|)0QskJ-;@?+QkrKT{nca8>h(gg~QAtL(Y!2Khc9Aokz^FX`AKwV6 zXQp?W;md;qyPa;;8l_tdZbCl+FdXjvBXX&p9FV_Q%)OHT?jPefLnh6mIJa7X=qhO+ z>-6(q@<~2dPWtm!6k7B6OM~>kv!E9UFG^0s{h0H|Co+!mLO~I_V<7>+P}OnEwiVWL zuma9%@n_U{);UkTi2$+R*zv&iqMIdas!%<<w5pm(laq-7CD4YCb&9>XW9aYXHa(BS z!U}=ldsuyz18t<)eTOQv+29vmTC}T)*&lrJ+{;WrN@*Oh*`<YkMI~cuE&UslQ1?$+ z;urYd)hbLn-t1PP=Ilq4j@k;C@2iigO%&`Kj&W?{!}d!PxSji{KSpOwMZT9pe^{{% z;Hmn#kUIwgFm&J#`&Jd+)kl&TaJo%Pn_5J@oBu!(`lxi_|2K(F*cUFp_~ye}UiGB4 z;p=}Qx-Ge$1Mj){NF_4FW6vT^5Hl^8E7iHR)Y^S%H?yfIq?SKRQy-&)x7KFipdOj0 z&VWAcHboxu)8z}qkUXYyJ1K29)?$1h(|mlK3V}<+rQVK|T}!^#eG0{5^_nV6Uwjhy zqTUiP<RLHc!dUg8;j2NE?H-dqb$Kgu3qNtS7I7ERtl6W<Z7Kc*d1^|6J0;`%S6$o) zk!B6A_UtQCbPEO?qy|2Qqjz7?F=Yh~<i*XrvY->O2m|%QvmvjR5XZ89$^l+(sHCV# zcWmi=$4h!eW!8KQ_@uWBa1O0CTFI!=6YZIy55N2bxr<0)%}FN2i%on2?gkzb^a+Kn zAT1G^+(KeY&euYHp7x9F3!NJ1Up5H|W|eGwOyXf{d!SAbSkUN=;Z@Rht#Z|?TcVMM z7DHt$uvw0Vx?cH-Gg%6|<gyS(NVQPLh$ye%6B(!e;kFtUiBhiNfqM8*>+ZWMDZ-&& zIU26o2QANB#c*bKe3Woag?k$;vmJ}u_a?Br=@(0QO7s+Zj}Yk(55IumxIlU8d2q~8 zIBbi(&A$F&!2%?xlEu;Hy6aT9P@<94)a?6f!^dNE(J^)xBBB)w#d;G*cr&eiT-jR< z`v%n*Jbc#WP%u=GXjb|+H&g9etEo<25m@PR1V47}65F6i0z?$a$j@&Vp0?h-$DF2E zws-eek85f4W3n=?{&Rh(C$WDy44`7R&wx<gA+1|4P&N-Z0kdUodz6|OWR!Ztqu*`( zt&_vN!#wSFy!&0+=bN9&Tl5Rip)RuuF6WohY&e4l24%KI<hZke?ddkAqO`yM_bdrJ z-+T~n8o3JP77BtD%W?qPYSa;QI{oqK&GZ0iRDu&$W;%a3)2OZMi$MC=ulH&<Dh5W) zpXp(?uE)yxW2C2~fO%OX&2Bh`X`5^>CmtRDYdR3|zTGD{HoF%cW5#Wb>a~J8Y-x9r zR>5NXTFjR6;){@<<}tcX#9Q1?^=1V%wD+e?E<cg$R?3@zWvmz4BM<vLUb8U>6Jj%{ z<$f2tg#^)k+M56MCp8&m8<_MuX1`f)#fv^ZGlqqcL1*OL%Od4AEkjc5Hy$r(@9eqH zr(ydz#uMZ=geUHfZ47=SKph!GFzKg}MAT$yPP4g<n^_dC;3`e47Q{5?cw({@<e0(( z3$ryY0!C(Mie<0z;;Vdw;*<gpd97BD!2k~D{_lOaHkEk5^2-|Hua!EgfB3t;p0RGJ I&ZC$AA5qX&!vFvP
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-basic-001.svg @@ -0,0 +1,63 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Single 1x1 patch (userSpaceOnUse).</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-basic-001-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="LinearMesh" x="20" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="l 200,0" /> + <stop style="stop-color:#00ff00" path="l 0,200" /> + <stop style="stop-color:#ffff00" path="l -200,0" /> + <stop style="stop-color:#00ff00" path="l 0,-200" /> + </meshpatch> + </meshrow> + </meshgradient> + <meshgradient id="BezierMesh" x="260" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="c 66.6667,0 133.333,0 200,0" /> + <stop style="stop-color:#00ff00" path="c 0,66.6667 0,133.333 0,200" /> + <stop style="stop-color:#ffff00" path="c -66.6667,0 -133.333,0 -200,0" /> + <stop style="stop-color:#00ff00" path="c 0,-66.6667 0,-133.333 0,-200" /> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="20" y="140" width="200" height="200" style="fill:url(#LinearMesh)" /> + <rect x="260" y="140" width="200" height="200" style="fill:url(#BezierMesh)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..691bff6244cd0abe046536efc0a100329b62d407 GIT binary patch literal 15882 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 I&ZC$AA5qX&!vFvP
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-basic-002.svg @@ -0,0 +1,63 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Single 1x1 patch (objectBoundingBox)</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-basic-002-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="LinearMesh" x="0" y="0" gradientUnits="objectBoundingBox"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="l 1,0" /> + <stop style="stop-color:#00ff00" path="l 0,1" /> + <stop style="stop-color:#ffff00" path="l -1,0" /> + <stop style="stop-color:#00ff00" path="l 0,-1" /> + </meshpatch> + </meshrow> + </meshgradient> + <meshgradient id="BezierMesh" x="0" y="0" gradientUnits="objectBoundingBox"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="c 0.3333,0 0.6667,0 1,0" /> + <stop style="stop-color:#00ff00" path="c 0,0.3333 0,0.6667 0,1" /> + <stop style="stop-color:#ffff00" path="c -0.3333,0 -0.6667,0 -1,0" /> + <stop style="stop-color:#00ff00" path="c 0,-0.3333 0,-0.6667 0,-1" /> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="20" y="140" width="200" height="200" style="fill:url(#LinearMesh)" /> + <rect x="260" y="140" width="200" height="200" style="fill:url(#BezierMesh)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..39c36a150fb1c9f98fcbd118a14589885527034b GIT binary patch literal 21887 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
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-basic-003.svg @@ -0,0 +1,103 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Simple 2x2 patch mesh (userSpaceOnUse).</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-basic-003-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="LinearMesh" x="20" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="l 100,0" /> + <stop style="stop-color:#00ff00" path="l 0,100" /> + <stop style="stop-color:#ffff00" path="l -100,0" /> + <stop style="stop-color:#00ff00" path="l 0,-100" /> + </meshpatch> + <meshpatch> + <stop path="l 100,0" /> + <stop style="stop-color:#ffff00" path="l 0,100" /> + <stop style="stop-color:#0000ff" path="l -100,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <!-- No initial stop --> + <stop path="l 0,100" /> + <stop style="stop-color:#0000ff" path="l -100,0" /> + <stop style="stop-color:#ffff00" path="l 0,-100" /> + </meshpatch> + <meshpatch> + <!-- No initial stop --> + <stop path="l 0,100" /> + <stop style="stop-color:#00ff00" path="l -100,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + </meshgradient> + <meshgradient id="BezierMesh" x="260" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="c 33.33,0 66.67,0 100,0" /> + <stop style="stop-color:#00ff00" path="c 0,33.33 0,66.67 0,100" /> + <stop style="stop-color:#ffff00" path="c -33.33,0 -66.67,0 -100,0" /> + <stop style="stop-color:#00ff00" path="c 0,-33.33 0,-66.67 0,-100" /> + </meshpatch> + <meshpatch> + <stop path="c 33.33,0 66.67,0 100,0" /> + <stop style="stop-color:#ffff00" path="c 0,33.33 0,66.67 0,100" /> + <stop style="stop-color:#0000ff" path="c -33.33,0 -66.67,0 -100,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <!-- No initial stop --> + <stop path="c 0,33.33 0,66.67 0,100" /> + <stop style="stop-color:#0000ff" path="c -33.33,0 -66.67,0 -100,0" /> + <stop style="stop-color:#ffff00" path="c 0,-33.33 0,-66.67 0,-100" /> + </meshpatch> + <meshpatch> + <!-- No initial stop --> + <stop path="c 0,33.33 0,66.67 0,100" /> + <stop style="stop-color:#00ff00" path="c -33.33,0 -66.67,0 -100,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="20" y="140" width="200" height="200" style="fill:url(#LinearMesh)" /> + <rect x="260" y="140" width="200" height="200" style="fill:url(#BezierMesh)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..39c36a150fb1c9f98fcbd118a14589885527034b GIT binary patch literal 21887 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
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-basic-004.svg @@ -0,0 +1,103 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Simple 2x2 patch mesh (objectBoundingBox).</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-basic-004-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="LinearMesh" x="0" y="0" gradientUnits="objectBoundingBox"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="l 0.5,0" /> + <stop style="stop-color:#00ff00" path="l 0,0.5" /> + <stop style="stop-color:#ffff00" path="l -0.5,0" /> + <stop style="stop-color:#00ff00" path="l 0,-0.5" /> + </meshpatch> + <meshpatch> + <stop path="l 0.5,0" /> + <stop style="stop-color:#ffff00" path="l 0,0.5" /> + <stop style="stop-color:#0000ff" path="l -0.5,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <!-- No initial stop --> + <stop path="l 0,0.5" /> + <stop style="stop-color:#0000ff" path="l -0.5,0" /> + <stop style="stop-color:#ffff00" path="l 0,-0.5" /> + </meshpatch> + <meshpatch> + <!-- No initial stop --> + <stop path="l 0,0.5" /> + <stop style="stop-color:#00ff00" path="l -0.5,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + </meshgradient> + <meshgradient id="BezierMesh" x="0" y="0" gradientUnits="objectBoundingBox"> + <meshrow> + <meshpatch> + <stop style="stop-color:#0000ff" path="c 0.1667,0 0.3333,0 0.5,0" /> + <stop style="stop-color:#00ff00" path="c 0,0.1667 0,0.3333 0,0.5" /> + <stop style="stop-color:#ffff00" path="c -0.1667,0 -0.3333,0 -0.5,0" /> + <stop style="stop-color:#00ff00" path="c 0,-0.1667 0,-0.3333 0,-0.5" /> + </meshpatch> + <meshpatch> + <stop path="c 0.1667,0 0.3333,0 0.5,0" /> + <stop style="stop-color:#ffff00" path="c 0,0.1667 0,0.3333 0,0.5" /> + <stop style="stop-color:#0000ff" path="c -0.1667,0 -0.3333,0 -0.5,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <!-- No initial stop --> + <stop path="c 0,0.1667 0,0.3333 0,0.5" /> + <stop style="stop-color:#0000ff" path="c -0.1667,0 -0.3333,0 -0.5,0" /> + <stop style="stop-color:#ffff00" path="c 0,-0.1667 0,-0.3333 0,-0.5" /> + </meshpatch> + <meshpatch> + <!-- No initial stop --> + <stop path="c 0,0.1667 0,0.3333 0,0.5" /> + <stop style="stop-color:#00ff00" path="c -0.1667,0 -0.3333,0 -0.5,0" /> + <!-- No final stop --> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="20" y="140" width="200" height="200" style="fill:url(#LinearMesh)" /> + <rect x="260" y="140" width="200" height="200" style="fill:url(#BezierMesh)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3cd5164b776717ed1c9d487430682ee4ecd00a84 GIT binary patch literal 15284 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 A8UO$Q
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-basic-005.svg @@ -0,0 +1,226 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Star: 10x2 patches.</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-basic-005-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="StarMesh" x="240" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop + style="stop-color:#0000ff" + path="l 32.3286,65.5041" /> + <stop + style="stop-color:#0000ff" + path="l -16.1641,22.248" /> + <stop + style="stop-color:#00ff00" + path="l -16.1643,-32.752" /> + <stop + style="stop-color:#00ff00" + path="l -0.000202026,-55" /> + </meshpatch> + <meshpatch> + <stop + path="l 72.2879,10.5037" /> + <stop + style="stop-color:#0000ff" + path="l -52.308,16.9961" /> + <stop + style="stop-color:#00ff00" + path="l -36.144,-5.25184" /> + </meshpatch> + <meshpatch> + <stop + path="l -52.308,50.9882" /> + <stop + style="stop-color:#0000ff" + path="l -26.1541,-8.49796" /> + <stop + style="stop-color:#00ff00" + path="l 26.154,-25.4941" /> + </meshpatch> + <meshpatch> + <stop + path="l 12.3486,71.9957" /> + <stop + style="stop-color:#0000ff" + path="l -32.3284,-44.4958" /> + <stop + style="stop-color:#00ff00" + path="l -6.1743,-35.9979" /> + </meshpatch> + <meshpatch> + <stop + path="l -64.6567,-33.9916" /> + <stop + style="stop-color:#0000ff" + path="l -5.60788e-06,-27.5" /> + <stop + style="stop-color:#00ff00" + path="l 32.3283,16.9958" /> + </meshpatch> + <meshpatch> + <stop + path="l -64.6561,33.9921" /> + <stop + style="stop-color:#0000ff" + path="l 32.328,-44.4961" /> + <stop + style="stop-color:#00ff00" + path="l 32.328,-16.9961" /> + </meshpatch> + <meshpatch> + <stop + path="l 12.3479,-71.9962" /> + <stop + style="stop-color:#0000ff" + path="l 26.1541,-8.49797" /> + <stop + style="stop-color:#00ff00" + path="l -6.17397,35.9981" /> + </meshpatch> + <meshpatch> + <stop + path="l -52.3082,-50.9874" /> + <stop + style="stop-color:#0000ff" + path="l 52.3082,16.9957" /> + <stop + style="stop-color:#00ff00" + path="l 26.1541,25.4937" /> + </meshpatch> + <meshpatch> + <stop + path="l 72.2881,-10.5044" /> + <stop + style="stop-color:#0000ff" + path="l 16.1641,22.248" /> + <stop + style="stop-color:#00ff00" + path="l -36.1441,5.25222" /> + </meshpatch> + <meshpatch> + <stop + path="l 32.3278,-65.5041" /> + <stop + style="stop-color:#0000ff" + path="l 0.000202026,55" /> + <stop + style="stop-color:#00ff00" + path="l -16.1639,32.752" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="l -16.1641,22.248" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + <stop + style="stop-color:#ffff00" + path="l -0.000202026,-55" /> + </meshpatch> + <meshpatch> + <stop + path="l -52.308,16.9961" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l -26.1541,-8.49796" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l -32.3284,-44.4958" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l -5.60788e-06,-27.5" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l 32.328,-44.4961" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l 26.1541,-8.49797" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l 52.3082,16.9957" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l 16.1641,22.248" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + <meshpatch> + <stop + path="l 0.000202026,55" /> + <stop + style="stop-color:#ffff00" + path="l 0,0" /> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <path d="m 240,140 32.328,65.504 72.288,10.504 -52.308,50.988 12.349,71.996 -64.657,-33.992 -64.6561,33.992 12.348,-71.996 -52.3082,-50.987 72.2881,-10.505 z" + style="fill:url(#StarMesh)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..551345d732c4f93e9f220d303f4823b5007d7605 GIT binary patch literal 38493 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[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 F_dot*H6Z{1
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-bicubic-001.svg @@ -0,0 +1,223 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Coons vs. Bicubic.</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-bicubic-001-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="CheckerBoardCoons" x="20" y="140" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + </meshgradient> + <meshgradient id="CheckerBoardBicubic" x="260" y="140" type="bicubic" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 22.2222,0 44.4444,0 66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c 0,-22.2222 0,-44.4444 0,-66.6667" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#00ff00;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,22.2222 0,44.4444 0,66.6667" /> + <stop + style="stop-color:#0000ff;stop-opacity:1" + path="c -22.2222,0 -44.4444,0 -66.6667,0" /> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="20" y="140" width="200" height="200" style="fill:url(#CheckerBoardCoons)" /> + <rect x="260" y="140" width="200" height="200" style="fill:url(#CheckerBoardBicubic)" /> + </g> + +</svg>
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4ce893b827cabc5e4627060f3e5334c1b829bd30 GIT binary patch literal 31532 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
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/svg/pservers/reftests/meshgradient-complex-001.svg @@ -0,0 +1,89 @@ +<svg id="svg-root" + width="480" height="360" viewBox="0 0 480 360" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>Mesh gradient: Patch paint order.</title> + <html:link rel="author" + title="Tavmjong Bah" + href="http://tavmjong.free.fr"/> + <html:link rel="help" + href="https://www.w3.org/TR/SVG2/pservers.html#MeshGradients"/> + <html:link rel="match" href="meshgradient-complex-001-ref.png" /> + </g> + + <style id="test-font" type="text/css"> + /* Standard Font (if needed). */ + @font-face { + font-family: FreeSans; + src: url("../fonts/FreeSans.woff") format("woff"); + } + text { + font-family: FreeSans, sans-serif; + text-anchor: middle; + fill: black; + } + #title { + font-size: 24px; + } + .label { + font-size: 18px; + } + </style> + + <defs> + <meshgradient id="PatchPaintOrder" x="120" y="110" gradientUnits="userSpaceOnUse"> + <meshrow> + <meshpatch> + <stop + style="stop-color:#0000ff" + path="c 53.3333,0 250,0 250,20" /> + <stop + style="stop-color:#00ff00" + path="c 0,40 0,60 0,100" /> + <stop + style="stop-color:#ffff00" + path="c 0,-20 -196.667,-20 -250,-20" /> + <stop + style="stop-color:#00ff00" + path="c 0,-40 0,-60 0,-100" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,20 -210,0 -140,20" /> + <stop + style="stop-color:#ffff00" + path="c 0,40 0,60 0,100" /> + <stop + style="stop-color:#0000ff" + path="c -70,-20 140,0 140,-20" /> + </meshpatch> + </meshrow> + <meshrow> + <meshpatch> + <stop + path="c 0,40 0,60 0,100" /> + <stop + style="stop-color:#0000ff" + path="c 0,-20 -196.667,-20 -250,-20" /> + <stop + style="stop-color:#ffff00" + path="c 0,-40 0,-60 0,-100" /> + </meshpatch> + <meshpatch> + <stop + path="c 0,40 0,60 0,100" /> + <stop + style="stop-color:#00ff00" + path="c -70,-20 140,0 140,-20" /> + </meshpatch> + </meshrow> + </meshgradient> + </defs> + + <g id="test-body-content"> + <rect x="80" y="110" width="320" height="240" style="fill:url(#PatchPaintOrder)" /> + </g> + +</svg>
--- a/testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/ctor-analyser.html @@ -27,17 +27,17 @@ }); audit.define('default constructor', (task, should) => { let prefix = 'node0'; let node = testDefaultConstructor(should, 'AnalyserNode', context, { prefix: prefix, numberOfInputs: 1, numberOfOutputs: 1, - channelCount: 1, + channelCount: 2, channelCountMode: 'max', channelInterpretation: 'speakers' }); testDefaultAttributes(should, node, prefix, [ {name: 'fftSize', value: 2048}, {name: 'frequencyBinCount', value: 1024}, {name: 'minDecibels', value: -100}, {name: 'maxDecibels', value: -30},
--- a/testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-analysernode-interface/test-analysernode.html @@ -22,18 +22,18 @@ source.buffer = buffer; source.connect(analyser); analyser.connect(destination); assert_equals( analyser.channelCount, - 1, - "analyser node has 1 input channels by default" + 2, + "analyser node has 2 input channels by default" ); assert_equals( analyser.channelCountMode, "max", "Correct channelCountMode for the analyser node" ); assert_equals( analyser.channelInterpretation, @@ -126,18 +126,18 @@ } function testConstructor() { var context = new AudioContext(); var analyser = new AnalyserNode(context); assert_equals( analyser.channelCount, - 1, - "analyser node has 1 input channels by default" + 2, + "analyser node has 2 input channels by default" ); assert_equals( analyser.channelCountMode, "max", "Correct channelCountMode for the analyser node" ); assert_equals( analyser.channelInterpretation,
--- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3736,20 +3736,20 @@ "record_in_processes": ["main", "content"], "expires_in_version": "never", "kind": "exponential", "high": 1000000, "n_buckets": 50, "description": "How many speculative connections are made needlessly" }, "TAB_COUNT": { - "record_in_processes": ["main", "content"], - "alert_emails": [], - "bug_numbers": [1361855], - "expires_in_version": "65", + "record_in_processes": ["main"], + "alert_emails": ["gijs@mozilla.com"], + "bug_numbers": [1361855, 1488945], + "expires_in_version": "never", "kind": "exponential", "high": 1000, "n_buckets": 100, "releaseChannelCollection": "opt-out", "description": "Number of tabs opened across all windows, collected at most every 5 minutes whenever the user interacts with the browser in the following ways: open tab/window, page load." }, "TAP_TO_LOAD_IMAGE_SIZE": { "record_in_processes": ["main", "content"],
--- a/toolkit/themes/shared/close-icon.inc.css +++ b/toolkit/themes/shared/close-icon.inc.css @@ -1,17 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ .close-icon { -moz-appearance: none; -moz-context-properties: fill, fill-opacity; list-style-image: url(chrome://global/skin/icons/close.svg); - color: inherit; + color: inherit !important; fill: currentColor; fill-opacity: 0; } .close-icon:hover { fill-opacity: 0.1; }