author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 21 Jul 2016 16:24:36 +0200 | |
changeset 306097 | 6b180266ac16e3226be33319ff710ddfa85f5836 |
parent 306096 | e28e856b987380f55d699092f11f6997378f79a6 (current diff) |
parent 306022 | 34fab997a0a18bc72da09d0811ff98357fe0eb5f (diff) |
child 306098 | ab54bfc55266aaadc00567341bf494e907b0e4d7 |
child 306145 | 8ad7dc5cba0ca3c18cdc32beaa0b0808488cabd3 |
child 306146 | 10501352b0eef4ecf19dd4d5b1d307ebb212cf5e |
child 306224 | f5154aaeaec4546dd04c66ac61a0d0ee69f4dfdf |
push id | 79765 |
push user | cbook@mozilla.com |
push date | Thu, 21 Jul 2016 14:26:34 +0000 |
treeherder | mozilla-inbound@ab54bfc55266 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 50.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/CLOBBER +++ b/CLOBBER @@ -17,9 +17,9 @@ # # Modifying this file will now automatically clobber the buildbot machines \o/ # # Are you updating CLOBBER because you think it's needed for your WebIDL # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 911216 - followup from the backout to fix bustage +Bug 911216 - clobber needed
--- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -2756,46 +2756,46 @@ KeyBinding::ToPlatformFormat(nsAString& stringBundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties", getter_AddRefs(keyStringBundle)); if (!keyStringBundle) return; nsAutoString separator; - keyStringBundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"), + keyStringBundle->GetStringFromName(u"MODIFIER_SEPARATOR", getter_Copies(separator)); nsAutoString modifierName; if (mModifierMask & kControl) { - keyStringBundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"), + keyStringBundle->GetStringFromName(u"VK_CONTROL", getter_Copies(modifierName)); aValue.Append(modifierName); aValue.Append(separator); } if (mModifierMask & kAlt) { - keyStringBundle->GetStringFromName(MOZ_UTF16("VK_ALT"), + keyStringBundle->GetStringFromName(u"VK_ALT", getter_Copies(modifierName)); aValue.Append(modifierName); aValue.Append(separator); } if (mModifierMask & kShift) { - keyStringBundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"), + keyStringBundle->GetStringFromName(u"VK_SHIFT", getter_Copies(modifierName)); aValue.Append(modifierName); aValue.Append(separator); } if (mModifierMask & kMeta) { - keyStringBundle->GetStringFromName(MOZ_UTF16("VK_META"), + keyStringBundle->GetStringFromName(u"VK_META", getter_Copies(modifierName)); aValue.Append(modifierName); aValue.Append(separator); } aValue.Append(mKey); }
--- a/accessible/generic/ApplicationAccessible.cpp +++ b/accessible/generic/ApplicationAccessible.cpp @@ -49,17 +49,17 @@ ApplicationAccessible::Name(nsString& aN nsCOMPtr<nsIStringBundle> bundle; nsresult rv = bundleService->CreateBundle("chrome://branding/locale/brand.properties", getter_AddRefs(bundle)); if (NS_FAILED(rv)) return eNameOK; nsXPIDLString appName; - rv = bundle->GetStringFromName(MOZ_UTF16("brandShortName"), + rv = bundle->GetStringFromName(u"brandShortName", getter_Copies(appName)); if (NS_FAILED(rv) || appName.IsEmpty()) { NS_WARNING("brandShortName not found, using default app name"); appName.AssignLiteral("Gecko based application"); } aName.Assign(appName); return eNameOK;
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1125,20 +1125,36 @@ DocAccessible::CharacterDataChanged(nsID void DocAccessible::ContentInserted(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aChild, int32_t /* unused */) { } void -DocAccessible::ContentRemoved(nsIDocument* aDocument, nsIContent* aContainer, - nsIContent* aChild, int32_t /* unused */, - nsIContent* aPreviousSibling) +DocAccessible::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainerNode, + nsIContent* aChildNode, int32_t /* unused */, + nsIContent* aPreviousSiblingNode) { +#ifdef A11Y_LOG + if (logging::IsEnabled(logging::eTree)) { + logging::MsgBegin("TREE", "DOM content removed; doc: %p", this); + logging::Node("container node", aContainerNode); + logging::Node("content node", aChildNode); + logging::MsgEnd(); + } +#endif + // This one and content removal notification from layout may result in + // double processing of same subtrees. If it pops up in profiling, then + // consider reusing a document node cache to reject these notifications early. + Accessible* container = GetAccessibleOrContainer(aContainerNode); + if (container) { + UpdateTreeOnRemoval(container, aChildNode); + } } void DocAccessible::ParentChainChanged(nsIContent* aContent) { }
--- a/accessible/tests/mochitest/treeupdate/a11y.ini +++ b/accessible/tests/mochitest/treeupdate/a11y.ini @@ -9,16 +9,17 @@ support-files = [test_bug852150.xhtml] [test_bug883708.xhtml] [test_bug884251.xhtml] [test_bug895082.html] [test_bug1040735.html] [test_bug1100602.html] [test_bug1175913.html] [test_bug1189277.html] +[test_bug1276857.html] [test_canvas.html] [test_colorpicker.xul] [test_contextmenu.xul] [test_cssoverflow.html] [test_deck.xul] [test_doc.html] [test_gencontent.html] [test_general.html]
new file mode 100644 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug1276857.html @@ -0,0 +1,143 @@ +<!DOCTYPE html> +<html> + +<head> + <title>DOM mutations test</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../events.js"></script> + + <script type="application/javascript"> + function runTest() + { + // children change will recreate the table + this.eventSeq = [ + new invokerChecker(EVENT_REORDER, getNode('c1')) + ]; + + this.invoke = function runTest_invoke() { + var tree = { + SECTION: [ // c1 + { TEXT_LEAF: [] }, // Some text + { TEXT_CONTAINER: [ + { TEXT_LEAF: [] } // something with .. + ] }, + { TEXT_LEAF: [] } // More text + ] + }; + testAccessibleTree('c1', tree); + + getNode('c1_t').querySelector('span').remove(); + }; + + this.finalCheck = function runTest_finalCheck() { + var tree = { + SECTION: [ // c1 + { TEXT_LEAF: [] }, // Some text + { TEXT_LEAF: [] } // More text + ] + }; + testAccessibleTree('c1', tree); + }; + + this.getID = function runTest_getID() + { + return 'child DOM node is removed before the layout notifies the a11y about parent removal/show'; + }; + } + + function runShadowTest() + { + // children change will recreate the table + this.eventSeq = [ + new invokerChecker(EVENT_REORDER, 'c2') + ]; + + this.invoke = function runShadowTest_invoke() { + var tree = { + SECTION: [ // c2 + { TEXT_LEAF: [] }, // Some text + { TEXT_CONTAINER: [ + { TEXT_LEAF: [] } // something with .. + ] }, + { TEXT_LEAF: [] } // More text + ] + }; + testAccessibleTree('c2', tree); + + gShadowRoot.firstElementChild.querySelector('span').remove(); + }; + + this.finalCheck = function runShadowTest_finalCheck() { + var tree = { + SECTION: [ // c2 + { TEXT_LEAF: [] }, // Some text + { TEXT_LEAF: [] } // More text + ] + }; + testAccessibleTree('c2', tree); + }; + + this.getID = function runShadowTest_getID() { + return 'child DOM node is removed before the layout notifies the a11y about parent removal/show in shadow DOM'; + }; + } + + //enableLogging("tree"); + //gA11yEventDumpToConsole = true; + + var gQueue = null; + function doTest() + { + gQueue = new eventQueue(); + gQueue.push(new runTest()); + gQueue.push(new runShadowTest()); + gQueue.invoke(); // will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> + +<body> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="c1"> + <div id="c1_t" style="display: table" role="presentation"> + Some text + <span style="display: table-cell">something with accessibles goes here</span> + More text + </div> + </div> + + <template id="tmpl"> + <div style="display: table" role="presentation"> + Some text + <span style="display: table-cell">something with accessibles goes here</span> + More text + </div> + </template> + + <div id="c2"><div id="c2_c" role="presentation"></div></div> + + <script> + var gShadowRoot = document.getElementById('c2_c').createShadowRoot(); + var tmpl = document.getElementById('tmpl'); + gShadowRoot.appendChild(document.importNode(tmpl.content, true)); + </script> +</body> +</html>
--- a/addon-sdk/source/lib/sdk/event/chrome.js +++ b/addon-sdk/source/lib/sdk/event/chrome.js @@ -52,14 +52,14 @@ function observe(topic) { // observerChannel (since third argument is `true`). There for if it // will be GC-ed with all it's event listeners once no other references // will be held. addObserver(observerChannel, topic, true); // We need to remove any observer added once the add-on is unloaded; // otherwise we'll get a "dead object" exception. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1001833 - unload(() => removeObserver(observerChannel, topic)); + unload(() => removeObserver(observerChannel, topic), { weak: true }); return observerChannel; } exports.observe = observe;
--- a/addon-sdk/source/lib/sdk/system/unload.js +++ b/addon-sdk/source/lib/sdk/system/unload.js @@ -5,26 +5,43 @@ // Parts of this module were taken from narwhal: // // http://narwhaljs.org module.metadata = { "stability": "experimental" }; +const { Cu } = require('chrome'); const { on, off } = require('./events'); const unloadSubject = require('@loader/unload'); const observers = []; const unloaders = []; -var when = exports.when = function when(observer) { - if (observers.indexOf(observer) != -1) - return; - observers.unshift(observer); +function WeakObserver(inner) { + this._inner = Cu.getWeakReference(inner); +} + +Object.defineProperty(WeakObserver.prototype, 'value', { + get: function() { this._inner.get() } +}); + +var when = exports.when = function when(observer, opts) { + opts = opts || {}; + for (var i = 0; i < observers.length; ++i) { + if (observers[i] === observer || observers[i].value === observer) { + return; + } + } + if (opts.weak) { + observers.unshift(new WeakObserver(observer)); + } else { + observers.unshift(observer); + } }; var ensure = exports.ensure = function ensure(obj, destructorName) { if (!destructorName) destructorName = "unload"; if (!(destructorName in obj)) throw new Error("object has no '" + destructorName + "' property"); @@ -50,17 +67,22 @@ var ensure = exports.ensure = function e unloaders.push(unloadWrapper); obj[destructorName] = unloadWrapper; }; function unload(reason) { observers.forEach(function(observer) { try { - observer(reason); + if (observer instanceof WeakObserver) { + observer = observer.value; + } + if (typeof observer === 'function') { + observer(reason); + } } catch (error) { console.exception(error); } }); } when(function(reason) {
--- a/addon-sdk/source/test/leak/jetpack-package.ini +++ b/addon-sdk/source/test/leak/jetpack-package.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = leak-utils.js [test-leak-window-events.js] [test-leak-event-dom-closed-window.js] +[test-leak-event-chrome.js]
--- a/addon-sdk/source/test/leak/leak-utils.js +++ b/addon-sdk/source/test/leak/leak-utils.js @@ -26,16 +26,17 @@ function gc() { resolve(); } } } Cu.schedulePreciseGC(genGCCallback()); }); } +exports.gc = gc; // Execute the given test function and verify that we did not leak windows // in the process. The test function must return a promise or be a generator. // If the promise is resolved, or generator completes, with an sdk loader // object then it will be unloaded after the memory measurements. exports.asyncWindowLeakTest = function*(assert, asyncTestFunc) { // SelfSupportBackend periodically tries to open windows. This can
new file mode 100644 --- /dev/null +++ b/addon-sdk/source/test/leak/test-leak-event-chrome.js @@ -0,0 +1,41 @@ +/* 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 { gc } = require("./leak-utils"); +const { Loader } = require("sdk/test/loader"); +const { Cu } = require("chrome"); +const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); + +exports["test sdk/event/chrome does not leak when not referenced"] = function*(assert) { + let loader = Loader(module); + let { observe } = loader.require("sdk/event/chrome"); + let { on } = loader.require("sdk/event/core"); + + let gotFooEvent = false; + on(observe("test-foo"), "data", function(evt) { + gotFooEvent = true; + }); + + let bar = observe("test-bar"); + let barPromise = new Promise(resolve => { + on(bar, "data", function(evt) { + assert.ok(!gotFooEvent, "should not have gotten test-foo event"); + resolve(); + }); + }); + + // This should clear the test-foo observer channel because we are not + // holding a reference to it above. + yield gc(); + + Services.obs.notifyObservers(null, "test-foo", null); + Services.obs.notifyObservers(null, "test-bar", null); + + yield barPromise; + + loader.unload(); +} + +require("sdk/test").run(exports);
--- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -51,16 +51,21 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ '/security/sandbox/chromium', '/security/sandbox/chromium-shim', ] USE_LIBS += [ 'sandbox_s', ] + DELAYLOAD_DLLS += [ + 'winmm.dll', + 'user32.dll', + ] + # Control the default heap size. # This is the heap returned by GetProcessHeap(). # As we use the CRT heap, the default size is too large and wastes VM. # # The default heap size is 1MB on Win32. # The heap will grow if need be. # # Set it to 256k. See bug 127069.
--- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -317,16 +317,30 @@ sizeof(XPCOM_DLL) - 1)) #endif } return rv; } int main(int argc, char* argv[], char* envp[]) { + mozilla::TimeStamp start = mozilla::TimeStamp::Now(); + +#ifdef HAS_DLL_BLOCKLIST + DllBlocklist_Initialize(); + +#ifdef DEBUG + // In order to be effective against AppInit DLLs, the blocklist must be + // initialized before user32.dll is loaded into the process (bug 932100). + if (GetModuleHandleA("user32.dll")) { + fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n"); + } +#endif +#endif + #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC // We are launching as a content process, delegate to the appropriate // main if (argc > 1 && IsArg(argv[1], "contentproc")) { #if defined(XP_WIN) && defined(MOZ_SANDBOX) // We need to initialize the sandbox TargetServices before InitXPCOMGlue // because we might need the sandbox broker to give access to some files. if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) { @@ -344,32 +358,19 @@ int main(int argc, char* argv[], char* e // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. NS_LogTerm(); return result; } #endif - mozilla::TimeStamp start = mozilla::TimeStamp::Now(); nsIFile *xreDirectory; -#ifdef HAS_DLL_BLOCKLIST - DllBlocklist_Initialize(); - -#ifdef DEBUG - // In order to be effective against AppInit DLLs, the blocklist must be - // initialized before user32.dll is loaded into the process (bug 932100). - if (GetModuleHandleA("user32.dll")) { - fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n"); - } -#endif -#endif - nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory); if (NS_FAILED(rv)) { return 255; } XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -940,17 +940,17 @@ pref("dom.ipc.plugins.sandbox-level.flas // This controls the strength of the Windows content process sandbox for testing // purposes. This will require a restart. // On windows these levels are: // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp // SetSecurityLevelForContentProcess() for what the different settings mean. #if defined(NIGHTLY_BUILD) pref("security.sandbox.content.level", 2); #else -pref("security.sandbox.content.level", 0); +pref("security.sandbox.content.level", 1); #endif #if defined(MOZ_STACKWALKING) // This controls the depth of stack trace that is logged when Windows sandbox // logging is turned on. This is only currently available for the content // process because the only other sandbox (for GMP) has too strict a policy to // allow stack tracing. This does not require a restart to take effect. pref("security.sandbox.windows.log.stackTraceDepth", 0);
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -6119,28 +6119,44 @@ // the tabbar (half a tab) let endScreenY = bo.screenY + 1.5 * bo.height; if (eY < endScreenY && eY > window.screenY) return; } // screen.availLeft et. al. only check the screen that this window is on, // but we want to look at the screen the tab is being dropped onto. - var sX = {}, sY = {}, sWidth = {}, sHeight = {}; - Cc["@mozilla.org/gfx/screenmanager;1"] - .getService(Ci.nsIScreenManager) - .screenForRect(eX, eY, 1, 1) - .GetAvailRect(sX, sY, sWidth, sHeight); + var screen = Cc["@mozilla.org/gfx/screenmanager;1"] + .getService(Ci.nsIScreenManager) + .screenForRect(eX, eY, 1, 1); + var fullX = {}, fullY = {}, fullWidth = {}, fullHeight = {}; + var availX = {}, availY = {}, availWidth = {}, availHeight = {}; + // get full screen rect and available rect, both in desktop pix + screen.GetRectDisplayPix(fullX, fullY, fullWidth, fullHeight); + screen.GetAvailRectDisplayPix(availX, availY, availWidth, availHeight); + + // scale factor to convert desktop pixels to CSS px + var scaleFactor = + screen.contentsScaleFactor / screen.defaultCSSScaleFactor; + // synchronize CSS-px top-left coordinates with the screen's desktop-px + // coordinates, to ensure uniqueness across multiple screens + // (compare the equivalent adjustments in nsGlobalWindow::GetScreenXY() + // and related methods) + availX.value = (availX.value - fullX.value) * scaleFactor + fullX.value; + availY.value = (availY.value - fullY.value) * scaleFactor + fullY.value; + availWidth.value *= scaleFactor; + availHeight.value *= scaleFactor; + // ensure new window entirely within screen - var winWidth = Math.min(window.outerWidth, sWidth.value); - var winHeight = Math.min(window.outerHeight, sHeight.value); - var left = Math.min(Math.max(eX - draggedTab._dragData.offsetX, sX.value), - sX.value + sWidth.value - winWidth); - var top = Math.min(Math.max(eY - draggedTab._dragData.offsetY, sY.value), - sY.value + sHeight.value - winHeight); + var winWidth = Math.min(window.outerWidth, availWidth.value); + var winHeight = Math.min(window.outerHeight, availHeight.value); + var left = Math.min(Math.max(eX - draggedTab._dragData.offsetX, availX.value), + availX.value + availWidth.value - winWidth); + var top = Math.min(Math.max(eY - draggedTab._dragData.offsetY, availY.value), + availY.value + availHeight.value - winHeight); delete draggedTab._dragData; if (this.tabbrowser.tabs.length == 1) { // resize _before_ move to ensure the window fits the new screen. if // the window is too large for its screen, the window manager may do // automatic repositioning. window.resizeTo(winWidth, winHeight);
--- a/browser/components/contextualidentity/test/browser/browser_forgetaboutsite.js +++ b/browser/components/contextualidentity/test/browser/browser_forgetaboutsite.js @@ -238,25 +238,25 @@ function* test_storage_cleared() { for (let userContextId of Object.keys(USER_CONTEXTS)) { // Load the page in 3 different contexts and set the local storage // which should only be visible in that context. let value = USER_CONTEXTS[userContextId]; // Open our tab in the given user context. let tabInfo = yield* openTabInUserContext(TEST_URL+ "file_set_storages.html?" + value, userContextId); - // Check that the local storage has been set correctly. - let win = tabInfo.browser.contentWindow; - Assert.equal(win.localStorage.getItem("userContext"), USER_CONTEXTS[userContextId], "Check the local storage value"); + // Check that the storages has been set correctly. + yield ContentTask.spawn(tabInfo.browser, { userContext: USER_CONTEXTS[userContextId] }, function* (arg) { + // Check that the local storage has been set correctly. + Assert.equal(content.localStorage.getItem("userContext"), arg.userContext, "Check the local storage value"); - // Check that the session storage has been set correctly. - Assert.equal(win.sessionStorage.getItem("userContext"), USER_CONTEXTS[userContextId], "Check the session storage value"); + // Check that the session storage has been set correctly. + Assert.equal(content.sessionStorage.getItem("userContext"), arg.userContext, "Check the session storage value"); - // Check that the indexedDB has been set correctly. - yield ContentTask.spawn(tabInfo.browser, { userContext: USER_CONTEXTS[userContextId] }, function* (arg) { + // Check that the indexedDB has been set correctly. let request = content.indexedDB.open("idb", 1); let db = yield new Promise(done => { request.onsuccess = event => { done(event.target.result); }; }); @@ -280,26 +280,26 @@ function* test_storage_cleared() { // Forget the site. ForgetAboutSite.removeDataFromDomain(TEST_HOST); // Open the tab again without setting the localStorage and check that the // local storage has been cleared or not. for (let userContextId of Object.keys(USER_CONTEXTS)) { // Open our tab in the given user context without setting local storage. let tabInfo = yield* openTabInUserContext(TEST_URL+ "file_set_storages.html", userContextId); - let win = tabInfo.browser.contentWindow; - - // Check that does the local storage be cleared or not. - Assert.ok(!win.localStorage.getItem("userContext"), "The local storage has been cleared"); - // Check that does the session storage be cleared or not. - Assert.ok(!win.sessionStorage.getItem("userContext"), "The session storage has been cleared"); + // Check that do storages be cleared or not. + yield ContentTask.spawn(tabInfo.browser, null, function* () { + // Check that does the local storage be cleared or not. + Assert.ok(!content.localStorage.getItem("userContext"), "The local storage has been cleared"); - // Check that does the indexedDB be cleared or not. - yield ContentTask.spawn(tabInfo.browser, null, function* () { + // Check that does the session storage be cleared or not. + Assert.ok(!content.sessionStorage.getItem("userContext"), "The session storage has been cleared"); + + // Check that does the indexedDB be cleared or not. let request = content.indexedDB.open("idb", 1); let db = yield new Promise(done => { request.onsuccess = event => { done(event.target.result); }; }); try {
--- a/browser/components/shell/nsGNOMEShellService.cpp +++ b/browser/components/shell/nsGNOMEShellService.cpp @@ -279,17 +279,17 @@ nsGNOMEShellService::SetDefaultBrowser(b do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStringBundle> brandBundle; rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle)); NS_ENSURE_SUCCESS(rv, rv); nsString brandShortName; - brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandShortName)); // use brandShortName as the application id. NS_ConvertUTF16toUTF8 id(brandShortName); nsCOMPtr<nsIGIOMimeApp> appInfo; rv = giovfs->CreateAppFromCommand(mAppPath, id, getter_AddRefs(appInfo)); @@ -397,17 +397,17 @@ nsGNOMEShellService::SetDesktopBackgroun nsString brandName; nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID; nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(bundleCID)); if (bundleService) { nsCOMPtr<nsIStringBundle> brandBundle; rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle)); if (NS_SUCCEEDED(rv) && brandBundle) { - rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + rv = brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandName)); NS_ENSURE_SUCCESS(rv, rv); } } // build the file name filePath.Append('/'); filePath.Append(NS_ConvertUTF16toUTF8(brandName));
--- a/browser/components/shell/nsWindowsShellService.cpp +++ b/browser/components/shell/nsWindowsShellService.cpp @@ -989,17 +989,17 @@ nsWindowsShellService::SetDesktopBackgro nsCOMPtr<nsIStringBundle> shellBundle; rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES, getter_AddRefs(shellBundle)); NS_ENSURE_SUCCESS(rv, rv); // e.g. "Desktop Background.bmp" nsString fileLeafName; rv = shellBundle->GetStringFromName - (MOZ_UTF16("desktopBackgroundLeafNameWin"), + (u"desktopBackgroundLeafNameWin", getter_Copies(fileLeafName)); NS_ENSURE_SUCCESS(rv, rv); // get the profile root directory nsCOMPtr<nsIFile> file; rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR, getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv);
--- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -116,16 +116,19 @@ LPROJ_ROOT := $(subst -,_,$(AB_CD)) endif endif DEFINES += -DLPROJ_ROOT=$(LPROJ_ROOT) DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION) ifdef MOZ_SYSTEM_ICU DEFINES += -DMOZ_SYSTEM_ICU endif +ifdef MOZ_ICU_DATA_ARCHIVE +DEFINES += -DMOZ_ICU_DATA_ARCHIVE +endif DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX) DEFINES += -DICU_DATA_FILE=$(ICU_DATA_FILE) ifdef CLANG_CXX DEFINES += -DCLANG_CXX endif ifdef CLANG_CL DEFINES += -DCLANG_CL endif
--- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -96,17 +96,17 @@ @BINPATH@/@MSVC_C_RUNTIME_DLL@ @BINPATH@/@MSVC_CXX_RUNTIME_DLL@ #endif #if MOZ_PACKAGE_WIN_UCRT_DLLS @BINPATH@/api-ms-win-*.dll @BINPATH@/ucrtbase.dll #endif #endif -#ifndef MOZ_SYSTEM_ICU +#ifdef MOZ_ICU_DATA_ARCHIVE @RESPATH@/@ICU_DATA_FILE@ #endif #ifdef MOZ_GTK3 @BINPATH@/@DLL_PREFIX@mozgtk@DLL_SUFFIX@ @BINPATH@/gtk2/@DLL_PREFIX@mozgtk@DLL_SUFFIX@ #endif [browser]
--- a/build/autoconf/icu.m4 +++ b/build/autoconf/icu.m4 @@ -77,17 +77,20 @@ if test -n "$USE_ICU"; then # TODO: the l is actually endian-dependent # We could make this set as 'l' or 'b' for little or big, respectively, # but we'd need to check in a big-endian version of the file. ICU_DATA_FILE="icudt${version}l.dat" dnl We won't build ICU data as a separate file when building dnl JS standalone so that embedders don't have to deal with it. - if test -z "$JS_STANDALONE" -a -z "$MOZ_SYSTEM_ICU"; then + dnl We also don't do it on Windows because sometimes the file goes + dnl missing -- possibly due to overzealous antivirus software? -- + dnl which prevents the browser from starting up :( + if test -z "$JS_STANDALONE" -a -z "$MOZ_SYSTEM_ICU" -a "$OS_TARGET" != WINNT; then MOZ_ICU_DATA_ARCHIVE=1 else MOZ_ICU_DATA_ARCHIVE= fi fi AC_SUBST(MOZ_ICU_VERSION) AC_SUBST(ENABLE_INTL_API)
--- a/build/autoconf/sanitize.m4 +++ b/build/autoconf/sanitize.m4 @@ -18,18 +18,18 @@ if test -n "$MOZ_ASAN"; then MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll # We use MOZ_PATH_PROG in order to get a Windows style path. MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB) if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB. It should be available in the same location as clang-cl.]) fi AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH) fi - CFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC $CFLAGS" - CXXFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC $CXXFLAGS" + CFLAGS="-fsanitize=address $CFLAGS" + CXXFLAGS="-fsanitize=address $CXXFLAGS" LDFLAGS="-fsanitize=address $LDFLAGS" AC_DEFINE(MOZ_ASAN) MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) fi AC_SUBST(MOZ_ASAN) dnl ======================================================== dnl = Use Memory Sanitizer
--- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -208,21 +208,17 @@ def get_compiler_info(compiler, language ''' # Note: MSVC doesn't expose __STDC_VERSION__. It does expose __STDC__, # but only when given the -Za option, which disables compiler # extensions. # Note: We'd normally do a version check for clang, but versions of clang # in Xcode have a completely different versioning scheme despite exposing # the version with the same defines. # So instead, we make things such that the version is missing when the - # clang used is below the minimum supported version (currently clang 3.4). - # Normally, we'd use __has_feature, but there are unfortunately no C++11 - # differences in clang 3.4. However, it supports the 2013-08-28 draft of - # the ISO WG21 SG10 feature test macro recommendations, and thus exposes - # new __cpp_* macros that older clang versions didn't. + # clang used is below the minimum supported version (currently clang 3.6). # We then only include the version information when the C++ compiler # matches the feature check, so that an unsupported version of clang would # have no version number. check = dedent('''\ #if defined(_MSC_VER) #if defined(__clang__) %COMPILER clang-cl %VERSION _MSC_FULL_VER @@ -533,17 +529,17 @@ def compiler(language, host_or_target, c raise FatalCheckError( 'Only GCC 4.8 or newer is supported (found version %s).' % info.version) # If you want to bump the version check here search for # __cpp_static_assert above, and see the associated comment. if info.type == 'clang' and not info.version: raise FatalCheckError( - 'Only clang/llvm 3.4 or newer is supported.') + 'Only clang/llvm 3.6 or newer is supported.') if info.type == 'msvc': if info.version < '19.00.23918': raise FatalCheckError( 'This version (%s) of the MSVC compiler is not ' 'supported.\n' 'You must install Visual C++ 2015 Update 2 or newer in ' 'order to build.\n'
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1009,17 +1009,17 @@ nsScriptSecurityManager::CheckLoadURIFla nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS, &hasSubsumersFlag); NS_ENSURE_SUCCESS(rv, rv); if (!hasFlags && !hasSubsumersFlag) { nsXPIDLString message; NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme); const char16_t* formatStrings[] = { ucsTargetScheme.get() }; rv = sStrBundle-> - FormatStringFromName(MOZ_UTF16("ProtocolFlagError"), + FormatStringFromName(u"ProtocolFlagError", formatStrings, ArrayLength(formatStrings), getter_Copies(message)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIConsoleService> console( do_GetService("@mozilla.org/consoleservice;1")); NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
--- a/devtools/server/actors/script.js +++ b/devtools/server/actors/script.js @@ -14,17 +14,16 @@ const { EnvironmentActor } = require("de const { FrameActor } = require("devtools/server/actors/frame"); const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object"); const { SourceActor, getSourceURL } = require("devtools/server/actors/source"); const { DebuggerServer } = require("devtools/server/main"); const { ActorClassWithSpec } = require("devtools/shared/protocol"); const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const { assert, dumpn, update, fetch } = DevToolsUtils; const promise = require("promise"); -const PromiseDebugging = require("PromiseDebugging"); const xpcInspector = require("xpcInspector"); const { DevToolsWorker } = require("devtools/shared/worker/worker"); const object = require("sdk/util/object"); const { threadSpec } = require("devtools/shared/specs/script"); const { defer, resolve, reject, all } = promise; loader.lazyGetter(this, "Debugger", () => {
--- a/devtools/shared/heapsnapshot/DeserializedNode.cpp +++ b/devtools/shared/heapsnapshot/DeserializedNode.cpp @@ -54,17 +54,17 @@ DeserializedStackFrame::getParentStackFr } // namespace mozilla namespace JS { namespace ubi { using mozilla::devtools::DeserializedEdge; const char16_t Concrete<DeserializedNode>::concreteTypeName[] = - MOZ_UTF16("mozilla::devtools::DeserializedNode"); + u"mozilla::devtools::DeserializedNode"; const char16_t* Concrete<DeserializedNode>::typeName() const { return get().typeName; } Node::Size
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -730,17 +730,17 @@ PopulateCompartmentsWithGlobals(Compartm // Add the given set of globals as explicit roots in the given roots // list. Returns false on OOM failure. static bool AddGlobalsAsRoots(AutoObjectVector& globals, ubi::RootList& roots) { unsigned length = globals.length(); for (unsigned i = 0; i < length; i++) { if (!roots.addRoot(ubi::Node(globals[i].get()), - MOZ_UTF16("heap snapshot global"))) + u"heap snapshot global")) { return false; } } return true; } // Choose roots and limits for a traversal, given `boundaries`. Set `roots` to
--- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp @@ -32,17 +32,17 @@ struct MockDeserializedNode : public Des size_t fakeMallocSizeOf(const void*) { EXPECT_TRUE(false); MOZ_ASSERT_UNREACHABLE("fakeMallocSizeOf should never be called because " "DeserializedNodes report the deserialized size."); return 0; } DEF_TEST(DeserializedNodeUbiNodes, { - const char16_t* typeName = MOZ_UTF16("TestTypeName"); + const char16_t* typeName = u"TestTypeName"; const char* className = "MyObjectClassName"; const char* filename = "my-cool-filename.js"; NodeId id = uint64_t(1) << 33; uint64_t size = uint64_t(1) << 60; MockDeserializedNode mocked(id, typeName, size); mocked.coarseType = JS::ubi::CoarseType::Script; mocked.jsObjectClassName = className;
--- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp @@ -19,18 +19,18 @@ struct MockDeserializedStackFrame : publ { MockDeserializedStackFrame() : DeserializedStackFrame() { } }; DEF_TEST(DeserializedStackFrameUbiStackFrames, { StackFrameId id = uint64_t(1) << 42; uint32_t line = 1337; uint32_t column = 9; // 3 space tabs!? - const char16_t* source = MOZ_UTF16("my-javascript-file.js"); - const char16_t* functionDisplayName = MOZ_UTF16("myFunctionName"); + const char16_t* source = u"my-javascript-file.js"; + const char16_t* functionDisplayName = u"myFunctionName"; MockDeserializedStackFrame mocked; mocked.id = id; mocked.line = line; mocked.column = column; mocked.source = source; mocked.functionDisplayName = functionDisplayName;
--- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h +++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h @@ -180,17 +180,17 @@ protected: public: static const char16_t concreteTypeName[]; static void construct(void* storage, FakeNode* ptr) { new (storage) Concrete(ptr); } }; -const char16_t Concrete<FakeNode>::concreteTypeName[] = MOZ_UTF16("FakeNode"); +const char16_t Concrete<FakeNode>::concreteTypeName[] = u"FakeNode"; } // namespace ubi } // namespace JS void AddEdge(FakeNode& node, FakeNode& referent, const char16_t* edgeName = nullptr) { char16_t* ownedEdgeName = nullptr; if (edgeName) { ownedEdgeName = NS_strdup(edgeName);
--- a/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp @@ -11,18 +11,18 @@ using testing::Field; using testing::IsNull; using testing::Property; using testing::Return; DEF_TEST(SerializesEdgeNames, { FakeNode node; FakeNode referent; - const char16_t edgeName[] = MOZ_UTF16("edge name"); - const char16_t emptyStr[] = MOZ_UTF16(""); + const char16_t edgeName[] = u"edge name"; + const char16_t emptyStr[] = u""; AddEdge(node, referent, edgeName); AddEdge(node, referent, emptyStr); AddEdge(node, referent, nullptr); ::testing::NiceMock<MockWriter> writer; // Should get the node with edges once.
--- a/devtools/shared/heapsnapshot/tests/gtest/SerializesTypeNames.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/SerializesTypeNames.cpp @@ -10,17 +10,17 @@ using testing::Property; using testing::Return; DEF_TEST(SerializesTypeNames, { FakeNode node; ::testing::NiceMock<MockWriter> writer; EXPECT_CALL(writer, writeNode(Property(&JS::ubi::Node::typeName, - UTF16StrEq(MOZ_UTF16("FakeNode"))), + UTF16StrEq(u"FakeNode")), _)) .Times(1) .WillOnce(Return(true)); JS::AutoCheckCannotGC noGC(rt); ASSERT_TRUE(WriteHeapGraph(cx, JS::ubi::Node(&node), writer,
--- a/devtools/shared/worker/loader.js +++ b/devtools/shared/worker/loader.js @@ -312,22 +312,16 @@ function WorkerDebuggerLoader(options) { } this.WorkerDebuggerLoader = WorkerDebuggerLoader; // The following APIs rely on the use of Components, and the worker debugger // does not provide alternative definitions for them. Consequently, they are // stubbed out both on the main thread and worker threads. -var PromiseDebugging = { - getState: function () { - throw new Error("PromiseDebugging is not available in workers!"); - } -}; - var chrome = { CC: undefined, Cc: undefined, ChromeWorker: undefined, Cm: undefined, Ci: undefined, Cu: undefined, Cr: undefined, @@ -491,17 +485,16 @@ this.worker = new WorkerDebuggerLoader({ "reportError": reportError, "rpc": rpc, "setImmediate": setImmediate, "URL": URL, }, loadSubScript: loadSubScript, modules: { "Debugger": Debugger, - "PromiseDebugging": PromiseDebugging, "Services": Object.create(null), "chrome": chrome, "xpcInspector": xpcInspector }, paths: { // âš DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING âš "": "resource://gre/modules/commonjs/", // âš DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING âš
--- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -443,17 +443,17 @@ nsDSURIContentListener::CheckFrameOption while (tokenizer.hasMoreTokens()) { const nsSubstring& tok = tokenizer.nextToken(); if (!CheckOneFrameOptionsPolicy(httpChannel, tok)) { // cancel the load and display about:blank httpChannel->Cancel(NS_BINDING_ABORTED); if (mDocShell) { nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell)); if (webNav) { - webNav->LoadURI(MOZ_UTF16("about:blank"), + webNav->LoadURI(u"about:blank", 0, nullptr, nullptr, nullptr); } } return false; } } return true;
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -5068,17 +5068,17 @@ nsDocShell::DisplayLoadError(nsresult aE nsCOMPtr<Element> element = do_QueryInterface(handler); element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr); } // DisplayLoadError requires a non-empty messageStr to proceed and call // LoadErrorPage. If the page doesn't have a title, we will use a blank // space which will be trimmed and thus treated as empty by the front-end. if (messageStr.IsEmpty()) { - messageStr.AssignLiteral(MOZ_UTF16(" ")); + messageStr.AssignLiteral(u" "); } } else { // Errors requiring simple formatting switch (aError) { case NS_ERROR_MALFORMED_URI: // URI is malformed error.AssignLiteral("malformedURI"); break; @@ -7683,17 +7683,17 @@ nsDocShell::EndPageLoad(nsIWebProgress* DisplayLoadError(aStatus, url, nullptr, aChannel); return NS_OK; } else if (aStatus == NS_ERROR_INVALID_SIGNATURE) { // NS_ERROR_INVALID_SIGNATURE indicates a content-signature error. // This currently only happens in case a remote about page fails. // We have to load a fallback in this case. // XXX: We always load about blank here, firefox has to overwrite this if // it wants to display something else. - return LoadURI(MOZ_UTF16("about:blank"), // URI string + return LoadURI(u"about:blank", // URI string nsIChannel::LOAD_NORMAL, // Load flags nullptr, // Referring URI nullptr, // Post data stream nullptr); // Headers stream } // Handle iframe document not loading error because source was // a tracking URL. We make a note of this iframe node by including @@ -13006,38 +13006,38 @@ nsDocShell::ConfirmRepost(bool* aRepost) rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle)); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(prompter && brandBundle && appBundle, "Unable to set up repost prompter."); nsXPIDLString brandName; - rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + rv = brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandName)); nsXPIDLString msgString, button0Title; if (NS_FAILED(rv)) { // No brand, use the generic version. - rv = appBundle->GetStringFromName(MOZ_UTF16("confirmRepostPrompt"), + rv = appBundle->GetStringFromName(u"confirmRepostPrompt", getter_Copies(msgString)); } else { // Brand available - if the app has an override file with formatting, the // app name will be included. Without an override, the prompt will look // like the generic version. const char16_t* formatStrings[] = { brandName.get() }; - rv = appBundle->FormatStringFromName(MOZ_UTF16("confirmRepostPrompt"), + rv = appBundle->FormatStringFromName(u"confirmRepostPrompt", formatStrings, ArrayLength(formatStrings), getter_Copies(msgString)); } if (NS_FAILED(rv)) { return rv; } - rv = appBundle->GetStringFromName(MOZ_UTF16("resendButton.label"), + rv = appBundle->GetStringFromName(u"resendButton.label", getter_Copies(button0Title)); if (NS_FAILED(rv)) { return rv; } int32_t buttonPressed; // The actual value here is irrelevant, but we can't pass an invalid // bool through XPConnect.
--- a/docshell/test/browser/browser_timelineMarkers-frame-04.js +++ b/docshell/test/browser/browser_timelineMarkers-frame-04.js @@ -45,17 +45,21 @@ if (Services.prefs.getBoolPref("javascri markers = markers.filter(m => (m.name == "Javascript" && m.causeName == "promise callback")); ok(markers.length > 0, "Found a Javascript marker"); let frame = markers[0].stack; ok(frame.asyncParent !== null, "Parent frame has async parent"); is(frame.asyncParent.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.asyncParent.functionDisplayName, "do_promise", + let asyncFrame = frame.asyncParent; + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') + asyncFrame = asyncFrame.parent; + is(asyncFrame.functionDisplayName, "do_promise", "Async parent has correct function name"); } }, { desc: "Async stack trace on Javascript marker with script", searchFor: (markers) => { return markers.some(m => (m.name == "Javascript" && m.causeName == "promise callback")); }, @@ -66,15 +70,19 @@ if (Services.prefs.getBoolPref("javascri markers = markers.filter(m => (m.name == "Javascript" && m.causeName == "promise callback")); ok(markers.length > 0, "Found a Javascript marker"); let frame = markers[0].stack; ok(frame.asyncParent !== null, "Parent frame has async parent"); is(frame.asyncParent.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.asyncParent.functionDisplayName, "do_promise_script", + let asyncFrame = frame.asyncParent; + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') + asyncFrame = asyncFrame.parent; + is(asyncFrame.functionDisplayName, "do_promise_script", "Async parent has correct function name"); } }); } timelineContentTest(TESTS);
--- a/docshell/test/browser/browser_timelineMarkers-frame-05.js +++ b/docshell/test/browser/browser_timelineMarkers-frame-05.js @@ -86,20 +86,32 @@ if (Services.prefs.getBoolPref("javascri searchFor: "ConsoleTime", setup: function(docShell) { let resolver = makePromise(); resolvePromise(resolver); }, check: function(markers) { markers = markers.filter(m => m.name == "ConsoleTime"); ok(markers.length > 0, "Promise marker includes stack"); - + ok(markers[0].stack.functionDisplayName == "testConsoleTime", + "testConsoleTime is on the stack"); let frame = markers[0].endStack; - ok(frame.parent.asyncParent !== null, "Parent frame has async parent"); - is(frame.parent.asyncParent.asyncCause, "promise callback", + ok(frame.functionDisplayName == "testConsoleTimeEnd", + "testConsoleTimeEnd is on the stack"); + + frame = frame.parent; + ok(frame.functionDisplayName == "makePromise/<", + "makePromise/< is on the stack"); + let asyncFrame = frame.asyncParent; + ok(asyncFrame !== null, "Frame has async parent"); + is(asyncFrame.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.parent.asyncParent.functionDisplayName, "makePromise", + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') { + asyncFrame = asyncFrame.parent; + } + is(asyncFrame.functionDisplayName, "makePromise", "Async parent has correct function name"); } }); } timelineContentTest(TESTS);
--- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -75,18 +75,18 @@ public: AudioChannelService::GetAudioChannelString(mAudioChannel, name); nsAutoCString topic; topic.Assign("audiochannel-activity-"); topic.Append(NS_ConvertUTF16toUTF8(name)); observerService->NotifyObservers(wrapper, topic.get(), mActive - ? MOZ_UTF16("active") - : MOZ_UTF16("inactive")); + ? u"active" + : u"inactive"); MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, ("NotifyChannelActiveRunnable, type = %d, active = %d\n", mAudioChannel, mActive)); return NS_OK; }
--- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -983,17 +983,17 @@ public: * namespace ID must not be kNameSpaceID_Unknown and the name must not be * null. Note that this can only return info on attributes that actually * live on this element (and is only virtual to handle XUL prototypes). That * is, this should only be called from methods that only care about attrs * that effectively live in mAttrsAndChildren. */ virtual nsAttrInfo GetAttrInfo(int32_t aNamespaceID, nsIAtom* aName) const; - virtual void NodeInfoChanged(mozilla::dom::NodeInfo* aOldNodeInfo) + virtual void NodeInfoChanged() { } /** * Parse a string into an nsAttrValue for a CORS attribute. This * never fails. The resulting value is an enumerated value whose * GetEnumValue() returns one of the above constants. */
--- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -873,21 +873,21 @@ EventSource::ConsoleError() nsresult rv = mSrc->GetSpec(targetSpec); NS_ENSURE_SUCCESS(rv, rv); NS_ConvertUTF8toUTF16 specUTF16(targetSpec); const char16_t *formatStrings[] = { specUTF16.get() }; if (mReadyState == CONNECTING) { rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties", - MOZ_UTF16("connectionFailure"), + u"connectionFailure", formatStrings, ArrayLength(formatStrings)); } else { rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties", - MOZ_UTF16("netInterrupt"), + u"netInterrupt", formatStrings, ArrayLength(formatStrings)); } NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult
--- a/dom/base/NodeIterator.cpp +++ b/dom/base/NodeIterator.cpp @@ -176,17 +176,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(NodeIterator) NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator) NS_IMETHODIMP NodeIterator::GetRoot(nsIDOMNode * *aRoot) { - NS_ADDREF(*aRoot = Root()->AsDOMNode()); + nsCOMPtr<nsIDOMNode> root = Root()->AsDOMNode(); + root.forget(aRoot); return NS_OK; } NS_IMETHODIMP NodeIterator::GetWhatToShow(uint32_t *aWhatToShow) { *aWhatToShow = WhatToShow(); return NS_OK; }
--- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -545,21 +545,21 @@ WebSocketImpl::ConsoleError() } } NS_ConvertUTF8toUTF16 specUTF16(mURI); const char16_t* formatStrings[] = { specUTF16.get() }; if (mWebSocket->ReadyState() < WebSocket::OPEN) { PrintErrorOnConsole("chrome://global/locale/appstrings.properties", - MOZ_UTF16("connectionFailure"), + u"connectionFailure", formatStrings, ArrayLength(formatStrings)); } else { PrintErrorOnConsole("chrome://global/locale/appstrings.properties", - MOZ_UTF16("netInterrupt"), + u"netInterrupt", formatStrings, ArrayLength(formatStrings)); } /// todo some specific errors - like for message too large return NS_OK; } void WebSocketImpl::FailConnection(uint16_t aReasonCode, @@ -1594,18 +1594,18 @@ WebSocketImpl::Init(JSContext* aCx, // upgrade the request from ws:// to wss:// and mark as secure mURI.ReplaceSubstring("ws://", "wss://"); if (NS_WARN_IF(mURI.Find("wss://") != 0)) { return; } mSecure = true; - const char16_t* params[] = { reportSpec.get(), MOZ_UTF16("wss") }; - CSP_LogLocalizedStr(MOZ_UTF16("upgradeInsecureRequest"), + const char16_t* params[] = { reportSpec.get(), u"wss" }; + CSP_LogLocalizedStr(u"upgradeInsecureRequest", params, ArrayLength(params), EmptyString(), // aSourceFile EmptyString(), // aScriptSample 0, // aLineNumber 0, // aColumnNumber nsIScriptError::warningFlag, "CSP", mInnerWindowID); } @@ -2628,26 +2628,19 @@ public: : MainThreadWorkerRunnable(aWorkerPrivate) , mImpl(aImpl) { } bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); - aWorkerPrivate->ModifyBusyCountFromWorker(true); return !NS_FAILED(mImpl->CancelInternal()); } - void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aRunResult) override - { - aWorkerPrivate->ModifyBusyCountFromWorker(false); - } - private: RefPtr<WebSocketImpl> mImpl; }; } // namespace // Window closed, stop/reload button pressed, user navigated away from page, etc. NS_IMETHODIMP @@ -2777,31 +2770,29 @@ public: , mWebSocketImpl(aImpl) , mEvent(Move(aEvent)) { } bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); - aWorkerPrivate->ModifyBusyCountFromWorker(true); // No messages when disconnected. if (mWebSocketImpl->mDisconnectingOrDisconnected) { NS_WARNING("Dispatching a WebSocket event after the disconnection!"); return true; } return !NS_FAILED(mEvent->Run()); } void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) override { - aWorkerPrivate->ModifyBusyCountFromWorker(false); } bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { // We don't call WorkerRunnable::PreDispatch because it would assert the // wrong thing about which thread we're on. We're on whichever thread the // channel implementation is running on (probably the main thread or socket
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -681,22 +681,22 @@ nsContentUtils::InitializeModifierString nsXPIDLString shiftModifier; nsXPIDLString metaModifier; nsXPIDLString osModifier; nsXPIDLString altModifier; nsXPIDLString controlModifier; nsXPIDLString modifierSeparator; if (bundle) { //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n - bundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"), getter_Copies(shiftModifier)); - bundle->GetStringFromName(MOZ_UTF16("VK_META"), getter_Copies(metaModifier)); - bundle->GetStringFromName(MOZ_UTF16("VK_WIN"), getter_Copies(osModifier)); - bundle->GetStringFromName(MOZ_UTF16("VK_ALT"), getter_Copies(altModifier)); - bundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"), getter_Copies(controlModifier)); - bundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"), getter_Copies(modifierSeparator)); + bundle->GetStringFromName(u"VK_SHIFT", getter_Copies(shiftModifier)); + bundle->GetStringFromName(u"VK_META", getter_Copies(metaModifier)); + bundle->GetStringFromName(u"VK_WIN", getter_Copies(osModifier)); + bundle->GetStringFromName(u"VK_ALT", getter_Copies(altModifier)); + bundle->GetStringFromName(u"VK_CONTROL", getter_Copies(controlModifier)); + bundle->GetStringFromName(u"MODIFIER_SEPARATOR", getter_Copies(modifierSeparator)); } //if any of these don't exist, we get an empty string sShiftText = new nsString(shiftModifier); sMetaText = new nsString(metaModifier); sOSText = new nsString(osModifier); sAltText = new nsString(altModifier); sControlText = new nsString(controlModifier); sModifierSeparator = new nsString(modifierSeparator); @@ -5117,17 +5117,17 @@ nsContentUtils::GetWindowProviderForCont already_AddRefed<nsPIDOMWindowOuter> nsContentUtils::GetMostRecentNonPBWindow() { nsCOMPtr<nsIWindowMediator> windowMediator = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); nsCOMPtr<nsIWindowMediator_44> wm = do_QueryInterface(windowMediator); nsCOMPtr<mozIDOMWindowProxy> window; - wm->GetMostRecentNonPBWindow(MOZ_UTF16("navigator:browser"), + wm->GetMostRecentNonPBWindow(u"navigator:browser", getter_AddRefs(window)); nsCOMPtr<nsPIDOMWindowOuter> pwindow; pwindow = do_QueryInterface(window); return pwindow.forget(); } /* static */ @@ -6386,26 +6386,22 @@ nsContentUtils::PlatformToDOMLineBreaks( } } bool nsContentUtils::PlatformToDOMLineBreaks(nsString& aString, const fallible_t& aFallible) { if (aString.FindChar(char16_t('\r')) != -1) { // Windows linebreaks: Map CRLF to LF: - if (!aString.ReplaceSubstring(MOZ_UTF16("\r\n"), - MOZ_UTF16("\n"), - aFallible)) { + if (!aString.ReplaceSubstring(u"\r\n", u"\n", aFallible)) { return false; } // Mac linebreaks: Map any remaining CR to LF: - if (!aString.ReplaceSubstring(MOZ_UTF16("\r"), - MOZ_UTF16("\n"), - aFallible)) { + if (!aString.ReplaceSubstring(u"\r", u"\n", aFallible)) { return false; } } return true; } void
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -3021,17 +3021,17 @@ GetFormattedTimeString(PRTime aTime, nsA char formatedTime[24]; if (snprintf_literal(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d", prtime.tm_month + 1, prtime.tm_mday, int(prtime.tm_year), prtime.tm_hour , prtime.tm_min, prtime.tm_sec)) { CopyASCIItoUTF16(nsDependentCString(formatedTime), aFormattedTimeString); } else { // If we for whatever reason failed to find the last modified time // (or even the current time), fall back to what NS4.x returned. - aFormattedTimeString.AssignLiteral(MOZ_UTF16("01/01/1970 00:00:00")); + aFormattedTimeString.AssignLiteral(u"01/01/1970 00:00:00"); } } void nsIDocument::GetLastModified(nsAString& aLastModified) const { if (!mLastModified.IsEmpty()) { aLastModified.Assign(mLastModified); @@ -9738,26 +9738,26 @@ nsDocument::GetReadyState(nsAString& aRe return NS_OK; } void nsIDocument::GetReadyState(nsAString& aReadyState) const { switch(mReadyState) { case READYSTATE_LOADING : - aReadyState.AssignLiteral(MOZ_UTF16("loading")); + aReadyState.AssignLiteral(u"loading"); break; case READYSTATE_INTERACTIVE : - aReadyState.AssignLiteral(MOZ_UTF16("interactive")); + aReadyState.AssignLiteral(u"interactive"); break; case READYSTATE_COMPLETE : - aReadyState.AssignLiteral(MOZ_UTF16("complete")); + aReadyState.AssignLiteral(u"complete"); break; default: - aReadyState.AssignLiteral(MOZ_UTF16("uninitialized")); + aReadyState.AssignLiteral(u"uninitialized"); } } namespace { struct SuppressArgs { nsIDocument::SuppressionType mWhat;
--- a/dom/base/nsGenericDOMDataNode.h +++ b/dom/base/nsGenericDOMDataNode.h @@ -167,23 +167,23 @@ public: NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override; NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override { - *aResult = CloneDataNode(aNodeInfo, true); + nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true); + result.forget(aResult); + if (!*aResult) { return NS_ERROR_OUT_OF_MEMORY; } - NS_ADDREF(*aResult); - return NS_OK; } nsresult SplitData(uint32_t aOffset, nsIContent** aReturn, bool aCloneAfterOriginal = true); // WebIDL API // Our XPCOM GetData is just fine for WebIDL
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -9480,17 +9480,17 @@ nsGlobalWindow::FindOuter(const nsAStrin if (aString.IsEmpty() || aShowDialog) { // See if the find dialog is already up using nsIWindowMediator nsCOMPtr<nsIWindowMediator> windowMediator = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); nsCOMPtr<mozIDOMWindowProxy> findDialog; if (windowMediator) { - windowMediator->GetMostRecentWindow(MOZ_UTF16("findInPage"), + windowMediator->GetMostRecentWindow(u"findInPage", getter_AddRefs(findDialog)); } if (findDialog) { // The Find dialog is already open, bring it to the top. auto* piFindDialog = nsPIDOMWindowOuter::From(findDialog); aError = piFindDialog->Focus(); } else if (finder) { @@ -11114,17 +11114,17 @@ nsGlobalWindow::ShowSlowScriptDialog() if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart + cutLength])) { // Likewise, don't drop a trailing low surrogate here. We want to // increase cutLength, since it might be 0 already so we can't very well // decrease it. ++cutLength; } // Insert U+2026 HORIZONTAL ELLIPSIS - filenameUTF16.Replace(cutStart, cutLength, NS_LITERAL_STRING("\x2026")); + filenameUTF16.Replace(cutStart, cutLength, NS_LITERAL_STRING(u"\x2026")); } const char16_t *formatParams[] = { filenameUTF16.get() }; rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES, "KillScriptLocation", formatParams, scriptLocation); if (NS_SUCCEEDED(rv) && scriptLocation) { @@ -11532,17 +11532,17 @@ nsGlobalWindow::Observe(nsISupports* aSu event->SetTrusted(true); bool dummy; return DispatchEvent(event, &dummy); } #endif // MOZ_B2G if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { - MOZ_ASSERT(!NS_strcmp(aData, MOZ_UTF16("intl.accept_languages"))); + MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages")); MOZ_ASSERT(IsInnerWindow()); // The user preferred languages have changed, we need to fire an event on // Window object and invalidate the cache for navigator.languages. It is // done for every change which can be a waste of cycles but those should be // fairly rare. // We MUST invalidate navigator.languages before sending the event in the // very likely situation where an event handler will try to read its value.
--- a/dom/base/nsHTMLContentSerializer.cpp +++ b/dom/base/nsHTMLContentSerializer.cpp @@ -149,19 +149,19 @@ nsHTMLContentSerializer::SerializeHTMLAt valueStr = NS_LITERAL_STRING("text/html; charset=") + NS_ConvertASCIItoUTF16(mCharset); } } nsDependentAtomString nameStr(attrName); nsAutoString prefix; if (namespaceID == kNameSpaceID_XML) { - prefix.AssignLiteral(MOZ_UTF16("xml")); + prefix.AssignLiteral(u"xml"); } else if (namespaceID == kNameSpaceID_XLink) { - prefix.AssignLiteral(MOZ_UTF16("xlink")); + prefix.AssignLiteral(u"xlink"); } // Expand shorthand attribute. if (aNamespace == kNameSpaceID_XHTML && namespaceID == kNameSpaceID_None && IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) { valueStr = nameStr;
--- a/dom/base/nsISelectionPrivate.idl +++ b/dom/base/nsISelectionPrivate.idl @@ -10,19 +10,19 @@ interface nsIDOMNode; interface nsISelectionListener; interface nsIContent; interface nsINode; %{C++ class nsIFrame; struct nsPoint; struct ScrollAxis; -template<class T> class nsTArray; #include "nsDirection.h" #include "nsIPresShell.h" // TODO: Remove this include +#include "nsTArrayForwardDeclare.h" #include "mozilla/EventForwards.h" %} [ptr] native nsIFrame(nsIFrame); [ptr] native RangeArray(nsTArray<nsRange*>); [ref] native constTextRangeStyleRef(const mozilla::TextRangeStyle); [ref] native nsPointRef(nsPoint); native nsDirection(nsDirection); @@ -47,17 +47,17 @@ interface nsISelectionPrivate : nsISelec */ [noscript] void endBatchChanges(); DOMString toStringWithFormat(in string formatType, in unsigned long flags, in int32_t wrapColumn); void addSelectionListener(in nsISelectionListener newListener); void removeSelectionListener(in nsISelectionListener listenerToRemove); /* Table selection stuff - We should probably move this and table-related + We should probably move this and table-related items in nsFrameSelection to a new nsITableSelection interface */ const long TABLESELECTION_NONE = 0; const long TABLESELECTION_CELL = 1; const long TABLESELECTION_ROW = 2; const long TABLESELECTION_COLUMN = 3; const long TABLESELECTION_TABLE = 4; @@ -90,17 +90,17 @@ interface nsISelectionPrivate : nsISelec [noscript] void setTextRangeStyle(in nsIDOMRange range, in constTextRangeStyleRef textRangeStyle); /** * Get the direction of the selection. */ [noscript, notxpcom] nsDirection getSelectionDirection(); [noscript, notxpcom] void setSelectionDirection(in nsDirection aDirection); - + /** * Returns the type of the selection (see nsISelectionController for * available constants). */ readonly attribute short type; /** * Return array of ranges intersecting with the given DOM interval.
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1616,18 +1616,18 @@ nsJSContext::EndCycleCollectionCallback( } nsCString gcMsg; if (aResults.mForcedGC) { gcMsg.AssignLiteral(", forced a GC"); } NS_NAMED_MULTILINE_LITERAL_STRING(kFmt, - MOZ_UTF16("CC(T+%.1f)[%s] max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n") - MOZ_UTF16("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu")); + u"CC(T+%.1f)[%s] max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n" + u"ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu"); nsString msg; msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC, ProcessNameForCollectorLog(), gCCStats.mMaxSliceTime, gCCStats.mTotalSliceTime, aResults.mNumSlices, gCCStats.mSuspected, aResults.mVisitedRefCounted, aResults.mVisitedGCed, mergeMsg.get(), aResults.mFreedRefCounted, aResults.mFreedGCed, sCCollectedWaitingForGC, sCCollectedZonesWaitingForGC, sLikelyShortLivingObjectsNeedingGC, @@ -1643,41 +1643,41 @@ nsJSContext::EndCycleCollectionCallback( do_GetService(NS_CONSOLESERVICE_CONTRACTID); if (cs) { cs->LogStringMessage(msg.get()); } } if (sPostGCEventsToObserver) { NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt, - MOZ_UTF16("{ \"timestamp\": %llu, ") - MOZ_UTF16("\"duration\": %lu, ") - MOZ_UTF16("\"max_slice_pause\": %lu, ") - MOZ_UTF16("\"total_slice_pause\": %lu, ") - MOZ_UTF16("\"max_finish_gc_duration\": %lu, ") - MOZ_UTF16("\"max_sync_skippable_duration\": %lu, ") - MOZ_UTF16("\"suspected\": %lu, ") - MOZ_UTF16("\"visited\": { ") - MOZ_UTF16("\"RCed\": %lu, ") - MOZ_UTF16("\"GCed\": %lu }, ") - MOZ_UTF16("\"collected\": { ") - MOZ_UTF16("\"RCed\": %lu, ") - MOZ_UTF16("\"GCed\": %lu }, ") - MOZ_UTF16("\"waiting_for_gc\": %lu, ") - MOZ_UTF16("\"zones_waiting_for_gc\": %lu, ") - MOZ_UTF16("\"short_living_objects_waiting_for_gc\": %lu, ") - MOZ_UTF16("\"forced_gc\": %d, ") - MOZ_UTF16("\"forget_skippable\": { ") - MOZ_UTF16("\"times_before_cc\": %lu, ") - MOZ_UTF16("\"min\": %lu, ") - MOZ_UTF16("\"max\": %lu, ") - MOZ_UTF16("\"avg\": %lu, ") - MOZ_UTF16("\"total\": %lu, ") - MOZ_UTF16("\"removed\": %lu } ") - MOZ_UTF16("}")); + u"{ \"timestamp\": %llu, " + u"\"duration\": %lu, " + u"\"max_slice_pause\": %lu, " + u"\"total_slice_pause\": %lu, " + u"\"max_finish_gc_duration\": %lu, " + u"\"max_sync_skippable_duration\": %lu, " + u"\"suspected\": %lu, " + u"\"visited\": { " + u"\"RCed\": %lu, " + u"\"GCed\": %lu }, " + u"\"collected\": { " + u"\"RCed\": %lu, " + u"\"GCed\": %lu }, " + u"\"waiting_for_gc\": %lu, " + u"\"zones_waiting_for_gc\": %lu, " + u"\"short_living_objects_waiting_for_gc\": %lu, " + u"\"forced_gc\": %d, " + u"\"forget_skippable\": { " + u"\"times_before_cc\": %lu, " + u"\"min\": %lu, " + u"\"max\": %lu, " + u"\"avg\": %lu, " + u"\"total\": %lu, " + u"\"removed\": %lu } " + u"}"); nsString json; json.Adopt(nsTextFormatter::smprintf(kJSONFmt.get(), endCCTime, ccNowDuration, gCCStats.mMaxSliceTime, gCCStats.mTotalSliceTime, gCCStats.mMaxGCDuration, gCCStats.mMaxSkippableDuration, gCCStats.mSuspected, aResults.mVisitedRefCounted, aResults.mVisitedGCed,
--- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -269,19 +269,18 @@ nsNodeInfoManager::GetNodeInfo(const nsA } #endif NodeInfo::NodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType); void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey); if (node) { - NodeInfo* nodeInfo = static_cast<NodeInfo *>(node); - - NS_ADDREF(*aNodeInfo = nodeInfo); + RefPtr<NodeInfo> nodeInfo = static_cast<NodeInfo*>(node); + nodeInfo.forget(aNodeInfo); return NS_OK; } nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aName); NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); RefPtr<NodeInfo> newNodeInfo =
--- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -395,17 +395,17 @@ nsNodeUtils::CloneNodeImpl(nsINode *aNod *aResult = nullptr; nsCOMPtr<nsINode> newNode; nsCOMArray<nsINode> nodesWithProperties; nsresult rv = Clone(aNode, aDeep, nullptr, nodesWithProperties, getter_AddRefs(newNode)); NS_ENSURE_SUCCESS(rv, rv); - newNode.swap(*aResult); + newNode.forget(aResult); return NS_OK; } /* static */ nsresult nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, nsNodeInfoManager *aNewNodeInfoManager, JS::Handle<JSObject*> aReparentScope, @@ -501,17 +501,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod if (aNode->IsElement()) { Element* element = aNode->AsElement(); oldDoc->ClearBoxObjectFor(element); wasRegistered = oldDoc->UnregisterActivityObserver(element); } aNode->mNodeInfo.swap(newNodeInfo); if (elem) { - elem->NodeInfoChanged(newNodeInfo); + elem->NodeInfoChanged(); } nsIDocument* newDoc = aNode->OwnerDoc(); if (newDoc) { // XXX what if oldDoc is null, we don't know if this should be // registered or not! Can that really happen? if (wasRegistered) { newDoc->RegisterActivityObserver(aNode->AsElement());
--- a/dom/base/nsPlainTextSerializer.cpp +++ b/dom/base/nsPlainTextSerializer.cpp @@ -440,17 +440,17 @@ nsPlainTextSerializer::AppendDocumentSta nsresult nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag) { // Check if we need output current node as placeholder character and ignore // child nodes. if (ShouldReplaceContainerWithPlaceholder(mElement->NodeInfo()->NameAtom())) { if (mIgnoredChildNodeLevel == 0) { // Serialize current node as placeholder character - Write(NS_LITERAL_STRING("\xFFFC")); + Write(NS_LITERAL_STRING(u"\xFFFC")); } // Ignore child nodes. mIgnoredChildNodeLevel++; return NS_OK; } if (IsIgnorableRubyAnnotation(aTag)) { // Ignorable ruby annotation shouldn't be replaced by a placeholder // character, neither any of its descendants. @@ -596,17 +596,17 @@ nsPlainTextSerializer::DoOpenContainer(n else if (aTag == nsGkAtoms::td || aTag == nsGkAtoms::th) { // We must make sure that the content of two table cells get a // space between them. // To make the separation between cells most obvious and // importable, we use a TAB. if (GetLastBool(mHasWrittenCellsForRow)) { // Bypass |Write| so that the TAB isn't compressed away. - AddToLine(MOZ_UTF16("\t"), 1); + AddToLine(u"\t", 1); mInWhitespace = true; } else if (mHasWrittenCellsForRow.IsEmpty()) { // We don't always see a <tr> (nor a <table>) before the <td> if we're // copying part of a table PushBool(mHasWrittenCellsForRow, true); // will never be popped } else { @@ -1113,17 +1113,17 @@ nsPlainTextSerializer::DoAddLeaf(nsIAtom while (line.Length() < width) { line.Append(char16_t('-')); } Write(line); EnsureVerticalSpace(0); } else if (mFlags & nsIDocumentEncoder::OutputNonTextContentAsPlaceholder) { - Write(NS_LITERAL_STRING("\xFFFC")); + Write(NS_LITERAL_STRING(u"\xFFFC")); } else if (aTag == nsGkAtoms::img) { /* Output (in decreasing order of preference) alt, title or nothing */ // See <http://www.w3.org/TR/REC-html40/struct/objects.html#edef-IMG> nsAutoString imageDescription; if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::alt, imageDescription))) { @@ -1212,17 +1212,17 @@ nsPlainTextSerializer::Output(nsString& } mOutputString->Append(aString); } static bool IsSpaceStuffable(const char16_t *s) { if (s[0] == '>' || s[0] == ' ' || s[0] == kNBSP || - nsCRT::strncmp(s, MOZ_UTF16("From "), 5) == 0) + nsCRT::strncmp(s, u"From ", 5) == 0) return true; else return false; } /** * This function adds a piece of text to the current stored line. If we are * wrapping text and the stored line will become too long, a suitable @@ -2026,9 +2026,8 @@ int32_t GetUnicharStringWidth(const char for (;*pwcs && n-- > 0; pwcs++) if ((w = GetUnicharWidth(*pwcs)) < 0) ++width; // Taking 1 as the width of non-printable character, for bug# 94475. else width += w; return width; } -
--- a/dom/base/test/browser_use_counters.js +++ b/dom/base/test/browser_use_counters.js @@ -6,17 +6,22 @@ var {Promise: promise} = Cu.import("reso const gHttpTestRoot = "http://example.com/browser/dom/base/test/"; /** * Enable local telemetry recording for the duration of the tests. */ var gOldContentCanRecord = false; add_task(function* test_initialize() { - gOldContentCanRecord = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () { + // Because canRecordExtended is a per-process variable, we need to make sure + // that all of the pages load in the same content process. Limit the number + // of content processes to at most 1 (or 0 if e10s is off entirely). + yield SpecialPowers.pushPrefEnv({ set: [[ "dom.ipc.processCount", 1 ]] }); + + gOldContentCanRecord = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () { let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); let old = telemetry.canRecordExtended; telemetry.canRecordExtended = true; return old; }); info("canRecord for content: " + gOldContentCanRecord); });
--- a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html +++ b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html @@ -20,105 +20,114 @@ https://bugzilla.mozilla.org/show_bug.cg is(exn.name, name, "Should have the right exception name in test " + testNumber); is("filename" in exn ? exn.filename : exn.fileName, filename, "Should have the right file name in test " + testNumber); is(exn.message, message, "Should have the right message in test " + testNumber); is(exn.code, code, "Should have the right .code in test " + testNumber); if (message === "") { - is(exn.name, "NS_ERROR_UNEXPECTED", + is(exn.name, "InternalError", "Should have one of our synthetic exceptions in test " + testNumber); } is(exn.stack, stack, "Should have the right stack in test " + testNumber); } function ensurePromiseFail(testNumber, value) { ok(false, "Test " + testNumber + " should not have a fulfilled promise"); } function doTest() { var t = new TestInterfaceJS(); /* Async parent frames from pushPrefEnv don't show up in e10s. */ var isE10S = !SpecialPowers.isMainProcess(); var asyncStack = SpecialPowers.getBoolPref("javascript.options.asyncstack"); var ourFile = location.href; - var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:3 + var unwrapError = "Promise rejection value is a non-unwrappable cross-compartment wrapper."; + var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:130:3 ` : ""; Promise.all([ t.testPromiseWithThrowingChromePromiseInit().then( ensurePromiseFail.bind(null, 1), - checkExn.bind(null, 48, "NS_ERROR_UNEXPECTED", "", undefined, - ourFile, 1, - `doTest@${ourFile}:48:7 + checkExn.bind(null, 49, "InternalError", unwrapError, + undefined, ourFile, 1, + `doTest@${ourFile}:49:7 ` + parentFrame)), t.testPromiseWithThrowingContentPromiseInit(function() { thereIsNoSuchContentFunction1(); }).then( ensurePromiseFail.bind(null, 2), - checkExn.bind(null, 56, "ReferenceError", + checkExn.bind(null, 57, "ReferenceError", "thereIsNoSuchContentFunction1 is not defined", undefined, ourFile, 2, - `doTest/<@${ourFile}:56:11 -doTest@${ourFile}:55:7 + `doTest/<@${ourFile}:57:11 +doTest@${ourFile}:56:7 ` + parentFrame)), t.testPromiseWithThrowingChromeThenFunction().then( ensurePromiseFail.bind(null, 3), - checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 3, "")), + checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 3, asyncStack ? (`Async*doTest@${ourFile}:67:7 +` + + parentFrame) : "")), t.testPromiseWithThrowingContentThenFunction(function() { thereIsNoSuchContentFunction2(); }).then( ensurePromiseFail.bind(null, 4), - checkExn.bind(null, 70, "ReferenceError", + checkExn.bind(null, 73, "ReferenceError", "thereIsNoSuchContentFunction2 is not defined", undefined, ourFile, 4, - `doTest/<@${ourFile}:70:11 + `doTest/<@${ourFile}:73:11 ` + - (asyncStack ? `Async*doTest@${ourFile}:69:7 + (asyncStack ? `Async*doTest@${ourFile}:72:7 ` : "") + parentFrame)), t.testPromiseWithThrowingChromeThenable().then( ensurePromiseFail.bind(null, 5), - checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 5, "")), + checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 5, asyncStack ? (`Async*doTest@${ourFile}:84:7 +` + + parentFrame) : "")), t.testPromiseWithThrowingContentThenable({ then: function() { thereIsNoSuchContentFunction3(); } }).then( ensurePromiseFail.bind(null, 6), - checkExn.bind(null, 85, "ReferenceError", + checkExn.bind(null, 90, "ReferenceError", "thereIsNoSuchContentFunction3 is not defined", undefined, ourFile, 6, - `doTest/<.then@${ourFile}:85:32 -`)), + `doTest/<.then@${ourFile}:90:32 +` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))), t.testPromiseWithDOMExceptionThrowingPromiseInit().then( ensurePromiseFail.bind(null, 7), - checkExn.bind(null, 93, "NotFoundError", + checkExn.bind(null, 98, "NotFoundError", "We are a second DOMException", DOMException.NOT_FOUND_ERR, ourFile, 7, - `doTest@${ourFile}:93:7 + `doTest@${ourFile}:98:7 ` + parentFrame)), t.testPromiseWithDOMExceptionThrowingThenFunction().then( ensurePromiseFail.bind(null, 8), - checkExn.bind(null, asyncStack ? 101 : 0, "NetworkError", + checkExn.bind(null, asyncStack ? 106 : 0, "NetworkError", "We are a third DOMException", DOMException.NETWORK_ERR, asyncStack ? ourFile : "", 8, - (asyncStack ? `Async*doTest@${ourFile}:101:7 + (asyncStack ? `Async*doTest@${ourFile}:106:7 ` + parentFrame : ""))), t.testPromiseWithDOMExceptionThrowingThenable().then( ensurePromiseFail.bind(null, 9), - checkExn.bind(null, 0, "TypeMismatchError", + checkExn.bind(null, asyncStack ? 114 : 0, "TypeMismatchError", "We are a fourth DOMException", - DOMException.TYPE_MISMATCH_ERR, "", 9, "")), + DOMException.TYPE_MISMATCH_ERR, + asyncStack ? ourFile : "", 9, + (asyncStack ? `Async*doTest@${ourFile}:114:7 +` + + parentFrame : ""))), ]).then(SimpleTest.finish, - function() { - ok(false, "One of our catch statements totally failed"); + function(err) { + ok(false, "One of our catch statements totally failed with err" + err + ', stack: ' + (err ? err.stack : '')); SimpleTest.finish(); }); } SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, doTest); </script> </head>
--- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -1297,17 +1297,17 @@ nsGonkCameraControl::StopRecordingImpl() ~RecordingComplete() { } NS_IMETHODIMP Run() { MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - obs->NotifyObservers(mFile, "file-watcher-notify", MOZ_UTF16("modified")); + obs->NotifyObservers(mFile, "file-watcher-notify", u"modified"); return NS_OK; } private: RefPtr<DeviceStorageFile> mFile; }; ReentrantMonitorAutoEnter mon(mRecorderMonitor);
--- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1557,18 +1557,18 @@ CanvasRenderingContext2D::EnsureTarget(c } else { mTarget = mBufferProvider->BorrowDrawTarget(IntRect(0, 0, mWidth, mHeight)); } ScheduleStableStateCallback(); if (mTarget) { // Restore clip and transform. - mTarget->SetTransform(CurrentState().transform); for (uint32_t i = 0; i < mStyleStack.Length(); i++) { + mTarget->SetTransform(mStyleStack[i].transform); for (uint32_t c = 0; c < mStyleStack[i].clipsPushed.Length(); c++) { mTarget->PushClip(mStyleStack[i].clipsPushed[c]); } } return mRenderingMode; } else { mBufferProvider = nullptr; }
--- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -931,17 +931,17 @@ protected: miterLimit(10.0f), globalAlpha(1.0f), shadowBlur(0.0), dashOffset(0.0f), op(mozilla::gfx::CompositionOp::OP_OVER), fillRule(mozilla::gfx::FillRule::FILL_WINDING), lineCap(mozilla::gfx::CapStyle::BUTT), lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL), - filterString(MOZ_UTF16("none")), + filterString(u"none"), updateFilterOnWriteOnly(false), imageSmoothingEnabled(true), fontExplicitLanguage(false) { } ContextState(const ContextState& aOther) : fontGroup(aOther.fontGroup), fontLanguage(aOther.fontLanguage),
new file mode 100644 --- /dev/null +++ b/dom/canvas/crashtests/1287515-1.html @@ -0,0 +1,7 @@ +<canvas id='i0'></canvas> +<script> +var c=document.getElementById('i0').getContext('2d'); +c.lineWidth=Number.MAX_SAFE_INTEGER; +c.setLineDash([1]); +c.strokeRect(1,1,0,Number.MIN_SAFE_INTEGER); +</script>
--- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -24,8 +24,9 @@ load 1161277-1.html load 1183363.html load 1190705.html load 1223740-1.html load 1225381-1.html skip-if(azureCairo) load 1229983-1.html load 1229932-1.html load 1244850-1.html load 1246775-1.html +skip-if(d2d) load 1287515-1.html
--- a/dom/devicestorage/DeviceStorageStatics.cpp +++ b/dom/devicestorage/DeviceStorageStatics.cpp @@ -698,19 +698,19 @@ DeviceStorageStatics::Observe(nsISupport if (NS_WARN_IF(!sInstance)) { return NS_OK; } // 'disk-space-watcher' notifications are sent when there is a modification // of a file in a specific location while a low device storage situation // exists or after recovery of a low storage situation. For Firefox OS, // these notifications are specific for apps storage. - if (!NS_strcmp(aData, MOZ_UTF16("full"))) { + if (!NS_strcmp(aData, u"full")) { sInstance->mLowDiskSpace = true; - } else if (!NS_strcmp(aData, MOZ_UTF16("free"))) { + } else if (!NS_strcmp(aData, u"free")) { sInstance->mLowDiskSpace = false; } else { return NS_OK; } uint32_t i = mListeners.Length(); DS_LOG_INFO("disk space %d (%u)", sInstance->mLowDiskSpace, i);
--- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -36,17 +36,17 @@ #undef TextRangeArray #undef Comment #endif using namespace mozilla::widget; namespace mozilla { -#define IDEOGRAPHIC_SPACE (NS_LITERAL_STRING("\x3000")) +#define IDEOGRAPHIC_SPACE (NS_LITERAL_STRING(u"\x3000")) /****************************************************************************** * TextComposition ******************************************************************************/ bool TextComposition::sHandlingSelectionEvent = false; TextComposition::TextComposition(nsPresContext* aPresContext,
--- a/dom/filehandle/ActorsParent.h +++ b/dom/filehandle/ActorsParent.h @@ -8,23 +8,23 @@ #include "mozilla/dom/FileHandleStorage.h" #include "mozilla/dom/PBackgroundMutableFileParent.h" #include "mozilla/ipc/BackgroundParent.h" #include "nsAutoPtr.h" #include "nsClassHashtable.h" #include "nsCOMPtr.h" #include "nsHashKeys.h" #include "nsString.h" +#include "nsTArrayForwardDeclare.h" #include "nsTHashtable.h" template <class> struct already_AddRefed; class nsIFile; class nsIRunnable; class nsIThreadPool; -template <class> class nsTArray; namespace mozilla { namespace ipc { class PBackgroundParent; } // namespace ipc
--- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -955,17 +955,17 @@ nsGeolocationService::StartDevice(nsIPri NS_FAILED(rv = mProvider->Watch(this))) { NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE); return rv; } obs->NotifyObservers(mProvider, "geolocation-device-events", - MOZ_UTF16("starting")); + u"starting"); return NS_OK; } void nsGeolocationService::StopDisconnectTimer() { if (mDisconnectTimer) { @@ -1044,17 +1044,17 @@ nsGeolocationService::StopDevice() return; } mHigherAccuracy = false; mProvider->Shutdown(); obs->NotifyObservers(mProvider, "geolocation-device-events", - MOZ_UTF16("shutdown")); + u"shutdown"); } StaticRefPtr<nsGeolocationService> nsGeolocationService::sService; already_AddRefed<nsGeolocationService> nsGeolocationService::GetGeolocationService() { RefPtr<nsGeolocationService> result;
--- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -927,22 +927,22 @@ HTMLFormElement::DoSecureToInsecureSubmi getter_AddRefs(stringBundle)); if (NS_FAILED(rv)) { return rv; } nsAutoString title; nsAutoString message; nsAutoString cont; stringBundle->GetStringFromName( - MOZ_UTF16("formPostSecureToInsecureWarning.title"), getter_Copies(title)); + u"formPostSecureToInsecureWarning.title", getter_Copies(title)); stringBundle->GetStringFromName( - MOZ_UTF16("formPostSecureToInsecureWarning.message"), + u"formPostSecureToInsecureWarning.message", getter_Copies(message)); stringBundle->GetStringFromName( - MOZ_UTF16("formPostSecureToInsecureWarning.continue"), + u"formPostSecureToInsecureWarning.continue", getter_Copies(cont)); int32_t buttonPressed; bool checkState = false; // this is unused (ConfirmEx requires this parameter) rv = prompt->ConfirmEx(title.get(), message.get(), (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) + (nsIPrompt::BUTTON_TITLE_CANCEL * nsIPrompt::BUTTON_POS_1), @@ -1752,17 +1752,17 @@ HTMLFormElement::GetActionURL(nsIURI** a // let's log a message to the console that we are upgrading a request nsAutoCString scheme; rv = actionURL->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); NS_ConvertUTF8toUTF16 reportScheme(scheme); const char16_t* params[] = { reportSpec.get(), reportScheme.get() }; - CSP_LogLocalizedStr(MOZ_UTF16("upgradeInsecureRequest"), + CSP_LogLocalizedStr(u"upgradeInsecureRequest", params, ArrayLength(params), EmptyString(), // aSourceFile EmptyString(), // aScriptSample 0, // aLineNumber 0, // aColumnNumber nsIScriptError::warningFlag, "CSP", document->InnerWindowID()); }
--- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -7833,25 +7833,25 @@ HTMLInputElement::SetFilePickerFiltersFr int32_t filterMask = 0; nsString filterName; nsString extensionListStr; // First, check for image/audio/video filters... if (token.EqualsLiteral("image/*")) { filterMask = nsIFilePicker::filterImages; - filterBundle->GetStringFromName(MOZ_UTF16("imageFilter"), + filterBundle->GetStringFromName(u"imageFilter", getter_Copies(extensionListStr)); } else if (token.EqualsLiteral("audio/*")) { filterMask = nsIFilePicker::filterAudio; - filterBundle->GetStringFromName(MOZ_UTF16("audioFilter"), + filterBundle->GetStringFromName(u"audioFilter", getter_Copies(extensionListStr)); } else if (token.EqualsLiteral("video/*")) { filterMask = nsIFilePicker::filterVideo; - filterBundle->GetStringFromName(MOZ_UTF16("videoFilter"), + filterBundle->GetStringFromName(u"videoFilter", getter_Copies(extensionListStr)); } else if (token.First() == '.') { if (token.Contains(';') || token.Contains('*')) { // Ignore this filter as it contains reserved characters continue; } extensionListStr = NS_LITERAL_STRING("*") + token; filterName = extensionListStr;
--- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -780,17 +780,17 @@ ImageDocument::UpdateTitleAndCharset() } nsXPIDLString status; if (mImageIsResized) { nsAutoString ratioStr; ratioStr.AppendInt(NSToCoordFloor(GetRatio() * 100)); const char16_t* formatString[1] = { ratioStr.get() }; - mStringBundle->FormatStringFromName(MOZ_UTF16("ScaledImage"), + mStringBundle->FormatStringFromName(u"ScaledImage", formatString, 1, getter_Copies(status)); } static const char* const formatNames[4] = { "ImageTitleWithNeitherDimensionsNorFile", "ImageTitleWithoutDimensions",
--- a/dom/html/PluginDocument.cpp +++ b/dom/html/PluginDocument.cpp @@ -163,17 +163,17 @@ PluginDocument::StartDocumentLoad(const bool aReset, nsIContentSink* aSink) { // do not allow message panes to host full-page plugins // returning an error causes helper apps to take over nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer)); if (dsti) { bool isMsgPane = false; - dsti->NameEquals(MOZ_UTF16("messagepane"), &isMsgPane); + dsti->NameEquals(u"messagepane", &isMsgPane); if (isMsgPane) { return NS_ERROR_FAILURE; } } nsresult rv = MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, aReset, aSink);
--- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -1299,21 +1299,21 @@ MapLangAttributeInto(const nsMappedAttri if (lang->GetUnit() == eCSSUnit_Null) { lang->SetStringValue(langValue->GetStringValue(), eCSSUnit_Ident); } } if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) { nsCSSValue* emphasisPos = aData->ValueForTextEmphasisPosition(); if (emphasisPos->GetUnit() == eCSSUnit_Null) { const nsAString& lang = langValue->GetStringValue(); - if (nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("zh"))) { + if (nsStyleUtil::MatchesLanguagePrefix(lang, u"zh")) { emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH, eCSSUnit_Enumerated); - } else if (nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("ja")) || - nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("mn"))) { + } else if (nsStyleUtil::MatchesLanguagePrefix(lang, u"ja") || + nsStyleUtil::MatchesLanguagePrefix(lang, u"mn")) { // This branch is currently no part of the spec. // See bug 1040668 comment 69 and comment 75. emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT, eCSSUnit_Enumerated); } } } } @@ -3077,17 +3077,17 @@ nsGenericHTMLFormElementWithState::Resto history->RemoveState(mStateKey); return result; } return false; } void -nsGenericHTMLFormElementWithState::NodeInfoChanged(mozilla::dom::NodeInfo* aOldNodeInfo) +nsGenericHTMLFormElementWithState::NodeInfoChanged() { mStateKey.SetIsVoid(true); } nsSize nsGenericHTMLElement::GetWidthHeightForImage(RefPtr<imgRequestProxy>& aImageRequest) { nsSize size(0,0);
--- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -1395,17 +1395,17 @@ public: * value of RestoreState() otherwise. */ bool RestoreFormControlState(); /** * Called when we have been cloned and adopted, and the information of the * node has been changed. */ - virtual void NodeInfoChanged(mozilla::dom::NodeInfo* aOldNodeInfo) override; + virtual void NodeInfoChanged() override; protected: /* Generates the state key for saving the form state in the session if not computed already. The result is stored in mStateKey on success */ nsresult GenerateStateKey(); /* Used to store the key to that element in the session. Is void until GenerateStateKey has been used */
--- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -167,18 +167,16 @@ protected: // Boolean indicating whether we've seen a <head> tag that might have had // attributes once already. bool mHaveSeenHead; // Boolean indicating whether we've notified insertion of our root content // yet. We want to make sure to only do this once. bool mNotifiedRootInsertion; - mozilla::dom::NodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1]; - nsresult FlushTags() override; // Routines for tags that require special handling nsresult CloseHTML(); nsresult OpenBody(); nsresult CloseBody(); void CloseHeadContext(); @@ -212,17 +210,17 @@ public: void DidAddContent(nsIContent* aContent); void UpdateChildCounts(); private: // Function to check whether we've notified for the current content. // What this actually does is check whether we've notified for all // of the parent's kids. bool HaveNotifiedForCurrentContent() const; - + public: HTMLContentSink* mSink; int32_t mNotifyLevel; struct Node { nsHTMLTag mType; nsGenericHTMLElement* mContent; uint32_t mNumFlushed; @@ -245,17 +243,17 @@ NS_NewHTMLElement(Element** aResult, alr RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo; nsIParserService* parserService = nsContentUtils::GetParserService(); if (!parserService) return NS_ERROR_OUT_OF_MEMORY; nsIAtom *name = nodeInfo->NameAtom(); - NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML), + NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML), "Trying to HTML elements that don't have the XHTML namespace"); // Per the Custom Element specification, unknown tags that are valid custom // element names should be HTMLElement instead of HTMLUnknownElement. int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name); if ((tag == eHTMLTag_userdefined && nsContentUtils::IsCustomElementName(name)) || aIs) { @@ -669,44 +667,32 @@ HTMLContentSink::~HTMLContentSink() if (mCurrentContext == mHeadContext) { mCurrentContext = nullptr; } delete mCurrentContext; delete mHeadContext; - - for (i = 0; uint32_t(i) < ArrayLength(mNodeInfoCache); ++i) { - NS_IF_RELEASE(mNodeInfoCache[i]); - } } NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLContentSink) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLContentSink, nsContentSink) NS_IMPL_CYCLE_COLLECTION_UNLINK(mHTMLDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBody) NS_IMPL_CYCLE_COLLECTION_UNLINK(mHead) - for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) { - NS_IF_RELEASE(tmp->mNodeInfoCache[i]); - } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLContentSink, nsContentSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHTMLDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBody) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHead) - for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfoCache[i]"); - cb.NoteNativeChild(tmp->mNodeInfoCache[i], - NS_CYCLE_COLLECTION_PARTICIPANT(NodeInfo)); - } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLContentSink) NS_INTERFACE_TABLE_BEGIN NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIContentSink) NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIHTMLContentSink) NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink) @@ -716,17 +702,17 @@ NS_IMPL_RELEASE_INHERITED(HTMLContentSin nsresult HTMLContentSink::Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer, nsIChannel* aChannel) { NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER); - + nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel); if (NS_FAILED(rv)) { return rv; } aDoc->AddObserver(this); mIsDocumentObserver = true; mHTMLDocument = do_QueryInterface(aDoc); @@ -834,17 +820,17 @@ HTMLContentSink::DidBuildModel(bool aTer // Make sure we no longer respond to document mutations. We've flushed all // our notifications out, so there's no need to do anything else here. // XXXbz I wonder whether we could End() our contexts here too, or something, // just to make sure we no longer notify... Or is the mIsDocumentObserver // thing sufficient? mDocument->RemoveObserver(this); mIsDocumentObserver = false; - + mDocument->EndLoad(); DropParserAndPerfHint(); return NS_OK; } NS_IMETHODIMP @@ -895,17 +881,17 @@ HTMLContentSink::OpenBody() mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent; if (mCurrentContext->mStackPos > 1) { int32_t parentIndex = mCurrentContext->mStackPos - 2; nsGenericHTMLElement *parent = mCurrentContext->mStack[parentIndex].mContent; int32_t numFlushed = mCurrentContext->mStack[parentIndex].mNumFlushed; int32_t childCount = parent->GetChildCount(); NS_ASSERTION(numFlushed < childCount, "Already notified on the body?"); - + int32_t insertionPoint = mCurrentContext->mStack[parentIndex].mInsertionPoint; // XXX: I have yet to see a case where numFlushed is non-zero and // insertionPoint is not -1, but this code will try to handle // those cases too. uint32_t oldUpdates = mUpdatesInNotification; @@ -1091,17 +1077,17 @@ HTMLContentSink::FlushPendingNotificatio nsresult HTMLContentSink::FlushTags() { if (!mNotifiedRootInsertion) { NotifyRootInsertion(); return NS_OK; } - + return mCurrentContext ? mCurrentContext->FlushTags() : NS_OK; } NS_IMETHODIMP HTMLContentSink::SetDocumentCharset(nsACString& aCharset) { MOZ_ASSERT_UNREACHABLE("<meta charset> case doesn't occur with about:blank"); return NS_ERROR_NOT_IMPLEMENTED;
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -787,17 +787,17 @@ nsHTMLDocument::StartDocumentLoad(const nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); NS_ASSERTION(NS_SUCCEEDED(rv) && bundleService, "The bundle service could not be loaded"); nsCOMPtr<nsIStringBundle> bundle; rv = bundleService->CreateBundle("chrome://global/locale/browser.properties", getter_AddRefs(bundle)); NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/browser.properties could not be loaded"); nsXPIDLString title; if (bundle) { - bundle->GetStringFromName(MOZ_UTF16("plainText.wordWrap"), getter_Copies(title)); + bundle->GetStringFromName(u"plainText.wordWrap", getter_Copies(title)); } SetSelectedStyleSheetSet(title); } // parser the content of the URI mParser->Parse(uri, nullptr, (void *)this); return rv;
--- a/dom/html/test/test_bug332246.html +++ b/dom/html/test/test_bug332246.html @@ -32,44 +32,40 @@ https://bugzilla.mozilla.org/show_bug.cg </div> </div> <pre id="test"> <script class="testbody" type="text/javascript"> /** Test for Bug 332246 **/ -function isWithFuzz(itIs, itShouldBe, fuzz, description) { - ok(Math.abs(itIs - itShouldBe) <= fuzz, `${description} - expected a value between ${itShouldBe - fuzz} and ${itShouldBe + fuzz}, got ${itIs}`); -} - var a1 = document.getElementById('a1'); var a2 = document.getElementById('a2'); -isWithFuzz(a1.scrollHeight, 400, 1, "Wrong a1.scrollHeight"); +is(a1.scrollHeight, 400, "Wrong a1.scrollHeight"); is(a1.offsetHeight, 100, "Wrong a1.offsetHeight"); a2.scrollIntoView(true); is(a1.scrollTop, 100, "Wrong scrollTop value after a2.scrollIntoView(true)"); a2.scrollIntoView(false); is(a1.scrollTop, 200, "Wrong scrollTop value after a2.scrollIntoView(false)"); var b1 = document.getElementById('b1'); var b2 = document.getElementById('b2'); -isWithFuzz(b1.scrollHeight, 420, 1, "Wrong b1.scrollHeight"); +is(b1.scrollHeight, 420, "Wrong b1.scrollHeight"); is(b1.offsetHeight, 100, "Wrong b1.offsetHeight"); b2.scrollIntoView(true); is(b1.scrollTop, 100, "Wrong scrollTop value after b2.scrollIntoView(true)"); b2.scrollIntoView(false); is(b1.scrollTop, 220, "Wrong scrollTop value after b2.scrollIntoView(false)"); var c1 = document.getElementById('c1'); var c2 = document.getElementById('c2'); -isWithFuzz(c1.scrollHeight, 320, 1, "Wrong c1.scrollHeight"); +is(c1.scrollHeight, 320, "Wrong c1.scrollHeight"); is(c1.offsetHeight, 100, "Wrong c1.offsetHeight"); c2.scrollIntoView(true); is(c1.scrollTop, 100, "Wrong scrollTop value after c2.scrollIntoView(true)"); c2.scrollIntoView(false); -isWithFuzz(c1.scrollTop, 220, 1, "Wrong scrollTop value after c2.scrollIntoView(false)"); +is(c1.scrollTop, 220, "Wrong scrollTop value after c2.scrollIntoView(false)"); </script> </pre> </body> </html>
--- a/dom/indexedDB/IDBEvents.cpp +++ b/dom/indexedDB/IDBEvents.cpp @@ -14,24 +14,24 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::indexedDB; namespace mozilla { namespace dom { namespace indexedDB { -const char16_t* kAbortEventType = MOZ_UTF16("abort"); -const char16_t* kBlockedEventType = MOZ_UTF16("blocked"); -const char16_t* kCompleteEventType = MOZ_UTF16("complete"); -const char16_t* kErrorEventType = MOZ_UTF16("error"); -const char16_t* kSuccessEventType = MOZ_UTF16("success"); -const char16_t* kUpgradeNeededEventType = MOZ_UTF16("upgradeneeded"); -const char16_t* kVersionChangeEventType = MOZ_UTF16("versionchange"); -const char16_t* kCloseEventType = MOZ_UTF16("close"); +const char16_t* kAbortEventType = u"abort"; +const char16_t* kBlockedEventType = u"blocked"; +const char16_t* kCompleteEventType = u"complete"; +const char16_t* kErrorEventType = u"error"; +const char16_t* kSuccessEventType = u"success"; +const char16_t* kUpgradeNeededEventType = u"upgradeneeded"; +const char16_t* kVersionChangeEventType = u"versionchange"; +const char16_t* kCloseEventType = u"close"; already_AddRefed<nsIDOMEvent> CreateGenericEvent(EventTarget* aOwner, const nsDependentString& aType, Bubbles aBubbles, Cancelable aCancelable) { RefPtr<Event> event = new Event(aOwner, nullptr, nullptr);
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1249,30 +1249,29 @@ ContentChild::RecvInitCompositor(Endpoin } bool ContentChild::RecvInitImageBridge(Endpoint<PImageBridgeChild>&& aEndpoint) { return ImageBridgeChild::InitForContent(Move(aEndpoint)); } +bool +ContentChild::RecvInitVRManager(Endpoint<PVRManagerChild>&& aEndpoint) +{ + return gfx::VRManagerChild::InitForContent(Move(aEndpoint)); +} + PSharedBufferManagerChild* ContentChild::AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherProcess) { return SharedBufferManagerChild::StartUpInChildProcess(aTransport, aOtherProcess); } -gfx::PVRManagerChild* -ContentChild::AllocPVRManagerChild(Transport* aTransport, - ProcessId aOtherProcess) -{ - return gfx::VRManagerChild::StartUpInChildProcess(aTransport, aOtherProcess); -} - PBackgroundChild* ContentChild::AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess) { return BackgroundChild::Alloc(aTransport, aOtherProcess); } PProcessHangMonitorChild*
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -147,29 +147,27 @@ public: AllocPAPZChild(const TabId& aTabId) override; bool DeallocPAPZChild(PAPZChild* aActor) override; bool RecvInitCompositor(Endpoint<PCompositorBridgeChild>&& aEndpoint) override; bool RecvInitImageBridge(Endpoint<PImageBridgeChild>&& aEndpoint) override; + bool + RecvInitVRManager(Endpoint<PVRManagerChild>&& aEndpoint) override; PSharedBufferManagerChild* AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherProcess) override; PProcessHangMonitorChild* AllocPProcessHangMonitorChild(Transport* aTransport, ProcessId aOtherProcess) override; - PVRManagerChild* - AllocPVRManagerChild(Transport* aTransport, - ProcessId aOtherProcess) override; - virtual bool RecvSetProcessSandbox(const MaybeFileDesc& aBroker) override; PBackgroundChild* AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess) override; virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId, const IPCTabContext& aContext,
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -270,18 +270,16 @@ using namespace mozilla::system; #ifdef XP_WIN #include "mozilla/widget/AudioSession.h" #endif #ifdef MOZ_CRASHREPORTER #include "nsThread.h" #endif -#include "VRManagerParent.h" // for VRManagerParent - // For VP9Benchmark::sBenchmarkFpsPref #include "Benchmark.h" static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); #if defined(XP_WIN) // e10s forced enable pref, defined in nsAppRunner.cpp extern const char* kForceEnableE10sPref; @@ -2444,18 +2442,21 @@ ContentParent::InitInternal(ProcessPrior Endpoint<PImageBridgeChild> endpoint; DebugOnly<bool> opened = gpm->CreateContentImageBridge(OtherPid(), &endpoint); MOZ_ASSERT(opened); Unused << SendInitImageBridge(Move(endpoint)); } { - DebugOnly<bool> opened = gfx::PVRManager::Open(this); + Endpoint<PVRManagerChild> endpoint; + DebugOnly<bool> opened = + gpm->CreateContentVRManager(OtherPid(), &endpoint); MOZ_ASSERT(opened); + Unused << SendInitVRManager(Move(endpoint)); } } #ifdef MOZ_WIDGET_GONK DebugOnly<bool> opened = PSharedBufferManager::Open(this); MOZ_ASSERT(opened); #endif } @@ -3236,23 +3237,16 @@ ContentParent::AllocPAPZParent(const Tab } bool ContentParent::DeallocPAPZParent(PAPZParent* aActor) { return true; } -gfx::PVRManagerParent* -ContentParent::AllocPVRManagerParent(Transport* aTransport, - ProcessId aOtherProcess) -{ - return gfx::VRManagerParent::CreateCrossProcess(aTransport, aOtherProcess); -} - PBackgroundParent* ContentParent::AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess) { return BackgroundParent::Alloc(this, aTransport, aOtherProcess); } PProcessHangMonitorParent*
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -752,20 +752,16 @@ private: PBackgroundParent* AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess) override; PProcessHangMonitorParent* AllocPProcessHangMonitorParent(Transport* aTransport, ProcessId aOtherProcess) override; - PVRManagerParent* - AllocPVRManagerParent(Transport* aTransport, - ProcessId aOtherProcess) override; - virtual bool RecvGetProcessAttributes(ContentParentId* aCpId, bool* aIsForApp, bool* aIsForBrowser) override; virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline, bool* aIsConnected, bool* aIsLangRTL,
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -382,17 +382,16 @@ struct BlobURLRegistrationData prio(normal upto urgent) sync protocol PContent { parent spawns PPluginModule; parent opens PProcessHangMonitor; parent opens PSharedBufferManager; parent opens PGMPService; - parent opens PVRManager; child opens PBackground; manages PAPZ; manages PBlob; manages PBluetooth; manages PBrowser; manages PCellBroadcast; manages PContentPermissionRequest; @@ -467,16 +466,17 @@ both: // ignored and should be null/zero. async PWebBrowserPersistDocument(nullable PBrowser aBrowser, uint64_t aOuterWindowID); child: // Give the content process its endpoints to the compositor. async InitCompositor(Endpoint<PCompositorBridgeChild> compositor); async InitImageBridge(Endpoint<PImageBridgeChild> bridge); + async InitVRManager(Endpoint<PVRManagerChild> endpoint); /** * Enable system-level sandboxing features, if available. Can * usually only be performed zero or one times. The child may * abnormally exit if this fails; the details are OS-specific. */ async SetProcessSandbox(MaybeFileDesc aBroker);
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -797,17 +797,16 @@ TabChild::Init() LayoutDeviceIntRect(0, 0, 0, 0), nullptr // HandleWidgetEvent ); baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0); baseWindow->Create(); // Set the tab context attributes then pass to docShell - SetPrivateBrowsingAttributes(mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW); NotifyTabContextUpdated(); // IPC uses a WebBrowser object for which DNS prefetching is turned off // by default. But here we really want it, so enable it explicitly nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup = do_QueryInterface(baseWindow); if (webBrowserSetup) { webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH, @@ -819,18 +818,17 @@ TabChild::Init() nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); MOZ_ASSERT(docShell); docShell->SetAffectPrivateSessionLifetime( mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME); nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation()); MOZ_ASSERT(loadContext); - loadContext->SetPrivateBrowsing( - mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW); + loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0); loadContext->SetRemoteTabs( mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW); // Few lines before, baseWindow->Create() will end up creating a new // window root in nsGlobalWindow::SetDocShell. // Then this chrome event handler, will be inherited to inner windows. // We want to also set it to the docshell so that inner windows // and any code that has access to the docshell
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2666,17 +2666,17 @@ TabParent::RecvAudioChannelActivityNotif nsCOMPtr<nsIObserverService> os = services::GetObserverService(); if (os) { nsAutoCString topic; topic.Assign("audiochannel-activity-"); topic.Append(AudioChannelService::GetAudioChannelTable()[aAudioChannel].tag); os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this), topic.get(), - aActive ? MOZ_UTF16("active") : MOZ_UTF16("inactive")); + aActive ? u"active" : u"inactive"); } return true; } already_AddRefed<nsFrameLoader> TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const {
--- a/dom/mathml/nsMathMLElement.cpp +++ b/dom/mathml/nsMathMLElement.cpp @@ -1082,18 +1082,17 @@ nsMathMLElement::SetAttr(int32_t aNameSp // is important here! The attribute is not set until SetAttr returns, and // we will need the updated attribute value because notifying the document // that content states have changed will call IntrinsicState, which will try // to get updated information about the visitedness from Link. if (aName == nsGkAtoms::href && (aNameSpaceID == kNameSpaceID_None || aNameSpaceID == kNameSpaceID_XLink)) { if (aNameSpaceID == kNameSpaceID_XLink) { - WarnDeprecated(MOZ_UTF16("xlink:href"), - MOZ_UTF16("href"), OwnerDoc()); + WarnDeprecated(u"xlink:href", u"href", OwnerDoc()); } Link::ResetLinkState(!!aNotify, true); } return rv; } nsresult
--- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -142,17 +142,17 @@ void InitBrandName() nsXPIDLString brandName; nsCOMPtr<nsIStringBundleService> stringBundleService = mozilla::services::GetStringBundleService(); if (stringBundleService) { nsCOMPtr<nsIStringBundle> brandBundle; nsresult rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle)); if (NS_SUCCEEDED(rv)) { - rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), + rv = brandBundle->GetStringFromName(u"brandShortName", getter_Copies(brandName)); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not get the program name for a cubeb stream."); } } /* cubeb expects a c-string. */ const char* ascii = NS_LossyConvertUTF16toASCII(brandName).get(); sBrandName = new char[brandName.Length() + 1];
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -835,24 +835,24 @@ NS_IMETHODIMP MediaDevice::GetType(nsAString& aType) { return NS_OK; } NS_IMETHODIMP VideoDevice::GetType(nsAString& aType) { - aType.AssignLiteral(MOZ_UTF16("video")); + aType.AssignLiteral(u"video"); return NS_OK; } NS_IMETHODIMP AudioDevice::GetType(nsAString& aType) { - aType.AssignLiteral(MOZ_UTF16("audio")); + aType.AssignLiteral(u"audio"); return NS_OK; } NS_IMETHODIMP MediaDevice::GetId(nsAString& aID) { aID.Assign(mID); return NS_OK; @@ -3047,17 +3047,17 @@ MediaManager::Observe(nsISupports* aSubj } else if (!strcmp(aTopic, "getUserMedia:response:deny")) { nsString errorMessage(NS_LITERAL_STRING("NotAllowedError")); if (aSubject) { nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject)); MOZ_ASSERT(msg); msg->GetData(errorMessage); if (errorMessage.IsEmpty()) - errorMessage.AssignLiteral(MOZ_UTF16("InternalError")); + errorMessage.AssignLiteral(u"InternalError"); } nsString key(aData); RefPtr<GetUserMediaTask> task; mActiveCallbacks.Remove(key, getter_AddRefs(task)); if (task) { task->Denied(errorMessage); }
--- a/dom/media/eme/EMEUtils.cpp +++ b/dom/media/eme/EMEUtils.cpp @@ -75,20 +75,20 @@ ParseKeySystem(const nsAString& aExpecte NS_WARNING("Invalid version in EME keySystem string"); return false; } aOutCDMVersion = version; return true; } -static const char16_t* sKeySystems[] = { - MOZ_UTF16("org.w3.clearkey"), - MOZ_UTF16("com.adobe.primetime"), - MOZ_UTF16("com.widevine.alpha"), +static const char16_t *const sKeySystems[] = { + u"org.w3.clearkey", + u"com.adobe.primetime", + u"com.widevine.alpha", }; bool ParseKeySystem(const nsAString& aInputKeySystem, nsAString& aOutKeySystem, int32_t& aOutCDMVersion) { for (const char16_t* keySystem : sKeySystems) {
--- a/dom/media/gtest/TestEME.cpp +++ b/dom/media/gtest/TestEME.cpp @@ -13,48 +13,48 @@ using namespace mozilla; struct ParseKeySystemTestCase { const char16_t* mInputKeySystemString; int32_t mOutCDMVersion; bool mShouldPass; }; const ParseKeySystemTestCase ParseKeySystemTests[] = { { - MOZ_UTF16("org.w3.clearkey"), + u"org.w3.clearkey", NO_CDM_VERSION, true, }, { - MOZ_UTF16("org.w3.clearkey.123"), + u"org.w3.clearkey.123", 123, true, }, { - MOZ_UTF16("org.w3.clearkey.-1"), + u"org.w3.clearkey.-1", NO_CDM_VERSION, false, }, { - MOZ_UTF16("org.w3.clearkey.NaN"), + u"org.w3.clearkey.NaN", NO_CDM_VERSION, false, }, { - MOZ_UTF16("org.w3.clearkey.0"), + u"org.w3.clearkey.0", 0, true, }, { - MOZ_UTF16("org.w3.clearkey.123567890123567890123567890123567890123567890"), + u"org.w3.clearkey.123567890123567890123567890123567890123567890", NO_CDM_VERSION, false, }, { - MOZ_UTF16("org.w3.clearkey.0.1"), + u"org.w3.clearkey.0.1", NO_CDM_VERSION, false, } }; TEST(EME, EMEParseKeySystem) { - const nsAutoString clearkey(MOZ_UTF16("org.w3.clearkey")); + const nsAutoString clearkey(u"org.w3.clearkey"); for (const ParseKeySystemTestCase& test : ParseKeySystemTests) { nsAutoString keySystem; int32_t version; bool rv = ParseKeySystem(nsDependentString(test.mInputKeySystemString), keySystem, version); EXPECT_EQ(rv, test.mShouldPass) << "parse should succeed if expected to"; if (!test.mShouldPass) {
--- a/dom/media/webrtc/MediaEngineDefault.cpp +++ b/dom/media/webrtc/MediaEngineDefault.cpp @@ -54,17 +54,17 @@ MediaEngineDefaultVideoSource::MediaEngi } MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource() {} void MediaEngineDefaultVideoSource::GetName(nsAString& aName) const { - aName.AssignLiteral(MOZ_UTF16("Default Video Device")); + aName.AssignLiteral(u"Default Video Device"); return; } void MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID) const { aUUID.AssignLiteral("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676"); return; @@ -382,17 +382,17 @@ MediaEngineDefaultAudioSource::MediaEngi } MediaEngineDefaultAudioSource::~MediaEngineDefaultAudioSource() {} void MediaEngineDefaultAudioSource::GetName(nsAString& aName) const { - aName.AssignLiteral(MOZ_UTF16("Default Audio Device")); + aName.AssignLiteral(u"Default Audio Device"); return; } void MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID) const { aUUID.AssignLiteral("B7CBD7C1-53EF-42F9-8353-73F61C70C092"); return;
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp @@ -117,17 +117,17 @@ MediaEngineTabVideoSource::InitRunnable: nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource)); start->Run(); return NS_OK; } void MediaEngineTabVideoSource::GetName(nsAString_internal& aName) const { - aName.AssignLiteral(MOZ_UTF16("&getUserMedia.videoSource.tabShare;")); + aName.AssignLiteral(u"&getUserMedia.videoSource.tabShare;"); } void MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid) const { aUuid.AssignLiteral("tab"); }
--- a/dom/network/interfaces/nsITCPSocketCallback.idl +++ b/dom/network/interfaces/nsITCPSocketCallback.idl @@ -7,17 +7,17 @@ * to highly privileged apps. It provides a buffered, non-blocking * interface for sending. For receiving, it uses an asynchronous, * event handler based interface. */ #include "domstubs.idl" %{C++ -template<class T> class InfallibleTArray; +#include "nsTArrayForwardDeclare.h" %} [ref] native nsUint8TArrayRef(InfallibleTArray<uint8_t>); [ptr] native JSContextPtr(JSContext); /* * This interface is implemented in TCPSocket.cpp as an internal interface * for use in cross-process socket implementation.
--- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -834,21 +834,21 @@ NotificationTelemetryService::RecordSend NS_IMETHODIMP NotificationTelemetryService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { uint32_t capability; if (strcmp("perm-changed", aTopic) || - !NS_strcmp(MOZ_UTF16("cleared"), aData) || + !NS_strcmp(u"cleared", aData) || !GetNotificationPermission(aSubject, &capability)) { return NS_OK; } - if (!NS_strcmp(MOZ_UTF16("deleted"), aData)) { + if (!NS_strcmp(u"deleted", aData)) { if (capability == nsIPermissionManager::DENY_ACTION) { Telemetry::Accumulate( Telemetry::WEB_NOTIFICATION_PERMISSION_REMOVED, 0); } else if (capability == nsIPermissionManager::ALLOW_ACTION) { Telemetry::Accumulate( Telemetry::WEB_NOTIFICATION_PERMISSION_REMOVED, 1); } }
--- a/dom/performance/PerformanceObserver.cpp +++ b/dom/performance/PerformanceObserver.cpp @@ -129,21 +129,21 @@ PerformanceObserver::QueueEntry(Performa aEntry->GetEntryType(entryType); if (!mEntryTypes.Contains<nsString>(entryType)) { return; } mQueuedEntries.AppendElement(aEntry); } -static const char16_t* sValidTypeNames[4] = { - MOZ_UTF16("mark"), - MOZ_UTF16("measure"), - MOZ_UTF16("resource"), - MOZ_UTF16("server") +static const char16_t *const sValidTypeNames[4] = { + u"mark", + u"measure", + u"resource", + u"server" }; void PerformanceObserver::Observe(const PerformanceObserverInit& aOptions, ErrorResult& aRv) { if (aOptions.mEntryTypes.IsEmpty()) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
--- a/dom/plugins/ipc/PluginHangUIParent.cpp +++ b/dom/plugins/ipc/PluginHangUIParent.cpp @@ -382,17 +382,17 @@ PluginHangUIParent::GetHangUIOwnerWindow windowHandle = nullptr; nsresult rv; nsCOMPtr<nsIWindowMediator> winMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIDOMWindowProxy> navWin; - rv = winMediator->GetMostRecentWindow(MOZ_UTF16("navigator:browser"), + rv = winMediator->GetMostRecentWindow(u"navigator:browser", getter_AddRefs(navWin)); NS_ENSURE_SUCCESS(rv, rv); if (!navWin) { return NS_ERROR_FAILURE; } nsPIDOMWindowOuter* win = nsPIDOMWindowOuter::From(navWin); nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(win);
--- a/dom/presentation/PresentationDeviceManager.cpp +++ b/dom/presentation/PresentationDeviceManager.cpp @@ -176,17 +176,17 @@ PresentationDeviceManager::AddDevice(nsI MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(mDevices.Contains(aDevice))) { return NS_ERROR_FAILURE; } mDevices.AppendElement(aDevice); - NotifyDeviceChange(aDevice, MOZ_UTF16("add")); + NotifyDeviceChange(aDevice, u"add"); return NS_OK; } NS_IMETHODIMP PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice) { NS_ENSURE_ARG(aDevice); @@ -194,32 +194,32 @@ PresentationDeviceManager::RemoveDevice( int32_t index = mDevices.IndexOf(aDevice); if (NS_WARN_IF(index < 0)) { return NS_ERROR_FAILURE; } mDevices.RemoveElementAt(index); - NotifyDeviceChange(aDevice, MOZ_UTF16("remove")); + NotifyDeviceChange(aDevice, u"remove"); return NS_OK; } NS_IMETHODIMP PresentationDeviceManager::UpdateDevice(nsIPresentationDevice* aDevice) { NS_ENSURE_ARG(aDevice); MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!mDevices.Contains(aDevice))) { return NS_ERROR_FAILURE; } - NotifyDeviceChange(aDevice, MOZ_UTF16("update")); + NotifyDeviceChange(aDevice, u"update"); return NS_OK; } NS_IMETHODIMP PresentationDeviceManager::OnSessionRequest(nsIPresentationDevice* aDevice, const nsAString& aUrl, const nsAString& aPresentationId,
--- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -140,17 +140,19 @@ QuotaUsageRequestChild::HandleResponse(n } void QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - mRequest->SetResult(aResponse.usage(), aResponse.fileUsage()); + mRequest->SetResult(aResponse.usage(), + aResponse.fileUsage(), + aResponse.limit()); } void QuotaUsageRequestChild::ActorDestroy(ActorDestroyReason aWhy) { AssertIsOnOwningThread(); if (mRequest) {
--- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1003,21 +1003,26 @@ private: virtual bool RecvStopIdleMaintenance() override; }; class GetUsageOp final : public NormalOriginOperationBase , public PQuotaUsageRequestParent { + // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage + // and the file usage. Otherwise, we use it to record the group usage and the + // limit. UsageInfo mUsageInfo; const UsageParams mParams; + nsCString mSuffix; nsCString mGroup; bool mIsApp; + bool mGetGroupUsage; public: explicit GetUsageOp(const UsageRequestParams& aParams); bool Init(Quota* aQuota); private: @@ -4578,16 +4583,50 @@ QuotaManager::GetGroupLimit() const uint64_t x = std::min<uint64_t>(mTemporaryStorageLimit * .20, 2 GB); // In low-storage situations, make an exception (while not exceeding the total // storage limit). return std::min<uint64_t>(mTemporaryStorageLimit, std::max<uint64_t>(x, 10 MB)); } +void +QuotaManager::GetGroupUsageAndLimit(const nsACString& aGroup, + UsageInfo* aUsageInfo) +{ + AssertIsOnIOThread(); + MOZ_ASSERT(aUsageInfo); + + { + MutexAutoLock lock(mQuotaMutex); + + aUsageInfo->SetLimit(GetGroupLimit()); + aUsageInfo->ResetUsage(); + + GroupInfoPair* pair; + if (!mGroupInfoPairs.Get(aGroup, &pair)) { + return; + } + + // Calculate temporary group usage + RefPtr<GroupInfo> temporaryGroupInfo = + pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY); + if (temporaryGroupInfo) { + aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage); + } + + // Calculate default group usage + RefPtr<GroupInfo> defaultGroupInfo = + pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT); + if (defaultGroupInfo) { + aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage); + } + } +} + // static void QuotaManager::GetStorageId(PersistenceType aPersistenceType, const nsACString& aOrigin, Client::Type aClientType, nsACString& aDatabaseId) { nsAutoCString str; @@ -5840,16 +5879,17 @@ Quota::RecvStopIdleMaintenance() return true; } GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) : NormalOriginOperationBase(Nullable<PersistenceType>(), OriginScope::FromNull(), /* aExclusive */ false) , mParams(aParams.get_UsageParams()) + , mGetGroupUsage(aParams.get_UsageParams().getGroupUsage()) { AssertIsOnOwningThread(); MOZ_ASSERT(aParams.type() == UsageRequestParams::TUsageParams); } bool GetUsageOp::Init(Quota* aQuota) { @@ -5875,17 +5915,17 @@ GetUsageOp::DoInitOnMainThread() nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(principalInfo, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Figure out which origin we're dealing with. nsCString origin; - rv = QuotaManager::GetInfoFromPrincipal(principal, nullptr, &mGroup, &origin, + rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, &origin, &mIsApp); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } mOriginScope.SetFromOrigin(origin); return NS_OK; @@ -5990,22 +6030,44 @@ GetUsageOp::AddToUsage(QuotaManager* aQu return NS_OK; } nsresult GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { AssertIsOnIOThread(); + MOZ_ASSERT(mUsageInfo.TotalUsage() == 0); PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork", js::ProfileEntry::Category::OTHER); + nsresult rv; + + if (mGetGroupUsage) { + nsCOMPtr<nsIFile> directory; + + // Ensure origin is initialized first. It will initialize all origins for + // temporary storage including origins belonging to our group. + rv = aQuotaManager->EnsureOriginIsInitialized(PERSISTENCE_TYPE_TEMPORARY, + mSuffix, mGroup, + mOriginScope.GetOrigin(), + mIsApp, + getter_AddRefs(directory)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Get cached usage and limit (the method doesn't have to stat any files). + aQuotaManager->GetGroupUsageAndLimit(mGroup, &mUsageInfo); + + return NS_OK; + } + // Add all the persistent/temporary/default storage files we care about. - nsresult rv; for (const PersistenceType type : kAllPersistenceTypes) { rv = AddToUsage(aQuotaManager, type); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } return NS_OK; @@ -6024,18 +6086,27 @@ GetUsageOp::SendResults() if (mUsageInfo.Canceled()) { mResultCode = NS_ERROR_FAILURE; } UsageRequestResponse response; if (NS_SUCCEEDED(mResultCode)) { UsageResponse usageResponse; + + // We'll get the group usage when mGetGroupUsage is true and get the + // origin usage when mGetGroupUsage is false. usageResponse.usage() = mUsageInfo.TotalUsage(); - usageResponse.fileUsage() = mUsageInfo.FileUsage(); + + if (mGetGroupUsage) { + usageResponse.limit() = mUsageInfo.Limit(); + } else { + usageResponse.fileUsage() = mUsageInfo.FileUsage(); + } + response = usageResponse; } else { response = mResultCode; } Unused << PQuotaUsageRequestParent::Send__delete__(this, response); } }
--- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -15,16 +15,17 @@ using mozilla::dom::quota::PersistenceTy namespace mozilla { namespace dom { namespace quota { struct UsageParams { PrincipalInfo principalInfo; + bool getGroupUsage; }; union UsageRequestParams { UsageParams; }; struct ClearOriginParams
--- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -7,16 +7,17 @@ include protocol PQuota; namespace mozilla { namespace dom { namespace quota { struct UsageResponse { uint64_t usage; uint64_t fileUsage; + uint64_t limit; }; union UsageRequestResponse { nsresult; UsageResponse; };
--- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -342,16 +342,20 @@ public: MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT); return mDefaultStoragePath; } uint64_t GetGroupLimit() const; + void + GetGroupUsageAndLimit(const nsACString& aGroup, + UsageInfo* aUsageInfo); + static void GetStorageId(PersistenceType aPersistenceType, const nsACString& aOrigin, Client::Type aClientType, nsACString& aDatabaseId); static nsresult GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
--- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -492,39 +492,41 @@ NS_IMPL_ADDREF(QuotaManagerService) NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService, Destroy()) NS_IMPL_QUERY_INTERFACE(QuotaManagerService, nsIQuotaManagerService, nsIObserver) NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, + bool aGetGroupUsage, nsIQuotaUsageRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); RefPtr<UsageRequest> request = new UsageRequest(aPrincipal, aCallback); UsageParams params; PrincipalInfo& principalInfo = params.principalInfo(); - nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo && principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) { return NS_ERROR_UNEXPECTED; } + params.getGroupUsage() = aGetGroupUsage; + nsAutoPtr<PendingRequestInfo> info(new UsageRequestInfo(request, params)); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval);
--- a/dom/quota/QuotaRequests.cpp +++ b/dom/quota/QuotaRequests.cpp @@ -87,21 +87,22 @@ RequestBase::GetResultCode(nsresult* aRe return NS_ERROR_FAILURE; } *aResultCode = mResultCode; return NS_OK; } UsageRequest::UsageRequest(nsIPrincipal* aPrincipal, - nsIQuotaUsageCallback* aCallback) + nsIQuotaUsageCallback* aCallback) : RequestBase(aPrincipal) , mCallback(aCallback) , mUsage(0) , mFileUsage(0) + , mLimit(0) , mBackgroundActor(nullptr) , mCanceled(false) { AssertIsOnOwningThread(); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); } @@ -120,23 +121,24 @@ UsageRequest::SetBackgroundActor(QuotaUs mBackgroundActor = aBackgroundActor; if (mCanceled) { mBackgroundActor->SendCancel(); } } void -UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage) +UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit) { AssertIsOnOwningThread(); MOZ_ASSERT(!mHaveResultOrErrorCode); mUsage = aUsage; mFileUsage = aFileUsage; + mLimit = aLimit; mHaveResultOrErrorCode = true; FireCallback(); } NS_IMPL_CYCLE_COLLECTION_INHERITED(UsageRequest, RequestBase, mCallback) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UsageRequest) @@ -169,16 +171,30 @@ UsageRequest::GetFileUsage(uint64_t* aFi return NS_ERROR_FAILURE; } *aFileUsage = mFileUsage; return NS_OK; } NS_IMETHODIMP +UsageRequest::GetLimit(uint64_t* aLimit) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aLimit); + + if (!mHaveResultOrErrorCode) { + return NS_ERROR_FAILURE; + } + + *aLimit = mLimit; + return NS_OK; +} + +NS_IMETHODIMP UsageRequest::GetCallback(nsIQuotaUsageCallback** aCallback) { AssertIsOnOwningThread(); MOZ_ASSERT(aCallback); NS_IF_ADDREF(*aCallback = mCallback); return NS_OK; }
--- a/dom/quota/QuotaRequests.h +++ b/dom/quota/QuotaRequests.h @@ -69,16 +69,19 @@ class UsageRequest final : public RequestBase , public nsIQuotaUsageRequest { nsCOMPtr<nsIQuotaUsageCallback> mCallback; uint64_t mUsage; uint64_t mFileUsage; + // Group Limit. + uint64_t mLimit; + QuotaUsageRequestChild* mBackgroundActor; bool mCanceled; public: UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback); @@ -89,17 +92,17 @@ public: ClearBackgroundActor() { AssertIsOnOwningThread(); mBackgroundActor = nullptr; } void - SetResult(uint64_t aUsage, uint64_t aFileUsage); + SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIQUOTAREQUESTBASE(RequestBase::) NS_DECL_NSIQUOTAUSAGEREQUEST NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(UsageRequest, RequestBase) private: ~UsageRequest();
--- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -13,17 +13,17 @@ #include "mozilla/CheckedInt.h" BEGIN_QUOTA_NAMESPACE class UsageInfo { public: UsageInfo() - : mCanceled(false), mDatabaseUsage(0), mFileUsage(0) + : mCanceled(false), mDatabaseUsage(0), mFileUsage(0), mLimit(0) { } virtual ~UsageInfo() { } bool Canceled() { @@ -47,29 +47,41 @@ public: } void AppendToFileUsage(uint64_t aUsage) { IncrementUsage(&mFileUsage, aUsage); } + void + SetLimit(uint64_t aLimit) + { + mLimit = aLimit; + } + uint64_t DatabaseUsage() { return mDatabaseUsage; } uint64_t FileUsage() { return mFileUsage; } uint64_t + Limit() + { + return mLimit; + } + + uint64_t TotalUsage() { uint64_t totalUsage = mDatabaseUsage; IncrementUsage(&totalUsage, mFileUsage); return totalUsage; } void @@ -93,13 +105,14 @@ public: } protected: mozilla::Atomic<bool> mCanceled; private: uint64_t mDatabaseUsage; uint64_t mFileUsage; + uint64_t mLimit; }; END_QUOTA_NAMESPACE #endif // mozilla_dom_quota_usageinfo_h__
--- a/dom/quota/nsIQuotaManagerService.idl +++ b/dom/quota/nsIQuotaManagerService.idl @@ -17,20 +17,26 @@ interface nsIQuotaManagerService : nsISu /** * Schedules an asynchronous callback that will return the total amount of * disk space being used by storages for the given origin. * * @param aPrincipal * A principal for the origin whose usage is being queried. * @param aCallback * The callback that will be called when the usage is available. + * @param aGetGroupUsage + * An optional flag to indicate whether getting group usage and limit + * or origin usage and file usage. The default value is false. + * Note: Origin usage here represents total usage of an origin. However, + * group usage here represents only non-persistent usage of a group. */ nsIQuotaUsageRequest getUsageForPrincipal(in nsIPrincipal aPrincipal, - in nsIQuotaUsageCallback aCallback); + in nsIQuotaUsageCallback aCallback, + [optional] in boolean aGetGroupUsage); /** * Removes all storages. The files may not be deleted immediately depending * on prohibitive concurrent operations. * Be careful, this removes *all* the data that has ever been stored! * * If the dom.quotaManager.testing preference is not true the call will be * a no-op.
--- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -20,16 +20,18 @@ interface nsIQuotaRequestBase : nsISuppo [scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)] interface nsIQuotaUsageRequest : nsIQuotaRequestBase { readonly attribute unsigned long long usage; readonly attribute unsigned long long fileUsage; + readonly attribute unsigned long long limit; + attribute nsIQuotaUsageCallback callback; void cancel(); }; [scriptable, uuid(22890e3e-ff25-4372-9684-d901060e2f6c)] interface nsIQuotaRequest : nsIQuotaRequestBase
--- a/dom/security/ContentVerifier.cpp +++ b/dom/security/ContentVerifier.cpp @@ -2,374 +2,229 @@ /* 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 "ContentVerifier.h" #include "mozilla/fallible.h" #include "mozilla/Logging.h" -#include "mozilla/Preferences.h" -#include "mozilla/StaticPtr.h" -#include "nsCharSeparatedTokenizer.h" +#include "MainThreadUtils.h" #include "nsIInputStream.h" #include "nsIRequest.h" -#include "nssb64.h" -#include "nsSecurityHeaderParser.h" #include "nsServiceManagerUtils.h" #include "nsStringStream.h" -#include "nsThreadUtils.h" using namespace mozilla; static LazyLogModule gContentVerifierPRLog("ContentVerifier"); #define CSV_LOG(args) MOZ_LOG(gContentVerifierPRLog, LogLevel::Debug, args) -// Content-Signature prefix -const nsLiteralCString kPREFIX = NS_LITERAL_CSTRING("Content-Signature:\x00"); - -NS_IMPL_ISUPPORTS(ContentVerifier, nsIStreamListener, nsISupports); +NS_IMPL_ISUPPORTS(ContentVerifier, + nsIContentSignatureReceiverCallback, + nsIStreamListener); nsresult -ContentVerifier::Init(const nsAString& aContentSignatureHeader) +ContentVerifier::Init(const nsACString& aContentSignatureHeader, + nsIRequest* aRequest, nsISupports* aContext) { - mVks = Preferences::GetString("browser.newtabpage.remote.keys"); - - if (aContentSignatureHeader.IsEmpty() || mVks.IsEmpty()) { - CSV_LOG( - ("Content-Signature header and verification keys must not be empty!\n")); + MOZ_ASSERT(NS_IsMainThread()); + if (aContentSignatureHeader.IsEmpty()) { + CSV_LOG(("Content-Signature header must not be empty!\n")); return NS_ERROR_INVALID_SIGNATURE; } - nsresult rv = ParseContentSignatureHeader(aContentSignatureHeader); - NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_SIGNATURE); - return CreateContext(); + // initialise the content signature "service" + nsresult rv; + mVerifier = + do_CreateInstance("@mozilla.org/security/contentsignatureverifier;1", &rv); + if (NS_FAILED(rv) || !mVerifier) { + return NS_ERROR_INVALID_SIGNATURE; + } + + // Keep references to the request and context. We need them in FinishSignature + // and the ContextCreated callback. + mContentRequest = aRequest; + mContentContext = aContext; + + rv = mVerifier->CreateContextWithoutCertChain( + this, aContentSignatureHeader, + NS_LITERAL_CSTRING("remote-newtab-signer.mozilla.org")); + if (NS_FAILED(rv)){ + mVerifier = nullptr; + } + return rv; } /** * Implement nsIStreamListener * We buffer the entire content here and kick off verification */ NS_METHOD AppendNextSegment(nsIInputStream* aInputStream, void* aClosure, const char* aRawSegment, uint32_t aToOffset, uint32_t aCount, uint32_t* outWrittenCount) { FallibleTArray<nsCString>* decodedData = static_cast<FallibleTArray<nsCString>*>(aClosure); - nsAutoCString segment(aRawSegment, aCount); + nsDependentCSubstring segment(aRawSegment, aCount); if (!decodedData->AppendElement(segment, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } *outWrittenCount = aCount; return NS_OK; } +void +ContentVerifier::FinishSignature() +{ + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsIStreamListener> nextListener; + nextListener.swap(mNextListener); + + // Verify the content: + // If this fails, we return an invalid signature error to load a fallback page. + // If everthing is good, we return a new stream to the next listener and kick + // that one off. + bool verified = false; + nsresult rv = NS_OK; + + // If the content signature check fails, stop the load + // and return a signature error. NSS resources are freed by the + // ContentSignatureVerifier on destruction. + if (NS_FAILED(mVerifier->End(&verified)) || !verified) { + CSV_LOG(("failed to verify content\n")); + (void)nextListener->OnStopRequest(mContentRequest, mContentContext, + NS_ERROR_INVALID_SIGNATURE); + return; + } + CSV_LOG(("Successfully verified content signature.\n")); + + // We emptied the input stream so we have to create a new one from mContent + // to hand it to the consuming listener. + uint64_t offset = 0; + for (uint32_t i = 0; i < mContent.Length(); ++i) { + nsCOMPtr<nsIInputStream> oInStr; + rv = NS_NewCStringInputStream(getter_AddRefs(oInStr), mContent[i]); + if (NS_FAILED(rv)) { + break; + } + // let the next listener know that there is data in oInStr + rv = nextListener->OnDataAvailable(mContentRequest, mContentContext, oInStr, + offset, mContent[i].Length()); + offset += mContent[i].Length(); + if (NS_FAILED(rv)) { + break; + } + } + + // propagate OnStopRequest and return + nextListener->OnStopRequest(mContentRequest, mContentContext, rv); +} + NS_IMETHODIMP ContentVerifier::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) { + MOZ_CRASH("This OnStartRequest should've never been called!"); return NS_OK; } NS_IMETHODIMP ContentVerifier::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus) { - // Verify the content: - // If this fails, we return an invalid signature error to load a fallback page. - // If everthing is good, we return a new stream to the next listener and kick - // that one of. - CSV_LOG(("VerifySignedContent, b64signature: %s\n", mSignature.get())); - CSV_LOG(("VerifySignedContent, key: \n[\n%s\n]\n", mKey.get())); - bool verified = false; - nsresult rv = End(&verified); - if (NS_FAILED(rv) || !verified || NS_FAILED(aStatus)) { - // cancel the request and return error - if (NS_FAILED(aStatus)) { - rv = aStatus; - } else { - rv = NS_ERROR_INVALID_SIGNATURE; - } - CSV_LOG(("failed to verify content\n")); - mNextListener->OnStartRequest(aRequest, aContext); - mNextListener->OnStopRequest(aRequest, aContext, rv); - return NS_ERROR_INVALID_SIGNATURE; - } - CSV_LOG(("Successfully verified content signature.\n")); - - // start the next listener - rv = mNextListener->OnStartRequest(aRequest, aContext); - if (NS_SUCCEEDED(rv)) { - // We emptied aInStr so we have to create a new one from buf to hand it - // to the consuming listener. - for (uint32_t i = 0; i < mContent.Length(); ++i) { - nsCOMPtr<nsIInputStream> oInStr; - rv = NS_NewCStringInputStream(getter_AddRefs(oInStr), mContent[i]); - if (NS_FAILED(rv)) { - break; - } - // let the next listener know that there is data in oInStr - rv = mNextListener->OnDataAvailable(aRequest, aContext, oInStr, 0, - mContent[i].Length()); - if (NS_FAILED(rv)) { - break; - } - } + // If we don't have a next listener, we handed off this request already. + // Return, there's nothing to do here. + if (!mNextListener) { + return NS_OK; } - // propagate OnStopRequest and return - return mNextListener->OnStopRequest(aRequest, aContext, rv); + if (NS_FAILED(aStatus)) { + CSV_LOG(("Stream failed\n")); + nsCOMPtr<nsIStreamListener> nextListener; + nextListener.swap(mNextListener); + return nextListener->OnStopRequest(aRequest, aContext, aStatus); + } + + mContentRead = true; + + // If the ContentSignatureVerifier is initialised, finish the verification. + if (mContextCreated) { + FinishSignature(); + return aStatus; + } + + return NS_OK; } NS_IMETHODIMP ContentVerifier::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aInputStream, uint64_t aOffset, uint32_t aCount) { // buffer the entire stream uint32_t read; nsresult rv = aInputStream->ReadSegments(AppendNextSegment, &mContent, aCount, &read); if (NS_FAILED(rv)) { return rv; } - // update the signature verifier - return Update(mContent[mContent.Length()-1]); -} - -/** - * ContentVerifier logic and utils - */ - -nsresult -ContentVerifier::GetVerificationKey(const nsAString& aKeyId) -{ - // get verification keys from the pref and see if we have |aKeyId| - nsCharSeparatedTokenizer tokenizerVK(mVks, ';'); - while (tokenizerVK.hasMoreTokens()) { - nsDependentSubstring token = tokenizerVK.nextToken(); - nsCharSeparatedTokenizer tokenizerKey(token, '='); - nsString prefKeyId; - if (tokenizerKey.hasMoreTokens()) { - prefKeyId = tokenizerKey.nextToken(); - } - nsString key; - if (tokenizerKey.hasMoreTokens()) { - key = tokenizerKey.nextToken(); - } - if (prefKeyId.Equals(aKeyId)) { - mKey.Assign(NS_ConvertUTF16toUTF8(key)); - return NS_OK; - } - } - - // we didn't find the appropriate key - return NS_ERROR_INVALID_SIGNATURE; -} - -nsresult -ContentVerifier::ParseContentSignatureHeader( - const nsAString& aContentSignatureHeader) -{ - // We only support p384 ecdsa according to spec - NS_NAMED_LITERAL_CSTRING(keyid_var, "keyid"); - NS_NAMED_LITERAL_CSTRING(signature_var, "p384ecdsa"); - - nsAutoString contentSignature; - nsAutoString keyId; - nsAutoCString header = NS_ConvertUTF16toUTF8(aContentSignatureHeader); - nsSecurityHeaderParser parser(header.get()); - nsresult rv = parser.Parse(); - if (NS_FAILED(rv)) { - CSV_LOG(("ContentVerifier: could not parse ContentSignature header\n")); - return NS_ERROR_INVALID_SIGNATURE; - } - LinkedList<nsSecurityHeaderDirective>* directives = parser.GetDirectives(); - - for (nsSecurityHeaderDirective* directive = directives->getFirst(); - directive != nullptr; directive = directive->getNext()) { - CSV_LOG(("ContentVerifier: found directive %s\n", directive->mName.get())); - if (directive->mName.Length() == keyid_var.Length() && - directive->mName.EqualsIgnoreCase(keyid_var.get(), - keyid_var.Length())) { - if (!keyId.IsEmpty()) { - CSV_LOG(("ContentVerifier: found two keyIds\n")); - return NS_ERROR_INVALID_SIGNATURE; - } - - CSV_LOG(("ContentVerifier: found a keyid directive\n")); - keyId = NS_ConvertUTF8toUTF16(directive->mValue); - rv = GetVerificationKey(keyId); - NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_SIGNATURE); - } - if (directive->mName.Length() == signature_var.Length() && - directive->mName.EqualsIgnoreCase(signature_var.get(), - signature_var.Length())) { - if (!contentSignature.IsEmpty()) { - CSV_LOG(("ContentVerifier: found two ContentSignatures\n")); - return NS_ERROR_INVALID_SIGNATURE; - } - - CSV_LOG(("ContentVerifier: found a ContentSignature directive\n")); - contentSignature = NS_ConvertUTF8toUTF16(directive->mValue); - mSignature = directive->mValue; - } - } - - // we have to ensure that we found a key and a signature at this point - if (mKey.IsEmpty()) { - CSV_LOG(("ContentVerifier: got a Content-Signature header but didn't find " - "an appropriate key.\n")); - return NS_ERROR_INVALID_SIGNATURE; - } - if (mSignature.IsEmpty()) { - CSV_LOG(("ContentVerifier: got a Content-Signature header but didn't find " - "a signature.\n")); - return NS_ERROR_INVALID_SIGNATURE; + // Update the signature verifier if the context has been created. + if (mContextCreated) { + return mVerifier->Update(mContent.LastElement()); } return NS_OK; } -/** - * Parse signature, public key, and algorithm data for input to verification - * functions in VerifyData and CreateContext. - * - * https://datatracker.ietf.org/doc/draft-thomson-http-content-signature/ - * If aSignature is a content signature, the function returns - * NS_ERROR_INVALID_SIGNATURE if anything goes wrong. Only p384 with sha384 - * is supported and aSignature is a raw signature (r||s). - */ -nsresult -ContentVerifier::ParseInput(ScopedSECKEYPublicKey& aPublicKeyOut, - ScopedSECItem& aSignatureItemOut, - SECOidTag& aOidOut, - const nsNSSShutDownPreventionLock&) +NS_IMETHODIMP +ContentVerifier::ContextCreated(bool successful) { - // Base 64 decode the key - ScopedSECItem keyItem(::SECITEM_AllocItem(nullptr, nullptr, 0)); - if (!keyItem || - !NSSBase64_DecodeBuffer(nullptr, keyItem, - mKey.get(), - mKey.Length())) { - return NS_ERROR_INVALID_SIGNATURE; - } + MOZ_ASSERT(NS_IsMainThread()); + if (!successful) { + // If we don't have a next listener, the request has been handed off already. + if (!mNextListener) { + return NS_OK; + } + // Get local reference to mNextListener and null it to ensure that we don't + // call it twice. + nsCOMPtr<nsIStreamListener> nextListener; + nextListener.swap(mNextListener); + + // Make sure that OnStartRequest was called and we have a request. + MOZ_ASSERT(mContentRequest); - // Extract the public key from the keyItem - ScopedCERTSubjectPublicKeyInfo pki( - SECKEY_DecodeDERSubjectPublicKeyInfo(keyItem)); - if (!pki) { - return NS_ERROR_INVALID_SIGNATURE; - } - aPublicKeyOut = SECKEY_ExtractPublicKey(pki.get()); + // In this case something went wrong with the cert. Let's stop this load. + CSV_LOG(("failed to get a valid cert chain\n")); + if (mContentRequest && nextListener) { + mContentRequest->Cancel(NS_ERROR_INVALID_SIGNATURE); + nsresult rv = nextListener->OnStopRequest(mContentRequest, mContentContext, + NS_ERROR_INVALID_SIGNATURE); + mContentRequest = nullptr; + mContentContext = nullptr; + return rv; + } - // in case we were not able to extract a key - if (!aPublicKeyOut) { - return NS_ERROR_INVALID_SIGNATURE; - } - - // Base 64 decode the signature - ScopedSECItem rawSignatureItem(::SECITEM_AllocItem(nullptr, nullptr, 0)); - if (!rawSignatureItem || - !NSSBase64_DecodeBuffer(nullptr, rawSignatureItem, - mSignature.get(), - mSignature.Length())) { - return NS_ERROR_INVALID_SIGNATURE; + // We should never get here! + MOZ_ASSERT_UNREACHABLE( + "ContentVerifier was used without getting OnStartRequest!"); + return NS_OK; } - // get signature object and oid - if (!aSignatureItemOut) { - return NS_ERROR_INVALID_SIGNATURE; - } - // We have a raw ecdsa signature r||s so we have to DER-encode it first - // Note that we have to check rawSignatureItem->len % 2 here as - // DSAU_EncodeDerSigWithLen asserts this - if (rawSignatureItem->len == 0 || rawSignatureItem->len % 2 != 0) { - return NS_ERROR_INVALID_SIGNATURE; - } - if (DSAU_EncodeDerSigWithLen(aSignatureItemOut, rawSignatureItem, - rawSignatureItem->len) != SECSuccess) { - return NS_ERROR_INVALID_SIGNATURE; - } - aOidOut = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; - - return NS_OK; -} - -/** - * Create a context for a signature verification. - * It sets signature, public key, and algorithms that should be used to verify - * the data. It also updates the verification buffer with the content-signature - * prefix. - */ -nsresult -ContentVerifier::CreateContext() -{ - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return NS_ERROR_INVALID_SIGNATURE; + // In this case the content verifier is initialised and we have to feed it + // the buffered content. + mContextCreated = true; + for (size_t i = 0; i < mContent.Length(); ++i) { + if (NS_FAILED(mVerifier->Update(mContent[i]))) { + // Bail out if this fails. We can't return an error here, but if this + // failed, NS_ERROR_INVALID_SIGNATURE is returned in FinishSignature. + break; + } } - // Bug 769521: We have to change b64 url to regular encoding as long as we - // don't have a b64 url decoder. This should change soon, but in the meantime - // we have to live with this. - mSignature.ReplaceChar('-', '+'); - mSignature.ReplaceChar('_', '/'); - - ScopedSECKEYPublicKey publicKey; - ScopedSECItem signatureItem(::SECITEM_AllocItem(nullptr, nullptr, 0)); - SECOidTag oid; - nsresult rv = ParseInput(publicKey, signatureItem, oid, locker); - if (NS_FAILED(rv)) { - return NS_ERROR_INVALID_SIGNATURE; - } - - mCx = UniqueVFYContext(VFY_CreateContext(publicKey, signatureItem, oid, NULL)); - if (!mCx) { - return NS_ERROR_INVALID_SIGNATURE; - } - - if (VFY_Begin(mCx.get()) != SECSuccess) { - return NS_ERROR_INVALID_SIGNATURE; - } - - // add the prefix to the verification buffer - return Update(kPREFIX); -} - -/** - * Add data to the context that should be verified. - */ -nsresult -ContentVerifier::Update(const nsACString& aData) -{ - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return NS_ERROR_INVALID_SIGNATURE; - } - - if (!aData.IsEmpty()) { - if (VFY_Update(mCx.get(), - (const unsigned char*)nsPromiseFlatCString(aData).get(), - aData.Length()) != SECSuccess) { - return NS_ERROR_INVALID_SIGNATURE; - } + // We read all content, let's verify the signature. + if (mContentRead) { + FinishSignature(); } return NS_OK; } - -/** - * Finish signature verification and return the result in _retval. - */ -nsresult -ContentVerifier::End(bool* _retval) -{ - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return NS_ERROR_INVALID_SIGNATURE; - } - - *_retval = (VFY_End(mCx.get()) == SECSuccess); - - return NS_OK; -} \ No newline at end of file
--- a/dom/security/ContentVerifier.h +++ b/dom/security/ContentVerifier.h @@ -2,97 +2,63 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_ContentVerifier_h #define mozilla_dom_ContentVerifier_h #include "nsCOMPtr.h" +#include "nsIContentSignatureVerifier.h" #include "nsIObserver.h" #include "nsIStreamListener.h" -#include "nsNSSShutDown.h" #include "nsString.h" #include "nsTArray.h" -#include "ScopedNSSTypes.h" /** * Mediator intercepting OnStartRequest in nsHttpChannel, blocks until all * data is read from the input stream, verifies the content signature and * releases the request to the next listener if the verification is successful. * If the verification fails or anything else goes wrong, a * NS_ERROR_INVALID_SIGNATURE is thrown. */ class ContentVerifier : public nsIStreamListener - , public nsNSSShutDownObject + , public nsIContentSignatureReceiverCallback { public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSICONTENTSIGNATURERECEIVERCALLBACK explicit ContentVerifier(nsIStreamListener* aMediatedListener, nsISupports* aMediatedContext) : mNextListener(aMediatedListener) - , mContext(aMediatedContext) - , mCx(nullptr) {} - - nsresult Init(const nsAString& aContentSignatureHeader); + , mContextCreated(false) + , mContentRead(false) {} - // nsNSSShutDownObject - virtual void virtualDestroyNSSReference() override - { - destructorSafeDestroyNSSReference(); - } + nsresult Init(const nsACString& aContentSignatureHeader, nsIRequest* aRequest, + nsISupports* aContext); protected: - virtual ~ContentVerifier() - { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return; - } - destructorSafeDestroyNSSReference(); - shutdown(calledFromObject); - } - - void destructorSafeDestroyNSSReference() - { - mCx = nullptr; - } + virtual ~ContentVerifier() {} private: - nsresult ParseContentSignatureHeader(const nsAString& aContentSignatureHeader); - nsresult GetVerificationKey(const nsAString& aKeyId); - - // utility function to parse input before put into verification functions - nsresult ParseInput(mozilla::ScopedSECKEYPublicKey& aPublicKeyOut, - mozilla::ScopedSECItem& aSignatureItemOut, - SECOidTag& aOidOut, - const nsNSSShutDownPreventionLock&); + void FinishSignature(); - // create a verifier context and store it in mCx - nsresult CreateContext(); - - // Adds data to the context that was used to generate the signature. - nsresult Update(const nsACString& aData); - - // Finalises the signature and returns the result of the signature - // verification. - nsresult End(bool* _retval); - + // buffered content to verify + FallibleTArray<nsCString> mContent; // content and next listener for nsIStreamListener nsCOMPtr<nsIStreamListener> mNextListener; - nsCOMPtr<nsISupports> mContext; - - // verifier context for incrementel verifications - mozilla::UniqueVFYContext mCx; - // buffered content to verify - FallibleTArray<nsCString> mContent; - // signature to verify - nsCString mSignature; - // verification key - nsCString mKey; - // verification key preference - nsString mVks; + // the verifier + nsCOMPtr<nsIContentSignatureVerifier> mVerifier; + // holding a pointer to the content request and context to resume/cancel it + nsCOMPtr<nsIRequest> mContentRequest; + nsCOMPtr<nsISupports> mContentContext; + // Semaphors to indicate that the verifying context was created, the entire + // content was read resp. The context gets created by ContentSignatureVerifier + // and mContextCreated is set in the ContextCreated callback. The content is + // read, i.e. mContentRead is set, when the content OnStopRequest is called. + bool mContextCreated; + bool mContentRead; }; #endif /* mozilla_dom_ContentVerifier_h */
--- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -887,17 +887,17 @@ nsCSPContext::SendReports(nsISupports* a for (uint32_t r = 0; r < reportURIs.Length(); r++) { nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]); // try to create a new uri from every report-uri string rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]); if (NS_FAILED(rv)) { const char16_t* params[] = { reportURIs[r].get() }; CSPCONTEXTLOG(("Could not create nsIURI for report URI %s", reportURICstring.get())); - logToConsole(MOZ_UTF16("triedToSendReport"), params, ArrayLength(params), + logToConsole(u"triedToSendReport", params, ArrayLength(params), aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); continue; // don't return yet, there may be more URIs } // try to create a new channel for every report-uri nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI; if (doc) { rv = NS_NewChannel(getter_AddRefs(reportChannel), @@ -928,17 +928,17 @@ nsCSPContext::SendReports(nsISupports* a // log a warning to console if scheme is not http or https bool isHttpScheme = (NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) || (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme); if (!isHttpScheme) { const char16_t* params[] = { reportURIs[r].get() }; - logToConsole(MOZ_UTF16("reportURInotHttpsOrHttp2"), params, ArrayLength(params), + logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params), aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); continue; } // make sure this is an anonymous request (no cookies) so in case the // policy URI is injected, it can't be abused for CSRF. nsLoadFlags flags; rv = reportChannel->GetLoadFlags(&flags); @@ -991,17 +991,17 @@ nsCSPContext::SendReports(nsISupports* a // AsyncOpen should not fail, but could if there's no load group (like if // SetRequestContext is not given a channel). This should fail quietly and // not return an error since it's really ok if reports don't go out, but // it's good to log the error locally. if (NS_FAILED(rv)) { const char16_t* params[] = { reportURIs[r].get() }; CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0])); - logToConsole(MOZ_UTF16("triedToSendReport"), params, ArrayLength(params), + logToConsole(u"triedToSendReport", params, ArrayLength(params), aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); } else { CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get())); } } return NS_OK; } @@ -1076,18 +1076,18 @@ class CSPReportSenderRunnable final : pu } else if (blockedString) { blockedString->GetData(blockedDataStr); } if (blockedDataStr.Length() > 0) { nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr); const char16_t* params[] = { mViolatedDirective.get(), blockedDataChar16.get() }; - mCSPContext->logToConsole(mReportOnlyFlag ? MOZ_UTF16("CSPROViolationWithURI") : - MOZ_UTF16("CSPViolationWithURI"), + mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" : + u"CSPViolationWithURI", params, ArrayLength(params), mSourceFile, mScriptSample, mLineNum, 0, nsIScriptError::errorFlag); } return NS_OK; } private: nsCOMPtr<nsISupports> mBlockedContentSource; @@ -1350,17 +1350,17 @@ nsCSPContext::GetCSPSandboxFlags(uint32_ // continue the loop checking for an enforcement policy. nsAutoString policy; mPolicies[i]->toString(policy); CSPCONTEXTLOG(("nsCSPContext::GetCSPSandboxFlags, report only policy, ignoring sandbox in: %s", policy.get())); const char16_t* params[] = { policy.get() }; - logToConsole(MOZ_UTF16("ignoringReportOnlyDirective"), params, ArrayLength(params), + logToConsole(u"ignoringReportOnlyDirective", params, ArrayLength(params), EmptyString(), EmptyString(), 0, 0, nsIScriptError::warningFlag); } } return NS_OK; } /* ========== CSPViolationReportListener implementation ========== */ @@ -1446,17 +1446,17 @@ CSPReportRedirectSink::AsyncOnChannelRed nsCOMPtr<nsIURI> uri; rv = aOldChannel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); NS_ASSERTION(observerService, "Observer service required to log CSP violations"); observerService->NotifyObservers(uri, CSP_VIOLATION_TOPIC, - MOZ_UTF16("denied redirect while sending violation report")); + u"denied redirect while sending violation report"); return NS_BINDING_REDIRECTED; } NS_IMETHODIMP CSPReportRedirectSink::GetInterface(const nsIID& aIID, void** aResult) { if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
--- a/dom/security/nsCSPParser.cpp +++ b/dom/security/nsCSPParser.cpp @@ -1156,48 +1156,48 @@ nsCSPParser::directive() CSPPARSERLOG(("nsCSPParser::directive, mCurToken: %s, mCurValue: %s", NS_ConvertUTF16toUTF8(mCurToken).get(), NS_ConvertUTF16toUTF8(mCurValue).get())); // Make sure that the directive-srcs-array contains at least // one directive and one src. if (mCurDir.Length() < 1) { - const char16_t* params[] = { MOZ_UTF16("directive missing") }; + const char16_t* params[] = { u"directive missing" }; logWarningErrorToConsole(nsIScriptError::warningFlag, "failedToParseUnrecognizedSource", params, ArrayLength(params)); return; } // Try to create a new CSPDirective nsCSPDirective* cspDir = directiveName(); if (!cspDir) { // if we can not create a CSPDirective, we can skip parsing the srcs for that array return; } // special case handling for block-all-mixed-content, which is only specified // by a directive name but does not include any srcs. if (cspDir->equals(nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)) { if (mCurDir.Length() > 1) { - const char16_t* params[] = { MOZ_UTF16("block-all-mixed-content") }; + const char16_t* params[] = { u"block-all-mixed-content" }; logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoreSrcForDirective", params, ArrayLength(params)); } // add the directive and return mPolicy->addDirective(cspDir); return; } // special case handling for upgrade-insecure-requests, which is only specified // by a directive name but does not include any srcs. if (cspDir->equals(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) { if (mCurDir.Length() > 1) { - const char16_t* params[] = { MOZ_UTF16("upgrade-insecure-requests") }; + const char16_t* params[] = { u"upgrade-insecure-requests" }; logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoreSrcForDirective", params, ArrayLength(params)); } // add the directive and return mPolicy->addUpgradeInsecDir(static_cast<nsUpgradeInsecureDirective*>(cspDir)); return; } @@ -1228,17 +1228,17 @@ nsCSPParser::directive() // Ignore unsafe-inline within script-src or style-src if nonce // or hash is specified, see: // http://www.w3.org/TR/CSP2/#directive-script-src if ((cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) || cspDir->equals(nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE)) && mHasHashOrNonce && mUnsafeInlineKeywordSrc) { mUnsafeInlineKeywordSrc->invalidate(); // log to the console that unsafe-inline will be ignored - const char16_t* params[] = { MOZ_UTF16("'unsafe-inline'") }; + const char16_t* params[] = { u"'unsafe-inline'" }; logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcWithinScriptStyleSrc", params, ArrayLength(params)); } // Add the newly created srcs to the directive and add the directive to the policy cspDir->addSrcs(srcs); mPolicy->addDirective(cspDir); }
--- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -1,15 +1,16 @@ /* -*- 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 "nsAttrValue.h" +#include "nsCharSeparatedTokenizer.h" #include "nsContentUtils.h" #include "nsCSPUtils.h" #include "nsDebug.h" #include "nsIConsoleService.h" #include "nsICryptoHash.h" #include "nsIScriptError.h" #include "nsIServiceManager.h" #include "nsIStringBundle.h"
--- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -694,17 +694,17 @@ nsMixedContentBlocker::ShouldLoad(bool a if (docShell->GetDocument()->GetBlockAllMixedContent(isPreload)) { // log a message to the console before returning. nsAutoCString spec; rv = aContentLocation->GetSpec(spec); NS_ENSURE_SUCCESS(rv, rv); NS_ConvertUTF8toUTF16 reportSpec(spec); const char16_t* params[] = { reportSpec.get()}; - CSP_LogLocalizedStr(MOZ_UTF16("blockAllMixedContent"), + CSP_LogLocalizedStr(u"blockAllMixedContent", params, ArrayLength(params), EmptyString(), // aSourceFile EmptyString(), // aScriptSample 0, // aLineNumber 0, // aColumnNumber nsIScriptError::errorFlag, "CSP", docShell->GetDocument()->InnerWindowID()); *aDecision = REJECT_REQUEST;
--- a/dom/security/test/contentverifier/browser.ini +++ b/dom/security/test/contentverifier/browser.ini @@ -5,12 +5,15 @@ support-files = file_about_newtab_bad.html file_about_newtab_bad_csp.html file_about_newtab_bad_csp_signature file_about_newtab_good_signature file_about_newtab_bad_signature file_about_newtab_broken_signature file_about_newtab_sri.html file_about_newtab_sri_signature + goodChain.pem + head.js script.js style.css [browser_verify_content_about_newtab.js] +[browser_verify_content_about_newtab2.js]
--- a/dom/security/test/contentverifier/browser_verify_content_about_newtab.js +++ b/dom/security/test/contentverifier/browser_verify_content_about_newtab.js @@ -1,243 +1,20 @@ -/* - * Test Content-Signature for remote about:newtab - * - Bug 1226928 - allow about:newtab to load remote content - * - * This tests content-signature verification on remote about:newtab in the - * following cases (see TESTS, all failed loads display about:blank fallback): - * - good case (signature should verify and correct page is displayed) - * - reload of newtab when the siganture was invalidated after the last correct - * load - * - malformed content-signature header - * - malformed keyid directive - * - malformed p384ecdsa directive - * - wrong signature (this is not a siganture for the delivered document) - * - invalid signature (this is not even a signature) - * - loading a file that doesn't fit the key or signature - * - cache poisoning (load a malicious remote page not in newtab, subsequent - * newtab load has to load the fallback) - */ - -const ABOUT_NEWTAB_URI = "about:newtab"; - -const BASE = "https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?"; -const URI_GOOD = BASE + "sig=good&key=good&file=good&header=good"; - -const INVALIDATE_FILE = BASE + "invalidateFile=yep"; -const VALIDATE_FILE = BASE + "validateFile=yep"; - -const URI_HEADER_BASE = BASE + "sig=good&key=good&file=good&header="; -const URI_ERROR_HEADER = URI_HEADER_BASE + "error"; -const URI_KEYERROR_HEADER = URI_HEADER_BASE + "errorInKeyid"; -const URI_SIGERROR_HEADER = URI_HEADER_BASE + "errorInSignature"; -const URI_NO_HEADER = URI_HEADER_BASE + "noHeader"; - -const URI_BAD_SIG = BASE + "sig=bad&key=good&file=good&header=good"; -const URI_BROKEN_SIG = BASE + "sig=broken&key=good&file=good&header=good"; -const URI_BAD_KEY = BASE + "sig=good&key=bad&file=good&header=good"; -const URI_BAD_FILE = BASE + "sig=good&key=good&file=bad&header=good"; -const URI_BAD_ALL = BASE + "sig=bad&key=bad&file=bad&header=bad"; -const URI_BAD_CSP = BASE + "sig=bad-csp&key=good&file=bad-csp&header=good"; - -const URI_BAD_FILE_CACHED = BASE + "sig=good&key=good&file=bad&header=good&cached=true"; - -const GOOD_ABOUT_STRING = "Just a fully good testpage for Bug 1226928"; -const BAD_ABOUT_STRING = "Just a bad testpage for Bug 1226928"; -const ABOUT_BLANK = "<head></head><body></body>"; - -const URI_CLEANUP = BASE + "cleanup=true"; -const CLEANUP_DONE = "Done"; - -const URI_SRI = BASE + "sig=sri&key=good&file=sri&header=good"; -const STYLESHEET_WITHOUT_SRI_BLOCKED = "Stylesheet without SRI blocked"; -const STYLESHEET_WITH_SRI_BLOCKED = "Stylesheet with SRI blocked"; -const STYLESHEET_WITH_SRI_LOADED = "Stylesheet with SRI loaded"; -const SCRIPT_WITHOUT_SRI_BLOCKED = "Script without SRI blocked"; -const SCRIPT_WITH_SRI_BLOCKED = "Script with SRI blocked"; -const SCRIPT_WITH_SRI_LOADED = "Script with SRI loaded"; - -const CSP_TEST_SUCCESS_STRING = "CSP violation test succeeded."; - -// Needs to sync with pref "security.signed_content.CSP.default". -const SIGNED_CONTENT_CSP = `{"csp-policies":[{"report-only":false,"script-src":["https://example.com","'unsafe-inline'"],"style-src":["https://example.com"]}]}`; const TESTS = [ // { newtab (aboutURI) or regular load (url) : url, // testStrings : expected strings in the loaded page } { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] }, { "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_KEYERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_SIGERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_NO_HEADER, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_BAD_SIG, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_BROKEN_SIG, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_BAD_KEY, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_BAD_FILE, "testStrings" : [ABOUT_BLANK] }, - { "aboutURI" : URI_BAD_ALL, "testStrings" : [ABOUT_BLANK] }, { "url" : URI_BAD_FILE_CACHED, "testStrings" : [BAD_ABOUT_STRING] }, { "aboutURI" : URI_BAD_FILE_CACHED, "testStrings" : [ABOUT_BLANK] }, { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] }, { "aboutURI" : URI_SRI, "testStrings" : [ STYLESHEET_WITHOUT_SRI_BLOCKED, STYLESHEET_WITH_SRI_LOADED, SCRIPT_WITHOUT_SRI_BLOCKED, SCRIPT_WITH_SRI_LOADED, ]}, { "aboutURI" : URI_BAD_CSP, "testStrings" : [CSP_TEST_SUCCESS_STRING] }, { "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] }, ]; -var browser = null; -var aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"] - .getService(Ci.nsIAboutNewTabService); - -function pushPrefs(...aPrefs) { - return new Promise((resolve) => { - SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve); - }); -} - -/* - * run tests with input from TESTS - */ -function doTest(aExpectedStrings, reload, aUrl, aNewTabPref) { - // set about:newtab location for this test if it's a newtab test - if (aNewTabPref) { - aboutNewTabService.newTabURL = aNewTabPref; - } - - // set prefs - yield pushPrefs( - ["browser.newtabpage.remote.content-signing-test", true], - ["browser.newtabpage.remote", true], [ - "browser.newtabpage.remote.keys", - "RemoteNewTabNightlyv0=BO9QHuP6E2eLKybql8iuD4o4Np9YFDfW3D+k" + - "a70EcXXTqZcikc7Am1CwyP1xBDTpEoe6gb9SWzJmaDW3dNh1av2u90VkUM" + - "B7aHIrImjTjLNg/1oC8GRcTKM4+WzbKF00iA==;OtherKey=eKQJ2fNSId" + - "CFzL6N326EzZ/5LCeFU5eyq3enwZ5MLmvOw+3gycr4ZVRc36/EiSPsQYHE" + - "3JvJs1EKs0QCaguHFOZsHwqXMPicwp/gLdeYbuOmN2s1SEf/cxw8GtcxSA" + - "kG;RemoteNewTab=MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4k3FmG7dFo" + - "Ot3Tuzl76abTRtK8sb/r/ibCSeVKa96RbrOX2ciscz/TT8wfqBYS/8cN4z" + - "Me1+f7wRmkNrCUojZR1ZKmYM2BeiUOMlMoqk2O7+uwsn1DwNQSYP58TkvZt6" - ]); - - if (aNewTabPref === URI_BAD_CSP) { - // Use stricter CSP to test CSP violation. - yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self'; style-src 'self'"]); - } else { - // Use weaker CSP to test normal content. - yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self' 'unsafe-inline'; style-src 'self'"]); - } - - // start the test - yield BrowserTestUtils.withNewTab({ - gBrowser, - url: aUrl, - }, - function * (browser) { - // check if everything's set correct for testing - ok(Services.prefs.getBoolPref( - "browser.newtabpage.remote.content-signing-test"), - "sanity check: remote newtab signing test should be used"); - ok(Services.prefs.getBoolPref("browser.newtabpage.remote"), - "sanity check: remote newtab should be used"); - // we only check this if we really do a newtab test - if (aNewTabPref) { - ok(aboutNewTabService.overridden, - "sanity check: default URL for about:newtab should be overriden"); - is(aboutNewTabService.newTabURL, aNewTabPref, - "sanity check: default URL for about:newtab should return the new URL"); - } - - // Every valid remote newtab page must have built-in CSP. - let shouldHaveCSP = ((aUrl === ABOUT_NEWTAB_URI) && - (aNewTabPref === URI_GOOD || aNewTabPref === URI_SRI)); - - if (shouldHaveCSP) { - is(browser.contentDocument.nodePrincipal.cspJSON, SIGNED_CONTENT_CSP, - "Valid remote newtab page must have built-in CSP."); - } - - yield ContentTask.spawn( - browser, aExpectedStrings, function * (aExpectedStrings) { - for (let expectedString of aExpectedStrings) { - ok(content.document.documentElement.innerHTML.includes(expectedString), - "Expect the following value in the result\n" + expectedString + - "\nand got " + content.document.documentElement.innerHTML); - } - }); - - // for good test cases we check if a reload fails if the remote page - // changed from valid to invalid in the meantime - if (reload) { - yield BrowserTestUtils.withNewTab({ - gBrowser, - url: INVALIDATE_FILE, - }, - function * (browser2) { - yield ContentTask.spawn(browser2, null, function * () { - ok(content.document.documentElement.innerHTML.includes("Done"), - "Expect the following value in the result\n" + "Done" + - "\nand got " + content.document.documentElement.innerHTML); - }); - } - ); - - browser.reload(); - yield BrowserTestUtils.browserLoaded(browser); - - let expectedStrings = [ABOUT_BLANK]; - if (aNewTabPref == URI_SRI) { - expectedStrings = [ - STYLESHEET_WITHOUT_SRI_BLOCKED, - STYLESHEET_WITH_SRI_BLOCKED, - SCRIPT_WITHOUT_SRI_BLOCKED, - SCRIPT_WITH_SRI_BLOCKED - ]; - } - yield ContentTask.spawn(browser, expectedStrings, - function * (expectedStrings) { - for (let expectedString of expectedStrings) { - ok(content.document.documentElement.innerHTML.includes(expectedString), - "Expect the following value in the result\n" + expectedString + - "\nand got " + content.document.documentElement.innerHTML); - } - } - ); - - yield BrowserTestUtils.withNewTab({ - gBrowser, - url: VALIDATE_FILE, - }, - function * (browser2) { - yield ContentTask.spawn(browser2, null, function * () { - ok(content.document.documentElement.innerHTML.includes("Done"), - "Expect the following value in the result\n" + "Done" + - "\nand got " + content.document.documentElement.innerHTML); - }); - } - ); - } - } - ); -} - -add_task(function * test() { - // run tests from TESTS - for (let i = 0; i < TESTS.length; i++) { - let testCase = TESTS[i]; - let url = "", aNewTabPref = ""; - let reload = false; - var aExpectedStrings = testCase.testStrings; - if (testCase.aboutURI) { - url = ABOUT_NEWTAB_URI; - aNewTabPref = testCase.aboutURI; - if (aNewTabPref == URI_GOOD || aNewTabPref == URI_SRI) { - reload = true; - } - } else { - url = testCase.url; - } - - yield doTest(aExpectedStrings, reload, url, aNewTabPref); - } -}); +add_task(runTests);
new file mode 100644 --- /dev/null +++ b/dom/security/test/contentverifier/browser_verify_content_about_newtab2.js @@ -0,0 +1,19 @@ + +const TESTS = [ + // { newtab (aboutURI) or regular load (url) : url, + // testStrings : expected strings in the loaded page } + { "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] }, + { "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_KEYERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_SIGERROR_HEADER, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_NO_HEADER, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_BAD_SIG, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_BROKEN_SIG, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_BAD_X5U, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_HTTP_X5U, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_BAD_FILE, "testStrings" : [ABOUT_BLANK] }, + { "aboutURI" : URI_BAD_ALL, "testStrings" : [ABOUT_BLANK] }, + { "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] }, +]; + +add_task(runTests);
--- a/dom/security/test/contentverifier/file_about_newtab_bad_csp_signature +++ b/dom/security/test/contentverifier/file_about_newtab_bad_csp_signature @@ -1,1 +1,1 @@ -8qXVAqzuF3TsF6C750u_v_JiRu90WJXf_0xT9x0S4Fgmvolgtfu-KSWq3lYpmk2dxO8u64zaHM3iguZdWAqcSL82RFtV7OPiprt16omCbHCKfVi-Bt_rXILRlexgmRl_ \ No newline at end of file +oiypz3lb-IyJsmKNsnlp2zDrqncste8yONn9WUE6ksgJWMhSEQ9lp8vRqN0W3JPwJb6uSk16RI-tDv7uy0jxon5jL1BZpqlqIpvimg7FCQEedMKoHZwtE9an-e95sOTd \ No newline at end of file
--- a/dom/security/test/contentverifier/file_about_newtab_good_signature +++ b/dom/security/test/contentverifier/file_about_newtab_good_signature @@ -1,1 +1,1 @@ -XBKzej3i6TAFZc3VZsuCekn-4dYWJBE4-b3OOtKrOV-JIzIvAnAhnOV1aj-kEm07kh-FciIxV-Xk2QUQlRQzHO7oW7E4mXkMKkbbAcvL0CFrItTObhfhKnBnpAE9ql1O \ No newline at end of file +-mqpvTYdZX4HYQDW1nScojL7ICw5yj8UF2gzxyLbSCx9UIfHH-gWZ40F_PFtqjHxoC1J3dHDb3VedVhOYczdaLrNKbRvPrlnkdGx7Rl8qEBrtZpF1py1Z9uAGoCrgUHa \ No newline at end of file
--- a/dom/security/test/contentverifier/file_about_newtab_sri_signature +++ b/dom/security/test/contentverifier/file_about_newtab_sri_signature @@ -1,1 +1,1 @@ -i5jOnrZWwyNwrTcIjfJ6fUR-8MhhvhtMvQbdrUD7j8aHTybNolv25v9NwJAT6rVU6kgkxmD_st9Kla086CQmzYQdLhKfzgLbTDXz0-1j23fQnyjsP1_4MNIu2xTea11p \ No newline at end of file +yoIyAYiiEzdP1zpkRy3KaqdsjUy62Notku89cytwVwcH0x6fKsMCdM-df1wbk9N28CSTaIOW5kcSenFy5K3nU-zPIoqZDjQo6aSjF8hF6lrw1a1xbhfl9K3g4YJsuWsO \ No newline at end of file
--- a/dom/security/test/contentverifier/file_contentserver.sjs +++ b/dom/security/test/contentverifier/file_contentserver.sjs @@ -1,37 +1,51 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */ // sjs for remote about:newtab (bug 1226928) +"use strict"; const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.importGlobalProperties(["URLSearchParams"]); const path = "browser/dom/security/test/contentverifier/"; const goodFileName = "file_about_newtab.html"; const goodFileBase = path + goodFileName; const goodFile = FileUtils.getDir("TmpD", [], true); goodFile.append(goodFileName); const goodSignature = path + "file_about_newtab_good_signature"; -const goodKeyId = "RemoteNewTab"; +const goodX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\""; const scriptFileName = "script.js"; const cssFileName = "style.css"; const badFile = path + "file_about_newtab_bad.html"; const brokenSignature = path + "file_about_newtab_broken_signature"; const badSignature = path + "file_about_newtab_bad_signature"; -const badKeyId = "OldRemoteNewTabKey"; +const badX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=bad\""; +const httpX5UString = "\"http://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\""; const sriFile = path + "file_about_newtab_sri.html"; const sriSignature = path + "file_about_newtab_sri_signature"; const badCspFile = path + "file_about_newtab_bad_csp.html"; const badCspSignature = path + "file_about_newtab_bad_csp_signature"; +// This cert chain is copied from +// security/manager/ssl/tests/unit/test_content_signing/ +// using the certificates +// * content_signing_remote_newtab_ee.pem +// * content_signing_int.pem +// * content_signing_root.pem +const goodCertChainPath = path + "goodChain.pem"; + const tempFileNames = [goodFileName, scriptFileName, cssFileName]; // we copy the file to serve as newtab to a temp directory because // we modify it during tests. setupTestFiles(); function setupTestFiles() { for (let fileName of tempFileNames) { @@ -110,24 +124,25 @@ function cleanupTestFiles() { * sig=good&key=good&file=good&header=good&cached=no to serve pages with * content signatures * * it further handles invalidateFile=yep and validateFile=yep to change the * served file */ function handleRequest(request, response) { let params = new URLSearchParams(request.queryString); - let keyType = params.get("key"); + let x5uType = params.get("x5u"); let signatureType = params.get("sig"); let fileType = params.get("file"); let headerType = params.get("header"); let cached = params.get("cached"); let invalidateFile = params.get("invalidateFile"); let validateFile = params.get("validateFile"); let resource = params.get("resource"); + let x5uParam = params.get("x5u"); if (params.get("cleanup")) { cleanupTestFiles(); response.setHeader("Content-Type", "text/html", false); response.write("Done"); return; } @@ -166,36 +181,46 @@ function handleRequest(request, response r = "Error"; } } response.setHeader("Content-Type", "text/html", false); response.write(r); return; } + // we have to return the certificate chain on request for the x5u parameter + if (x5uParam && x5uParam == "default") { + response.setHeader("Cache-Control", "max-age=216000", false); + response.setHeader("Content-Type", "text/plain", false); + response.write(loadFile(getFileName(goodCertChainPath, "CurWorkD"))); + return; + } + // avoid confusing cache behaviours if (!cached) { response.setHeader("Cache-Control", "no-cache", false); } else { response.setHeader("Cache-Control", "max-age=3600", false); } // send HTML to test allowed/blocked behaviours response.setHeader("Content-Type", "text/html", false); // set signature header and key for Content-Signature header /* By default a good content-signature header is returned. Any broken return * value has to be indicated in the url. */ let csHeader = ""; - let keyId = goodKeyId; + let x5uString = goodX5UString; let signature = goodSignature; let file = goodFile; - if (keyType == "bad") { - keyId = badKeyId; + if (x5uType == "bad") { + x5uString = badX5UString; + } else if (x5uType == "http") { + x5uString = httpX5UString; } if (signatureType == "bad") { signature = badSignature; } else if (signatureType == "broken") { signature = brokenSignature; } else if (signatureType == "sri") { signature = sriSignature; } else if (signatureType == "bad-csp") { @@ -206,29 +231,29 @@ function handleRequest(request, response } else if (fileType == "sri") { file = getFileName(sriFile, "CurWorkD"); } else if (fileType == "bad-csp") { file = getFileName(badCspFile, "CurWorkD"); } if (headerType == "good") { // a valid content-signature header - csHeader = "keyid=" + keyId + ";p384ecdsa=" + + csHeader = "x5u=" + x5uString + ";p384ecdsa=" + loadFile(getFileName(signature, "CurWorkD")); } else if (headerType == "error") { // this content-signature header is missing ; before p384ecdsa - csHeader = "keyid=" + keyId + "p384ecdsa=" + + csHeader = "x5u=" + x5uString + "p384ecdsa=" + loadFile(getFileName(signature, "CurWorkD")); - } else if (headerType == "errorInKeyid") { + } else if (headerType == "errorInX5U") { // this content-signature header is missing the keyid directive - csHeader = "keid=" + keyId + ";p384ecdsa=" + + csHeader = "x6u=" + x5uString + ";p384ecdsa=" + loadFile(getFileName(signature, "CurWorkD")); } else if (headerType == "errorInSignature") { // this content-signature header is missing the p384ecdsa directive - csHeader = "keyid=" + keyId + ";p385ecdsa=" + + csHeader = "x5u=" + x5uString + ";p385ecdsa=" + loadFile(getFileName(signature, "CurWorkD")); } if (csHeader) { response.setHeader("Content-Signature", csHeader, false); } let result = loadFile(file);
new file mode 100644 --- /dev/null +++ b/dom/security/test/contentverifier/goodChain.pem @@ -0,0 +1,51 @@ +-----BEGIN CERTIFICATE----- +MIICSTCCATOgAwIBAgIUWQzTTfKLNZgX5ngi/ENiI2DO2kowCwYJKoZIhvcNAQEL +MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE0MTEyNzAwMDAwMFoYDzIwMTcwMjA0 +MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q +nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD +dKpuqc6jRDBCMBMGA1UdJQQMMAoGCCsGAQUFBwMDMCsGA1UdEQQkMCKCIHJlbW90 +ZS1uZXd0YWItc2lnbmVyLm1vemlsbGEub3JnMAsGCSqGSIb3DQEBCwOCAQEAc2nE +feYpA8WFyiPfZi56NgVgc8kXSKRNgplDtBHXK7gT7ICNQTSKkt+zHxnS9tAoXoix +OGKsyp/8LNIYGMr4vHVNyOGnxuiLzAYjmDxXhp3t36xOFlU5Y7UaKf9G4feMXrNH ++q1SPYlP84keo1MaC5yhTZTTmJMKkRBsCbIVhfDnL3BUczxVZmk9F+7qK/trL222 +RoAaTZW5hdXUZrX630CYs1sQHWgL0B5rg2y9bwFk7toQ34JbjS0Z25e/MZUtFz19 +5tSjAZQHlLE6fAYZ3knrxF9xVMJCZf7gQqVphJzBtgy9yvTAtlMsrf6XS6sRRngz +27HBxIpd4tYniYrtfg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC0TCCAbugAwIBAgIULYyr3v/0zZ+XiR22NH7hOcnj2FcwCwYJKoZIhvcNAQEL +MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw +MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x +nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM +wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF +4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20 +yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx +j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT +BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADfRBKSM08JF6vqz +0EA+KNc0XIEAWApuHuwX6XXWeLgo6QN4E/9qfrsaO+C366WT+JDsjDOi40wW46SA +XbguxtZQeZasNDUWp/leZix4RSJoHB7OllG1rgZJfN76zKVaXRGUmyQObkMMOJZe +wIA0OBURT8ik9Z89pD0IWrqscds71Edfjt0hHgg63wVvIaklReZXvFOD3VmSCPNn +2wB6ZzECcbhJpnzxZdsoMSGH0C6apYnNNTjqZjO90JVm/Ph/7nbi/KncYXA6ccl6 +Jz2mfiAquWIua2+CzBGbqjZVSATTpWCp+cXQJE1xka+hWUaL5HPTq1bTULRFlauZ +HGl5lJk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICzTCCAbegAwIBAgIUIVkGGA8HiO3RIKGjdOjVi+d6EVkwCwYJKoZIhvcNAQEL +MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw +MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu +Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO +7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf +qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt +HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx +uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyUwIzAMBgNVHRMEBTADAQH/MBMGA1Ud +JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAlpbRzRIPnf43AwGfMvKP +zOtntRy2nE9GlmY9I00uioHUnUrPLs8aw3UDtyiDWMGqcYysXGx9EX2Vk0POS4gf +G6PA95F6GxTtbzIEZmTPVuzA/cfc9HU3HXDPqh+dySJ8/Ta4c4vX1lgeGGAvstNe +q+9DaCGXs8MqMF8KtXNmOm3eS9q622hKEvTVEoxqj1t365kwKHaNpbObddQ6Xcny +akvfh2L+8QbJSflcm8fL/JTup/2/cRG1ytOsaiXEr9JBEITOtQO0Ot/4Qzq+MJjv +weaJ3hZ0c+cTy3tEvt+I7+lnW4Q5dB7aLR2/BZfLubhxz1SUVMuHfLH64fc0Uf1Q +Nw== +-----END CERTIFICATE-----
new file mode 100644 --- /dev/null +++ b/dom/security/test/contentverifier/head.js @@ -0,0 +1,210 @@ +/* + * Test Content-Signature for remote about:newtab + * - Bug 1226928 - allow about:newtab to load remote content + * + * This tests content-signature verification on remote about:newtab in the + * following cases (see TESTS, all failed loads display about:blank fallback): + * - good case (signature should verify and correct page is displayed) + * - reload of newtab when the siganture was invalidated after the last correct + * load + * - malformed content-signature header + * - malformed keyid directive + * - malformed p384ecdsa directive + * - wrong signature (this is not a siganture for the delivered document) + * - invalid signature (this is not even a signature) + * - loading a file that doesn't fit the key or signature + * - cache poisoning (load a malicious remote page not in newtab, subsequent + * newtab load has to load the fallback) + */ + +const ABOUT_NEWTAB_URI = "about:newtab"; + +const BASE = "https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?"; +const URI_GOOD = BASE + "sig=good&x5u=good&file=good&header=good"; + +const INVALIDATE_FILE = BASE + "invalidateFile=yep"; +const VALIDATE_FILE = BASE + "validateFile=yep"; + +const URI_HEADER_BASE = BASE + "sig=good&x5u=good&file=good&header="; +const URI_ERROR_HEADER = URI_HEADER_BASE + "error"; +const URI_KEYERROR_HEADER = URI_HEADER_BASE + "errorInX5U"; +const URI_SIGERROR_HEADER = URI_HEADER_BASE + "errorInSignature"; +const URI_NO_HEADER = URI_HEADER_BASE + "noHeader"; + +const URI_BAD_SIG = BASE + "sig=bad&x5u=good&file=good&header=good"; +const URI_BROKEN_SIG = BASE + "sig=broken&x5u=good&file=good&header=good"; +const URI_BAD_X5U = BASE + "sig=good&x5u=bad&file=good&header=good"; +const URI_HTTP_X5U = BASE + "sig=good&x5u=http&file=good&header=good"; +const URI_BAD_FILE = BASE + "sig=good&x5u=good&file=bad&header=good"; +const URI_BAD_ALL = BASE + "sig=bad&x5u=bad&file=bad&header=bad"; +const URI_BAD_CSP = BASE + "sig=bad-csp&x5u=good&file=bad-csp&header=good"; + +const URI_BAD_FILE_CACHED = BASE + "sig=good&x5u=good&file=bad&header=good&cached=true"; + +const GOOD_ABOUT_STRING = "Just a fully good testpage for Bug 1226928"; +const BAD_ABOUT_STRING = "Just a bad testpage for Bug 1226928"; +const ABOUT_BLANK = "<head></head><body></body>"; + +const URI_CLEANUP = BASE + "cleanup=true"; +const CLEANUP_DONE = "Done"; + +const URI_SRI = BASE + "sig=sri&x5u=good&file=sri&header=good"; +const STYLESHEET_WITHOUT_SRI_BLOCKED = "Stylesheet without SRI blocked"; +const STYLESHEET_WITH_SRI_BLOCKED = "Stylesheet with SRI blocked"; +const STYLESHEET_WITH_SRI_LOADED = "Stylesheet with SRI loaded"; +const SCRIPT_WITHOUT_SRI_BLOCKED = "Script without SRI blocked"; +const SCRIPT_WITH_SRI_BLOCKED = "Script with SRI blocked"; +const SCRIPT_WITH_SRI_LOADED = "Script with SRI loaded"; + +const CSP_TEST_SUCCESS_STRING = "CSP violation test succeeded."; + +// Needs to sync with pref "security.signed_content.CSP.default". +const SIGNED_CONTENT_CSP = `{"csp-policies":[{"report-only":false,"script-src":["https://example.com","'unsafe-inline'"],"style-src":["https://example.com"]}]}`; + +var browser = null; +var aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"] + .getService(Ci.nsIAboutNewTabService); + +function pushPrefs(...aPrefs) { + return new Promise((resolve) => { + SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve); + }); +} + +/* + * run tests with input from TESTS + */ +function doTest(aExpectedStrings, reload, aUrl, aNewTabPref) { + // set about:newtab location for this test if it's a newtab test + if (aNewTabPref) { + aboutNewTabService.newTabURL = aNewTabPref; + } + + // set prefs + yield pushPrefs( + ["browser.newtabpage.remote.content-signing-test", true], + ["browser.newtabpage.remote", true], + ["security.content.signature.root_hash", + "65:AE:D8:1E:B5:12:AE:B0:6B:38:58:BC:7C:47:35:3D:D4:EA:25:F1:63:DA:08:BB:86:3A:2E:97:39:66:8F:55"]); + + if (aNewTabPref === URI_BAD_CSP) { + // Use stricter CSP to test CSP violation. + yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self'; style-src 'self'"]); + } else { + // Use weaker CSP to test normal content. + yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self' 'unsafe-inline'; style-src 'self'"]); + } + + // start the test + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: aUrl, + }, + function * (browser) { + // check if everything's set correct for testing + ok(Services.prefs.getBoolPref( + "browser.newtabpage.remote.content-signing-test"), + "sanity check: remote newtab signing test should be used"); + ok(Services.prefs.getBoolPref("browser.newtabpage.remote"), + "sanity check: remote newtab should be used"); + // we only check this if we really do a newtab test + if (aNewTabPref) { + ok(aboutNewTabService.overridden, + "sanity check: default URL for about:newtab should be overriden"); + is(aboutNewTabService.newTabURL, aNewTabPref, + "sanity check: default URL for about:newtab should return the new URL"); + } + + // Every valid remote newtab page must have built-in CSP. + let shouldHaveCSP = ((aUrl === ABOUT_NEWTAB_URI) && + (aNewTabPref === URI_GOOD || aNewTabPref === URI_SRI)); + + if (shouldHaveCSP) { + is(browser.contentDocument.nodePrincipal.cspJSON, SIGNED_CONTENT_CSP, + "Valid remote newtab page must have built-in CSP."); + } + + yield ContentTask.spawn( + browser, aExpectedStrings, function * (aExpectedStrings) { + for (let expectedString of aExpectedStrings) { + ok(content.document.documentElement.innerHTML.includes(expectedString), + "Expect the following value in the result\n" + expectedString + + "\nand got " + content.document.documentElement.innerHTML); + } + }); + + // for good test cases we check if a reload fails if the remote page + // changed from valid to invalid in the meantime + if (reload) { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: INVALIDATE_FILE, + }, + function * (browser2) { + yield ContentTask.spawn(browser2, null, function * () { + ok(content.document.documentElement.innerHTML.includes("Done"), + "Expect the following value in the result\n" + "Done" + + "\nand got " + content.document.documentElement.innerHTML); + }); + } + ); + + browser.reload(); + yield BrowserTestUtils.browserLoaded(browser); + + let expectedStrings = [ABOUT_BLANK]; + if (aNewTabPref == URI_SRI) { + expectedStrings = [ + STYLESHEET_WITHOUT_SRI_BLOCKED, + STYLESHEET_WITH_SRI_BLOCKED, + SCRIPT_WITHOUT_SRI_BLOCKED, + SCRIPT_WITH_SRI_BLOCKED + ]; + } + yield ContentTask.spawn(browser, expectedStrings, + function * (expectedStrings) { + for (let expectedString of expectedStrings) { + ok(content.document.documentElement.innerHTML.includes(expectedString), + "Expect the following value in the result\n" + expectedString + + "\nand got " + content.document.documentElement.innerHTML); + } + } + ); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: VALIDATE_FILE, + }, + function * (browser2) { + yield ContentTask.spawn(browser2, null, function * () { + ok(content.document.documentElement.innerHTML.includes("Done"), + "Expect the following value in the result\n" + "Done" + + "\nand got " + content.document.documentElement.innerHTML); + }); + } + ); + } + } + ); +} + +function runTests() { + // run tests from TESTS + for (let i = 0; i < TESTS.length; i++) { + let testCase = TESTS[i]; + let url = "", aNewTabPref = ""; + let reload = false; + var aExpectedStrings = testCase.testStrings; + if (testCase.aboutURI) { + url = ABOUT_NEWTAB_URI; + aNewTabPref = testCase.aboutURI; + if (aNewTabPref == URI_GOOD || aNewTabPref == URI_SRI) { + reload = true; + } + } else { + url = testCase.url; + } + + yield doTest(aExpectedStrings, reload, url, aNewTabPref); + } +}
--- a/dom/storage/DOMStorage.cpp +++ b/dom/storage/DOMStorage.cpp @@ -213,18 +213,18 @@ DOMStorage::BroadcastChangeNotification( // Note, this DOM event should never reach JS. It is cloned later in // nsGlobalWindow. RefPtr<StorageEvent> event = StorageEvent::Constructor(nullptr, NS_LITERAL_STRING("storage"), dict); RefPtr<StorageNotifierRunnable> r = new StorageNotifierRunnable(event, GetType() == LocalStorage - ? MOZ_UTF16("localStorage") - : MOZ_UTF16("sessionStorage")); + ? u"localStorage" + : u"sessionStorage"); NS_DispatchToMainThread(r); } static const char kPermissionType[] = "cookie"; static const char kStorageEnabled[] = "dom.storage.enabled"; // static, public bool
--- a/dom/svg/SVGLength.cpp +++ b/dom/svg/SVGLength.cpp @@ -20,17 +20,17 @@ namespace mozilla { static void GetUnitString(nsAString& unit, uint16_t unitType); static uint16_t GetUnitTypeForString(const nsAString& unitStr); void SVGLength::GetValueAsString(nsAString &aValue) const { char16_t buf[24]; nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("%g"), + u"%g", (double)mValue); aValue.Assign(buf); nsAutoString unitString; GetUnitString(unitString, mUnit); aValue.Append(unitString); }
--- a/dom/svg/SVGNumberList.cpp +++ b/dom/svg/SVGNumberList.cpp @@ -28,17 +28,17 @@ SVGNumberList::GetValueAsString(nsAStrin { aValue.Truncate(); char16_t buf[24]; uint32_t last = mNumbers.Length() - 1; for (uint32_t i = 0; i < mNumbers.Length(); ++i) { // Would like to use aValue.AppendPrintf("%f", mNumbers[i]), but it's not // possible to always avoid trailing zeros. nsTextFormatter::snprintf(buf, ArrayLength(buf), - MOZ_UTF16("%g"), + u"%g", double(mNumbers[i])); // We ignore OOM, since it's not useful for us to return an error. aValue.Append(buf); if (i != last) { aValue.Append(' '); } } }
--- a/dom/svg/SVGPathSegUtils.cpp +++ b/dom/svg/SVGPathSegUtils.cpp @@ -32,51 +32,51 @@ SVGPathSegUtils::GetValueAsString(const uint32_t type = DecodeType(aSeg[0]); char16_t typeAsChar = GetPathSegTypeAsLetter(type); // Special case arcs: if (IsArcType(type)) { bool largeArcFlag = aSeg[4] != 0.0f; bool sweepFlag = aSeg[5] != 0.0f; nsTextFormatter::ssprintf(aValue, - MOZ_UTF16("%c%g,%g %g %d,%d %g,%g"), + u"%c%g,%g %g %d,%d %g,%g", typeAsChar, aSeg[1], aSeg[2], aSeg[3], largeArcFlag, sweepFlag, aSeg[6], aSeg[7]); } else { switch (ArgCountForType(type)) { case 0: aValue = typeAsChar; break; case 1: - nsTextFormatter::ssprintf(aValue, MOZ_UTF16("%c%g"), + nsTextFormatter::ssprintf(aValue, u"%c%g", typeAsChar, aSeg[1]); break; case 2: - nsTextFormatter::ssprintf(aValue, MOZ_UTF16("%c%g,%g"), + nsTextFormatter::ssprintf(aValue, u"%c%g,%g", typeAsChar, aSeg[1], aSeg[2]); break; case 4: - nsTextFormatter::ssprintf(aValue, MOZ_UTF16("%c%g,%g %g,%g"), + nsTextFormatter::ssprintf(aValue, u"%c%g,%g %g,%g", typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4]); break; case 6: nsTextFormatter::ssprintf(aValue, - MOZ_UTF16("%c%g,%g %g,%g %g,%g"), + u"%c%g,%g %g,%g %g,%g", typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4], aSeg[5], aSeg[6]); break; default: MOZ_ASSERT(false, "Unknown segment type"); - aValue = MOZ_UTF16("<unknown-segment-type>"); + aValue = u"<unknown-segment-type>"; return; } } // nsTextFormatter::ssprintf is one of the nsTextFormatter methods that // randomly appends '\0' to its output string, which means that the length // of the output string is one too long. We need to manually remove that '\0' // until nsTextFormatter is fixed.
--- a/dom/svg/SVGPointList.cpp +++ b/dom/svg/SVGPointList.cpp @@ -27,17 +27,17 @@ SVGPointList::GetValueAsString(nsAString { aValue.Truncate(); char16_t buf[50]; uint32_t last = mItems.Length() - 1; for (uint32_t i = 0; i < mItems.Length(); ++i) { // Would like to use aValue.AppendPrintf("%f,%f", item.mX, item.mY), // but it's not possible to always avoid trailing zeros. nsTextFormatter::snprintf(buf, ArrayLength(buf), - MOZ_UTF16("%g,%g"), + u"%g,%g", double(mItems[i].mX), double(mItems[i].mY)); // We ignore OOM, since it's not useful for us to return an error. aValue.Append(buf); if (i != last) { aValue.Append(' '); } } }
--- a/dom/svg/nsSVGAngle.cpp +++ b/dom/svg/nsSVGAngle.cpp @@ -81,17 +81,17 @@ GetUnitTypeForString(const nsAString& un return SVG_ANGLETYPE_UNKNOWN; } static void GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType) { char16_t buf[24]; nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("%g"), + u"%g", (double)aValue); aValueAsString.Assign(buf); nsAutoString unitString; GetUnitString(unitString, aUnitType); aValueAsString.Append(unitString); }
--- a/dom/svg/nsSVGLength2.cpp +++ b/dom/svg/nsSVGLength2.cpp @@ -84,17 +84,17 @@ GetUnitTypeForString(const nsAString& un return nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN; } static void GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType) { char16_t buf[24]; nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("%g"), + u"%g", (double)aValue); aValueAsString.Assign(buf); nsAutoString unitString; GetUnitString(unitString, aUnitType); aValueAsString.Append(unitString); }
--- a/dom/svg/nsSVGTransform.cpp +++ b/dom/svg/nsSVGTransform.cpp @@ -20,51 +20,51 @@ nsSVGTransform::GetValueAsString(nsAStri { char16_t buf[256]; switch (mType) { case SVG_TRANSFORM_TRANSLATE: // The spec say that if Y is not provided, it is assumed to be zero. if (mMatrix._32 != 0) nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("translate(%g, %g)"), + u"translate(%g, %g)", mMatrix._31, mMatrix._32); else nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("translate(%g)"), + u"translate(%g)", mMatrix._31); break; case SVG_TRANSFORM_ROTATE: if (mOriginX != 0.0f || mOriginY != 0.0f) nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("rotate(%g, %g, %g)"), + u"rotate(%g, %g, %g)", mAngle, mOriginX, mOriginY); else nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("rotate(%g)"), mAngle); + u"rotate(%g)", mAngle); break; case SVG_TRANSFORM_SCALE: if (mMatrix._11 != mMatrix._22) nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("scale(%g, %g)"), mMatrix._11, mMatrix._22); + u"scale(%g, %g)", mMatrix._11, mMatrix._22); else nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("scale(%g)"), mMatrix._11); + u"scale(%g)", mMatrix._11); break; case SVG_TRANSFORM_SKEWX: nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("skewX(%g)"), mAngle); + u"skewX(%g)", mAngle); break; case SVG_TRANSFORM_SKEWY: nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("skewY(%g)"), mAngle); + u"skewY(%g)", mAngle); break; case SVG_TRANSFORM_MATRIX: nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("matrix(%g, %g, %g, %g, %g, %g)"), + u"matrix(%g, %g, %g, %g, %g, %g)", mMatrix._11, mMatrix._12, mMatrix._21, mMatrix._22, mMatrix._31, mMatrix._32); break; default: buf[0] = '\0'; NS_ERROR("unknown transformation type"); break;
--- a/dom/svg/nsSVGViewBox.cpp +++ b/dom/svg/nsSVGViewBox.cpp @@ -202,17 +202,17 @@ void nsSVGViewBox::GetBaseValueString(nsAString& aValue) const { if (mBaseVal.none) { aValue.AssignLiteral("none"); return; } char16_t buf[200]; nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t), - MOZ_UTF16("%g %g %g %g"), + u"%g %g %g %g", (double)mBaseVal.x, (double)mBaseVal.y, (double)mBaseVal.width, (double)mBaseVal.height); aValue.Assign(buf); } already_AddRefed<dom::SVGAnimatedRect> nsSVGViewBox::ToSVGAnimatedRect(nsSVGElement* aSVGElement)
--- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -51,20 +51,20 @@ using namespace mozilla::dom; using namespace mozilla::dom::gonk; using namespace android; using namespace mozilla; using namespace mozilla::dom::bluetooth; #undef LOG #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args) -#define HEADPHONES_STATUS_HEADSET MOZ_UTF16("headset") -#define HEADPHONES_STATUS_HEADPHONE MOZ_UTF16("headphone") -#define HEADPHONES_STATUS_OFF MOZ_UTF16("off") -#define HEADPHONES_STATUS_UNKNOWN MOZ_UTF16("unknown") +#define HEADPHONES_STATUS_HEADSET u"headset" +#define HEADPHONES_STATUS_HEADPHONE u"headphone" +#define HEADPHONES_STATUS_OFF u"off" +#define HEADPHONES_STATUS_UNKNOWN u"unknown" #define HEADPHONES_STATUS_CHANGED "headphones-status-changed" #define MOZ_SETTINGS_CHANGE_ID "mozsettings-changed" #define AUDIO_CHANNEL_PROCESS_CHANGED "audio-channel-process-changed" #define AUDIO_POLICY_SERVICE_NAME "media.audio_policy" #define SETTINGS_SERVICE "@mozilla.org/settingsService;1" // Refer AudioService.java from Android static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp @@ -173,39 +173,37 @@ public: nsCOMPtr<nsIObserverService> obsService = services::GetObserverService(); obsService->NotifyObservers(provider, "geolocation-device-events", mData); return NS_OK; } private: const char16_t* mData; }; - - void GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status) { const char* msgStream=0; switch (status->status) { case GPS_STATUS_NONE: msgStream = "geo: GPS_STATUS_NONE\n"; break; case GPS_STATUS_SESSION_BEGIN: msgStream = "geo: GPS_STATUS_SESSION_BEGIN\n"; break; case GPS_STATUS_SESSION_END: msgStream = "geo: GPS_STATUS_SESSION_END\n"; break; case GPS_STATUS_ENGINE_ON: msgStream = "geo: GPS_STATUS_ENGINE_ON\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask( MOZ_UTF16("GPSStarting"))); + NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSStarting")); break; case GPS_STATUS_ENGINE_OFF: msgStream = "geo: GPS_STATUS_ENGINE_OFF\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask( MOZ_UTF16("GPSShutdown"))); + NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSShutdown")); break; default: msgStream = "geo: Unknown GPS status\n"; break; } if (gDebug_isLoggingEnabled){ DBG("%s", msgStream); }
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -67,16 +67,17 @@ var ecmaGlobals = {name: "Intl", android: false}, "Iterator", "JSON", "Map", "Math", {name: "NaN", xbl: false}, "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", "Reflect", "RegExp", "Set", {name: "SharedArrayBuffer", nightly: true}, {name: "SIMD", nightly: true}, @@ -957,18 +958,16 @@ var interfaceNamesInGlobalScope = {name: "PresentationSession", disabled: true, permission: ["presentation"]}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "PresentationSessionConnectEvent", disabled: true, permission: ["presentation"]}, // IMPORTANT: Do not change this list without review from a DOM peer! "ProcessingInstruction", // IMPORTANT: Do not change this list without review from a DOM peer! "ProgressEvent", // IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", -// IMPORTANT: Do not change this list without review from a DOM peer! {name: "PushManager", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "PushSubscription", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "PushSubscriptionOptions", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "RadioNodeList", // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/general/test_offsets.html +++ b/dom/tests/mochitest/general/test_offsets.html @@ -7,22 +7,18 @@ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"> <style> input { box-sizing: content-box; } </style> </head> - -<!-- We set a transform on the body element so that it creates a reference frame. - This makes sure that snapping of scrolled areas for the contained elements - is not influenced by offsets outside of this document. --> <body id="body" onload="setTimeout(testElements, 0, 'testelements', SimpleTest.finish);" - style="margin: 1px; border: 2px solid black; padding: 4px; transform: translateY(1px);"> + style="margin: 1px; border: 2px solid black; padding: 4px;"> <div id="testelements" style="margin: 0; border: 0; padding: 0;"> <div id="div1" style="margin: 0; margin-left: 6px; margin-top: 2px; border: 1px solid green; padding: 6px; width: 50px; height: 20px" _offsetLeft="13" _offsetTop="9" _offsetWidth="64" _offsetHeight="34" _scrollWidth="62" _scrollHeight="32" _clientLeft="1" _clientTop="1" _clientWidth="62" _clientHeight="32"></div> <div id="noscroll" style="margin: 2px; border: 1px solid blue; padding: 3px;" _offsetLeft="10" _offsetTop="12" _offsetWidth="64" _offsetHeight="34" @@ -54,17 +50,17 @@ <div id="fixed" style="position: fixed; margin: 2px; border: 1px solid orange; padding: 7px; left: 87px; top: 12px;"> This is some fixed positioned text. <div id="fixed-block" _offsetParent="fixed"> <div id="fixed-replaced" _offsetParent="fixed" style="margin: 1px; border: 0; padding: 3px;"></div> </div> </div> <div id="scrollbox" - style="overflow: scroll; padding-left: 0px; margin: 3px; border: 4px solid green; max-width: 80px; max-height: 70px" + style="overflow: scroll; padding-left: 0px; margin: 3px; border: 4px solid green; max-width: 80px; max-height: 70px;" _scrollWidth="62" _scrollHeight="32" _clientLeft="1" _clientTop="1" _clientWidth="62" _clientHeight="32"><p id="p1" style="margin: 0; padding: 0;">One</p> <p id="p2">Two</p> <p id="scrollchild">Three</p> <p id="lastlinebox" style="margin: 0; padding: 0;"><input id="lastline" type="button" style="margin: 0px; border: 2px solid red;" value="This button is much longer than the others"> </p></div>
--- a/dom/tests/mochitest/general/test_offsets.js +++ b/dom/tests/mochitest/general/test_offsets.js @@ -176,35 +176,22 @@ function checkClientState(element, left, } function checkCoord(element, type, val, testname) { if (val != -10000) is(element[type], Math.round(val), testname + " " + type); } -function checkCoordFuzzy(element, type, val, fuzz, testname) -{ - if (val != -10000) - ok(Math.abs(element[type] - Math.round(val)) <= fuzz, testname + " " + type); -} - function checkCoords(element, type, left, top, width, height, testname) { checkCoord(element, type + "Left", left, testname); checkCoord(element, type + "Top", top, testname); - - if (type == "scroll") { - // scrollWidth and scrollHeight can deviate by 1 pixel due to snapping. - checkCoordFuzzy(element, type + "Width", width, 1, testname); - checkCoordFuzzy(element, type + "Height", height, 1, testname); - } else { - checkCoord(element, type + "Width", width, testname); - checkCoord(element, type + "Height", height, testname); - } + checkCoord(element, type + "Width", width, testname); + checkCoord(element, type + "Height", height, testname); if (element instanceof SVGElement) return; if (element.id == "outerpopup" && !element.parentNode.open) // closed popup return; if (element.id == "div-displaynone" || element.id == "nonappended") // hidden elements
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -42,16 +42,17 @@ var ecmaGlobals = {name: "Intl", android: false}, "Iterator", "JSON", "Map", "Math", "NaN", "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", "Reflect", "RegExp", "Set", {name: "SharedArrayBuffer", nightly: true}, {name: "SIMD", nightly: true}, @@ -170,18 +171,16 @@ var interfaceNamesInGlobalScope = "PerformanceMark", // IMPORTANT: Do not change this list without review from a DOM peer! "PerformanceMeasure", // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserver", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserverEntryList", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", -// IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushEvent", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushManager", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushMessageData", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushSubscription", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -42,16 +42,17 @@ var ecmaGlobals = {name: "Intl", android: false}, "Iterator", "JSON", "Map", "Math", "NaN", "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", "Reflect", "RegExp", "Set", {name: "SharedArrayBuffer", nightly: true}, {name: "SIMD", nightly: true}, @@ -162,18 +163,16 @@ var interfaceNamesInGlobalScope = "PerformanceMark", // IMPORTANT: Do not change this list without review from a DOM peer! "PerformanceMeasure", // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserver", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserverEntryList", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", -// IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushManager", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushSubscription", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushSubscriptionOptions", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! "Request", // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/xbl/nsXBLDocumentInfo.cpp +++ b/dom/xbl/nsXBLDocumentInfo.cpp @@ -241,17 +241,17 @@ nsXBLDocumentInfo::ReadPrototypeBindings break; rv = nsXBLPrototypeBinding::ReadNewBinding(stream, docInfo, doc, flags); if (NS_FAILED(rv)) { return rv; } } - docInfo.swap(*aDocInfo); + docInfo.forget(aDocInfo); return NS_OK; } nsresult nsXBLDocumentInfo::WritePrototypeBindings() { // Only write out bindings with the system principal if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal()))
--- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -489,10 +489,10 @@ nsXBLProtoImplField::Write(nsIObjectOutp nsresult rv = aStream->Write8(type); NS_ENSURE_SUCCESS(rv, rv); rv = aStream->WriteWStringZ(mName); NS_ENSURE_SUCCESS(rv, rv); rv = aStream->Write32(mLineNumber); NS_ENSURE_SUCCESS(rv, rv); - return aStream->WriteWStringZ(mFieldText ? mFieldText : MOZ_UTF16("")); + return aStream->WriteWStringZ(mFieldText ? mFieldText : u""); }
--- a/dom/xbl/nsXBLPrototypeHandler.cpp +++ b/dom/xbl/nsXBLPrototypeHandler.cpp @@ -997,10 +997,10 @@ nsXBLPrototypeHandler::Write(nsIObjectOu rv = aStream->Write32(mDetail); NS_ENSURE_SUCCESS(rv, rv); rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get()); NS_ENSURE_SUCCESS(rv, rv); rv = aStream->Write32(mLineNumber); NS_ENSURE_SUCCESS(rv, rv); - return aStream->WriteWStringZ(mHandlerText ? mHandlerText : MOZ_UTF16("")); + return aStream->WriteWStringZ(mHandlerText ? mHandlerText : u""); }
--- a/dom/xbl/nsXBLService.cpp +++ b/dom/xbl/nsXBLService.cpp @@ -493,17 +493,17 @@ nsXBLService::LoadBindings(nsIContent* a // Set up our properties rv = newBinding->InstallImplementation(); NS_ENSURE_SUCCESS(rv, rv); // Figure out if we have any scoped sheets. If so, we do a second resolve. *aResolveStyle = newBinding->HasStyleSheets(); - newBinding.swap(*aBinding); + newBinding.forget(aBinding); } return NS_OK; } nsresult nsXBLService::FlushStyleBindings(nsIContent* aContent) {
--- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -1324,18 +1324,18 @@ nsXMLContentSink::ReportError(const char mXSLTProcessor->CancelLoads(); mXSLTProcessor = nullptr; } // release the nodes on stack mContentStack.Clear(); mNotifyLevel = 0; - rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"), - MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\"")); + rv = HandleProcessingInstruction(u"xml-stylesheet", + u"href=\"chrome://global/locale/intl.css\" type=\"text/css\""); NS_ENSURE_SUCCESS(rv, rv); const char16_t* noAtts[] = { 0, 0 }; NS_NAMED_LITERAL_STRING(errorNs, "http://www.mozilla.org/newlayout/xml/parsererror.xml"); nsAutoString parsererror(errorNs);
--- a/dom/xslt/xpath/txPathExpr.cpp +++ b/dom/xslt/xpath/txPathExpr.cpp @@ -58,17 +58,17 @@ PathExpr::evaluate(txIEvalContext* aCont NS_ENSURE_TRUE(res->getResultType() == txAExprResult::NODESET, NS_ERROR_XSLT_NODESET_EXPECTED); RefPtr<txNodeSet> nodes = static_cast<txNodeSet*> (static_cast<txAExprResult*> (res)); if (nodes->isEmpty()) { - res.swap(*aResult); + res.forget(aResult); return NS_OK; } res = nullptr; // To allow recycling // Evaluate remaining steps uint32_t i, len = mItems.Length(); for (i = 1; i < len; ++i) {
--- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -253,17 +253,17 @@ txEXSLTFunctionCall::evaluate(txIEvalCon switch (mType) { case NODE_SET: { RefPtr<txAExprResult> exprResult; rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult)); NS_ENSURE_SUCCESS(rv, rv); if (exprResult->getResultType() == txAExprResult::NODESET) { - exprResult.swap(*aResult); + exprResult.forget(aResult); } else { RefPtr<txNodeSet> resultSet; rv = aContext->recycler()-> getNodeSet(getter_AddRefs(resultSet)); NS_ENSURE_SUCCESS(rv, rv); if (exprResult->getResultType() ==
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -350,19 +350,17 @@ txStylesheetSink::GetInterface(const nsI nsCOMPtr<nsIWindowWatcher> wwatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIAuthPrompt> prompt; rv = wwatcher->GetNewAuthPrompter(nullptr, getter_AddRefs(prompt)); NS_ENSURE_SUCCESS(rv, rv); - nsIAuthPrompt* rawPtr = nullptr; - prompt.swap(rawPtr); - *aResult = rawPtr; + prompt.forget(aResult); return NS_OK; } return NS_ERROR_NO_INTERFACE; } class txCompileObserver final : public txACompileObserver
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -1089,22 +1089,22 @@ txMozillaXSLTProcessor::reportError(nsre nsXPIDLString errorMessage; nsCOMPtr<nsIStringBundle> bundle; sbs->CreateBundle(XSLT_MSGS_URL, getter_AddRefs(bundle)); if (bundle) { const char16_t* error[] = { errorText.get() }; if (mStylesheet) { - bundle->FormatStringFromName(MOZ_UTF16("TransformError"), + bundle->FormatStringFromName(u"TransformError", error, 1, getter_Copies(errorMessage)); } else { - bundle->FormatStringFromName(MOZ_UTF16("LoadingError"), + bundle->FormatStringFromName(u"LoadingError", error, 1, getter_Copies(errorMessage)); } } mErrorText.Assign(errorMessage); } }
--- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -1429,17 +1429,17 @@ XULDocument::GetPopupNode(nsIDOMNode** a nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { node = pm->GetLastTriggerPopupNode(this); } } if (node && nsContentUtils::CanCallerAccess(node) && GetScopeObjectOfNode(node)) { - node.swap(*aNode); + node.forget(aNode); } return NS_OK; } already_AddRefed<nsINode> XULDocument::GetPopupNode() { @@ -1541,17 +1541,17 @@ NS_IMETHODIMP XULDocument::GetTooltipNode(nsIDOMNode** aNode) { *aNode = nullptr; nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { nsCOMPtr<nsIDOMNode> node = pm->GetLastTriggerTooltipNode(this); if (node && nsContentUtils::CanCallerAccess(node)) - node.swap(*aNode); + node.forget(aNode); } return NS_OK; } already_AddRefed<nsINode> XULDocument::GetTooltipNode() { @@ -3574,17 +3574,17 @@ XULDocument::CreateElementFromPrototype( NOT_FROM_PARSER); if (NS_FAILED(rv)) return rv; rv = AddAttributes(aPrototype, result); if (NS_FAILED(rv)) return rv; } - result.swap(*aResult); + result.forget(aResult); return NS_OK; } nsresult XULDocument::CreateOverlayElement(nsXULPrototypeElement* aPrototype, Element** aResult) {
--- a/dom/xul/nsXULPopupListener.cpp +++ b/dom/xul/nsXULPopupListener.cpp @@ -22,17 +22,17 @@ #include "nsIScriptContext.h" #include "nsIDOMWindow.h" #include "nsIDOMXULDocument.h" #include "nsIDocument.h" #include "nsServiceManagerUtils.h" #include "nsIPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsLayoutUtils.h" -#include "nsHTMLReflowState.h" +#include "mozilla/ReflowInput.h" #include "nsIObjectLoadingContent.h" #include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" #include "mozilla/Preferences.h" #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() #include "mozilla/dom/EventTarget.h" #include "mozilla/dom/FragmentOrElement.h"
--- a/dom/xul/templates/nsXULContentUtils.cpp +++ b/dom/xul/templates/nsXULContentUtils.cpp @@ -89,17 +89,17 @@ nsXULContentUtils::Init() #define XUL_RESOURCE(ident, uri) \ PR_BEGIN_MACRO \ rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \ if (NS_FAILED(rv)) return rv; \ PR_END_MACRO #define XUL_LITERAL(ident, val) \ PR_BEGIN_MACRO \ - rv = gRDF->GetLiteral(MOZ_UTF16(val), &(ident)); \ + rv = gRDF->GetLiteral(val, &(ident)); \ if (NS_FAILED(rv)) return rv; \ PR_END_MACRO #include "nsXULResourceList.h" #undef XUL_RESOURCE #undef XUL_LITERAL gFormat = nsIDateTimeFormat::Create().take();
--- a/dom/xul/templates/nsXULResourceList.h +++ b/dom/xul/templates/nsXULResourceList.h @@ -5,9 +5,9 @@ // N.B., no include guard! We'll include this multiple times in some // files. XUL_RESOURCE(NC_child, NC_NAMESPACE_URI "child"); XUL_RESOURCE(NC_Folder, NC_NAMESPACE_URI "Folder"); XUL_RESOURCE(NC_open, NC_NAMESPACE_URI "open"); -XUL_LITERAL(true_, "true"); +XUL_LITERAL(true_, u"true");
--- a/editor/composer/nsEditingSession.cpp +++ b/editor/composer/nsEditingSession.cpp @@ -1028,17 +1028,17 @@ nsEditingSession::EndDocumentLoad(nsIWeb void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) { nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(static_cast<nsIWeakReference*> (aClosure)); if (docShell) { nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell)); if (webNav) - webNav->LoadURI(MOZ_UTF16("about:blank"), + webNav->LoadURI(u"about:blank", 0, nullptr, nullptr, nullptr); } } /*--------------------------------------------------------------------------- StartPageLoad
--- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -1207,22 +1207,20 @@ HTMLEditor::ReplaceHeadContentsWithHTML( NS_ENSURE_TRUE(headNode, NS_ERROR_NULL_POINTER); // First, make sure there are no return chars in the source. Bad things // happen if you insert returns (instead of dom newlines, \n) into an editor // document. nsAutoString inputString (aSourceToInsert); // hope this does copy-on-write // Windows linebreaks: Map CRLF to LF: - inputString.ReplaceSubstring(MOZ_UTF16("\r\n"), - MOZ_UTF16("\n")); + inputString.ReplaceSubstring(u"\r\n", u"\n"); // Mac linebreaks: Map any remaining CR to LF: - inputString.ReplaceSubstring(MOZ_UTF16("\r"), - MOZ_UTF16("\n")); + inputString.ReplaceSubstring(u"\r", u"\n"); AutoEditBatch beginBatching(this); // Get the first range in the selection, for context: RefPtr<nsRange> range = selection->GetRangeAt(0); NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER); ErrorResult err;
--- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -6,17 +6,17 @@ // Local Includes #include "nsDocShellTreeOwner.h" #include "nsWebBrowser.h" // Helper Classes #include "nsStyleCoord.h" #include "nsSize.h" -#include "nsHTMLReflowState.h" +#include "mozilla/ReflowInput.h" #include "nsIServiceManager.h" #include "nsComponentManagerUtils.h" #include "nsXPIDLString.h" #include "nsIAtom.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsISimpleEnumerator.h" #include "mozilla/LookAndFeel.h"
--- a/embedding/components/commandhandler/nsCommandManager.cpp +++ b/embedding/components/commandhandler/nsCommandManager.cpp @@ -77,17 +77,17 @@ nsCommandManager::CommandStatusChanged(c if (commandObservers) { // XXX Should we worry about observers removing themselves from Observe()? int32_t i, numItems = commandObservers->Length(); for (i = 0; i < numItems; ++i) { nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i); // should we get the command state to pass here? This might be expensive. observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this), aCommandName, - MOZ_UTF16("command_status_changed")); + u"command_status_changed"); } } return NS_OK; } #if 0 #pragma mark -
--- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -1690,17 +1690,17 @@ nsPermissionManager::AddInternal(nsIPrin } if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, - MOZ_UTF16("added")); + u"added"); } break; } case eOperationRemoving: { PermissionEntry oldPermissionEntry = entry->GetPermissions()[index]; @@ -1714,17 +1714,17 @@ nsPermissionManager::AddInternal(nsIPrin nsIPermissionManager::EXPIRE_NEVER, 0, 0); if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], oldPermissionEntry.mPermission, oldPermissionEntry.mExpireType, oldPermissionEntry.mExpireTime, - MOZ_UTF16("deleted")); + u"deleted"); } // If there are no more permissions stored for that entry, clear it. if (entry->GetPermissions().IsEmpty()) { mPermissionTable.RemoveEntry(entry); } break; @@ -1760,17 +1760,17 @@ nsPermissionManager::AddInternal(nsIPrin aPermission, aExpireType, aExpireTime, aModificationTime); if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, - MOZ_UTF16("changed")); + u"changed"); } break; } case eOperationReplacingDefault: { // this is handling the case when we have an existing permission // entry that was created as a "default" (and thus isn't in the DB) with @@ -1808,17 +1808,17 @@ nsPermissionManager::AddInternal(nsIPrin } if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, - MOZ_UTF16("changed")); + u"changed"); } } break; } return NS_OK; } @@ -1919,17 +1919,17 @@ nsPermissionManager::RemoveAllInternal(b // database is authoritative, we do not need confirmation from the // on-disk database to notify observers. RemoveAllFromMemory(); // Re-import the defaults ImportDefaults(); if (aNotifyObservers) { - NotifyObservers(nullptr, MOZ_UTF16("cleared")); + NotifyObservers(nullptr, u"cleared"); } // clear the db if (mDBConn) { nsCOMPtr<mozIStorageAsyncStatement> removeStmt; nsresult rv = mDBConn-> CreateAsyncStatement(NS_LITERAL_CSTRING( "DELETE FROM moz_perms" @@ -2448,32 +2448,32 @@ nsPermissionManager::RemoveExpiredPermis entry->GetPermissions().RemoveElementAt(i); NotifyObserversWithPermission(principal, mTypeArray.ElementAt(oldPermEntry.mType), oldPermEntry.mPermission, oldPermEntry.mExpireType, oldPermEntry.mExpireTime, - MOZ_UTF16("deleted")); + u"deleted"); --i; continue; } permEntry.mPermission = permEntry.mNonSessionPermission; permEntry.mExpireType = permEntry.mNonSessionExpireType; permEntry.mExpireTime = permEntry.mNonSessionExpireTime; NotifyObserversWithPermission(principal, mTypeArray.ElementAt(permEntry.mType), permEntry.mPermission, permEntry.mExpireType, permEntry.mExpireTime, - MOZ_UTF16("changed")); + u"changed"); } } return NS_OK; } //***************************************************************************** //*** nsPermissionManager private methods
--- a/extensions/gio/nsGIOProtocolHandler.cpp +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -821,27 +821,27 @@ mount_operation_ask_password (GMountOper return; } nsAutoString nsmessage; if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { if (flags & G_ASK_PASSWORD_NEED_USERNAME) { if (!realm.IsEmpty()) { const char16_t *strings[] = { realm.get(), dispHost.get() }; - bundle->FormatStringFromName(MOZ_UTF16("EnterLoginForRealm2"), + bundle->FormatStringFromName(u"EnterLoginForRealm2", strings, 2, getter_Copies(nsmessage)); } else { const char16_t *strings[] = { dispHost.get() }; - bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordFor2"), + bundle->FormatStringFromName(u"EnterUserPasswordFor2", strings, 1, getter_Copies(nsmessage)); } } else { NS_ConvertUTF8toUTF16 userName(default_user); const char16_t *strings[] = { userName.get(), dispHost.get() }; - bundle->FormatStringFromName(MOZ_UTF16("EnterPasswordFor"), + bundle->FormatStringFromName(u"EnterPasswordFor", strings, 2, getter_Copies(nsmessage)); } } else { g_warning("Unknown mount operation request (flags: %x)", flags); } if (nsmessage.IsEmpty()) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED);
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp +++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp @@ -509,21 +509,21 @@ nsresult nsAutoConfig::PromptForEMailAdd NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStringBundle> bundle; rv = bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", getter_AddRefs(bundle)); NS_ENSURE_SUCCESS(rv, rv); nsXPIDLString title; - rv = bundle->GetStringFromName(MOZ_UTF16("emailPromptTitle"), getter_Copies(title)); + rv = bundle->GetStringFromName(u"emailPromptTitle", getter_Copies(title)); NS_ENSURE_SUCCESS(rv, rv); nsXPIDLString err; - rv = bundle->GetStringFromName(MOZ_UTF16("emailPromptMsg"), getter_Copies(err)); + rv = bundle->GetStringFromName(u"emailPromptMsg", getter_Copies(err)); NS_ENSURE_SUCCESS(rv, rv); bool check = false; nsXPIDLString emailResult; bool success; rv = promptService->Prompt(nullptr, title.get(), err.get(), getter_Copies(emailResult), nullptr, &check, &success); if (!success) return NS_ERROR_FAILURE; NS_ENSURE_SUCCESS(rv, rv);
--- a/extensions/pref/autoconfig/src/nsReadConfig.cpp +++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp @@ -51,22 +51,22 @@ static void DisplayError(void) nsCOMPtr<nsIStringBundle> bundle; bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", getter_AddRefs(bundle)); if (!bundle) return; nsXPIDLString title; - rv = bundle->GetStringFromName(MOZ_UTF16("readConfigTitle"), getter_Copies(title)); + rv = bundle->GetStringFromName(u"readConfigTitle", getter_Copies(title)); if (NS_FAILED(rv)) return; nsXPIDLString err; - rv = bundle->GetStringFromName(MOZ_UTF16("readConfigMsg"), getter_Copies(err)); + rv = bundle->GetStringFromName(u"readConfigMsg", getter_Copies(err)); if (NS_FAILED(rv)) return; promptService->Alert(nullptr, title.get(), err.get()); } // nsISupports Implementation
--- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -221,22 +221,21 @@ SetPaintPattern(SkPaint& aPaint, const P case PatternType::COLOR: { Color color = static_cast<const ColorPattern&>(aPattern).mColor; aPaint.setColor(ColorToSkColor(color, aAlpha)); break; } case PatternType::LINEAR_GRADIENT: { const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); - SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH); - - if (stops->mCount < 2 || + if (!stops || stops->mCount < 2 || !pat.mBegin.IsFinite() || !pat.mEnd.IsFinite()) { aPaint.setColor(SK_ColorTRANSPARENT); } else { + SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH); SkPoint points[2]; points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y)); SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points, &stops->mColors.front(), @@ -245,23 +244,22 @@ SetPaintPattern(SkPaint& aPaint, const P mode, 0, &mat); aPaint.setShader(shader); } break; } case PatternType::RADIAL_GRADIENT: { const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); - SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH); - - if (stops->mCount < 2 || + if (!stops || stops->mCount < 2 || !pat.mCenter1.IsFinite() || !IsFinite(pat.mRadius1) || !pat.mCenter2.IsFinite() || !IsFinite(pat.mRadius2)) { aPaint.setColor(SK_ColorTRANSPARENT); } else { + SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH); SkPoint points[2]; points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y)); SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(points[0], SkFloatToScalar(pat.mRadius1),
--- a/gfx/2d/SFNTNameTable.cpp +++ b/gfx/2d/SFNTNameTable.cpp @@ -211,17 +211,17 @@ SFNTNameTable::GetU16FullName(mozilla::u } mozilla::u16string styleName; if (!ReadU16Name(StyleMatchers(), styleName)) { return false; } aU16FullName.assign(Move(familyName)); - aU16FullName.append(MOZ_UTF16(" ")); + aU16FullName.append(u" "); aU16FullName.append(styleName); return true; } bool SFNTNameTable::ReadU16Name(const NameRecordMatchers& aMatchers, mozilla::u16string& aU16Name) {
--- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -3,22 +3,24 @@ /* 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 "GPUParent.h" #include "gfxConfig.h" #include "gfxPlatform.h" #include "gfxPrefs.h" #include "GPUProcessHost.h" -#include "VsyncBridgeParent.h" #include "mozilla/Assertions.h" #include "mozilla/ipc/ProcessChild.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ImageBridgeParent.h" +#include "VRManager.h" +#include "VRManagerParent.h" +#include "VsyncBridgeParent.h" namespace mozilla { namespace gfx { using namespace ipc; using namespace layers; GPUParent::GPUParent() @@ -36,25 +38,27 @@ GPUParent::Init(base::ProcessId aParentP { if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) { return false; } // Ensure gfxPrefs are initialized. gfxPrefs::GetSingleton(); CompositorThreadHolder::Start(); + VRManager::ManagerInit(); gfxPlatform::InitNullMetadata(); return true; } bool GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs) { - for (auto setting : prefs) { - gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()]; + const nsTArray<gfxPrefs::Pref*>& globalPrefs = gfxPrefs::all(); + for (auto& setting : prefs) { + gfxPrefs::Pref* pref = globalPrefs[setting.index()]; pref->SetCachedValue(setting.value()); } return true; } bool GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) { @@ -65,16 +69,23 @@ GPUParent::RecvInitVsyncBridge(Endpoint< bool GPUParent::RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) { ImageBridgeParent::CreateForGPUProcess(Move(aEndpoint)); return true; } bool +GPUParent::RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) +{ + VRManagerParent::CreateForGPUProcess(Move(aEndpoint)); + return true; +} + +bool GPUParent::RecvUpdatePref(const GfxPrefSetting& setting) { gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()]; pref->SetCachedValue(setting.value()); return true; } static void @@ -107,16 +118,22 @@ GPUParent::RecvNewContentCompositorBridg } bool GPUParent::RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) { return ImageBridgeParent::CreateForContent(Move(aEndpoint)); } +bool +GPUParent::RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) +{ + return VRManagerParent::CreateForContent(Move(aEndpoint)); +} + void GPUParent::ActorDestroy(ActorDestroyReason aWhy) { if (AbnormalShutdown == aWhy) { NS_WARNING("Shutting down GPU process early due to a crash!"); ProcessChild::QuickExit(); }
--- a/gfx/ipc/GPUParent.h +++ b/gfx/ipc/GPUParent.h @@ -22,24 +22,26 @@ public: bool Init(base::ProcessId aParentPid, MessageLoop* aIOLoop, IPC::Channel* aChannel); bool RecvInit(nsTArray<GfxPrefSetting>&& prefs) override; bool RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override; bool RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override; + bool RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override; bool RecvUpdatePref(const GfxPrefSetting& pref) override; bool RecvNewWidgetCompositor( Endpoint<PCompositorBridgeParent>&& aEndpoint, const CSSToLayoutDeviceScale& aScale, const bool& aUseExternalSurface, const IntSize& aSurfaceSize) override; bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override; bool RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override; + bool RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override; void ActorDestroy(ActorDestroyReason aWhy) override; private: RefPtr<VsyncBridgeParent> mVsyncBridge; }; } // namespace gfx
--- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -12,16 +12,18 @@ #include "mozilla/layers/InProcessCompositorSession.h" #include "mozilla/layers/RemoteCompositorSession.h" #include "mozilla/widget/PlatformWidgetTypes.h" #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING # include "mozilla/widget/CompositorWidgetChild.h" #endif #include "nsBaseWidget.h" #include "nsContentUtils.h" +#include "VRManagerChild.h" +#include "VRManagerParent.h" #include "VsyncBridgeChild.h" #include "VsyncIOThreadHolder.h" namespace mozilla { namespace gfx { using namespace mozilla::layers; @@ -157,16 +159,44 @@ GPUProcessManager::EnsureImageBridgeChil return; } mGPUChild->SendInitImageBridge(Move(parentPipe)); ImageBridgeChild::InitWithGPUProcess(Move(childPipe)); } void +GPUProcessManager::EnsureVRManager() +{ + if (VRManagerChild::IsCreated()) { + return; + } + + if (!mGPUChild) { + VRManagerChild::InitSameProcess(); + return; + } + + ipc::Endpoint<PVRManagerParent> parentPipe; + ipc::Endpoint<PVRManagerChild> childPipe; + nsresult rv = PVRManager::CreateEndpoints( + mGPUChild->OtherPid(), + base::GetCurrentProcId(), + &parentPipe, + &childPipe); + if (NS_FAILED(rv)) { + DisableGPUProcess("Failed to create PVRManager endpoints"); + return; + } + + mGPUChild->SendInitVRManager(Move(parentPipe)); + VRManagerChild::InitWithGPUProcess(Move(childPipe)); +} + +void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { MOZ_ASSERT(mProcess && mProcess == aHost); if (!mProcess->IsConnected()) { DisableGPUProcess("Failed to launch GPU process"); return; } @@ -253,16 +283,17 @@ GPUProcessManager::CreateTopLevelComposi CSSToLayoutDeviceScale aScale, bool aUseAPZ, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) { uint64_t layerTreeId = AllocateLayerTreeId(); EnsureImageBridgeChild(); + EnsureVRManager(); if (mGPUChild) { RefPtr<CompositorSession> session = CreateRemoteSession( aWidget, aLayerManager, layerTreeId, aScale, aUseAPZ, @@ -413,16 +444,50 @@ GPUProcessManager::CreateContentImageBri return false; } } *aOutEndpoint = Move(childPipe); return true; } +bool +GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess, + ipc::Endpoint<PVRManagerChild>* aOutEndpoint) +{ + EnsureVRManager(); + + base::ProcessId gpuPid = mGPUChild + ? mGPUChild->OtherPid() + : base::GetCurrentProcId(); + + ipc::Endpoint<PVRManagerParent> parentPipe; + ipc::Endpoint<PVRManagerChild> childPipe; + nsresult rv = PVRManager::CreateEndpoints( + gpuPid, + aOtherProcess, + &parentPipe, + &childPipe); + if (NS_FAILED(rv)) { + gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv)); + return false; + } + + if (mGPUChild) { + mGPUChild->SendNewContentVRManager(Move(parentPipe)); + } else { + if (!VRManagerParent::CreateForContent(Move(parentPipe))) { + return false; + } + } + + *aOutEndpoint = Move(childPipe); + return true; +} + already_AddRefed<APZCTreeManager> GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId) { return CompositorBridgeParent::GetAPZCTreeManager(aLayersId); } uint64_t GPUProcessManager::AllocateLayerTreeId()
--- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -40,16 +40,17 @@ class TabParent; namespace ipc { class GeckoChildProcessHost; } // namespace ipc namespace gfx { class GPUChild; class VsyncBridgeChild; class VsyncIOThreadHolder; +class PVRManagerChild; // The GPUProcessManager is a singleton responsible for creating GPU-bound // objects that may live in another process. Currently, it provides access // to the compositor via CompositorBridgeParent. class GPUProcessManager final : public GPUProcessHost::Listener { typedef layers::APZCTreeManager APZCTreeManager; typedef layers::ClientLayerManager ClientLayerManager; @@ -78,19 +79,20 @@ public: ClientLayerManager* aLayerManager, CSSToLayoutDeviceScale aScale, bool aUseAPZ, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize); bool CreateContentCompositorBridge(base::ProcessId aOtherProcess, ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint); - bool CreateContentImageBridge(base::ProcessId aOtherProcess, ipc::Endpoint<PImageBridgeChild>* aOutEndpoint); + bool CreateContentVRManager(base::ProcessId aOtherProcess, + ipc::Endpoint<PVRManagerChild>* aOutEndpoint); // This returns a reference to the APZCTreeManager to which // pan/zoom-related events can be sent. already_AddRefed<APZCTreeManager> GetAPZCTreeManagerForLayers(uint64_t aLayersId); // Allocate an ID that can be used to refer to a layer tree and // associated resources that live only on the compositor thread. // @@ -143,16 +145,17 @@ private: // Shutdown the GPU process. void CleanShutdown(); void DestroyProcess(); void EnsureVsyncIOThread(); void ShutdownVsyncIOThread(); void EnsureImageBridgeChild(); + void EnsureVRManager(); RefPtr<CompositorSession> CreateRemoteSession( nsBaseWidget* aWidget, ClientLayerManager* aLayerManager, const uint64_t& aRootLayerTreeId, CSSToLayoutDeviceScale aScale, bool aUseAPZ, bool aUseExternalSurfaceSize,
--- a/gfx/ipc/PGPU.ipdl +++ b/gfx/ipc/PGPU.ipdl @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 8; 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 protocol PCompositorBridge; include protocol PImageBridge; +include protocol PVRManager; include protocol PVsyncBridge; using mozilla::CSSToLayoutDeviceScale from "Units.h"; using mozilla::gfx::IntSize from "mozilla/gfx/2D.h"; namespace mozilla { namespace gfx { @@ -28,25 +29,27 @@ struct GfxPrefSetting { sync protocol PGPU { parent: // Sent by the UI process to initiate core settings. async Init(GfxPrefSetting[] prefs); async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint); async InitImageBridge(Endpoint<PImageBridgeParent> endpoint); + async InitVRManager(Endpoint<PVRManagerParent> endpoint); // Called to update a gfx preference. async UpdatePref(GfxPrefSetting pref); // Create a new top-level compositor. async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint, CSSToLayoutDeviceScale scale, bool useExternalSurface, IntSize surfaceSize); // Create a new content-process compositor bridge. async NewContentCompositorBridge(Endpoint<PCompositorBridgeParent> endpoint); async NewContentImageBridge(Endpoint<PImageBridgeParent> endpoint); + async NewContentVRManager(Endpoint<PVRManagerParent> endpoint); }; } // namespace gfx } // namespace mozilla
new file mode 100644 --- /dev/null +++ b/gfx/layers/apz/test/mochitest/helper_touch_action_complex.html @@ -0,0 +1,143 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width; initial-scale=1.0"> + <title>Complex touch-action test</title> + <script type="application/javascript" src="apz_test_native_event_utils.js"></script> + <script type="application/javascript" src="apz_test_utils.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script> + <script type="application/javascript"> + +function checkScroll(target, x, y, desc) { + is(target.scrollLeft, x, desc + " - x axis"); + is(target.scrollTop, y, desc + " - y axis"); +} + +function resetConfiguration(config, testDriver) { + // Cycle through all the configuration_X elements, setting them to display:none + // except for when X == config, in which case set it to display:block + var i = 0; + while (true) { + i++; + var element = document.getElementById('configuration_' + i); + if (element == null) { + if (i <= config) { + ok(false, "The configuration requested was not encountered!"); + } + break; + } + + if (i == config) { + element.style.display = 'block'; + } else { + element.style.display = 'none'; + } + } + + // Also reset the scroll position on the scrollframe + var s = document.getElementById('scrollframe'); + s.scrollLeft = 0; + s.scrollTop = 0; + + return waitForAllPaints(function() { + flushApzRepaints(testDriver); + }); +} + +function* test(testDriver) { + var scrollframe = document.getElementById('scrollframe'); + + document.body.addEventListener('touchend', testDriver, { passive: true }); + + // Helper function for the tests below. + // Touch-pan configuration |configuration| towards scroll offset (dx, dy) with + // the pan touching down at (x, y). Check that the final scroll offset is + // (ex, ey). |desc| is some description string. + function* scrollAndCheck(configuration, x, y, dx, dy, ex, ey, desc) { + // Start with a clean slate + yield resetConfiguration(configuration, testDriver); + // Figure out the panning deltas + if (dx != 0) { + dx = -(dx + TOUCH_SLOP); + } + if (dy != 0) { + dy = -(dy + TOUCH_SLOP); + } + // Do the pan + yield ok(synthesizeNativeTouchDrag(scrollframe, x, y, dx, dy), + "Synthesized drag of (" + dx + ", " + dy + ") on configuration " + configuration); + yield waitForAllPaints(function() { + flushApzRepaints(testDriver); + }); + // Check for expected scroll position + checkScroll(scrollframe, ex, ey, 'configuration ' + configuration + ' ' + desc); + } + + // Test configuration_1, which contains two sibling elements that are + // overlapping. The touch-action from the second sibling (which is on top) + // should be used for the overlapping area. + yield* scrollAndCheck(1, 25, 75, 20, 0, 20, 0, "first element horizontal scroll"); + yield* scrollAndCheck(1, 25, 75, 0, 50, 0, 0, "first element vertical scroll"); + yield* scrollAndCheck(1, 75, 75, 50, 0, 0, 0, "overlap horizontal scroll"); + yield* scrollAndCheck(1, 75, 75, 0, 50, 0, 50, "overlap vertical scroll"); + yield* scrollAndCheck(1, 125, 75, 20, 0, 0, 0, "second element horizontal scroll"); + yield* scrollAndCheck(1, 125, 75, 0, 50, 0, 50, "second element vertical scroll"); + + // Test configuration_2, which contains two overlapping elements with a + // parent/child relationship. The parent has pan-x and the child has pan-y, + // which means that panning on the parent should work horizontally only, and + // on the child no panning should occur at all. + yield* scrollAndCheck(2, 125, 125, 50, 50, 0, 0, "child scroll"); + yield* scrollAndCheck(2, 75, 75, 50, 50, 0, 0, "overlap scroll"); + yield* scrollAndCheck(2, 25, 75, 0, 50, 0, 0, "parent vertical scroll"); + yield* scrollAndCheck(2, 75, 25, 50, 0, 50, 0, "parent horizontal scroll"); + + // Test configuration_3, which is the same as configuration_2, except the child + // has a rotation transform applied. This forces the event regions on the two + // elements to be built separately and then get merged. + yield* scrollAndCheck(3, 125, 125, 50, 50, 0, 0, "child scroll"); + yield* scrollAndCheck(3, 75, 75, 50, 50, 0, 0, "overlap scroll"); + yield* scrollAndCheck(3, 25, 75, 0, 50, 0, 0, "parent vertical scroll"); + yield* scrollAndCheck(3, 75, 25, 50, 0, 50, 0, "parent horizontal scroll"); + + // Test configuration_4 has two elements, one above the other, not overlapping, + // and the second element is a child of the first. The parent has pan-x, the + // child has pan-y, but that means panning horizontally on the parent should + // work and panning in any direction on the child should not do anything. + yield* scrollAndCheck(4, 75, 75, 50, 50, 50, 0, "parent diagonal scroll"); + yield* scrollAndCheck(4, 75, 150, 50, 50, 0, 0, "child diagonal scroll"); +} + +waitUntilApzStable() +.then(runContinuation(test)) +.then(subtestDone); + + </script> +</head> +<body> + <div id="scrollframe" style="width: 300px; height: 300px; overflow:scroll"> + <div id="scrolled_content" style="width: 1000px; height: 1000px; background-color: green"> + </div> + <div id="configuration_1" style="display:none; position: relative; top: -1000px"> + <div style="touch-action: pan-x; width: 100px; height: 100px; background-color: blue"></div> + <div style="touch-action: pan-y; width: 100px; height: 100px; position: relative; top: -100px; left: 50px; background-color: yellow"></div> + </div> + <div id="configuration_2" style="display:none; position: relative; top: -1000px"> + <div style="touch-action: pan-x; width: 100px; height: 100px; background-color: blue"> + <div style="touch-action: pan-y; width: 100px; height: 100px; position: relative; top: 50px; left: 50px; background-color: yellow"></div> + </div> + </div> + <div id="configuration_3" style="display:none; position: relative; top: -1000px"> + <div style="touch-action: pan-x; width: 100px; height: 100px; background-color: blue"> + <div style="touch-action: pan-y; width: 100px; height: 100px; position: relative; top: 50px; left: 50px; background-color: yellow; transform: rotate(90deg)"></div> + </div> + </div> + <div id="configuration_4" style="display:none; position: relative; top: -1000px"> + <div style="touch-action: pan-x; width: 100px; height: 100px; background-color: blue"> + <div style="touch-action: pan-y; width: 100px; height: 100px; position: relative; top: 125px; background-color: yellow"></div> + </div> + </div> + </div> +</body> +</html>
--- a/gfx/layers/apz/test/mochitest/mochitest.ini +++ b/gfx/layers/apz/test/mochitest/mochitest.ini @@ -20,16 +20,17 @@ support-files = helper_bug1271432.html helper_touch_action.html helper_touch_action_regions.html helper_scroll_inactive_perspective.html helper_scroll_inactive_zindex.html helper_bug1280013.html helper_tall.html helper_drag_scroll.html + helper_touch_action_complex.html tags = apz [test_bug982141.html] [test_bug1151663.html] [test_bug1277814.html] skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet [test_wheel_scroll.html] skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet [test_wheel_transactions.html]
--- a/gfx/layers/apz/test/mochitest/test_group_touchevents.html +++ b/gfx/layers/apz/test/mochitest/test_group_touchevents.html @@ -1,14 +1,15 @@ <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Various touch tests that spawn in new windows</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="apz_test_native_event_utils.js"></script> <script type="application/javascript" src="apz_test_utils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <script type="application/javascript"> var basic_pan_prefs = [ // Dropping the touch slop to 0 makes the tests easier to write because // we can just do a one-pixel drag to get over the pan threshold rather // than having to hard-code some larger value. @@ -56,22 +57,29 @@ var subtests = [ // For the following test, we want to make sure APZ doesn't wait for a content // response that is never going to arrive. To detect this we set the content response // timeout to a day, so that the entire test times out and fails if APZ does // end up waiting. {'file': 'helper_tap_passive.html', 'prefs': [["apz.content_response_timeout", 24 * 60 * 60 * 1000]]}, // Simple test to exercise touch-action CSS property {'file': 'helper_touch_action.html', 'prefs': touch_action_prefs}, + // More complex touch-action tests, with overlapping regions and such + {'file': 'helper_touch_action_complex.html', 'prefs': touch_action_prefs}, // Tests that touch-action CSS properties are handled in APZ without waiting // on the main-thread, when possible {'file': 'helper_touch_action_regions.html', 'prefs': touch_action_prefs}, ]; if (isApzEnabled()) { + if (getPlatform() == "android") { + // This has a lot of subtests, and Android emulators are slow. + SimpleTest.requestLongerTimeout(2); + } + SimpleTest.waitForExplicitFinish(); window.onload = function() { runSubtestsSeriallyInFreshWindows(subtests) .then(SimpleTest.finish); }; } </script>
--- a/gfx/layers/client/TextureClientPool.cpp +++ b/gfx/layers/client/TextureClientPool.cpp @@ -14,40 +14,35 @@ #include "nsComponentManagerUtils.h" #define TCP_LOG(...) //#define TCP_LOG(...) printf_stderr(__VA_ARGS__); namespace mozilla { namespace layers { -static void -ShrinkCallback(nsITimer *aTimer, void *aClosure) -{ - static_cast<TextureClientPool*>(aClosure)->ShrinkToMinimumSize(); -} TextureClientPool::TextureClientPool(LayersBackend aLayersBackend, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, TextureFlags aFlags, - uint32_t aMaxTextureClients, - uint32_t aShrinkTimeoutMsec, + uint32_t aInitialPoolSize, + uint32_t aPoolIncrementSize, TextureForwarder* aAllocator) : mBackend(aLayersBackend) , mFormat(aFormat) , mSize(aSize) , mFlags(aFlags) - , mMaxTextureClients(aMaxTextureClients) - , mShrinkTimeoutMsec(aShrinkTimeoutMsec) + , mInitialPoolSize(aInitialPoolSize) + , mPoolIncrementSize(aPoolIncrementSize) , mOutstandingClients(0) , mSurfaceAllocator(aAllocator) { - TCP_LOG("TexturePool %p created with max size %u and timeout %u\n", - this, mMaxTextureClients, aShrinkTimeoutMsec); + TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n", + this, mInitialPoolSize); mTimer = do_CreateInstance("@mozilla.org/timer;1"); if (aFormat == gfx::SurfaceFormat::UNKNOWN) { gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format"; } } TextureClientPool::~TextureClientPool() { @@ -87,56 +82,76 @@ static bool TestClientPool(const char* w } #endif already_AddRefed<TextureClient> TextureClientPool::GetTextureClient() { // Try to fetch a client from the pool RefPtr<TextureClient> textureClient; - if (mTextureClients.size()) { - mOutstandingClients++; - textureClient = mTextureClients.top(); - mTextureClients.pop(); -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this); - MOZ_ASSERT(ok); -#endif - TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n", - this, textureClient.get(), mTextureClients.size(), mOutstandingClients); - return textureClient.forget(); + + // We initially allocate mInitialPoolSize for our pool. If we run + // out of TextureClients, we allocate additional TextureClients to try and keep around + // mPoolIncrementSize + if (!mTextureClients.size()) { + size_t size = mOutstandingClients ? mPoolIncrementSize : mInitialPoolSize; + AllocateTextureClients(size); } - // We're increasing the number of outstanding TextureClients without reusing a - // client, we may need to free a deferred-return TextureClient. - ShrinkToMaximumSize(); - - // No unused clients in the pool, create one - if (gfxPrefs::ForceShmemTiles()) { - // gfx::BackendType::NONE means use the content backend - textureClient = TextureClient::CreateForRawBufferAccess(mSurfaceAllocator, - mFormat, mSize, gfx::BackendType::NONE, - mFlags, ALLOC_DEFAULT); - } else { - textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator, - mFormat, mSize, mBackend, BackendSelector::Content, mFlags); + if (!mTextureClients.size()) { + // All our allocations failed, return nullptr + return nullptr; } mOutstandingClients++; + textureClient = mTextureClients.top(); + mTextureClients.pop(); #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL if (textureClient) { textureClient->mPoolTracker = this; } + DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this); + MOZ_ASSERT(ok); #endif - TCP_LOG("TexturePool %p giving new %p; size %u outstanding %u\n", + TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n", this, textureClient.get(), mTextureClients.size(), mOutstandingClients); + return textureClient.forget(); } void +TextureClientPool::AllocateTextureClients(size_t aSize) +{ + TCP_LOG("TexturePool %p allocating %u clients, outstanding %u\n", + this, aSize, mOutstandingClients); + + RefPtr<TextureClient> newClient; + while (mTextureClients.size() < aSize) { + if (gfxPrefs::ForceShmemTiles()) { + // gfx::BackendType::NONE means use the content backend + newClient = + TextureClient::CreateForRawBufferAccess(mSurfaceAllocator, + mFormat, mSize, + gfx::BackendType::NONE, + mFlags, ALLOC_DEFAULT); + } else { + newClient = + TextureClient::CreateForDrawing(mSurfaceAllocator, + mFormat, mSize, + mBackend, + BackendSelector::Content, + mFlags); + } + if (newClient) { + mTextureClients.push(newClient); + } + } +} + +void TextureClientPool::ReturnTextureClient(TextureClient *aClient) { if (!aClient) { return; } #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL DebugOnly<bool> ok = TestClientPool("return", aClient, this); MOZ_ASSERT(ok); @@ -145,24 +160,16 @@ TextureClientPool::ReturnTextureClient(T MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size()); mOutstandingClients--; mTextureClients.push(aClient); TCP_LOG("TexturePool %p had client %p returned; size %u outstanding %u\n", this, aClient, mTextureClients.size(), mOutstandingClients); // Shrink down if we're beyond our maximum size ShrinkToMaximumSize(); - - // Kick off the pool shrinking timer if there are still more unused texture - // clients than our desired minimum cache size. - if (mTextureClients.size() > sMinCacheSize) { - TCP_LOG("TexturePool %p scheduling a shrink-to-min-size\n", this); - mTimer->InitWithFuncCallback(ShrinkCallback, this, mShrinkTimeoutMsec, - nsITimer::TYPE_ONE_SHOT); - } } void TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient) { if (!aClient) { return; } @@ -175,90 +182,64 @@ TextureClientPool::ReturnTextureClientDe TCP_LOG("TexturePool %p had client %p defer-returned, size %u outstanding %u\n", this, aClient, mTextureClientsDeferred.size(), mOutstandingClients); ShrinkToMaximumSize(); } void TextureClientPool::ShrinkToMaximumSize() { - uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients; - TCP_LOG("TexturePool %p shrinking to max size %u; total outstanding %u\n", - this, mMaxTextureClients, totalClientsOutstanding); - // We're over our desired maximum size, immediately shrink down to the - // maximum, or zero if we have too many outstanding texture clients. + // maximum. + // // We cull from the deferred TextureClients first, as we can't reuse those // until they get returned. - while (totalClientsOutstanding > mMaxTextureClients) { + uint32_t totalUnusedTextureClients = mTextureClients.size() + mTextureClientsDeferred.size(); + + // If we have > mInitialPoolSize outstanding, then we want to keep around + // mPoolIncrementSize at a maximum. If we have fewer than mInitialPoolSize + // outstanding, then keep around the entire initial pool size. + uint32_t targetUnusedClients; + if (mOutstandingClients > mInitialPoolSize) { + targetUnusedClients = mPoolIncrementSize; + } else { + targetUnusedClients = mInitialPoolSize; + } + + TCP_LOG("TexturePool %p shrinking to maximum unused size %u; total outstanding %u\n", + this, targetUnusedClients, mOutstandingClients); + + while (totalUnusedTextureClients > targetUnusedClients) { if (mTextureClientsDeferred.size()) { - MOZ_ASSERT(mOutstandingClients > 0); mOutstandingClients--; TCP_LOG("TexturePool %p dropped deferred client %p; %u remaining\n", this, mTextureClientsDeferred.front().get(), mTextureClientsDeferred.size() - 1); mTextureClientsDeferred.pop_front(); } else { - if (!mTextureClients.size()) { - // Getting here means we're over our desired number of TextureClients - // with none in the pool. This can happen during shutdown, or for - // pathological cases, or it could mean that mMaxTextureClients needs - // adjusting for whatever device we're running on. - TCP_LOG("TexturePool %p encountering pathological case!\n", this); - break; - } TCP_LOG("TexturePool %p dropped non-deferred client %p; %u remaining\n", this, mTextureClients.top().get(), mTextureClients.size() - 1); mTextureClients.pop(); } - totalClientsOutstanding--; - } -} - -void -TextureClientPool::ShrinkToMinimumSize() -{ - ReturnUnlockedClients(); - - while (!mTextureClientsDeferred.empty()) { - MOZ_ASSERT(mOutstandingClients > 0); - mOutstandingClients--; - TCP_LOG("TexturePool %p releasing deferred client %p\n", - this, mTextureClientsDeferred.front().get()); - mTextureClientsDeferred.pop_front(); - } - - TCP_LOG("TexturePool %p shrinking to minimum size %u\n", this, sMinCacheSize); - while (mTextureClients.size() > sMinCacheSize) { - TCP_LOG("TexturePool %p popped %p; shrunk to %u\n", - this, mTextureClients.top().get(), mTextureClients.size() - 1); - mTextureClients.pop(); + totalUnusedTextureClients--; } } void TextureClientPool::ReturnDeferredClients() { - TCP_LOG("TexturePool %p returning %u deferred clients to pool\n", - this, mTextureClientsDeferred.size()); - if (mTextureClientsDeferred.empty()) { return; } + TCP_LOG("TexturePool %p returning %u deferred clients to pool\n", + this, mTextureClientsDeferred.size()); + ReturnUnlockedClients(); ShrinkToMaximumSize(); - - // Kick off the pool shrinking timer if there are still more unused texture - // clients than our desired minimum cache size. - if (mTextureClients.size() > sMinCacheSize) { - TCP_LOG("TexturePool %p kicking off shrink-to-min timer\n", this); - mTimer->InitWithFuncCallback(ShrinkCallback, this, mShrinkTimeoutMsec, - nsITimer::TYPE_ONE_SHOT); - } } void TextureClientPool::ReturnUnlockedClients() { for (auto it = mTextureClientsDeferred.begin(); it != mTextureClientsDeferred.end();) { MOZ_ASSERT((*it)->GetReadLock()->GetReadCount() >= 1); // Last count is held by the lock itself. @@ -299,13 +280,14 @@ TextureClientPool::Clear() this, mTextureClientsDeferred.front().get()); mTextureClientsDeferred.pop_front(); } } void TextureClientPool::Destroy() { Clear(); - mMaxTextureClients = 0; + mInitialPoolSize = 0; + mPoolIncrementSize = 0; } } // namespace layers } // namespace mozilla
--- a/gfx/layers/client/TextureClientPool.h +++ b/gfx/layers/client/TextureClientPool.h @@ -43,18 +43,18 @@ class TextureClientPool final : public T { ~TextureClientPool(); public: TextureClientPool(LayersBackend aBackend, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, TextureFlags aFlags, - uint32_t aMaxTextureClients, - uint32_t aShrinkTimeoutMsec, + uint32_t aInitialPoolSize, + uint32_t aPoolIncrementSize, TextureForwarder* aAllocator); /** * Gets an allocated TextureClient of size and format that are determined * by the initialisation parameters given to the pool. This will either be * a cached client that was returned to the pool, or a newly allocated * client if one isn't available. * @@ -71,34 +71,28 @@ public: /** * Return a TextureClient that is not yet ready to be reused, but will be * imminently. */ void ReturnTextureClientDeferred(TextureClient *aClient) override; /** - * Attempt to shrink the pool so that there are no more than - * mMaxTextureClients clients outstanding. - */ - void ShrinkToMaximumSize(); - - /** - * Attempt to shrink the pool so that there are no more than sMinCacheSize - * unused clients. - */ - void ShrinkToMinimumSize(); - - /** * Return any clients to the pool that were previously returned in * ReturnTextureClientDeferred. */ void ReturnDeferredClients(); /** + * Attempt to shrink the pool so that there are no more than + * mInitialPoolSize outstanding. + */ + void ShrinkToMaximumSize(); + + /** * Report that a client retrieved via GetTextureClient() has become * unusable, so that it will no longer be tracked. */ virtual void ReportClientLost() override; /** * Calling this will cause the pool to attempt to relinquish any unused * clients. @@ -112,39 +106,41 @@ public: /** * Clear the pool and put it in a state where it won't recycle any new texture. */ void Destroy(); private: void ReturnUnlockedClients(); - // The minimum size of the pool (the number of tiles that will be kept after - // shrinking). - static const uint32_t sMinCacheSize = 0; + /// We maintain a number of unused texture clients for immediate return from + /// GetTextureClient(). This will normally be called if there are no + /// TextureClients available in the pool, which ideally should only ever + /// be at startup. + void AllocateTextureClients(size_t aSize); /// Backend passed to the TextureClient for buffer creation. LayersBackend mBackend; /// Format is passed to the TextureClient for buffer creation. gfx::SurfaceFormat mFormat; /// The width and height of the tiles to be used. gfx::IntSize mSize; /// Flags passed to the TextureClient for buffer creation. const TextureFlags mFlags; - // The maximum number of texture clients managed by this pool that we want - // to remain active. - uint32_t mMaxTextureClients; + // The initial number of unused texture clients to seed the pool with + // on construction + uint32_t mInitialPoolSize; - // The time in milliseconds before the pool will be shrunk to the minimum - // size after returning a client. - uint32_t mShrinkTimeoutMsec; + // How many unused texture clients to try and keep around if we go over + // the initial allocation + uint32_t mPoolIncrementSize; /// This is a total number of clients in the wild and in the stack of /// deferred clients (see below). So, the total number of clients in /// existence is always mOutstandingClients + the size of mTextureClients. uint32_t mOutstandingClients; // On b2g gonk, std::queue might be a better choice. // On ICS, fence wait happens implicitly before drawing.
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -924,28 +924,28 @@ CompositorBridgeChild::GetTexturePool(La } } mTexturePools.AppendElement( new TextureClientPool(aBackend, aFormat, IntSize(gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight()), aFlags, - gfxPrefs::LayersTileMaxPoolSize(), - gfxPrefs::LayersTileShrinkPoolTimeout(), + gfxPrefs::LayersTileInitialPoolSize(), + gfxPrefs::LayersTilePoolIncrementSize(), this)); return mTexturePools.LastElement(); } void CompositorBridgeChild::HandleMemoryPressure() { for (size_t i = 0; i < mTexturePools.Length(); i++) { - mTexturePools[i]->ShrinkToMinimumSize(); + mTexturePools[i]->Clear(); } } void CompositorBridgeChild::ClearTexturePool() { for (size_t i = 0; i < mTexturePools.Length(); i++) { mTexturePools[i]->Clear();
--- a/gfx/skia/skia/src/effects/SkDashPathEffect.cpp +++ b/gfx/skia/skia/src/effects/SkDashPathEffect.cpp @@ -243,17 +243,24 @@ bool SkDashPathEffect::asPoints(PointDat len2 -= fIntervals[1]; // also skip first space if (len2 < 0) { len2 = 0; } } else { len2 -= clampedInitialDashLength; // skip initial partial empty } } - int numMidPoints = SkScalarFloorToInt(len2 / fIntervalLength); + // Too many midpoints can cause results->fNumPoints to overflow or + // otherwise cause the results->fPoints allocation below to OOM. + // Cap it to a sane value. + SkScalar numIntervals = len2 / fIntervalLength; + if (!SkScalarIsFinite(numIntervals) || numIntervals > SkDashPath::kMaxDashCount) { + return false; + } + int numMidPoints = SkScalarFloorToInt(numIntervals); results->fNumPoints += numMidPoints; len2 -= numMidPoints * fIntervalLength; bool partialLast = false; if (len2 > 0) { if (len2 < fIntervals[0]) { partialLast = true; } else { ++numMidPoints;
--- a/gfx/skia/skia/src/gpu/GrDrawContext.cpp +++ b/gfx/skia/skia/src/gpu/GrDrawContext.cpp @@ -985,17 +985,22 @@ void GrDrawContext::internalDrawPath(con if (nullptr == pr) { if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) && !strokeInfoPtr->isFillStyle()) { // It didn't work above, so try again with stroke converted to a fill. if (!tmpPath.isValid()) { tmpPath.init(); } - dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())); + SkScalar scale = SkScalarAbs(viewMatrix.getMaxScale()); + if (!SkScalarIsFinite(scale)) { + SkDebugf("View matrix scale is not finite.\n"); + return; + } + dashlessStrokeInfo.setResScale(scale); if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { return; } pathPtr = tmpPath.get(); if (pathPtr->isEmpty()) { return; } dashlessStrokeInfo.setFillStyle();
--- a/gfx/skia/skia/src/utils/SkDashPath.cpp +++ b/gfx/skia/skia/src/utils/SkDashPath.cpp @@ -171,16 +171,17 @@ public: // now estimate how many quads will be added to the path // resulting segments = pathLen * intervalCount / intervalLen // resulting points = 4 * segments SkScalar ptCount = SkScalarMulDiv(pathLength, SkIntToScalar(intervalCount), intervalLength); + ptCount = SkTMin(ptCount, SkDashPath::kMaxDashCount); int n = SkScalarCeilToInt(ptCount) << 2; dst->incReserve(n); // we will take care of the stroking rec->setFillStyle(); return true; } @@ -247,17 +248,16 @@ bool SkDashPath::InternalFilter(SkPath* // Since the path length / dash length ratio may be arbitrarily large, we can exert // significant memory pressure while attempting to build the filtered path. To avoid this, // we simply give up dashing beyond a certain threshold. // // The original bug report (http://crbug.com/165432) is based on a path yielding more than // 90 million dash segments and crashing the memory allocator. A limit of 1 million // segments seems reasonable: at 2 verbs per segment * 9 bytes per verb, this caps the // maximum dash memory overhead at roughly 17MB per path. - static const SkScalar kMaxDashCount = 1000000; dashCount += length * (count >> 1) / intervalLength; if (dashCount > kMaxDashCount) { dst->reset(); return false; } // Using double precision to avoid looping indefinitely due to single precision rounding // (for extreme path_length/dash_length ratios). See test_infinite_dash() unittest.
--- a/gfx/skia/skia/src/utils/SkDashPathPriv.h +++ b/gfx/skia/skia/src/utils/SkDashPathPriv.h @@ -21,16 +21,18 @@ namespace SkDashPath { */ void CalcDashParameters(SkScalar phase, const SkScalar intervals[], int32_t count, SkScalar* initialDashLength, int32_t* initialDashIndex, SkScalar* intervalLength, SkScalar* adjustedPhase = nullptr); bool FilterDashPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*, const SkPathEffect::DashInfo& info); + const SkScalar kMaxDashCount = 1000000; + /* * Caller should have already used ValidDashPath to exclude invalid data. */ bool InternalFilter(SkPath* dst, const SkPath& src, SkStrokeRec* rec, const SkRect* cullRect, const SkScalar aIntervals[], int32_t count, SkScalar initialDashLength, int32_t initialDashIndex, SkScalar intervalLength);
--- a/gfx/src/nsRect.cpp +++ b/gfx/src/nsRect.cpp @@ -1,44 +1,30 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsRect.h" #include "mozilla/gfx/Types.h" // for NS_SIDE_BOTTOM, etc -#include "mozilla/CheckedInt.h" // for CheckedInt #include "nsDeviceContext.h" // for nsDeviceContext #include "nsString.h" // for nsAutoString, etc #include "nsMargin.h" // for nsMargin static_assert((int(NS_SIDE_TOP) == 0) && (int(NS_SIDE_RIGHT) == 1) && (int(NS_SIDE_BOTTOM) == 2) && (int(NS_SIDE_LEFT) == 3), "The mozilla::css::Side sequence must match the nsMargin nscoord sequence"); const mozilla::gfx::IntRect& GetMaxSizedIntRect() { static const mozilla::gfx::IntRect r(0, 0, INT32_MAX, INT32_MAX); return r; } - -bool nsRect::Overflows() const { -#ifdef NS_COORD_IS_FLOAT - return false; -#else - mozilla::CheckedInt<int32_t> xMost = this->x; - xMost += this->width; - mozilla::CheckedInt<int32_t> yMost = this->y; - yMost += this->height; - return !xMost.isValid() || !yMost.isValid(); -#endif -} - #ifdef DEBUG // Diagnostics FILE* operator<<(FILE* out, const nsRect& rect) { nsAutoString tmp; // Output the coordinates in fractional pixels so they're easier to read
--- a/gfx/src/nsRect.h +++ b/gfx/src/nsRect.h @@ -124,19 +124,16 @@ struct nsRect : { *this = aRect1.SaturatingUnion(aRect2); } void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2) { *this = aRect1.SaturatingUnionEdges(aRect2); } - // Return whether this rect's right or bottom edge overflow int32. - bool Overflows() const; - /** * Return this rect scaled to a different appunits per pixel (APP) ratio. * In the RoundOut version we make the rect the smallest rect containing the * unrounded result. In the RoundIn version we make the rect the largest rect * contained in the unrounded result. * @param aFromAPP the APP to scale from * @param aToAPP the APP to scale to * @note this can turn an empty rectangle into a non-empty rectangle
--- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -14,17 +14,16 @@ #include "gfxMatrix.h" #include "gfxPattern.h" #include "nsTArray.h" #include "mozilla/gfx/2D.h" typedef struct _cairo cairo_t; class GlyphBufferAzure; -template <typename T> class FallibleTArray; namespace mozilla { namespace gfx { struct RectCornerRadii; } // namespace gfx } // namespace mozilla class ClipExporter; @@ -208,30 +207,30 @@ public: * resulting rectangle is the minimum device-space rectangle that * encloses the user-space rectangle given. */ gfxRect UserToDevice(const gfxRect& rect) const; /** * Takes the given rect and tries to align it to device pixels. If * this succeeds, the method will return true, and the rect will - * be in device coordinates (already transformed by the CTM). If it + * be in device coordinates (already transformed by the CTM). If it * fails, the method will return false, and the rect will not be * changed. * * If ignoreScale is true, then snapping will take place even if * the CTM has a scale applied. Snapping never takes place if * there is a rotation in the CTM. */ bool UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale = false) const; /** * Takes the given point and tries to align it to device pixels. If * this succeeds, the method will return true, and the point will - * be in device coordinates (already transformed by the CTM). If it + * be in device coordinates (already transformed by the CTM). If it * fails, the method will return false, and the point will not be * changed. * * If ignoreScale is true, then snapping will take place even if * the CTM has a scale applied. Snapping never takes place if * there is a rotation in the CTM. */ bool UserToDevicePixelSnapped(gfxPoint& pt, bool ignoreScale = false) const; @@ -385,18 +384,18 @@ public: gfxRect GetClipExtents(); /** * Whether the current clip is not a simple rectangle. */ bool HasComplexClip() const; /** - * Returns true if the given rectangle is fully contained in the current clip. - * This is conservative; it may return false even when the given rectangle is + * Returns true if the given rectangle is fully contained in the current clip. + * This is conservative; it may return false even when the given rectangle is * fully contained by the current clip. */ bool ClipContainsRect(const gfxRect& aRect); /** * Exports the current clip using the provided exporter. */ bool ExportClip(ClipExporter& aExporter); @@ -466,17 +465,17 @@ private: typedef mozilla::gfx::Matrix Matrix; typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::Color Color; typedef mozilla::gfx::StrokeOptions StrokeOptions; typedef mozilla::gfx::Float Float; typedef mozilla::gfx::PathBuilder PathBuilder; typedef mozilla::gfx::SourceSurface SourceSurface; - + struct AzureState { AzureState() : op(mozilla::gfx::CompositionOp::OP_OVER) , color(0, 0, 0, 1.0f) , aaMode(mozilla::gfx::AntialiasMode::SUBPIXEL) , patternTransformChanged(false) , mBlendOpacity(0.0f) {} @@ -557,17 +556,17 @@ public: ~gfxContextAutoSaveRestore() { Restore(); } void SetContext(gfxContext *aContext) { NS_ASSERTION(!mContext, "Not going to call Restore() on some context!!!"); mContext = aContext; - mContext->Save(); + mContext->Save(); } void EnsureSaved(gfxContext *aContext) { MOZ_ASSERT(!mContext || mContext == aContext, "wrong context"); if (!mContext) { mContext = aContext; mContext->Save(); }
--- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -27,16 +27,20 @@ #include <fontconfig/fcfreetype.h> #ifdef MOZ_WIDGET_GTK #include <gdk/gdk.h> #include "gfxPlatformGtk.h" #endif +#ifdef MOZ_X11 +#include "mozilla/X11Util.h" +#endif + using namespace mozilla; using namespace mozilla::unicode; #ifndef FC_POSTSCRIPT_NAME #define FC_POSTSCRIPT_NAME "postscriptname" /* String */ #endif #define PRINTING_FC_PROPERTY "gfx.printing" @@ -712,16 +716,39 @@ gfxFontconfigFontEntry::CreateScaledFont return scaledFont; } #ifdef MOZ_WIDGET_GTK // defintion included below static void ApplyGdkScreenFontOptions(FcPattern *aPattern); #endif +#ifdef MOZ_X11 +static bool +GetXftInt(Display* aDisplay, const char* aName, int* aResult) +{ + if (!aDisplay) { + return false; + } + char* value = XGetDefault(aDisplay, "Xft", aName); + if (!value) { + return false; + } + if (FcNameConstant(const_cast<FcChar8*>(ToFcChar8Ptr(value)), aResult)) { + return true; + } + char* end; + *aResult = strtol(value, &end, 0); + if (end != value) { + return true; + } + return false; +} +#endif + static void PreparePattern(FcPattern* aPattern, bool aIsPrinterFont) { FcConfigSubstitute(nullptr, aPattern, FcMatchPattern); // This gets cairo_font_options_t for the Screen. We should have // different font options for printing (no hinting) but we are not told // what we are measuring for. @@ -740,16 +767,26 @@ PreparePattern(FcPattern* aPattern, bool cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); cairo_ft_font_options_substitute(options, aPattern); cairo_font_options_destroy(options); FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue); } else { #ifdef MOZ_WIDGET_GTK ApplyGdkScreenFontOptions(aPattern); #endif + +#ifdef MOZ_X11 + FcValue value; + int lcdfilter; + if (FcPatternGet(aPattern, FC_LCD_FILTER, 0, &value) + == FcResultNoMatch && + GetXftInt(DefaultXDisplay(), "lcdfilter", &lcdfilter)) { + FcPatternAddInteger(aPattern, FC_LCD_FILTER, lcdfilter); + } +#endif } FcDefaultSubstitute(aPattern); } gfxFont* gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
--- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -881,17 +881,17 @@ nsresult gfxFontUtils::MakeUniqueUserFon // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> - char *p; for (p = guidB64; *p; p++) { if (*p == '/') *p = '-'; } - aName.AssignLiteral(MOZ_UTF16("uf")); + aName.AssignLiteral(u"uf"); aName.AppendASCII(guidB64); return NS_OK; } // TrueType/OpenType table handling code // need byte aligned structs
--- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -24,17 +24,18 @@ class gfxMacPlatformFontList; // a single member of a font family (i.e. a single face, such as Times Italic) class MacOSFontEntry : public gfxFontEntry { public: friend class gfxMacPlatformFontList; MacOSFontEntry(const nsAString& aPostscriptName, int32_t aWeight, - bool aIsStandardFace = false); + bool aIsStandardFace = false, + double aSizeHint = 0.0); // for use with data fonts MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef, uint16_t aWeight, uint16_t aStretch, uint8_t aStyle, bool aIsDataUserFont, bool aIsLocal); virtual ~MacOSFontEntry() { ::CGFontRelease(mFontRef); @@ -59,16 +60,18 @@ protected: virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) override; virtual bool HasFontTable(uint32_t aTableTag) override; static void DestroyBlobFunc(void* aUserData); CGFontRef mFontRef; // owning reference to the CGFont, released on destruction + double mSizeHint; + bool mFontRefInitialized; bool mRequiresAAT; bool mIsCFF; bool mIsCFFInitialized; nsTHashtable<nsUint32HashKey> mAvailableTables; }; class gfxMacPlatformFontList : public gfxPlatformFontList { @@ -115,17 +118,17 @@ private: // initialize font lists nsresult InitFontList() override; // special case font faces treated as font families (set via prefs) void InitSingleFaceList(); // initialize system fonts - void InitSystemFonts(); + void InitSystemFontNames(); // helper function to lookup in both hidden system fonts and normal fonts gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily); static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, @@ -164,13 +167,13 @@ private: // for different locales (e.g. .Helvetica Neue UI, .SF NS Text) FontFamilyTable mSystemFontFamilies; // font families that -apple-system maps to // Pre-10.11 this was always a single font family, such as Lucida Grande // or Helvetica Neue. For OSX 10.11, Apple uses pair of families // for the UI, one for text sizes and another for display sizes bool mUseSizeSensitiveSystemFont; - RefPtr<gfxFontFamily> mSystemTextFontFamily; - RefPtr<gfxFontFamily> mSystemDisplayFontFamily; // only used on OSX 10.11 + nsString mSystemTextFontFamilyName; + nsString mSystemDisplayFontFamilyName; // only used on OSX 10.11 }; #endif /* gfxMacPlatformFontList_H_ */
--- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -250,35 +250,38 @@ MacOSFontEntry::IsCFF() mIsCFF = HasFontTable(TRUETYPE_TAG('C','F','F',' ')); } return mIsCFF; } MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, int32_t aWeight, - bool aIsStandardFace) + bool aIsStandardFace, + double aSizeHint) : gfxFontEntry(aPostscriptName, aIsStandardFace), mFontRef(NULL), + mSizeHint(aSizeHint), mFontRefInitialized(false), mRequiresAAT(false), mIsCFF(false), mIsCFFInitialized(false) { mWeight = aWeight; } MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef, uint16_t aWeight, uint16_t aStretch, uint8_t aStyle, bool aIsDataUserFont, bool aIsLocalUserFont) : gfxFontEntry(aPostscriptName, false), mFontRef(NULL), + mSizeHint(0.0), mFontRefInitialized(false), mRequiresAAT(false), mIsCFF(false), mIsCFFInitialized(false) { mFontRef = aFontRef; mFontRefInitialized = true; ::CFRetain(mFontRef); @@ -296,16 +299,29 @@ MacOSFontEntry::MacOSFontEntry(const nsA CGFontRef MacOSFontEntry::GetFontRef() { if (!mFontRefInitialized) { mFontRefInitialized = true; NSString *psname = GetNSStringForString(mName); mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname)); + if (!mFontRef) { + // This happens on macOS 10.12 for font entry names that start with + // .AppleSystemUIFont. For those fonts, we need to go through NSFont + // to get the correct CGFontRef. + // Both the Text and the Display variant of the display font use + // .AppleSystemUIFontSomethingSomething as their member names. + // That's why we're carrying along mSizeHint to this place so that + // we get the variant that we want for this family. + NSFont* font = [NSFont fontWithName:psname size:mSizeHint]; + if (font) { + mFontRef = CTFontCopyGraphicsFont((CTFontRef)font, nullptr); + } + } } return mFontRef; } // For a logging build, we wrap the CFDataRef in a FontTableRec so that we can // use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging // does not get this overhead. class FontTableRec { @@ -394,25 +410,29 @@ MacOSFontEntry::AddSizeOfIncludingThis(M } /* gfxMacFontFamily */ #pragma mark- class gfxMacFontFamily : public gfxFontFamily { public: - explicit gfxMacFontFamily(nsAString& aName) : - gfxFontFamily(aName) + explicit gfxMacFontFamily(nsAString& aName, double aSizeHint) : + gfxFontFamily(aName), + mSizeHint(aSizeHint) {} virtual ~gfxMacFontFamily() {} virtual void LocalizedName(nsAString& aLocalizedName); virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr); + +protected: + double mSizeHint; }; void gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName) { nsAutoreleasePool localPool; if (!HasOtherFamilyNames()) { @@ -502,17 +522,17 @@ gfxMacFontFamily::FindStyleVariations(Fo [facename isEqualToString:@"Bold Italic"] || [facename isEqualToString:@"Bold Oblique"]) { isStandardFace = true; } // create a font entry MacOSFontEntry *fontEntry = - new MacOSFontEntry(postscriptFontName, cssWeight, isStandardFace); + new MacOSFontEntry(postscriptFontName, cssWeight, isStandardFace, mSizeHint); if (!fontEntry) { break; } // set additional properties based on the traits reported by Cocoa if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) { fontEntry->mStretch = NS_FONT_STRETCH_CONDENSED; } else if (macTraits & NSExpandedFontMask) { @@ -668,20 +688,26 @@ gfxMacPlatformFontList::AddFamily(CFStri bool hiddenSystemFont = [family hasPrefix:@"."]; FontFamilyTable& table = hiddenSystemFont ? mSystemFontFamilies : mFontFamilies; nsAutoString familyName; nsCocoaUtils::GetStringForNSString(family, familyName); + double sizeHint = 0.0; + if (hiddenSystemFont && mUseSizeSensitiveSystemFont && + mSystemDisplayFontFamilyName.Equals(familyName)) { + sizeHint = 128.0; + } + nsAutoString key; ToLowerCase(familyName, key); - gfxFontFamily* familyEntry = new gfxMacFontFamily(familyName); + gfxFontFamily* familyEntry = new gfxMacFontFamily(familyName, sizeHint); table.Put(key, familyEntry); // check the bad underline blacklist if (mBadUnderlineFamilyNames.Contains(key)) { familyEntry->SetBadUnderlineFamily(); } } @@ -693,28 +719,28 @@ gfxMacPlatformFontList::InitFontList() Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer; // reset font lists gfxPlatformFontList::InitFontList(); mSystemFontFamilies.Clear(); // iterate over available families + InitSystemFontNames(); + CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames(); for (NSString* familyName in (NSArray*)familyNames) { AddFamily((CFStringRef)familyName); } CFRelease(familyNames); InitSingleFaceList(); - InitSystemFonts(); - // to avoid full search of font name tables, seed the other names table with localized names from // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause // a font lookup miss earlier. this is a simple optimization, it's not required for correctness PreloadNamesList(); // start the delayed cmap loader GetPrefsAndStartLoader(); @@ -787,43 +813,40 @@ static NSString* GetRealFamilyName(NSFon // for text sizes and another for larger, display sizes. Each has a // different number of weights. There aren't efficient API's for looking // this information up, so hard code the logic here but confirm via // debug assertions that the logic is correct. const CGFloat kTextDisplayCrossover = 20.0; // use text family below this size void -gfxMacPlatformFontList::InitSystemFonts() +gfxMacPlatformFontList::InitSystemFontNames() { // system font under 10.11 are two distinct families for text/display sizes if (nsCocoaFeatures::OnElCapitanOrLater()) { mUseSizeSensitiveSystemFont = true; } // text font family NSFont* sys = [NSFont systemFontOfSize: 0.0]; NSString* textFamilyName = GetRealFamilyName(sys); nsAutoString familyName; nsCocoaUtils::GetStringForNSString(textFamilyName, familyName); - mSystemTextFontFamily = FindSystemFontFamily(familyName); - NS_ASSERTION(mSystemTextFontFamily, "null system display font family"); + mSystemTextFontFamilyName = familyName; // display font family, if on OSX 10.11 if (mUseSizeSensitiveSystemFont) { NSFont* displaySys = [NSFont systemFontOfSize: 128.0]; NSString* displayFamilyName = GetRealFamilyName(displaySys); nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName); - mSystemDisplayFontFamily = FindSystemFontFamily(familyName); - NS_ASSERTION(mSystemDisplayFontFamily, "null system display font family"); + mSystemDisplayFontFamilyName = familyName; #if DEBUG // confirm that the optical size switch is at 20.0 - NS_ASSERTION(mSystemTextFontFamily && mSystemDisplayFontFamily && - [textFamilyName compare:displayFamilyName] != NSOrderedSame, + NS_ASSERTION([textFamilyName compare:displayFamilyName] != NSOrderedSame, "system text/display fonts are the same!"); NSString* fam19 = GetRealFamilyName([NSFont systemFontOfSize: (kTextDisplayCrossover - 1.0)]); NSString* fam20 = GetRealFamilyName([NSFont systemFontOfSize: kTextDisplayCrossover]); NS_ASSERTION(fam19 && fam20 && [fam19 compare:fam20] != NSOrderedSame, "system text/display font size switch point is not as expected!"); #endif @@ -1105,20 +1128,20 @@ gfxMacPlatformFontList::FindAndAddFamili nsTArray<gfxFontFamily*>* aOutput, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { // search for special system font name, -apple-system if (aFamily.EqualsLiteral(kSystemFont_system)) { if (mUseSizeSensitiveSystemFont && aStyle && (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover) { - aOutput->AppendElement(mSystemDisplayFontFamily); + aOutput->AppendElement(FindSystemFontFamily(mSystemDisplayFontFamilyName)); return true; } - aOutput->AppendElement(mSystemTextFontFamily); + aOutput->AppendElement(FindSystemFontFamily(mSystemTextFontFamilyName)); return true; } return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle, aDevToCssSize); } void
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -410,17 +410,17 @@ NS_IMPL_ISUPPORTS(SRGBOverrideObserver, #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb" NS_IMETHODIMP SRGBOverrideObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t* someData) { NS_ASSERTION(NS_strcmp(someData, - MOZ_UTF16(GFX_PREF_CMS_FORCE_SRGB)) == 0, + (u"" GFX_PREF_CMS_FORCE_SRGB)) == 0, "Restarting CMS on wrong pref!"); ShutdownCMS(); // Update current cms profile. gfxPlatform::CreateCMSOutputProfile(); return NS_OK; } static const char* kObservedPrefs[] = { @@ -883,17 +883,16 @@ gfxPlatform::InitLayersIPC() sLayersIPCIsUp = true; if (XRE_IsParentProcess()) { layers::CompositorThreadHolder::Start(); #ifdef MOZ_WIDGET_GONK SharedBufferManagerChild::StartUp(); #endif - gfx::VRManagerChild::StartUpSameProcess(); } } /* static */ void gfxPlatform::ShutdownLayersIPC() { if (!sLayersIPCIsUp) { return;
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -65,17 +65,16 @@ #define DECL_GFX_PREF(Update, Prefname, Name, Type, Default) \ public: \ static Type Name() { MOZ_ASSERT(SingletonExists()); return GetSingleton().mPref##Name.mValue; } \ static void Set##Name(Type aVal) { MOZ_ASSERT(SingletonExists()); \ GetSingleton().mPref##Name.Set(UpdatePolicy::Update, Get##Name##PrefName(), aVal); } \ static const char* Get##Name##PrefName() { return Prefname; } \ static Type Get##Name##PrefDefault() { return Default; } \ private: \ -static Pref* Get##Name##PrefPtr() { return &GetSingleton().mPref##Name; } \ PrefTemplate<UpdatePolicy::Update, Type, Get##Name##PrefDefault, Get##Name##PrefName> mPref##Name namespace mozilla { namespace gfx { class GfxPrefValue; // defined in PGPU.ipdl } // namespace gfx } // namespace mozilla @@ -411,29 +410,28 @@ private: 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.mozsamplesize.enabled", ImageMozSampleSizeEnabled, bool, false); DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit", ImageMTDecodingLimit, int32_t, -1); DECL_GFX_PREF(Live, "image.single-color-optimization.enabled", ImageSingleColorOptimizationEnabled, bool, true); - DECL_GFX_PREF(Live, "layers.child-process-shutdown", ChildProcessShutdown, bool, true); DECL_GFX_PREF(Once, "layers.acceleration.disabled", LayersAccelerationDisabledDoNotUseDirectly, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps", LayersDrawFPS, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false); DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabledDoNotUseDirectly, bool, false); DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false); DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false); DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true); DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false); DECL_GFX_PREF(Live, "layers.bench.enabled", LayersBenchEnabled, bool, false); DECL_GFX_PREF(Once, "layers.bufferrotation.enabled", BufferRotationEnabled, bool, true); - DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false); + DECL_GFX_PREF(Live, "layers.child-process-shutdown", ChildProcessShutdown, bool, true); #ifdef MOZ_GFX_OPTIMIZE_MOBILE // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off // and ignore the preference. DECL_GFX_PREF(Skip, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, false); #else // If MOZ_GFX_OPTIMIZE_MOBILE is not defined, we actually take the // preference value, defaulting to true. DECL_GFX_PREF(Once, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, true); @@ -472,33 +470,34 @@ private: DECL_GFX_PREF(Live, "layers.max-active", MaxActiveLayers, int32_t, -1); DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false); DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1); DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0); DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking", OverzealousGrallocUnlocking, bool, false); DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false); DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false); DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false); + DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false); + DECL_GFX_PREF(Live, "layers.single-tile.enabled", LayersSingleTileEnabled, bool, true); DECL_GFX_PREF(Once, "layers.stereo-video.enabled", StereoVideoEnabled, bool, false); // We allow for configurable and rectangular tile size to avoid wasting memory on devices whose // screen size does not align nicely to the default tile size. Although layers can be any size, // they are often the same size as the screen, especially for width. DECL_GFX_PREF(Once, "layers.tile-width", LayersTileWidth, int32_t, 256); DECL_GFX_PREF(Once, "layers.tile-height", LayersTileHeight, int32_t, 256); - DECL_GFX_PREF(Once, "layers.tile-max-pool-size", LayersTileMaxPoolSize, uint32_t, (uint32_t)50); - DECL_GFX_PREF(Once, "layers.tile-shrink-pool-timeout", LayersTileShrinkPoolTimeout, uint32_t, (uint32_t)1000); + DECL_GFX_PREF(Once, "layers.tile-initial-pool-size", LayersTileInitialPoolSize, uint32_t, (uint32_t)50); + DECL_GFX_PREF(Once, "layers.tile-pool-increment-size", LayersTilePoolIncrementSize, uint32_t, (uint32_t)10); DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true); DECL_GFX_PREF(Once, "layers.tiles.edge-padding", TileEdgePaddingEnabled, bool, true); DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled", LayerTileFadeInEnabled, bool, false); DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms", LayerTileFadeInDuration, uint32_t, 250); DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, true); - DECL_GFX_PREF(Live, "layers.single-tile.enabled", LayersSingleTileEnabled, bool, true); DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f); DECL_GFX_PREF(Live, "layout.css.scroll-behavior.enabled", ScrollBehaviorEnabled, bool, false); DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f); DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-max-velocity", ScrollSnapPredictionMaxVelocity, int32_t, 2000); DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-sensitivity", ScrollSnapPredictionSensitivity, float, 0.750f); DECL_GFX_PREF(Live, "layout.css.scroll-snap.proximity-threshold", ScrollSnapProximityThreshold, int32_t, 200); DECL_GFX_PREF(Live, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false); @@ -506,16 +505,19 @@ private: DECL_GFX_PREF(Live, "layout.display-list.dump-content", LayoutDumpDisplayListContent, bool, false); DECL_GFX_PREF(Live, "layout.event-regions.enabled", LayoutEventRegionsEnabledDoNotUseDirectly, bool, false); DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1); DECL_GFX_PREF(Once, "layout.paint_rects_separately", LayoutPaintRectsSeparately, bool, true); // This and code dependent on it should be removed once containerless scrolling looks stable. DECL_GFX_PREF(Once, "layout.scroll.root-frame-containers", LayoutUseContainersForRootFrames, bool, true); + DECL_GFX_PREF(Once, "media.hardware-video-decoding.force-enabled", + HardwareVideoDecodingForceEnabled, bool, false); + // These affect how line scrolls from wheel events will be accelerated. DECL_GFX_PREF(Live, "mousewheel.acceleration.factor", MouseWheelAccelerationFactor, int32_t, -1); DECL_GFX_PREF(Live, "mousewheel.acceleration.start", MouseWheelAccelerationStart, int32_t, -1); // This affects whether events will be routed through APZ or not. DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.enabled", MouseWheelHasRootScrollDeltaOverride, bool, false); DECL_GFX_PREF(Live, "mousewheel.transaction.ignoremovedelay",MouseWheelIgnoreMoveDelayMs, int32_t, (int32_t)100); @@ -559,19 +561,16 @@ private: DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false); DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false); DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false); DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true); DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false); DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false); - DECL_GFX_PREF(Once, "media.hardware-video-decoding.force-enabled", - HardwareVideoDecodingForceEnabled, bool, false); - // WARNING: // Please make sure that you've added your new preference to the list above in alphabetical order. // Please do not just append it to the end of the list. public: // Manage the singleton: static gfxPrefs& GetSingleton() {
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1087,17 +1087,17 @@ gfxWindowsPlatform::UseClearTypeAlways() return mUseClearTypeAlways; } void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion) { DWORD versInfoSize, vers[4] = {0}; // version info not available case - aVersion.AssignLiteral(MOZ_UTF16("0.0.0.0")); + aVersion.AssignLiteral(u"0.0.0.0"); versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr); AutoTArray<BYTE,512> versionInfo; if (versInfoSize == 0 || !versionInfo.AppendElements(uint32_t(versInfoSize))) { return; }
--- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -38,45 +38,60 @@ VRManagerChild::~VRManagerChild() /*static*/ VRManagerChild* VRManagerChild::Get() { MOZ_ASSERT(sVRManagerChildSingleton); return sVRManagerChildSingleton; } -/*static*/ VRManagerChild* -VRManagerChild::StartUpInChildProcess(Transport* aTransport, ProcessId aOtherPid) +/* static */ bool +VRManagerChild::IsCreated() +{ + return !!sVRManagerChildSingleton; +} + +/* static */ bool +VRManagerChild::InitForContent(Endpoint<PVRManagerChild>&& aEndpoint) { MOZ_ASSERT(NS_IsMainThread()); - - // There's only one VRManager per child process. MOZ_ASSERT(!sVRManagerChildSingleton); RefPtr<VRManagerChild> child(new VRManagerChild()); - if (!child->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ChildSide)) { + if (!aEndpoint.Bind(child, nullptr)) { NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); - return nullptr; + return false; } - sVRManagerChildSingleton = child; - - return sVRManagerChildSingleton; + return true; } /*static*/ void -VRManagerChild::StartUpSameProcess() +VRManagerChild::InitSameProcess() { - NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); - if (sVRManagerChildSingleton == nullptr) { - sVRManagerChildSingleton = new VRManagerChild(); - sVRManagerParentSingleton = VRManagerParent::CreateSameProcess(); - sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(), - mozilla::layers::CompositorThreadHolder::Loop(), - mozilla::ipc::ChildSide); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!sVRManagerChildSingleton); + + sVRManagerChildSingleton = new VRManagerChild(); + sVRManagerParentSingleton = VRManagerParent::CreateSameProcess(); + sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(), + mozilla::layers::CompositorThreadHolder::Loop(), + mozilla::ipc::ChildSide); +} + +/* static */ void +VRManagerChild::InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!sVRManagerChildSingleton); + + sVRManagerChildSingleton = new VRManagerChild(); + if (!aEndpoint.Bind(sVRManagerChildSingleton, nullptr)) { + NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); + return; } } /*static*/ void VRManagerChild::ShutDown() { MOZ_ASSERT(NS_IsMainThread()); if (sVRManagerChildSingleton) {
--- a/gfx/vr/ipc/VRManagerChild.h +++ b/gfx/vr/ipc/VRManagerChild.h @@ -23,22 +23,23 @@ class VRDeviceProxy; class VRManagerChild : public PVRManagerChild { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VRManagerChild) int GetInputFrameID(); bool GetVRDevices(nsTArray<RefPtr<VRDeviceProxy> >& aDevices); bool RefreshVRDevicesWithCallback(dom::Navigator* aNavigator); - static VRManagerChild* StartUpInChildProcess(Transport* aTransport, - ProcessId aOtherProcess); - static void StartUpSameProcess(); + static void InitSameProcess(); + static void InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint); + static bool InitForContent(Endpoint<PVRManagerChild>&& aEndpoint); static void ShutDown(); + static bool IsCreated(); static VRManagerChild* Get(); protected: explicit VRManagerChild(); ~VRManagerChild(); void Destroy(); static void DeferredDestroy(RefPtr<VRManagerChild> aVRManagerChild);
--- a/gfx/vr/ipc/VRManagerParent.cpp +++ b/gfx/vr/ipc/VRManagerParent.cpp @@ -12,19 +12,17 @@ #include "mozilla/TimeStamp.h" // for TimeStamp #include "mozilla/layers/CompositorThread.h" #include "mozilla/unused.h" #include "VRManager.h" namespace mozilla { namespace gfx { -VRManagerParent::VRManagerParent(MessageLoop* aLoop, - Transport* aTransport, - ProcessId aChildProcessId) +VRManagerParent::VRManagerParent(ProcessId aChildProcessId) { MOZ_COUNT_CTOR(VRManagerParent); MOZ_ASSERT(NS_IsMainThread()); SetOtherProcessId(aChildProcessId); } VRManagerParent::~VRManagerParent() @@ -45,53 +43,68 @@ void VRManagerParent::RegisterWithManage void VRManagerParent::UnregisterFromManager() { VRManager* vm = VRManager::Get(); vm->RemoveVRManagerParent(this); mVRManagerHolder = nullptr; } -/*static*/ void -VRManagerParent::ConnectVRManagerInParentProcess(VRManagerParent* aVRManager, - ipc::Transport* aTransport, - base::ProcessId aOtherPid) +/* static */ bool +VRManagerParent::CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint) { - aVRManager->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ParentSide); - aVRManager->RegisterWithManager(); + MessageLoop* loop = layers::CompositorThreadHolder::Loop(); + + RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid()); + loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>( + vmp, &VRManagerParent::Bind, Move(aEndpoint))); + + return true; } -/*static*/ VRManagerParent* -VRManagerParent::CreateCrossProcess(Transport* aTransport, ProcessId aChildProcessId) +void +VRManagerParent::Bind(Endpoint<PVRManagerParent>&& aEndpoint) { - MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop(); - RefPtr<VRManagerParent> vmp = new VRManagerParent(loop, aTransport, aChildProcessId); - vmp->mSelfRef = vmp; - loop->PostTask(NewRunnableFunction(ConnectVRManagerInParentProcess, - vmp.get(), aTransport, aChildProcessId)); - return vmp.get(); + if (!aEndpoint.Bind(this, nullptr)) { + return; + } + mSelfRef = this; + + RegisterWithManager(); } /*static*/ void VRManagerParent::RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager) { aVRManager->RegisterWithManager(); } /*static*/ VRManagerParent* VRManagerParent::CreateSameProcess() { MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop(); - RefPtr<VRManagerParent> vmp = new VRManagerParent(loop, nullptr, base::GetCurrentProcId()); + RefPtr<VRManagerParent> vmp = new VRManagerParent(base::GetCurrentProcId()); vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton(); vmp->mSelfRef = vmp; loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get())); return vmp.get(); } +bool +VRManagerParent::CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint) +{ + MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop(); + + RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid()); + vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton(); + loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>( + vmp, &VRManagerParent::Bind, Move(aEndpoint))); + return true; +} + void VRManagerParent::DeferredDestroy() { mCompositorThreadHolder = nullptr; mSelfRef = nullptr; } void @@ -101,29 +114,17 @@ VRManagerParent::ActorDestroy(ActorDestr MessageLoop::current()->PostTask(NewRunnableMethod(this, &VRManagerParent::DeferredDestroy)); } mozilla::ipc::IToplevelProtocol* VRManagerParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds, base::ProcessHandle aPeerProcess, mozilla::ipc::ProtocolCloneContext* aCtx) { - for (unsigned int i = 0; i < aFds.Length(); i++) { - if (aFds[i].protocolId() == unsigned(GetProtocolId())) { - UniquePtr<Transport> transport = - OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER); - PVRManagerParent* vm = CreateCrossProcess(transport.get(), base::GetProcId(aPeerProcess)); - vm->CloneManagees(this, aCtx); - vm->IToplevelProtocol::SetTransport(Move(transport)); - // The reference to the compositor thread is held in OnChannelConnected(). - // We need to do this for cloned actors, too. - vm->OnChannelConnected(base::GetProcId(aPeerProcess)); - return vm; - } - } + MOZ_ASSERT_UNREACHABLE("Not supported"); return nullptr; } void VRManagerParent::OnChannelConnected(int32_t aPid) { mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton(); }
--- a/gfx/vr/ipc/VRManagerParent.h +++ b/gfx/vr/ipc/VRManagerParent.h @@ -18,22 +18,21 @@ namespace mozilla { namespace gfx { class VRManager; class VRManagerParent final : public PVRManagerParent { NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VRManagerParent) public: - VRManagerParent(MessageLoop* aLoop, Transport* aTransport, ProcessId aChildProcessId); + explicit VRManagerParent(ProcessId aChildProcessId); - static VRManagerParent* CreateCrossProcess(Transport* aTransport, - ProcessId aOtherProcess); static VRManagerParent* CreateSameProcess(); - + static bool CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint); + static bool CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint); // Overriden from IToplevelProtocol ipc::IToplevelProtocol* CloneToplevel(const InfallibleTArray<ipc::ProtocolFdMapping>& aFds, base::ProcessHandle aPeerProcess, mozilla::ipc::ProtocolCloneContext* aCtx) override; protected: @@ -47,24 +46,22 @@ protected: virtual bool RecvKeepSensorTracking(const uint32_t& aDeviceID) override; virtual bool RecvSetFOV(const uint32_t& aDeviceID, const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight, const double& zNear, const double& zFar) override; private: - void RegisterWithManager(); void UnregisterFromManager(); + void Bind(Endpoint<PVRManagerParent>&& aEndpoint); + static void RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager); - static void ConnectVRManagerInParentProcess(VRManagerParent* aVRManager, - ipc::Transport* aTransport, - base::ProcessId aOtherPid); void DeferredDestroy(); // This keeps us alive until ActorDestroy(), at which point we do a // deferred destruction of ourselves. RefPtr<VRManagerParent> mSelfRef; // Keep the compositor thread alive, until we have destroyed ourselves.
--- a/image/Decoder.cpp +++ b/image/Decoder.cpp @@ -47,16 +47,17 @@ private: Decoder::Decoder(RasterImage* aImage) : mImageData(nullptr) , mImageDataLength(0) , mColormap(nullptr) , mColormapSize(0) , mImage(aImage) , mProgress(NoProgress) , mFrameCount(0) + , mLoopLength(FrameTimeout::Zero()) , mDecoderFlags(DefaultDecoderFlags()) , mSurfaceFlags(DefaultSurfaceFlags()) , mInitialized(false) , mMetadataDecode(false) , mInFrame(false) , mReachedTerminalState(false) , mDecodeDone(false) , mError(false) @@ -336,45 +337,43 @@ Decoder::AllocateFrameInternal(uint32_t // Another decoder beat us to decoding this frame. We abort this decoder // rather than treat this as a real error. mDecodeAborted = true; ref->Abort(); return RawAccessFrameRef(); } } - nsIntRect refreshArea; - if (aFrameNum == 1) { MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated"); aPreviousFrame->SetRawAccessOnly(); // If we dispose of the first frame by clearing it, then the first frame's // refresh area is all of itself. // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR). AnimationData previousFrameData = aPreviousFrame->GetAnimationData(); if (previousFrameData.mDisposalMethod == DisposalMethod::CLEAR || previousFrameData.mDisposalMethod == DisposalMethod::CLEAR_ALL || previousFrameData.mDisposalMethod == DisposalMethod::RESTORE_PREVIOUS) { - refreshArea = previousFrameData.mRect; + mFirstFrameRefreshArea = previousFrameData.mRect; } } if (aFrameNum > 0) { ref->SetRawAccessOnly(); // Some GIFs are huge but only have a small area that they animate. We only // need to refresh that small area when frame 0 comes around again. - refreshArea.UnionRect(refreshArea, frame->GetRect()); + mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, frame->GetRect()); } mFrameCount++; if (mImage) { - mImage->OnAddedFrame(mFrameCount, refreshArea); + mImage->OnAddedFrame(mFrameCount); } return ref; } /* * Hook stubs. Override these as necessary in decoder implementations. */ @@ -406,45 +405,47 @@ Decoder::PostSize(int32_t aWidth, void Decoder::PostHasTransparency() { mProgress |= FLAG_HAS_TRANSPARENCY; } void -Decoder::PostIsAnimated(int32_t aFirstFrameTimeout) +Decoder::PostIsAnimated(FrameTimeout aFirstFrameTimeout) { mProgress |= FLAG_IS_ANIMATED; mImageMetadata.SetHasAnimation(); mImageMetadata.SetFirstFrameTimeout(aFirstFrameTimeout); } void Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */, DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */, - int32_t aTimeout /* = 0 */, + FrameTimeout aTimeout /* = FrameTimeout::Forever() */, BlendMethod aBlendMethod /* = BlendMethod::OVER */, const Maybe<nsIntRect>& aBlendRect /* = Nothing() */) { // We should be mid-frame MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode"); MOZ_ASSERT(mInFrame, "Stopping frame when we didn't start one"); MOZ_ASSERT(mCurrentFrame, "Stopping frame when we don't have one"); // Update our state mInFrame = false; mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout, aBlendMethod, aBlendRect); mProgress |= FLAG_FRAME_COMPLETE; + mLoopLength += aTimeout; + // If we're not sending partial invalidations, then we send an invalidation // here when the first frame is complete. if (!ShouldSendPartialInvalidations() && mFrameCount == 1) { mInvalidRect.UnionRect(mInvalidRect, gfx::IntRect(gfx::IntPoint(0, 0), GetSize())); } } @@ -470,16 +471,25 @@ Decoder::PostDecodeDone(int32_t aLoopCou { MOZ_ASSERT(!IsMetadataDecode(), "Done with decoding in metadata decode"); MOZ_ASSERT(!mInFrame, "Can't be done decoding if we're mid-frame!"); MOZ_ASSERT(!mDecodeDone, "Decode already done!"); mDecodeDone = true; mImageMetadata.SetLoopCount(aLoopCount); + // Some metadata that we track should take into account every frame in the + // image. If this is a first-frame-only decode, our accumulated loop length + // and first frame refresh area only includes the first frame, so it's not + // correct and we don't record it. + if (!IsFirstFrameDecode()) { + mImageMetadata.SetLoopLength(mLoopLength); + mImageMetadata.SetFirstFrameRefreshArea(mFirstFrameRefreshArea); + } + mProgress |= FLAG_DECODE_COMPLETE; } void Decoder::PostError() { mError = true;
--- a/image/Decoder.h +++ b/image/Decoder.h @@ -329,26 +329,26 @@ protected: // until the entire frame has been decoded, decoders may take into account the // actual contents of the frame and give a more accurate result. void PostHasTransparency(); // Called by decoders if they determine that the image is animated. // // @param aTimeout The time for which the first frame should be shown before // we advance to the next frame. - void PostIsAnimated(int32_t aFirstFrameTimeout); + void PostIsAnimated(FrameTimeout aFirstFrameTimeout); // Called by decoders when they end a frame. Informs the image, sends // notifications, and does internal book-keeping. // Specify whether this frame is opaque as an optimization. // For animated images, specify the disposal, blend method and timeout for // this frame. void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY, DisposalMethod aDisposalMethod = DisposalMethod::KEEP, - int32_t aTimeout = 0, + FrameTimeout aTimeout = FrameTimeout::Forever(), BlendMethod aBlendMethod = BlendMethod::OVER, const Maybe<nsIntRect>& aBlendRect = Nothing()); /** * Called by the decoders when they have a region to invalidate. We may not * actually pass these invalidations on right away. * * @param aRect The invalidation rect in the coordinate system of the unscaled @@ -422,16 +422,19 @@ private: RefPtr<RasterImage> mImage; Maybe<SourceBufferIterator> mIterator; RawAccessFrameRef mCurrentFrame; ImageMetadata mImageMetadata; nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame. Progress mProgress; uint32_t mFrameCount; // Number of frames, including anything in-progress + FrameTimeout mLoopLength; // Length of a single loop of this image. + gfx::IntRect mFirstFrameRefreshArea; // The area of the image that needs to + // be invalidated when the animation loops. // Telemetry data for this decoder. TimeDuration mDecodeTime; DecoderFlags mDecoderFlags; SurfaceFlags mSurfaceFlags; bool mInitialized : 1;
--- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -15,285 +15,270 @@ #include "pixman.h" namespace mozilla { using namespace gfx; namespace image { -int32_t -FrameAnimator::GetSingleLoopTime() const +/////////////////////////////////////////////////////////////////////////////// +// AnimationState implementation. +/////////////////////////////////////////////////////////////////////////////// + +void +AnimationState::SetDoneDecoding(bool aDone) +{ + mDoneDecoding = aDone; +} + +void +AnimationState::ResetAnimation() +{ + mCurrentAnimationFrameIndex = 0; +} + +void +AnimationState::SetAnimationMode(uint16_t aAnimationMode) +{ + mAnimationMode = aAnimationMode; +} + +void +AnimationState::SetFirstFrameRefreshArea(const IntRect& aRefreshArea) { - // If we aren't done decoding, we don't know the image's full play time. - if (!mDoneDecoding) { - return -1; + mFirstFrameRefreshArea = aRefreshArea; +} + +void +AnimationState::InitAnimationFrameTimeIfNecessary() +{ + if (mCurrentAnimationFrameTime.IsNull()) { + mCurrentAnimationFrameTime = TimeStamp::Now(); } +} - // If we're not looping, a single loop time has no meaning - if (mAnimationMode != imgIContainer::kNormalAnimMode) { - return -1; +void +AnimationState::SetAnimationFrameTime(const TimeStamp& aTime) +{ + mCurrentAnimationFrameTime = aTime; +} + +uint32_t +AnimationState::GetCurrentAnimationFrameIndex() const +{ + return mCurrentAnimationFrameIndex; +} + +FrameTimeout +AnimationState::LoopLength() const +{ + // If we don't know the loop length yet, we have to treat it as infinite. + if (!mLoopLength) { + return FrameTimeout::Forever(); } - int32_t looptime = 0; - for (uint32_t i = 0; i < mImage->GetNumFrames(); ++i) { - int32_t timeout = GetTimeoutForFrame(i); - if (timeout >= 0) { - looptime += static_cast<uint32_t>(timeout); - } else { - // If we have a frame that never times out, we're probably in an error - // case, but let's handle it more gracefully. - NS_WARNING("Negative frame timeout - how did this happen?"); - return -1; - } + MOZ_ASSERT(mDoneDecoding, "We know the loop length but decoding isn't done?"); + + // If we're not looping, a single loop time has no meaning. + if (mAnimationMode != imgIContainer::kNormalAnimMode) { + return FrameTimeout::Forever(); } - return looptime; + return *mLoopLength; } + +/////////////////////////////////////////////////////////////////////////////// +// FrameAnimator implementation. +/////////////////////////////////////////////////////////////////////////////// + TimeStamp -FrameAnimator::GetCurrentImgFrameEndTime() const +FrameAnimator::GetCurrentImgFrameEndTime(AnimationState& aState) const { - TimeStamp currentFrameTime = mCurrentAnimationFrameTime; - int32_t timeout = - GetTimeoutForFrame(mCurrentAnimationFrameIndex); + TimeStamp currentFrameTime = aState.mCurrentAnimationFrameTime; + FrameTimeout timeout = GetTimeoutForFrame(aState.mCurrentAnimationFrameIndex); - if (timeout < 0) { + if (timeout == FrameTimeout::Forever()) { // We need to return a sentinel value in this case, because our logic - // doesn't work correctly if we have a negative timeout value. We use - // one year in the future as the sentinel because it works with the loop - // in RequestRefresh() below. + // doesn't work correctly if we have an infinitely long timeout. We use one + // year in the future as the sentinel because it works with the loop in + // RequestRefresh() below. // XXX(seth): It'd be preferable to make our logic work correctly with - // negative timeouts. + // infinitely long timeouts. return TimeStamp::NowLoRes() + TimeDuration::FromMilliseconds(31536000.0); } TimeDuration durationOfTimeout = - TimeDuration::FromMilliseconds(static_cast<double>(timeout)); + TimeDuration::FromMilliseconds(double(timeout.AsMilliseconds())); TimeStamp currentFrameEndTime = currentFrameTime + durationOfTimeout; return currentFrameEndTime; } -FrameAnimator::RefreshResult -FrameAnimator::AdvanceFrame(TimeStamp aTime) +RefreshResult +FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) { NS_ASSERTION(aTime <= TimeStamp::Now(), "Given time appears to be in the future"); PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); RefreshResult ret; // Determine what the next frame is, taking into account looping. - uint32_t currentFrameIndex = mCurrentAnimationFrameIndex; + uint32_t currentFrameIndex = aState.mCurrentAnimationFrameIndex; uint32_t nextFrameIndex = currentFrameIndex + 1; if (mImage->GetNumFrames() == nextFrameIndex) { // We can only accurately determine if we are at the end of the loop if we are // done decoding, otherwise we don't know how many frames there will be. - if (!mDoneDecoding) { + if (!aState.mDoneDecoding) { // We've already advanced to the last decoded frame, nothing more we can do. // We're blocked by network/decoding from displaying the animation at the // rate specified, so that means the frame we are displaying (the latest // available) is the frame we want to be displaying at this time. So we // update the current animation time. If we didn't update the current // animation time then it could lag behind, which would indicate that we // are behind in the animation and should try to catch up. When we are // done decoding (and thus can loop around back to the start of the // animation) we would then jump to a random point in the animation to // try to catch up. But we were never behind in the animation. - mCurrentAnimationFrameTime = aTime; + aState.mCurrentAnimationFrameTime = aTime; return ret; } // End of an animation loop... // If we are not looping forever, initialize the loop counter - if (mLoopRemainingCount < 0 && LoopCount() >= 0) { - mLoopRemainingCount = LoopCount(); + if (aState.mLoopRemainingCount < 0 && aState.LoopCount() >= 0) { + aState.mLoopRemainingCount = aState.LoopCount(); } // If animation mode is "loop once", or we're at end of loop counter, // it's time to stop animating. - if (mAnimationMode == imgIContainer::kLoopOnceAnimMode || - mLoopRemainingCount == 0) { - ret.animationFinished = true; + if (aState.mAnimationMode == imgIContainer::kLoopOnceAnimMode || + aState.mLoopRemainingCount == 0) { + ret.mAnimationFinished = true; } nextFrameIndex = 0; - if (mLoopRemainingCount > 0) { - mLoopRemainingCount--; + if (aState.mLoopRemainingCount > 0) { + aState.mLoopRemainingCount--; } // If we're done, exit early. - if (ret.animationFinished) { + if (ret.mAnimationFinished) { return ret; } } // There can be frames in the surface cache with index >= mImage->GetNumFrames() // that GetRawFrame can access because the decoding thread has decoded them, but // RasterImage hasn't acknowledged those frames yet. We don't want to go past // what RasterImage knows about so that we stay in sync with RasterImage. The code // above should obey this, the MOZ_ASSERT records this invariant. MOZ_ASSERT(nextFrameIndex < mImage->GetNumFrames()); RawAccessFrameRef nextFrame = GetRawFrame(nextFrameIndex); // If we're done decoding, we know we've got everything we're going to get. // If we aren't, we only display fully-downloaded frames; everything else // gets delayed. - bool canDisplay = mDoneDecoding || + bool canDisplay = aState.mDoneDecoding || (nextFrame && nextFrame->IsFinished()); if (!canDisplay) { // Uh oh, the frame we want to show is currently being decoded (partial) // Wait until the next refresh driver tick and try again return ret; } - // Bad data - if (GetTimeoutForFrame(nextFrameIndex) < 0) { - ret.animationFinished = true; - ret.error = true; + if (GetTimeoutForFrame(nextFrameIndex) == FrameTimeout::Forever()) { + ret.mAnimationFinished = true; } if (nextFrameIndex == 0) { - ret.dirtyRect = mFirstFrameRefreshArea; + ret.mDirtyRect = aState.FirstFrameRefreshArea(); } else { MOZ_ASSERT(nextFrameIndex == currentFrameIndex + 1); // Change frame - if (!DoBlend(&ret.dirtyRect, currentFrameIndex, nextFrameIndex)) { + if (!DoBlend(&ret.mDirtyRect, currentFrameIndex, nextFrameIndex)) { // something went wrong, move on to next NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed"); nextFrame->SetCompositingFailed(true); - mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); - mCurrentAnimationFrameIndex = nextFrameIndex; + aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); + aState.mCurrentAnimationFrameIndex = nextFrameIndex; - ret.error = true; return ret; } nextFrame->SetCompositingFailed(false); } - mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); + aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); // If we can get closer to the current time by a multiple of the image's loop - // time, we should. We need to be done decoding in order to know the full loop - // time though! - int32_t loopTime = GetSingleLoopTime(); - if (loopTime > 0) { - // We shouldn't be advancing by a whole loop unless we are decoded and know - // what a full loop actually is. GetSingleLoopTime should return -1 so this - // never happens. - MOZ_ASSERT(mDoneDecoding); - TimeDuration delay = aTime - mCurrentAnimationFrameTime; - if (delay.ToMilliseconds() > loopTime) { + // time, we should. We can only do this if we're done decoding; otherwise, we + // don't know the full loop length, and LoopLength() will have to return + // FrameTimeout::Forever(). + FrameTimeout loopTime = aState.LoopLength(); + if (loopTime != FrameTimeout::Forever()) { + TimeDuration delay = aTime - aState.mCurrentAnimationFrameTime; + if (delay.ToMilliseconds() > loopTime.AsMilliseconds()) { // Explicitly use integer division to get the floor of the number of // loops. - uint64_t loops = static_cast<uint64_t>(delay.ToMilliseconds()) / loopTime; - mCurrentAnimationFrameTime += - TimeDuration::FromMilliseconds(loops * loopTime); + uint64_t loops = static_cast<uint64_t>(delay.ToMilliseconds()) + / loopTime.AsMilliseconds(); + aState.mCurrentAnimationFrameTime += + TimeDuration::FromMilliseconds(loops * loopTime.AsMilliseconds()); } } // Set currentAnimationFrameIndex at the last possible moment - mCurrentAnimationFrameIndex = nextFrameIndex; + aState.mCurrentAnimationFrameIndex = nextFrameIndex; // If we're here, we successfully advanced the frame. - ret.frameAdvanced = true; + ret.mFrameAdvanced = true; return ret; } -FrameAnimator::RefreshResult -FrameAnimator::RequestRefresh(const TimeStamp& aTime) +RefreshResult +FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime) { // only advance the frame if the current time is greater than or // equal to the current frame's end time. - TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime(); + TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime(aState); // By default, an empty RefreshResult. RefreshResult ret; while (currentFrameEndTime <= aTime) { TimeStamp oldFrameEndTime = currentFrameEndTime; - RefreshResult frameRes = AdvanceFrame(aTime); + RefreshResult frameRes = AdvanceFrame(aState, aTime); // Accumulate our result for returning to callers. ret.Accumulate(frameRes); - currentFrameEndTime = GetCurrentImgFrameEndTime(); + currentFrameEndTime = GetCurrentImgFrameEndTime(aState); - // if we didn't advance a frame, and our frame end time didn't change, + // If we didn't advance a frame, and our frame end time didn't change, // then we need to break out of this loop & wait for the frame(s) - // to finish downloading - if (!frameRes.frameAdvanced && (currentFrameEndTime == oldFrameEndTime)) { + // to finish downloading. + if (!frameRes.mFrameAdvanced && (currentFrameEndTime == oldFrameEndTime)) { break; } } return ret; } -void -FrameAnimator::ResetAnimation() -{ - mCurrentAnimationFrameIndex = 0; - mLastCompositedFrameIndex = -1; -} - -void -FrameAnimator::SetDoneDecoding(bool aDone) -{ - mDoneDecoding = aDone; -} - -void -FrameAnimator::SetAnimationMode(uint16_t aAnimationMode) -{ - mAnimationMode = aAnimationMode; -} - -void -FrameAnimator::InitAnimationFrameTimeIfNecessary() -{ - if (mCurrentAnimationFrameTime.IsNull()) { - mCurrentAnimationFrameTime = TimeStamp::Now(); - } -} - -void -FrameAnimator::SetAnimationFrameTime(const TimeStamp& aTime) -{ - mCurrentAnimationFrameTime = aTime; -} - -void -FrameAnimator::UnionFirstFrameRefreshArea(const nsIntRect& aRect) -{ - mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, aRect); -} - -uint32_t -FrameAnimator::GetCurrentAnimationFrameIndex() const -{ - return mCurrentAnimationFrameIndex; -} - -nsIntRect -FrameAnimator::GetFirstFrameRefreshArea() const -{ - return mFirstFrameRefreshArea; -} - LookupResult FrameAnimator::GetCompositedFrame(uint32_t aFrameNum) { MOZ_ASSERT(aFrameNum != 0, "First frame is never composited"); // If we have a composited version of this frame, return that. if (mLastCompositedFrameIndex == int32_t(aFrameNum)) { return LookupResult(mCompositingFrame->DrawableRef(), MatchType::EXACT); @@ -306,50 +291,27 @@ FrameAnimator::GetCompositedFrame(uint32 RasterSurfaceKey(mSize, DefaultSurfaceFlags(), aFrameNum)); MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(), "About to return a paletted frame"); return result; } -int32_t +FrameTimeout FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const { - int32_t rawTimeout = 0; - RawAccessFrameRef frame = GetRawFrame(aFrameNum); if (frame) { AnimationData data = frame->GetAnimationData(); - rawTimeout = data.mRawTimeout; - } else if (aFrameNum == 0) { - rawTimeout = mFirstFrameTimeout; - } else { - NS_WARNING("No frame; called GetTimeoutForFrame too early?"); - return 100; + return data.mTimeout; } - // Ensure a minimal time between updates so we don't throttle the UI thread. - // consider 0 == unspecified and make it fast but not too fast. Unless we - // have a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug - // 207059. The behavior of recent IE and Opera versions seems to be: - // IE 6/Win: - // 10 - 50ms go 100ms - // >50ms go correct speed - // Opera 7 final/Win: - // 10ms goes 100ms - // >10ms go correct speed - // It seems that there are broken tools out there that set a 0ms or 10ms - // timeout when they really want a "default" one. So munge values in that - // range. - if (rawTimeout >= 0 && rawTimeout <= 10) { - return 100; - } - - return rawTimeout; + NS_WARNING("No frame; called GetTimeoutForFrame too early?"); + return FrameTimeout::FromRawMilliseconds(100); } static void DoCollectSizeOfCompositingSurfaces(const RawAccessFrameRef& aSurface, SurfaceMemoryCounterType aType, nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) { @@ -402,17 +364,17 @@ FrameAnimator::GetRawFrame(uint32_t aFra return result ? result.DrawableRef()->RawAccessRef() : RawAccessFrameRef(); } //****************************************************************************** // DoBlend gets called when the timer for animation get fired and we have to // update the composited frame of the animation. bool -FrameAnimator::DoBlend(nsIntRect* aDirtyRect, +FrameAnimator::DoBlend(IntRect* aDirtyRect, uint32_t aPrevFrameIndex, uint32_t aNextFrameIndex) { RawAccessFrameRef prevFrame = GetRawFrame(aPrevFrameIndex); RawAccessFrameRef nextFrame = GetRawFrame(aNextFrameIndex); MOZ_ASSERT(prevFrame && nextFrame, "Should have frames here"); @@ -683,73 +645,73 @@ FrameAnimator::DoBlend(nsIntRect* aDirty mLastCompositedFrameIndex = int32_t(aNextFrameIndex); return true; } //****************************************************************************** // Fill aFrame with black. Does also clears the mask. void -FrameAnimator::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect) +FrameAnimator::ClearFrame(uint8_t* aFrameData, const IntRect& aFrameRect) { if (!aFrameData) { return; } memset(aFrameData, 0, aFrameRect.width * aFrameRect.height * 4); } //****************************************************************************** void -FrameAnimator::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, - const nsIntRect& aRectToClear) +FrameAnimator::ClearFrame(uint8_t* aFrameData, const IntRect& aFrameRect, + const IntRect& aRectToClear) { if (!aFrameData || aFrameRect.width <= 0 || aFrameRect.height <= 0 || aRectToClear.width <= 0 || aRectToClear.height <= 0) { return; } - nsIntRect toClear = aFrameRect.Intersect(aRectToClear); + IntRect toClear = aFrameRect.Intersect(aRectToClear); if (toClear.IsEmpty()) { return; } uint32_t bytesPerRow = aFrameRect.width * 4; for (int row = toClear.y; row < toClear.y + toClear.height; ++row) { memset(aFrameData + toClear.x * 4 + row * bytesPerRow, 0, toClear.width * 4); } } //****************************************************************************** // Whether we succeed or fail will not cause a crash, and there's not much // we can do about a failure, so there we don't return a nsresult bool FrameAnimator::CopyFrameImage(const uint8_t* aDataSrc, - const nsIntRect& aRectSrc, + const IntRect& aRectSrc, uint8_t* aDataDest, - const nsIntRect& aRectDest) + const IntRect& aRectDest) { uint32_t dataLengthSrc = aRectSrc.width * aRectSrc.height * 4; uint32_t dataLengthDest = aRectDest.width * aRectDest.height * 4; if (!aDataDest || !aDataSrc || dataLengthSrc != dataLengthDest) { return false; } memcpy(aDataDest, aDataSrc, dataLengthDest); return true; } nsresult -FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect, +FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const IntRect& aSrcRect, uint32_t aSrcPaletteLength, bool aSrcHasAlpha, - uint8_t* aDstPixels, const nsIntRect& aDstRect, - BlendMethod aBlendMethod, const Maybe<nsIntRect>& aBlendRect) + uint8_t* aDstPixels, const IntRect& aDstRect, + BlendMethod aBlendMethod, const Maybe<IntRect>& aBlendRect) { NS_ENSURE_ARG_POINTER(aSrcData); NS_ENSURE_ARG_POINTER(aDstPixels); // According to both AGIF and APNG specs, offsets are unsigned if (aSrcRect.x < 0 || aSrcRect.y < 0) { NS_WARNING("FrameAnimator::DrawFrameTo: negative offsets not allowed"); return NS_ERROR_FAILURE;
--- a/image/FrameAnimator.h +++ b/image/FrameAnimator.h @@ -5,94 +5,38 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_image_FrameAnimator_h #define mozilla_image_FrameAnimator_h #include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/TimeStamp.h" -#include "gfx2DGlue.h" #include "gfxTypes.h" #include "imgFrame.h" #include "nsCOMPtr.h" #include "nsRect.h" #include "SurfaceCache.h" namespace mozilla { namespace image { class RasterImage; -class FrameAnimator +class AnimationState { public: - FrameAnimator(RasterImage* aImage, - gfx::IntSize aSize, - uint16_t aAnimationMode) - : mImage(aImage) - , mSize(aSize) - , mCurrentAnimationFrameIndex(0) + explicit AnimationState(uint16_t aAnimationMode) + : mCurrentAnimationFrameIndex(0) , mLoopRemainingCount(-1) - , mLastCompositedFrameIndex(-1) , mLoopCount(-1) - , mFirstFrameTimeout(0) + , mFirstFrameTimeout(FrameTimeout::FromRawMilliseconds(0)) , mAnimationMode(aAnimationMode) , mDoneDecoding(false) - { - MOZ_COUNT_CTOR(FrameAnimator); - } - - ~FrameAnimator() - { - MOZ_COUNT_DTOR(FrameAnimator); - } - - /** - * Return value from RequestRefresh. Tells callers what happened in that call - * to RequestRefresh. - */ - struct RefreshResult - { - // The dirty rectangle to be re-drawn after this RequestRefresh(). - nsIntRect dirtyRect; - - // Whether any frame changed, and hence the dirty rect was set. - bool frameAdvanced : 1; - - // Whether the animation has finished playing. - bool animationFinished : 1; - - // Whether an error has occurred when trying to advance a frame. Note that - // errors do not, on their own, end the animation. - bool error : 1; - - RefreshResult() - : frameAdvanced(false) - , animationFinished(false) - , error(false) - { } - - void Accumulate(const RefreshResult& other) - { - frameAdvanced = frameAdvanced || other.frameAdvanced; - animationFinished = animationFinished || other.animationFinished; - error = error || other.error; - dirtyRect = dirtyRect.Union(other.dirtyRect); - } - }; - - /** - * Re-evaluate what frame we're supposed to be on, and do whatever blending - * is necessary to get us to that frame. - * - * Returns the result of that blending, including whether the current frame - * changed and what the resulting dirty rectangle is. - */ - RefreshResult RequestRefresh(const TimeStamp& aTime); + { } /** * Call when this image is finished decoding so we know that there aren't any * more frames coming. */ void SetDoneDecoding(bool aDone); /** @@ -104,20 +48,21 @@ public: /** * The animation mode of the image. * * Constants defined in imgIContainer.idl. */ void SetAnimationMode(uint16_t aAnimationMode); /** - * Union the area to refresh when we loop around to the first frame with this - * rect. + * Get or set the area of the image to invalidate when we loop around to the + * first frame. */ - void UnionFirstFrameRefreshArea(const nsIntRect& aRect); + void SetFirstFrameRefreshArea(const gfx::IntRect& aRefreshArea); + gfx::IntRect FirstFrameRefreshArea() const { return mFirstFrameRefreshArea; } /** * If the animation frame time has not yet been set, set it to * TimeStamp::Now(). */ void InitAnimationFrameTimeIfNecessary(); /** @@ -125,112 +70,191 @@ public: */ void SetAnimationFrameTime(const TimeStamp& aTime); /** * The current frame we're on, from 0 to (numFrames - 1). */ uint32_t GetCurrentAnimationFrameIndex() const; + /* + * Set number of times to loop the image. + * @note -1 means loop forever. + */ + void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; } + int32_t LoopCount() const { return mLoopCount; } + + /// Set the @aLength of a single loop through this image. + void SetLoopLength(FrameTimeout aLength) { mLoopLength = Some(aLength); } + /** - * Get the area we refresh when we loop around to the first frame. + * @return the length of a single loop of this image. If this image is not + * finished decoding, is not animated, or it is animated but does not loop, + * returns FrameTimeout::Forever(). + */ + FrameTimeout LoopLength() const; + + /* + * Get or set the timeout for the first frame. This is used to allow animation + * scheduling even before a full decode runs for this image. */ - nsIntRect GetFirstFrameRefreshArea() const; + void SetFirstFrameTimeout(FrameTimeout aTimeout) { mFirstFrameTimeout = aTimeout; } + FrameTimeout FirstFrameTimeout() const { return mFirstFrameTimeout; } + +private: + friend class FrameAnimator; + + //! Area of the first frame that needs to be redrawn on subsequent loops. + gfx::IntRect mFirstFrameRefreshArea; + + //! the time that the animation advanced to the current frame + TimeStamp mCurrentAnimationFrameTime; + + //! The current frame index we're on. 0 to (numFrames - 1). + uint32_t mCurrentAnimationFrameIndex; + + //! number of loops remaining before animation stops (-1 no stop) + int32_t mLoopRemainingCount; + + //! The total number of loops for the image. + int32_t mLoopCount; + + //! The length of a single loop through this image. + Maybe<FrameTimeout> mLoopLength; + + //! The timeout for the first frame of this image. + FrameTimeout mFirstFrameTimeout; + + //! The animation mode of this image. Constants defined in imgIContainer. + uint16_t mAnimationMode; + + //! Whether this image is done being decoded. + bool mDoneDecoding; +}; + +/** + * RefreshResult is used to let callers know how the state of the animation + * changed during a call to FrameAnimator::RequestRefresh(). + */ +struct RefreshResult +{ + RefreshResult() + : mFrameAdvanced(false) + , mAnimationFinished(false) + { } + + /// Merges another RefreshResult's changes into this RefreshResult. + void Accumulate(const RefreshResult& aOther) + { + mFrameAdvanced = mFrameAdvanced || aOther.mFrameAdvanced; + mAnimationFinished = mAnimationFinished || aOther.mAnimationFinished; + mDirtyRect = mDirtyRect.Union(aOther.mDirtyRect); + } + + // The region of the image that has changed. + gfx::IntRect mDirtyRect; + + // If true, we changed frames at least once. Note that, due to looping, we + // could still have ended up on the same frame! + bool mFrameAdvanced : 1; + + // Whether the animation has finished playing. + bool mAnimationFinished : 1; +}; + +class FrameAnimator +{ +public: + FrameAnimator(RasterImage* aImage, const gfx::IntSize& aSize) + : mImage(aImage) + , mSize(aSize) + , mLastCompositedFrameIndex(-1) + { + MOZ_COUNT_CTOR(FrameAnimator); + } + + ~FrameAnimator() + { + MOZ_COUNT_DTOR(FrameAnimator); + } + + /** + * Re-evaluate what frame we're supposed to be on, and do whatever blending + * is necessary to get us to that frame. + * + * Returns the result of that blending, including whether the current frame + * changed and what the resulting dirty rectangle is. + */ + RefreshResult RequestRefresh(AnimationState& aState, const TimeStamp& aTime); /** * If we have a composited frame for @aFrameNum, returns it. Otherwise, * returns an empty LookupResult. It is an error to call this method with * aFrameNum == 0, because the first frame is never composited. */ LookupResult GetCompositedFrame(uint32_t aFrameNum); - /* - * Returns the frame's adjusted timeout. If the animation loops and the - * timeout falls in between a certain range then the timeout is adjusted so - * that it's never 0. If the animation does not loop then no adjustments are - * made. - */ - int32_t GetTimeoutForFrame(uint32_t aFrameNum) const; - - /* - * Set number of times to loop the image. - * @note -1 means loop forever. - */ - void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; } - int32_t LoopCount() const { return mLoopCount; } - - /* - * Set the timeout for the first frame. This is used to allow animation - * scheduling even before a full decode runs for this image. - */ - void SetFirstFrameTimeout(int32_t aTimeout) { mFirstFrameTimeout = aTimeout; } - /** * Collect an accounting of the memory occupied by the compositing surfaces we * use during animation playback. All of the actual animation frames are * stored in the SurfaceCache, so we don't need to report them here. */ void CollectSizeOfCompositingSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) const; private: // methods /** - * Gets the length of a single loop of this image, in milliseconds. - * - * If this image is not finished decoding, is not animated, or it is animated - * but does not loop, returns -1. Can return 0 in the case of an animated - * image that has a 0ms delay between its frames and does not loop. - */ - int32_t GetSingleLoopTime() const; - - /** * Advances the animation. Typically, this will advance a single frame, but it * may advance multiple frames. This may happen if we have infrequently * "ticking" refresh drivers (e.g. in background tabs), or extremely short- * lived animation frames. * * @param aTime the time that the animation should advance to. This will * typically be <= TimeStamp::Now(). * * @returns a RefreshResult that shows whether the frame was successfully * advanced, and its resulting dirty rect. */ - RefreshResult AdvanceFrame(TimeStamp aTime); + RefreshResult AdvanceFrame(AnimationState& aState, TimeStamp aTime); + + /** + * Get the @aIndex-th frame in the frame index, ignoring results of blending. + */ + RawAccessFrameRef GetRawFrame(uint32_t aFrameNum) const; + + /// @return the given frame's timeout. + FrameTimeout GetTimeoutForFrame(uint32_t aFrameNum) const; /** * Get the time the frame we're currently displaying is supposed to end. * * In the error case, returns an "infinity" timestamp. */ - TimeStamp GetCurrentImgFrameEndTime() const; - - bool DoBlend(nsIntRect* aDirtyRect, uint32_t aPrevFrameIndex, - uint32_t aNextFrameIndex); + TimeStamp GetCurrentImgFrameEndTime(AnimationState& aState) const; - /** - * Get the @aIndex-th frame in the frame index, ignoring results of blending. - */ - RawAccessFrameRef GetRawFrame(uint32_t aFrameNum) const; + bool DoBlend(gfx::IntRect* aDirtyRect, + uint32_t aPrevFrameIndex, + uint32_t aNextFrameIndex); /** Clears an area of <aFrame> with transparent black. * * @param aFrameData Target Frame data * @param aFrameRect The rectangle of the data pointed ot by aFrameData * * @note Does also clears the transparency mask */ - static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect); + static void ClearFrame(uint8_t* aFrameData, const gfx::IntRect& aFrameRect); //! @overload - static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, - const nsIntRect& aRectToClear); + static void ClearFrame(uint8_t* aFrameData, const gfx::IntRect& aFrameRect, + const gfx::IntRect& aRectToClear); //! Copy one frame's image and mask into another - static bool CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc, - uint8_t* aDataDest, const nsIntRect& aRectDest); + static bool CopyFrameImage(const uint8_t* aDataSrc, const gfx::IntRect& aRectSrc, + uint8_t* aDataDest, const gfx::IntRect& aRectDest); /** * Draws one frame's image to into another, at the position specified by * aSrcRect. * * @aSrcData the raw data of the current frame being drawn * @aSrcRect the size of the source frame, and the position of that frame in * the composition frame @@ -239,21 +263,21 @@ private: // methods * @aSrcHasAlpha whether the source data represents an image with alpha * @aDstPixels the raw data of the composition frame where the current frame * is drawn into (32-bit ARGB) * @aDstRect the size of the composition frame * @aBlendMethod the blend method for how to blend src on the composition * frame. */ static nsresult DrawFrameTo(const uint8_t* aSrcData, - const nsIntRect& aSrcRect, + const gfx::IntRect& aSrcRect, uint32_t aSrcPaletteLength, bool aSrcHasAlpha, - uint8_t* aDstPixels, const nsIntRect& aDstRect, + uint8_t* aDstPixels, const gfx::IntRect& aDstRect, BlendMethod aBlendMethod, - const Maybe<nsIntRect>& aBlendRect); + const Maybe<gfx::IntRect>& aBlendRect); private: // data //! A weak pointer to our owning image. RasterImage* mImage; //! The intrinsic size of the image. gfx::IntSize mSize; @@ -270,40 +294,16 @@ private: // data /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS * * The Previous Frame (all frames composited up to the current) needs to be * stored in cases where the image specifies it wants the last frame back * when it's done with the current frame. */ RawAccessFrameRef mCompositingPrevFrame; - //! Area of the first frame that needs to be redrawn on subsequent loops. - nsIntRect mFirstFrameRefreshArea; - - //! the time that the animation advanced to the current frame - TimeStamp mCurrentAnimationFrameTime; - - //! The current frame index we're on. 0 to (numFrames - 1). - uint32_t mCurrentAnimationFrameIndex; - - //! number of loops remaining before animation stops (-1 no stop) - int32_t mLoopRemainingCount; - //! Track the last composited frame for Optimizations (See DoComposite code) int32_t mLastCompositedFrameIndex; - - //! The total number of loops for the image. - int32_t mLoopCount; - - //! The timeout for the first frame of this image. - int32_t mFirstFrameTimeout; - - //! The animation mode of this image. Constants defined in imgIContainer. - uint16_t mAnimationMode; - - //! Whether this image is done being decoded. - bool mDoneDecoding; }; } // namespace image } // namespace mozilla #endif // mozilla_image_FrameAnimator_h