diff --git a/b2g/dev/config/tooltool-manifests/linux64/releng.manifest b/b2g/dev/config/tooltool-manifests/linux64/releng.manifest index 80b88d8e46e..3ece07507e8 100644 --- a/b2g/dev/config/tooltool-manifests/linux64/releng.manifest +++ b/b2g/dev/config/tooltool-manifests/linux64/releng.manifest @@ -15,8 +15,8 @@ "unpack": true }, { -"size": 73029932, -"digest": "ef1818acf065838dcb72554e521f9fd7098f0a3690cb6a3106d7bf18f46c342bfdd5a2b7d86e92ee3ddb9e478380343e58ecf8fd242807b8881a2d53fbec5ab3", +"size": 193213220, +"digest": "58b8ebd8de923117831dcbba71172a53e26c25bd16c2b2bb363a1254f2cd4e87f95e2c5f41e2dce10e18e43a17e0a395637c9ddcbf1e27673582792f9095c62e", "algorithm": "sha512", "filename": "rustc.tar.xz", "unpack": true diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 72101a1d008..a89041e9b04 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -5197,8 +5197,10 @@ var TabletModeUpdater = { }; var gTabletModePageCounter = { + enabled: false, inc() { - if (!AppConstants.isPlatformAndVersionAtLeast("win", "10.0")) { + this.enabled = AppConstants.isPlatformAndVersionAtLeast("win", "10.0"); + if (!this.enabled) { this.inc = () => {}; return; } @@ -5214,8 +5216,11 @@ var gTabletModePageCounter = { }, finish() { - Services.telemetry.getKeyedHistogramById("FX_TABLETMODE_PAGE_LOAD").add("tablet", this._tabletCount); - Services.telemetry.getKeyedHistogramById("FX_TABLETMODE_PAGE_LOAD").add("desktop", this._desktopCount); + if (this.enabled) { + let histogram = Services.telemetry.getKeyedHistogramById("FX_TABLETMODE_PAGE_LOAD"); + histogram.add("tablet", this._tabletCount); + histogram.add("desktop", this._desktopCount); + } }, }; diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index e1ce5adf6bd..98017e91752 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -4691,6 +4691,9 @@ let hoveredTab = this._hoveredTab; if (hoveredTab) { hoveredTab._mouseleave(); + } + hoveredTab = this.querySelector("tab:hover"); + if (hoveredTab) { hoveredTab._mouseenter(); } ]]> diff --git a/browser/config/tooltool-manifests/linux64/releng.manifest b/browser/config/tooltool-manifests/linux64/releng.manifest index 2373871b30b..6522d5585e5 100644 --- a/browser/config/tooltool-manifests/linux64/releng.manifest +++ b/browser/config/tooltool-manifests/linux64/releng.manifest @@ -14,17 +14,17 @@ "unpack": true }, { +"size": 193213220, +"digest": "58b8ebd8de923117831dcbba71172a53e26c25bd16c2b2bb363a1254f2cd4e87f95e2c5f41e2dce10e18e43a17e0a395637c9ddcbf1e27673582792f9095c62e", +"algorithm": "sha512", +"filename": "rustc.tar.xz", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", "filename": "sccache.tar.bz2", "unpack": true -}, -{ -"size": 73029932, -"digest": "ef1818acf065838dcb72554e521f9fd7098f0a3690cb6a3106d7bf18f46c342bfdd5a2b7d86e92ee3ddb9e478380343e58ecf8fd242807b8881a2d53fbec5ab3", -"algorithm": "sha512", -"filename": "rustc.tar.xz", -"unpack": true } ] diff --git a/browser/config/tooltool-manifests/macosx64/releng.manifest b/browser/config/tooltool-manifests/macosx64/releng.manifest index c34baf77810..46e237b10b4 100644 --- a/browser/config/tooltool-manifests/macosx64/releng.manifest +++ b/browser/config/tooltool-manifests/macosx64/releng.manifest @@ -10,8 +10,8 @@ "unpack": true }, { -"size": 128301120, -"digest": "d2d71103a6cec84b150b8f08bfef2682aa713c2d6eadce584f79836ef27ba4380ffb444165d999b79605f18ad165641a7a8cc0e04a201675ad5f655a59adbda9", +"size": 215952362, +"digest": "5e9825dbe83b2a157879076da70fc5c989a1638e30d3b14a9901b166db09013c356a9dc4eaf6c16209a1832d9cb1c67ca869e9b9003cab8355a7f03b3dc08775", "algorithm": "sha512", "filename": "rustc.tar.bz2", "unpack": true diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm index 2a467eb9d30..3c783a85d29 100644 --- a/browser/experiments/Experiments.jsm +++ b/browser/experiments/Experiments.jsm @@ -30,6 +30,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment", "resource://gre/modules/TelemetryEnvironment.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetryLog", "resource://gre/modules/TelemetryLog.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "TelemetryUtils", + "resource://gre/modules/TelemetryUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", "resource://services-common/utils.js"); XPCOMUtils.defineLazyModuleGetter(this, "Metrics", @@ -160,10 +162,6 @@ function loadJSONAsync(file, options) { }); } -function telemetryEnabled() { - return gPrefsTelemetry.get(PREF_TELEMETRY_ENABLED, false); -} - // Returns a promise that is resolved with the AddonInstall for that URL. function addonInstallForURL(url, hash) { let deferred = Promise.defer(); @@ -389,7 +387,7 @@ Experiments.Experiments.prototype = { this._shutdown = false; configureLogging(); - gExperimentsEnabled = gPrefs.get(PREF_ENABLED, false); + gExperimentsEnabled = gPrefs.get(PREF_ENABLED, false) && TelemetryUtils.isTelemetryEnabled; this._log.trace("enabled=" + gExperimentsEnabled + ", " + this.enabled); gPrefs.observe(PREF_LOGGING, configureLogging); @@ -580,7 +578,7 @@ Experiments.Experiments.prototype = { _toggleExperimentsEnabled: Task.async(function* (enabled) { this._log.trace("_toggleExperimentsEnabled(" + enabled + ")"); let wasEnabled = gExperimentsEnabled; - gExperimentsEnabled = enabled && telemetryEnabled(); + gExperimentsEnabled = enabled && TelemetryUtils.isTelemetryEnabled; if (wasEnabled == gExperimentsEnabled) { return; diff --git a/browser/experiments/test/xpcshell/head.js b/browser/experiments/test/xpcshell/head.js index 40eb9aa01a9..436d9345d3b 100644 --- a/browser/experiments/test/xpcshell/head.js +++ b/browser/experiments/test/xpcshell/head.js @@ -233,3 +233,7 @@ function replaceExperiments(experiment, list) { }, }); } + +// Experiments require Telemetry to be enabled, and that's not true for debug +// builds. Let's just enable it here instead of going through each test. +Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true); diff --git a/browser/experiments/test/xpcshell/test_telemetry_disabled.js b/browser/experiments/test/xpcshell/test_telemetry_disabled.js new file mode 100644 index 00000000000..74f85ccfc7e --- /dev/null +++ b/browser/experiments/test/xpcshell/test_telemetry_disabled.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +Cu.import("resource:///modules/experiments/Experiments.jsm"); + +add_test(function test_experiments_activation() { + do_get_profile(); + loadAddonManager(); + + Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); + Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, false); + + let experiments = Experiments.instance(); + Assert.ok(!experiments.enabled, "Experiments must be disabled if Telemetry is disabled."); + + // TODO: Test that Experiments are turned back on when bug 1232648 lands. + + run_next_test(); +}); diff --git a/browser/experiments/test/xpcshell/xpcshell.ini b/browser/experiments/test/xpcshell/xpcshell.ini index cf716b9cbd8..a2d40d3f6be 100644 --- a/browser/experiments/test/xpcshell/xpcshell.ini +++ b/browser/experiments/test/xpcshell/xpcshell.ini @@ -24,6 +24,7 @@ generated-files = [test_disableExperiments.js] [test_fetch.js] [test_telemetry.js] +[test_telemetry_disabled.js] [test_healthreport.js] [test_previous_provider.js] [test_upgrade.js] diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index c5615035ade..4c092f00568 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -72,7 +72,7 @@ SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt)) dd SEARCHPLUGINS_FILENAMES = $(subst :hidden,,$(SEARCHPLUGINS_NAMES)) SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD) SEARCHPLUGINS_TARGET := libs searchplugins -SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin)))) +SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(warning Missing searchplugin: $(plugin)))) # Some locale-specific search plugins may have preprocessor directives, but the # default en-US ones do not. SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings diff --git a/browser/themes/windows/pageInfo.css b/browser/themes/windows/pageInfo.css index d125fd93ce9..e7f311f45ea 100644 --- a/browser/themes/windows/pageInfo.css +++ b/browser/themes/windows/pageInfo.css @@ -123,7 +123,7 @@ groupbox.collapsable caption .caption-icon { background-position: center; -moz-margin-start: 2px; -moz-margin-end: 2px; - background-image: url("chrome://global/skin/tree/twisty-open.png"); + background-image: url("chrome://global/skin/tree/twisty.svg#open"); } groupbox.collapsable[closed="true"] { @@ -133,7 +133,7 @@ groupbox.collapsable[closed="true"] { } groupbox.collapsable[closed="true"] caption .caption-icon { - background-image: url("chrome://global/skin/tree/twisty-clsd.png"); + background-image: url("chrome://global/skin/tree/twisty.svg#clsd"); } groupbox tree { diff --git a/build/autoconf/rust.m4 b/build/autoconf/rust.m4 index a4d014a62e4..75409d5a5f8 100644 --- a/build/autoconf/rust.m4 +++ b/build/autoconf/rust.m4 @@ -25,10 +25,10 @@ AC_DEFUN([MOZ_RUST_SUPPORT], [ fi if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \ "$_RUSTC_MAJOR_VERSION" -lt 1 -o \ - \( "$_RUSTC_MAJOR_VERSION" -eq 1 -a "$_RUSTC_MINOR_VERSION" -lt 4 \); then + \( "$_RUSTC_MAJOR_VERSION" -eq 1 -a "$_RUSTC_MINOR_VERSION" -lt 5 \); then AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old. To compile Rust language sources please install at least - version 1.4 of the 'rustc' toolchain and make sure it is + version 1.5 of the 'rustc' toolchain and make sure it is first in your path. You can verify this by typing 'rustc --version'.]) fi diff --git a/config/rules.mk b/config/rules.mk index 938c956720d..81e52860e2b 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -945,7 +945,7 @@ ifdef MOZ_RUST # in the target's LIBS. $(RSOBJS): $(REPORT_BUILD) - $(RUSTC) $(RUSTFLAGS) --crate-type staticlib -o $(call mk_libname,$<) $(_VPATH_SRCS) + $(RUSTC) $(RUSTFLAGS) --crate-type staticlib --emit dep-info=$(MDDEPDIR)/$(call mk_libname,$<).pp,link=$(call mk_libname,$<) $(_VPATH_SRCS) endif $(SOBJS): diff --git a/configure.in b/configure.in index 463c9f6e2eb..c210a39ff91 100644 --- a/configure.in +++ b/configure.in @@ -6405,14 +6405,6 @@ AC_SUBST(TAR) AC_CHECK_PROGS(WGET, wget, "") AC_SUBST(WGET) -dnl ======================================================== -dnl Signing -dnl ======================================================== - -if test -n "$MOZ_SIGN_CMD"; then - AC_DEFINE(MOZ_SIGNING) -fi - dnl ======================================================== dnl Maintenance Service dnl ======================================================== diff --git a/devtools/client/framework/test/browser_toolbox_theme_registration.js b/devtools/client/framework/test/browser_toolbox_theme_registration.js index 7612c641a4f..1afa8434884 100644 --- a/devtools/client/framework/test/browser_toolbox_theme_registration.js +++ b/devtools/client/framework/test/browser_toolbox_theme_registration.js @@ -2,60 +2,45 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +// Test for dynamically registering and unregistering themes const CHROME_URL = "chrome://mochitests/content/browser/devtools/client/framework/test/"; var toolbox; -function test() -{ - gBrowser.selectedTab = gBrowser.addTab(); - let target = TargetFactory.forTab(gBrowser.selectedTab); +add_task(function* themeRegistration() { + let tab = yield addTab("data:text/html,test"); + let target = TargetFactory.forTab(tab); + toolbox = yield gDevTools.showToolbox(target); - gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) { - gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true); - gDevTools.showToolbox(target).then(testRegister); - }, true); + let themeId = yield new Promise(resolve => { + gDevTools.once("theme-registered", (e, themeId) => { + resolve(themeId); + }); - content.location = "data:text/html,test for dynamically registering and unregistering themes"; -} - -function testRegister(aToolbox) -{ - toolbox = aToolbox - gDevTools.once("theme-registered", themeRegistered); - - gDevTools.registerTheme({ - id: "test-theme", - label: "Test theme", - stylesheets: [CHROME_URL + "doc_theme.css"], - classList: ["theme-test"], + gDevTools.registerTheme({ + id: "test-theme", + label: "Test theme", + stylesheets: [CHROME_URL + "doc_theme.css"], + classList: ["theme-test"], + }); }); -} -function themeRegistered(event, themeId) -{ is(themeId, "test-theme", "theme-registered event handler sent theme id"); ok(gDevTools.getThemeDefinitionMap().has(themeId), "theme added to map"); +}); - // Test that new theme appears in the Options panel - let target = TargetFactory.forTab(gBrowser.selectedTab); - gDevTools.showToolbox(target, "options").then(() => { - let panel = toolbox.getCurrentPanel(); - let doc = panel.panelWin.frameElement.contentDocument; - let themeOption = doc.querySelector("#devtools-theme-box > radio[value=test-theme]"); +add_task(function* themeInOptionsPanel() { - ok(themeOption, "new theme exists in the Options panel"); + yield toolbox.selectTool("options"); - // Apply the new theme. - applyTheme(); - }); -} - -function applyTheme() -{ + let panel = toolbox.getCurrentPanel(); let panelWin = toolbox.getCurrentPanel().panelWin; let doc = panelWin.frameElement.contentDocument; + let themeOption = doc.querySelector("#devtools-theme-box > radio[value=test-theme]"); + + ok(themeOption, "new theme exists in the Options panel"); + let testThemeOption = doc.querySelector("#devtools-theme-box > radio[value=test-theme]"); let lightThemeOption = doc.querySelector("#devtools-theme-box > radio[value=light]"); @@ -65,24 +50,26 @@ function applyTheme() // Select test theme. testThemeOption.click(); + info("Waiting for theme to finish loading"); + yield once(panelWin, "theme-switch-complete"); + color = panelWin.getComputedStyle(testThemeOption).color; is(color, "rgb(255, 0, 0)", "style applied"); // Select light theme lightThemeOption.click(); + info("Waiting for theme to finish loading"); + yield once(panelWin, "theme-switch-complete"); + color = panelWin.getComputedStyle(testThemeOption).color; isnot(color, "rgb(255, 0, 0)", "style unapplied"); // Select test theme again. testThemeOption.click(); +}); - // Then unregister the test theme. - testUnregister(); -} - -function testUnregister() -{ +add_task(function* themeUnregistration() { gDevTools.unregisterTheme("test-theme"); ok(!gDevTools.getThemeDefinitionMap().has("test-theme"), "theme removed from map"); @@ -94,20 +81,9 @@ function testUnregister() // The default light theme must be selected now. is(themeBox.selectedItem, themeBox.querySelector("[value=light]"), "theme light must be selected"); +}); - // Make sure the tab-attaching process is done before we destroy the toolbox. - let target = TargetFactory.forTab(gBrowser.selectedTab); - let actor = target.activeTab.actor; - target.client.attachTab(actor, (response) => { - cleanup(); - }); -} - -function cleanup() -{ - toolbox.destroy().then(function() { - toolbox = null; - gBrowser.removeCurrentTab(); - finish(); - }); -} +add_task(function* cleanup() { + yield toolbox.destroy(); + toolbox = null; +}); diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index a4f60e52db6..118fb2143a6 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -39,24 +39,24 @@ devtools.jar: content/animationinspector/animation-controller.js (animationinspector/animation-controller.js) content/animationinspector/animation-panel.js (animationinspector/animation-panel.js) content/animationinspector/animation-inspector.xhtml (animationinspector/animation-inspector.xhtml) - content/sourceeditor/codemirror/comment/comment.js (sourceeditor/codemirror/addon/comment/comment.js) - content/sourceeditor/codemirror/edit/trailingspace.js (sourceeditor/codemirror/addon/edit/trailingspace.js) - content/sourceeditor/codemirror/edit/matchbrackets.js (sourceeditor/codemirror/addon/edit/matchbrackets.js) - content/sourceeditor/codemirror/edit/closebrackets.js (sourceeditor/codemirror/addon/edit/closebrackets.js) - content/sourceeditor/codemirror/dialog/dialog.js (sourceeditor/codemirror/addon/dialog/dialog.js) - content/sourceeditor/codemirror/dialog/dialog.css (sourceeditor/codemirror/addon/dialog/dialog.css) - content/sourceeditor/codemirror/fold/foldcode.js (sourceeditor/codemirror/addon/fold/foldcode.js) - content/sourceeditor/codemirror/fold/brace-fold.js (sourceeditor/codemirror/addon/fold/brace-fold.js) - content/sourceeditor/codemirror/fold/comment-fold.js (sourceeditor/codemirror/addon/fold/comment-fold.js) - content/sourceeditor/codemirror/fold/xml-fold.js (sourceeditor/codemirror/addon/fold/xml-fold.js) - content/sourceeditor/codemirror/fold/foldgutter.js (sourceeditor/codemirror/addon/fold/foldgutter.js) - content/sourceeditor/codemirror/hint/show-hint.js (sourceeditor/codemirror/addon/hint/show-hint.js) - content/sourceeditor/codemirror/search/search.js (sourceeditor/codemirror/addon/search/search.js) - content/sourceeditor/codemirror/search/searchcursor.js (sourceeditor/codemirror/addon/search/searchcursor.js) - content/sourceeditor/codemirror/selection/active-line.js (sourceeditor/codemirror/addon/selection/active-line.js) - content/sourceeditor/codemirror/tern/tern.js (sourceeditor/codemirror/addon/tern/tern.js) - content/sourceeditor/codemirror/codemirror.js (sourceeditor/codemirror/lib/codemirror.js) - content/sourceeditor/codemirror/codemirror.css (sourceeditor/codemirror/lib/codemirror.css) + content/sourceeditor/codemirror/addon/comment/comment.js (sourceeditor/codemirror/addon/comment/comment.js) + content/sourceeditor/codemirror/addon/edit/trailingspace.js (sourceeditor/codemirror/addon/edit/trailingspace.js) + content/sourceeditor/codemirror/addon/edit/matchbrackets.js (sourceeditor/codemirror/addon/edit/matchbrackets.js) + content/sourceeditor/codemirror/addon/edit/closebrackets.js (sourceeditor/codemirror/addon/edit/closebrackets.js) + content/sourceeditor/codemirror/addon/dialog/dialog.js (sourceeditor/codemirror/addon/dialog/dialog.js) + content/sourceeditor/codemirror/addon/dialog/dialog.css (sourceeditor/codemirror/addon/dialog/dialog.css) + content/sourceeditor/codemirror/addon/fold/foldcode.js (sourceeditor/codemirror/addon/fold/foldcode.js) + content/sourceeditor/codemirror/addon/fold/brace-fold.js (sourceeditor/codemirror/addon/fold/brace-fold.js) + content/sourceeditor/codemirror/addon/fold/comment-fold.js (sourceeditor/codemirror/addon/fold/comment-fold.js) + content/sourceeditor/codemirror/addon/fold/xml-fold.js (sourceeditor/codemirror/addon/fold/xml-fold.js) + content/sourceeditor/codemirror/addon/fold/foldgutter.js (sourceeditor/codemirror/addon/fold/foldgutter.js) + content/sourceeditor/codemirror/addon/hint/show-hint.js (sourceeditor/codemirror/addon/hint/show-hint.js) + content/sourceeditor/codemirror/addon/search/search.js (sourceeditor/codemirror/addon/search/search.js) + content/sourceeditor/codemirror/addon/search/searchcursor.js (sourceeditor/codemirror/addon/search/searchcursor.js) + content/sourceeditor/codemirror/addon/selection/active-line.js (sourceeditor/codemirror/addon/selection/active-line.js) + content/sourceeditor/codemirror/addon/tern/tern.js (sourceeditor/codemirror/addon/tern/tern.js) + content/sourceeditor/codemirror/lib/codemirror.js (sourceeditor/codemirror/lib/codemirror.js) + content/sourceeditor/codemirror/lib/codemirror.css (sourceeditor/codemirror/lib/codemirror.css) content/sourceeditor/codemirror/mode/javascript.js (sourceeditor/codemirror/mode/javascript.js) content/sourceeditor/codemirror/mode/xml.js (sourceeditor/codemirror/mode/xml.js) content/sourceeditor/codemirror/mode/css.js (sourceeditor/codemirror/mode/css.js) diff --git a/devtools/client/shared/test/browser_theme_switching.js b/devtools/client/shared/test/browser_theme_switching.js index a90569a21ea..8188e815b37 100644 --- a/devtools/client/shared/test/browser_theme_switching.js +++ b/devtools/client/shared/test/browser_theme_switching.js @@ -7,7 +7,8 @@ var toolbox; add_task(function*() { let target = TargetFactory.forTab(gBrowser.selectedTab); let toolbox = yield gDevTools.showToolbox(target); - let root = toolbox.frame.contentDocument.documentElement; + let doc = toolbox.frame.contentDocument; + let root = doc.documentElement; let platform = root.getAttribute("platform"); let expectedPlatform = getPlatform(); @@ -15,7 +16,24 @@ add_task(function*() { let theme = Services.prefs.getCharPref("devtools.theme"); let className = "theme-" + theme; - ok(root.classList.contains(className), ":root has " + className + " class (current theme)"); + ok(root.classList.contains(className), + ":root has " + className + " class (current theme)"); + + // Convert the xpath result into an array of strings + // like `href="{URL}" type="text/css"` + let sheetsIterator = doc.evaluate("processing-instruction('xml-stylesheet')", + doc, null, XPathResult.ANY_TYPE, null); + let sheetsInDOM = []; + let sheet; + while (sheet = sheetsIterator.iterateNext()) { + sheetsInDOM.push(sheet.data); + } + + let sheetsFromTheme = gDevTools.getThemeDefinition(theme).stylesheets; + info ("Checking for existence of " + sheetsInDOM.length + " sheets"); + for (let sheet of sheetsFromTheme) { + ok(sheetsInDOM.some(s=>s.includes(sheet)), "There is a stylesheet for " + sheet); + } yield toolbox.destroy(); }); diff --git a/devtools/client/shared/theme-switching.js b/devtools/client/shared/theme-switching.js index 00ae124577c..eee1e09df95 100644 --- a/devtools/client/shared/theme-switching.js +++ b/devtools/client/shared/theme-switching.js @@ -3,8 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ (function() { - const DEVTOOLS_SKIN_URL = "chrome://devtools/skin/"; + const SCROLLBARS_URL = "chrome://devtools/skin/floating-scrollbars-light.css"; let documentElement = document.documentElement; + let devtoolsStyleSheets = new WeakMap(); function forceStyle() { let computedStyle = window.getComputedStyle(documentElement); @@ -19,6 +20,45 @@ documentElement.style.display = display; // Restore } + /* + * Append a new processing instruction and return an object with + * - styleSheet: DOMNode + * - loadPromise: Promise that resolves once the sheets loads or errors + */ + function appendStyleSheet(url) { + let styleSheetAttr = `href="${url}" type="text/css"`; + let styleSheet = document.createProcessingInstruction( + "xml-stylesheet", styleSheetAttr); + let loadPromise = new Promise((resolve, reject) => { + function onload() { + styleSheet.removeEventListener("load", onload); + styleSheet.removeEventListener("error", onerror); + resolve(); + } + function onerror() { + styleSheet.removeEventListener("load", onload); + styleSheet.removeEventListener("error", onerror); + reject("Failed to load theme file " + url); + } + + styleSheet.addEventListener("load", onload); + styleSheet.addEventListener("error", onerror); + }); + document.insertBefore(styleSheet, documentElement); + return {styleSheet, loadPromise}; + } + + /* + * Notify the window that a theme switch finished so tests can check the DOM + */ + function notifyWindow() { + window.dispatchEvent(new CustomEvent("theme-switch-complete", {})); + } + + /* + * Apply all the sheets from `newTheme` and remove all of the sheets + * from `oldTheme` + */ function switchTheme(newTheme, oldTheme) { if (newTheme === oldTheme) { return; @@ -28,8 +68,8 @@ // Unload all theme stylesheets related to the old theme. if (oldThemeDef) { - for (let url of oldThemeDef.stylesheets) { - StylesheetUtils.removeSheet(window, url, "author"); + for (let sheet of devtoolsStyleSheets.get(oldThemeDef) || []) { + sheet.remove(); } } @@ -42,8 +82,17 @@ newThemeDef = gDevTools.getThemeDefinition("light"); } + // Store the sheets in a WeakMap for access later when the theme gets + // unapplied. It's hard to query for processing instructions so this + // is an easy way to access them later without storing a property on + // the window + devtoolsStyleSheets.set(newThemeDef, []); + + let loadEvents = []; for (let url of newThemeDef.stylesheets) { - StylesheetUtils.loadSheet(window, url, "author"); + let {styleSheet,loadPromise} = appendStyleSheet(url); + devtoolsStyleSheets.get(newThemeDef).push(styleSheet); + loadEvents.push(loadPromise); } // Floating scroll-bars like in OSX @@ -53,21 +102,10 @@ // TODO: extensions might want to customize scrollbar styles too. if (!hiddenDOMWindow.matchMedia("(-moz-overlay-scrollbars)").matches) { - let scrollbarsUrl = Services.io.newURI( - DEVTOOLS_SKIN_URL + "floating-scrollbars-light.css", null, null); - if (newTheme == "dark") { - StylesheetUtils.loadSheet( - window, - scrollbarsUrl, - "agent" - ); + StylesheetUtils.loadSheet(window, SCROLLBARS_URL, "agent"); } else if (oldTheme == "dark") { - StylesheetUtils.removeSheet( - window, - scrollbarsUrl, - "agent" - ); + StylesheetUtils.removeSheet(window, SCROLLBARS_URL, "agent"); } forceStyle(); } @@ -92,6 +130,8 @@ // Final notification for further theme-switching related logic. gDevTools.emit("theme-switched", window, newTheme, oldTheme); + + Promise.all(loadEvents).then(notifyWindow, console.error.bind(console)); } function handlePrefChange(event, data) { @@ -101,7 +141,6 @@ } const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://devtools/client/framework/gDevTools.jsm"); const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/sourceeditor/autocomplete.js b/devtools/client/sourceeditor/autocomplete.js index 4827268c65c..cebc9372e1b 100644 --- a/devtools/client/sourceeditor/autocomplete.js +++ b/devtools/client/sourceeditor/autocomplete.js @@ -8,8 +8,8 @@ const cssAutoCompleter = require("devtools/client/sourceeditor/css-autocompleter const { AutocompletePopup } = require("devtools/client/shared/autocomplete-popup"); const CM_TERN_SCRIPTS = [ - "chrome://devtools/content/sourceeditor/codemirror/tern/tern.js", - "chrome://devtools/content/sourceeditor/codemirror/hint/show-hint.js" + "chrome://devtools/content/sourceeditor/codemirror/addon/tern/tern.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/hint/show-hint.js" ]; const autocompleteMap = new WeakMap(); diff --git a/devtools/client/sourceeditor/editor.js b/devtools/client/sourceeditor/editor.js index c3274891b70..592fc003a06 100644 --- a/devtools/client/sourceeditor/editor.js +++ b/devtools/client/sourceeditor/editor.js @@ -47,35 +47,35 @@ const { OS } = Services.appinfo; const CM_STYLES = [ "chrome://devtools/skin/common.css", - "chrome://devtools/content/sourceeditor/codemirror/codemirror.css", - "chrome://devtools/content/sourceeditor/codemirror/dialog/dialog.css", + "chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css", + "chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css", "chrome://devtools/content/sourceeditor/codemirror/mozilla.css" ]; const CM_SCRIPTS = [ "chrome://devtools/content/shared/theme-switching.js", - "chrome://devtools/content/sourceeditor/codemirror/codemirror.js", - "chrome://devtools/content/sourceeditor/codemirror/dialog/dialog.js", - "chrome://devtools/content/sourceeditor/codemirror/search/searchcursor.js", - "chrome://devtools/content/sourceeditor/codemirror/search/search.js", - "chrome://devtools/content/sourceeditor/codemirror/edit/matchbrackets.js", - "chrome://devtools/content/sourceeditor/codemirror/edit/closebrackets.js", - "chrome://devtools/content/sourceeditor/codemirror/comment/comment.js", + "chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/search/searchcursor.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/search/search.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/edit/matchbrackets.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/edit/closebrackets.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/comment/comment.js", "chrome://devtools/content/sourceeditor/codemirror/mode/javascript.js", "chrome://devtools/content/sourceeditor/codemirror/mode/xml.js", "chrome://devtools/content/sourceeditor/codemirror/mode/css.js", "chrome://devtools/content/sourceeditor/codemirror/mode/htmlmixed.js", "chrome://devtools/content/sourceeditor/codemirror/mode/clike.js", - "chrome://devtools/content/sourceeditor/codemirror/selection/active-line.js", - "chrome://devtools/content/sourceeditor/codemirror/edit/trailingspace.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/selection/active-line.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/edit/trailingspace.js", "chrome://devtools/content/sourceeditor/codemirror/keymap/emacs.js", "chrome://devtools/content/sourceeditor/codemirror/keymap/vim.js", "chrome://devtools/content/sourceeditor/codemirror/keymap/sublime.js", - "chrome://devtools/content/sourceeditor/codemirror/fold/foldcode.js", - "chrome://devtools/content/sourceeditor/codemirror/fold/brace-fold.js", - "chrome://devtools/content/sourceeditor/codemirror/fold/comment-fold.js", - "chrome://devtools/content/sourceeditor/codemirror/fold/xml-fold.js", - "chrome://devtools/content/sourceeditor/codemirror/fold/foldgutter.js" + "chrome://devtools/content/sourceeditor/codemirror/addon/fold/foldcode.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/fold/brace-fold.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/fold/comment-fold.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/fold/xml-fold.js", + "chrome://devtools/content/sourceeditor/codemirror/addon/fold/foldgutter.js" ]; const CM_IFRAME = diff --git a/devtools/client/sourceeditor/test/codemirror/codemirror.html b/devtools/client/sourceeditor/test/codemirror/codemirror.html index a8bdebd8dd6..7449f1ce524 100644 --- a/devtools/client/sourceeditor/test/codemirror/codemirror.html +++ b/devtools/client/sourceeditor/test/codemirror/codemirror.html @@ -3,15 +3,15 @@ CodeMirror: Basic Tests - + - - - - - + + + + + diff --git a/devtools/client/sourceeditor/test/codemirror/vimemacs.html b/devtools/client/sourceeditor/test/codemirror/vimemacs.html index 0c39d90bc79..e3d9ff39310 100644 --- a/devtools/client/sourceeditor/test/codemirror/vimemacs.html +++ b/devtools/client/sourceeditor/test/codemirror/vimemacs.html @@ -3,15 +3,15 @@ CodeMirror: VIM/Emacs tests - + - - - - - + + + + + diff --git a/devtools/client/themes/animationinspector.css b/devtools/client/themes/animationinspector.css index 8ceeda7da40..9d6248336cd 100644 --- a/devtools/client/themes/animationinspector.css +++ b/devtools/client/themes/animationinspector.css @@ -290,7 +290,7 @@ body { height: 100%; box-sizing: border-box; - --timelime-border-color: var(--theme-body-color); + --timeline-border-color: var(--theme-body-color); --timeline-background-color: var(--theme-splitter-color); /* Iterations of the animation are displayed with a repeating linear-gradient @@ -299,25 +299,25 @@ body { the border of this element */ background-image: linear-gradient(to right, - var(--timelime-border-color) 0, - var(--timelime-border-color) 1px, + var(--timeline-border-color) 0, + var(--timeline-border-color) 1px, transparent 1px, transparent 2px); background-repeat: repeat-x; background-position: -1px 0; - border: 1px solid var(--timelime-border-color); + border: 1px solid var(--timeline-border-color); /* The background color is set independently */ background-color: var(--timeline-background-color); } .animation-timeline .animation .cssanimation { - --timelime-border-color: var(--theme-highlight-lightorange); + --timeline-border-color: var(--theme-highlight-lightorange); --timeline-background-color: var(--theme-contrast-background); } .animation-timeline .animation .csstransition { - --timelime-border-color: var(--theme-highlight-bluegrey); + --timeline-border-color: var(--theme-highlight-bluegrey); --timeline-background-color: var(--theme-highlight-blue); } @@ -369,14 +369,14 @@ body { box-sizing: border-box; height: calc(100% + 2px); - border: 1px solid var(--timelime-border-color); + border: 1px solid var(--timeline-border-color); border-width: 1px 0 1px 1px; background-image: repeating-linear-gradient(45deg, transparent, transparent 1px, var(--theme-selection-color) 1px, var(--theme-selection-color) 4px); - background-color: var(--timelime-border-color); + background-color: var(--timeline-border-color); } .animation-timeline .animation .delay.negative { diff --git a/devtools/client/themes/layoutview.css b/devtools/client/themes/layoutview.css index 125d7f24724..8cef3b4b8e1 100644 --- a/devtools/client/themes/layoutview.css +++ b/devtools/client/themes/layoutview.css @@ -6,7 +6,7 @@ box-sizing: border-box; } -.theme-sidebar body { +body.theme-sidebar { /* The view will grow bigger as the window gets resized, until 400px */ max-width: 400px; margin: 0px auto; diff --git a/devtools/client/webconsole/webconsole.js b/devtools/client/webconsole/webconsole.js index 0641bc7cb9d..b81e461dde5 100644 --- a/devtools/client/webconsole/webconsole.js +++ b/devtools/client/webconsole/webconsole.js @@ -194,12 +194,12 @@ const PREF_INPUT_HISTORY_COUNT = "devtools.webconsole.inputHistoryCount"; * implementation. * * @constructor - * @param object aWebConsoleOwner + * @param object webConsoleOwner * The WebConsole owner object. */ -function WebConsoleFrame(aWebConsoleOwner) +function WebConsoleFrame(webConsoleOwner) { - this.owner = aWebConsoleOwner; + this.owner = webConsoleOwner; this.hudId = this.owner.hudId; this.window = this.owner.iframeWindow; @@ -390,13 +390,13 @@ WebConsoleFrame.prototype = { ]; // Make sure the web console client connection is established first. - this.webConsoleClient.getPreferences(toGet, aResponse => { - if (!aResponse.error) { - this._saveRequestAndResponseBodies = aResponse.preferences[toGet[0]]; + this.webConsoleClient.getPreferences(toGet, response => { + if (!response.error) { + this._saveRequestAndResponseBodies = response.preferences[toGet[0]]; deferred.resolve(this._saveRequestAndResponseBodies); } else { - deferred.reject(aResponse.error); + deferred.reject(response.error); } }); @@ -406,30 +406,30 @@ WebConsoleFrame.prototype = { /** * Setter for saving of network request and response bodies. * - * @param boolean aValue + * @param boolean value * The new value you want to set. */ setSaveRequestAndResponseBodies: - function WCF_setSaveRequestAndResponseBodies(aValue) { + function WCF_setSaveRequestAndResponseBodies(value) { if (!this.webConsoleClient) { // Don't continue if the webconsole disconnected. return promise.resolve(null); } let deferred = promise.defer(); - let newValue = !!aValue; + let newValue = !!value; let toSet = { "NetworkMonitor.saveRequestAndResponseBodies": newValue, }; // Make sure the web console client connection is established first. - this.webConsoleClient.setPreferences(toSet, aResponse => { - if (!aResponse.error) { + this.webConsoleClient.setPreferences(toSet, response => { + if (!response.error) { this._saveRequestAndResponseBodies = newValue; - deferred.resolve(aResponse); + deferred.resolve(response); } else { - deferred.reject(aResponse.error); + deferred.reject(response.error); } }); @@ -495,11 +495,11 @@ WebConsoleFrame.prototype = { this.proxy.connect().then(() => { // on success this._initDefer.resolve(this); - }, (aReason) => { // on failure + }, (reason) => { // on failure let node = this.createMessageNode(CATEGORY_JS, SEVERITY_ERROR, - aReason.error + ": " + aReason.message); - this.outputMessage(CATEGORY_JS, node, [aReason]); - this._initDefer.reject(aReason); + reason.error + ": " + reason.message); + this.outputMessage(CATEGORY_JS, node, [reason]); + this._initDefer.reject(reason); }); return this._initDefer.promise; @@ -560,17 +560,17 @@ WebConsoleFrame.prototype = { // calculations. this._updateCharSize(); - let updateSaveBodiesPrefUI = (aElement) => { - this.getSaveRequestAndResponseBodies().then(aValue => { - aElement.setAttribute("checked", aValue); + let updateSaveBodiesPrefUI = (element) => { + this.getSaveRequestAndResponseBodies().then(value => { + element.setAttribute("checked", value); this.emit("save-bodies-ui-toggled"); }); } - let reverseSaveBodiesPref = ({ target: aElement }) => { - this.getSaveRequestAndResponseBodies().then(aValue => { - this.setSaveRequestAndResponseBodies(!aValue); - aElement.setAttribute("checked", aValue); + let reverseSaveBodiesPref = ({ target: element }) => { + this.getSaveRequestAndResponseBodies().then(value => { + this.setSaveRequestAndResponseBodies(!value); + element.setAttribute("checked", value); this.emit("save-bodies-pref-reversed"); }); } @@ -670,19 +670,19 @@ WebConsoleFrame.prototype = { * Attach / detach reflow listeners depending on the checked status * of the `CSS > Log` menuitem. * - * @param function [aCallback=null] + * @param function [callback=null] * Optional function to invoke when the listener has been * added/removed. */ _updateReflowActivityListener: - function WCF__updateReflowActivityListener(aCallback) + function WCF__updateReflowActivityListener(callback) { if (this.webConsoleClient) { let pref = this._filterPrefsPrefix + "csslog"; if (Services.prefs.getBoolPref(pref)) { - this.webConsoleClient.startListeners(["ReflowActivity"], aCallback); + this.webConsoleClient.startListeners(["ReflowActivity"], callback); } else { - this.webConsoleClient.stopListeners(["ReflowActivity"], aCallback); + this.webConsoleClient.stopListeners(["ReflowActivity"], callback); } } }, @@ -692,12 +692,12 @@ WebConsoleFrame.prototype = { * preferences. If the user isn't interested in the server logs at * all the listener is not registered. * - * @param function [aCallback=null] + * @param function [callback=null] * Optional function to invoke when the listener has been * added/removed. */ _updateServerLoggingListener: - function WCF__updateServerLoggingListener(aCallback) + function WCF__updateServerLoggingListener(callback) { if (!this.webConsoleClient) { return; @@ -713,9 +713,9 @@ WebConsoleFrame.prototype = { } if (startListener) { - this.webConsoleClient.startListeners(["ServerLogging"], aCallback); + this.webConsoleClient.startListeners(["ServerLogging"], callback); } else { - this.webConsoleClient.stopListeners(["ServerLogging"], aCallback); + this.webConsoleClient.stopListeners(["ServerLogging"], callback); } }, @@ -755,25 +755,25 @@ WebConsoleFrame.prototype = { { let categories = this.document .querySelectorAll(".webconsole-filter-button[category]"); - Array.forEach(categories, function(aButton) { - aButton.addEventListener("contextmenu", (aEvent) => { - aButton.open = true; + Array.forEach(categories, function(button) { + button.addEventListener("contextmenu", (event) => { + button.open = true; }, false); - aButton.addEventListener("click", this._toggleFilter, false); + button.addEventListener("click", this._toggleFilter, false); let someChecked = false; - let severities = aButton.querySelectorAll("menuitem[prefKey]"); - Array.forEach(severities, function(aMenuItem) { - aMenuItem.addEventListener("command", this._toggleFilter, false); + let severities = button.querySelectorAll("menuitem[prefKey]"); + Array.forEach(severities, function(menuItem) { + menuItem.addEventListener("command", this._toggleFilter, false); - let prefKey = aMenuItem.getAttribute("prefKey"); + let prefKey = menuItem.getAttribute("prefKey"); let checked = this.filterPrefs[prefKey]; - aMenuItem.setAttribute("checked", checked); + menuItem.setAttribute("checked", checked); someChecked = someChecked || checked; }, this); - aButton.setAttribute("checked", someChecked); - aButton.setAttribute("aria-pressed", someChecked); + button.setAttribute("checked", someChecked); + button.setAttribute("aria-pressed", someChecked); }, this); if (!this.owner._browserConsole) { @@ -804,7 +804,7 @@ WebConsoleFrame.prototype = { * The size of the font change. Accepted values are "+" and "-". * An unmatched size assumes a font reset. */ - changeFontSize: function WCF_changeFontSize(aSize) + changeFontSize: function WCF_changeFontSize(size) { let fontSize = this.window .getComputedStyle(this.outputNode, null) @@ -814,10 +814,10 @@ WebConsoleFrame.prototype = { fontSize = this.outputNode.style.fontSize.replace("px", ""); } - if (aSize == "+" || aSize == "-") { + if (size == "+" || size == "-") { fontSize = parseInt(fontSize, 10); - if (aSize == "+") { + if (size == "+") { fontSize += 1; } else { @@ -876,22 +876,22 @@ WebConsoleFrame.prototype = { * off. * * @private - * @param nsIDOMEvent aEvent + * @param nsIDOMEvent event * The event that triggered the filter change. */ - _toggleFilter: function WCF__toggleFilter(aEvent) + _toggleFilter: function WCF__toggleFilter(event) { - let target = aEvent.target; + let target = event.target; let tagName = target.tagName; // Prevent toggle if generated from a contextmenu event (right click) - let isRightClick = (aEvent.button === 2); // right click is button 2; - if (tagName != aEvent.currentTarget.tagName || isRightClick) { + let isRightClick = (event.button === 2); // right click is button 2; + if (tagName != event.currentTarget.tagName || isRightClick) { return; } switch (tagName) { case "toolbarbutton": { - let originalTarget = aEvent.originalTarget; + let originalTarget = event.originalTarget; let classes = originalTarget.classList; if (originalTarget.localName !== "toolbarbutton") { @@ -912,7 +912,7 @@ WebConsoleFrame.prototype = { // Toggle on the targeted filter button, and if the user alt clicked, // toggle off all other filter buttons and their associated filters. let state = target.getAttribute("checked") !== "true"; - if (aEvent.getModifierState("Alt")) { + if (event.getModifierState("Alt")) { let buttons = this.document .querySelectorAll(".webconsole-filter-button"); Array.forEach(buttons, (button) => { @@ -985,34 +985,34 @@ WebConsoleFrame.prototype = { * Set the menu attributes for a specific toggle button. * * @private - * @param XULElement aTarget + * @param XULElement target * Button with drop down items to be toggled. - * @param boolean aState + * @param boolean state * True if the menu item is being toggled on, and false otherwise. */ - _setMenuState: function WCF__setMenuState(aTarget, aState) + _setMenuState: function WCF__setMenuState(target, state) { - let menuItems = aTarget.querySelectorAll("menuitem"); + let menuItems = target.querySelectorAll("menuitem"); Array.forEach(menuItems, (item) => { - item.setAttribute("checked", aState); + item.setAttribute("checked", state); let prefKey = item.getAttribute("prefKey"); - this.setFilterState(prefKey, aState); + this.setFilterState(prefKey, state); }); }, /** * Set the filter state for a specific toggle button. * - * @param string aToggleType - * @param boolean aState + * @param string toggleType + * @param boolean state * @returns void */ - setFilterState: function WCF_setFilterState(aToggleType, aState) + setFilterState: function WCF_setFilterState(toggleType, state) { - this.filterPrefs[aToggleType] = aState; - this.adjustVisibilityForMessageType(aToggleType, aState); + this.filterPrefs[toggleType] = state; + this.adjustVisibilityForMessageType(toggleType, state); - Services.prefs.setBoolPref(this._filterPrefsPrefix + aToggleType, aState); + Services.prefs.setBoolPref(this._filterPrefsPrefix + toggleType, state); if (this._updateListenersTimeout) { Timers.clearTimeout(this._updateListenersTimeout); @@ -1025,12 +1025,12 @@ WebConsoleFrame.prototype = { /** * Get the filter state for a specific toggle button. * - * @param string aToggleType + * @param string toggleType * @returns boolean */ - getFilterState: function WCF_getFilterState(aToggleType) + getFilterState: function WCF_getFilterState(toggleType) { - return this.filterPrefs[aToggleType]; + return this.filterPrefs[toggleType]; }, /** @@ -1045,20 +1045,20 @@ WebConsoleFrame.prototype = { /** * Check that the passed string matches the filter arguments. * - * @param String aString + * @param String str * to search for filter words in. - * @param String aFilter + * @param String filter * is a string containing all of the words to filter on. * @returns boolean */ - stringMatchesFilters: function WCF_stringMatchesFilters(aString, aFilter) + stringMatchesFilters: function WCF_stringMatchesFilters(str, filter) { - if (!aFilter || !aString) { + if (!filter || !str) { return true; } - let searchStr = aString.toLowerCase(); - let filterStrings = aFilter.toLowerCase().split(/\s+/); + let searchStr = str.toLowerCase(); + let filterStrings = filter.toLowerCase().split(/\s+/); return !filterStrings.some(function (f) { return searchStr.indexOf(f) == -1; }); @@ -1066,18 +1066,18 @@ WebConsoleFrame.prototype = { /** * Turns the display of log nodes on and off appropriately to reflect the - * adjustment of the message type filter named by @aPrefKey. + * adjustment of the message type filter named by @prefKey. * - * @param string aPrefKey + * @param string prefKey * The preference key for the message type being filtered: one of the * values in the MESSAGE_PREFERENCE_KEYS table. - * @param boolean aState - * True if the filter named by @aMessageType is being turned on; false + * @param boolean state + * True if the filter named by @messageType is being turned on; false * otherwise. * @returns void */ adjustVisibilityForMessageType: - function WCF_adjustVisibilityForMessageType(aPrefKey, aState) + function WCF_adjustVisibilityForMessageType(prefKey, state) { let outputNode = this.outputNode; let doc = this.document; @@ -1086,16 +1086,16 @@ WebConsoleFrame.prototype = { // (filter="error", filter="cssparser", etc.) and add or remove the // "filtered-by-type" class, which turns on or off the display. - let attribute = WORKERTYPES_PREFKEYS.indexOf(aPrefKey) == -1 + let attribute = WORKERTYPES_PREFKEYS.indexOf(prefKey) == -1 ? 'filter' : 'workerType'; let xpath = ".//*[contains(@class, 'message') and " + - "@" + attribute + "='" + aPrefKey + "']"; + "@" + attribute + "='" + prefKey + "']"; let result = doc.evaluate(xpath, outputNode, null, Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (let i = 0; i < result.snapshotLength; i++) { let node = result.snapshotItem(i); - if (aState) { + if (state) { node.classList.remove("filtered-by-type"); } else { @@ -1134,41 +1134,41 @@ WebConsoleFrame.prototype = { * Applies the user's filters to a newly-created message node via CSS * classes. * - * @param nsIDOMNode aNode + * @param nsIDOMNode node * The newly-created message node. * @return boolean * True if the message was filtered or false otherwise. */ - filterMessageNode: function WCF_filterMessageNode(aNode) + filterMessageNode: function WCF_filterMessageNode(node) { let isFiltered = false; // Filter by the message type. - let prefKey = MESSAGE_PREFERENCE_KEYS[aNode.category][aNode.severity]; + let prefKey = MESSAGE_PREFERENCE_KEYS[node.category][node.severity]; if (prefKey && !this.getFilterState(prefKey)) { // The node is filtered by type. - aNode.classList.add("filtered-by-type"); + node.classList.add("filtered-by-type"); isFiltered = true; } // Filter by worker type - if ("workerType" in aNode && !this.getFilterState(aNode.workerType)) { - aNode.classList.add("filtered-by-type"); + if ("workerType" in node && !this.getFilterState(node.workerType)) { + node.classList.add("filtered-by-type"); isFiltered = true; } // Filter on the search string. let search = this.filterBox.value; - let text = aNode.clipboardText; + let text = node.clipboardText; // if string matches the filter text if (!this.stringMatchesFilters(text, search)) { - aNode.classList.add("filtered-by-string"); + node.classList.add("filtered-by-string"); isFiltered = true; } - if (isFiltered && aNode.classList.contains("inlined-variables-view")) { - aNode.classList.add("hidden-message"); + if (isFiltered && node.classList.contains("inlined-variables-view")) { + node.classList.add("hidden-message"); } return isFiltered; @@ -1176,17 +1176,17 @@ WebConsoleFrame.prototype = { /** * Merge the attributes of the two nodes that are about to be filtered. - * Increment the number of repeats of aOriginal. + * Increment the number of repeats of original. * - * @param nsIDOMNode aOriginal + * @param nsIDOMNode original * The Original Node. The one being merged into. - * @param nsIDOMNode aFiltered + * @param nsIDOMNode filtered * The node being filtered out because it is repeated. */ mergeFilteredMessageNode: - function WCF_mergeFilteredMessageNode(aOriginal, aFiltered) + function WCF_mergeFilteredMessageNode(original, filtered) { - let repeatNode = aOriginal.getElementsByClassName("message-repeats")[0]; + let repeatNode = original.getElementsByClassName("message-repeats")[0]; if (!repeatNode) { return; // no repeat node, return early. } @@ -1203,15 +1203,15 @@ WebConsoleFrame.prototype = { * Filter the message node from the output if it is a repeat. * * @private - * @param nsIDOMNode aNode + * @param nsIDOMNode node * The message node to be filtered or not. * @returns nsIDOMNode|null * Returns the duplicate node if the message was filtered, null * otherwise. */ - _filterRepeatedMessage: function WCF__filterRepeatedMessage(aNode) + _filterRepeatedMessage: function WCF__filterRepeatedMessage(node) { - let repeatNode = aNode.getElementsByClassName("message-repeats")[0]; + let repeatNode = node.getElementsByClassName("message-repeats")[0]; if (!repeatNode) { return null; } @@ -1219,17 +1219,17 @@ WebConsoleFrame.prototype = { let uid = repeatNode._uid; let dupeNode = null; - if (aNode.category == CATEGORY_CSS || - aNode.category == CATEGORY_SECURITY) { + if (node.category == CATEGORY_CSS || + node.category == CATEGORY_SECURITY) { dupeNode = this._repeatNodes[uid]; if (!dupeNode) { - this._repeatNodes[uid] = aNode; + this._repeatNodes[uid] = node; } } - else if ((aNode.category == CATEGORY_WEBDEV || - aNode.category == CATEGORY_JS) && - aNode.category != CATEGORY_NETWORK && - !aNode.classList.contains("inlined-variables-view")) { + else if ((node.category == CATEGORY_WEBDEV || + node.category == CATEGORY_JS) && + node.category != CATEGORY_NETWORK && + !node.classList.contains("inlined-variables-view")) { let lastMessage = this.outputNode.lastChild; if (!lastMessage) { return null; @@ -1242,7 +1242,7 @@ WebConsoleFrame.prototype = { } if (dupeNode) { - this.mergeFilteredMessageNode(dupeNode, aNode); + this.mergeFilteredMessageNode(dupeNode, node); return dupeNode; } @@ -1253,33 +1253,33 @@ WebConsoleFrame.prototype = { * Display cached messages that may have been collected before the UI is * displayed. * - * @param array aRemoteMessages + * @param array remoteMessages * Array of cached messages coming from the remote Web Console * content instance. */ - displayCachedMessages: function WCF_displayCachedMessages(aRemoteMessages) + displayCachedMessages: function WCF_displayCachedMessages(remoteMessages) { - if (!aRemoteMessages.length) { + if (!remoteMessages.length) { return; } - aRemoteMessages.forEach(function(aMessage) { - switch (aMessage._type) { + remoteMessages.forEach(function(message) { + switch (message._type) { case "PageError": { - let category = Utils.categoryForScriptError(aMessage); + let category = Utils.categoryForScriptError(message); this.outputMessage(category, this.reportPageError, - [category, aMessage]); + [category, message]); break; } case "LogMessage": - this.handleLogMessage(aMessage); + this.handleLogMessage(message); break; case "ConsoleAPI": this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, - [aMessage]); + [message]); break; case "NetworkEvent": - this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aMessage]); + this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [message]); break; } }, this); @@ -1289,26 +1289,26 @@ WebConsoleFrame.prototype = { * Logs a message to the Web Console that originates from the Web Console * server. * - * @param object aMessage + * @param object message * The message received from the server. * @return nsIDOMElement|null * The message element to display in the Web Console output. */ - logConsoleAPIMessage: function WCF_logConsoleAPIMessage(aMessage) + logConsoleAPIMessage: function WCF_logConsoleAPIMessage(message) { let body = null; let clipboardText = null; - let sourceURL = aMessage.filename; - let sourceLine = aMessage.lineNumber; - let level = aMessage.level; - let args = aMessage.arguments; + let sourceURL = message.filename; + let sourceLine = message.lineNumber; + let level = message.level; + let args = message.arguments; let objectActors = new Set(); let node = null; // Gather the actor IDs. - args.forEach((aValue) => { - if (WebConsoleUtils.isActorGrip(aValue)) { - objectActors.add(aValue.actor); + args.forEach((value) => { + if (WebConsoleUtils.isActorGrip(value)) { + objectActors.add(value.actor); } }); @@ -1320,37 +1320,37 @@ WebConsoleFrame.prototype = { case "exception": case "assert": case "debug": { - let msg = new Messages.ConsoleGeneric(aMessage); + let msg = new Messages.ConsoleGeneric(message); node = msg.init(this.output).render().element; break; } case "table": { - let msg = new Messages.ConsoleTable(aMessage); + let msg = new Messages.ConsoleTable(message); node = msg.init(this.output).render().element; break; } case "trace": { - let msg = new Messages.ConsoleTrace(aMessage); + let msg = new Messages.ConsoleTrace(message); node = msg.init(this.output).render().element; break; } case "dir": { body = { arguments: args }; let clipboardArray = []; - args.forEach((aValue) => { - clipboardArray.push(VariablesView.getString(aValue)); + args.forEach((value) => { + clipboardArray.push(VariablesView.getString(value)); }); clipboardText = clipboardArray.join(" "); break; } case "dirxml": { // We just alias console.dirxml() with console.log(). - aMessage.level = "log"; - return WCF_logConsoleAPIMessage.call(this, aMessage); + message.level = "log"; + return WCF_logConsoleAPIMessage.call(this, message); } case "group": case "groupCollapsed": - clipboardText = body = aMessage.groupName; + clipboardText = body = message.groupName; this.groupDepth++; break; @@ -1361,7 +1361,7 @@ WebConsoleFrame.prototype = { break; case "time": { - let timer = aMessage.timer; + let timer = message.timer; if (!timer) { return null; } @@ -1375,7 +1375,7 @@ WebConsoleFrame.prototype = { } case "timeEnd": { - let timer = aMessage.timer; + let timer = message.timer; if (!timer) { return null; } @@ -1386,7 +1386,7 @@ WebConsoleFrame.prototype = { } case "count": { - let counter = aMessage.counter; + let counter = message.counter; if (!counter) { return null; } @@ -1394,7 +1394,7 @@ WebConsoleFrame.prototype = { Cu.reportError(l10n.getStr(counter.error)); return null; } - let msg = new Messages.ConsoleGeneric(aMessage); + let msg = new Messages.ConsoleGeneric(message); node = msg.init(this.output).render().element; break; } @@ -1431,8 +1431,8 @@ WebConsoleFrame.prototype = { if (!node) { node = this.createMessageNode(CATEGORY_WEBDEV, LEVELS[level], body, sourceURL, sourceLine, clipboardText, - level, aMessage.timeStamp); - if (aMessage.private) { + level, message.timeStamp); + if (message.private) { node.setAttribute("private", true); } } @@ -1446,7 +1446,7 @@ WebConsoleFrame.prototype = { } } - let workerTypeID = CONSOLE_WORKER_IDS.indexOf(aMessage.workerType); + let workerTypeID = CONSOLE_WORKER_IDS.indexOf(message.workerType); if (workerTypeID != -1) { node.workerType = WORKERTYPES_PREFKEYS[workerTypeID]; node.setAttribute('workerType', WORKERTYPES_PREFKEYS[workerTypeID]); @@ -1459,65 +1459,67 @@ WebConsoleFrame.prototype = { * Handle ConsoleAPICall objects received from the server. This method outputs * the window.console API call. * - * @param object aMessage + * @param object message * The console API message received from the server. */ - handleConsoleAPICall: function WCF_handleConsoleAPICall(aMessage) + handleConsoleAPICall: function WCF_handleConsoleAPICall(message) { - this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, [aMessage]); + this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, [message]); }, /** * Reports an error in the page source, either JavaScript or CSS. * - * @param nsIScriptError aScriptError + * @param nsIScriptError scriptError * The error message to report. * @return nsIDOMElement|undefined * The message element to display in the Web Console output. */ - reportPageError: function WCF_reportPageError(aCategory, aScriptError) + reportPageError: function WCF_reportPageError(category, scriptError) { // Warnings and legacy strict errors become warnings; other types become // errors. let severity = 'error'; - if (aScriptError.warning || aScriptError.strict) { + if (scriptError.warning || scriptError.strict) { severity = 'warning'; - } else if (aScriptError.info) { + } else if (scriptError.info) { severity = 'log'; } - let category = 'js'; - switch(aCategory) { + switch(category) { case CATEGORY_CSS: category = 'css'; break; case CATEGORY_SECURITY: category = 'security'; break; + default: + category = "js"; + break; } let objectActors = new Set(); // Gather the actor IDs. for (let prop of ["errorMessage", "lineText"]) { - let grip = aScriptError[prop]; + let grip = scriptError[prop]; if (WebConsoleUtils.isActorGrip(grip)) { objectActors.add(grip.actor); } } - let errorMessage = aScriptError.errorMessage; + let errorMessage = scriptError.errorMessage; if (errorMessage.type && errorMessage.type == "longString") { errorMessage = errorMessage.initial; } - let displayOrigin = aScriptError.sourceName; + let displayOrigin = scriptError.sourceName; // TLS errors are related to the connection and not the resource; therefore // it makes sense to only display the protcol, host and port (prePath). // This also means messages are grouped for a single origin. - if (aScriptError.category && aScriptError.category == "SHA-1 Signature") { - let sourceURI = Services.io.newURI(aScriptError.sourceName, null, null).QueryInterface(Ci.nsIURL); + if (scriptError.category && scriptError.category == "SHA-1 Signature") { + let sourceURI = Services.io.newURI(scriptError.sourceName, null, null).QueryInterface(Ci.nsIURL); displayOrigin = sourceURI.prePath; } @@ -1525,14 +1527,14 @@ WebConsoleFrame.prototype = { let msg = new Messages.Simple(errorMessage, { location: { url: displayOrigin, - line: aScriptError.lineNumber, - column: aScriptError.columnNumber + line: scriptError.lineNumber, + column: scriptError.columnNumber }, - stack: aScriptError.stacktrace, + stack: scriptError.stacktrace, category: category, severity: severity, - timestamp: aScriptError.timeStamp, - private: aScriptError.private, + timestamp: scriptError.timeStamp, + private: scriptError.private, filterDuplicates: true }); @@ -1541,7 +1543,7 @@ WebConsoleFrame.prototype = { // Select the body of the message node that is displayed in the console let msgBody = node.getElementsByClassName("message-body")[0]; // Add the more info link node to messages that belong to certain categories - this.addMoreInfoLink(msgBody, aScriptError); + this.addMoreInfoLink(msgBody, scriptError); if (objectActors.size > 0) { node._objectActors = objectActors; @@ -1554,26 +1556,26 @@ WebConsoleFrame.prototype = { * Handle PageError objects received from the server. This method outputs the * given error. * - * @param nsIScriptError aPageError + * @param nsIScriptError pageError * The error received from the server. */ - handlePageError: function WCF_handlePageError(aPageError) + handlePageError: function WCF_handlePageError(pageError) { - let category = Utils.categoryForScriptError(aPageError); - this.outputMessage(category, this.reportPageError, [category, aPageError]); + let category = Utils.categoryForScriptError(pageError); + this.outputMessage(category, this.reportPageError, [category, pageError]); }, /** * Handle log messages received from the server. This method outputs the given * message. * - * @param object aPacket + * @param object packet * The message packet received from the server. */ - handleLogMessage: function WCF_handleLogMessage(aPacket) + handleLogMessage: function WCF_handleLogMessage(packet) { - if (aPacket.message) { - this.outputMessage(CATEGORY_JS, this._reportLogMessage, [aPacket]); + if (packet.message) { + this.outputMessage(CATEGORY_JS, this._reportLogMessage, [packet]); } }, @@ -1581,21 +1583,21 @@ WebConsoleFrame.prototype = { * Display log messages received from the server. * * @private - * @param object aPacket + * @param object packet * The message packet received from the server. * @return nsIDOMElement * The message element to render for the given log message. */ - _reportLogMessage: function WCF__reportLogMessage(aPacket) + _reportLogMessage: function WCF__reportLogMessage(packet) { - let msg = aPacket.message; + let msg = packet.message; if (msg.type && msg.type == "longString") { msg = msg.initial; } let node = this.createMessageNode(CATEGORY_JS, SEVERITY_LOG, msg, null, - null, null, null, aPacket.timeStamp); - if (WebConsoleUtils.isActorGrip(aPacket.message)) { - node._objectActors = new Set([aPacket.message.actor]); + null, null, null, packet.timeStamp); + if (WebConsoleUtils.isActorGrip(packet.message)) { + node._objectActors = new Set([packet.message.actor]); } return node; }, @@ -1688,10 +1690,10 @@ WebConsoleFrame.prototype = { /** * Create a mixed content warning Node. * - * @param aLinkNode + * @param linkNode * Parent to the requested urlNode. */ - makeMixedContentNode: function WCF_makeMixedContentNode(aLinkNode) + makeMixedContentNode: function WCF_makeMixedContentNode(linkNode) { let mixedContentWarning = "[" + l10n.getStr("webConsoleMixedContentWarning") + "]"; @@ -1703,10 +1705,10 @@ WebConsoleFrame.prototype = { mixedContentWarningNode.textContent = mixedContentWarning; mixedContentWarningNode.draggable = false; - aLinkNode.appendChild(mixedContentWarningNode); + linkNode.appendChild(mixedContentWarningNode); - this._addMessageLinkCallback(mixedContentWarningNode, (aEvent) => { - aEvent.stopPropagation(); + this._addMessageLinkCallback(mixedContentWarningNode, (event) => { + event.stopPropagation(); this.owner.openLink(MIXED_CONTENT_LEARN_MORE); }); }, @@ -1715,15 +1717,15 @@ WebConsoleFrame.prototype = { * Adds a more info link node to messages based on the nsIScriptError object * that we need to report to the console * - * @param aNode + * @param node * The node to which we will be adding the more info link node - * @param aScriptError + * @param scriptError * The script error object that we are reporting to the console */ - addMoreInfoLink: function WCF_addMoreInfoLink(aNode, aScriptError) + addMoreInfoLink: function WCF_addMoreInfoLink(node, scriptError) { let url; - switch (aScriptError.category) { + switch (scriptError.category) { case "Insecure Password Field": url = INSECURE_PASSWORDS_LEARN_MORE; break; @@ -1748,7 +1750,7 @@ WebConsoleFrame.prototype = { return; } - this.addLearnMoreWarningNode(aNode, url); + this.addLearnMoreWarningNode(node, url); }, /* @@ -1756,55 +1758,55 @@ WebConsoleFrame.prototype = { * as a parameter to the function. When a user clicks on the appended * warning node, the browser navigates to the provided url. * - * @param aNode + * @param node * The node to which we will be adding a clickable warning node. - * @param aURL + * @param url * The url which points to the page where the user can learn more * about security issues associated with the specific message that's * being logged. */ addLearnMoreWarningNode: - function WCF_addLearnMoreWarningNode(aNode, aURL) + function WCF_addLearnMoreWarningNode(node, url) { let moreInfoLabel = "[" + l10n.getStr("webConsoleMoreInfoLabel") + "]"; let warningNode = this.document.createElementNS(XHTML_NS, "a"); - warningNode.title = aURL; - warningNode.href = aURL; + warningNode.title = url; + warningNode.href = url; warningNode.draggable = false; warningNode.textContent = moreInfoLabel; warningNode.className = "learn-more-link"; - this._addMessageLinkCallback(warningNode, (aEvent) => { - aEvent.stopPropagation(); - this.owner.openLink(aURL); + this._addMessageLinkCallback(warningNode, (event) => { + event.stopPropagation(); + this.owner.openLink(url); }); - aNode.appendChild(warningNode); + node.appendChild(warningNode); }, /** * Log file activity. * - * @param string aFileURI + * @param string fileURI * The file URI that was loaded. * @return nsIDOMElement|undefined * The message element to display in the Web Console output. */ - logFileActivity: function WCF_logFileActivity(aFileURI) + logFileActivity: function WCF_logFileActivity(fileURI) { let urlNode = this.document.createElementNS(XHTML_NS, "a"); - urlNode.setAttribute("title", aFileURI); + urlNode.setAttribute("title", fileURI); urlNode.className = "url"; - urlNode.textContent = aFileURI; + urlNode.textContent = fileURI; urlNode.draggable = false; - urlNode.href = aFileURI; + urlNode.href = fileURI; let outputNode = this.createMessageNode(CATEGORY_NETWORK, SEVERITY_LOG, - urlNode, null, null, aFileURI); + urlNode, null, null, fileURI); this._addMessageLinkCallback(urlNode, () => { - this.owner.viewSource(aFileURI); + this.owner.viewSource(fileURI); }); return outputNode; @@ -1813,23 +1815,23 @@ WebConsoleFrame.prototype = { /** * Handle the file activity messages coming from the remote Web Console. * - * @param string aFileURI + * @param string fileURI * The file URI that was requested. */ - handleFileActivity: function WCF_handleFileActivity(aFileURI) + handleFileActivity: function WCF_handleFileActivity(fileURI) { - this.outputMessage(CATEGORY_NETWORK, this.logFileActivity, [aFileURI]); + this.outputMessage(CATEGORY_NETWORK, this.logFileActivity, [fileURI]); }, /** * Handle the reflow activity messages coming from the remote Web Console. * - * @param object aMessage + * @param object msg * An object holding information about a reflow batch. */ - logReflowActivity: function WCF_logReflowActivity(aMessage) + logReflowActivity: function WCF_logReflowActivity(message) { - let {start, end, sourceURL, sourceLine} = aMessage; + let {start, end, sourceURL, sourceLine} = message; let duration = Math.round((end - start) * 100) / 100; let node = this.document.createElementNS(XHTML_NS, "span"); if (sourceURL) { @@ -1838,7 +1840,7 @@ WebConsoleFrame.prototype = { a.href = "#"; a.draggable = "false"; let filename = WebConsoleUtils.abbreviateSourceURL(sourceURL); - let functionName = aMessage.functionName || l10n.getStr("stacktrace.anonymousFunction"); + let functionName = message.functionName || l10n.getStr("stacktrace.anonymousFunction"); a.textContent = l10n.getFormatStr("reflow.messageLinkText", [functionName, filename, sourceLine]); this._addMessageLinkCallback(a, () => { @@ -1852,9 +1854,9 @@ WebConsoleFrame.prototype = { }, - handleReflowActivity: function WCF_handleReflowActivity(aMessage) + handleReflowActivity: function WCF_handleReflowActivity(message) { - this.outputMessage(CATEGORY_CSS, this.logReflowActivity, [aMessage]); + this.outputMessage(CATEGORY_CSS, this.logReflowActivity, [message]); }, /** @@ -1911,14 +1913,14 @@ WebConsoleFrame.prototype = { * given a network event actor ID. * * @private - * @param string aActorId + * @param string actorId * The network event actor ID for which you want to update the message. * @return boolean * |true| if the message node was updated, or |false| otherwise. */ - _updateNetMessage: function WCF__updateNetMessage(aActorId) + _updateNetMessage: function WCF__updateNetMessage(actorId) { - let networkInfo = this.webConsoleClient.getNetworkRequest(aActorId); + let networkInfo = this.webConsoleClient.getNetworkRequest(actorId); if (!networkInfo || !networkInfo.node) { return; } @@ -1985,32 +1987,32 @@ WebConsoleFrame.prototype = { /** * Handler for page location changes. * - * @param string aURI + * @param string uri * New page location. - * @param string aTitle + * @param string title * New page title. */ - onLocationChange: function WCF_onLocationChange(aURI, aTitle) + onLocationChange: function WCF_onLocationChange(uri, title) { - this.contentLocation = aURI; + this.contentLocation = uri; if (this.owner.onLocationChange) { - this.owner.onLocationChange(aURI, aTitle); + this.owner.onLocationChange(uri, title); } }, /** * Handler for the tabNavigated notification. * - * @param string aEvent + * @param string event * Event name. - * @param object aPacket + * @param object packet * Notification packet received from the server. */ - handleTabNavigated: function WCF_handleTabNavigated(aEvent, aPacket) + handleTabNavigated: function WCF_handleTabNavigated(event, packet) { - if (aEvent == "will-navigate") { + if (event == "will-navigate") { if (this.persistLog) { - let marker = new Messages.NavigationMarker(aPacket, Date.now()); + let marker = new Messages.NavigationMarker(packet, Date.now()); this.output.addMessage(marker); } else { @@ -2018,11 +2020,11 @@ WebConsoleFrame.prototype = { } } - if (aPacket.url) { - this.onLocationChange(aPacket.url, aPacket.title); + if (packet.url) { + this.onLocationChange(packet.url, packet.title); } - if (aEvent == "navigate" && !aPacket.nativeConsoleAPI) { + if (event == "navigate" && !packet.nativeConsoleAPI) { this.logWarningAboutReplacedAPI(); } }, @@ -2034,20 +2036,20 @@ WebConsoleFrame.prototype = { * Note: this call is async - the given message node may not be displayed when * you call this method. * - * @param integer aCategory + * @param integer category * The category of the message you want to output. See the CATEGORY_* * constants. - * @param function|nsIDOMElement aMethodOrNode + * @param function|nsIDOMElement methodOrNode * The method that creates the message element to send to the output or * the actual element. If a method is given it will be bound to the HUD - * object and the arguments will be |aArguments|. - * @param array [aArguments] + * object and the arguments will be |args|. + * @param array [args] * If a method is given to output the message element then the method * will be invoked with the list of arguments given here. The last * object in this array should be the packet received from the * back end. */ - outputMessage: function WCF_outputMessage(aCategory, aMethodOrNode, aArguments) + outputMessage: function WCF_outputMessage(category, methodOrNode, args) { if (!this._outputQueue.length) { // If the queue is empty we consider that now was the last output flush. @@ -2055,7 +2057,7 @@ WebConsoleFrame.prototype = { this._lastOutputFlush = Date.now(); } - this._outputQueue.push([aCategory, aMethodOrNode, aArguments]); + this._outputQueue.push([category, methodOrNode, args]); this._initOutputTimer(); }, @@ -2146,8 +2148,8 @@ WebConsoleFrame.prototype = { } let categories = Object.keys(this._pruneCategoriesQueue); - categories.forEach(function _pruneOutput(aCategory) { - removedNodes += this.pruneOutputIfNecessary(aCategory); + categories.forEach(function _pruneOutput(category) { + removedNodes += this.pruneOutputIfNecessary(category); }, this); this._pruneCategoriesQueue = {}; } @@ -2211,9 +2213,9 @@ WebConsoleFrame.prototype = { * Output a message from the queue. * * @private - * @param nsISupportsString aHudIdSupportsString + * @param nsISupportsString hudIdSupportsString * The HUD ID as an nsISupportsString. - * @param array aItem + * @param array item * An item from the output queue - this item represents a message. * @return object * An object that holds the following properties: @@ -2223,9 +2225,9 @@ WebConsoleFrame.prototype = { * - visible: boolean that tells if the message is visible. */ _outputMessageFromQueue: - function WCF__outputMessageFromQueue(aHudIdSupportsString, aItem) + function WCF__outputMessageFromQueue(hudIdSupportsString, item) { - let [category, methodOrNode, args] = aItem; + let [category, methodOrNode, args] = item; // The last object in the args array should be message // object or response packet received from the server. @@ -2254,7 +2256,7 @@ WebConsoleFrame.prototype = { this._pruneCategoriesQueue[node.category] = true; let nodeID = node.getAttribute("id"); - Services.obs.notifyObservers(aHudIdSupportsString, + Services.obs.notifyObservers(hudIdSupportsString, "web-console-message-created", nodeID); } @@ -2282,12 +2284,12 @@ WebConsoleFrame.prototype = { let nodes = {}; // Group the messages per category. - this._outputQueue.forEach(function(aItem, aIndex) { - let [category] = aItem; + this._outputQueue.forEach(function(item, index) { + let [category] = item; if (!(category in nodes)) { nodes[category] = []; } - nodes[category].push(aIndex); + nodes[category].push(index); }, this); let pruned = 0; @@ -2314,15 +2316,15 @@ WebConsoleFrame.prototype = { * after all. * * @private - * @param array aItem + * @param array item * The item you want to destroy. Does not remove it from the output * queue. */ - _destroyItem: function WCF__destroyItem(aItem) + _destroyItem: function WCF__destroyItem(item) { // TODO: handle object releasing in a more elegant way once all console // messages use the new API - bug 778766. - let [category, methodOrNode, args] = aItem; + let [category, methodOrNode, args] = item; if (typeof methodOrNode != "function" && methodOrNode._objectActors) { for (let actor of methodOrNode._objectActors) { this._releaseObject(actor); @@ -2358,9 +2360,9 @@ WebConsoleFrame.prototype = { } else if (category == CATEGORY_WEBDEV && methodOrNode == this.logConsoleAPIMessage) { - args[0].arguments.forEach((aValue) => { - if (WebConsoleUtils.isActorGrip(aValue)) { - this._releaseObject(aValue.actor); + args[0].arguments.forEach((value) => { + if (WebConsoleUtils.isActorGrip(value)) { + this._releaseObject(value.actor); } }); } @@ -2383,19 +2385,19 @@ WebConsoleFrame.prototype = { }, /** - * Ensures that the number of message nodes of type aCategory don't exceed that + * Ensures that the number of message nodes of type category don't exceed that * category's line limit by removing old messages as needed. * - * @param integer aCategory + * @param integer category * The category of message nodes to prune if needed. * @return number * The number of removed nodes. */ - pruneOutputIfNecessary: function WCF_pruneOutputIfNecessary(aCategory) + pruneOutputIfNecessary: function WCF_pruneOutputIfNecessary(category) { - let logLimit = Utils.logLimitForCategory(aCategory); + let logLimit = Utils.logLimitForCategory(category); let messageNodes = this.outputNode.querySelectorAll(".message[category=" + - CATEGORY_CLASS_FRAGMENTS[aCategory] + "]"); + CATEGORY_CLASS_FRAGMENTS[category] + "]"); let n = Math.max(0, messageNodes.length - logLimit); [...messageNodes].slice(0, n).forEach(this.removeOutputMessage, this); return n; @@ -2404,67 +2406,67 @@ WebConsoleFrame.prototype = { /** * Remove a given message from the output. * - * @param nsIDOMNode aNode + * @param nsIDOMNode node * The message node you want to remove. */ - removeOutputMessage: function WCF_removeOutputMessage(aNode) + removeOutputMessage: function WCF_removeOutputMessage(node) { - if (aNode._messageObject) { - aNode._messageObject.destroy(); + if (node._messageObject) { + node._messageObject.destroy(); } - if (aNode._objectActors) { - for (let actor of aNode._objectActors) { + if (node._objectActors) { + for (let actor of node._objectActors) { this._releaseObject(actor); } - aNode._objectActors.clear(); + node._objectActors.clear(); } - if (aNode.category == CATEGORY_CSS || - aNode.category == CATEGORY_SECURITY) { - let repeatNode = aNode.getElementsByClassName("message-repeats")[0]; + if (node.category == CATEGORY_CSS || + node.category == CATEGORY_SECURITY) { + let repeatNode = node.getElementsByClassName("message-repeats")[0]; if (repeatNode && repeatNode._uid) { delete this._repeatNodes[repeatNode._uid]; } } - else if (aNode._connectionId && - aNode.category == CATEGORY_NETWORK) { - this.webConsoleClient.removeNetworkRequest(aNode._connectionId); - this._releaseObject(aNode._connectionId); + else if (node._connectionId && + node.category == CATEGORY_NETWORK) { + this.webConsoleClient.removeNetworkRequest(node._connectionId); + this._releaseObject(node._connectionId); } - else if (aNode.classList.contains("inlined-variables-view")) { - let view = aNode._variablesView; + else if (node.classList.contains("inlined-variables-view")) { + let view = node._variablesView; if (view) { view.controller.releaseActors(); } - aNode._variablesView = null; + node._variablesView = null; } - aNode.remove(); + node.remove(); }, /** * Given a category and message body, creates a DOM node to represent an * incoming message. The timestamp is automatically added. * - * @param number aCategory + * @param number category * The category of the message: one of the CATEGORY_* constants. - * @param number aSeverity + * @param number severity * The severity of the message: one of the SEVERITY_* constants; - * @param string|nsIDOMNode aBody + * @param string|nsIDOMNode body * The body of the message, either a simple string or a DOM node. - * @param string aSourceURL [optional] + * @param string sourceURL [optional] * The URL of the source file that emitted the error. - * @param number aSourceLine [optional] + * @param number sourceLine [optional] * The line number on which the error occurred. If zero or omitted, * there is no line number associated with this message. - * @param string aClipboardText [optional] + * @param string clipboardText [optional] * The text that should be copied to the clipboard when this node is - * copied. If omitted, defaults to the body text. If `aBody` is not + * copied. If omitted, defaults to the body text. If `body` is not * a string, then the clipboard text must be supplied. - * @param number aLevel [optional] + * @param number level [optional] * The level of the console API message. - * @param number aTimeStamp [optional] + * @param number timestamp [optional] * The timestamp to use for this message node. If omitted, the current * date and time is used. * @return nsIDOMNode @@ -2472,11 +2474,11 @@ WebConsoleFrame.prototype = { * output node. */ createMessageNode: - function WCF_createMessageNode(aCategory, aSeverity, aBody, aSourceURL, - aSourceLine, aClipboardText, aLevel, aTimeStamp) + function WCF_createMessageNode(category, severity, body, sourceURL, + sourceLine, clipboardText, level, timestamp) { - if (typeof aBody != "string" && aClipboardText == null && aBody.innerText) { - aClipboardText = aBody.innerText; + if (typeof body != "string" && clipboardText == null && body.innerText) { + clipboardText = body.innerText; } let indentNode = this.document.createElementNS(XHTML_NS, "span"); @@ -2497,53 +2499,53 @@ WebConsoleFrame.prototype = { bodyNode.className = "message-body-wrapper message-body devtools-monospace"; // Store the body text, since it is needed later for the variables view. - let body = aBody; + let storedBody = body; // If a string was supplied for the body, turn it into a DOM node and an // associated clipboard string now. - aClipboardText = aClipboardText || - (aBody + (aSourceURL ? " @ " + aSourceURL : "") + - (aSourceLine ? ":" + aSourceLine : "")); + clipboardText = clipboardText || + (body + (sourceURL ? " @ " + sourceURL : "") + + (sourceLine ? ":" + sourceLine : "")); - let timestamp = aTimeStamp || Date.now(); + timestamp = timestamp || Date.now(); // Create the containing node and append all its elements to it. let node = this.document.createElementNS(XHTML_NS, "div"); node.id = "console-msg-" + gSequenceId(); node.className = "message"; - node.clipboardText = aClipboardText; + node.clipboardText = clipboardText; node.timestamp = timestamp; - this.setMessageType(node, aCategory, aSeverity); + this.setMessageType(node, category, severity); - if (aBody instanceof Ci.nsIDOMNode) { - bodyNode.appendChild(aBody); + if (body instanceof Ci.nsIDOMNode) { + bodyNode.appendChild(body); } else { let str = undefined; - if (aLevel == "dir") { - str = VariablesView.getString(aBody.arguments[0]); + if (level == "dir") { + str = VariablesView.getString(body.arguments[0]); } else { - str = aBody; + str = body; } if (str !== undefined) { - aBody = this.document.createTextNode(str); - bodyNode.appendChild(aBody); + body = this.document.createTextNode(str); + bodyNode.appendChild(body); } } // Add the message repeats node only when needed. let repeatNode = null; - if (aCategory != CATEGORY_INPUT && - aCategory != CATEGORY_OUTPUT && - aCategory != CATEGORY_NETWORK && - !(aCategory == CATEGORY_CSS && aSeverity == SEVERITY_LOG)) { + if (category != CATEGORY_INPUT && + category != CATEGORY_OUTPUT && + category != CATEGORY_NETWORK && + !(category == CATEGORY_CSS && severity == SEVERITY_LOG)) { repeatNode = this.document.createElementNS(XHTML_NS, "span"); repeatNode.setAttribute("value", "1"); repeatNode.className = "message-repeats"; repeatNode.textContent = 1; - repeatNode._uid = [bodyNode.textContent, aCategory, aSeverity, aLevel, - aSourceURL, aSourceLine].join(":"); + repeatNode._uid = [bodyNode.textContent, category, severity, level, + sourceURL, sourceLine].join(":"); } // Create the timestamp. @@ -2556,9 +2558,9 @@ WebConsoleFrame.prototype = { // Create the source location (e.g. www.example.com:6) that sits on the // right side of the message, if applicable. let locationNode; - if (aSourceURL && IGNORED_SOURCE_URLS.indexOf(aSourceURL) == -1) { - locationNode = this.createLocationNode({url: aSourceURL, - line: aSourceLine}); + if (sourceURL && IGNORED_SOURCE_URLS.indexOf(sourceURL) == -1) { + locationNode = this.createLocationNode({url: sourceURL, + line: sourceLine}); } node.appendChild(timestampNode); @@ -2566,14 +2568,14 @@ WebConsoleFrame.prototype = { node.appendChild(iconContainer); // Display the variables view after the message node. - if (aLevel == "dir") { + if (level == "dir") { let options = { - objectActor: body.arguments[0], + objectActor: storedBody.arguments[0], targetElement: bodyNode, hideFilterInput: true, }; - this.jsterm.openVariablesView(options).then((aView) => { - node._variablesView = aView; + this.jsterm.openVariablesView(options).then((view) => { + node._variablesView = view; if (node.classList.contains("hidden-message")) { node.classList.remove("hidden-message"); } @@ -2600,14 +2602,14 @@ WebConsoleFrame.prototype = { * * @param object aLocation * An object containing url, line and column number of the message source (destructured). - * @param string aTarget [optional] + * @param string target [optional] * Tells which tool to open the link with, on click. Supported tools: * jsdebugger, styleeditor, scratchpad. * @return nsIDOMNode * The new anchor element, ready to be added to the message node. */ createLocationNode: - function WCF_createLocationNode({url, line, column}, aTarget) + function WCF_createLocationNode({url, line, column}, target) { if (!url) { url = ""; @@ -2637,8 +2639,8 @@ WebConsoleFrame.prototype = { locationNode.href = isScratchpad || !fullURL ? "#" : fullURL; locationNode.draggable = false; - if (aTarget) { - locationNode.target = aTarget; + if (target) { + locationNode.target = target; } locationNode.setAttribute("title", url); locationNode.className = "message-location theme-link devtools-monospace"; @@ -2682,57 +2684,57 @@ WebConsoleFrame.prototype = { /** * Adjusts the category and severity of the given message. * - * @param nsIDOMNode aMessageNode + * @param nsIDOMNode messageNode * The message node to alter. - * @param number aCategory + * @param number category * The category for the message; one of the CATEGORY_ constants. - * @param number aSeverity + * @param number severity * The severity for the message; one of the SEVERITY_ constants. * @return void */ setMessageType: - function WCF_setMessageType(aMessageNode, aCategory, aSeverity) + function WCF_setMessageType(messageNode, category, severity) { - aMessageNode.category = aCategory; - aMessageNode.severity = aSeverity; - aMessageNode.setAttribute("category", CATEGORY_CLASS_FRAGMENTS[aCategory]); - aMessageNode.setAttribute("severity", SEVERITY_CLASS_FRAGMENTS[aSeverity]); - aMessageNode.setAttribute("filter", MESSAGE_PREFERENCE_KEYS[aCategory][aSeverity]); + messageNode.category = category; + messageNode.severity = severity; + messageNode.setAttribute("category", CATEGORY_CLASS_FRAGMENTS[category]); + messageNode.setAttribute("severity", SEVERITY_CLASS_FRAGMENTS[severity]); + messageNode.setAttribute("filter", MESSAGE_PREFERENCE_KEYS[category][severity]); }, /** * Add the mouse event handlers needed to make a link. * * @private - * @param nsIDOMNode aNode + * @param nsIDOMNode node * The node for which you want to add the event handlers. - * @param function aCallback + * @param function callback * The function you want to invoke on click. */ - _addMessageLinkCallback: function WCF__addMessageLinkCallback(aNode, aCallback) + _addMessageLinkCallback: function WCF__addMessageLinkCallback(node, callback) { - aNode.addEventListener("mousedown", (aEvent) => { + node.addEventListener("mousedown", (event) => { this._mousedown = true; - this._startX = aEvent.clientX; - this._startY = aEvent.clientY; + this._startX = event.clientX; + this._startY = event.clientY; }, false); - aNode.addEventListener("click", (aEvent) => { + node.addEventListener("click", (event) => { let mousedown = this._mousedown; this._mousedown = false; - aEvent.preventDefault(); + event.preventDefault(); // Do not allow middle/right-click or 2+ clicks. - if (aEvent.detail != 1 || aEvent.button != 0) { + if (event.detail != 1 || event.button != 0) { return; } // If this event started with a mousedown event and it ends at a different // location, we consider this text selection. if (mousedown && - (this._startX != aEvent.clientX) && - (this._startY != aEvent.clientY)) + (this._startX != event.clientX) && + (this._startY != event.clientY)) { this._startX = this._startY = undefined; return; @@ -2740,24 +2742,24 @@ WebConsoleFrame.prototype = { this._startX = this._startY = undefined; - aCallback.call(this, aEvent); + callback.call(this, event); }, false); }, - _addFocusCallback: function WCF__addFocusCallback(aNode, aCallback) + _addFocusCallback: function WCF__addFocusCallback(node, callback) { - aNode.addEventListener("mousedown", (aEvent) => { + node.addEventListener("mousedown", (event) => { this._mousedown = true; - this._startX = aEvent.clientX; - this._startY = aEvent.clientY; + this._startX = event.clientX; + this._startY = event.clientY; }, false); - aNode.addEventListener("click", (aEvent) => { + node.addEventListener("click", (event) => { let mousedown = this._mousedown; this._mousedown = false; // Do not allow middle/right-click or 2+ clicks. - if (aEvent.detail != 1 || aEvent.button != 0) { + if (event.detail != 1 || event.button != 0) { return; } @@ -2766,8 +2768,8 @@ WebConsoleFrame.prototype = { // Add a fuzz modifier of two pixels in any direction to account for sloppy // clicking. if (mousedown && - (Math.abs(aEvent.clientX - this._startX) >= 2) && - (Math.abs(aEvent.clientY - this._startY) >= 1)) + (Math.abs(event.clientX - this._startX) >= 2) && + (Math.abs(event.clientY - this._startY) >= 1)) { this._startX = this._startY = undefined; return; @@ -2775,7 +2777,7 @@ WebConsoleFrame.prototype = { this._startX = this._startY = undefined; - aCallback.call(this, aEvent); + callback.call(this, event); }, false); }, @@ -2784,16 +2786,16 @@ WebConsoleFrame.prototype = { * Currently this function only handles the timestamps preferences. * * @private - * @param object aEvent + * @param object event * This parameter is a string that holds the event name * pref-changed in this case. - * @param object aData + * @param object data * This is the pref-changed data object. */ - _onToolboxPrefChanged: function WCF__onToolboxPrefChanged(aEvent, aData) + _onToolboxPrefChanged: function WCF__onToolboxPrefChanged(event, data) { - if (aData.pref == PREF_MESSAGE_TIMESTAMP) { - if (aData.newValue) { + if (data.pref == PREF_MESSAGE_TIMESTAMP) { + if (data.newValue) { this.outputNode.classList.remove("hideTimestamps"); } else { @@ -2805,7 +2807,7 @@ WebConsoleFrame.prototype = { /** * Copies the selected items to the system clipboard. * - * @param object aOptions + * @param object options * - linkOnly: * An optional flag to copy only URL without timestamp and * other meta-information. Default is false. @@ -2813,15 +2815,15 @@ WebConsoleFrame.prototype = { * An optional flag to copy the last clicked item which brought * up the context menu if nothing is selected. Default is false. */ - copySelectedItems: function WCF_copySelectedItems(aOptions) + copySelectedItems: function WCF_copySelectedItems(options) { - aOptions = aOptions || { linkOnly: false, contextmenu: false }; + options = options || { linkOnly: false, contextmenu: false }; // Gather up the selected items and concatenate their clipboard text. let strings = []; let children = this.output.getSelectedMessages(); - if (!children.length && aOptions.contextmenu) { + if (!children.length && options.contextmenu) { children = [this._contextMenuHandler.lastClickedMessage]; } @@ -2830,7 +2832,7 @@ WebConsoleFrame.prototype = { if (!item.classList.contains("filtered-by-type") && !item.classList.contains("filtered-by-string")) { let timestampString = l10n.timestampString(item.timestamp); - if (aOptions.linkOnly) { + if (options.linkOnly) { strings.push(item.url); } else { @@ -2846,22 +2848,22 @@ WebConsoleFrame.prototype = { * Object properties provider. This function gives you the properties of the * remote object you want. * - * @param string aActor + * @param string actor * The object actor ID from which you want the properties. - * @param function aCallback + * @param function callback * Function you want invoked once the properties are received. */ objectPropertiesProvider: - function WCF_objectPropertiesProvider(aActor, aCallback) + function WCF_objectPropertiesProvider(actor, callback) { - this.webConsoleClient.inspectObjectProperties(aActor, - function(aResponse) { - if (aResponse.error) { + this.webConsoleClient.inspectObjectProperties(actor, + function(response) { + if (response.error) { Cu.reportError("Failed to retrieve the object properties from the " + - "server. Error: " + aResponse.error); + "server. Error: " + response.error); return; } - aCallback(aResponse.properties); + callback(response.properties); }); }, @@ -2869,13 +2871,13 @@ WebConsoleFrame.prototype = { * Release an actor. * * @private - * @param string aActor + * @param string actor * The actor ID you want to release. */ - _releaseObject: function WCF__releaseObject(aActor) + _releaseObject: function WCF__releaseObject(actor) { if (this.proxy) { - this.proxy.releaseActor(aActor); + this.proxy.releaseActor(actor); } }, @@ -2964,27 +2966,27 @@ WebConsoleFrame.prototype = { /** * @see VariablesView.simpleValueEvalMacro */ -function simpleValueEvalMacro(aItem, aCurrentString) +function simpleValueEvalMacro(item, currentString) { - return VariablesView.simpleValueEvalMacro(aItem, aCurrentString, "_self"); + return VariablesView.simpleValueEvalMacro(item, currentString, "_self"); }; /** * @see VariablesView.overrideValueEvalMacro */ -function overrideValueEvalMacro(aItem, aCurrentString) +function overrideValueEvalMacro(item, currentString) { - return VariablesView.overrideValueEvalMacro(aItem, aCurrentString, "_self"); + return VariablesView.overrideValueEvalMacro(item, currentString, "_self"); }; /** * @see VariablesView.getterOrSetterEvalMacro */ -function getterOrSetterEvalMacro(aItem, aCurrentString) +function getterOrSetterEvalMacro(item, currentString) { - return VariablesView.getterOrSetterEvalMacro(aItem, aCurrentString, "_self"); + return VariablesView.getterOrSetterEvalMacro(item, currentString, "_self"); } @@ -2995,12 +2997,12 @@ function getterOrSetterEvalMacro(aItem, aCurrentString) * with handling command line input, code evaluation and result output. * * @constructor - * @param object aWebConsoleFrame + * @param object webConsoleFrame * The WebConsoleFrame object that owns this JSTerm instance. */ -function JSTerm(aWebConsoleFrame) +function JSTerm(webConsoleFrame) { - this.hud = aWebConsoleFrame; + this.hud = webConsoleFrame; this.hudId = this.hud.hudId; this.inputHistoryCount = Services.prefs.getIntPref(PREF_INPUT_HISTORY_COUNT); @@ -3241,29 +3243,29 @@ JSTerm.prototype = { * The JavaScript evaluation response handler. * * @private - * @param object [aAfterMessage] + * @param object [afterMessage] * Optional message after which the evaluation result will be * inserted. - * @param function [aCallback] + * @param function [callback] * Optional function to invoke when the evaluation result is added to * the output. - * @param object aResponse + * @param object response * The message received from the server. */ _executeResultCallback: - function JST__executeResultCallback(aAfterMessage, aCallback, aResponse) + function JST__executeResultCallback(afterMessage, callback, response) { if (!this.hud) { return; } - if (aResponse.error) { - Cu.reportError("Evaluation error " + aResponse.error + ": " + - aResponse.message); + if (response.error) { + Cu.reportError("Evaluation error " + response.error + ": " + + response.message); return; } - let errorMessage = aResponse.exceptionMessage; - let result = aResponse.result; - let helperResult = aResponse.helperResult; + let errorMessage = response.exceptionMessage; + let result = response.result; + let helperResult = response.helperResult; let helperHasRawOutput = !!(helperResult || {}).rawOutput; if (helperResult && helperResult.type) { @@ -3275,11 +3277,11 @@ JSTerm.prototype = { this.clearHistory(); break; case "inspectObject": - if (aAfterMessage) { - if (!aAfterMessage._objectActors) { - aAfterMessage._objectActors = new Set(); + if (afterMessage) { + if (!afterMessage._objectActors) { + afterMessage._objectActors = new Set(); } - aAfterMessage._objectActors.add(helperResult.object.actor); + afterMessage._objectActors.add(helperResult.object.actor); } this.openVariablesView({ label: VariablesView.getString(helperResult.object, { concise: true }), @@ -3307,17 +3309,17 @@ JSTerm.prototype = { if (!errorMessage && result && typeof result == "object" && result.type == "undefined" && helperResult && !helperHasRawOutput) { - aCallback && aCallback(); + callback && callback(); return; } - let msg = new Messages.JavaScriptEvalOutput(aResponse, errorMessage); + let msg = new Messages.JavaScriptEvalOutput(response, errorMessage); this.hud.output.addMessage(msg); - if (aCallback) { + if (callback) { let oldFlushCallback = this.hud._flushCallback; this.hud._flushCallback = () => { - aCallback(msg.element); + callback(msg.element); if (oldFlushCallback) { oldFlushCallback(); this.hud._flushCallback = oldFlushCallback; @@ -3328,11 +3330,11 @@ JSTerm.prototype = { }; } - msg._afterMessage = aAfterMessage; + msg._afterMessage = afterMessage; msg._objectActors = new Set(); - if (WebConsoleUtils.isActorGrip(aResponse.exception)) { - msg._objectActors.add(aResponse.exception.actor); + if (WebConsoleUtils.isActorGrip(response.exception)) { + msg._objectActors.add(response.exception.actor); } if (WebConsoleUtils.isActorGrip(result)) { @@ -3343,28 +3345,28 @@ JSTerm.prototype = { /** * Execute a string. Execution happens asynchronously in the content process. * - * @param string [aExecuteString] + * @param string [executeString] * The string you want to execute. If this is not provided, the current * user input is used - taken from |this.inputNode.value|. - * @param function [aCallback] + * @param function [callback] * Optional function to invoke when the result is displayed. * This is deprecated - please use the promise return value instead. * @returns Promise * Resolves with the message once the result is displayed. */ - execute: function JST_execute(aExecuteString, aCallback) + execute: function JST_execute(executeString, callback) { let deferred = promise.defer(); - let callback = function(msg) { + let resultCallback = function(msg) { deferred.resolve(msg); - if (aCallback) { - aCallback(msg); + if (callback) { + callback(msg); } } // attempt to execute the content of the inputNode - aExecuteString = aExecuteString || this.inputNode.value; - if (!aExecuteString) { + executeString = executeString || this.inputNode.value; + if (!executeString) { return; } @@ -3374,24 +3376,24 @@ JSTerm.prototype = { selectedNodeActor = inspectorSelection.nodeFront.actorID; } - let message = new Messages.Simple(aExecuteString, { + let message = new Messages.Simple(executeString, { category: "input", severity: "log", }); this.hud.output.addMessage(message); - let onResult = this._executeResultCallback.bind(this, message, callback); + let onResult = this._executeResultCallback.bind(this, message, resultCallback); let options = { frame: this.SELECTED_FRAME, selectedNodeActor: selectedNodeActor, }; - this.requestEvaluation(aExecuteString, options).then(onResult, onResult); + this.requestEvaluation(executeString, options).then(onResult, onResult); // Append a new value in the history of executed code, or overwrite the most // recent entry. The most recent entry may contain the last edited input // value that was not evaluated yet. - this.history[this.historyIndex++] = aExecuteString; + this.history[this.historyIndex++] = executeString; this.historyPlaceHolder = this.history.length; if (this.history.length > this.inputHistoryCount) { @@ -3408,9 +3410,9 @@ JSTerm.prototype = { /** * Request a JavaScript string evaluation from the server. * - * @param string aString + * @param string str * String to execute. - * @param object [aOptions] + * @param object [options] * Options for evaluation: * - bindObjectActor: tells the ObjectActor ID for which you want to do * the evaluation. The Debugger.Object of the OA will be bound to @@ -3429,44 +3431,44 @@ JSTerm.prototype = { * A promise object that is resolved when the server response is * received. */ - requestEvaluation: function JST_requestEvaluation(aString, aOptions = {}) + requestEvaluation: function JST_requestEvaluation(str, options = {}) { let deferred = promise.defer(); - function onResult(aResponse) { - if (!aResponse.error) { - deferred.resolve(aResponse); + function onResult(response) { + if (!response.error) { + deferred.resolve(response); } else { - deferred.reject(aResponse); + deferred.reject(response); } } let frameActor = null; - if ("frame" in aOptions) { - frameActor = this.getFrameActor(aOptions.frame); + if ("frame" in options) { + frameActor = this.getFrameActor(options.frame); } let evalOptions = { - bindObjectActor: aOptions.bindObjectActor, + bindObjectActor: options.bindObjectActor, frameActor: frameActor, - selectedNodeActor: aOptions.selectedNodeActor, - selectedObjectActor: aOptions.selectedObjectActor, + selectedNodeActor: options.selectedNodeActor, + selectedObjectActor: options.selectedObjectActor, }; - this.webConsoleClient.evaluateJSAsync(aString, onResult, evalOptions); + this.webConsoleClient.evaluateJSAsync(str, onResult, evalOptions); return deferred.promise; }, /** * Retrieve the FrameActor ID given a frame depth. * - * @param number aFrame + * @param number frame * Frame depth. * @return string|null * The FrameActor ID for the given frame depth. */ - getFrameActor: function JST_getFrameActor(aFrame) + getFrameActor: function JST_getFrameActor(frame) { let state = this.hud.owner.getDebuggerFrames(); if (!state) { @@ -3474,11 +3476,11 @@ JSTerm.prototype = { } let grip; - if (aFrame == this.SELECTED_FRAME) { + if (frame == this.SELECTED_FRAME) { grip = state.frames[state.selected]; } else { - grip = state.frames[aFrame]; + grip = state.frames[frame]; } return grip ? grip.actor : null; @@ -3487,7 +3489,7 @@ JSTerm.prototype = { /** * Opens a new variables view that allows the inspection of the given object. * - * @param object aOptions + * @param object options * Options for the variables view: * - objectActor: grip of the ObjectActor you want to show in the * variables view. @@ -3505,41 +3507,41 @@ JSTerm.prototype = { * A promise object that is resolved when the variables view has * opened. The new variables view instance is given to the callbacks. */ - openVariablesView: function JST_openVariablesView(aOptions) + openVariablesView: function JST_openVariablesView(options) { - let onContainerReady = (aWindow) => { - let container = aWindow.document.querySelector("#variables"); + let onContainerReady = (window) => { + let container = window.document.querySelector("#variables"); let view = this._variablesView; - if (!view || aOptions.targetElement) { + if (!view || options.targetElement) { let viewOptions = { container: container, - hideFilterInput: aOptions.hideFilterInput, + hideFilterInput: options.hideFilterInput, }; view = this._createVariablesView(viewOptions); - if (!aOptions.targetElement) { + if (!options.targetElement) { this._variablesView = view; - aWindow.addEventListener("keypress", this._onKeypressInVariablesView); + window.addEventListener("keypress", this._onKeypressInVariablesView); } } - aOptions.view = view; - this._updateVariablesView(aOptions); + options.view = view; + this._updateVariablesView(options); - if (!aOptions.targetElement && aOptions.autofocus) { - aWindow.focus(); + if (!options.targetElement && options.autofocus) { + window.focus(); } - this.emit("variablesview-open", view, aOptions); + this.emit("variablesview-open", view, options); return view; }; let openPromise; - if (aOptions.targetElement) { + if (options.targetElement) { let deferred = promise.defer(); openPromise = deferred.promise; - let document = aOptions.targetElement.ownerDocument; + let document = options.targetElement.ownerDocument; let iframe = document.createElementNS(XHTML_NS, "iframe"); - iframe.addEventListener("load", function onIframeLoad(aEvent) { + iframe.addEventListener("load", function onIframeLoad(event) { iframe.removeEventListener("load", onIframeLoad, true); iframe.style.visibility = "visible"; deferred.resolve(iframe.contentWindow); @@ -3548,7 +3550,7 @@ JSTerm.prototype = { iframe.flex = 1; iframe.style.visibility = "hidden"; iframe.setAttribute("src", VARIABLES_VIEW_URL); - aOptions.targetElement.appendChild(iframe); + options.targetElement.appendChild(iframe); } else { if (!this.sidebar) { @@ -3612,28 +3614,28 @@ JSTerm.prototype = { * is used for removing the sidebar when Escape is pressed. * * @private - * @param nsIDOMEvent aEvent + * @param nsIDOMEvent event * The keypress DOM event object. */ - _onKeypressInVariablesView: function JST__onKeypressInVariablesView(aEvent) + _onKeypressInVariablesView: function JST__onKeypressInVariablesView(event) { - let tag = aEvent.target.nodeName; - if (aEvent.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE || aEvent.shiftKey || - aEvent.altKey || aEvent.ctrlKey || aEvent.metaKey || + let tag = event.target.nodeName; + if (event.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE || event.shiftKey || + event.altKey || event.ctrlKey || event.metaKey || ["input", "textarea", "select", "textbox"].indexOf(tag) > -1) { return; } this._sidebarDestroy(); this.inputNode.focus(); - aEvent.stopPropagation(); + event.stopPropagation(); }, /** * Create a variables view instance. * * @private - * @param object aOptions + * @param object options * Options for the new Variables View instance: * - container: the DOM element where the variables view is inserted. * - hideFilterInput: boolean, if true the variables filter input is @@ -3641,27 +3643,27 @@ JSTerm.prototype = { * @return object * The new Variables View instance. */ - _createVariablesView: function JST__createVariablesView(aOptions) + _createVariablesView: function JST__createVariablesView(options) { - let view = new VariablesView(aOptions.container); + let view = new VariablesView(options.container); view.toolbox = gDevTools.getToolbox(this.hud.owner.target); view.searchPlaceholder = l10n.getStr("propertiesFilterPlaceholder"); view.emptyText = l10n.getStr("emptyPropertiesList"); - view.searchEnabled = !aOptions.hideFilterInput; + view.searchEnabled = !options.hideFilterInput; view.lazyEmpty = this._lazyVariablesView; VariablesViewController.attach(view, { - getEnvironmentClient: aGrip => { - return new EnvironmentClient(this.hud.proxy.client, aGrip); + getEnvironmentClient: grip => { + return new EnvironmentClient(this.hud.proxy.client, grip); }, - getObjectClient: aGrip => { - return new ObjectClient(this.hud.proxy.client, aGrip); + getObjectClient: grip => { + return new ObjectClient(this.hud.proxy.client, grip); }, - getLongStringClient: aGrip => { - return this.webConsoleClient.longString(aGrip); + getLongStringClient: grip => { + return this.webConsoleClient.longString(grip); }, - releaseActor: aActor => { - this.hud._releaseObject(aActor); + releaseActor: actor => { + this.hud._releaseObject(actor); }, simpleValueEvalMacro: simpleValueEvalMacro, overrideValueEvalMacro: overrideValueEvalMacro, @@ -3669,8 +3671,8 @@ JSTerm.prototype = { }); // Relay events from the VariablesView. - view.on("fetched", (aEvent, aType, aVar) => { - this.emit("variablesview-fetched", aVar); + view.on("fetched", (event, type, variableObject) => { + this.emit("variablesview-fetched", variableObject); }); return view; @@ -3680,7 +3682,7 @@ JSTerm.prototype = { * Update the variables view. * * @private - * @param object aOptions + * @param object options * Options for updating the variables view: * - view: the view you want to update. * - objectActor: the grip of the new ObjectActor you want to show in @@ -3688,24 +3690,24 @@ JSTerm.prototype = { * - rawObject: the new raw object you want to show. * - label: the new label for the inspected object. */ - _updateVariablesView: function JST__updateVariablesView(aOptions) + _updateVariablesView: function JST__updateVariablesView(options) { - let view = aOptions.view; + let view = options.view; view.empty(); // We need to avoid pruning the object inspection starting point. // That one is pruned when the console message is removed. - view.controller.releaseActors(aActor => { - return view._consoleLastObjectActor != aActor; + view.controller.releaseActors(actor => { + return view._consoleLastObjectActor != actor; }); - if (aOptions.objectActor && + if (options.objectActor && (!this.hud.owner._browserConsole || Services.prefs.getBoolPref("devtools.chrome.enabled"))) { // Make sure eval works in the correct context. - view.eval = this._variablesViewEvaluate.bind(this, aOptions); - view.switch = this._variablesViewSwitch.bind(this, aOptions); - view.delete = this._variablesViewDelete.bind(this, aOptions); + view.eval = this._variablesViewEvaluate.bind(this, options); + view.switch = this._variablesViewSwitch.bind(this, options); + view.delete = this._variablesViewDelete.bind(this, options); } else { view.eval = null; @@ -3713,13 +3715,13 @@ JSTerm.prototype = { view.delete = null; } - let { variable, expanded } = view.controller.setSingleVariable(aOptions); + let { variable, expanded } = view.controller.setSingleVariable(options); variable.evaluationMacro = simpleValueEvalMacro; - if (aOptions.objectActor) { - view._consoleLastObjectActor = aOptions.objectActor.actor; + if (options.objectActor) { + view._consoleLastObjectActor = options.objectActor.actor; } - else if (aOptions.rawObject) { + else if (options.rawObject) { view._consoleLastObjectActor = null; } else { @@ -3728,7 +3730,7 @@ JSTerm.prototype = { } expanded.then(() => { - this.emit("variablesview-updated", view, aOptions); + this.emit("variablesview-updated", view, options); }); }, @@ -3737,23 +3739,23 @@ JSTerm.prototype = { * value. * * @private - * @param object aOptions + * @param object options * The options used for |this._updateVariablesView()|. - * @param object aVar + * @param object variableObject * The Variable object instance for the edited property. - * @param string aValue + * @param string value * The value the edited property was changed to. */ _variablesViewEvaluate: - function JST__variablesViewEvaluate(aOptions, aVar, aValue) + function JST__variablesViewEvaluate(options, variableObject, value) { - let updater = this._updateVariablesView.bind(this, aOptions); + let updater = this._updateVariablesView.bind(this, options); let onEval = this._silentEvalCallback.bind(this, updater); - let string = aVar.evaluationMacro(aVar, aValue); + let string = variableObject.evaluationMacro(variableObject, value); let evalOptions = { frame: this.SELECTED_FRAME, - bindObjectActor: aOptions.objectActor.actor, + bindObjectActor: options.objectActor.actor, }; this.requestEvaluation(string, evalOptions).then(onEval, onEval); @@ -3764,21 +3766,21 @@ JSTerm.prototype = { * is deleted. * * @private - * @param object aOptions + * @param object options * The options used for |this._updateVariablesView()|. - * @param object aVar + * @param object variableObject * The Variable object instance for the deleted property. */ - _variablesViewDelete: function JST__variablesViewDelete(aOptions, aVar) + _variablesViewDelete: function JST__variablesViewDelete(options, variableObject) { let onEval = this._silentEvalCallback.bind(this, null); let evalOptions = { frame: this.SELECTED_FRAME, - bindObjectActor: aOptions.objectActor.actor, + bindObjectActor: options.objectActor.actor, }; - this.requestEvaluation("delete _self" + aVar.symbolicName, evalOptions) + this.requestEvaluation("delete _self" + variableObject.symbolicName, evalOptions) .then(onEval, onEval); }, @@ -3787,31 +3789,31 @@ JSTerm.prototype = { * is renamed. * * @private - * @param object aOptions + * @param object options * The options used for |this._updateVariablesView()|. - * @param object aVar + * @param object variableObject * The Variable object instance for the renamed property. - * @param string aNewName + * @param string newName * The new name for the property. */ _variablesViewSwitch: - function JST__variablesViewSwitch(aOptions, aVar, aNewName) + function JST__variablesViewSwitch(options, variableObject, newName) { - let updater = this._updateVariablesView.bind(this, aOptions); + let updater = this._updateVariablesView.bind(this, options); let onEval = this._silentEvalCallback.bind(this, updater); let evalOptions = { frame: this.SELECTED_FRAME, - bindObjectActor: aOptions.objectActor.actor, + bindObjectActor: options.objectActor.actor, }; - let newSymbolicName = aVar.ownerView.symbolicName + '["' + aNewName + '"]'; - if (newSymbolicName == aVar.symbolicName) { + let newSymbolicName = variableObject.ownerView.symbolicName + '["' + newName + '"]'; + if (newSymbolicName == variableObject.symbolicName) { return; } - let code = "_self" + newSymbolicName + " = _self" + aVar.symbolicName + ";" + - "delete _self" + aVar.symbolicName; + let code = "_self" + newSymbolicName + " = _self" + variableObject.symbolicName + ";" + + "delete _self" + variableObject.symbolicName; this.requestEvaluation(code, evalOptions).then(onEval, onEval); }, @@ -3825,48 +3827,48 @@ JSTerm.prototype = { * Exceptions are displayed in the output. * * @private - * @param function aCallback + * @param function callback * Function to invoke once the response is received. - * @param object aResponse + * @param object response * The response packet received from the server. */ - _silentEvalCallback: function JST__silentEvalCallback(aCallback, aResponse) + _silentEvalCallback: function JST__silentEvalCallback(callback, response) { - if (aResponse.error) { - Cu.reportError("Web Console evaluation failed. " + aResponse.error + ":" + - aResponse.message); + if (response.error) { + Cu.reportError("Web Console evaluation failed. " + response.error + ":" + + response.message); - aCallback && aCallback(aResponse); + callback && callback(response); return; } - if (aResponse.exceptionMessage) { - let message = new Messages.Simple(aResponse.exceptionMessage, { + if (response.exceptionMessage) { + let message = new Messages.Simple(response.exceptionMessage, { category: "output", severity: "error", - timestamp: aResponse.timestamp, + timestamp: response.timestamp, }); this.hud.output.addMessage(message); message._objectActors = new Set(); - if (WebConsoleUtils.isActorGrip(aResponse.exception)) { - message._objectActors.add(aResponse.exception.actor); + if (WebConsoleUtils.isActorGrip(response.exception)) { + message._objectActors.add(response.exception.actor); } } - let helper = aResponse.helperResult || { type: null }; + let helper = response.helperResult || { type: null }; let helperGrip = null; if (helper.type == "inspectObject") { helperGrip = helper.object; } - let grips = [aResponse.result, helperGrip]; + let grips = [response.result, helperGrip]; for (let grip of grips) { if (WebConsoleUtils.isActorGrip(grip)) { this.hud._releaseObject(grip.actor); } } - aCallback && aCallback(aResponse); + callback && callback(response); }, @@ -3875,11 +3877,11 @@ JSTerm.prototype = { * * This method emits the "messages-cleared" notification. * - * @param boolean aClearStorage + * @param boolean clearStorage * True if you want to clear the console messages storage associated to * this Web Console. */ - clearOutput: function JST_clearOutput(aClearStorage) + clearOutput: function JST_clearOutput(clearStorage) { let hud = this.hud; let outputNode = hud.outputNode; @@ -3894,7 +3896,7 @@ JSTerm.prototype = { this.webConsoleClient.clearNetworkRequests(); hud._repeatNodes = {}; - if (aClearStorage) { + if (clearStorage) { this.webConsoleClient.clearMessagesCache(); } @@ -3942,14 +3944,14 @@ JSTerm.prototype = { * fit its contents. This method is preferred over setting "inputNode.value" * directly, because it correctly resizes the field. * - * @param string aNewValue + * @param string newValue * The new value to set. * @returns void */ - setInputValue: function JST_setInputValue(aNewValue) + setInputValue: function JST_setInputValue(newValue) { - this.inputNode.value = aNewValue; - this.lastInputValue = aNewValue; + this.inputNode.value = newValue; + this.lastInputValue = newValue; this.completeNode.value = ""; this.resizeInput(); this._inputChanged = true; @@ -3985,15 +3987,15 @@ JSTerm.prototype = { * The inputNode "keypress" event handler. * * @private - * @param nsIDOMEvent aEvent + * @param nsIDOMEvent event */ - _keyPress: function JST__keyPress(aEvent) + _keyPress: function JST__keyPress(event) { let inputNode = this.inputNode; let inputUpdated = false; - if (aEvent.ctrlKey) { - switch (aEvent.charCode) { + if (event.ctrlKey) { + switch (event.charCode) { case 101: // control-e if (Services.appinfo.OS == "WINNT") { @@ -4011,7 +4013,7 @@ JSTerm.prototype = { } } inputNode.setSelectionRange(lineEndPos, lineEndPos); - aEvent.preventDefault(); + event.preventDefault(); this.clearCompletion(); break; @@ -4022,7 +4024,7 @@ JSTerm.prototype = { if (Services.appinfo.OS == "Darwin" && this.canCaretGoNext() && this.historyPeruse(HISTORY_FORWARD)) { - aEvent.preventDefault(); + event.preventDefault(); // Ctrl-N is also used to focus the Network category button on MacOSX. // The preventDefault() call doesn't prevent the focus from moving // away from the input. @@ -4038,7 +4040,7 @@ JSTerm.prototype = { if (Services.appinfo.OS == "Darwin" && this.canCaretGoPrevious() && this.historyPeruse(HISTORY_BACK)) { - aEvent.preventDefault(); + event.preventDefault(); // Ctrl-P may also be used to focus some category button on MacOSX. // The preventDefault() call doesn't prevent the focus from moving // away from the input. @@ -4051,24 +4053,24 @@ JSTerm.prototype = { } return; } - else if (aEvent.shiftKey && - aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN) { + else if (event.shiftKey && + event.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN) { // shift return // TODO: expand the inputNode height by one line return; } - switch (aEvent.keyCode) { + switch (event.keyCode) { case Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE: if (this.autocompletePopup.isOpen) { this.clearCompletion(); - aEvent.preventDefault(); - aEvent.stopPropagation(); + event.preventDefault(); + event.stopPropagation(); } else if (this.sidebar) { this._sidebarDestroy(); - aEvent.preventDefault(); - aEvent.stopPropagation(); + event.preventDefault(); + event.stopPropagation(); } break; @@ -4082,7 +4084,7 @@ JSTerm.prototype = { this.execute(); this._inputChanged = false; } - aEvent.preventDefault(); + event.preventDefault(); break; case Ci.nsIDOMKeyEvent.DOM_VK_UP: @@ -4096,7 +4098,7 @@ JSTerm.prototype = { inputUpdated = this.historyPeruse(HISTORY_BACK); } if (inputUpdated) { - aEvent.preventDefault(); + event.preventDefault(); } break; @@ -4111,7 +4113,7 @@ JSTerm.prototype = { inputUpdated = this.historyPeruse(HISTORY_FORWARD); } if (inputUpdated) { - aEvent.preventDefault(); + event.preventDefault(); } break; @@ -4129,7 +4131,7 @@ JSTerm.prototype = { this.hud.outputNode.parentNode.clientHeight ); } - aEvent.preventDefault(); + event.preventDefault(); break; case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN: @@ -4146,26 +4148,26 @@ JSTerm.prototype = { this.hud.outputNode.parentNode.clientHeight ); } - aEvent.preventDefault(); + event.preventDefault(); break; case Ci.nsIDOMKeyEvent.DOM_VK_HOME: if (this.autocompletePopup.isOpen) { this.autocompletePopup.selectedIndex = 0; - aEvent.preventDefault(); + event.preventDefault(); } else if (this.inputNode.value.length <= 0) { this.hud.outputNode.parentNode.scrollTop = 0; - aEvent.preventDefault(); + event.preventDefault(); } break; case Ci.nsIDOMKeyEvent.DOM_VK_END: if (this.autocompletePopup.isOpen) { this.autocompletePopup.selectedIndex = this.autocompletePopup.itemCount - 1; - aEvent.preventDefault(); + event.preventDefault(); } else if (this.inputNode.value.length <= 0) { this.hud.outputNode.parentNode.scrollTop = this.hud.outputNode.parentNode.scrollHeight; - aEvent.preventDefault(); + event.preventDefault(); } break; @@ -4187,7 +4189,7 @@ JSTerm.prototype = { this.complete(this.COMPLETE_HINT_ONLY) && this.lastCompletion.value && this.acceptProposedCompletion()) { - aEvent.preventDefault(); + event.preventDefault(); } if (this.autocompletePopup.isOpen) { this.clearCompletion(); @@ -4199,11 +4201,11 @@ JSTerm.prototype = { if (this.complete(this.COMPLETE_HINT_ONLY) && this.lastCompletion && this.acceptProposedCompletion()) { - aEvent.preventDefault(); + event.preventDefault(); } else if (this._inputChanged) { this.updateCompleteNode(l10n.getStr("Autocomplete.blank")); - aEvent.preventDefault(); + event.preventDefault(); } break; default: @@ -4223,20 +4225,20 @@ JSTerm.prototype = { /** * Go up/down the history stack of input values. * - * @param number aDirection + * @param number direction * History navigation direction: HISTORY_BACK or HISTORY_FORWARD. * * @returns boolean * True if the input value changed, false otherwise. */ - historyPeruse: function JST_historyPeruse(aDirection) + historyPeruse: function JST_historyPeruse(direction) { if (!this.history.length) { return false; } // Up Arrow key - if (aDirection == HISTORY_BACK) { + if (direction == HISTORY_BACK) { if (this.historyPlaceHolder <= 0) { return false; } @@ -4253,7 +4255,7 @@ JSTerm.prototype = { this.setInputValue(inputVal); } // Down Arrow key - else if (aDirection == HISTORY_FORWARD) { + else if (direction == HISTORY_FORWARD) { if (this.historyPlaceHolder >= (this.history.length-1)) { return false; } @@ -4326,7 +4328,7 @@ JSTerm.prototype = { * only if the selection/cursor is at the end of the string. If no completion * is found, the current inputNode value and cursor/selection stay. * - * @param int aType possible values are + * @param int type possible values are * - this.COMPLETE_FORWARD: If there is more than one possible completion * and the input value stayed the same compared to the last time this * function was called, then the next completion of all possible @@ -4348,13 +4350,13 @@ JSTerm.prototype = { * used again. If there is only one possible completion, then * the inputNode.value is set to this value and the selection is set * from the current cursor position to the end of the completed text. - * @param function aCallback + * @param function callback * Optional function invoked when the autocomplete properties are * updated. * @returns boolean true if there existed a completion for the current input, * or false otherwise. */ - complete: function JSTF_complete(aType, aCallback) + complete: function JSTF_complete(type, callback) { let inputNode = this.inputNode; let inputValue = inputNode.value; @@ -4363,7 +4365,7 @@ JSTerm.prototype = { // If the inputNode has no value, then don't try to complete on it. if (!inputValue) { this.clearCompletion(); - aCallback && aCallback(this); + callback && callback(this); this.emit("autocomplete-updated"); return false; } @@ -4371,38 +4373,38 @@ JSTerm.prototype = { // Only complete if the selection is empty. if (inputNode.selectionStart != inputNode.selectionEnd) { this.clearCompletion(); - aCallback && aCallback(this); + callback && callback(this); this.emit("autocomplete-updated"); return false; } // Update the completion results. if (this.lastCompletion.value != inputValue || frameActor != this._lastFrameActorId) { - this._updateCompletionResult(aType, aCallback); + this._updateCompletionResult(type, callback); return false; } let popup = this.autocompletePopup; let accepted = false; - if (aType != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) { + if (type != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) { this.acceptProposedCompletion(); accepted = true; } - else if (aType == this.COMPLETE_BACKWARD) { + else if (type == this.COMPLETE_BACKWARD) { popup.selectPreviousItem(); } - else if (aType == this.COMPLETE_FORWARD) { + else if (type == this.COMPLETE_FORWARD) { popup.selectNextItem(); } - else if (aType == this.COMPLETE_PAGEUP) { + else if (type == this.COMPLETE_PAGEUP) { popup.selectPreviousPageItem(); } - else if (aType == this.COMPLETE_PAGEDOWN) { + else if (type == this.COMPLETE_PAGEDOWN) { popup.selectNextPageItem(); } - aCallback && aCallback(this); + callback && callback(this); this.emit("autocomplete-updated"); return accepted || popup.itemCount > 0; }, @@ -4412,13 +4414,13 @@ JSTerm.prototype = { * fetching updated results from the content process. * * @private - * @param int aType + * @param int type * Completion type. See this.complete() for details. - * @param function [aCallback] + * @param function [callback] * Optional, function to invoke when completion results are received. */ _updateCompletionResult: - function JST__updateCompletionResult(aType, aCallback) + function JST__updateCompletionResult(type, callback) { let frameActor = this.getFrameActor(this.SELECTED_FRAME); if (this.lastCompletion.value == this.inputNode.value && frameActor == this._lastFrameActorId) { @@ -4457,12 +4459,12 @@ JSTerm.prototype = { this.lastCompletion = { requestId: null, - completionType: aType, + completionType: type, value: null, }; let response = { matches: newList, matchProp: filterBy }; - this._receiveAutocompleteProperties(null, aCallback, response); + this._receiveAutocompleteProperties(null, callback, response); return; } @@ -4470,14 +4472,14 @@ JSTerm.prototype = { this.lastCompletion = { requestId: requestId, - completionType: aType, + completionType: type, value: null, }; - let callback = this._receiveAutocompleteProperties.bind(this, requestId, - aCallback); + let autocompleteCallback = this._receiveAutocompleteProperties.bind(this, requestId, + callback); - this.webConsoleClient.autocomplete(input, cursor, callback, frameActor); + this.webConsoleClient.autocomplete(input, cursor, autocompleteCallback, frameActor); }, /** @@ -4485,43 +4487,43 @@ JSTerm.prototype = { * the completion result received from the server and updates the UI * accordingly. * - * @param number aRequestId + * @param number requestId * Request ID. - * @param function [aCallback=null] + * @param function [callback=null] * Optional, function to invoke when the completion result is received. - * @param object aMessage + * @param object message * The JSON message which holds the completion results received from * the content process. */ _receiveAutocompleteProperties: - function JST__receiveAutocompleteProperties(aRequestId, aCallback, aMessage) + function JST__receiveAutocompleteProperties(requestId, callback, message) { let inputNode = this.inputNode; let inputValue = inputNode.value; if (this.lastCompletion.value == inputValue || - aRequestId != this.lastCompletion.requestId) { + requestId != this.lastCompletion.requestId) { return; } // Cache whatever came from the server if the last char is alphanumeric or '.' let cursor = inputNode.selectionStart; let inputUntilCursor = inputValue.substring(0, cursor); - if (aRequestId != null && /[a-zA-Z0-9.]$/.test(inputUntilCursor)) { - this._autocompleteCache = aMessage.matches; + if (requestId != null && /[a-zA-Z0-9.]$/.test(inputUntilCursor)) { + this._autocompleteCache = message.matches; this._autocompleteQuery = inputUntilCursor; } - let matches = aMessage.matches; - let lastPart = aMessage.matchProp; + let matches = message.matches; + let lastPart = message.matchProp; if (!matches.length) { this.clearCompletion(); - aCallback && aCallback(this); + callback && callback(this); this.emit("autocomplete-updated"); return; } - let items = matches.reverse().map(function(aMatch) { - return { preLabel: lastPart, label: aMatch }; + let items = matches.reverse().map(function(match) { + return { preLabel: lastPart, label: match }; }); let popup = this.autocompletePopup; @@ -4561,7 +4563,7 @@ JSTerm.prototype = { popup.selectNextItem(); } - aCallback && aCallback(this); + callback && callback(this); this.emit("autocomplete-updated"); }, @@ -4629,14 +4631,14 @@ JSTerm.prototype = { /** * Update the node that displays the currently selected autocomplete proposal. * - * @param string aSuffix + * @param string suffix * The proposed suffix for the inputNode value. */ - updateCompleteNode: function JSTF_updateCompleteNode(aSuffix) + updateCompleteNode: function JSTF_updateCompleteNode(suffix) { // completion prefix = input, with non-control chars replaced by spaces - let prefix = aSuffix ? this.inputNode.value.replace(/[\S]/g, " ") : ""; - this.completeNode.value = prefix + aSuffix; + let prefix = suffix ? this.inputNode.value.replace(/[\S]/g, " ") : ""; + this.completeNode.value = prefix + suffix; }, @@ -4702,28 +4704,28 @@ var Utils = { /** * Scrolls a node so that it's visible in its containing element. * - * @param nsIDOMNode aNode + * @param nsIDOMNode node * The node to make visible. * @returns void */ - scrollToVisible: function Utils_scrollToVisible(aNode) + scrollToVisible: function Utils_scrollToVisible(node) { - aNode.scrollIntoView(false); + node.scrollIntoView(false); }, /** * Check if the given output node is scrolled to the bottom. * - * @param nsIDOMNode aOutputNode + * @param nsIDOMNode outputNode * @return boolean * True if the output node is scrolled to the bottom, or false * otherwise. */ - isOutputScrolledToBottom: function Utils_isOutputScrolledToBottom(aOutputNode) + isOutputScrolledToBottom: function Utils_isOutputScrolledToBottom(outputNode) { - let lastNodeHeight = aOutputNode.lastChild ? - aOutputNode.lastChild.clientHeight : 0; - let scrollNode = aOutputNode.parentNode; + let lastNodeHeight = outputNode.lastChild ? + outputNode.lastChild.clientHeight : 0; + let scrollNode = outputNode.parentNode; return scrollNode.scrollTop + scrollNode.clientHeight >= scrollNode.scrollHeight - lastNodeHeight / 2; }, @@ -4731,15 +4733,15 @@ var Utils = { /** * Determine the category of a given nsIScriptError. * - * @param nsIScriptError aScriptError + * @param nsIScriptError scriptError * The script error you want to determine the category for. * @return CATEGORY_JS|CATEGORY_CSS|CATEGORY_SECURITY * Depending on the script error CATEGORY_JS, CATEGORY_CSS, or * CATEGORY_SECURITY can be returned. */ - categoryForScriptError: function Utils_categoryForScriptError(aScriptError) + categoryForScriptError: function Utils_categoryForScriptError(scriptError) { - let category = aScriptError.category; + let category = scriptError.category; if (/^(?:CSS|Layout)\b/.test(category)) { return CATEGORY_CSS; @@ -4768,18 +4770,18 @@ var Utils = { /** * Retrieve the limit of messages for a specific category. * - * @param number aCategory + * @param number category * The category of messages you want to retrieve the limit for. See the * CATEGORY_* constants. * @return number * The number of messages allowed for the specific category. */ - logLimitForCategory: function Utils_logLimitForCategory(aCategory) + logLimitForCategory: function Utils_logLimitForCategory(category) { let logLimit = DEFAULT_LOG_LIMIT; try { - let prefName = CATEGORY_CLASS_FRAGMENTS[aCategory]; + let prefName = CATEGORY_CLASS_FRAGMENTS[category]; logLimit = Services.prefs.getIntPref("devtools.hud.loglimit." + prefName); logLimit = Math.max(logLimit, 1); } @@ -4797,9 +4799,9 @@ var Utils = { * A controller (an instance of nsIController) that makes editing actions * behave appropriately in the context of the Web Console. */ -function CommandController(aWebConsole) +function CommandController(webConsole) { - this.owner = aWebConsole; + this.owner = webConsole; } CommandController.prototype = { @@ -4832,17 +4834,17 @@ CommandController.prototype = { this.owner.copySelectedItems({ linkOnly: false, contextmenu: true }); }, - supportsCommand: function CommandController_supportsCommand(aCommand) + supportsCommand: function CommandController_supportsCommand(command) { if (!this.owner || !this.owner.output) { return false; } - return this.isCommandEnabled(aCommand); + return this.isCommandEnabled(command); }, - isCommandEnabled: function CommandController_isCommandEnabled(aCommand) + isCommandEnabled: function CommandController_isCommandEnabled(command) { - switch (aCommand) { + switch (command) { case "consoleCmd_openURL": case "consoleCmd_copyURL": { // Only enable URL-related actions if node is Net Activity. @@ -4869,9 +4871,9 @@ CommandController.prototype = { return false; }, - doCommand: function CommandController_doCommand(aCommand) + doCommand: function CommandController_doCommand(command) { - switch (aCommand) { + switch (command) { case "consoleCmd_openURL": this.openURL(); break; @@ -4915,15 +4917,15 @@ CommandController.prototype = { * and the application we connect to through the remote debug protocol. * * @constructor - * @param object aWebConsole - * The Web Console instance that owns this connection proxy. - * @param RemoteTarget aTarget + * @param object webConsoleFrame + * The WebConsoleFrame object that owns this connection proxy. + * @param RemoteTarget target * The target that the console will connect to. */ -function WebConsoleConnectionProxy(aWebConsole, aTarget) +function WebConsoleConnectionProxy(webConsoleFrame, target) { - this.owner = aWebConsole; - this.target = aTarget; + this.webConsoleFrame = webConsoleFrame; + this.target = target; this._onPageError = this._onPageError.bind(this); this._onLogMessage = this._onLogMessage.bind(this); @@ -4942,12 +4944,12 @@ function WebConsoleConnectionProxy(aWebConsole, aTarget) WebConsoleConnectionProxy.prototype = { /** - * The owning Web Console instance. + * The owning Web Console Frame instance. * * @see WebConsoleFrame * @type object */ - owner: null, + webConsoleFrame: null, /** * The target that the console connects to. @@ -5050,7 +5052,7 @@ WebConsoleConnectionProxy.prototype = { this._consoleActor = this.target.form.consoleActor; if (this.target.isTabActor) { let tab = this.target.form; - this.owner.onLocationChange(tab.url, tab.title); + this.webConsoleFrame.onLocationChange(tab.url, tab.title); } this._attachConsole(); @@ -5087,46 +5089,46 @@ WebConsoleConnectionProxy.prototype = { * The "attachConsole" response handler. * * @private - * @param object aResponse + * @param object response * The JSON response object received from the server. - * @param object aWebConsoleClient + * @param object webConsoleClient * The WebConsoleClient instance for the attached console, for the * specific tab we work with. */ - _onAttachConsole: function WCCP__onAttachConsole(aResponse, aWebConsoleClient) + _onAttachConsole: function WCCP__onAttachConsole(response, webConsoleClient) { - if (aResponse.error) { - Cu.reportError("attachConsole failed: " + aResponse.error + " " + - aResponse.message); - this._connectDefer.reject(aResponse); + if (response.error) { + Cu.reportError("attachConsole failed: " + response.error + " " + + response.message); + this._connectDefer.reject(response); return; } - this.webConsoleClient = aWebConsoleClient; + this.webConsoleClient = webConsoleClient; - this._hasNativeConsoleAPI = aResponse.nativeConsoleAPI; + this._hasNativeConsoleAPI = response.nativeConsoleAPI; this.webConsoleClient.on("networkEvent", this._onNetworkEvent); this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate); let msgs = ["PageError", "ConsoleAPI"]; this.webConsoleClient.getCachedMessages(msgs, this._onCachedMessages); - this.owner._onUpdateListeners(); + this.webConsoleFrame._onUpdateListeners(); }, /** * The "cachedMessages" response handler. * * @private - * @param object aResponse + * @param object response * The JSON response object received from the server. */ - _onCachedMessages: function WCCP__onCachedMessages(aResponse) + _onCachedMessages: function WCCP__onCachedMessages(response) { - if (aResponse.error) { - Cu.reportError("Web Console getCachedMessages error: " + aResponse.error + - " " + aResponse.message); - this._connectDefer.reject(aResponse); + if (response.error) { + Cu.reportError("Web Console getCachedMessages error: " + response.error + + " " + response.message); + this._connectDefer.reject(response); return; } @@ -5136,13 +5138,13 @@ WebConsoleConnectionProxy.prototype = { Cu.reportError("Web Console getCachedMessages error: invalid state."); } - let messages = aResponse.messages.concat(...this.webConsoleClient.getNetworkEvents()); + let messages = response.messages.concat(...this.webConsoleClient.getNetworkEvents()); messages.sort((a, b) => a.timeStamp - b.timeStamp); - this.owner.displayCachedMessages(messages); + this.webConsoleFrame.displayCachedMessages(messages); if (!this._hasNativeConsoleAPI) { - this.owner.logWarningAboutReplacedAPI(); + this.webConsoleFrame.logWarningAboutReplacedAPI(); } this.connected = true; @@ -5154,15 +5156,15 @@ WebConsoleConnectionProxy.prototype = { * for displaying. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onPageError: function WCCP__onPageError(aType, aPacket) + _onPageError: function WCCP__onPageError(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handlePageError(aPacket.pageError); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handlePageError(packet.pageError); } }, @@ -5171,15 +5173,15 @@ WebConsoleConnectionProxy.prototype = { * for displaying. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onLogMessage: function WCCP__onLogMessage(aType, aPacket) + _onLogMessage: function WCCP__onLogMessage(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handleLogMessage(aPacket); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handleLogMessage(packet); } }, @@ -5188,15 +5190,15 @@ WebConsoleConnectionProxy.prototype = { * the UI for displaying. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onConsoleAPICall: function WCCP__onConsoleAPICall(aType, aPacket) + _onConsoleAPICall: function WCCP__onConsoleAPICall(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handleConsoleAPICall(aPacket.message); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handleConsoleAPICall(packet.message); } }, @@ -5212,8 +5214,8 @@ WebConsoleConnectionProxy.prototype = { */ _onNetworkEvent: function(type, networkInfo) { - if (this.owner) { - this.owner.handleNetworkEvent(networkInfo); + if (this.webConsoleFrame) { + this.webConsoleFrame.handleNetworkEvent(networkInfo); } }, @@ -5231,8 +5233,8 @@ WebConsoleConnectionProxy.prototype = { */ _onNetworkEventUpdate: function(type, { packet, networkInfo }) { - if (this.owner) { - this.owner.handleNetworkEventUpdate(networkInfo, packet); + if (this.webConsoleFrame) { + this.webConsoleFrame.handleNetworkEventUpdate(networkInfo, packet); } }, @@ -5241,22 +5243,22 @@ WebConsoleConnectionProxy.prototype = { * the UI for displaying. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onFileActivity: function WCCP__onFileActivity(aType, aPacket) + _onFileActivity: function WCCP__onFileActivity(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handleFileActivity(aPacket.uri); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handleFileActivity(packet.uri); } }, - _onReflowActivity: function WCCP__onReflowActivity(aType, aPacket) + _onReflowActivity: function WCCP__onReflowActivity(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handleReflowActivity(aPacket); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handleReflowActivity(packet); } }, @@ -5265,15 +5267,15 @@ WebConsoleConnectionProxy.prototype = { * the UI for displaying. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onServerLogCall: function WCCP__onServerLogCall(aType, aPacket) + _onServerLogCall: function WCCP__onServerLogCall(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.handleConsoleAPICall(aPacket.message); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.handleConsoleAPICall(packet.message); } }, @@ -5282,16 +5284,16 @@ WebConsoleConnectionProxy.prototype = { * received the Web Console UI is cleared. * * @private - * @param string aType + * @param string type * Message type. - * @param object aPacket + * @param object packet * The message received from the server. */ _onLastPrivateContextExited: - function WCCP__onLastPrivateContextExited(aType, aPacket) + function WCCP__onLastPrivateContextExited(type, packet) { - if (this.owner && aPacket.from == this._consoleActor) { - this.owner.jsterm.clearPrivateMessages(); + if (this.webConsoleFrame && packet.from == this._consoleActor) { + this.webConsoleFrame.jsterm.clearPrivateMessages(); } }, @@ -5300,30 +5302,30 @@ WebConsoleConnectionProxy.prototype = { * to the UI for displaying. * * @private - * @param string aEvent + * @param string event * Event type. - * @param object aPacket + * @param object packet * The message received from the server. */ - _onTabNavigated: function WCCP__onTabNavigated(aEvent, aPacket) + _onTabNavigated: function WCCP__onTabNavigated(event, packet) { - if (!this.owner) { + if (!this.webConsoleFrame) { return; } - this.owner.handleTabNavigated(aEvent, aPacket); + this.webConsoleFrame.handleTabNavigated(event, packet); }, /** * Release an object actor. * - * @param string aActor + * @param string actor * The actor ID to send the request to. */ - releaseActor: function WCCP_releaseActor(aActor) + releaseActor: function WCCP_releaseActor(actor) { if (this.client) { - this.client.release(aActor); + this.client.release(actor); } }, @@ -5362,7 +5364,7 @@ WebConsoleConnectionProxy.prototype = { this.webConsoleClient = null; this.target = null; this.connected = false; - this.owner = null; + this.webConsoleFrame = null; this._disconnecter.resolve(null); return this._disconnecter.promise; @@ -5383,12 +5385,12 @@ gSequenceId.n = 0; * ConsoleContextMenu this used to handle the visibility of context menu items. * * @constructor - * @param object aOwner + * @param object owner * The WebConsoleFrame instance that owns this object. */ -function ConsoleContextMenu(aOwner) +function ConsoleContextMenu(owner) { - this.owner = aOwner; + this.owner = owner; this.popup = this.owner.document.getElementById("output-contextmenu"); this.build = this.build.bind(this); this.popup.addEventListener("popupshowing", this.build); @@ -5400,9 +5402,9 @@ ConsoleContextMenu.prototype = { /* * Handle to show/hide context menu item. */ - build: function CCM_build(aEvent) + build: function CCM_build(event) { - let metadata = this.getSelectionMetadata(aEvent.rangeParent); + let metadata = this.getSelectionMetadata(event.rangeParent); for (let element of this.popup.children) { element.hidden = this.shouldHideMenuItem(element, metadata); } @@ -5411,12 +5413,12 @@ ConsoleContextMenu.prototype = { /* * Get selection information from the view. * - * @param nsIDOMElement aClickElement + * @param nsIDOMElement clickElement * The DOM element the user clicked on. * @return object * Selection metadata. */ - getSelectionMetadata: function CCM_getSelectionMetadata(aClickElement) + getSelectionMetadata: function CCM_getSelectionMetadata(clickElement) { let metadata = { selectionType: "", @@ -5424,7 +5426,7 @@ ConsoleContextMenu.prototype = { }; let selectedItems = this.owner.output.getSelectedMessages(); if (!selectedItems.length) { - let clickedItem = this.owner.output.getMessageForElement(aClickElement); + let clickedItem = this.owner.output.getMessageForElement(clickElement); if (clickedItem) { this.lastClickedMessage = clickedItem; selectedItems = [clickedItem]; @@ -5460,26 +5462,26 @@ ConsoleContextMenu.prototype = { /* * Determine if an item should be hidden. * - * @param nsIDOMElement aMenuItem - * @param object aMetadata + * @param nsIDOMElement menuItem + * @param object metadata * @return boolean * Whether the given item should be hidden or not. */ - shouldHideMenuItem: function CCM_shouldHideMenuItem(aMenuItem, aMetadata) + shouldHideMenuItem: function CCM_shouldHideMenuItem(menuItem, metadata) { - let selectionType = aMenuItem.getAttribute("selectiontype"); - if (selectionType && !aMetadata.selectionType == selectionType) { + let selectionType = menuItem.getAttribute("selectiontype"); + if (selectionType && !metadata.selectionType == selectionType) { return true; } - let selection = aMenuItem.getAttribute("selection"); + let selection = menuItem.getAttribute("selection"); if (!selection) { return false; } let shouldHide = true; let itemData = selection.split("|"); - for (let type of aMetadata.selection) { + for (let type of metadata.selection) { // check whether this menu item should show or not. if (itemData.indexOf(type) !== -1) { shouldHide = false; diff --git a/devtools/shared/heapsnapshot/DominatorTree.cpp b/devtools/shared/heapsnapshot/DominatorTree.cpp index 96f0e68593f..e53c196cf3e 100644 --- a/devtools/shared/heapsnapshot/DominatorTree.cpp +++ b/devtools/shared/heapsnapshot/DominatorTree.cpp @@ -4,25 +4,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/devtools/DominatorTree.h" -#include "js/Debug.h" -#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/dom/DominatorTreeBinding.h" namespace mozilla { namespace devtools { -static MallocSizeOf -getCurrentThreadDebuggerMallocSizeOf() -{ - auto ccrt = CycleCollectedJSRuntime::Get(); - MOZ_ASSERT(ccrt); - auto rt = ccrt->Runtime(); - MOZ_ASSERT(rt); - auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt); - MOZ_ASSERT(mallocSizeOf); - return mallocSizeOf; -} - dom::Nullable DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv) { @@ -31,7 +17,7 @@ DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv) if (node.isNothing()) return dom::Nullable(); - auto mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf(); + auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); JS::ubi::Node::Size size = 0; if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); @@ -83,7 +69,7 @@ DominatorTree::GetImmediatelyDominated(uint64_t aNodeId, return; // Get all immediately dominated nodes and their retained sizes. - MallocSizeOf mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf(); + MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); Maybe range = mDominatorTree.getDominatedSet(*node); MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot."); size_t length = range->length(); diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp index 854bd3cdc94..9cae51a56ea 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -55,6 +55,18 @@ using ::google::protobuf::io::ZeroCopyInputStream; using JS::ubi::AtomOrTwoByteChars; +MallocSizeOf +GetCurrentThreadDebuggerMallocSizeOf() +{ + auto ccrt = CycleCollectedJSRuntime::Get(); + MOZ_ASSERT(ccrt); + auto rt = ccrt->Runtime(); + MOZ_ASSERT(rt); + auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt); + MOZ_ASSERT(mallocSizeOf); + return mallocSizeOf; +} + /*** Cycle Collection Boilerplate *****************************************************************/ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HeapSnapshot, mParent) @@ -482,7 +494,7 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, return; } - JS::ubi::CensusHandler handler(census, rootCount); + JS::ubi::CensusHandler handler(census, rootCount, GetCurrentThreadDebuggerMallocSizeOf()); { JS::AutoCheckCannotGC nogc; @@ -504,7 +516,7 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, } } - if (NS_WARN_IF(!handler.report(rval))) { + if (NS_WARN_IF(!handler.report(cx, rval))) { rv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.h b/devtools/shared/heapsnapshot/HeapSnapshot.h index c869c74ae5d..c8e4557c479 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.h +++ b/devtools/shared/heapsnapshot/HeapSnapshot.h @@ -221,6 +221,9 @@ WriteHeapGraph(JSContext* cx, ignoreNodeCount, ignoreEdgeCount); } +// Get the mozilla::MallocSizeOf for the current thread's JSRuntime. +MallocSizeOf GetCurrentThreadDebuggerMallocSizeOf(); + } // namespace devtools } // namespace mozilla diff --git a/dom/base/FileReader.cpp b/dom/base/FileReader.cpp index 10bfea467d3..892bcdf5c77 100644 --- a/dom/base/FileReader.cpp +++ b/dom/base/FileReader.cpp @@ -6,34 +6,34 @@ #include "FileReader.h" -#include "nsContentCID.h" -#include "nsContentUtils.h" -#include "nsDOMClassInfoID.h" -#include "nsError.h" -#include "nsIFile.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" +#include "nsIEventTarget.h" +#include "nsIGlobalObject.h" +#include "nsITimer.h" +#include "nsITransport.h" +#include "nsIStreamTransportService.h" -#include "nsXPCOM.h" -#include "nsIDOMEventListener.h" -#include "nsJSEnvironment.h" -#include "nsCycleCollectionParticipant.h" #include "mozilla/Base64.h" +#include "mozilla/dom/DOMError.h" #include "mozilla/dom/EncodingUtils.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FileReaderBinding.h" #include "mozilla/dom/ProgressEvent.h" -#include "xpcpublic.h" +#include "nsContentUtils.h" +#include "nsCycleCollectionParticipant.h" #include "nsDOMJSUtils.h" +#include "nsError.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "xpcpublic.h" -#include "jsfriendapi.h" - -#include "nsITransport.h" -#include "nsIStreamTransportService.h" +#include "WorkerPrivate.h" +#include "WorkerScope.h" namespace mozilla { namespace dom { +using namespace workers; + #define ABORT_STR "abort" #define LOAD_STR "load" #define LOADSTART_STR "loadstart" @@ -56,7 +56,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileReader, DOMEventTargetHelper) - tmp->mResultArrayBuffer = nullptr; + tmp->Shutdown(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob) NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressNotifier) NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) @@ -76,6 +76,20 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(FileReader, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(FileReader, DOMEventTargetHelper) +class MOZ_RAII FileReaderDecreaseBusyCounter +{ + RefPtr mFileReader; +public: + explicit FileReaderDecreaseBusyCounter(FileReader* aFileReader) + : mFileReader(aFileReader) + {} + + ~FileReaderDecreaseBusyCounter() + { + mFileReader->DecreaseBusyCounter(); + } +}; + void FileReader::RootResultArrayBuffer() { @@ -84,7 +98,8 @@ FileReader::RootResultArrayBuffer() //FileReader constructors/initializers -FileReader::FileReader(nsPIDOMWindow* aWindow) +FileReader::FileReader(nsPIDOMWindow* aWindow, + WorkerPrivate* aWorkerPrivate) : DOMEventTargetHelper(aWindow) , mFileData(nullptr) , mDataLen(0) @@ -95,14 +110,18 @@ FileReader::FileReader(nsPIDOMWindow* aWindow) , mReadyState(EMPTY) , mTotal(0) , mTransferred(0) + , mTarget(do_GetCurrentThread()) + , mBusyCount(0) + , mWorkerPrivate(aWorkerPrivate) { + MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate && !aWindow); + MOZ_ASSERT_IF(NS_IsMainThread(), !mWorkerPrivate); SetDOMStringToNull(mResult); } FileReader::~FileReader() { - FreeFileData(); - mResultArrayBuffer = nullptr; + Shutdown(); DropJSObjects(this); } @@ -111,9 +130,17 @@ FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { // The owner can be null when this object is used by chrome code. nsCOMPtr owner = do_QueryInterface(aGlobal.GetAsSupports()); - RefPtr fileReader = new FileReader(owner); + WorkerPrivate* workerPrivate = nullptr; - if (!owner && nsContentUtils::IsCallerChrome()) { + if (!NS_IsMainThread()) { + JSContext* cx = aGlobal.Context(); + workerPrivate = GetWorkerPrivateFromContext(cx); + MOZ_ASSERT(workerPrivate); + } + + RefPtr fileReader = new FileReader(owner, workerPrivate); + + if (!owner && nsContentUtils::ThreadsafeIsCallerChrome()) { // Instead of grabbing some random global from the context stack, // let's use the default one (junk scope) for now. // We should move away from this Init... @@ -215,7 +242,17 @@ FileReader::DoOnLoadEnd(nsresult aStatus, switch (mDataFormat) { case FILE_AS_ARRAYBUFFER: { AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(DOMEventTargetHelper::GetParentObject()))) { + nsCOMPtr globalObject; + + if (NS_IsMainThread()) { + globalObject = do_QueryInterface(GetParentObject()); + } else { + MOZ_ASSERT(mWorkerPrivate); + MOZ_ASSERT(mBusyCount); + globalObject = mWorkerPrivate->GlobalScope(); + } + + if (!globalObject || !jsapi.Init(globalObject)) { FreeFileData(); return NS_ERROR_FAILURE; } @@ -256,9 +293,29 @@ FileReader::DoOnLoadEnd(nsresult aStatus, } nsresult -FileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount) +FileReader::DoAsyncWait() { - MOZ_ASSERT(aStream); + nsresult rv = IncreaseBusyCounter(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = mAsyncStream->AsyncWait(this, + /* aFlags*/ 0, + /* aRequestedCount */ 0, + mTarget); + if (NS_WARN_IF(NS_FAILED(rv))) { + DecreaseBusyCounter(); + return rv; + } + + return NS_OK; +} + +nsresult +FileReader::DoReadData(uint64_t aCount) +{ + MOZ_ASSERT(mAsyncStream); if (mDataFormat == FILE_AS_BINARY) { //Continuously update our binary string as data comes in @@ -271,8 +328,8 @@ FileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount) NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); uint32_t bytesRead = 0; - aStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount, - &bytesRead); + mAsyncStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount, + &bytesRead); NS_ASSERTION(bytesRead == aCount, "failed to read data"); } else { @@ -287,7 +344,7 @@ FileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount) } uint32_t bytesRead = 0; - aStream->Read(mFileData + mDataLen, aCount, &bytesRead); + mAsyncStream->Read(mFileData + mDataLen, aCount, &bytesRead); NS_ASSERTION(bytesRead == aCount, "failed to read data"); } @@ -361,10 +418,7 @@ FileReader::ReadFileContent(Blob& aBlob, return; } - aRv = mAsyncStream->AsyncWait(this, - /* aFlags*/ 0, - /* aRequestedCount */ 0, - NS_GetCurrentThread()); + aRv = DoAsyncWait(); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -467,6 +521,7 @@ FileReader::StartProgressEventTimer() mProgressEventWasDelayed = false; mTimerIsActive = true; mProgressNotifier->Cancel(); + mProgressNotifier->SetTarget(mTarget); mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL, nsITimer::TYPE_ONE_SHOT); } @@ -550,18 +605,20 @@ FileReader::OnInputStreamReady(nsIAsyncInputStream* aStream) return NS_OK; } + // We use this class to decrease the busy counter at the end of this method. + // In theory we can do it immediatelly but, for debugging reasons, we want to + // be 100% sure we have a feature when OnLoadEnd() is called. + FileReaderDecreaseBusyCounter RAII(this); + uint64_t aCount; nsresult rv = aStream->Available(&aCount); if (NS_SUCCEEDED(rv) && aCount) { - rv = DoReadData(aStream, aCount); + rv = DoReadData(aCount); } if (NS_SUCCEEDED(rv)) { - rv = aStream->AsyncWait(this, - /* aFlags*/ 0, - /* aRequestedCount */ 0, - NS_GetCurrentThread()); + rv = DoAsyncWait(); } if (NS_FAILED(rv) || !aCount) { @@ -643,5 +700,56 @@ FileReader::Abort(ErrorResult& aRv) DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR)); } +nsresult +FileReader::IncreaseBusyCounter() +{ + if (mWorkerPrivate && mBusyCount++ == 0 && + !mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +void +FileReader::DecreaseBusyCounter() +{ + MOZ_ASSERT_IF(mWorkerPrivate, mBusyCount); + if (mWorkerPrivate && --mBusyCount == 0) { + mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this); + } +} + +bool +FileReader::Notify(JSContext* aCx, Status aStatus) +{ + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (aStatus > Running) { + Shutdown(); + } + + return true; +} + +void +FileReader::Shutdown() +{ + FreeFileData(); + mResultArrayBuffer = nullptr; + + if (mAsyncStream) { + mAsyncStream->Close(); + mAsyncStream = nullptr; + } + + if (mWorkerPrivate && mBusyCount != 0) { + mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this); + mWorkerPrivate = nullptr; + mBusyCount = 0; + } +} + } // dom namespace } // mozilla namespace diff --git a/dom/base/FileReader.h b/dom/base/FileReader.h index 7026d94a7f1..ab733ff39c7 100644 --- a/dom/base/FileReader.h +++ b/dom/base/FileReader.h @@ -9,37 +9,45 @@ #include "mozilla/Attributes.h" #include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/dom/DOMError.h" -#include "nsCOMPtr.h" #include "nsIAsyncInputStream.h" -#include "nsIStreamListener.h" -#include "nsISupportsUtils.h" #include "nsIInterfaceRequestor.h" -#include "nsITimer.h" -#include "nsJSUtils.h" +#include "nsCOMPtr.h" #include "nsString.h" -#include "nsTArray.h" #include "nsWeakReference.h" -#include "prtime.h" +#include "WorkerFeature.h" #define NS_PROGRESS_EVENT_INTERVAL 50 +class nsITimer; +class nsIEventTarget; + namespace mozilla { namespace dom { class Blob; +class DOMError; + +namespace workers { +class WorkerPrivate; +} extern const uint64_t kUnknownSize; +class FileReaderDecreaseBusyCounter; + class FileReader final : public DOMEventTargetHelper, public nsIInterfaceRequestor, public nsSupportsWeakReference, public nsIInputStreamCallback, - public nsITimerCallback + public nsITimerCallback, + public workers::WorkerFeature { + friend class FileReaderDecreaseBusyCounter; + public: - explicit FileReader(nsPIDOMWindow* aWindow); + FileReader(nsPIDOMWindow* aWindow, + workers::WorkerPrivate* aWorkerPrivate); NS_DECL_ISUPPORTS_INHERITED @@ -47,9 +55,11 @@ public: NS_DECL_NSIINPUTSTREAMCALLBACK NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FileReader, DOMEventTargetHelper) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FileReader, + DOMEventTargetHelper) - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; // WebIDL static already_AddRefed @@ -96,6 +106,9 @@ public: ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv); } + // WorkerFeature + bool Notify(JSContext* aCx, workers::Status) override; + private: virtual ~FileReader(); @@ -131,7 +144,8 @@ private: void DispatchError(nsresult rv, nsAString& finalEvent); nsresult DispatchProgressEvent(const nsAString& aType); - nsresult DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount); + nsresult DoAsyncWait(); + nsresult DoReadData(uint64_t aCount); nsresult DoOnLoadEnd(nsresult aStatus, nsAString& aSuccessEvent, nsAString& aTerminationEvent); @@ -143,6 +157,11 @@ private: mDataLen = 0; } + nsresult IncreaseBusyCounter(); + void DecreaseBusyCounter(); + + void Shutdown(); + char *mFileData; RefPtr mBlob; nsCString mCharset; @@ -166,6 +185,13 @@ private: uint64_t mTotal; uint64_t mTransferred; + + nsCOMPtr mTarget; + + uint64_t mBusyCount; + + // Kept alive with a WorkerFeature. + workers::WorkerPrivate* mWorkerPrivate; }; } // dom namespace diff --git a/dom/base/ImageEncoder.cpp b/dom/base/ImageEncoder.cpp index 22691f6863a..9df021f52b9 100644 --- a/dom/base/ImageEncoder.cpp +++ b/dom/base/ImageEncoder.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ImageEncoder.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" @@ -13,7 +14,10 @@ #include "mozilla/SyncRunnable.h" #include "mozilla/unused.h" #include "gfxUtils.h" +#include "nsIThreadPool.h" #include "nsNetUtil.h" +#include "nsXPCOMCIDInternal.h" +#include "WorkerPrivate.h" using namespace mozilla::gfx; @@ -69,27 +73,28 @@ GetBRGADataSourceSurfaceSync(already_AddRefed aImage) return helper->GetDataSurfaceSafe(); } -class EncodingCompleteEvent : public nsRunnable +class EncodingCompleteEvent : public nsCancelableRunnable { virtual ~EncodingCompleteEvent() {} public: - NS_DECL_ISUPPORTS_INHERITED - - EncodingCompleteEvent(nsIThread* aEncoderThread, - EncodeCompleteCallback* aEncodeCompleteCallback) + explicit EncodingCompleteEvent(EncodeCompleteCallback* aEncodeCompleteCallback) : mImgSize(0) , mType() , mImgData(nullptr) - , mEncoderThread(aEncoderThread) , mEncodeCompleteCallback(aEncodeCompleteCallback) , mFailed(false) - {} + { + if (!NS_IsMainThread() && workers::GetCurrentThreadWorkerPrivate()) { + mCreationThread = NS_GetCurrentThread(); + } else { + NS_GetMainThread(getter_AddRefs(mCreationThread)); + } + } NS_IMETHOD Run() override { nsresult rv = NS_OK; - MOZ_ASSERT(NS_IsMainThread()); if (!mFailed) { // The correct parentObject has to be set by the mEncodeCompleteCallback. @@ -102,7 +107,6 @@ public: mEncodeCompleteCallback = nullptr; - mEncoderThread->Shutdown(); return rv; } @@ -118,17 +122,20 @@ public: mFailed = true; } + nsIThread* GetCreationThread() + { + return mCreationThread; + } + private: uint64_t mImgSize; nsAutoString mType; void* mImgData; - nsCOMPtr mEncoderThread; + nsCOMPtr mCreationThread; RefPtr mEncodeCompleteCallback; bool mFailed; }; -NS_IMPL_ISUPPORTS_INHERITED0(EncodingCompleteEvent, nsRunnable); - class EncodingRunnable : public nsRunnable { virtual ~EncodingRunnable() {} @@ -207,7 +214,8 @@ public: } else { mEncodingCompleteEvent->SetMembers(imgData, imgSize, mType); } - rv = NS_DispatchToMainThread(mEncodingCompleteEvent); + rv = mEncodingCompleteEvent->GetCreationThread()-> + Dispatch(mEncodingCompleteEvent, nsIThread::DISPATCH_NORMAL); if (NS_FAILED(rv)) { // Better to leak than to crash. Unused << mEncodingCompleteEvent.forget(); @@ -231,6 +239,8 @@ private: NS_IMPL_ISUPPORTS_INHERITED0(EncodingRunnable, nsRunnable); +StaticRefPtr ImageEncoder::sThreadPool; + /* static */ nsresult ImageEncoder::ExtractData(nsAString& aType, @@ -262,12 +272,13 @@ ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType, return NS_IMAGELIB_ERROR_NO_ENCODER; } - nsCOMPtr encoderThread; - nsresult rv = NS_NewThread(getter_AddRefs(encoderThread), nullptr); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = EnsureThreadPool(); + if (NS_FAILED(rv)) { + return rv; + } RefPtr completeEvent = - new EncodingCompleteEvent(encoderThread, aEncodeCallback); + new EncodingCompleteEvent(aEncodeCallback); nsIntSize size(aImage->GetSize().width, aImage->GetSize().height); nsCOMPtr event = new EncodingRunnable(aType, @@ -279,7 +290,7 @@ ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType, imgIEncoder::INPUT_FORMAT_HOSTARGB, size, aUsingCustomOptions); - return encoderThread->Dispatch(event, NS_DISPATCH_NORMAL); + return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL); } /* static */ @@ -297,12 +308,13 @@ ImageEncoder::ExtractDataAsync(nsAString& aType, return NS_IMAGELIB_ERROR_NO_ENCODER; } - nsCOMPtr encoderThread; - nsresult rv = NS_NewThread(getter_AddRefs(encoderThread), nullptr); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = EnsureThreadPool(); + if (NS_FAILED(rv)) { + return rv; + } RefPtr completeEvent = - new EncodingCompleteEvent(encoderThread, aEncodeCallback); + new EncodingCompleteEvent(aEncodeCallback); nsCOMPtr event = new EncodingRunnable(aType, aOptions, @@ -313,7 +325,7 @@ ImageEncoder::ExtractDataAsync(nsAString& aType, aFormat, aSize, aUsingCustomOptions); - return encoderThread->Dispatch(event, NS_DISPATCH_NORMAL); + return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL); } /*static*/ nsresult @@ -479,5 +491,48 @@ ImageEncoder::GetImageEncoder(nsAString& aType) return encoder.forget(); } +/* static */ +nsresult +ImageEncoder::EnsureThreadPool() +{ + if (!sThreadPool) { + nsCOMPtr threadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID); + sThreadPool = threadPool; + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void { + ClearOnShutdown(&sThreadPool); + })); + } else { + ClearOnShutdown(&sThreadPool); + } + + const uint32_t kThreadLimit = 2; + const uint32_t kIdleThreadLimit = 1; + const uint32_t kIdleThreadTimeoutMs = 30000; + + nsresult rv = sThreadPool->SetName(NS_LITERAL_CSTRING("EncodingRunnable")); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = sThreadPool->SetThreadLimit(kThreadLimit); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = sThreadPool->SetIdleThreadLimit(kIdleThreadLimit); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = sThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + return NS_OK; +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/ImageEncoder.h b/dom/base/ImageEncoder.h index def44c547f4..de159021509 100644 --- a/dom/base/ImageEncoder.h +++ b/dom/base/ImageEncoder.h @@ -16,6 +16,7 @@ #include "nsSize.h" class nsICanvasRenderingContextInternal; +class nsIThreadPool; namespace mozilla { @@ -107,6 +108,11 @@ private: // undefined in this case. static already_AddRefed GetImageEncoder(nsAString& aType); + static nsresult EnsureThreadPool(); + + // Thread pool for dispatching EncodingRunnable. + static StaticRefPtr sThreadPool; + friend class EncodingRunnable; }; diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index d6932d376dd..056deeaae8b 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -28,6 +28,7 @@ #include "mozilla/dom/SubtleCryptoBinding.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/WebCryptoCommon.h" +#include "mozilla/gfx/2D.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" @@ -306,7 +307,7 @@ StructuredCloneHolder::Read(nsISupports* aParent, // If we are tranferring something, we cannot call 'Read()' more than once. if (mSupportsTransferring) { mBlobImplArray.Clear(); - mClonedImages.Clear(); + mClonedSurfaces.Clear(); Clear(); } } @@ -976,7 +977,7 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx, nsCOMPtr parent = do_QueryInterface(mParent); // aIndex is the index of the cloned image. return ImageBitmap::ReadStructuredClone(aCx, aReader, - parent, GetImages(), aIndex); + parent, GetSurfaces(), aIndex); } return ReadFullySerializableObjects(aCx, aReader, aTag); @@ -1021,7 +1022,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, ImageBitmap* imageBitmap = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) { return ImageBitmap::WriteStructuredClone(aWriter, - GetImages(), + GetSurfaces(), imageBitmap); } } @@ -1072,7 +1073,8 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx, MOZ_ASSERT(aContent); OffscreenCanvasCloneData* data = static_cast(aContent); - RefPtr canvas = OffscreenCanvas::CreateFromCloneData(data); + nsCOMPtr parent = do_QueryInterface(mParent); + RefPtr canvas = OffscreenCanvas::CreateFromCloneData(parent, data); delete data; JS::Rooted value(aCx); @@ -1085,6 +1087,26 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx, return true; } + if (aTag == SCTAG_DOM_IMAGEBITMAP) { + MOZ_ASSERT(mSupportedContext == SameProcessSameThread || + mSupportedContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + ImageBitmapCloneData* data = + static_cast(aContent); + nsCOMPtr parent = do_QueryInterface(mParent); + RefPtr bitmap = ImageBitmap::CreateFromCloneData(parent, data); + delete data; + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, bitmap, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; + } + return false; } @@ -1133,6 +1155,21 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx, return true; } + + ImageBitmap* bitmap = nullptr; + rv = UNWRAP_OBJECT(ImageBitmap, aObj, bitmap); + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(bitmap); + + *aExtraData = 0; + *aTag = SCTAG_DOM_IMAGEBITMAP; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = bitmap->ToCloneData(); + MOZ_ASSERT(*aContent); + bitmap->Close(); + + return true; + } } } @@ -1163,6 +1200,16 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag, delete data; return; } + + if (aTag == SCTAG_DOM_IMAGEBITMAP) { + MOZ_ASSERT(mSupportedContext == SameProcessSameThread || + mSupportedContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + ImageBitmapCloneData* data = + static_cast(aContent); + delete data; + return; + } } } // dom namespace diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h index 39121b556ae..7a620b28507 100644 --- a/dom/base/StructuredCloneHolder.h +++ b/dom/base/StructuredCloneHolder.h @@ -22,6 +22,10 @@ namespace layers { class Image; } +namespace gfx { +class DataSourceSurface; +} + namespace dom { class StructuredCloneHolderBase @@ -181,7 +185,7 @@ public: bool HasClonedDOMObjects() const { return !mBlobImplArray.IsEmpty() || - !mClonedImages.IsEmpty(); + !mClonedSurfaces.IsEmpty(); } nsTArray>& BlobImpls() @@ -212,9 +216,9 @@ public: return mPortIdentifiers; } - nsTArray>& GetImages() + nsTArray>& GetSurfaces() { - return mClonedImages; + return mClonedSurfaces; } // Implementations of the virtual methods to allow cloning of objects which @@ -291,10 +295,10 @@ protected: nsTArray> mBlobImplArray; // This is used for sharing the backend of ImageBitmaps. - // The layers::Image object must be thread-safely reference-counted. - // The layers::Image object will not be written ever via any ImageBitmap + // The DataSourceSurface object must be thread-safely reference-counted. + // The DataSourceSurface object will not be written ever via any ImageBitmap // instance, so no race condition will occur. - nsTArray> mClonedImages; + nsTArray> mClonedSurfaces; // This raw pointer is only set within ::Read() and is unset by the end. nsISupports* MOZ_NON_OWNING_REF mParent; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e282d5f7220..0a75ff67f50 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6775,66 +6775,6 @@ nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2) return principalsEqual; } -static void -CheckForWindowedPlugins(nsISupports* aSupports, void* aResult) -{ - nsCOMPtr content(do_QueryInterface(aSupports)); - if (!content || !content->IsInDoc()) { - return; - } - nsCOMPtr olc(do_QueryInterface(content)); - if (!olc) { - return; - } - RefPtr plugin; - olc->GetPluginInstance(getter_AddRefs(plugin)); - if (!plugin) { - return; - } - bool isWindowless = false; - nsresult res = plugin->IsWindowless(&isWindowless); - if (NS_SUCCEEDED(res) && !isWindowless) { - *static_cast(aResult) = true; - } -} - -static bool -DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult) -{ - if (!nsContentUtils::IsChromeDoc(aDoc)) { - aDoc->EnumerateActivityObservers(CheckForWindowedPlugins, aResult); - } - if (*static_cast(aResult)) { - // Return false to stop iteration, we found a windowed plugin. - return false; - } - aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult); - // Return false to stop iteration if we found a windowed plugin in - // the sub documents. - return !*static_cast(aResult); -} - -/* static */ -bool -nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc) -{ -#ifdef XP_MACOSX - // We control dispatch to all mac plugins. - return false; -#endif - bool result = false; - - // Find the top of the document's branch, the child of the chrome document. - nsIDocument* doc = aDoc; - nsIDocument* parent = nullptr; - while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) { - doc = parent; - } - - DocTreeContainsWindowedPlugins(doc, &result); - return result; -} - /* static */ bool nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) @@ -6842,10 +6782,30 @@ nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) #ifdef XP_MACOSX // We control dispatch to all mac plugins. return false; +#else + if (!aContent || !aContent->IsInDoc()) { + return false; + } + + nsCOMPtr olc = do_QueryInterface(aContent); + if (!olc) { + return false; + } + + RefPtr plugin; + olc->GetPluginInstance(getter_AddRefs(plugin)); + if (!plugin) { + return false; + } + + bool isWindowless = false; + nsresult res = plugin->IsWindowless(&isWindowless); + if (NS_FAILED(res)) { + return false; + } + + return !isWindowless; #endif - bool result = false; - CheckForWindowedPlugins(aContent, &result); - return result; } /* static */ diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 6d043af5620..0e8fd34f341 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2059,14 +2059,6 @@ public: return sPrivacyResistFingerprinting; } - /** - * Returns true if the doc tree branch which contains aDoc contains any - * plugins which we don't control event dispatch for, i.e. do any plugins - * in the same tab as this document receive key events outside of our - * control? This always returns false on MacOSX. - */ - static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc); - /** * Return true if this doc is controlled by a ServiceWorker. */ diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 0b9ac998111..dc80936aa26 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7668,7 +7668,6 @@ nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName, false, // aDoJSFixups true, // aNavigate nullptr, nullptr, // No args - GetPrincipal(), // aCalleePrincipal nullptr, // aJSCallerContext getter_AddRefs(window)); if (NS_SUCCEEDED(rv) && window) { @@ -7689,7 +7688,6 @@ nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName, true, // aDoJSFixups true, // aNavigate nullptr, nullptr, // No args - GetPrincipal(), // aCalleePrincipal nsContentUtils::GetCurrentJSContext(), // aJSCallerContext _retval); } @@ -7709,7 +7707,6 @@ nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName, false, // aDoJSFixups true, // aNavigate nullptr, aExtraArgument, // Arguments - GetPrincipal(), // aCalleePrincipal nullptr, // aJSCallerContext _retval); } @@ -7729,7 +7726,6 @@ nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl, false, // aDoJSFixups false, // aNavigate nullptr, nullptr, // No args - GetPrincipal(), // aCalleePrincipal nullptr, // aJSCallerContext _retval); @@ -7759,7 +7755,6 @@ nsGlobalWindow::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl, false, // aDoJSFixups true, // aNavigate argvArray, nullptr, // Arguments - GetPrincipal(), // aCalleePrincipal aCx, // aJSCallerContext getter_AddRefs(dialog)); return dialog.forget(); @@ -8839,7 +8834,6 @@ nsGlobalWindow::ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgumen true, // aDoJSFixups true, // aNavigate nullptr, argHolder, // args - GetPrincipal(), // aCalleePrincipal nullptr, // aJSCallerContext getter_AddRefs(dlgWin)); nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel); @@ -11270,7 +11264,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName, bool aDoJSFixups, bool aNavigate, nsIArray *argv, nsISupports *aExtraArgument, - nsIPrincipal *aCalleePrincipal, JSContext *aJSCallerContext, nsIDOMWindow **aReturn) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 1952d4eb18c..eeaac900a9f 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1392,7 +1392,6 @@ private: bool aNavigate, nsIArray *argv, nsISupports *aExtraArgument, - nsIPrincipal *aCalleePrincipal, JSContext *aJSCallerContext, nsIDOMWindow **aReturn); diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 5e89c391199..0e480db623e 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -5219,19 +5219,17 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, IntRect dstWriteRect = srcReadRect; dstWriteRect.MoveBy(-aX, -aY); - uint8_t* src; - uint32_t srcStride; - - if (readback) { - srcStride = rawData.mStride; - src = rawData.mData + srcReadRect.y * srcStride + srcReadRect.x * 4; - } - JS::AutoCheckCannotGC nogc; bool isShared; uint8_t* data = JS_GetUint8ClampedArrayData(darray, &isShared, nogc); MOZ_ASSERT(!isShared); // Should not happen, data was created above - if (!readback) { + + uint8_t* src; + uint32_t srcStride; + if (readback) { + srcStride = rawData.mStride; + src = rawData.mData + srcReadRect.y * srcStride + srcReadRect.x * 4; + } else { src = data; srcStride = aWidth * 4; } @@ -5579,9 +5577,9 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager) return mBufferProvider; } -already_AddRefed +already_AddRefed CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, + Layer *aOldLayer, LayerManager *aManager) { if (mOpaque || mIsSkiaGL) { @@ -5624,8 +5622,10 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, data.mBufferProvider = provider; } - if (userData && userData->IsForContext(this) && aOldLayer->IsDataValid(data)) { - RefPtr ret = aOldLayer; + if (userData && + userData->IsForContext(this) && + static_cast(aOldLayer)->IsDataValid(data)) { + RefPtr ret = aOldLayer; return ret.forget(); } } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index d2782b594d3..04c3bd89048 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -459,9 +459,9 @@ public: bool GetIsOpaque() override { return mOpaque; } NS_IMETHOD Reset() override; mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager); - already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, - LayerManager *aManager) override; + already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer *aOldLayer, + LayerManager *aManager) override; virtual bool ShouldForceInactiveLayer(LayerManager *aManager) override; void MarkContextClean() override; void MarkContextCleanForFrameCapture() override; diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp index ac4b87c9613..07977c375ac 100644 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CanvasRenderingContextHelper.h" +#include "ImageBitmapRenderingContext.h" #include "ImageEncoder.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/Telemetry.h" @@ -26,36 +27,6 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx, JS::Handle aParams, ErrorResult& aRv) { - nsAutoString type; - nsContentUtils::ASCIIToLower(aType, type); - - nsAutoString params; - bool usingCustomParseOptions; - aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); - if (aRv.Failed()) { - return; - } - - if (mCurrentContext) { - // We disallow canvases of width or height zero, and set them to 1, so - // we will have a discrepancy with the sizes of the canvas and the context. - // That discrepancy is OK, the rest are not. - nsIntSize elementSize = GetWidthHeight(); - if ((elementSize.width != mCurrentContext->GetWidth() && - (elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) || - (elementSize.height != mCurrentContext->GetHeight() && - (elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - } - - UniquePtr imageBuffer; - int32_t format = 0; - if (mCurrentContext) { - imageBuffer = mCurrentContext->GetImageBuffer(&format); - } - // Encoder callback when encoding is complete. class EncodeCallback : public EncodeCompleteCallback { @@ -97,6 +68,49 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx, RefPtr callback = new EncodeCallback(aGlobal, &aCallback); + ToBlob(aCx, aGlobal, callback, aType, aParams, aRv); +} + +void +CanvasRenderingContextHelper::ToBlob(JSContext* aCx, + nsIGlobalObject* aGlobal, + EncodeCompleteCallback* aCallback, + const nsAString& aType, + JS::Handle aParams, + ErrorResult& aRv) +{ + nsAutoString type; + nsContentUtils::ASCIIToLower(aType, type); + + nsAutoString params; + bool usingCustomParseOptions; + aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions); + if (aRv.Failed()) { + return; + } + + if (mCurrentContext) { + // We disallow canvases of width or height zero, and set them to 1, so + // we will have a discrepancy with the sizes of the canvas and the context. + // That discrepancy is OK, the rest are not. + nsIntSize elementSize = GetWidthHeight(); + if ((elementSize.width != mCurrentContext->GetWidth() && + (elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) || + (elementSize.height != mCurrentContext->GetHeight() && + (elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + } + + UniquePtr imageBuffer; + int32_t format = 0; + if (mCurrentContext) { + imageBuffer = mCurrentContext->GetImageBuffer(&format); + } + + RefPtr callback = aCallback; + aRv = ImageEncoder::ExtractDataAsync(type, params, usingCustomParseOptions, @@ -138,6 +152,11 @@ CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType) return nullptr; break; + + case CanvasContextType::ImageBitmap: + ret = new ImageBitmapRenderingContext(); + + break; } MOZ_ASSERT(ret); diff --git a/dom/canvas/CanvasRenderingContextHelper.h b/dom/canvas/CanvasRenderingContextHelper.h index 1e1afa6da76..b047d60fcfc 100644 --- a/dom/canvas/CanvasRenderingContextHelper.h +++ b/dom/canvas/CanvasRenderingContextHelper.h @@ -18,13 +18,15 @@ class ErrorResult; namespace dom { +class EncodeCompleteCallback; class FileCallback; enum class CanvasContextType : uint8_t { NoContext, Canvas2D, WebGL1, - WebGL2 + WebGL2, + ImageBitmap }; /** @@ -57,6 +59,10 @@ protected: const nsAString& aType, JS::Handle aParams, ErrorResult& aRv); + void ToBlob(JSContext* aCx, nsIGlobalObject* aGlobal, EncodeCompleteCallback* aCallback, + const nsAString& aType, JS::Handle aParams, + ErrorResult& aRv); + virtual already_AddRefed CreateContext(CanvasContextType aContextType); diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp index 9d258c01f70..ac0e2684947 100644 --- a/dom/canvas/CanvasUtils.cpp +++ b/dom/canvas/CanvasUtils.cpp @@ -61,6 +61,11 @@ GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_typ } } + if (str.EqualsLiteral("bitmaprenderer")) { + *out_type = dom::CanvasContextType::ImageBitmap; + return true; + } + return false; } diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index 1103f242308..2c7c3d412a2 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/ImageBitmap.h" + #include "mozilla/dom/ImageBitmapBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/StructuredCloneTags.h" @@ -145,15 +146,14 @@ CropAndCopyDataSourceSurface(DataSourceSurface* aSurface, const IntRect& aCropRe } /* - * Encapsulate the given _aSurface_ into a layers::CairoImage. + * Encapsulate the given _aSurface_ into a layers::SourceSurfaceImage. */ static already_AddRefed CreateImageFromSurface(SourceSurface* aSurface) { MOZ_ASSERT(aSurface); - RefPtr image = - new layers::CairoImage(aSurface->GetSize(), aSurface); - + RefPtr image = + new layers::SourceSurfaceImage(aSurface->GetSize(), aSurface); return image.forget(); } @@ -250,13 +250,13 @@ CreateImageFromRawData(const gfx::IntSize& aSize, /* * This is a synchronous task. - * This class is used to create a layers::CairoImage from raw data in the main + * This class is used to create a layers::SourceSurfaceImage from raw data in the main * thread. While creating an ImageBitmap from an ImageData, we need to create * a SouceSurface from the ImageData's raw data and then set the SourceSurface - * into a layers::CairoImage. However, the layers::CairoImage asserts the + * into a layers::SourceSurfaceImage. However, the layers::SourceSurfaceImage asserts the * setting operation in the main thread, so if we are going to create an * ImageBitmap from an ImageData off the main thread, we post an event to the - * main thread to create a layers::CairoImage from an ImageData's raw data. + * main thread to create a layers::SourceSurfaceImage from an ImageData's raw data. */ class CreateImageFromRawDataInMainThreadSyncTask final : public WorkerMainThreadRunnable @@ -408,6 +408,14 @@ ImageBitmap::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return ImageBitmapBinding::Wrap(aCx, this, aGivenProto); } +void +ImageBitmap::Close() +{ + mData = nullptr; + mSurface = nullptr; + mPictureRect.SetEmpty(); +} + void ImageBitmap::SetPictureRect(const IntRect& aRect, ErrorResult& aRv) { @@ -419,6 +427,10 @@ ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget) { MOZ_ASSERT(aTarget); + if (!mData) { + return nullptr; + } + if (!mSurface) { mSurface = mData->GetAsSourceSurface(); } @@ -493,6 +505,68 @@ ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget) return surface.forget(); } +already_AddRefed +ImageBitmap::TransferAsImage() +{ + RefPtr image = mData; + Close(); + return image.forget(); +} + +ImageBitmapCloneData* +ImageBitmap::ToCloneData() +{ + ImageBitmapCloneData* result = new ImageBitmapCloneData(); + result->mPictureRect = mPictureRect; + RefPtr surface = mData->GetAsSourceSurface(); + result->mSurface = surface->GetDataSurface(); + MOZ_ASSERT(result->mSurface); + + return result; +} + +/* static */ already_AddRefed +ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal, + ImageBitmapCloneData* aData) +{ + RefPtr data = + CreateImageFromSurface(aData->mSurface); + + RefPtr ret = new ImageBitmap(aGlobal, data); + ErrorResult rv; + ret->SetPictureRect(aData->mPictureRect, rv); + return ret.forget(); +} + +/* static */ already_AddRefed +ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, + OffscreenCanvas& aOffscreenCanvas, + ErrorResult& aRv) +{ + // Check origin-clean. + if (aOffscreenCanvas.IsWriteOnly()) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, + nsLayoutUtils::SFE_WANT_FIRST_FRAME); + + RefPtr surface = res.GetSourceSurface(); + + if (NS_WARN_IF(!surface)) { + aRv.Throw(NS_ERROR_NOT_AVAILABLE); + return nullptr; + } + + RefPtr data = + CreateImageFromSurface(surface); + + RefPtr ret = new ImageBitmap(aGlobal, data); + return ret.forget(); +} + /* static */ already_AddRefed ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl, const Maybe& aCropRect, ErrorResult& aRv) @@ -1154,7 +1228,7 @@ ImageBitmap::Create(nsIGlobalObject* aGlobal, const ImageBitmapSource& aSrc, ImageBitmap::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader, nsIGlobalObject* aParent, - const nsTArray>& aClonedImages, + const nsTArray>& aClonedSurfaces, uint32_t aIndex) { MOZ_ASSERT(aCx); @@ -1177,8 +1251,8 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, int32_t picRectHeight = BitwiseCast(picRectHeight_); // Create a new ImageBitmap. - MOZ_ASSERT(!aClonedImages.IsEmpty()); - MOZ_ASSERT(aIndex < aClonedImages.Length()); + MOZ_ASSERT(!aClonedSurfaces.IsEmpty()); + MOZ_ASSERT(aIndex < aClonedSurfaces.Length()); // RefPtr needs to go out of scope before toObjectOrNull() is // called because the static analysis thinks dereferencing XPCOM objects @@ -1187,8 +1261,9 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, // while destructors are running. JS::Rooted value(aCx); { + RefPtr img = CreateImageFromSurface(aClonedSurfaces[aIndex]); RefPtr imageBitmap = - new ImageBitmap(aParent, aClonedImages[aIndex]); + new ImageBitmap(aParent, img); ErrorResult error; imageBitmap->SetPictureRect(IntRect(picRectX, picRectY, @@ -1208,7 +1283,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, /*static*/ bool ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, - nsTArray>& aClonedImages, + nsTArray>& aClonedSurfaces, ImageBitmap* aImageBitmap) { MOZ_ASSERT(aWriter); @@ -1219,8 +1294,8 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, const uint32_t picRectWidth = BitwiseCast(aImageBitmap->mPictureRect.width); const uint32_t picRectHeight = BitwiseCast(aImageBitmap->mPictureRect.height); - // Indexing the cloned images and send the index to the receiver. - uint32_t index = aClonedImages.Length(); + // Indexing the cloned surfaces and send the index to the receiver. + uint32_t index = aClonedSurfaces.Length(); if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) || @@ -1228,8 +1303,24 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, return false; } - aClonedImages.AppendElement(aImageBitmap->mData); - + RefPtr surface = + aImageBitmap->mData->GetAsSourceSurface(); + RefPtr snapshot = surface->GetDataSurface(); + RefPtr dstDataSurface; + { + // DataSourceSurfaceD2D1::GetStride() will call EnsureMapped implicitly and + // won't Unmap after exiting function. So instead calling GetStride() + // directly, using ScopedMap to get stride. + DataSourceSurface::ScopedMap map(snapshot, DataSourceSurface::READ); + dstDataSurface = + Factory::CreateDataSourceSurfaceWithStride(snapshot->GetSize(), + snapshot->GetFormat(), + map.GetStride(), + true); + } + MOZ_ASSERT(dstDataSurface); + Factory::CopyDataSourceSurface(snapshot, dstDataSurface); + aClonedSurfaces.AppendElement(dstDataSurface); return true; } diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index ac849770a1b..4480efeef20 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -25,6 +25,7 @@ namespace mozilla { class ErrorResult; namespace gfx { +class DataSourceSurface; class SourceSurface; } @@ -33,6 +34,7 @@ class Image; } namespace dom { +class OffscreenCanvas; namespace workers { class WorkerStructuredCloneClosure; @@ -50,6 +52,12 @@ class CreateImageBitmapFromBlob; class CreateImageBitmapFromBlobTask; class CreateImageBitmapFromBlobWorkerTask; +struct ImageBitmapCloneData final +{ + RefPtr mSurface; + gfx::IntRect mPictureRect; +}; + /* * ImageBitmap is an opaque handler to several kinds of image-like objects from * HTMLImageElement, HTMLVideoElement, HTMLCanvasElement, ImageData to @@ -83,6 +91,8 @@ public: return mPictureRect.Height(); } + void Close(); + /* * The PrepareForDrawTarget() might return null if the mPictureRect does not * intersect with the size of mData. @@ -90,6 +100,24 @@ public: already_AddRefed PrepareForDrawTarget(gfx::DrawTarget* aTarget); + /* + * Transfer ownership of buffer to caller. So this function call + * Close() implicitly. + */ + already_AddRefed + TransferAsImage(); + + ImageBitmapCloneData* + ToCloneData(); + + static already_AddRefed + CreateFromCloneData(nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData); + + static already_AddRefed + CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, + OffscreenCanvas& aOffscreenCanvas, + ErrorResult& aRv); + static already_AddRefed Create(nsIGlobalObject* aGlobal, const ImageBitmapSource& aSrc, const Maybe& aCropRect, ErrorResult& aRv); @@ -98,12 +126,12 @@ public: ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader, nsIGlobalObject* aParent, - const nsTArray>& aClonedImages, + const nsTArray>& aClonedSurfaces, uint32_t aIndex); static bool WriteStructuredClone(JSStructuredCloneWriter* aWriter, - nsTArray>& aClonedImages, + nsTArray>& aClonedSurfaces, ImageBitmap* aImageBitmap); friend CreateImageBitmapFromBlob; diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp new file mode 100644 index 00000000000..b8b079eeb5c --- /dev/null +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -0,0 +1,303 @@ +/* -*- 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 "ImageBitmapRenderingContext.h" +#include "mozilla/dom/ImageBitmapRenderingContextBinding.h" +#include "ImageContainer.h" +#include "ImageLayers.h" + +namespace mozilla { +namespace dom { + +ImageBitmapRenderingContext::ImageBitmapRenderingContext() + : mWidth(0) + , mHeight(0) +{ +} + +ImageBitmapRenderingContext::~ImageBitmapRenderingContext() +{ + RemovePostRefreshObserver(); +} + +JSObject* +ImageBitmapRenderingContext::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return ImageBitmapRenderingContextBinding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed +ImageBitmapRenderingContext::ClipToIntrinsicSize() +{ + if (!mImage) { + return nullptr; + } + + // If image is larger than canvas intrinsic size, clip it to the intrinsic size. + RefPtr surface; + RefPtr result; + if (mWidth < mImage->GetSize().width || + mHeight < mImage->GetSize().height) { + surface = MatchWithIntrinsicSize(); + } else { + surface = mImage->GetAsSourceSurface(); + } + result = new layers::SourceSurfaceImage(gfx::IntSize(mWidth, mHeight), surface); + return result.forget(); +} + +void +ImageBitmapRenderingContext::TransferImageBitmap(ImageBitmap& aImageBitmap) +{ + Reset(); + mImage = aImageBitmap.TransferAsImage(); + + if (!mImage) { + return; + } + + Redraw(gfxRect(0, 0, mWidth, mHeight)); +} + +int32_t +ImageBitmapRenderingContext::GetWidth() const +{ + return mWidth; +} + +int32_t +ImageBitmapRenderingContext::GetHeight() const +{ + return mHeight; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight) +{ + mWidth = aWidth; + mHeight = aHeight; + return NS_OK; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::InitializeWithSurface(nsIDocShell* aDocShell, + gfxASurface* aSurface, + int32_t aWidth, + int32_t aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +already_AddRefed +ImageBitmapRenderingContext::MatchWithIntrinsicSize() +{ + RefPtr surface = mImage->GetAsSourceSurface(); + RefPtr temp = + Factory::CreateDataSourceSurface(IntSize(mWidth, mHeight), surface->GetFormat()); + if (!temp) { + return nullptr; + } + + DataSourceSurface::ScopedMap map(temp, DataSourceSurface::READ_WRITE); + if (!map.IsMapped()) { + return nullptr; + } + + RefPtr dt = + Factory::CreateDrawTargetForData(BackendType::CAIRO, + map.GetData(), + temp->GetSize(), + map.GetStride(), + temp->GetFormat()); + if (!dt) { + return nullptr; + } + + + dt->ClearRect(Rect(0, 0, mWidth, mHeight)); + dt->CopySurface(surface, + IntRect(0, 0, surface->GetSize().width, + surface->GetSize().height), + IntPoint(0, 0)); + + return temp.forget(); +} + +mozilla::UniquePtr +ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat) +{ + *aFormat = 0; + + if (!mImage) { + return nullptr; + } + + RefPtr surface = mImage->GetAsSourceSurface(); + RefPtr data = surface->GetDataSurface(); + if (!data) { + return nullptr; + } + + if (data->GetSize() != IntSize(mWidth, mHeight)) { + data = MatchWithIntrinsicSize(); + } + + *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB; + return SurfaceToPackedBGRA(data); +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::GetInputStream(const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** aStream) +{ + nsCString enccid("@mozilla.org/image/encoder;2?type="); + enccid += aMimeType; + nsCOMPtr encoder = do_CreateInstance(enccid.get()); + if (!encoder) { + return NS_ERROR_FAILURE; + } + + int32_t format = 0; + UniquePtr imageBuffer = GetImageBuffer(&format); + if (!imageBuffer) { + return NS_ERROR_FAILURE; + } + + return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(), format, + encoder, aEncoderOptions, aStream); +} + +already_AddRefed +ImageBitmapRenderingContext::GetSurfaceSnapshot(bool* aPremultAlpha) +{ + if (!mImage) { + return nullptr; + } + + if (aPremultAlpha) { + *aPremultAlpha = true; + } + + RefPtr surface = mImage->GetAsSourceSurface(); + if (surface->GetSize() != IntSize(mWidth, mHeight)) { + return MatchWithIntrinsicSize(); + } + + return surface.forget(); +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetIsOpaque(bool aIsOpaque) +{ + return NS_OK; +} + +bool +ImageBitmapRenderingContext::GetIsOpaque() +{ + return false; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::Reset() +{ + if (mCanvasElement) { + mCanvasElement->InvalidateCanvas(); + } + + mImage = nullptr; + + return NS_OK; +} + +already_AddRefed +ImageBitmapRenderingContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer* aOldLayer, + LayerManager* aManager) +{ + if (!mImage) { + // No DidTransactionCallback will be received, so mark the context clean + // now so future invalidations will be dispatched. + MarkContextClean(); + return nullptr; + } + + RefPtr imageLayer; + + if (aOldLayer) { + imageLayer = static_cast(aOldLayer); + } else { + imageLayer = aManager->CreateImageLayer(); + } + + RefPtr imageContainer = imageLayer->GetContainer(); + if (!imageContainer) { + imageContainer = aManager->CreateImageContainer(); + imageLayer->SetContainer(imageContainer); + } + + nsAutoTArray imageList; + RefPtr image = ClipToIntrinsicSize(); + imageList.AppendElement(ImageContainer::NonOwningImage(image)); + imageContainer->SetCurrentImages(imageList); + + return imageLayer.forget(); +} + +void +ImageBitmapRenderingContext::MarkContextClean() +{ +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::Redraw(const gfxRect& aDirty) +{ + if (!mCanvasElement) { + return NS_OK; + } + + mozilla::gfx::Rect rect = ToRect(aDirty); + mCanvasElement->InvalidateCanvasContent(&rect); + return NS_OK; +} + +NS_IMETHODIMP +ImageBitmapRenderingContext::SetIsIPC(bool aIsIPC) +{ + return NS_OK; +} + +void +ImageBitmapRenderingContext::DidRefresh() +{ +} + +void +ImageBitmapRenderingContext::MarkContextCleanForFrameCapture() +{ +} + +bool +ImageBitmapRenderingContext::IsContextCleanForFrameCapture() +{ + return true; +} + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext) + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmapRenderingContext, + mCanvasElement, + mOffscreenCanvas) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +} +} diff --git a/dom/canvas/ImageBitmapRenderingContext.h b/dom/canvas/ImageBitmapRenderingContext.h new file mode 100644 index 00000000000..aa5c5061119 --- /dev/null +++ b/dom/canvas/ImageBitmapRenderingContext.h @@ -0,0 +1,97 @@ +/* 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 ImageBitmapRenderingContext_h +#define ImageBitmapRenderingContext_h + +#include "nsICanvasRenderingContextInternal.h" +#include "nsWrapperCache.h" + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +class SourceSurface; +} + +namespace layers { +class Image; +class ImageContainer; +} + +namespace dom { + +/** + * The purpose of ImageBitmapRenderingContext is to provide a faster and efficient + * way to display ImageBitmap. Simply call TransferImageBitmap() then we'll transfer + * the surface of ImageBitmap to this context and then to use it to display. + * + * See more details in spec: https://wiki.whatwg.org/wiki/OffscreenCanvas + */ +class ImageBitmapRenderingContext final : + public nsICanvasRenderingContextInternal, + public nsWrapperCache +{ + virtual ~ImageBitmapRenderingContext(); + +public: + ImageBitmapRenderingContext(); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + // nsISupports interface + CC + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageBitmapRenderingContext) + + void TransferImageBitmap(ImageBitmap& aImageBitmap); + + // nsICanvasRenderingContextInternal + virtual int32_t GetWidth() const override; + virtual int32_t GetHeight() const override; + + NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override; + + NS_IMETHOD InitializeWithSurface(nsIDocShell* aDocShell, + gfxASurface* aSurface, + int32_t aWidth, + int32_t aHeight) override; + + virtual mozilla::UniquePtr GetImageBuffer(int32_t* aFormat) override; + NS_IMETHOD GetInputStream(const char* aMimeType, + const char16_t* aEncoderOptions, + nsIInputStream** aStream) override; + + virtual already_AddRefed + GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override; + + NS_IMETHOD SetIsOpaque(bool aIsOpaque) override; + virtual bool GetIsOpaque() override; + NS_IMETHOD Reset() override; + virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer* aOldLayer, + LayerManager* aManager) override; + virtual void MarkContextClean() override; + + NS_IMETHOD Redraw(const gfxRect& aDirty) override; + NS_IMETHOD SetIsIPC(bool aIsIPC) override; + + virtual void DidRefresh() override; + + virtual void MarkContextCleanForFrameCapture() override; + virtual bool IsContextCleanForFrameCapture() override; + +protected: + already_AddRefed MatchWithIntrinsicSize(); + already_AddRefed ClipToIntrinsicSize(); + int32_t mWidth; + int32_t mHeight; + + RefPtr mImage; +}; + +} +} + +#endif /* ImageBitmapRenderingContext_h */ diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index adb666018f8..857da02aeac 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/OffscreenCanvasBinding.h" #include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerScope.h" #include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/layers/CanvasClient.h" #include "mozilla/layers/ImageBridgeChild.h" @@ -24,12 +25,13 @@ namespace dom { OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, layers::LayersBackend aCompositorBackend, - bool aNeutered) + bool aNeutered, bool aIsWriteOnly) : mRenderer(aRenderer) , mWidth(aWidth) , mHeight(aHeight) , mCompositorBackendType(aCompositorBackend) , mNeutered(aNeutered) + , mIsWriteOnly(aIsWriteOnly) { } @@ -37,12 +39,15 @@ OffscreenCanvasCloneData::~OffscreenCanvasCloneData() { } -OffscreenCanvas::OffscreenCanvas(uint32_t aWidth, +OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, + uint32_t aWidth, uint32_t aHeight, layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer) - : mAttrDirty(false) + : DOMEventTargetHelper(aGlobal) + , mAttrDirty(false) , mNeutered(false) + , mIsWriteOnly(false) , mWidth(aWidth) , mHeight(aHeight) , mCompositorBackendType(aCompositorBackend) @@ -55,12 +60,6 @@ OffscreenCanvas::~OffscreenCanvas() ClearResources(); } -OffscreenCanvas* -OffscreenCanvas::GetParentObject() const -{ - return nullptr; -} - JSObject* OffscreenCanvas::WrapObject(JSContext* aCx, JS::Handle aGivenProto) @@ -68,6 +67,19 @@ OffscreenCanvas::WrapObject(JSContext* aCx, return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto); } +/* static */ already_AddRefed +OffscreenCanvas::Constructor(const GlobalObject& aGlobal, + uint32_t aWidth, + uint32_t aHeight, + ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr offscreenCanvas = + new OffscreenCanvas(global, aWidth, aHeight, + layers::LayersBackend::LAYERS_NONE, nullptr); + return offscreenCanvas.forget(); +} + void OffscreenCanvas::ClearResources() { @@ -79,7 +91,9 @@ OffscreenCanvas::ClearResources() if (mCanvasRenderer) { nsCOMPtr activeThread = mCanvasRenderer->GetActiveThread(); MOZ_RELEASE_ASSERT(activeThread); - MOZ_RELEASE_ASSERT(activeThread == NS_GetCurrentThread()); + bool current; + activeThread->IsOnCurrentThread(¤t); + MOZ_RELEASE_ASSERT(current); mCanvasRenderer->SetCanvasClient(nullptr); mCanvasRenderer->mContext = nullptr; mCanvasRenderer->mGLContext = nullptr; @@ -107,7 +121,8 @@ OffscreenCanvas::GetContext(JSContext* aCx, } if (!(contextType == CanvasContextType::WebGL1 || - contextType == CanvasContextType::WebGL2)) + contextType == CanvasContextType::WebGL2 || + contextType == CanvasContextType::ImageBitmap)) { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); return nullptr; @@ -124,28 +139,31 @@ OffscreenCanvas::GetContext(JSContext* aCx, } if (mCanvasRenderer) { - WebGLContext* webGL = static_cast(mCurrentContext.get()); - gl::GLContext* gl = webGL->GL(); - mCanvasRenderer->mContext = mCurrentContext; - mCanvasRenderer->SetActiveThread(); - mCanvasRenderer->mGLContext = gl; - mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); + if (contextType == CanvasContextType::WebGL1 || + contextType == CanvasContextType::WebGL2) { + WebGLContext* webGL = static_cast(mCurrentContext.get()); + gl::GLContext* gl = webGL->GL(); + mCanvasRenderer->mContext = mCurrentContext; + mCanvasRenderer->SetActiveThread(); + mCanvasRenderer->mGLContext = gl; + mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha); - if (ImageBridgeChild::IsCreated()) { - TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; - mCanvasClient = ImageBridgeChild::GetSingleton()-> - CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); - mCanvasRenderer->SetCanvasClient(mCanvasClient); + if (ImageBridgeChild::IsCreated()) { + TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT; + mCanvasClient = ImageBridgeChild::GetSingleton()-> + CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take(); + mCanvasRenderer->SetCanvasClient(mCanvasClient); - gl::GLScreenBuffer* screen = gl->Screen(); - gl::SurfaceCaps caps = screen->mCaps; - auto forwarder = mCanvasClient->GetForwarder(); + gl::GLScreenBuffer* screen = gl->Screen(); + gl::SurfaceCaps caps = screen->mCaps; + auto forwarder = mCanvasClient->GetForwarder(); - UniquePtr factory = - gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); + UniquePtr factory = + gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags); - if (factory) - screen->Morph(Move(factory)); + if (factory) + screen->Morph(Move(factory)); + } } } @@ -165,6 +183,12 @@ OffscreenCanvas::CreateContext(CanvasContextType aContextType) void OffscreenCanvas::CommitFrameToCompositor() { + if (!mCanvasRenderer) { + // This offscreen canvas doesn't associate to any HTML canvas element. + // So, just bail out. + return; + } + // The attributes has changed, we have to notify main // thread to change canvas size. if (mAttrDirty) { @@ -191,15 +215,121 @@ OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() { return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight, - mCompositorBackendType, mNeutered); + mCompositorBackendType, mNeutered, mIsWriteOnly); +} + +already_AddRefed +OffscreenCanvas::TransferToImageBitmap() +{ + ErrorResult rv; + RefPtr result = ImageBitmap::CreateFromOffscreenCanvas(GetGlobalObject(), *this, rv); + + // Clear the content. + if ((mCurrentContextType == CanvasContextType::WebGL1 || + mCurrentContextType == CanvasContextType::WebGL2)) + { + WebGLContext* webGL = static_cast(mCurrentContext.get()); + webGL->ClearScreen(); + } + + return result.forget(); +} + +already_AddRefed +OffscreenCanvas::ToBlob(JSContext* aCx, + const nsAString& aType, + JS::Handle aParams, + ErrorResult& aRv) +{ + // do a trust check if this is a write-only canvas + if (mIsWriteOnly) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + nsCOMPtr global = GetGlobalObject(); + + RefPtr promise = Promise::Create(global, aRv); + if (aRv.Failed()) { + return nullptr; + } + + // Encoder callback when encoding is complete. + class EncodeCallback : public EncodeCompleteCallback + { + public: + EncodeCallback(nsIGlobalObject* aGlobal, Promise* aPromise) + : mGlobal(aGlobal) + , mPromise(aPromise) {} + + // This is called on main thread. + nsresult ReceiveBlob(already_AddRefed aBlob) + { + RefPtr blob = aBlob; + + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + if (rv.Failed()) { + rv.SuppressException(); + } else { + AutoJSAPI jsapi; + if (jsapi.Init(mGlobal)) { + JS_updateMallocCounter(jsapi.cx(), size); + } + } + + if (mPromise) { + RefPtr newBlob = Blob::Create(mGlobal, blob->Impl()); + mPromise->MaybeResolve(newBlob); + } + + mGlobal = nullptr; + mPromise = nullptr; + + return rv.StealNSResult(); + } + + nsCOMPtr mGlobal; + RefPtr mPromise; + }; + + RefPtr callback = + new EncodeCallback(global, promise); + + CanvasRenderingContextHelper::ToBlob(aCx, global, + callback, aType, aParams, aRv); + + return promise.forget(); +} + +already_AddRefed +OffscreenCanvas::GetSurfaceSnapshot(bool* aPremultAlpha) +{ + if (!mCurrentContext) { + return nullptr; + } + + return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha); +} + +nsCOMPtr +OffscreenCanvas::GetGlobalObject() +{ + if (NS_IsMainThread()) { + return GetParentObject(); + } + + dom::workers::WorkerPrivate* workerPrivate = + dom::workers::GetCurrentThreadWorkerPrivate(); + return workerPrivate->GlobalScope(); } /* static */ already_AddRefed -OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData) +OffscreenCanvas::CreateFromCloneData(nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData) { MOZ_ASSERT(aData); RefPtr wc = - new OffscreenCanvas(aData->mWidth, aData->mHeight, + new OffscreenCanvas(aGlobal, aData->mWidth, aData->mHeight, aData->mCompositorBackendType, aData->mRenderer); if (aData->mNeutered) { wc->SetNeutered(); diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h index 1c8f57b8f4d..520149e55b0 100644 --- a/dom/canvas/OffscreenCanvas.h +++ b/dom/canvas/OffscreenCanvas.h @@ -25,6 +25,8 @@ class CanvasClient; } // namespace layers namespace dom { +class Blob; +class ImageBitmap; // This is helper class for transferring OffscreenCanvas to worker thread. // Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen- @@ -35,7 +37,7 @@ struct OffscreenCanvasCloneData final OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight, layers::LayersBackend aCompositorBackend, - bool aNeutered); + bool aNeutered, bool aIsWriteOnly); ~OffscreenCanvasCloneData(); RefPtr mRenderer; @@ -43,6 +45,7 @@ struct OffscreenCanvasCloneData final uint32_t mHeight; layers::LayersBackend mCompositorBackendType; bool mNeutered; + bool mIsWriteOnly; }; class OffscreenCanvas final : public DOMEventTargetHelper @@ -52,16 +55,23 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas, DOMEventTargetHelper) - OffscreenCanvas(uint32_t aWidth, + OffscreenCanvas(nsIGlobalObject* aGlobal, + uint32_t aWidth, uint32_t aHeight, layers::LayersBackend aCompositorBackend, layers::AsyncCanvasRenderer* aRenderer); - OffscreenCanvas* GetParentObject() const; + nsCOMPtr GetParentObject() const { return GetOwnerGlobal(); } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + uint32_t aWidth, + uint32_t aHeight, + ErrorResult& aRv); + void ClearResources(); uint32_t Width() const @@ -100,13 +110,24 @@ public: } } + already_AddRefed + TransferToImageBitmap(); + + already_AddRefed + ToBlob(JSContext* aCx, + const nsAString& aType, + JS::Handle aParams, + ErrorResult& aRv); + nsICanvasRenderingContextInternal* GetContext() const { return mCurrentContext; } + already_AddRefed GetSurfaceSnapshot(bool* aPremultAlpha = nullptr); + static already_AddRefed - CreateFromCloneData(OffscreenCanvasCloneData* aData); + CreateFromCloneData(nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData); static bool PrefEnabled(JSContext* aCx, JSObject* aObj); @@ -147,6 +168,16 @@ public: return mNeutered; } + void SetWriteOnly() + { + mIsWriteOnly = true; + } + + bool IsWriteOnly() const + { + return mIsWriteOnly; + } + layers::LayersBackend GetCompositorBackendType() const { return mCompositorBackendType; @@ -155,6 +186,8 @@ public: private: ~OffscreenCanvas(); + nsCOMPtr GetGlobalObject(); + void CanvasAttrChanged() { mAttrDirty = true; @@ -164,6 +197,7 @@ private: bool mAttrDirty; bool mNeutered; + bool mIsWriteOnly; uint32_t mWidth; uint32_t mHeight; diff --git a/dom/canvas/WebGL2Context.cpp b/dom/canvas/WebGL2Context.cpp index 7a695c0c8c0..0ecd60e5569 100644 --- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -5,10 +5,10 @@ #include "WebGL2Context.h" +#include "gfxPrefs.h" #include "GLContext.h" #include "mozilla/dom/WebGL2RenderingContextBinding.h" #include "mozilla/ArrayUtils.h" -#include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "WebGLBuffer.h" #include "WebGLFormats.h" @@ -37,7 +37,7 @@ WebGL2Context::CreateFormatUsage(gl::GLContext* gl) const /*static*/ bool WebGL2Context::IsSupported() { - return Preferences::GetBool("webgl.enable-prototype-webgl2", false); + return gfxPrefs::WebGL2Enabled(); } /*static*/ WebGL2Context* diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index b8bc7a14807..aa2fcad5ab3 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1131,9 +1131,9 @@ private: RefPtr mCanvas; }; -already_AddRefed +already_AddRefed WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, - CanvasLayer* oldLayer, + Layer* oldLayer, LayerManager* manager) { if (IsContextLost()) @@ -1141,7 +1141,7 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder, if (!mResetLayer && oldLayer && oldLayer->HasUserData(&gWebGLLayerUserData)) { - RefPtr ret = oldLayer; + RefPtr ret = oldLayer; return ret.forget(); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 5e3d61722cd..74f475a3a2d 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -331,8 +331,8 @@ public: return ActiveBoundTextureForTarget(texTarget); } - already_AddRefed - GetCanvasLayer(nsDisplayListBuilder* builder, CanvasLayer* oldLayer, + already_AddRefed + GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer, LayerManager* manager) override; // Note that 'clean' here refers to its invalidation state, not the diff --git a/dom/canvas/WebGLFormats.cpp b/dom/canvas/WebGLFormats.cpp index b7e748e9114..41e09c79bb0 100644 --- a/dom/canvas/WebGLFormats.cpp +++ b/dom/canvas/WebGLFormats.cpp @@ -539,11 +539,14 @@ FormatUsageAuthority::CreateForWebGL1(gl::GLContext* gl) // RGBA8 is made renderable in WebGL 1.0, "Framebuffer Object Attachments" // render filter // able able - fnSet(EffectiveFormat::RGBA8 , true , true); - fnSet(EffectiveFormat::RGBA4 , true , true); - fnSet(EffectiveFormat::RGB5_A1, true , true); - fnSet(EffectiveFormat::RGB8 , false, true); - fnSet(EffectiveFormat::RGB565 , true , true); + fnSet(EffectiveFormat::RGBA8 , true, true); + fnSet(EffectiveFormat::RGBA4 , true, true); + fnSet(EffectiveFormat::RGB5_A1, true, true); + fnSet(EffectiveFormat::RGB565 , true, true); + + // RGB8 is not guaranteed to be renderable, but we should allow it for web-compat. + // Min-capability mode should mark this as non-renderable. + fnSet(EffectiveFormat::RGB8, true, true); fnSet(EffectiveFormat::Luminance8Alpha8, false, true); fnSet(EffectiveFormat::Luminance8 , false, true); diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 8810ca891f6..7ea8448414b 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -7,7 +7,7 @@ TEST_DIRS += ['compiledtest'] # Number changes to this file to avoid bug 1081323 (clobber after changing a manifest): -# 1 +# 2 MOCHITEST_MANIFESTS += [ 'test/crossorigin/mochitest.ini', @@ -34,6 +34,7 @@ EXPORTS.mozilla.dom += [ 'CanvasRenderingContextHelper.h', 'CanvasUtils.h', 'ImageBitmap.h', + 'ImageBitmapRenderingContext.h', 'ImageBitmapSource.h', 'ImageData.h', 'OffscreenCanvas.h', @@ -50,6 +51,7 @@ UNIFIED_SOURCES += [ 'DocumentRendererChild.cpp', 'DocumentRendererParent.cpp', 'ImageBitmap.cpp', + 'ImageBitmapRenderingContext.cpp', 'ImageData.cpp', 'OffscreenCanvas.cpp', ] diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index a18e4001bb1..2c446421fa5 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -26,6 +26,7 @@ class nsDisplayListBuilder; namespace mozilla { namespace layers { class CanvasLayer; +class Layer; class LayerManager; } // namespace layers namespace gfx { @@ -39,6 +40,7 @@ class nsICanvasRenderingContextInternal : { public: typedef mozilla::layers::CanvasLayer CanvasLayer; + typedef mozilla::layers::Layer Layer; typedef mozilla::layers::LayerManager LayerManager; NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID) @@ -129,9 +131,9 @@ public: // Return the CanvasLayer for this context, creating // one for the given layer manager if not available. - virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* builder, - CanvasLayer *oldLayer, - LayerManager *manager) = 0; + virtual already_AddRefed GetCanvasLayer(nsDisplayListBuilder* builder, + Layer *oldLayer, + LayerManager *manager) = 0; // Return true if the canvas should be forced to be "inactive" to ensure // it can be drawn to the screen even if it's too large to be blitted by diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 04c6b1c785c..a79506f87e3 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -218,6 +218,7 @@ skip-if = toolkit != 'cocoa' [test_2d.path.rect.zero.6.html] disabled = bug 407107 [test_2d.strokeRect.zero.5.html] +[test_bitmaprenderer.html] [test_bug232227.html] [test_bug613794.html] [test_bug753758.html] @@ -246,11 +247,13 @@ support-files = captureStream_common.js support-files = file_drawWindow_source.html file_drawWindow_common.js skip-if = (buildapp == 'b2g' && toolkit != 'gonk') [test_imagebitmap.html] +[test_imagebitmap_close.html] [test_imagebitmap_cropping.html] [test_imagebitmap_on_worker.html] [test_imagebitmap_structuredclone.html] [test_imagebitmap_structuredclone_iframe.html] [test_imagebitmap_structuredclone_window.html] +[test_imagebitmap_transfer.html] [test_ImageData_ctor.html] [test_isPointInStroke.html] [test_mozDashOffset.html] @@ -267,6 +270,10 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965 [test_createPattern_broken.html] [test_setlinedash.html] [test_filter.html] +[test_offscreencanvas_toblob.html] +tags = offscreencanvas +[test_offscreencanvas_toimagebitmap.html] +tags = offscreencanvas [test_offscreencanvas_basic_webgl.html] tags = offscreencanvas [test_offscreencanvas_dynamic_fallback.html] diff --git a/dom/canvas/test/offscreencanvas.js b/dom/canvas/test/offscreencanvas.js index 6dec8220f46..f530bc280ca 100644 --- a/dom/canvas/test/offscreencanvas.js +++ b/dom/canvas/test/offscreencanvas.js @@ -1,27 +1,49 @@ /* WebWorker for test_offscreencanvas_*.html */ +(function(){ + var port = null; -function ok(expect, msg) { - if (port) { - port.postMessage({type: "test", result: !!expect, name: msg}); - } else { - postMessage({type: "test", result: !!expect, name: msg}); +function isInWorker() { + try { + return !(self instanceof Window); + } catch (e) { + return true; } } +function postMessageGeneral(data) { + if (isInWorker()) { + if (port) { + port.postMessage(data); + } else { + postMessage(data); + } + } else { + postMessage(data, "*"); + } +} + +function ok(expect, msg) { + postMessageGeneral({type: "test", result: !!expect, name: msg}); +} + function finish() { - if (port) { - port.postMessage({type: "finish"}); - } else { - postMessage({type: "finish"}); - } + postMessageGeneral({type: "finish"}); } function drawCount(count) { + postMessageGeneral({type: "draw", count: count}); +} + +function sendBlob(blob) { + postMessageGeneral({type: "blob", blob: blob}); +} + +function sendImageBitmap(img) { if (port) { - port.postMessage({type: "draw", count: count}); + port.postMessage({type: "imagebitmap", bitmap: img}); } else { - postMessage({type: "draw", count: count}); + postMessage({type: "imagebitmap", bitmap: img}); } } @@ -140,7 +162,7 @@ function createDrawFunc(canvas) { // Start drawing checkGLError('after setup'); - return function(prefix) { + return function(prefix, needCommitFrame) { if (prefix) { prefix = "[" + prefix + "] "; } else { @@ -152,7 +174,9 @@ function createDrawFunc(canvas) { preDraw(prefix); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); postDraw(prefix); - gl.commit(); + if (needCommitFrame) { + gl.commit(); + } checkGLError(prefix); }; } @@ -161,6 +185,9 @@ function createDrawFunc(canvas) { function entryFunction(testStr, subtests, offscreenCanvas) { var test = testStr; var canvas = offscreenCanvas; + if (test == "webgl_imagebitmap") { + canvas = new OffscreenCanvas(64, 64); + } if (test != "subworker") { ok(canvas, "Canvas successfully transfered to worker"); @@ -190,7 +217,7 @@ function entryFunction(testStr, subtests, offscreenCanvas) { finish(); return; } - draw("loop " +count); + draw("loop " +count, true); }, 0); } //------------------------------------------------------------------------ @@ -205,11 +232,38 @@ function entryFunction(testStr, subtests, offscreenCanvas) { var count = 0; var iid = setInterval(function() { ++count; - draw("loop " + count); + draw("loop " + count, true); drawCount(count); }, 0); } //------------------------------------------------------------------------ + // Test toBlob + //------------------------------------------------------------------------ + else if (test == "webgl_toblob") { + draw = createDrawFunc(canvas); + if (!draw) { + return; + } + + draw("", false); + canvas.toBlob().then(function(blob) { + sendBlob(blob); + }); + } + //------------------------------------------------------------------------ + // Test toImageBitmap + //------------------------------------------------------------------------ + else if (test == "webgl_imagebitmap") { + draw = createDrawFunc(canvas); + if (!draw) { + return; + } + + draw("", false); + var imgBitmap = canvas.transferToImageBitmap(); + sendImageBitmap(imgBitmap); + } + //------------------------------------------------------------------------ // Canvas Size Change from Worker //------------------------------------------------------------------------ else if (test == "webgl_changesize") { @@ -219,22 +273,22 @@ function entryFunction(testStr, subtests, offscreenCanvas) { return; } - draw("64x64"); + draw("64x64", true); setTimeout(function() { canvas.width = 128; canvas.height = 128; - draw("Increased to 128x128"); + draw("Increased to 128x128", true); setTimeout(function() { canvas.width = 32; canvas.width = 32; - draw("Decreased to 32x32"); + draw("Decreased to 32x32", true); setTimeout(function() { canvas.width = 64; canvas.height = 64; - draw("Increased to 64x64"); + draw("Increased to 64x64", true); ok(true, "Worker is done"); finish(); @@ -297,3 +351,9 @@ onconnect = function(evt) { port.start(); }; + +if (!isInWorker()) { + window.entryFunction = entryFunction; +} + +})(); diff --git a/dom/canvas/test/test_bitmaprenderer.html b/dom/canvas/test/test_bitmaprenderer.html new file mode 100644 index 00000000000..246b3d2c697 --- /dev/null +++ b/dom/canvas/test/test_bitmaprenderer.html @@ -0,0 +1,163 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + + diff --git a/dom/canvas/test/test_imagebitmap_close.html b/dom/canvas/test/test_imagebitmap_close.html new file mode 100644 index 00000000000..86e14d67d38 --- /dev/null +++ b/dom/canvas/test/test_imagebitmap_close.html @@ -0,0 +1,93 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + + diff --git a/dom/canvas/test/test_imagebitmap_transfer.html b/dom/canvas/test/test_imagebitmap_transfer.html new file mode 100644 index 00000000000..360f6133551 --- /dev/null +++ b/dom/canvas/test/test_imagebitmap_transfer.html @@ -0,0 +1,111 @@ + +Test ImageBitmap : Transfer + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_toblob.html b/dom/canvas/test/test_offscreencanvas_toblob.html new file mode 100644 index 00000000000..d5cc2c02de6 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_toblob.html @@ -0,0 +1,91 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + + + + diff --git a/dom/canvas/test/test_offscreencanvas_toimagebitmap.html b/dom/canvas/test/test_offscreencanvas_toimagebitmap.html new file mode 100644 index 00000000000..a7dd30eab47 --- /dev/null +++ b/dom/canvas/test/test_offscreencanvas_toimagebitmap.html @@ -0,0 +1,69 @@ + + + +WebGL in OffscreenCanvas + + + + + + + + + + diff --git a/dom/canvas/test/webgl-mochitest.ini b/dom/canvas/test/webgl-mochitest.ini index d843d2df466..8e165c751b9 100644 --- a/dom/canvas/test/webgl-mochitest.ini +++ b/dom/canvas/test/webgl-mochitest.ini @@ -13,7 +13,6 @@ fail-if = (os == 'b2g') support-files = captureStream_common.js [webgl-mochitest/test_cubemap_must_be_square.html] [webgl-mochitest/test_depth_tex_lazy_clear.html] -skip-if = 1 [webgl-mochitest/test_draw.html] [webgl-mochitest/test_fb_param.html] [webgl-mochitest/test_fb_param_crash.html] diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 0e8a449f8ac..a07df8fa6a9 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -374,7 +374,8 @@ HTMLCanvasElement::~HTMLCanvasElement() NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement, mCurrentContext, mPrintCallback, - mPrintState, mOriginalCanvas) + mPrintState, mOriginalCanvas, + mOffscreenCanvas) NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element) NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element) @@ -779,10 +780,17 @@ HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv) renderer->SetWidth(sz.width); renderer->SetHeight(sz.height); - mOffscreenCanvas = new OffscreenCanvas(sz.width, + nsCOMPtr global = + do_QueryInterface(OwnerDoc()->GetInnerWindow()); + mOffscreenCanvas = new OffscreenCanvas(global, + sz.width, sz.height, GetCompositorBackendType(), renderer); + if (mWriteOnly) { + mOffscreenCanvas->SetWriteOnly(); + } + if (!mContextObserver) { mContextObserver = new HTMLCanvasElementObserver(this); } @@ -1038,9 +1046,9 @@ HTMLCanvasElement::GetOpaqueAttr() return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque); } -already_AddRefed +already_AddRefed HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, + Layer *aOldLayer, LayerManager *aManager) { // The address of sOffscreenCanvasLayerUserDataDummy is used as the user @@ -1056,7 +1064,7 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, if (mOffscreenCanvas) { if (!mResetLayer && aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) { - RefPtr ret = aOldLayer; + RefPtr ret = aOldLayer; return ret.forget(); } @@ -1173,7 +1181,7 @@ void HTMLCanvasElement::SetFrameCapture(already_AddRefed aSurface) { RefPtr surface = aSurface; - RefPtr image = new CairoImage(surface->GetSize(), surface); + RefPtr image = new SourceSurfaceImage(surface->GetSize(), surface); // Loop backwards to allow removing elements in the loop. for (int i = mRequestedFrameListeners.Length() - 1; i >= 0; --i) { diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 1d11a27706e..c7c30ef79af 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -31,6 +31,7 @@ namespace layers { class AsyncCanvasRenderer; class CanvasLayer; class Image; +class Layer; class LayerManager; } // namespace layers namespace gfx { @@ -120,6 +121,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement, typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer; typedef layers::CanvasLayer CanvasLayer; + typedef layers::Layer Layer; typedef layers::LayerManager LayerManager; public: @@ -308,9 +310,9 @@ public: * Helpers called by various users of Canvas */ - already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, - CanvasLayer *aOldLayer, - LayerManager *aManager); + already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + Layer *aOldLayer, + LayerManager *aManager); // Should return true if the canvas layer should always be marked inactive. // We should return true here if we can't do accelerated compositing with // a non-BasicCanvasLayer. diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 9ed2f3f134c..b2257eb1854 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -996,7 +996,7 @@ HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode, mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue); } - if (!mInDocResponsiveContent) { + if (!mInDocResponsiveContent && IsInComposedDoc()) { nsIDocument* doc = GetOurOwnerDoc(); if (doc) { doc->AddResponsiveContent(this); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index aaca0823c4f..ecad501e664 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -295,20 +295,25 @@ NS_IMPL_ISUPPORTS(UploadLastDir::ContentPrefCallback, nsIContentPrefCallback2) NS_IMETHODIMP UploadLastDir::ContentPrefCallback::HandleCompletion(uint16_t aReason) { - nsCOMPtr localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); - NS_ENSURE_STATE(localFile); + nsCOMPtr localFile; + nsAutoString prefStr; - if (aReason == nsIContentPrefCallback2::COMPLETE_ERROR || - !mResult) { - // Default to "desktop" directory for each platform - nsCOMPtr homeDir; - NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir)); - localFile = do_QueryInterface(homeDir); - } else { - nsAutoString prefStr; - nsCOMPtr pref; - mResult->GetValue(getter_AddRefs(pref)); - pref->GetAsAString(prefStr); + if (aReason == nsIContentPrefCallback2::COMPLETE_ERROR || !mResult) { + prefStr = Preferences::GetString("dom.input.fallbackUploadDir"); + if (prefStr.IsEmpty()) { + // If no custom directory was set through the pref, default to + // "desktop" directory for each platform. + NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(localFile)); + } + } + + if (!localFile) { + if (prefStr.IsEmpty() && mResult) { + nsCOMPtr pref; + mResult->GetValue(getter_AddRefs(pref)); + pref->GetAsAString(prefStr); + } + localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); localFile->InitWithPath(prefStr); } diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 340a2654481..c25fef89f41 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -600,3 +600,5 @@ skip-if = buildapp == 'b2g' # bug 1129014 [test_image_clone_load.html] [test_bug1203668.html] [test_bug1166138.html] +[test_filepicker_default_directory.html] +skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' diff --git a/dom/html/test/test_filepicker_default_directory.html b/dom/html/test/test_filepicker_default_directory.html new file mode 100644 index 00000000000..c2212baa04b --- /dev/null +++ b/dom/html/test/test_filepicker_default_directory.html @@ -0,0 +1,83 @@ + + + + + Test for filepicker default directory + + + + + +Mozilla Bug 1194893 +
+ +
+
+
+
+ + diff --git a/dom/ipc/StructuredCloneData.cpp b/dom/ipc/StructuredCloneData.cpp index 10919290bf6..8ae867ca4b2 100644 --- a/dom/ipc/StructuredCloneData.cpp +++ b/dom/ipc/StructuredCloneData.cpp @@ -44,7 +44,7 @@ StructuredCloneData::Copy(const StructuredCloneData& aData) MOZ_ASSERT(BlobImpls().IsEmpty()); BlobImpls().AppendElements(aData.BlobImpls()); - MOZ_ASSERT(GetImages().IsEmpty()); + MOZ_ASSERT(GetSurfaces().IsEmpty()); return true; } diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 49113f7c3bd..d3fba3552b0 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -790,6 +790,7 @@ MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType) UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */); + MOZ_ASSERT(!mIsDormant, "should be out of dormant by now"); MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value."); int64_t timeUsecs = 0; diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 53aa9c9c994..5e2013147e6 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -782,6 +782,17 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, self->WaitRequestRef(aRejection.mType).Complete(); })); + // We are out of data to decode and will enter buffering mode soon. + // We want to play the frames we have already decoded, so we stop pre-rolling + // and ensure that loadeddata is fired as required. + if (isAudio) { + StopPrerollingAudio(); + } else { + StopPrerollingVideo(); + } + if (mState == DECODER_STATE_BUFFERING || mState == DECODER_STATE_DECODING) { + MaybeFinishDecodeFirstFrame(); + } return; } @@ -1481,7 +1492,7 @@ MediaDecoderStateMachine::Seek(SeekTarget aTarget) return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__); } - NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA, + MOZ_ASSERT(mState > DECODER_STATE_DECODING_METADATA, "We should have got duration already"); if (mState < DECODER_STATE_DECODING || diff --git a/dom/media/MediaEventSource.h b/dom/media/MediaEventSource.h index cff00190e55..26c4cca4ad8 100644 --- a/dom/media/MediaEventSource.h +++ b/dom/media/MediaEventSource.h @@ -9,6 +9,7 @@ #include "mozilla/AbstractThread.h" #include "mozilla/Atomics.h" +#include "mozilla/IndexSequence.h" #include "mozilla/Mutex.h" #include "mozilla/Tuple.h" #include "mozilla/TypeTraits.h" diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 097cfcffd6a..aea7bcdb8e1 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -546,6 +546,9 @@ MediaFormatReader::OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure NotifyError(aTrack); break; case DemuxerFailureReason::WAITING_FOR_DATA: + if (!decoder.mWaitingForData) { + decoder.mNeedDraining = true; + } NotifyWaitingForData(aTrack); break; case DemuxerFailureReason::CANCELED: @@ -691,6 +694,9 @@ MediaFormatReader::NotifyWaitingForData(TrackType aTrack) MOZ_ASSERT(OnTaskQueue()); auto& decoder = GetDecoderData(aTrack); decoder.mWaitingForData = true; + if (decoder.mTimeThreshold) { + decoder.mTimeThreshold.ref().mWaiting = true; + } ScheduleUpdate(aTrack); } @@ -760,18 +766,32 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) if (!decoder.mReceivedNewData) { return false; } - decoder.mReceivedNewData = false; - decoder.mWaitingForData = false; - bool hasLastEnd; - media::TimeUnit lastEnd = decoder.mTimeRanges.GetEnd(&hasLastEnd); + // Update our cached TimeRange. decoder.mTimeRanges = decoder.mTrackDemuxer->GetBuffered(); - if (decoder.mTimeRanges.Length() && - (!hasLastEnd || decoder.mTimeRanges.GetEnd() > lastEnd)) { - // New data was added after our previous end, we can clear the EOS flag. - decoder.mDemuxEOS = false; + + if (decoder.mDrainComplete || decoder.mDraining) { + // We do not want to clear mWaitingForData or mDemuxEOS while + // a drain is in progress in order to properly complete the operation. + return false; } + bool hasLastEnd; + media::TimeUnit lastEnd = decoder.mTimeRanges.GetEnd(&hasLastEnd); + if (hasLastEnd) { + if (decoder.mLastTimeRangesEnd && decoder.mLastTimeRangesEnd.ref() > lastEnd) { + // New data was added after our previous end, we can clear the EOS flag. + decoder.mDemuxEOS = false; + } + decoder.mLastTimeRangesEnd = Some(lastEnd); + } + + decoder.mReceivedNewData = false; + if (decoder.mTimeThreshold) { + decoder.mTimeThreshold.ref().mWaiting = false; + } + decoder.mWaitingForData = false; + if (decoder.mError) { return false; } @@ -808,6 +828,8 @@ MediaFormatReader::RequestDemuxSamples(TrackType aTrack) if (decoder.mDemuxEOS) { // Nothing left to demux. + // We do not want to attempt to demux while in waiting for data mode + // as it would retrigger an unecessary drain. return; } @@ -883,6 +905,7 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, info->GetID()); decoder.mInfo = info; decoder.mLastStreamSourceID = info->GetID(); + decoder.mNextStreamSourceID.reset(); // Flush will clear our array of queued samples. So make a copy now. nsTArray> samples{decoder.mQueuedSamples}; Flush(aTrack); @@ -892,38 +915,11 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, decoder.mQueuedSamples.AppendElements(Move(samples)); NotifyDecodingRequested(aTrack); } else { - MOZ_ASSERT(decoder.mTimeThreshold.isNothing()); + SeekTarget seekTarget = + decoder.mTimeThreshold.refOr(SeekTarget(TimeUnit::FromMicroseconds(sample->mTime), false)); LOG("Stream change occurred on a non-keyframe. Seeking to:%lld", - sample->mTime); - decoder.mTimeThreshold = Some(TimeUnit::FromMicroseconds(sample->mTime)); - RefPtr self = this; - decoder.ResetDemuxer(); - decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref()) - ->Then(OwnerThread(), __func__, - [self, aTrack] (media::TimeUnit aTime) { - auto& decoder = self->GetDecoderData(aTrack); - decoder.mSeekRequest.Complete(); - self->NotifyDecodingRequested(aTrack); - }, - [self, aTrack] (DemuxerFailureReason aResult) { - auto& decoder = self->GetDecoderData(aTrack); - decoder.mSeekRequest.Complete(); - switch (aResult) { - case DemuxerFailureReason::WAITING_FOR_DATA: - self->NotifyWaitingForData(aTrack); - break; - case DemuxerFailureReason::END_OF_STREAM: - self->NotifyEndOfStream(aTrack); - break; - case DemuxerFailureReason::CANCELED: - case DemuxerFailureReason::SHUTDOWN: - break; - default: - self->NotifyError(aTrack); - break; - } - decoder.mTimeThreshold.reset(); - })); + seekTarget.mTime.ToMicroseconds()); + InternalSeek(aTrack, seekTarget); } return; } @@ -957,6 +953,42 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, decoder.mInputExhausted = false; } +void +MediaFormatReader::InternalSeek(TrackType aTrack, const SeekTarget& aTarget) +{ + MOZ_ASSERT(OnTaskQueue()); + auto& decoder = GetDecoderData(aTrack); + decoder.mTimeThreshold = Some(aTarget); + RefPtr self = this; + decoder.ResetDemuxer(); + decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().mTime) + ->Then(OwnerThread(), __func__, + [self, aTrack] (media::TimeUnit aTime) { + auto& decoder = self->GetDecoderData(aTrack); + decoder.mSeekRequest.Complete(); + self->NotifyDecodingRequested(aTrack); + }, + [self, aTrack] (DemuxerFailureReason aResult) { + auto& decoder = self->GetDecoderData(aTrack); + decoder.mSeekRequest.Complete(); + switch (aResult) { + case DemuxerFailureReason::WAITING_FOR_DATA: + self->NotifyWaitingForData(aTrack); + break; + case DemuxerFailureReason::END_OF_STREAM: + self->NotifyEndOfStream(aTrack); + break; + case DemuxerFailureReason::CANCELED: + case DemuxerFailureReason::SHUTDOWN: + break; + default: + self->NotifyError(aTrack); + break; + } + decoder.mTimeThreshold.reset(); + })); +} + void MediaFormatReader::DrainDecoder(TrackType aTrack) { @@ -992,7 +1024,6 @@ MediaFormatReader::Update(TrackType aTrack) LOGV("Processing update for %s", TrackTypeToStr(aTrack)); - bool needInput = false; bool needOutput = false; auto& decoder = GetDecoderData(aTrack); decoder.mUpdateScheduled = false; @@ -1006,65 +1037,79 @@ MediaFormatReader::Update(TrackType aTrack) return; } - if (!decoder.HasPromise() && decoder.mWaitingForData) { - // Nothing more we can do at present. - LOGV("Still waiting for data."); - return; - } - // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder); - if (aTrack == TrackInfo::kVideoTrack) { - uint64_t delta = - decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames; - a.mDecoded = static_cast(delta); - mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal; + // Drop any frames found prior our internal seek target. + while (decoder.mTimeThreshold && decoder.mOutput.Length()) { + RefPtr& output = decoder.mOutput[0]; + SeekTarget target = decoder.mTimeThreshold.ref(); + media::TimeUnit time = media::TimeUnit::FromMicroseconds(output->mTime); + if (time >= target.mTime) { + // We have reached our internal seek target. + decoder.mTimeThreshold.reset(); + } + if (time < target.mTime || target.mDropTarget) { + LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)", + TrackTypeToStr(aTrack), + media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(), + target.mTime.ToSeconds(), + output->mKeyframe); + decoder.mOutput.RemoveElementAt(0); + } } if (decoder.HasPromise()) { needOutput = true; - if (!decoder.mOutput.IsEmpty()) { + if (decoder.mOutput.Length()) { // We have a decoded sample ready to be returned. if (aTrack == TrackType::kVideoTrack) { + uint64_t delta = + decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames; + a.mDecoded = static_cast(delta); + mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal; nsCString error; mVideo.mIsHardwareAccelerated = mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error); } - while (decoder.mOutput.Length()) { - RefPtr output = decoder.mOutput[0]; - decoder.mOutput.RemoveElementAt(0); - decoder.mSizeOfQueue -= 1; - if (decoder.mTimeThreshold.isNothing() || - media::TimeUnit::FromMicroseconds(output->mTime) >= decoder.mTimeThreshold.ref()) { - ReturnOutput(output, aTrack); - decoder.mTimeThreshold.reset(); - break; - } else { - LOGV("Internal Seeking: Dropping frame time:%f wanted:%f (kf:%d)", - media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(), - decoder.mTimeThreshold.ref().ToSeconds(), - output->mKeyframe); - } - } - } else if (decoder.mDrainComplete) { - decoder.mDrainComplete = false; - decoder.mDraining = false; - if (decoder.mError) { - LOG("Decoding Error"); - decoder.RejectPromise(DECODE_ERROR, __func__); - return; - } else if (decoder.mDemuxEOS) { - decoder.RejectPromise(END_OF_STREAM, __func__); - } + RefPtr output = decoder.mOutput[0]; + decoder.mOutput.RemoveElementAt(0); + decoder.mSizeOfQueue -= 1; + decoder.mLastSampleTime = + Some(media::TimeUnit::FromMicroseconds(output->mTime)); + ReturnOutput(output, aTrack); } else if (decoder.mError) { + LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack)); decoder.RejectPromise(DECODE_ERROR, __func__); return; - } else if (decoder.mWaitingForData) { - LOG("Waiting For Data"); - decoder.RejectPromise(WAITING_FOR_DATA, __func__); - return; + } else if (decoder.mDrainComplete) { + bool wasDraining = decoder.mDraining; + decoder.mDrainComplete = false; + decoder.mDraining = false; + if (decoder.mDemuxEOS) { + LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack)); + decoder.RejectPromise(END_OF_STREAM, __func__); + } else if (decoder.mWaitingForData) { + if (wasDraining && decoder.mLastSampleTime && + !decoder.mNextStreamSourceID) { + // We have completed draining the decoder following WaitingForData. + // Set up the internal seek machinery to be able to resume from the + // last sample decoded. + LOG("Seeking to last sample time: %lld", + decoder.mLastSampleTime.ref().ToMicroseconds()); + InternalSeek(aTrack, SeekTarget(decoder.mLastSampleTime.ref(), true)); + } + LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack)); + decoder.RejectPromise(WAITING_FOR_DATA, __func__); + } + // Now that draining has completed, we check if we have received + // new data again as the result may now be different from the earlier + // run. + if (UpdateReceivedNewData(aTrack)) { + LOGV("Nothing more to do"); + return; + } } } @@ -1073,20 +1118,27 @@ MediaFormatReader::Update(TrackType aTrack) return; } - if (!NeedInput(decoder)) { + bool needInput = NeedInput(decoder); + + LOGV("Update(%s) ni=%d no=%d ie=%d, in:%llu out:%llu qs=%u pending:%u waiting:%d ahead:%d sid:%u", + TrackTypeToStr(aTrack), needInput, needOutput, decoder.mInputExhausted, + decoder.mNumSamplesInput, decoder.mNumSamplesOutput, + uint32_t(size_t(decoder.mSizeOfQueue)), uint32_t(decoder.mOutput.Length()), + decoder.mWaitingForData, !decoder.HasPromise(), decoder.mLastStreamSourceID); + + if (decoder.mWaitingForData && + (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) { + // Nothing more we can do at present. + LOGV("Still waiting for data."); + return; + } + + if (!needInput) { LOGV("No need for additional input (pending:%u)", uint32_t(decoder.mOutput.Length())); return; } - needInput = true; - - LOGV("Update(%s) ni=%d no=%d ie=%d, in:%llu out:%llu qs=%u pending:%u ahead:%d sid:%u", - TrackTypeToStr(aTrack), needInput, needOutput, decoder.mInputExhausted, - decoder.mNumSamplesInput, decoder.mNumSamplesOutput, - uint32_t(size_t(decoder.mSizeOfQueue)), uint32_t(decoder.mOutput.Length()), - !decoder.HasPromise(), decoder.mLastStreamSourceID); - // Demux samples if we don't have some. RequestDemuxSamples(aTrack); diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index eb2437b480e..c2e4680dccd 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -127,6 +127,22 @@ private: // Decode any pending already demuxed samples. bool DecodeDemuxedSamples(TrackType aTrack, MediaRawData* aSample); + + struct SeekTarget { + SeekTarget(const media::TimeUnit& aTime, bool aDropTarget) + : mTime(aTime) + , mDropTarget(aDropTarget) + , mWaiting(false) + {} + + media::TimeUnit mTime; + bool mDropTarget; + bool mWaiting; + }; + // Perform an internal seek to aTime. If aDropTarget is true then + // the first sample past the target will be dropped. + void InternalSeek(TrackType aTrack, const SeekTarget& aTarget); + // Drain the current decoder. void DrainDecoder(TrackType aTrack); void NotifyNewOutput(TrackType aTrack, MediaData* aSample); @@ -261,8 +277,11 @@ private: bool mDraining; bool mDrainComplete; // If set, all decoded samples prior mTimeThreshold will be dropped. - // Used for internal seeking when a change of stream is detected. - Maybe mTimeThreshold; + // Used for internal seeking when a change of stream is detected or when + // encountering data discontinuity. + Maybe mTimeThreshold; + // Time of last sample returned. + Maybe mLastSampleTime; // Decoded samples returned my mDecoder awaiting being returned to // state machine upon request. @@ -300,6 +319,7 @@ private: mDraining = false; mDrainComplete = false; mTimeThreshold.reset(); + mLastSampleTime.reset(); mOutput.Clear(); mNumSamplesInput = 0; mNumSamplesOutput = 0; @@ -316,6 +336,7 @@ private: uint32_t mLastStreamSourceID; Maybe mNextStreamSourceID; media::TimeIntervals mTimeRanges; + Maybe mLastTimeRangesEnd; RefPtr mInfo; }; diff --git a/dom/media/mediasink/DecodedStream.cpp b/dom/media/mediasink/DecodedStream.cpp index e0913d27cd0..83076bded47 100644 --- a/dom/media/mediasink/DecodedStream.cpp +++ b/dom/media/mediasink/DecodedStream.cpp @@ -480,7 +480,10 @@ DecodedStream::CreateData(MozPromiseHolder&& aPromise) self->mOutputStreamManager.Disconnect(); delete data; }); - AbstractThread::MainThread()->Dispatch(r.forget()); + // We are in tail dispatching phase. Don't call + // AbstractThread::MainThread()->Dispatch() to avoid reentrant + // AutoTaskDispatcher. + NS_DispatchToMainThread(r.forget()); } } RefPtr mThis; diff --git a/dom/media/mediasink/VideoSink.cpp b/dom/media/mediasink/VideoSink.cpp index ffa1c746f37..9a2fb741f2d 100644 --- a/dom/media/mediasink/VideoSink.cpp +++ b/dom/media/mediasink/VideoSink.cpp @@ -4,6 +4,7 @@ * 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 "MediaQueue.h" #include "VideoSink.h" namespace mozilla { diff --git a/dom/media/mediasource/MediaSourceDemuxer.cpp b/dom/media/mediasource/MediaSourceDemuxer.cpp index 4011ce77339..c7f96f557f2 100644 --- a/dom/media/mediasource/MediaSourceDemuxer.cpp +++ b/dom/media/mediasource/MediaSourceDemuxer.cpp @@ -295,7 +295,7 @@ MediaSourceTrackDemuxer::MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent, , mManager(aManager) , mType(aType) , mMonitor("MediaSourceTrackDemuxer") - , mLastSeek(Some(TimeUnit())) + , mReset(true) { } @@ -328,7 +328,8 @@ MediaSourceTrackDemuxer::Reset() RefPtr self = this; nsCOMPtr task = NS_NewRunnableFunction([self] () { - self->mLastSeek = Some(TimeUnit()); + self->mNextSample.reset(); + self->mReset = true; self->mManager->Seek(self->mType, TimeUnit(), TimeUnit()); { MonitorAutoLock mon(self->mMonitor); @@ -380,49 +381,58 @@ MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime) buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); if (!buffered.Contains(aTime)) { - mLastSeek = Some(aTime); // We don't have the data to seek to. return SeekPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } TimeUnit seekTime = mManager->Seek(mType, aTime, MediaSourceDemuxer::EOS_FUZZ); + bool error; + RefPtr sample = + mManager->GetSample(mType, + media::TimeUnit(), + error); + MOZ_ASSERT(!error && sample); + mNextSample = Some(sample); + mReset = false; { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType); } - mLastSeek = Some(aTime); return SeekPromise::CreateAndResolve(seekTime, __func__); } RefPtr MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) { - if (mLastSeek) { + if (mReset) { // If a seek (or reset) was recently performed, we ensure that the data // we are about to retrieve is still available. TimeIntervals buffered = mManager->Buffered(mType); buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); - if (!buffered.Contains(mLastSeek.ref())) { + if (!buffered.Contains(TimeUnit::FromMicroseconds(0))) { return SamplesPromise::CreateAndReject( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - mLastSeek.reset(); + mReset = false; } - bool error; - RefPtr sample = - mManager->GetSample(mType, - MediaSourceDemuxer::EOS_FUZZ, - error); - if (!sample) { - if (error) { - return SamplesPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); + bool error = false; + RefPtr sample; + if (mNextSample) { + sample = mNextSample.ref(); + mNextSample.reset(); + } else { + sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, error); + if (!sample) { + if (error) { + return SamplesPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); + } + return SamplesPromise::CreateAndReject( + mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : + DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - return SamplesPromise::CreateAndReject( - mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : - DemuxerFailureReason::WAITING_FOR_DATA, __func__); } RefPtr samples = new SamplesHolder; samples->mSamples.AppendElement(sample); diff --git a/dom/media/mediasource/MediaSourceDemuxer.h b/dom/media/mediasource/MediaSourceDemuxer.h index f32746210d5..8be870cbf62 100644 --- a/dom/media/mediasource/MediaSourceDemuxer.h +++ b/dom/media/mediasource/MediaSourceDemuxer.h @@ -129,7 +129,10 @@ private: // Monitor protecting members below accessed from multiple threads. Monitor mMonitor; media::TimeUnit mNextRandomAccessPoint; - Maybe mLastSeek; + Maybe> mNextSample; + // Set to true following a reset. Ensure that the next sample demuxed + // is available at position 0. + bool mReset; }; } // namespace mozilla diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index c5cb728726b..f4d21ee2430 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -40,7 +40,9 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) [test_BufferingWait.html] skip-if = toolkit == 'android' #timeout android bug 1199531 [test_BufferingWait_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ +[test_DrainOnMissingData_mp4.html] +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_EndOfStream.html] skip-if = (true || toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187 and bug 1182946 [test_EndOfStream_mp4.html] @@ -51,7 +53,7 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) [test_FrameSelection.html] [test_HaveMetadataUnbufferedSeek.html] [test_HaveMetadataUnbufferedSeek_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_LoadedDataFired_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_LoadedMetadataFired.html] @@ -98,11 +100,11 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_TruncatedDuration.html] [test_TruncatedDuration_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_WaitingOnMissingData.html] skip-if = true # Disabled due to bug 1124493 and friends. WebM MSE is deprioritized. [test_WaitingOnMissingData_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_WaitingToEndedTransition_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ diff --git a/dom/media/mediasource/test/test_BufferingWait.html b/dom/media/mediasource/test/test_BufferingWait.html index 77527b4bcf9..117ab07bea1 100644 --- a/dom/media/mediasource/test/test_BufferingWait.html +++ b/dom/media/mediasource/test/test_BufferingWait.html @@ -41,14 +41,15 @@ runWithMSE(function(ms, v) { /* Note - Missing |46712, 67833 - 46712| segment here corresponding to (0.8, 1.2] */ /* Note - Missing |67833, 88966 - 67833| segment here corresponding to (1.2, 1.6] */ loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 88966))).then(function() { - var promise = waitUntilTime(0.27); + // 0.767 is the time of the last video sample +- 40ms. + var promise = waitUntilTime(.767-0.04); info("Playing video. It should play for a bit, then fire 'waiting'"); v.play(); return promise; }).then(function() { window.firstStop = Date.now(); loadSegment(sb, new Uint8Array(arrayBuffer, 46712, 67833 - 46712)); - return waitUntilTime(0.66); + return waitUntilTime(1.167-0.04); }).then(function() { var waitDuration = (Date.now() - window.firstStop) / 1000; ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration); diff --git a/dom/media/mediasource/test/test_BufferingWait_mp4.html b/dom/media/mediasource/test/test_BufferingWait_mp4.html index 289b915d838..db04f4e0b19 100644 --- a/dom/media/mediasource/test/test_BufferingWait_mp4.html +++ b/dom/media/mediasource/test/test_BufferingWait_mp4.html @@ -41,18 +41,16 @@ runWithMSE(function(ms, v) { /* Note - Missing |bipbop4| segment here corresponding to (2.41, 3.20] */ .then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop', ['5'], '.m4s')) .then(function() { - // Some decoders (Windows in particular) may keep up to 25 frames queued - // before returning a sample. 0.7 is 1.62s - 25 * 0.03333 - var promise = waitUntilTime(0.7); + // last audio sample has a start time of 1.578956s + var promise = waitUntilTime(1.57895); info("Playing video. It should play for a bit, then fire 'waiting'"); v.play(); return promise; }).then(function() { window.firstStop = Date.now(); fetchAndLoad(sb, 'bipbop/bipbop', ['3'], '.m4s'); - // Some decoders (Windows in particular) may keep up to 25 frames queued - // before returning a sample. 1.5 is 2.41s - 25 * 0.03333 - return waitUntilTime(1.5); + // last audio sample has a start time of 2.368435 + return waitUntilTime(2.36843); }).then(function() { var waitDuration = (Date.now() - window.firstStop) / 1000; ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration); diff --git a/dom/media/mediasource/test/test_DrainOnMissingData_mp4.html b/dom/media/mediasource/test/test_DrainOnMissingData_mp4.html new file mode 100644 index 00000000000..f2284377f69 --- /dev/null +++ b/dom/media/mediasource/test/test_DrainOnMissingData_mp4.html @@ -0,0 +1,60 @@ + + + + MSE: |waiting| event when source data is missing + + + + + +

+
+ + diff --git a/dom/media/mediasource/test/test_PlayEvents.html b/dom/media/mediasource/test/test_PlayEvents.html index 1f6f1ad11a0..a390ae247b7 100644 --- a/dom/media/mediasource/test/test_PlayEvents.html +++ b/dom/media/mediasource/test/test_PlayEvents.html @@ -24,6 +24,18 @@ SimpleTest.waitForExplicitFinish(); runWithMSE(function(ms, el) { el.controls = true; once(ms, 'sourceopen').then(function() { + // Log events for debugging. + var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata", + "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort", + "waiting", "pause", "durationchange", "seeking", "seeked"]; + function logEvent(e) { + var v = e.target; + info("got " + e.type + " event"); + } + events.forEach(function(e) { + el.addEventListener(e, logEvent, false); + }); + ok(true, "Receive a sourceopen event"); var videosb = ms.addSourceBuffer("video/mp4"); el.addEventListener("error", function(e) { @@ -37,9 +49,6 @@ runWithMSE(function(ms, el) { var promises = []; promises.push(once(el, 'loadeddata')); promises.push(once(el, 'canplay')); - // Load [0, 1.601666). We must ensure that we load over 25 frames as the - // windows H264 decoder will not produce a sample until then - // (bug 1191138). promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(1, 3), '.m4s')); return Promise.all(promises); }) diff --git a/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html b/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html index b9d52daba95..79344c772bf 100644 --- a/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html +++ b/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html @@ -40,9 +40,9 @@ runWithMSE(function(ms, el) { // currentTime is based on the current video frame, so if the audio ends just before // the next video frame, currentTime can be up to 1 frame's worth earlier than // min(audioEnd, videoEnd). - // Some decoders (Windows in particular) may keep up to 25 frames queued. - isfuzzy(el.currentTime, Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 1/60, - 25 * 1/30, "Got a waiting event at " + el.currentTime); + // 0.0465 is the length of the last audio frame. + ok(el.currentTime >= (Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 0.0465), + "Got a waiting event at " + el.currentTime); info("Loading more data"); var p = once(el, 'ended'); var loads = Promise.all([fetchAndLoad(audiosb, 'bipbop/bipbop_audio', [5], '.m4s'), diff --git a/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html index 185d3e6242b..f932b3d4e72 100644 --- a/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html +++ b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html @@ -17,6 +17,10 @@ runWithMSE(function(ms, el) { ok(true, "Receive a sourceopen event"); var audiosb = ms.addSourceBuffer("audio/mp4"); var videosb = ms.addSourceBuffer("video/mp4"); + // ensure tracks end at approximately the same time to ensure ended event is + // always fired (bug 1233639). + audiosb.appendWindowEnd = 3.9; + videosb.appendWindowEnd = 3.9; fetchAndLoad(audiosb, 'bipbop/bipbop_audio', ['init'], '.mp4') .then(fetchAndLoad.bind(null, videosb, 'bipbop/bipbop_video', ['init'], '.mp4')) .then(fetchAndLoad.bind(null, audiosb, 'bipbop/bipbop_audio', range(1, 5), '.m4s')) @@ -34,19 +38,12 @@ runWithMSE(function(ms, el) { var p = once(el, 'waiting'); el.play(); return p; - }).then(function() { - // currentTime is based on the current video frame, so if the audio ends just before - // the next video frame, currentTime can be up to 1 frame's worth earlier than - // min(audioEnd, videoEnd). - // Some decoders (Windows in particular) may keep up to 25 frames queued. - isfuzzy(el.currentTime, Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 1/60, - 25 * 1/30, "Got a waiting event at " + el.currentTime); }).then(function() { var p = once(el, 'ended'); ms.endOfStream(); return p; }).then(function() { - is(el.duration, 4.005, "Video has correct duration: " + el.duration); + is(el.duration, 3.854512, "Video has correct duration: " + el.duration); is(el.currentTime, el.duration, "Video has correct currentTime."); SimpleTest.finish(); }); diff --git a/dom/media/platforms/omx/OmxDataDecoder.cpp b/dom/media/platforms/omx/OmxDataDecoder.cpp index 2a9bee7c055..421934a9fe7 100644 --- a/dom/media/platforms/omx/OmxDataDecoder.cpp +++ b/dom/media/platforms/omx/OmxDataDecoder.cpp @@ -226,23 +226,12 @@ OmxDataDecoder::DoAsyncShutdown() mWatchManager.Unwatch(mOmxState, &OmxDataDecoder::OmxStateRunner); mWatchManager.Unwatch(mPortSettingsChanged, &OmxDataDecoder::PortSettingsChanged); - // Do flush so all port can be returned to client. + // Flush to all ports, so all buffers can be returned from component. RefPtr self = this; mOmxLayer->SendCommand(OMX_CommandFlush, OMX_ALL, nullptr) ->Then(mOmxTaskQueue, __func__, [self] () -> RefPtr { - LOG("DoAsyncShutdown: flush complete, collecting buffers..."); - self->CollectBufferPromises(OMX_DirMax) - ->Then(self->mOmxTaskQueue, __func__, - [self] () { - LOG("DoAsyncShutdown: releasing all buffers."); - self->ReleaseBuffers(OMX_DirInput); - self->ReleaseBuffers(OMX_DirOutput); - }, - [self] () { - self->mOmxLayer->Shutdown(); - }); - + LOG("DoAsyncShutdown: flush complete"); return self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateIdle, nullptr); }, [self] () { @@ -251,8 +240,30 @@ OmxDataDecoder::DoAsyncShutdown() ->CompletionPromise() ->Then(mOmxTaskQueue, __func__, [self] () -> RefPtr { - LOG("DoAsyncShutdown: OMX_StateIdle"); - return self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, nullptr); + RefPtr p = + self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, nullptr); + + LOG("DoAsyncShutdown: collecting buffers..."); + self->CollectBufferPromises(OMX_DirMax) + ->Then(self->mOmxTaskQueue, __func__, + [self] () { + // According to spec 3.1.1.2.2.1: + // OMX_StateLoaded needs to be sent before releasing buffers. + // And state transition from OMX_StateIdle to OMX_StateLoaded + // is completed when all of the buffers have been removed + // from the component. + // Here the buffer promises are not resolved due to displaying + // in layer, it needs to wait before the layer returns the + // buffers. + LOG("DoAsyncShutdown: all buffers collected, releasing buffers..."); + self->ReleaseBuffers(OMX_DirInput); + self->ReleaseBuffers(OMX_DirOutput); + }, + [self] () { + self->mOmxLayer->Shutdown(); + }); + + return p; }, [self] () { self->mOmxLayer->Shutdown(); diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.cpp b/dom/media/webrtc/MediaEngineTabVideoSource.cpp index ac8791fbf66..e4c097cb57e 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp @@ -196,7 +196,7 @@ MediaEngineTabVideoSource::NotifyPull(MediaStreamGraph*, MonitorAutoLock mon(mMonitor); // Note: we're not giving up mImage here - RefPtr image = mImage; + RefPtr image = mImage; StreamTime delta = aDesiredTime - aSource->GetEndOfAppendedData(aID); if (delta > 0) { // nullptr images are allowed @@ -298,7 +298,7 @@ MediaEngineTabVideoSource::Draw() { return; } - RefPtr image = new layers::CairoImage(size, surface); + RefPtr image = new layers::SourceSurfaceImage(size, surface); MonitorAutoLock mon(mMonitor); mImage = image; diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.h b/dom/media/webrtc/MediaEngineTabVideoSource.h index ee84abcf013..8a0d3f17f39 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ b/dom/media/webrtc/MediaEngineTabVideoSource.h @@ -88,7 +88,7 @@ private: ScopedFreePtr mData; size_t mDataSize; nsCOMPtr mWindow; - RefPtr mImage; + RefPtr mImage; nsCOMPtr mTimer; Monitor mMonitor; nsCOMPtr mTabSource; diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index cac0322ef44..4b22f70946d 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -957,7 +957,7 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect, RefPtr sourceSurface = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface); - RefPtr image = new CairoImage(surface->GetSize(), sourceSurface); + RefPtr image = new SourceSurfaceImage(surface->GetSize(), sourceSurface); nsAutoTArray imageList; imageList.AppendElement( diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index fcc84a090eb..ecb67f80930 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -139,62 +139,6 @@ CSPService::ShouldLoad(uint32_t aContentType, return NS_OK; } - // ----- THIS IS A TEMPORARY FAST PATH FOR CERTIFIED APPS. ----- - // ----- PLEASE REMOVE ONCE bug 925004 LANDS. ----- - - // Cache the app status for this origin. - uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED; - nsAutoCString sourceOrigin; - if (aRequestPrincipal && aRequestOrigin) { - aRequestOrigin->GetPrePath(sourceOrigin); - if (!mAppStatusCache.Get(sourceOrigin, &status)) { - aRequestPrincipal->GetAppStatus(&status); - mAppStatusCache.Put(sourceOrigin, status); - } - } - - if (status == nsIPrincipal::APP_STATUS_CERTIFIED) { - // The CSP for certified apps is : - // "default-src * data: blob:; script-src 'self'; object-src 'none'; style-src 'self' app://theme.gaiamobile.org:*" - // That means we can optimize for this case by: - // - loading same origin scripts and stylesheets, and stylesheets from the - // theme url space. - // - never loading objects. - // - accepting everything else. - - switch (aContentType) { - case nsIContentPolicy::TYPE_SCRIPT: - case nsIContentPolicy::TYPE_STYLESHEET: - { - // Whitelist the theme resources. - auto themeOrigin = Preferences::GetCString("b2g.theme.origin"); - nsAutoCString contentOrigin; - aContentLocation->GetPrePath(contentOrigin); - - if (!(sourceOrigin.Equals(contentOrigin) || - (themeOrigin && themeOrigin.Equals(contentOrigin)))) { - *aDecision = nsIContentPolicy::REJECT_SERVER; - } - } - break; - - case nsIContentPolicy::TYPE_OBJECT: - *aDecision = nsIContentPolicy::REJECT_SERVER; - break; - - default: - *aDecision = nsIContentPolicy::ACCEPT; - } - - // Only cache and return if we are successful. If not, we want the error - // to be reported, and thus fallback to the slow path. - if (*aDecision == nsIContentPolicy::ACCEPT) { - return NS_OK; - } - } - - // ----- END OF TEMPORARY FAST PATH FOR CERTIFIED APPS. ----- - // query the principal of the document; if no document is passed, then // fall back to using the requestPrincipal (e.g. service workers do not // pass a document). diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 2e8a122d4b8..38f483e3654 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -703,6 +703,8 @@ var interfaceNamesInGlobalScope = "Image", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageBitmap", +// IMPORTANT: Do not change this list without review from a DOM peer! + "ImageBitmapRenderingContext", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "ImageCapture", disabled: true}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/FileReader.webidl b/dom/webidl/FileReader.webidl index b4bea254058..f3647aea423 100644 --- a/dom/webidl/FileReader.webidl +++ b/dom/webidl/FileReader.webidl @@ -11,7 +11,7 @@ */ [Constructor, - Exposed=(Window,System)] + Exposed=(Window,Worker,System)] interface FileReader : EventTarget { // async read methods [Throws] diff --git a/dom/webidl/ImageBitmap.webidl b/dom/webidl/ImageBitmap.webidl index a257d63ff3e..e52b35a85c5 100644 --- a/dom/webidl/ImageBitmap.webidl +++ b/dom/webidl/ImageBitmap.webidl @@ -23,6 +23,18 @@ interface ImageBitmap { readonly attribute unsigned long height; }; +// It's crucial that there be a way to explicitly dispose of ImageBitmaps +// since they refer to potentially large graphics resources. Some uses +// of this API proposal will result in repeated allocations of ImageBitmaps, +// and garbage collection will not reliably reclaim them quickly enough. +// Here we reuse close(), which also exists on another Transferable type, +// MessagePort. Potentially, all Transferable types should inherit from a +// new interface type "Closeable". +partial interface ImageBitmap { + // Dispose of all graphical resources associated with this ImageBitmap. + void close(); +}; + [NoInterfaceObject, Exposed=(Window,Worker)] interface ImageBitmapFactories { [Throws] diff --git a/dom/webidl/ImageBitmapRenderingContext.webidl b/dom/webidl/ImageBitmapRenderingContext.webidl new file mode 100644 index 00000000000..4696427b2ea --- /dev/null +++ b/dom/webidl/ImageBitmapRenderingContext.webidl @@ -0,0 +1,36 @@ +/* -*- Mode: IDL; 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/. + * + * The origin of this IDL file is + * https://wiki.whatwg.org/wiki/OffscreenCanvas + * + * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +// The new ImageBitmapRenderingContext is a canvas rendering context +// which only provides the functionality to replace the canvas's +// contents with the given ImageBitmap. Its context id (the first argument +// to getContext) is "bitmaprenderer". +[Exposed=(Window,Worker)] +interface ImageBitmapRenderingContext { + // Displays the given ImageBitmap in the canvas associated with this + // rendering context. Ownership of the ImageBitmap is transferred to + // the canvas. The caller may not use its reference to the ImageBitmap + // after making this call. (This semantic is crucial to enable prompt + // reclamation of expensive graphics resources, rather than relying on + // garbage collection to do so.) + // + // The ImageBitmap conceptually replaces the canvas's bitmap, but + // it does not change the canvas's intrinsic width or height. + // + // The ImageBitmap, when displayed, is clipped to the rectangle + // defined by the canvas's instrinsic width and height. Pixels that + // would be covered by the canvas's bitmap which are not covered by + // the supplied ImageBitmap are rendered transparent black. Any CSS + // styles affecting the display of the canvas are applied as usual. + void transferImageBitmap(ImageBitmap bitmap); +}; diff --git a/dom/webidl/OffscreenCanvas.webidl b/dom/webidl/OffscreenCanvas.webidl index 592ac6e14fe..ffe2b91473f 100644 --- a/dom/webidl/OffscreenCanvas.webidl +++ b/dom/webidl/OffscreenCanvas.webidl @@ -5,14 +5,10 @@ * * For more information on this interface, please see * https://wiki.whatwg.org/wiki/OffscreenCanvas - * - * Current implementation focus on transfer canvas from main thread to worker. - * So there are some spec doesn't implement, such as [Constructor], toBlob() and - * transferToImageBitmap in OffscreenCanvas. Bug 1172796 will implement - * remaining spec. */ -[Exposed=(Window,Worker), +[Constructor(unsigned long width, unsigned long height), + Exposed=(Window,Worker), Func="mozilla::dom::OffscreenCanvas::PrefEnabled"] interface OffscreenCanvas : EventTarget { [Pure, SetterThrows] @@ -23,6 +19,11 @@ interface OffscreenCanvas : EventTarget { [Throws] nsISupports? getContext(DOMString contextId, optional any contextOptions = null); + + ImageBitmap transferToImageBitmap(); + [Throws] + Promise toBlob(optional DOMString type = "", + optional any encoderOptions); }; // OffscreenCanvas implements Transferable; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index beae51d9c51..2234c287869 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -265,6 +265,7 @@ WEBIDL_FILES = [ 'IDBTransaction.webidl', 'IDBVersionChangeEvent.webidl', 'ImageBitmap.webidl', + 'ImageBitmapRenderingContext.webidl', 'ImageCapture.webidl', 'ImageData.webidl', 'ImageDocument.webidl', diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 5efef6f3d9c..ba7e17cc0b1 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -629,6 +629,7 @@ private: // If one load info cancels or hits an error, it can race with the start // callback coming from another load info. if (mCanceledMainThread || !mCacheCreator) { + aRequest->Cancel(NS_ERROR_FAILURE); return NS_ERROR_FAILURE; } diff --git a/dom/workers/test/fileapi_chromeScript.js b/dom/workers/test/fileapi_chromeScript.js new file mode 100644 index 00000000000..85f80a60b2b --- /dev/null +++ b/dom/workers/test/fileapi_chromeScript.js @@ -0,0 +1,29 @@ +var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.importGlobalProperties(["File"]); + +var fileNum = 1; + +function createFileWithData(fileData) { + var willDelete = fileData === null; + var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); + var testFile = dirSvc.get("ProfD", Ci.nsIFile); + testFile.append("fileAPItestfile" + fileNum); + fileNum++; + var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate + 0666, 0); + if (willDelete) { + fileData = "some irrelevant test data\n"; + } + outStream.write(fileData, fileData.length); + outStream.close(); + var domFile = new File(testFile); + if (willDelete) { + testFile.remove(/* recursive: */ false); + } + return domFile; +} + +addMessageListener("files.open", function (message) { + sendAsyncMessage("files.opened", message.map(createFileWithData)); +}); diff --git a/dom/workers/test/mochitest.ini b/dom/workers/test/mochitest.ini index daaed889a15..7bb3539b3d1 100644 --- a/dom/workers/test/mochitest.ini +++ b/dom/workers/test/mochitest.ini @@ -119,6 +119,8 @@ support-files = worker_referrer.js websocket_https.html websocket_https_worker.js + worker_fileReader.js + fileapi_chromeScript.js [test_404.html] [test_atob.html] @@ -236,3 +238,4 @@ skip-if = (os == "win") || (os == "mac") || toolkit == 'android' #bug 798220 [test_referrer.html] [test_sharedWorker_ports.html] [test_sharedWorker_lifetime.html] +[test_fileReader.html] diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 98a472882a6..adb96005004 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -114,6 +114,8 @@ var interfaceNamesInGlobalScope = "FetchEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "File", +// IMPORTANT: Do not change this list without review from a DOM peer! + "FileReader", // IMPORTANT: Do not change this list without review from a DOM peer! "FileReaderSync", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -144,6 +146,8 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageBitmap", +// IMPORTANT: Do not change this list without review from a DOM peer! + "ImageBitmapRenderingContext", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_fileReader.html b/dom/workers/test/test_fileReader.html new file mode 100644 index 00000000000..26e73bdb64f --- /dev/null +++ b/dom/workers/test/test_fileReader.html @@ -0,0 +1,100 @@ + + + + Test for FileReader in workers + + + + + + + + diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index bf02b190132..af9f18e7d27 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -106,6 +106,8 @@ var interfaceNamesInGlobalScope = "EventTarget", // IMPORTANT: Do not change this list without review from a DOM peer! "File", +// IMPORTANT: Do not change this list without review from a DOM peer! + "FileReader", // IMPORTANT: Do not change this list without review from a DOM peer! "FileReaderSync", // IMPORTANT: Do not change this list without review from a DOM peer! @@ -136,6 +138,8 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageBitmap", +// IMPORTANT: Do not change this list without review from a DOM peer! + "ImageBitmapRenderingContext", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/worker_fileReader.js b/dom/workers/test/worker_fileReader.js new file mode 100644 index 00000000000..f4e91b325e0 --- /dev/null +++ b/dom/workers/test/worker_fileReader.js @@ -0,0 +1,417 @@ +var testRanCounter = 0; +var expectedTestCount = 0; +var testSetupFinished = false; + +function ok(a, msg) { + postMessage({type: 'check', status: !!a, msg: msg }); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + postMessage({type: 'finish'}); +} + +function convertToUTF16(s) { + res = ""; + for (var i = 0; i < s.length; ++i) { + c = s.charCodeAt(i); + res += String.fromCharCode(c & 255, c >>> 8); + } + return res; +} + +function convertToUTF8(s) { + return unescape(encodeURIComponent(s)); +} + +function convertToDataURL(s) { + return "data:application/octet-stream;base64," + btoa(s); +} + +onmessage = function(message) { + is(FileReader.EMPTY, 0, "correct EMPTY value"); + is(FileReader.LOADING, 1, "correct LOADING value"); + is(FileReader.DONE, 2, "correct DONE value"); + + // List of blobs. + var asciiFile = message.data.blobs.shift(); + var binaryFile = message.data.blobs.shift(); + var nonExistingFile = message.data.blobs.shift(); + var utf8TextFile = message.data.blobs.shift(); + var utf16TextFile = message.data.blobs.shift(); + var emptyFile = message.data.blobs.shift(); + var dataUrlFile0 = message.data.blobs.shift(); + var dataUrlFile1 = message.data.blobs.shift(); + var dataUrlFile2 = message.data.blobs.shift(); + + // List of buffers for testing. + var testTextData = message.data.testTextData; + var testASCIIData = message.data.testASCIIData; + var testBinaryData = message.data.testBinaryData; + var dataurldata0 = message.data.dataurldata0; + var dataurldata1 = message.data.dataurldata1; + var dataurldata2 = message.data.dataurldata2; + + // Test that plain reading works and fires events as expected, both + // for text and binary reading + + var onloadHasRunText = false; + var onloadStartHasRunText = false; + r = new FileReader(); + is(r.readyState, FileReader.EMPTY, "correct initial text readyState"); + r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "plain reading"); + r.addEventListener("load", function() { onloadHasRunText = true }, false); + r.addEventListener("loadstart", function() { onloadStartHasRunText = true }, false); + r.readAsText(asciiFile); + is(r.readyState, FileReader.LOADING, "correct loading text readyState"); + is(onloadHasRunText, false, "text loading must be async"); + is(onloadStartHasRunText, true, "text loadstart should fire sync"); + expectedTestCount++; + + var onloadHasRunBinary = false; + var onloadStartHasRunBinary = false; + r = new FileReader(); + is(r.readyState, FileReader.EMPTY, "correct initial binary readyState"); + r.addEventListener("load", function() { onloadHasRunBinary = true }, false); + r.addEventListener("loadstart", function() { onloadStartHasRunBinary = true }, false); + r.readAsBinaryString(binaryFile); + r.onload = getLoadHandler(testBinaryData, testBinaryData.length, "binary reading"); + is(r.readyState, FileReader.LOADING, "correct loading binary readyState"); + is(onloadHasRunBinary, false, "binary loading must be async"); + is(onloadStartHasRunBinary, true, "binary loadstart should fire sync"); + expectedTestCount++; + + var onloadHasRunArrayBuffer = false; + var onloadStartHasRunArrayBuffer = false; + r = new FileReader(); + is(r.readyState, FileReader.EMPTY, "correct initial arrayBuffer readyState"); + r.addEventListener("load", function() { onloadHasRunArrayBuffer = true }, false); + r.addEventListener("loadstart", function() { onloadStartHasRunArrayBuffer = true }, false); + r.readAsArrayBuffer(binaryFile); + r.onload = getLoadHandlerForArrayBuffer(testBinaryData, testBinaryData.length, "array buffer reading"); + is(r.readyState, FileReader.LOADING, "correct loading arrayBuffer readyState"); + is(onloadHasRunArrayBuffer, false, "arrayBuffer loading must be async"); + is(onloadStartHasRunArrayBuffer, true, "arrayBuffer loadstart should fire sync"); + expectedTestCount++; + + // Test a variety of encodings, and make sure they work properly + r = new FileReader(); + r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "no encoding reading"); + r.readAsText(asciiFile, ""); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "iso8859 reading"); + r.readAsText(asciiFile, "iso-8859-1"); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler(testTextData, + convertToUTF8(testTextData).length, + "utf8 reading"); + r.readAsText(utf8TextFile, "utf8"); + expectedTestCount++; + + r = new FileReader(); + r.readAsText(utf16TextFile, "utf-16"); + r.onload = getLoadHandler(testTextData, + convertToUTF16(testTextData).length, + "utf16 reading"); + expectedTestCount++; + + // Test get result without reading + r = new FileReader(); + is(r.readyState, FileReader.EMPTY, + "readyState in test reader get result without reading"); + is(r.error, null, + "no error in test reader get result without reading"); + is(r.result, null, + "result in test reader get result without reading"); + + // Test loading an empty file works (and doesn't crash!) + r = new FileReader(); + r.onload = getLoadHandler("", 0, "empty no encoding reading"); + r.readAsText(emptyFile, ""); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler("", 0, "empty utf8 reading"); + r.readAsText(emptyFile, "utf8"); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler("", 0, "empty utf16 reading"); + r.readAsText(emptyFile, "utf-16"); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler("", 0, "empty binary string reading"); + r.readAsBinaryString(emptyFile); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandlerForArrayBuffer("", 0, "empty array buffer reading"); + r.readAsArrayBuffer(emptyFile); + expectedTestCount++; + + r = new FileReader(); + r.onload = getLoadHandler(convertToDataURL(""), 0, "empt binary string reading"); + r.readAsDataURL(emptyFile); + expectedTestCount++; + + // Test reusing a FileReader to read multiple times + r = new FileReader(); + r.onload = getLoadHandler(testASCIIData, + testASCIIData.length, + "to-be-reused reading text") + var makeAnotherReadListener = function(event) { + r = event.target; + r.removeEventListener("load", makeAnotherReadListener, false); + r.onload = getLoadHandler(testASCIIData, + testASCIIData.length, + "reused reading text"); + r.readAsText(asciiFile); + }; + r.addEventListener("load", makeAnotherReadListener, false); + r.readAsText(asciiFile); + expectedTestCount += 2; + + r = new FileReader(); + r.onload = getLoadHandler(testBinaryData, + testBinaryData.length, + "to-be-reused reading binary") + var makeAnotherReadListener2 = function(event) { + r = event.target; + r.removeEventListener("load", makeAnotherReadListener2, false); + r.onload = getLoadHandler(testBinaryData, + testBinaryData.length, + "reused reading binary"); + r.readAsBinaryString(binaryFile); + }; + r.addEventListener("load", makeAnotherReadListener2, false); + r.readAsBinaryString(binaryFile); + expectedTestCount += 2; + + r = new FileReader(); + r.onload = getLoadHandler(convertToDataURL(testBinaryData), + testBinaryData.length, + "to-be-reused reading data url") + var makeAnotherReadListener3 = function(event) { + r = event.target; + r.removeEventListener("load", makeAnotherReadListener3, false); + r.onload = getLoadHandler(convertToDataURL(testBinaryData), + testBinaryData.length, + "reused reading data url"); + r.readAsDataURL(binaryFile); + }; + r.addEventListener("load", makeAnotherReadListener3, false); + r.readAsDataURL(binaryFile); + expectedTestCount += 2; + + r = new FileReader(); + r.onload = getLoadHandlerForArrayBuffer(testBinaryData, + testBinaryData.length, + "to-be-reused reading arrayBuffer") + var makeAnotherReadListener4 = function(event) { + r = event.target; + r.removeEventListener("load", makeAnotherReadListener4, false); + r.onload = getLoadHandlerForArrayBuffer(testBinaryData, + testBinaryData.length, + "reused reading arrayBuffer"); + r.readAsArrayBuffer(binaryFile); + }; + r.addEventListener("load", makeAnotherReadListener4, false); + r.readAsArrayBuffer(binaryFile); + expectedTestCount += 2; + + // Test first reading as ArrayBuffer then read as something else + // (BinaryString) and doesn't crash + r = new FileReader(); + r.onload = getLoadHandlerForArrayBuffer(testBinaryData, + testBinaryData.length, + "to-be-reused reading arrayBuffer") + var makeAnotherReadListener5 = function(event) { + r = event.target; + r.removeEventListener("load", makeAnotherReadListener5, false); + r.onload = getLoadHandler(testBinaryData, + testBinaryData.length, + "reused reading binary string"); + r.readAsBinaryString(binaryFile); + }; + r.addEventListener("load", makeAnotherReadListener5, false); + r.readAsArrayBuffer(binaryFile); + expectedTestCount += 2; + + //Test data-URI encoding on differing file sizes + is(dataurldata0.length % 3, 0, "Want to test data with length % 3 == 0"); + r = new FileReader(); + r.onload = getLoadHandler(convertToDataURL(dataurldata0), + dataurldata0.length, + "dataurl reading, %3 = 0"); + r.readAsDataURL(dataUrlFile0); + expectedTestCount++; + + is(dataurldata1.length % 3, 1, "Want to test data with length % 3 == 1"); + r = new FileReader(); + r.onload = getLoadHandler(convertToDataURL(dataurldata1), + dataurldata1.length, + "dataurl reading, %3 = 1"); + r.readAsDataURL(dataUrlFile1); + expectedTestCount++; + + is(dataurldata2.length % 3, 2, "Want to test data with length % 3 == 2"); + r = new FileReader(); + r.onload = getLoadHandler(convertToDataURL(dataurldata2), + dataurldata2.length, + "dataurl reading, %3 = 2"); + r.readAsDataURL(dataUrlFile2), + expectedTestCount++; + + + // Test abort() + var abortHasRun = false; + var loadEndHasRun = false; + r = new FileReader(); + r.onabort = function (event) { + is(abortHasRun, false, "abort should only fire once"); + is(loadEndHasRun, false, "loadend shouldn't have fired yet"); + abortHasRun = true; + is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort"); + is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads"); + is(event.target.result, null, "file data should be null on aborted reads"); + } + r.onloadend = function (event) { + is(abortHasRun, true, "abort should fire before loadend"); + is(loadEndHasRun, false, "loadend should only fire once"); + loadEndHasRun = true; + is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort"); + is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads"); + is(event.target.result, null, "file data should be null on aborted reads"); + } + r.onload = function() { ok(false, "load should not fire for aborted reads") }; + r.onerror = function() { ok(false, "error should not fire for aborted reads") }; + r.onprogress = function() { ok(false, "progress should not fire for aborted reads") }; + var abortThrew = false; + try { + r.abort(); + } catch(e) { + abortThrew = true; + } + is(abortThrew, true, "abort() must throw if not loading"); + is(abortHasRun, false, "abort() is a no-op unless loading"); + r.readAsText(asciiFile); + r.abort(); + is(abortHasRun, true, "abort should fire sync"); + is(loadEndHasRun, true, "loadend should fire sync"); + + // Test calling readAsX to cause abort() + var reuseAbortHasRun = false; + r = new FileReader(); + r.onabort = function (event) { + is(reuseAbortHasRun, false, "abort should only fire once"); + reuseAbortHasRun = true; + is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort"); + is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads"); + is(event.target.result, null, "file data should be null on aborted reads"); + } + r.onload = function() { ok(false, "load should not fire for aborted reads") }; + var abortThrew = false; + try { + r.abort(); + } catch(e) { + abortThrew = true; + } + is(abortThrew, true, "abort() must throw if not loading"); + is(reuseAbortHasRun, false, "abort() is a no-op unless loading"); + r.readAsText(asciiFile); + r.readAsText(asciiFile); + is(reuseAbortHasRun, true, "abort should fire sync"); + r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "reuse-as-abort reading"); + expectedTestCount++; + + + // Test reading from nonexistent files + r = new FileReader(); + var didThrow = false; + r.onerror = function (event) { + is(event.target.readyState, FileReader.DONE, "should be DONE while firing onerror"); + is(event.target.error.name, "NotFoundError", "error set to NotFoundError for nonexistent files"); + is(event.target.result, null, "file data should be null on aborted reads"); + testHasRun(); + }; + r.onload = function (event) { + is(false, "nonexistent file shouldn't load! (FIXME: bug 1122788)"); + testHasRun(); + }; + try { + r.readAsDataURL(nonExistingFile); + expectedTestCount++; + } catch(ex) { + didThrow = true; + } + // Once this test passes, we should test that onerror gets called and + // that the FileReader object is in the right state during that call. + is(didThrow, false, "shouldn't throw when opening nonexistent file, should fire error instead"); + + + function getLoadHandler(expectedResult, expectedLength, testName) { + return function (event) { + is(event.target.readyState, FileReader.DONE, + "readyState in test " + testName); + is(event.target.error, null, + "no error in test " + testName); + is(event.target.result, expectedResult, + "result in test " + testName); + is(event.lengthComputable, true, + "lengthComputable in test " + testName); + is(event.loaded, expectedLength, + "loaded in test " + testName); + is(event.total, expectedLength, + "total in test " + testName); + testHasRun(); + } + } + + function getLoadHandlerForArrayBuffer(expectedResult, expectedLength, testName) { + return function (event) { + is(event.target.readyState, FileReader.DONE, + "readyState in test " + testName); + is(event.target.error, null, + "no error in test " + testName); + is(event.lengthComputable, true, + "lengthComputable in test " + testName); + is(event.loaded, expectedLength, + "loaded in test " + testName); + is(event.total, expectedLength, + "total in test " + testName); + is(event.target.result.byteLength, expectedLength, + "array buffer size in test " + testName); + var u8v = new Uint8Array(event.target.result); + is(String.fromCharCode.apply(String, u8v), expectedResult, + "array buffer contents in test " + testName); + u8v = null; + is(event.target.result.byteLength, expectedLength, + "array buffer size after gc in test " + testName); + u8v = new Uint8Array(event.target.result); + is(String.fromCharCode.apply(String, u8v), expectedResult, + "array buffer contents after gc in test " + testName); + testHasRun(); + } + } + + function testHasRun() { + //alert(testRanCounter); + ++testRanCounter; + if (testRanCounter == expectedTestCount) { + is(testSetupFinished, true, "test setup should have finished; check for exceptions"); + is(onloadHasRunText, true, "onload text should have fired by now"); + is(onloadHasRunBinary, true, "onload binary should have fired by now"); + finish(); + } + } + + testSetupFinished = true; +} diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 8ce1773ab8b..2135a3b0982 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -317,8 +317,13 @@ class DrawTargetCaptureImpl; * This is the base class for source surfaces. These objects are surfaces * which may be used as a source in a SurfacePattern or a DrawSurface call. * They cannot be drawn to directly. + * + * Although SourceSurface has thread-safe refcount, some SourceSurface cannot + * be used on random threads at the same time. Only DataSourceSurface can be + * used on random threads now. This will be fixed in the future. Eventually + * all SourceSurface should be thread-safe. */ -class SourceSurface : public RefCounted +class SourceSurface : public external::AtomicRefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface) @@ -1227,6 +1232,11 @@ public: CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride, const IntSize &aSize, SurfaceFormat aFormat); + static void + CopyDataSourceSurface(DataSourceSurface* aSource, + DataSourceSurface* aDest); + + static already_AddRefed CreateEventRecorderForFile(const char *aFilename); diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index e50cc7a0fc4..f99b3a3d5e8 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -919,6 +919,97 @@ Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize, return nullptr; } +static uint16_t +PackRGB565(uint8_t r, uint8_t g, uint8_t b) +{ + uint16_t pixel = ((r << 11) & 0xf800) | + ((g << 5) & 0x07e0) | + ((b ) & 0x001f); + + return pixel; +} + +void +Factory::CopyDataSourceSurface(DataSourceSurface* aSource, + DataSourceSurface* aDest) +{ + // Don't worry too much about speed. + MOZ_ASSERT(aSource->GetSize() == aDest->GetSize()); + MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 || + aSource->GetFormat() == SurfaceFormat::R8G8B8X8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8A8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8X8); + MOZ_ASSERT(aDest->GetFormat() == SurfaceFormat::R8G8B8A8 || + aDest->GetFormat() == SurfaceFormat::R8G8B8X8 || + aDest->GetFormat() == SurfaceFormat::B8G8R8A8 || + aDest->GetFormat() == SurfaceFormat::B8G8R8X8 || + aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16); + + const bool isSrcBGR = aSource->GetFormat() == SurfaceFormat::B8G8R8A8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8X8; + const bool isDestBGR = aDest->GetFormat() == SurfaceFormat::B8G8R8A8 || + aDest->GetFormat() == SurfaceFormat::B8G8R8X8; + const bool needsSwap02 = isSrcBGR != isDestBGR; + + const bool srcHasAlpha = aSource->GetFormat() == SurfaceFormat::R8G8B8A8 || + aSource->GetFormat() == SurfaceFormat::B8G8R8A8; + const bool destHasAlpha = aDest->GetFormat() == SurfaceFormat::R8G8B8A8 || + aDest->GetFormat() == SurfaceFormat::B8G8R8A8; + const bool needsAlphaMask = !srcHasAlpha && destHasAlpha; + + const bool needsConvertTo16Bits = aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16; + + DataSourceSurface::MappedSurface srcMap; + DataSourceSurface::MappedSurface destMap; + if (!aSource->Map(DataSourceSurface::MapType::READ, &srcMap) || + !aDest->Map(DataSourceSurface::MapType::WRITE, &destMap)) { + MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface."); + return; + } + + MOZ_ASSERT(srcMap.mStride >= 0); + MOZ_ASSERT(destMap.mStride >= 0); + + const size_t srcBPP = BytesPerPixel(aSource->GetFormat()); + const size_t srcRowBytes = aSource->GetSize().width * srcBPP; + const size_t srcRowHole = srcMap.mStride - srcRowBytes; + + const size_t destBPP = BytesPerPixel(aDest->GetFormat()); + const size_t destRowBytes = aDest->GetSize().width * destBPP; + const size_t destRowHole = destMap.mStride - destRowBytes; + + uint8_t* srcRow = srcMap.mData; + uint8_t* destRow = destMap.mData; + const size_t rows = aSource->GetSize().height; + for (size_t i = 0; i < rows; i++) { + const uint8_t* srcRowEnd = srcRow + srcRowBytes; + + while (srcRow != srcRowEnd) { + uint8_t d0 = needsSwap02 ? srcRow[2] : srcRow[0]; + uint8_t d1 = srcRow[1]; + uint8_t d2 = needsSwap02 ? srcRow[0] : srcRow[2]; + uint8_t d3 = needsAlphaMask ? 0xff : srcRow[3]; + + if (needsConvertTo16Bits) { + *(uint16_t*)destRow = PackRGB565(d0, d1, d2); + } else { + destRow[0] = d0; + destRow[1] = d1; + destRow[2] = d2; + destRow[3] = d3; + } + srcRow += srcBPP; + destRow += destBPP; + } + + srcRow += srcRowHole; + destRow += destRowHole; + } + + aSource->Unmap(); + aDest->Unmap(); +} + already_AddRefed Factory::CreateEventRecorderForFile(const char *aFilename) { diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index 0ef63de1ad3..8d4b9f3d008 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -250,96 +250,6 @@ SwapRAndBComponents(DataSourceSurface* surf) surf->Unmap(); } -static uint16_t -PackRGB565(uint8_t r, uint8_t g, uint8_t b) -{ - uint16_t pixel = ((r << 11) & 0xf800) | - ((g << 5) & 0x07e0) | - ((b ) & 0x001f); - - return pixel; -} - -static void -CopyDataSourceSurface(DataSourceSurface* aSource, - DataSourceSurface* aDest) -{ - // Don't worry too much about speed. - MOZ_ASSERT(aSource->GetSize() == aDest->GetSize()); - MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 || - aSource->GetFormat() == SurfaceFormat::R8G8B8X8 || - aSource->GetFormat() == SurfaceFormat::B8G8R8A8 || - aSource->GetFormat() == SurfaceFormat::B8G8R8X8); - MOZ_ASSERT(aDest->GetFormat() == SurfaceFormat::R8G8B8A8 || - aDest->GetFormat() == SurfaceFormat::R8G8B8X8 || - aDest->GetFormat() == SurfaceFormat::B8G8R8A8 || - aDest->GetFormat() == SurfaceFormat::B8G8R8X8 || - aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16); - - const bool isSrcBGR = aSource->GetFormat() == SurfaceFormat::B8G8R8A8 || - aSource->GetFormat() == SurfaceFormat::B8G8R8X8; - const bool isDestBGR = aDest->GetFormat() == SurfaceFormat::B8G8R8A8 || - aDest->GetFormat() == SurfaceFormat::B8G8R8X8; - const bool needsSwap02 = isSrcBGR != isDestBGR; - - const bool srcHasAlpha = aSource->GetFormat() == SurfaceFormat::R8G8B8A8 || - aSource->GetFormat() == SurfaceFormat::B8G8R8A8; - const bool destHasAlpha = aDest->GetFormat() == SurfaceFormat::R8G8B8A8 || - aDest->GetFormat() == SurfaceFormat::B8G8R8A8; - const bool needsAlphaMask = !srcHasAlpha && destHasAlpha; - - const bool needsConvertTo16Bits = aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16; - - DataSourceSurface::MappedSurface srcMap; - DataSourceSurface::MappedSurface destMap; - if (!aSource->Map(DataSourceSurface::MapType::READ, &srcMap) || - !aDest->Map(DataSourceSurface::MapType::WRITE, &destMap)) { - MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface."); - return; - } - MOZ_ASSERT(srcMap.mStride >= 0); - MOZ_ASSERT(destMap.mStride >= 0); - - const size_t srcBPP = BytesPerPixel(aSource->GetFormat()); - const size_t srcRowBytes = aSource->GetSize().width * srcBPP; - const size_t srcRowHole = srcMap.mStride - srcRowBytes; - - const size_t destBPP = BytesPerPixel(aDest->GetFormat()); - const size_t destRowBytes = aDest->GetSize().width * destBPP; - const size_t destRowHole = destMap.mStride - destRowBytes; - - uint8_t* srcRow = srcMap.mData; - uint8_t* destRow = destMap.mData; - const size_t rows = aSource->GetSize().height; - for (size_t i = 0; i < rows; i++) { - const uint8_t* srcRowEnd = srcRow + srcRowBytes; - - while (srcRow != srcRowEnd) { - uint8_t d0 = needsSwap02 ? srcRow[2] : srcRow[0]; - uint8_t d1 = srcRow[1]; - uint8_t d2 = needsSwap02 ? srcRow[0] : srcRow[2]; - uint8_t d3 = needsAlphaMask ? 0xff : srcRow[3]; - - if (needsConvertTo16Bits) { - *(uint16_t*)destRow = PackRGB565(d0, d1, d2); - } else { - destRow[0] = d0; - destRow[1] = d1; - destRow[2] = d2; - destRow[3] = d3; - } - srcRow += srcBPP; - destRow += destBPP; - } - - srcRow += srcRowHole; - destRow += destRowHole; - } - - aSource->Unmap(); - aDest->Unmap(); -} - static int CalcRowStride(int width, int pixelSize, int alignment) { @@ -500,7 +410,7 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) if (readSurf != dest) { MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); - CopyDataSourceSurface(readSurf, dest); + gfx::Factory::CopyDataSourceSurface(readSurf, dest); } // Check if GL is giving back 1.0 alpha for diff --git a/gfx/layers/ImageContainer.cpp b/gfx/layers/ImageContainer.cpp index 7fba710ca15..d2eeb49f9af 100644 --- a/gfx/layers/ImageContainer.cpp +++ b/gfx/layers/ImageContainer.cpp @@ -549,18 +549,18 @@ PlanarYCbCrImage::GetAsSourceSurface() return surface.forget(); } -CairoImage::CairoImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface) +SourceSurfaceImage::SourceSurfaceImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface) : Image(nullptr, ImageFormat::CAIRO_SURFACE), mSize(aSize), mSourceSurface(aSourceSurface) {} -CairoImage::~CairoImage() +SourceSurfaceImage::~SourceSurfaceImage() { } TextureClient* -CairoImage::GetTextureClient(CompositableClient *aClient) +SourceSurfaceImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index fb082463465..6a9ef6f960d 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -83,6 +83,50 @@ public: } }; +class nsOwningThreadSourceSurfaceRef; + +template <> +class nsAutoRefTraits { +public: + typedef mozilla::gfx::SourceSurface* RawRef; + + /** + * The XPCOM event that will do the actual release on the creation thread. + */ + class SurfaceReleaser : public nsRunnable { + public: + explicit SurfaceReleaser(RawRef aRef) : mRef(aRef) {} + NS_IMETHOD Run() { + mRef->Release(); + return NS_OK; + } + RawRef mRef; + }; + + static RawRef Void() { return nullptr; } + void Release(RawRef aRawRef) + { + MOZ_ASSERT(mOwningThread); + bool current; + mOwningThread->IsOnCurrentThread(¤t); + if (current) { + aRawRef->Release(); + return; + } + nsCOMPtr runnable = new SurfaceReleaser(aRawRef); + mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL); + } + void AddRef(RawRef aRawRef) + { + MOZ_ASSERT(!mOwningThread); + NS_GetCurrentThread(getter_AddRefs(mOwningThread)); + aRawRef->AddRef(); + } + +private: + nsCOMPtr mOwningThread; +}; + #endif #ifdef XP_WIN @@ -763,11 +807,11 @@ protected: }; /** - * Currently, the data in a CairoImage surface is treated as being in the + * Currently, the data in a SourceSurfaceImage surface is treated as being in the * device output color space. This class is very simple as all backends * have to know about how to deal with drawing a cairo image. */ -class CairoImage final : public Image { +class SourceSurfaceImage final : public Image { public: virtual already_AddRefed GetAsSourceSurface() override { @@ -779,12 +823,12 @@ public: virtual gfx::IntSize GetSize() override { return mSize; } - CairoImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface); - ~CairoImage(); + SourceSurfaceImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface); + ~SourceSurfaceImage(); private: gfx::IntSize mSize; - nsCountedRef mSourceSurface; + nsCountedRef mSourceSurface; nsDataHashtable > mTextureClients; }; diff --git a/gfx/layers/ImageTypes.h b/gfx/layers/ImageTypes.h index 2300085c2a7..9619f297241 100644 --- a/gfx/layers/ImageTypes.h +++ b/gfx/layers/ImageTypes.h @@ -41,7 +41,7 @@ enum class ImageFormat { SHARED_RGB, /** - * The CAIRO_SURFACE format creates a CairoImage. All backends should + * The CAIRO_SURFACE format creates a SourceSurfaceImage. All backends should * support this format, because video rendering sometimes requires it. * * This format is useful even though a PaintedLayer could be used. diff --git a/gfx/layers/apz/src/InputBlockState.cpp b/gfx/layers/apz/src/InputBlockState.cpp index 7e6f28cc836..196c011918d 100644 --- a/gfx/layers/apz/src/InputBlockState.cpp +++ b/gfx/layers/apz/src/InputBlockState.cpp @@ -614,6 +614,7 @@ bool PanGestureBlockState::SetContentResponse(bool aPreventDefault) { if (aPreventDefault) { + TBS_LOG("%p setting interrupted flag\n", this); mInterrupted = true; } bool stateChanged = CancelableBlockState::SetContentResponse(aPreventDefault); diff --git a/gfx/layers/apz/src/InputQueue.cpp b/gfx/layers/apz/src/InputQueue.cpp index 7b62a7ff000..4323593756c 100644 --- a/gfx/layers/apz/src/InputQueue.cpp +++ b/gfx/layers/apz/src/InputQueue.cpp @@ -207,7 +207,8 @@ InputQueue::ReceiveMouseInput(const RefPtr& aTarget, *aOutInputBlockId = block->GetBlockId(); } - INPQ_LOG("started new drag block %p for target %p\n", block, aTarget.get()); + INPQ_LOG("started new drag block %p id %" PRIu64 " for target %p\n", + block, block->GetBlockId(), aTarget.get()); SweepDepletedBlocks(); mInputBlockQueue.AppendElement(block); @@ -262,7 +263,8 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr& aTarge if (!block) { block = new WheelBlockState(aTarget, aTargetConfirmed, aEvent); - INPQ_LOG("started new scroll wheel block %p for target %p\n", block, aTarget.get()); + INPQ_LOG("started new scroll wheel block %p id %" PRIu64 " for target %p\n", + block, block->GetBlockId(), aTarget.get()); SweepDepletedBlocks(); mInputBlockQueue.AppendElement(block); @@ -321,19 +323,25 @@ InputQueue::ReceivePanGestureInput(const RefPtr& aTarget block = mInputBlockQueue.LastElement()->AsPanGestureBlock(); } + PanGestureInput event = aEvent; nsEventStatus result = nsEventStatus_eConsumeDoDefault; if (!block || block->WasInterrupted()) { - if (aEvent.mType != PanGestureInput::PANGESTURE_START) { - // Only PANGESTURE_START events are allowed to start a new pan gesture block. - return nsEventStatus_eConsumeDoDefault; + if (event.mType != PanGestureInput::PANGESTURE_START) { + // Only PANGESTURE_START events are allowed to start a new pan gesture + // block, but we really want to start a new block here, so we magically + // turn this input into a PANGESTURE_START. + INPQ_LOG("transmogrifying pan input %d to PANGESTURE_START for new block\n", + event.mType); + event.mType = PanGestureInput::PANGESTURE_START; } - block = new PanGestureBlockState(aTarget, aTargetConfirmed, aEvent); - INPQ_LOG("started new pan gesture block %p for target %p\n", block, aTarget.get()); + block = new PanGestureBlockState(aTarget, aTargetConfirmed, event); + INPQ_LOG("started new pan gesture block %p id %" PRIu64 " for target %p\n", + block, block->GetBlockId(), aTarget.get()); if (aTargetConfirmed && - aEvent.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection && - !CanScrollTargetHorizontally(aEvent, block)) { + event.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection && + !CanScrollTargetHorizontally(event, block)) { // This event may trigger a swipe gesture, depending on what our caller // wants to do it. We need to suspend handling of this block until we get // a content response which will tell us whether to proceed or abort the @@ -363,8 +371,8 @@ InputQueue::ReceivePanGestureInput(const RefPtr& aTarget // null) should take priority. This is equivalent to just always using the // target (confirmed or not) from the block, which is what // MaybeHandleCurrentBlock() does. - if (!MaybeHandleCurrentBlock(block, aEvent)) { - block->AddEvent(aEvent.AsPanGestureInput()); + if (!MaybeHandleCurrentBlock(block, event)) { + block->AddEvent(event.AsPanGestureInput()); } return result; diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index 5ef6a4aed43..43b95985419 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -8,6 +8,7 @@ #include "ContentHelper.h" #include "gfxPlatform.h" // For gfxPlatform::UseTiling #include "gfxPrefs.h" +#include "LayersLogging.h" // For Stringify #include "mozilla/dom/Element.h" #include "mozilla/dom/TabParent.h" #include "mozilla/IntegerPrintfMacros.h" diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 6ce806a198c..351dfdbc75f 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -605,6 +605,12 @@ public: virtual void FlushContentDrawing() {} + // If a device reset has occurred, update the necessary platform backend + // bits. + virtual bool UpdateForDeviceReset() { + return false; + } + /** * Helper method, creates a draw target for a specific Azure backend. * Used by CreateOffscreenDrawTarget. diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index abd62ac8901..7bb41fdc8eb 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -428,6 +428,7 @@ private: DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false); DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions", WebGLPrivilegedExtensionsEnabled, bool, false); + DECL_GFX_PREF(Once, "webgl.enable-prototype-webgl2", WebGL2Enabled, bool, false); DECL_GFX_PREF(Live, "webgl.force-enabled", WebGLForceEnabled, bool, false); DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 64c1a310487..99ee4466dae 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1192,6 +1192,30 @@ gfxWindowsPlatform::DidRenderingDeviceReset(DeviceResetReason* aResetReason) return false; } +BOOL CALLBACK +InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) +{ + RedrawWindow(aWnd, nullptr, nullptr, + RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME); + return TRUE; +} + +bool +gfxWindowsPlatform::UpdateForDeviceReset() +{ + if (!DidRenderingDeviceReset()) { + return false; + } + + // Trigger an ::OnPaint for each window. + ::EnumThreadWindows(GetCurrentThreadId(), + InvalidateWindowForDeviceReset, + 0); + + gfxCriticalNote << "Detected rendering device reset on refresh"; + return true; +} + void gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size) { diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 20ec4c5fc21..02c0af4e641 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -213,7 +213,8 @@ public: */ virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) override; - virtual bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) override; + bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) override; + bool UpdateForDeviceReset() override; mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) override; diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index 80fdf2d97d3..0525243917e 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -632,7 +632,7 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags) GetWidth(&size.width); GetHeight(&size.height); - RefPtr image = new layers::CairoImage(size, surface); + RefPtr image = new layers::SourceSurfaceImage(size, surface); return MakePair(drawResult, Move(image)); } diff --git a/ipc/chromium/src/base/platform_thread_posix.cc b/ipc/chromium/src/base/platform_thread_posix.cc index eb13b980ef8..be250691a3c 100644 --- a/ipc/chromium/src/base/platform_thread_posix.cc +++ b/ipc/chromium/src/base/platform_thread_posix.cc @@ -14,9 +14,6 @@ #elif defined(OS_LINUX) #include #include -#elif defined(OS_FREEBSD) && !defined(__GLIBC__) -#include -#include #endif #if !defined(OS_MACOSX) @@ -61,13 +58,7 @@ PlatformThreadId PlatformThread::CurrentId() { #elif defined(OS_DRAGONFLY) return lwp_gettid(); #elif defined(OS_FREEBSD) -# if __FreeBSD_version > 900030 - return pthread_getthreadid_np(); -# else - long lwpid; - thr_self(&lwpid); - return lwpid; -# endif + return pthread_getthreadid_np(); #endif } diff --git a/ipc/chromium/src/base/process_util_bsd.cc b/ipc/chromium/src/base/process_util_bsd.cc index e4d233625d6..e10149b1f05 100644 --- a/ipc/chromium/src/base/process_util_bsd.cc +++ b/ipc/chromium/src/base/process_util_bsd.cc @@ -2,70 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// derived from process_util_linux.cc and process_util_mac.cc +// derived from process_util_mac.cc #include "base/process_util.h" -#include - #include -#include +#include +#include #include #include "base/eintr_wrapper.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/string_tokenizer.h" -#include "base/string_util.h" -#include "mozilla/UniquePtr.h" -#if defined(_POSIX_SPAWN) && _POSIX_SPAWN > 0 -#define HAVE_POSIX_SPAWN 1 -#endif - -/* - * On platforms that are not gonk based, we fall back to an arbitrary - * UID. This is generally the UID for user `nobody', albeit it is not - * always the case. - */ - -#if defined(OS_NETBSD) || defined(OS_OPENBSD) -# define CHILD_UNPRIVILEGED_UID 32767 -# define CHILD_UNPRIVILEGED_GID 32767 -#else -# define CHILD_UNPRIVILEGED_UID 65534 -# define CHILD_UNPRIVILEGED_GID 65534 -#endif - -#ifndef __dso_public -# ifdef __exported -# define __dso_public __exported -# else -# define __dso_public __attribute__((__visibility__("default"))) -# endif -#endif - -#ifdef HAVE_POSIX_SPAWN -#include -extern "C" char **environ __dso_public; -#endif - -namespace { - -enum ParsingState { - KEY_NAME, - KEY_VALUE -}; - -static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG"); - -} // namespace +extern "C" char **environ __attribute__((__visibility__("default"))); namespace base { -#ifdef HAVE_POSIX_SPAWN - void FreeEnvVarsArray(char* array[], int length) { for (int i = 0; i < length; i++) { @@ -201,107 +153,4 @@ void SetCurrentProcessPrivileges(ChildPrivileges privs) { } -#else // no posix_spawn, use fork/exec - -bool LaunchApp(const std::vector& argv, - const file_handle_mapping_vector& fds_to_remap, - bool wait, ProcessHandle* process_handle) { - return LaunchApp(argv, fds_to_remap, environment_map(), - wait, process_handle); -} - -bool LaunchApp(const std::vector& argv, - const file_handle_mapping_vector& fds_to_remap, - const environment_map& env_vars_to_set, - bool wait, ProcessHandle* process_handle, - ProcessArchitecture arch) { - return LaunchApp(argv, fds_to_remap, env_vars_to_set, - PRIVILEGES_INHERIT, - wait, process_handle); -} - -bool LaunchApp(const std::vector& argv, - const file_handle_mapping_vector& fds_to_remap, - const environment_map& env_vars_to_set, - ChildPrivileges privs, - bool wait, ProcessHandle* process_handle, - ProcessArchitecture arch) { - mozilla::UniquePtr argv_cstr(new char*[argv.size() + 1]); - // Illegal to allocate memory after fork and before execvp - InjectiveMultimap fd_shuffle1, fd_shuffle2; - fd_shuffle1.reserve(fds_to_remap.size()); - fd_shuffle2.reserve(fds_to_remap.size()); - - pid_t pid = fork(); - if (pid < 0) - return false; - - if (pid == 0) { - for (file_handle_mapping_vector::const_iterator - it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { - fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); - fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); - } - - if (!ShuffleFileDescriptors(&fd_shuffle1)) - _exit(127); - - CloseSuperfluousFds(fd_shuffle2); - - for (size_t i = 0; i < argv.size(); i++) - argv_cstr[i] = const_cast(argv[i].c_str()); - argv_cstr[argv.size()] = NULL; - - SetCurrentProcessPrivileges(privs); - - for (environment_map::const_iterator it = env_vars_to_set.begin(); - it != env_vars_to_set.end(); ++it) { - if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/)) - _exit(127); - } - execv(argv_cstr[0], argv_cstr.get()); - // if we get here, we're in serious trouble and should complain loudly - DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0]; - _exit(127); - } else { - gProcessLog.print("==> process %d launched child process %d\n", - GetCurrentProcId(), pid); - if (wait) - HANDLE_EINTR(waitpid(pid, 0, 0)); - - if (process_handle) - *process_handle = pid; - } - - return true; -} - -bool LaunchApp(const CommandLine& cl, - bool wait, bool start_hidden, - ProcessHandle* process_handle) { - file_handle_mapping_vector no_files; - return LaunchApp(cl.argv(), no_files, wait, process_handle); -} - -void SetCurrentProcessPrivileges(ChildPrivileges privs) { - if (privs == PRIVILEGES_INHERIT) { - return; - } - - gid_t gid = CHILD_UNPRIVILEGED_GID; - uid_t uid = CHILD_UNPRIVILEGED_UID; - if (setgid(gid) != 0) { - DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS"; - _exit(127); - } - if (setuid(uid) != 0) { - DLOG(ERROR) << "FAILED TO setuid() CHILD PROCESS"; - _exit(127); - } - if (chdir("/") != 0) - gProcessLog.print("==> could not chdir()\n"); -} - -#endif - } // namespace base diff --git a/js/public/UbiNodeCensus.h b/js/public/UbiNodeCensus.h index e881eb18848..891694efa07 100644 --- a/js/public/UbiNodeCensus.h +++ b/js/public/UbiNodeCensus.h @@ -87,7 +87,7 @@ using CountBasePtr = UniquePtr; // Abstract base class for CountType nodes. struct CountType { - explicit CountType(Census& census) : census(census) { } + explicit CountType() { } virtual ~CountType() { } // Destruct a count tree node that this type instance constructed. @@ -102,14 +102,13 @@ struct CountType { // Implement the 'count' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool count(CountBase& count, const Node& node) = 0; + virtual bool count(CountBase& count, + mozilla::MallocSizeOf mallocSizeOf, + const Node& node) = 0; // Implement the 'report' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool report(CountBase& count, MutableHandleValue report) = 0; - - protected: - Census& census; + virtual bool report(JSContext* cx, CountBase& count, MutableHandleValue report) = 0; }; using CountTypePtr = UniquePtr>; @@ -129,12 +128,16 @@ class CountBase { explicit CountBase(CountType& type) : type(type), total_(0) { } // Categorize and count |node| as appropriate for this count's type. - bool count(const Node& node) { return type.count(*this, node); } + bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { + return type.count(*this, mallocSizeOf, node); + } // Construct a JavaScript object reporting the counts recorded in this // count, and store it in |report|. Return true on success, or false on // failure. - bool report(MutableHandleValue report) { return type.report(*this, report); } + bool report(JSContext* cx, MutableHandleValue report) { + return type.report(cx, *this, report); + } // Down-cast this CountBase to its true type, based on its 'type' member, // and run its destructor. @@ -173,18 +176,6 @@ struct Census { explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } bool init(); - - // A 'new' work-alike that behaves like TempAllocPolicy: report OOM on this - // census's context, but don't charge the memory allocated to our context's - // GC pressure counters. - template - T* new_(Args&&... args) MOZ_HEAP_ALLOCATOR { - void* memory = js_malloc(sizeof(T)); - if (MOZ_UNLIKELY(!memory)) { - return nullptr; - } - return new(memory) T(mozilla::Forward(args)...); - } }; // A BreadthFirst handler type that conducts a census, using a CountBase to @@ -192,15 +183,17 @@ struct Census { class CensusHandler { Census& census; CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; public: - CensusHandler(Census& census, CountBasePtr& rootCount) + CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) : census(census), - rootCount(rootCount) + rootCount(rootCount), + mallocSizeOf(mallocSizeOf) { } - bool report(MutableHandleValue report) { - return rootCount->report(report); + bool report(JSContext* cx, MutableHandleValue report) { + return rootCount->report(cx, report); } // This class needs to retain no per-node data. @@ -213,11 +206,17 @@ class CensusHandler { using CensusTraversal = BreadthFirst; -// Examine the census options supplied by the API consumer, and use that to -// build a CountType tree. +// Examine the census options supplied by the API consumer, and (among other +// things) use that to build a CountType tree. bool ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTypePtr& outResult); +// Parse the breakdown language (as described in +// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer +// is returned on error and is reported to the cx. +CountTypePtr ParseBreakdown(JSContext* cx, HandleValue breakdownValue); + + } // namespace ubi } // namespace JS diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 8d6c4a1b7c3..1758a149c90 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -610,8 +610,6 @@ const JSFunctionSpec js::regexp_methods[] = { } DEFINE_STATIC_GETTER(static_input_getter, return res->createPendingInput(cx, args.rval())) -DEFINE_STATIC_GETTER(static_multiline_getter, args.rval().setBoolean(res->multiline()); - return true) DEFINE_STATIC_GETTER(static_lastMatch_getter, return res->createLastMatch(cx, args.rval())) DEFINE_STATIC_GETTER(static_lastParen_getter, return res->createLastParen(cx, args.rval())) DEFINE_STATIC_GETTER(static_leftContext_getter, return res->createLeftContext(cx, args.rval())) @@ -655,6 +653,36 @@ static_input_setter(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +WarnOnceAboutRegExpMultiline(JSContext* cx) +{ + if (!cx->compartment()->warnedAboutRegExpMultiline) { + if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr, + JSMSG_DEPRECATED_REGEXP_MULTILINE)) + { + return false; + } + cx->compartment()->warnedAboutRegExpMultiline = true; + } + + return true; +} + +static bool +static_multiline_getter(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + RegExpStatics* res = cx->global()->getRegExpStatics(cx); + if (!res) + return false; + + if (!WarnOnceAboutRegExpMultiline(cx)) + return false; + + args.rval().setBoolean(res->multiline()); + return true; +} + static bool static_multiline_setter(JSContext* cx, unsigned argc, Value* vp) { @@ -663,6 +691,9 @@ static_multiline_setter(JSContext* cx, unsigned argc, Value* vp) if (!res) return false; + if (!WarnOnceAboutRegExpMultiline(cx)) + return false; + bool b = ToBoolean(args.get(0)); res->setMultiline(cx, b); args.rval().setBoolean(b); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 0b8cd6af79b..f9b01f004c2 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -763,55 +763,6 @@ Statistics::Statistics(JSRuntime* rt) for (auto d : MakeRange(NumTimingArrays)) PodArrayZero(phaseTimes[d]); - static bool initialized = false; - if (!initialized) { - initialized = true; - - for (size_t i = 0; i < PHASE_LIMIT; i++) { - MOZ_ASSERT(phases[i].index == i); - for (size_t j = 0; j < PHASE_LIMIT; j++) - MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket); - } - - // Create a static table of descendants for every phase with multiple - // children. This assumes that all descendants come linearly in the - // list, which is reasonable since full dags are not supported; any - // path from the leaf to the root must encounter at most one node with - // multiple parents. - size_t dagSlot = 0; - for (size_t i = 0; i < mozilla::ArrayLength(dagChildEdges); i++) { - Phase parent = dagChildEdges[i].parent; - if (!phaseExtra[parent].dagSlot) - phaseExtra[parent].dagSlot = ++dagSlot; - - Phase child = dagChildEdges[i].child; - MOZ_ASSERT(phases[child].parent == PHASE_MULTI_PARENTS); - int j = child; - do { - dagDescendants[phaseExtra[parent].dagSlot].append(Phase(j)); - j++; - } while (j != PHASE_LIMIT && phases[j].parent != PHASE_MULTI_PARENTS); - } - MOZ_ASSERT(dagSlot <= MaxMultiparentPhases - 1); - - // Fill in the depth of each node in the tree. Multi-parented nodes - // have depth 0. - mozilla::Vector stack; - stack.append(PHASE_LIMIT); // Dummy entry to avoid special-casing the first node - for (int i = 0; i < PHASE_LIMIT; i++) { - if (phases[i].parent == PHASE_NO_PARENT || - phases[i].parent == PHASE_MULTI_PARENTS) - { - stack.clear(); - } else { - while (stack.back() != phases[i].parent) - stack.popBack(); - } - phaseExtra[i].depth = stack.length(); - stack.append(Phase(i)); - } - } - char* env = getenv("MOZ_GCTIMER"); if (env) { if (strcmp(env, "none") == 0) { @@ -834,6 +785,55 @@ Statistics::~Statistics() fclose(fp); } +/* static */ void +Statistics::initialize() +{ + for (size_t i = 0; i < PHASE_LIMIT; i++) { + MOZ_ASSERT(phases[i].index == i); + for (size_t j = 0; j < PHASE_LIMIT; j++) + MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket); + } + + // Create a static table of descendants for every phase with multiple + // children. This assumes that all descendants come linearly in the + // list, which is reasonable since full dags are not supported; any + // path from the leaf to the root must encounter at most one node with + // multiple parents. + size_t dagSlot = 0; + for (size_t i = 0; i < mozilla::ArrayLength(dagChildEdges); i++) { + Phase parent = dagChildEdges[i].parent; + if (!phaseExtra[parent].dagSlot) + phaseExtra[parent].dagSlot = ++dagSlot; + + Phase child = dagChildEdges[i].child; + MOZ_ASSERT(phases[child].parent == PHASE_MULTI_PARENTS); + int j = child; + do { + dagDescendants[phaseExtra[parent].dagSlot].append(Phase(j)); + j++; + } while (j != PHASE_LIMIT && phases[j].parent != PHASE_MULTI_PARENTS); + } + MOZ_ASSERT(dagSlot <= MaxMultiparentPhases - 1); + + // Fill in the depth of each node in the tree. Multi-parented nodes + // have depth 0. + mozilla::Vector stack; + stack.append(PHASE_LIMIT); // Dummy entry to avoid special-casing the first node + for (int i = 0; i < PHASE_LIMIT; i++) { + if (phases[i].parent == PHASE_NO_PARENT || + phases[i].parent == PHASE_MULTI_PARENTS) + { + stack.clear(); + } else { + while (stack.back() != phases[i].parent) + stack.popBack(); + } + phaseExtra[i].depth = stack.length(); + stack.append(Phase(i)); + } + +} + JS::GCSliceCallback Statistics::setSliceCallback(JS::GCSliceCallback newCallback) { diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 722e1f8a225..3f78225ef68 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -162,6 +162,8 @@ struct Statistics /* Create a convenient type for referring to tables of phase times. */ using PhaseTimeTable = int64_t[NumTimingArrays][PHASE_LIMIT]; + static void initialize(); + explicit Statistics(JSRuntime* rt); ~Statistics(); diff --git a/js/src/jit-test/tests/basic/regexp-multiline-warning.js b/js/src/jit-test/tests/basic/regexp-multiline-warning.js new file mode 100644 index 00000000000..91760f86f63 --- /dev/null +++ b/js/src/jit-test/tests/basic/regexp-multiline-warning.js @@ -0,0 +1,23 @@ +// RegExp.multiline access should be warned once and only once. + +function testWarn(code) { + enableLastWarning(); + var g = newGlobal(); + g.code = code; + g.eval('eval(code)'); + var warning = getLastWarning(); + assertEq(warning !== null, true, "warning should be caught for " + code); + assertEq(warning.name, "SyntaxError"); + + clearLastWarning(); + g.eval('eval(code)'); + warning = getLastWarning(); + assertEq(warning, null, "warning should not be caught for 2nd ocurrence"); + disableLastWarning(); +} + +testWarn("var a = RegExp.multiline;"); +testWarn("RegExp.multiline = true;"); + +testWarn("var a = RegExp['$*'];"); +testWarn("RegExp['$*'] = true;"); diff --git a/js/src/jit-test/tests/sharedbuf/subtypes.js b/js/src/jit-test/tests/sharedbuf/subtypes.js new file mode 100644 index 00000000000..ce893cc4518 --- /dev/null +++ b/js/src/jit-test/tests/sharedbuf/subtypes.js @@ -0,0 +1,53 @@ +// Test cases for subclasses of SharedArrayBuffer. + +if (!this.SharedArrayBuffer) + quit(0); + +load(libdir + "asserts.js"); + +// Basic subclassing. + +class MySharedArrayBuffer1 extends SharedArrayBuffer { + constructor(n) { super(n) } +} + +let mv1 = new MySharedArrayBuffer1(1024); +assertEq(mv1 instanceof SharedArrayBuffer, true); +assertEq(mv1 instanceof MySharedArrayBuffer1, true); +assertEq(mv1.byteLength, 1024); + +// Can construct views on the subclasses and read/write elements. + +let mva1 = new Int8Array(mv1); +assertEq(mva1.length, mv1.byteLength); +assertEq(mva1.buffer, mv1); + +for ( let i=1 ; i < mva1.length ; i++ ) + mva1[i] = i; + +for ( let i=1 ; i < mva1.length ; i++ ) + assertEq(mva1[i], (i << 24) >> 24); + +// Passing modified arguments to superclass to get a different length. + +class MySharedArrayBuffer2 extends SharedArrayBuffer { + constructor(n) { super(n-1) } +} + +let mv2 = new MySharedArrayBuffer2(10); +assertEq(mv2 instanceof SharedArrayBuffer, true); +assertEq(mv2 instanceof MySharedArrayBuffer2, true); +assertEq(mv2.byteLength, 9); + +// Returning a different object altogether. + +class MySharedArrayBuffer3 extends SharedArrayBuffer { + constructor(n) { + return new Array(n); + } +} + +let mv3 = new MySharedArrayBuffer3(10); +assertEq(mv3 instanceof Array, true); +assertEq(mv3 instanceof MySharedArrayBuffer3, false); +assertEq(mv3.length, 10); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 4bd759987b3..be68916253b 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -26,6 +26,7 @@ #include "jsscriptinlines.h" +#include "jit/BaselineFrameInfo-inl.h" #include "jit/MacroAssembler-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" diff --git a/js/src/jit/BaselineFrameInfo-inl.h b/js/src/jit/BaselineFrameInfo-inl.h new file mode 100644 index 00000000000..69987090457 --- /dev/null +++ b/js/src/jit/BaselineFrameInfo-inl.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_BaselineFrameInfo_inl_h +#define jit_BaselineFrameInfo_inl_h + +namespace js { +namespace jit { + +void +FrameInfo::pop(StackAdjustment adjust) +{ + spIndex--; + StackValue* popped = &stack[spIndex]; + + if (adjust == AdjustStack && popped->kind() == StackValue::Stack) + masm.addToStackPtr(Imm32(sizeof(Value))); + // Assert when anything uses this value. + popped->reset(); +} + +void +FrameInfo::popn(uint32_t n, StackAdjustment adjust) +{ + uint32_t poppedStack = 0; + for (uint32_t i = 0; i < n; i++) { + if (peek(-1)->kind() == StackValue::Stack) + poppedStack++; + pop(DontAdjustStack); + } + if (adjust == AdjustStack && poppedStack > 0) + masm.addToStackPtr(Imm32(sizeof(Value) * poppedStack)); +} + +} // namespace jit +} // namespace js + +#endif /* jit_BaselineFrameInfo_inl_h */ diff --git a/js/src/jit/BaselineFrameInfo.cpp b/js/src/jit/BaselineFrameInfo.cpp index e285656a96f..5f4cf8ee3c1 100644 --- a/js/src/jit/BaselineFrameInfo.cpp +++ b/js/src/jit/BaselineFrameInfo.cpp @@ -10,6 +10,9 @@ # include "jit/BytecodeAnalysis.h" #endif +#include "jit/BaselineFrameInfo-inl.h" +#include "jit/MacroAssembler-inl.h" + using namespace js; using namespace js::jit; diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h index 2866d372ba2..18af6d6ab0b 100644 --- a/js/src/jit/BaselineFrameInfo.h +++ b/js/src/jit/BaselineFrameInfo.h @@ -223,26 +223,8 @@ class FrameInfo return const_cast(&stack[spIndex + index]); } - inline void pop(StackAdjustment adjust = AdjustStack) { - spIndex--; - StackValue* popped = &stack[spIndex]; - - if (adjust == AdjustStack && popped->kind() == StackValue::Stack) - masm.addToStackPtr(Imm32(sizeof(Value))); - - // Assert when anything uses this value. - popped->reset(); - } - inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack) { - uint32_t poppedStack = 0; - for (uint32_t i = 0; i < n; i++) { - if (peek(-1)->kind() == StackValue::Stack) - poppedStack++; - pop(DontAdjustStack); - } - if (adjust == AdjustStack && poppedStack > 0) - masm.addToStackPtr(Imm32(sizeof(Value) * poppedStack)); - } + inline void pop(StackAdjustment adjust = AdjustStack); + inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack); inline void push(const Value& val) { StackValue* sv = rawPush(); sv->setConstant(val); diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index cc1b66bbba2..5df070e44c5 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -23,6 +23,7 @@ #include "jsscriptinlines.h" #include "jit/JitFrames-inl.h" +#include "jit/MacroAssembler-inl.h" #include "vm/Stack-inl.h" using namespace js; diff --git a/js/src/jit/ExecutableAllocatorWin.cpp b/js/src/jit/ExecutableAllocatorWin.cpp index fe068b90814..4fa240a2fce 100644 --- a/js/src/jit/ExecutableAllocatorWin.cpp +++ b/js/src/jit/ExecutableAllocatorWin.cpp @@ -77,22 +77,6 @@ ExecutableAllocator::computeRandomAllocationAddress() return (void*) (base | (rand & mask)); } -static bool -RandomizeIsBrokenImpl() -{ - // We disable everything before Vista, for now. - return !mozilla::IsVistaOrLater(); -} - -static bool -RandomizeIsBroken() -{ - // Use the compiler's intrinsic guards for |static type value = expr| to avoid some potential - // races if runtimes are created from multiple threads. - static int result = RandomizeIsBrokenImpl(); - return !!result; -} - #ifdef JS_CPU_X64 static js::JitExceptionHandler sJitExceptionHandler; @@ -236,15 +220,11 @@ js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize) ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n) { - void* allocation = nullptr; - if (!RandomizeIsBroken()) { - void* randomAddress = computeRandomAllocationAddress(); - allocation = AllocateExecutableMemory(randomAddress, n, initialProtectionFlags(Executable), - "js-jit-code", pageSize); - } + void* randomAddress = computeRandomAllocationAddress(); + unsigned flags = initialProtectionFlags(Executable); + void* allocation = AllocateExecutableMemory(randomAddress, n, flags, "js-jit-code", pageSize); if (!allocation) { - allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable), - "js-jit-code", pageSize); + allocation = AllocateExecutableMemory(nullptr, n, flags, "js-jit-code", pageSize); } ExecutablePool::Allocation alloc = { reinterpret_cast(allocation), n }; return alloc; diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index db06fdf8e69..0c50b1d7470 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -313,6 +313,15 @@ MacroAssembler::hasSelfReference() const return selfReferencePatch_.bound(); } +// =============================================================== +// Arithmetic functions + +void +MacroAssembler::addPtr(ImmPtr imm, Register dest) +{ + addPtr(ImmWord(uintptr_t(imm.value)), dest); +} + //}}} check_macroassembler_style // =============================================================== @@ -332,6 +341,31 @@ MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind branch32(cond, scratch, Imm32(bit), label); } +#ifndef JS_CODEGEN_ARM64 + +template void +MacroAssembler::addToStackPtr(T t) +{ + addPtr(t, getStackPointer()); +} + +template void +MacroAssembler::addStackPtrTo(T t) +{ + addPtr(getStackPointer(), t); +} + +#endif // !JS_CODEGEN_ARM64 + +void +MacroAssembler::bumpKey(Int32Key* key, int diff) +{ + if (key->isRegister()) + add32(Imm32(diff), key->reg()); + else + key->bumpConstant(diff); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2e329be9668..d3830609d57 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -731,11 +731,59 @@ class MacroAssembler : public MacroAssemblerSpecific // =============================================================== // Arithmetic functions + inline void add32(Register src, Register dest) PER_SHARED_ARCH; + inline void add32(Imm32 imm, Register dest) PER_SHARED_ARCH; + inline void add32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; + inline void add32(Imm32 imm, const AbsoluteAddress& dest) DEFINED_ON(x86_shared); + + inline void addPtr(Register src, Register dest) PER_ARCH; + inline void addPtr(Register src1, Register src2, Register dest) DEFINED_ON(arm64); + inline void addPtr(Imm32 imm, Register dest) PER_ARCH; + inline void addPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); + inline void addPtr(ImmWord imm, Register dest) PER_ARCH; + inline void addPtr(ImmPtr imm, Register dest); + inline void addPtr(Imm32 imm, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void addPtr(Imm32 imm, const AbsoluteAddress& dest) DEFINED_ON(x86, x64); + inline void addPtr(const Address& src, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + + inline void add64(Register64 src, Register64 dest) PER_ARCH; + inline void add64(Imm32 imm, Register64 dest) PER_ARCH; + + inline void addFloat32(FloatRegister src, FloatRegister dest) DEFINED_ON(x86_shared); + + inline void addDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; + inline void addConstantDouble(double d, FloatRegister dest) DEFINED_ON(x86); + inline void sub32(const Address& src, Register dest) PER_SHARED_ARCH; inline void sub32(Register src, Register dest) PER_SHARED_ARCH; inline void sub32(Imm32 imm, Register dest) PER_SHARED_ARCH; - inline void add64(Register64 src, Register64 dest) PER_ARCH; + inline void subPtr(Register src, Register dest) PER_ARCH; + inline void subPtr(Register src, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + inline void subPtr(Imm32 imm, Register dest) PER_ARCH; + inline void subPtr(const Address& addr, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + + inline void subDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; + + inline void mul32(Register src1, Register src2, Register dest, Label* onOver, Label* onZero) DEFINED_ON(arm64); + + inline void mul64(Imm64 imm, const Register64& dest) PER_ARCH; + + inline void mulBy3(Register src, Register dest) PER_ARCH; + + inline void mulDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; + + inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64); + + inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; + + inline void inc64(AbsoluteAddress dest) PER_ARCH; + + inline void neg32(Register reg) PER_SHARED_ARCH; + + inline void negateFloat(FloatRegister reg) DEFINED_ON(arm64, x86_shared); + + inline void negateDouble(FloatRegister reg) PER_SHARED_ARCH; // =============================================================== // Shift functions @@ -1002,12 +1050,7 @@ class MacroAssembler : public MacroAssemblerSpecific void branchIfNotInterpretedConstructor(Register fun, Register scratch, Label* label); - void bumpKey(Int32Key* key, int diff) { - if (key->isRegister()) - add32(Imm32(diff), key->reg()); - else - key->bumpConstant(diff); - } + inline void bumpKey(Int32Key* key, int diff); void storeKey(const Int32Key& key, const Address& dest) { if (key.isRegister()) @@ -1254,10 +1297,8 @@ class MacroAssembler : public MacroAssemblerSpecific // StackPointer manipulation functions. // On ARM64, the StackPointer is implemented as two synchronized registers. // Code shared across platforms must use these functions to be valid. - template - void addToStackPtr(T t) { addPtr(t, getStackPointer()); } - template - void addStackPtrTo(T t) { addPtr(getStackPointer(), t); } + template inline void addToStackPtr(T t); + template inline void addStackPtrTo(T t); template void subFromStackPtr(T t) { subPtr(t, getStackPointer()); } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index d43e4627da3..831a709cf44 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -34,8 +34,7 @@ using namespace js::jit; namespace js { namespace jit { -// Don't explicitly initialize, it's not guaranteed that this initializer will -// run before the constructors for static VMFunctions. +// Statics are initialized to null. /* static */ VMFunction* VMFunction::functions; AutoDetectInvalidation::AutoDetectInvalidation(JSContext* cx, MutableHandleValue rval) @@ -48,11 +47,6 @@ AutoDetectInvalidation::AutoDetectInvalidation(JSContext* cx, MutableHandleValue void VMFunction::addToFunctions() { - static bool initialized = false; - if (!initialized) { - initialized = true; - functions = nullptr; - } this->next = functions; functions = this; } diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 4ae13769493..61edf6d9e47 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -138,6 +138,62 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::add32(Register src, Register dest) +{ + ma_add(src, dest, SetCC); +} + +void +MacroAssembler::add32(Imm32 imm, Register dest) +{ + ma_add(imm, dest, SetCC); +} + +void +MacroAssembler::add32(Imm32 imm, const Address& dest) +{ + ScratchRegisterScope scratch(*this); + load32(dest, scratch); + ma_add(imm, scratch, SetCC); + store32(scratch, dest); +} + +void +MacroAssembler::addPtr(Register src, Register dest) +{ + ma_add(src, dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + ma_add(imm, dest); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + addPtr(Imm32(imm.value), dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, const Address& dest) +{ + ScratchRegisterScope scratch(*this); + loadPtr(dest, scratch); + addPtr(imm, scratch); + storePtr(scratch, dest); +} + +void +MacroAssembler::addPtr(const Address& src, Register dest) +{ + ScratchRegisterScope scratch(*this); + load32(src, scratch); + ma_add(scratch, dest, SetCC); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { @@ -145,6 +201,19 @@ MacroAssembler::add64(Register64 src, Register64 dest) ma_adc(src.high, dest.high); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + ma_add(imm, dest.low, SetCC); + ma_adc(Imm32(0), dest.high, LeaveCC); +} + +void +MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) +{ + ma_vadd(dest, src, dest); +} + void MacroAssembler::sub32(Register src, Register dest) { @@ -165,6 +234,125 @@ MacroAssembler::sub32(const Address& src, Register dest) ma_sub(scratch, dest, SetCC); } +void +MacroAssembler::subPtr(Register src, Register dest) +{ + ma_sub(src, dest); +} + +void +MacroAssembler::subPtr(Register src, const Address& dest) +{ + ScratchRegisterScope scratch(*this); + loadPtr(dest, scratch); + ma_sub(src, scratch); + storePtr(scratch, dest); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + ma_sub(imm, dest); +} + +void +MacroAssembler::subPtr(const Address& addr, Register dest) +{ + ScratchRegisterScope scratch(*this); + loadPtr(addr, scratch); + ma_sub(scratch, dest); +} + +void +MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) +{ + ma_vsub(dest, src, dest); +} + +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + ma_mov(Imm32(imm.value & 0xFFFFFFFFL), ScratchRegister); + as_mul(dest.high, dest.high, ScratchRegister); + + // high:low = LOW(dest) * LOW(imm); + as_umull(secondScratchReg_, ScratchRegister, dest.low, ScratchRegister); + + // HIGH(dest) += high; + as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) + as_add(secondScratchReg_, dest.low, lsl(dest.low, 2)); + else + MOZ_CRASH("Not supported imm"); + as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); + + // LOW(dest) = low; + ma_mov(ScratchRegister, dest.low); +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + as_add(dest, src, lsl(src, 1)); +} + +void +MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) +{ + ma_vmul(dest, src, dest); +} + +void +MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) +{ + movePtr(imm, ScratchRegister); + loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); +} + +void +MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) +{ + ma_vdiv(dest, src, dest); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + ScratchRegisterScope scratch(*this); + + ma_strd(r0, r1, EDtrAddr(sp, EDtrOffImm(-8)), PreIndex); + + ma_mov(Imm32((int32_t)dest.addr), scratch); + ma_ldrd(EDtrAddr(scratch, EDtrOffImm(0)), r0, r1); + + ma_add(Imm32(1), r0, SetCC); + ma_adc(Imm32(0), r1, LeaveCC); + + ma_strd(r0, r1, EDtrAddr(scratch, EDtrOffImm(0))); + ma_ldrd(EDtrAddr(sp, EDtrOffImm(8)), r0, r1, PostIndex); +} + +void +MacroAssembler::neg32(Register reg) +{ + ma_neg(reg, reg, SetCC); +} + +void +MacroAssembler::negateDouble(FloatRegister reg) +{ + ma_vneg(reg, reg); +} + // =============================================================== // Shift functions @@ -205,6 +393,27 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +template +void +MacroAssemblerARMCompat::branchAdd32(Condition cond, T src, Register dest, Label* label) +{ + asMasm().add32(src, dest); + j(cond, label); +} + +void +MacroAssemblerARMCompat::incrementInt32Value(const Address& addr) +{ + asMasm().add32(Imm32(1), ToPayload(addr)); +} + +void +MacroAssemblerARMCompat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) +{ + asMasm().subPtr(imm, lhs); + branch32(cond, lhs, Imm32(0), label); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 41741528a5b..b72779ef8f9 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -97,9 +97,9 @@ MacroAssemblerARMCompat::convertUInt64ToDouble(Register64 src, Register temp, Fl convertUInt32ToDouble(src.high, dest); movePtr(ImmPtr(&TO_DOUBLE_HIGH_SCALE), ScratchRegister); loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); + asMasm().mulDouble(ScratchDoubleReg, dest); convertUInt32ToDouble(src.low, ScratchDoubleReg); - addDouble(ScratchDoubleReg, dest); + asMasm().addDouble(ScratchDoubleReg, dest); } void @@ -246,53 +246,6 @@ MacroAssemblerARM::convertInt32ToFloat32(const Address& src, FloatRegister dest) as_vcvt(dest, VFPRegister(scratch).sintOverlay()); } -void -MacroAssemblerARM::addDouble(FloatRegister src, FloatRegister dest) -{ - ma_vadd(dest, src, dest); -} - -void -MacroAssemblerARM::subDouble(FloatRegister src, FloatRegister dest) -{ - ma_vsub(dest, src, dest); -} - -void -MacroAssemblerARM::mulDouble(FloatRegister src, FloatRegister dest) -{ - ma_vmul(dest, src, dest); -} - -void -MacroAssemblerARM::divDouble(FloatRegister src, FloatRegister dest) -{ - ma_vdiv(dest, src, dest); -} - -void -MacroAssemblerARM::negateDouble(FloatRegister reg) -{ - ma_vneg(reg, reg); -} - -void -MacroAssemblerARM::inc64(AbsoluteAddress dest) -{ - ScratchRegisterScope scratch(asMasm()); - - ma_strd(r0, r1, EDtrAddr(sp, EDtrOffImm(-8)), PreIndex); - - ma_mov(Imm32((int32_t)dest.addr), scratch); - ma_ldrd(EDtrAddr(scratch, EDtrOffImm(0)), r0, r1); - - ma_add(Imm32(1), r0, SetCC); - ma_adc(Imm32(0), r1, LeaveCC); - - ma_strd(r0, r1, EDtrAddr(scratch, EDtrOffImm(0))); - ma_ldrd(EDtrAddr(sp, EDtrOffImm(8)), r0, r1, PostIndex); -} - bool MacroAssemblerARM::alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op, SBit s, Condition c) @@ -1947,41 +1900,6 @@ MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic) // Exists for MIPS compatibility. } -void -MacroAssemblerARMCompat::add32(Register src, Register dest) -{ - ma_add(src, dest, SetCC); -} - -void -MacroAssemblerARMCompat::add32(Imm32 imm, Register dest) -{ - ma_add(imm, dest, SetCC); -} - -void -MacroAssemblerARMCompat::add32(Imm32 imm, const Address& dest) -{ - ScratchRegisterScope scratch(asMasm()); - load32(dest, scratch); - ma_add(imm, scratch, SetCC); - store32(scratch, dest); -} - -void -MacroAssemblerARMCompat::addPtr(Register src, Register dest) -{ - ma_add(src, dest); -} - -void -MacroAssemblerARMCompat::addPtr(const Address& src, Register dest) -{ - ScratchRegisterScope scratch(asMasm()); - load32(src, scratch); - ma_add(scratch, dest, SetCC); -} - void MacroAssemblerARMCompat::move32(Imm32 imm, Register dest) { @@ -2626,50 +2544,6 @@ MacroAssemblerARMCompat::setStackArg(Register reg, uint32_t arg) } -void -MacroAssemblerARMCompat::subPtr(Imm32 imm, const Register dest) -{ - ma_sub(imm, dest); -} - -void -MacroAssemblerARMCompat::subPtr(const Address& addr, const Register dest) -{ - ScratchRegisterScope scratch(asMasm()); - loadPtr(addr, scratch); - ma_sub(scratch, dest); -} - -void -MacroAssemblerARMCompat::subPtr(Register src, Register dest) -{ - ma_sub(src, dest); -} - -void -MacroAssemblerARMCompat::subPtr(Register src, const Address& dest) -{ - ScratchRegisterScope scratch(asMasm()); - loadPtr(dest, scratch); - ma_sub(src, scratch); - storePtr(scratch, dest); -} - -void -MacroAssemblerARMCompat::addPtr(Imm32 imm, const Register dest) -{ - ma_add(imm, dest); -} - -void -MacroAssemblerARMCompat::addPtr(Imm32 imm, const Address& dest) -{ - ScratchRegisterScope scratch(asMasm()); - loadPtr(dest, scratch); - addPtr(imm, scratch); - storePtr(scratch, dest); -} - void MacroAssemblerARMCompat::compareDouble(FloatRegister lhs, FloatRegister rhs) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 23962bbded8..f563ef05a6f 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -97,14 +97,6 @@ class MacroAssemblerARM : public Assembler void convertInt32ToFloat32(Register src, FloatRegister dest); void convertInt32ToFloat32(const Address& src, FloatRegister dest); - void addDouble(FloatRegister src, FloatRegister dest); - void subDouble(FloatRegister src, FloatRegister dest); - void mulDouble(FloatRegister src, FloatRegister dest); - void divDouble(FloatRegister src, FloatRegister dest); - - void negateDouble(FloatRegister reg); - void inc64(AbsoluteAddress dest); - // Somewhat direct wrappers for the low-level assembler funcitons // bitops. Attempt to encode a virtual alu instruction using two real // instructions. @@ -639,9 +631,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM ma_bx(scratch); } - void neg32(Register reg) { - ma_neg(reg, reg, SetCC); - } void negl(Register reg) { ma_neg(reg, reg, SetCC); } @@ -982,10 +971,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { branch32(cond, lhs, imm, label); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subPtr(imm, lhs); - branch32(cond, lhs, Imm32(0), label); - } + inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label); void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label); void moveValue(const Value& val, Register type, Register data); @@ -1185,26 +1171,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Common interface. ///////////////////////////////////////////////////////////////// public: - void add32(Register src, Register dest); - void add32(Imm32 imm, Register dest); - void add32(Imm32 imm, const Address& dest); - template - void branchAdd32(Condition cond, T src, Register dest, Label* label) { - add32(src, dest); - j(cond, label); - } + template inline void branchAdd32(Condition cond, T src, Register dest, Label* label); template void branchSub32(Condition cond, T src, Register dest, Label* label) { ma_sub(src, dest, SetCC); j(cond, label); } - void addPtr(Register src, Register dest); - void addPtr(const Address& src, Register dest); - void add64(Imm32 imm, Register64 dest) { - ma_add(imm, dest.low, SetCC); - ma_adc(Imm32(0), dest.high, LeaveCC); - } void not32(Register reg); void move32(Imm32 imm, Register dest); @@ -1631,9 +1604,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM ma_mov(Imm32(0), reg, LeaveCC, Signed); } - void incrementInt32Value(const Address& addr) { - add32(Imm32(1), ToPayload(addr)); - } + inline void incrementInt32Value(const Address& addr); void cmp32(Register lhs, Imm32 rhs); void cmp32(Register lhs, Register rhs); @@ -1651,54 +1622,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void cmpPtr(const Address& lhs, ImmGCPtr rhs); void cmpPtr(const Address& lhs, Imm32 rhs); - void subPtr(Imm32 imm, const Register dest); - void subPtr(const Address& addr, const Register dest); - void subPtr(Register src, Register dest); - void subPtr(Register src, const Address& dest); - void addPtr(Imm32 imm, const Register dest); - void addPtr(Imm32 imm, const Address& dest); - void addPtr(ImmWord imm, const Register dest) { - addPtr(Imm32(imm.value), dest); - } - void addPtr(ImmPtr imm, const Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } - void mulBy3(const Register& src, const Register& dest) { - as_add(dest, src, lsl(src, 1)); - } - void mul64(Imm64 imm, const Register64& dest) { - // LOW32 = LOW(LOW(dest) * LOW(imm)); - // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] - // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] - // + HIGH(LOW(dest) * LOW(imm)) [carry] - - // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); - ma_mov(Imm32(imm.value & 0xFFFFFFFFL), ScratchRegister); - as_mul(dest.high, dest.high, ScratchRegister); - - // high:low = LOW(dest) * LOW(imm); - as_umull(secondScratchReg_, ScratchRegister, dest.low, ScratchRegister); - - // HIGH(dest) += high; - as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); - - // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); - if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) - as_add(secondScratchReg_, dest.low, lsl(dest.low, 2)); - else - MOZ_CRASH("Not supported imm"); - as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); - - // LOW(dest) = low; - ma_mov(ScratchRegister, dest.low); - } - void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - movePtr(imm, ScratchRegister); - loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); - } void setStackArg(Register reg, uint32_t arg); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 7550437a4ad..d1046efd873 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -150,12 +150,101 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::add32(Register src, Register dest) +{ + Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); +} + +void +MacroAssembler::add32(Imm32 imm, Register dest) +{ + Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); +} + +void +MacroAssembler::add32(Imm32 imm, const Address& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch32 = temps.AcquireW(); + MOZ_ASSERT(scratch32.asUnsized() != dest.base); + + Ldr(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); + Add(scratch32, scratch32, Operand(imm.value)); + Str(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); +} + +void +MacroAssembler::addPtr(Register src, Register dest) +{ + addPtr(src, dest, dest); +} + +void +MacroAssembler::addPtr(Register src1, Register src2, Register dest) +{ + Add(ARMRegister(dest, 64), ARMRegister(src1, 64), Operand(ARMRegister(src2, 64))); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + addPtr(imm, dest, dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register src, Register dest) +{ + Add(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value)); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); +} + +void +MacroAssembler::addPtr(Imm32 imm, const Address& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(scratch64.asUnsized() != dest.base); + + Ldr(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); + Add(scratch64, scratch64, Operand(imm.value)); + Str(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); +} + +void +MacroAssembler::addPtr(const Address& src, Register dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(scratch64.asUnsized() != src.base); + + Ldr(scratch64, MemOperand(ARMRegister(src.base, 64), src.offset)); + Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64)); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { addPtr(src.reg, dest.reg); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value)); +} + +void +MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) +{ + fadd(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); +} + void MacroAssembler::sub32(Imm32 imm, Register dest) { @@ -178,6 +267,135 @@ MacroAssembler::sub32(const Address& src, Register dest) Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32)); } +void +MacroAssembler::subPtr(Register src, Register dest) +{ + Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); +} + +void +MacroAssembler::subPtr(Register src, const Address& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(scratch64.asUnsized() != dest.base); + + Ldr(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); + Sub(scratch64, scratch64, Operand(ARMRegister(src, 64))); + Str(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); +} + +void +MacroAssembler::subPtr(const Address& addr, Register dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(scratch64.asUnsized() != addr.base); + + Ldr(scratch64, MemOperand(ARMRegister(addr.base, 64), addr.offset)); + Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64)); +} + +void +MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) +{ + fsub(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); +} + +void +MacroAssembler::mul32(Register src1, Register src2, Register dest, Label* onOver, Label* onZero) +{ + Smull(ARMRegister(dest, 64), ARMRegister(src1, 32), ARMRegister(src2, 32)); + if (onOver) { + Cmp(ARMRegister(dest, 64), Operand(ARMRegister(dest, 32), vixl::SXTW)); + B(onOver, NotEqual); + } + if (onZero) + Cbz(ARMRegister(dest, 32), onZero); + + // Clear upper 32 bits. + Mov(ARMRegister(dest, 32), ARMRegister(dest, 32)); +} + +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(dest.reg != scratch64.asUnsized()); + mov(ImmWord(imm.value), scratch64.asUnsized()); + Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64); +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + ARMRegister xdest(dest, 64); + ARMRegister xsrc(src, 64); + Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1)); +} + +void +MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) +{ + fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); +} + +void +MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) +{ + vixl::UseScratchRegisterScope temps(this); + const Register scratch = temps.AcquireX().asUnsized(); + MOZ_ASSERT(temp != scratch); + movePtr(imm, scratch); + const ARMFPRegister scratchDouble = temps.AcquireD(); + Ldr(scratchDouble, MemOperand(Address(scratch, 0))); + fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble); +} + +void +MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) +{ + fdiv(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratchAddr64 = temps.AcquireX(); + const ARMRegister scratch64 = temps.AcquireX(); + + Mov(scratchAddr64, uint64_t(dest.addr)); + Ldr(scratch64, MemOperand(scratchAddr64, 0)); + Add(scratch64, scratch64, Operand(1)); + Str(scratch64, MemOperand(scratchAddr64, 0)); +} + +void +MacroAssembler::neg32(Register reg) +{ + Negs(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32))); +} + +void +MacroAssembler::negateFloat(FloatRegister reg) +{ + fneg(ARMFPRegister(reg, 32), ARMFPRegister(reg, 32)); +} + +void +MacroAssembler::negateDouble(FloatRegister reg) +{ + fneg(ARMFPRegister(reg, 64), ARMFPRegister(reg, 64)); +} + // =============================================================== // Shift functions @@ -220,6 +438,34 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +template +void +MacroAssemblerCompat::addToStackPtr(T t) +{ + asMasm().addPtr(t, getStackPointer()); +} + +template +void +MacroAssemblerCompat::addStackPtrTo(T t) +{ + asMasm().addPtr(getStackPointer(), t); +} + +template +void +MacroAssemblerCompat::subFromStackPtr(T t) +{ + asMasm().subPtr(t, getStackPointer()); syncStackPtr(); +} + +template +void +MacroAssemblerCompat::subStackPtrFrom(T t) +{ + asMasm().subPtr(getStackPointer(), t); +} + template void MacroAssemblerCompat::andToStackPtr(T t) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index c7060b57a28..adda0d64c11 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -226,7 +226,7 @@ MacroAssemblerCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Regi const Nursery& nursery = GetJitContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); + asMasm().addPtr(ptr, temp); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, temp, ImmWord(nursery.nurserySize()), label); } @@ -248,7 +248,7 @@ MacroAssemblerCompat::branchValueIsNurseryObject(Condition cond, ValueOperand va Value start = ObjectValue(*reinterpret_cast(nursery.start())); movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), temp); - addPtr(value.valueReg(), temp); + asMasm().addPtr(value.valueReg(), temp); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, temp, ImmWord(nursery.nurserySize()), label); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 268caa8b2c2..da13c0bc803 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -814,10 +814,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler BufferOffset movePatchablePtr(ImmWord ptr, Register dest); BufferOffset movePatchablePtr(ImmPtr ptr, Register dest); - void neg32(Register reg) { - Negs(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32))); - } - void loadPtr(wasm::SymbolicAddress address, Register dest) { vixl::UseScratchRegisterScope temps(this); const ARMRegister scratch = temps.AcquireX(); @@ -1029,15 +1025,11 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void storeUnalignedFloat32x4(FloatRegister dest, const BaseIndex& addr) { MOZ_CRASH("NYI"); } // StackPointer manipulation. - template - void addToStackPtr(T t) { addPtr(t, getStackPointer()); } - template - void addStackPtrTo(T t) { addPtr(getStackPointer(), t); } + template void addToStackPtr(T t); + template void addStackPtrTo(T t); - template - void subFromStackPtr(T t) { subPtr(t, getStackPointer()); syncStackPtr(); } - template - void subStackPtrFrom(T t) { subPtr(getStackPointer(), t); } + template inline void subFromStackPtr(T t); + template inline void subStackPtrFrom(T t); template void andToStackPtr(T t); template void andStackPtrTo(T t); @@ -1234,24 +1226,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void zeroFloat32(FloatRegister reg) { fmov(ARMFPRegister(reg, 32), vixl::wzr); } - void negateDouble(FloatRegister reg) { - fneg(ARMFPRegister(reg, 64), ARMFPRegister(reg, 64)); - } - void negateFloat(FloatRegister reg) { - fneg(ARMFPRegister(reg, 32), ARMFPRegister(reg, 32)); - } - void addDouble(FloatRegister src, FloatRegister dest) { - fadd(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); - } - void subDouble(FloatRegister src, FloatRegister dest) { - fsub(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); - } - void mulDouble(FloatRegister src, FloatRegister dest) { - fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); - } - void divDouble(FloatRegister src, FloatRegister dest) { - fdiv(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64)); - } void moveFloat32(FloatRegister src, FloatRegister dest) { fmov(ARMFPRegister(dest, 32), ARMFPRegister(src, 32)); @@ -1328,22 +1302,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler doBaseIndex(ARMRegister(dest, 32), src, vixl::LDRH_w); } - void add32(Register src, Register dest) { - Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); - } - void add32(Imm32 imm, Register dest) { - Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); - } - void add32(Imm32 imm, const Address& dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch32 = temps.AcquireW(); - MOZ_ASSERT(scratch32.asUnsized() != dest.base); - - Ldr(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - Add(scratch32, scratch32, Operand(imm.value)); - Str(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - } - void adds32(Register src, Register dest) { Adds(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); } @@ -1359,9 +1317,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Adds(scratch32, scratch32, Operand(imm.value)); Str(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); } - void add64(Imm32 imm, Register64 dest) { - Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value)); - } void subs32(Imm32 imm, Register dest) { Subs(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); @@ -1370,79 +1325,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Subs(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); } - void addPtr(Register src, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); - } - void addPtr(Register src1, Register src2, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(src1, 64), Operand(ARMRegister(src2, 64))); - } - - void addPtr(Imm32 imm, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void addPtr(Imm32 imm, Register src, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value)); - } - - void addPtr(Imm32 imm, const Address& dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch64 = temps.AcquireX(); - MOZ_ASSERT(scratch64.asUnsized() != dest.base); - - Ldr(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - Add(scratch64, scratch64, Operand(imm.value)); - Str(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - } - void addPtr(ImmWord imm, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void addPtr(ImmPtr imm, Register dest) { - Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(uint64_t(imm.value))); - } - void addPtr(const Address& src, Register dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch64 = temps.AcquireX(); - MOZ_ASSERT(scratch64.asUnsized() != src.base); - - Ldr(scratch64, MemOperand(ARMRegister(src.base, 64), src.offset)); - Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64)); - } - void subPtr(Imm32 imm, Register dest) { - Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void subPtr(Register src, Register dest) { - Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); - } - void subPtr(const Address& addr, Register dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch64 = temps.AcquireX(); - MOZ_ASSERT(scratch64.asUnsized() != addr.base); - - Ldr(scratch64, MemOperand(ARMRegister(addr.base, 64), addr.offset)); - Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64)); - } - void subPtr(Register src, const Address& dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch64 = temps.AcquireX(); - MOZ_ASSERT(scratch64.asUnsized() != dest.base); - - Ldr(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - Sub(scratch64, scratch64, Operand(ARMRegister(src, 64))); - Str(scratch64, MemOperand(ARMRegister(dest.base, 64), dest.offset)); - } - void mul32(Register src1, Register src2, Register dest, Label* onOver, Label* onZero) { - Smull(ARMRegister(dest, 64), ARMRegister(src1, 32), ARMRegister(src2, 32)); - if (onOver) { - Cmp(ARMRegister(dest, 64), Operand(ARMRegister(dest, 32), vixl::SXTW)); - B(onOver, NotEqual); - } - if (onZero) - Cbz(ARMRegister(dest, 32), onZero); - - // Clear upper 32 bits. - Mov(ARMRegister(dest, 32), ARMRegister(dest, 32)); - } - void ret() { pop(lr); abiret(); @@ -2945,32 +2827,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler vixl::MacroAssembler::Ret(vixl::lr); } - void mulBy3(Register src, Register dest) { - ARMRegister xdest(dest, 64); - ARMRegister xsrc(src, 64); - Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1)); - } - - void mul64(Imm64 imm, const Register64& dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch64 = temps.AcquireX(); - MOZ_ASSERT(dest.reg != scratch64.asUnsized()); - mov(ImmWord(imm.value), scratch64.asUnsized()); - Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64); - } - void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) { Ucvtf(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64)); } - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - vixl::UseScratchRegisterScope temps(this); - const Register scratch = temps.AcquireX().asUnsized(); - MOZ_ASSERT(temp != scratch); - movePtr(imm, scratch); - const ARMFPRegister scratchDouble = temps.AcquireD(); - Ldr(scratchDouble, MemOperand(Address(scratch, 0))); - fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble); - } template void branchAdd32(Condition cond, T src, Register dest, Label* label) { @@ -3011,16 +2870,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Add(scratch32, scratch32, Operand(1)); store32(scratch32.asUnsized(), addr); } - void inc64(AbsoluteAddress dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratchAddr64 = temps.AcquireX(); - const ARMRegister scratch64 = temps.AcquireX(); - - Mov(scratchAddr64, uint64_t(dest.addr)); - Ldr(scratch64, MemOperand(scratchAddr64, 0)); - Add(scratch64, scratch64, Operand(1)); - Str(scratch64, MemOperand(scratchAddr64, 0)); - } void BoundsCheck(Register ptrReg, Label* onFail, vixl::CPURegister zeroMe = vixl::NoReg) { // use tst rather than Tst to *ensure* that a single instrution is generated. diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 19ee11aa456..2e00baf5c76 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -78,6 +78,47 @@ MacroAssembler::xor32(Imm32 imm, Register dest) // =============================================================== // Arithmetic instructions +void +MacroAssembler::add32(Register src, Register dest) +{ + as_addu(dest, dest, src); +} + +void +MacroAssembler::add32(Imm32 imm, Register dest) +{ + ma_addu(dest, dest, imm); +} + +void +MacroAssembler::add32(Imm32 imm, const Address& dest) +{ + load32(dest, SecondScratchReg); + ma_addu(SecondScratchReg, imm); + store32(SecondScratchReg, dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, const Address& dest) +{ + loadPtr(dest, ScratchRegister); + addPtr(imm, ScratchRegister); + storePtr(ScratchRegister, dest); +} + +void +MacroAssembler::addPtr(const Address& src, Register dest) +{ + loadPtr(src, ScratchRegister); + addPtr(ScratchRegister, dest); +} + +void +MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) +{ + as_addd(dest, dest, src); +} + void MacroAssembler::sub32(Register src, Register dest) { @@ -97,6 +138,59 @@ MacroAssembler::sub32(const Address& src, Register dest) as_subu(dest, dest, SecondScratchReg); } +void +MacroAssembler::subPtr(Register src, const Address& dest) +{ + loadPtr(dest, SecondScratchReg); + subPtr(src, SecondScratchReg); + storePtr(SecondScratchReg, dest); +} + +void +MacroAssembler::subPtr(const Address& addr, Register dest) +{ + loadPtr(addr, SecondScratchReg); + subPtr(SecondScratchReg, dest); +} + +void +MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) +{ + as_subd(dest, dest, src); +} + +void +MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) +{ + as_muld(dest, dest, src); +} + +void +MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) +{ + movePtr(imm, ScratchRegister); + loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); +} + +void +MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) +{ + as_divd(dest, dest, src); +} + +void +MacroAssembler::neg32(Register reg) +{ + ma_negu(reg, reg); +} + +void +MacroAssembler::negateDouble(FloatRegister reg) +{ + as_negd(reg, reg); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index d7fce94fbf2..9dab27f7d5d 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -78,6 +78,24 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::addPtr(Register src, Register dest) +{ + ma_addu(dest, src); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + ma_addu(dest, imm); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + addPtr(Imm32(imm.value), dest); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { @@ -87,6 +105,96 @@ MacroAssembler::add64(Register64 src, Register64 dest) as_addu(dest.high, dest.high, ScratchRegister); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + as_addiu(dest.low, dest.low, imm.value); + as_sltiu(ScratchRegister, dest.low, imm.value); + as_addu(dest.high, dest.high, ScratchRegister); +} + +void +MacroAssembler::subPtr(Register src, Register dest) +{ + as_subu(dest, dest, src); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + ma_subu(dest, dest, imm); +} + +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + ma_li(ScratchRegister, Imm32(imm.value & LOW_32_MASK)); + as_multu(dest.high, ScratchRegister); + as_mflo(dest.high); + + // mfhi:mflo = LOW(dest) * LOW(imm); + as_multu(dest.low, ScratchRegister); + + // HIGH(dest) += mfhi; + as_mfhi(ScratchRegister); + as_addu(dest.high, dest.high, ScratchRegister); + + if (((imm.value >> 32) & LOW_32_MASK) == 5) { + // Optimized case for Math.random(). + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + as_sll(ScratchRegister, dest.low, 2); + as_addu(ScratchRegister, ScratchRegister, dest.low); + as_addu(dest.high, dest.high, ScratchRegister); + + // LOW(dest) = mflo; + as_mflo(dest.low); + } else { + // tmp = mflo + as_mflo(SecondScratchReg); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + ma_li(ScratchRegister, Imm32((imm.value >> 32) & LOW_32_MASK)); + as_multu(dest.low, ScratchRegister); + as_mflo(ScratchRegister); + as_addu(dest.high, dest.high, ScratchRegister); + + // LOW(dest) = tmp; + ma_move(dest.low, SecondScratchReg); + } +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + as_addu(dest, src, src); + as_addu(dest, dest, src); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + ma_li(ScratchRegister, Imm32((int32_t)dest.addr)); + as_lw(SecondScratchReg, ScratchRegister, 0); + + as_addiu(SecondScratchReg, SecondScratchReg, 1); + as_sw(SecondScratchReg, ScratchRegister, 0); + + as_sltiu(SecondScratchReg, SecondScratchReg, 1); + as_lw(ScratchRegister, ScratchRegister, 4); + + as_addu(SecondScratchReg, ScratchRegister, SecondScratchReg); + + ma_li(ScratchRegister, Imm32((int32_t)dest.addr)); + as_sw(SecondScratchReg, ScratchRegister, 4); +} + // =============================================================== // Shift functions @@ -131,6 +239,36 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +void +MacroAssemblerMIPSCompat::incrementInt32Value(const Address& addr) +{ + asMasm().add32(Imm32(1), ToPayload(addr)); +} + +void +MacroAssemblerMIPSCompat::computeEffectiveAddress(const BaseIndex& address, Register dest) +{ + computeScaledAddress(address, dest); + if (address.offset) + asMasm().addPtr(Imm32(address.offset), dest); +} + +void +MacroAssemblerMIPSCompat::retn(Imm32 n) { + // pc <- [sp]; sp += n + loadPtr(Address(StackPointer, 0), ra); + asMasm().addPtr(n, StackPointer); + as_jr(ra); + as_nop(); +} + +void +MacroAssemblerMIPSCompat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) +{ + asMasm().subPtr(imm, lhs); + branchPtr(cond, lhs, Imm32(0), label); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 462c1d0a873..95593367002 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -77,51 +77,6 @@ MacroAssemblerMIPSCompat::convertUInt32ToDouble(Register src, FloatRegister dest as_addd(dest, dest, SecondScratchDoubleReg); } -void -MacroAssemblerMIPSCompat::mul64(Imm64 imm, const Register64& dest) -{ - // LOW32 = LOW(LOW(dest) * LOW(imm)); - // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] - // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] - // + HIGH(LOW(dest) * LOW(imm)) [carry] - - // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); - ma_li(ScratchRegister, Imm32(imm.value & LOW_32_MASK)); - as_multu(dest.high, ScratchRegister); - as_mflo(dest.high); - - // mfhi:mflo = LOW(dest) * LOW(imm); - as_multu(dest.low, ScratchRegister); - - // HIGH(dest) += mfhi; - as_mfhi(ScratchRegister); - as_addu(dest.high, dest.high, ScratchRegister); - - if (((imm.value >> 32) & LOW_32_MASK) == 5) { - // Optimized case for Math.random(). - - // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); - as_sll(ScratchRegister, dest.low, 2); - as_addu(ScratchRegister, ScratchRegister, dest.low); - as_addu(dest.high, dest.high, ScratchRegister); - - // LOW(dest) = mflo; - as_mflo(dest.low); - } else { - // tmp = mflo - as_mflo(SecondScratchReg); - - // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); - ma_li(ScratchRegister, Imm32((imm.value >> 32) & LOW_32_MASK)); - as_multu(dest.low, ScratchRegister); - as_mflo(ScratchRegister); - as_addu(dest.high, dest.high, ScratchRegister); - - // LOW(dest) = tmp; - ma_move(dest.low, SecondScratchReg); - } -} - static const double TO_DOUBLE_HIGH_SCALE = 0x100000000; void @@ -129,9 +84,9 @@ MacroAssemblerMIPSCompat::convertUInt64ToDouble(Register64 src, Register temp, F { convertUInt32ToDouble(src.high, dest); loadConstantDouble(TO_DOUBLE_HIGH_SCALE, ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); + asMasm().mulDouble(ScratchDoubleReg, dest); convertUInt32ToDouble(src.low, ScratchDoubleReg); - addDouble(ScratchDoubleReg, dest); + asMasm().addDouble(ScratchDoubleReg, dest); } void @@ -263,54 +218,6 @@ MacroAssemblerMIPSCompat::convertInt32ToFloat32(const Address& src, FloatRegiste as_cvtsw(dest, dest); } -void -MacroAssemblerMIPSCompat::addDouble(FloatRegister src, FloatRegister dest) -{ - as_addd(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::subDouble(FloatRegister src, FloatRegister dest) -{ - as_subd(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::mulDouble(FloatRegister src, FloatRegister dest) -{ - as_muld(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::divDouble(FloatRegister src, FloatRegister dest) -{ - as_divd(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::negateDouble(FloatRegister reg) -{ - as_negd(reg, reg); -} - -void -MacroAssemblerMIPSCompat::inc64(AbsoluteAddress dest) -{ - ma_li(ScratchRegister, Imm32((int32_t)dest.addr)); - as_lw(SecondScratchReg, ScratchRegister, 0); - - as_addiu(SecondScratchReg, SecondScratchReg, 1); - as_sw(SecondScratchReg, ScratchRegister, 0); - - as_sltiu(SecondScratchReg, SecondScratchReg, 1); - as_lw(ScratchRegister, ScratchRegister, 4); - - as_addu(SecondScratchReg, ScratchRegister, SecondScratchReg); - - ma_li(ScratchRegister, Imm32((int32_t)dest.addr)); - as_sw(SecondScratchReg, ScratchRegister, 4); -} - void MacroAssemblerMIPS::ma_li(Register dest, CodeOffset* label) { @@ -812,46 +719,6 @@ MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void* fakeReturnAddr) return true; } -void -MacroAssemblerMIPSCompat::add32(Register src, Register dest) -{ - as_addu(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::add32(Imm32 imm, Register dest) -{ - ma_addu(dest, dest, imm); -} - -void - -MacroAssemblerMIPSCompat::add32(Imm32 imm, const Address& dest) -{ - load32(dest, SecondScratchReg); - ma_addu(SecondScratchReg, imm); - store32(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPSCompat::addPtr(Register src, Register dest) -{ - ma_addu(dest, src); -} - -void -MacroAssemblerMIPSCompat::addPtr(const Address& src, Register dest) -{ - loadPtr(src, ScratchRegister); - ma_addu(dest, ScratchRegister); -} - -void -MacroAssemblerMIPSCompat::subPtr(Register src, Register dest) -{ - as_subu(dest, dest, src); -} - void MacroAssemblerMIPSCompat::move32(Imm32 imm, Register dest) { @@ -1241,41 +1108,6 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) bind(&done); } -void -MacroAssemblerMIPSCompat::subPtr(Imm32 imm, const Register dest) -{ - ma_subu(dest, dest, imm); -} - -void -MacroAssemblerMIPSCompat::subPtr(const Address& addr, const Register dest) -{ - loadPtr(addr, SecondScratchReg); - subPtr(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPSCompat::subPtr(Register src, const Address& dest) -{ - loadPtr(dest, SecondScratchReg); - subPtr(src, SecondScratchReg); - storePtr(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPSCompat::addPtr(Imm32 imm, const Register dest) -{ - ma_addu(dest, imm); -} - -void -MacroAssemblerMIPSCompat::addPtr(Imm32 imm, const Address& dest) -{ - loadPtr(dest, ScratchRegister); - addPtr(imm, ScratchRegister); - storePtr(ScratchRegister, dest); -} - void MacroAssemblerMIPSCompat::branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) @@ -2175,7 +2007,7 @@ void MacroAssemblerMIPSCompat::pushValue(ValueOperand val) { // Allocate stack slots for type and payload. One for each. - subPtr(Imm32(sizeof(Value)), StackPointer); + asMasm().subPtr(Imm32(sizeof(Value)), StackPointer); // Store type and payload. storeValue(val, Address(StackPointer, 0)); } @@ -2293,7 +2125,7 @@ void MacroAssemblerMIPSCompat::alignStackPointer() { movePtr(StackPointer, SecondScratchReg); - subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + asMasm().subPtr(Imm32(sizeof(uintptr_t)), StackPointer); asMasm().andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); storePtr(SecondScratchReg, Address(StackPointer, 0)); } @@ -2329,7 +2161,7 @@ MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler) { // Reserve space for exception information. int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1); - subPtr(Imm32(size), StackPointer); + asMasm().subPtr(Imm32(size), StackPointer); ma_move(a0, StackPointer); // Use a0 since it is a first function argument // Call the handler. @@ -2548,7 +2380,7 @@ MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Condition cond, Register ptr, const Nursery& nursery = GetJitContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg); - addPtr(ptr, SecondScratchReg); + asMasm().addPtr(ptr, SecondScratchReg); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, SecondScratchReg, Imm32(nursery.nurserySize()), label); } @@ -2647,7 +2479,7 @@ void MacroAssembler::reserveStack(uint32_t amount) { if (amount) - subPtr(Imm32(amount), StackPointer); + asMasm().subPtr(Imm32(amount), StackPointer); adjustFrame(amount); } @@ -2663,7 +2495,7 @@ MacroAssembler::setupUnalignedABICall(Register scratch) ma_move(scratch, StackPointer); // Force sp to be aligned - subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + asMasm().subPtr(Imm32(sizeof(uintptr_t)), StackPointer); ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); storePtr(scratch, Address(StackPointer, 0)); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 319748378f6..ce85e06f1d6 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -175,26 +175,13 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void convertInt32ToFloat32(Register src, FloatRegister dest); void convertInt32ToFloat32(const Address& src, FloatRegister dest); - void addDouble(FloatRegister src, FloatRegister dest); - void subDouble(FloatRegister src, FloatRegister dest); - void mulDouble(FloatRegister src, FloatRegister dest); - void divDouble(FloatRegister src, FloatRegister dest); - - void negateDouble(FloatRegister reg); - void inc64(AbsoluteAddress dest); - void computeScaledAddress(const BaseIndex& address, Register dest); void computeEffectiveAddress(const Address& address, Register dest) { ma_addu(dest, address.base, Imm32(address.offset)); } - void computeEffectiveAddress(const BaseIndex& address, Register dest) { - computeScaledAddress(address, dest); - if (address.offset) { - addPtr(Imm32(address.offset), dest); - } - } + inline void computeEffectiveAddress(const BaseIndex& address, Register dest); void j(Label* dest) { ma_b(dest); @@ -235,13 +222,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS as_jr(ra); as_nop(); } - void retn(Imm32 n) { - // pc <- [sp]; sp += n - loadPtr(Address(StackPointer, 0), ra); - addPtr(n, StackPointer); - as_jr(ra); - as_nop(); - } + inline void retn(Imm32 n); void push(Imm32 imm) { ma_li(ScratchRegister, imm); ma_push(ScratchRegister); @@ -317,9 +298,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS branch(code); } - void neg32(Register reg) { - ma_negu(reg, reg); - } void negl(Register reg) { ma_negu(reg, reg); } @@ -566,10 +544,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { ma_b(lhs, imm, label, cond); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subPtr(imm, lhs); - branchPtr(cond, lhs, Imm32(0), label); - } + inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label); // higher level tag testing code Operand ToPayload(Operand base); @@ -1072,18 +1047,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS Register temp, Register valueTemp, Register offsetTemp, Register maskTemp, AnyRegister output); - void add32(Register src, Register dest); - void add32(Imm32 imm, Register dest); - void add32(Imm32 imm, const Address& dest); - void add64(Imm32 imm, Register64 dest) { - as_addiu(dest.low, dest.low, imm.value); - as_sltiu(ScratchRegister, dest.low, imm.value); - as_addu(dest.high, dest.high, ScratchRegister); - } - - void incrementInt32Value(const Address& addr) { - add32(Imm32(1), ToPayload(addr)); - } + inline void incrementInt32Value(const Address& addr); template void branchAdd32(Condition cond, T src, Register dest, Label* overflow) { @@ -1111,10 +1075,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS } } - void addPtr(Register src, Register dest); - void subPtr(Register src, Register dest); - void addPtr(const Address& src, Register dest); - void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); void move64(Register64 src, Register64 dest) { @@ -1255,30 +1215,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void clampIntToUint8(Register reg); - void subPtr(Imm32 imm, const Register dest); - void subPtr(const Address& addr, const Register dest); - void subPtr(Register src, const Address& dest); - void addPtr(Imm32 imm, const Register dest); - void addPtr(Imm32 imm, const Address& dest); - void addPtr(ImmWord imm, const Register dest) { - addPtr(Imm32(imm.value), dest); - } - void addPtr(ImmPtr imm, const Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } - void mulBy3(const Register& src, const Register& dest) { - as_addu(dest, src, src); - as_addu(dest, dest, src); - } - - void mul64(Imm64 imm, const Register64& dest); - void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - movePtr(imm, ScratchRegister); - loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); - } void breakpoint(); diff --git a/js/src/jit/mips64/MacroAssembler-mips64-inl.h b/js/src/jit/mips64/MacroAssembler-mips64-inl.h index 6f84296df14..10f4a785d4c 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h +++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h @@ -76,12 +76,74 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::addPtr(Register src, Register dest) +{ + ma_daddu(dest, src); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + ma_daddu(dest, imm); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + movePtr(imm, ScratchRegister); + addPtr(ScratchRegister, dest); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { addPtr(src.reg, dest.reg); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + ma_daddu(dest.reg, imm); +} + +void +MacroAssembler::subPtr(Register src, Register dest) +{ + as_dsubu(dest, dest, src); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + ma_dsubu(dest, dest, imm); +} + +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + MOZ_ASSERT(dest.reg != ScratchRegister); + mov(ImmWord(imm.value), ScratchRegister); + as_dmultu(dest.reg, ScratchRegister); + as_mflo(dest.reg); +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + as_daddu(dest, src, src); + as_daddu(dest, dest, src); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + ma_li(ScratchRegister, ImmWord(uintptr_t(dest.addr))); + as_ld(SecondScratchReg, ScratchRegister, 0); + as_daddiu(SecondScratchReg, SecondScratchReg, 1); + as_sd(SecondScratchReg, ScratchRegister, 0); +} + // =============================================================== // Shift functions @@ -118,6 +180,37 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +void +MacroAssemblerMIPS64Compat::incrementInt32Value(const Address& addr) +{ + asMasm().add32(Imm32(1), addr); +} + +void +MacroAssemblerMIPS64Compat::computeEffectiveAddress(const BaseIndex& address, Register dest) +{ + computeScaledAddress(address, dest); + if (address.offset) + asMasm().addPtr(Imm32(address.offset), dest); +} + +void +MacroAssemblerMIPS64Compat::retn(Imm32 n) +{ + // pc <- [sp]; sp += n + loadPtr(Address(StackPointer, 0), ra); + asMasm().addPtr(n, StackPointer); + as_jr(ra); + as_nop(); +} + +void +MacroAssemblerMIPS64Compat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) +{ + asMasm().subPtr(imm, lhs); + branchPtr(cond, lhs, Imm32(0), label); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 6b30781854a..8cbe3c72994 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -88,7 +88,7 @@ MacroAssemblerMIPS64Compat::convertUInt64ToDouble(Register64 src, Register temp, ma_or(ScratchRegister, SecondScratchReg); as_dmtc1(ScratchRegister, dest); as_cvtdl(dest, dest); - addDouble(dest, dest); + asMasm().addDouble(dest, dest); ma_b(&done, ShortJump); bind(&positive); @@ -227,45 +227,6 @@ MacroAssemblerMIPS64Compat::convertInt32ToFloat32(const Address& src, FloatRegis as_cvtsw(dest, dest); } -void -MacroAssemblerMIPS64Compat::addDouble(FloatRegister src, FloatRegister dest) -{ - as_addd(dest, dest, src); -} - -void -MacroAssemblerMIPS64Compat::subDouble(FloatRegister src, FloatRegister dest) -{ - as_subd(dest, dest, src); -} - -void -MacroAssemblerMIPS64Compat::mulDouble(FloatRegister src, FloatRegister dest) -{ - as_muld(dest, dest, src); -} - -void -MacroAssemblerMIPS64Compat::divDouble(FloatRegister src, FloatRegister dest) -{ - as_divd(dest, dest, src); -} - -void -MacroAssemblerMIPS64Compat::negateDouble(FloatRegister reg) -{ - as_negd(reg, reg); -} - -void -MacroAssemblerMIPS64Compat::inc64(AbsoluteAddress dest) -{ - ma_li(ScratchRegister, ImmWord(uintptr_t(dest.addr))); - as_ld(SecondScratchReg, ScratchRegister, 0); - as_daddiu(SecondScratchReg, SecondScratchReg, 1); - as_sd(SecondScratchReg, ScratchRegister, 0); -} - void MacroAssemblerMIPS64Compat::movq(Register rs, Register rd) { @@ -897,46 +858,6 @@ MacroAssemblerMIPS64Compat::buildOOLFakeExitFrame(void* fakeReturnAddr) return true; } -void -MacroAssemblerMIPS64Compat::add32(Register src, Register dest) -{ - as_addu(dest, dest, src); -} - -void -MacroAssemblerMIPS64Compat::add32(Imm32 imm, Register dest) -{ - ma_addu(dest, dest, imm); -} - -void - -MacroAssemblerMIPS64Compat::add32(Imm32 imm, const Address& dest) -{ - load32(dest, SecondScratchReg); - ma_addu(SecondScratchReg, imm); - store32(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPS64Compat::addPtr(Register src, Register dest) -{ - ma_daddu(dest, src); -} - -void -MacroAssemblerMIPS64Compat::addPtr(const Address& src, Register dest) -{ - loadPtr(src, ScratchRegister); - ma_daddu(dest, ScratchRegister); -} - -void -MacroAssemblerMIPS64Compat::subPtr(Register src, Register dest) -{ - as_dsubu(dest, dest, src); -} - void MacroAssemblerMIPS64Compat::move32(Imm32 imm, Register dest) { @@ -1327,41 +1248,6 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) bind(&done); } -void -MacroAssemblerMIPS64Compat::subPtr(Imm32 imm, const Register dest) -{ - ma_dsubu(dest, dest, imm); -} - -void -MacroAssemblerMIPS64Compat::subPtr(const Address& addr, const Register dest) -{ - loadPtr(addr, SecondScratchReg); - subPtr(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPS64Compat::subPtr(Register src, const Address& dest) -{ - loadPtr(dest, SecondScratchReg); - subPtr(src, SecondScratchReg); - storePtr(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPS64Compat::addPtr(Imm32 imm, const Register dest) -{ - ma_daddu(dest, imm); -} - -void -MacroAssemblerMIPS64Compat::addPtr(Imm32 imm, const Address& dest) -{ - loadPtr(dest, ScratchRegister); - addPtr(imm, ScratchRegister); - storePtr(ScratchRegister, dest); -} - void MacroAssemblerMIPS64Compat::branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) @@ -2324,7 +2210,7 @@ void MacroAssemblerMIPS64Compat::pushValue(ValueOperand val) { // Allocate stack slots for Value. One for each. - subPtr(Imm32(sizeof(Value)), StackPointer); + asMasm().subPtr(Imm32(sizeof(Value)), StackPointer); // Store Value storeValue(val, Address(StackPointer, 0)); } @@ -2432,7 +2318,7 @@ MacroAssemblerMIPS64Compat::handleFailureWithHandlerTail(void* handler) { // Reserve space for exception information. int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1); - subPtr(Imm32(size), StackPointer); + asMasm().subPtr(Imm32(size), StackPointer); ma_move(a0, StackPointer); // Use a0 since it is a first function argument // Call the handler. @@ -2651,7 +2537,7 @@ MacroAssemblerMIPS64Compat::branchPtrInNurseryRange(Condition cond, Register ptr const Nursery& nursery = GetJitContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg); - addPtr(ptr, SecondScratchReg); + asMasm().addPtr(ptr, SecondScratchReg); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, SecondScratchReg, Imm32(nursery.nurserySize()), label); } @@ -2667,7 +2553,7 @@ MacroAssemblerMIPS64Compat::branchValueIsNurseryObject(Condition cond, ValueOper Value start = ObjectValue(*reinterpret_cast(nursery.start())); movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), SecondScratchReg); - addPtr(value.valueReg(), SecondScratchReg); + asMasm().addPtr(value.valueReg(), SecondScratchReg); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, SecondScratchReg, Imm32(nursery.nurserySize()), label); } @@ -2735,7 +2621,7 @@ void MacroAssembler::reserveStack(uint32_t amount) { if (amount) - subPtr(Imm32(amount), StackPointer); + asMasm().subPtr(Imm32(amount), StackPointer); adjustFrame(amount); } @@ -2751,7 +2637,7 @@ MacroAssembler::setupUnalignedABICall(Register scratch) ma_move(scratch, StackPointer); // Force sp to be aligned - subPtr(Imm32(sizeof(uintptr_t)), StackPointer); + asMasm().subPtr(Imm32(sizeof(uintptr_t)), StackPointer); ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1))); storePtr(scratch, Address(StackPointer, 0)); } diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 44364ffca37..fd92de94f38 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -185,14 +185,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void convertInt32ToFloat32(Register src, FloatRegister dest); void convertInt32ToFloat32(const Address& src, FloatRegister dest); - void addDouble(FloatRegister src, FloatRegister dest); - void subDouble(FloatRegister src, FloatRegister dest); - void mulDouble(FloatRegister src, FloatRegister dest); - void divDouble(FloatRegister src, FloatRegister dest); - - void negateDouble(FloatRegister reg); - void inc64(AbsoluteAddress dest); - void movq(Register rs, Register rd); void computeScaledAddress(const BaseIndex& address, Register dest); @@ -201,12 +193,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 ma_daddu(dest, address.base, Imm32(address.offset)); } - void computeEffectiveAddress(const BaseIndex& address, Register dest) { - computeScaledAddress(address, dest); - if (address.offset) { - addPtr(Imm32(address.offset), dest); - } - } + inline void computeEffectiveAddress(const BaseIndex& address, Register dest); void j(Label* dest) { ma_b(dest); @@ -256,13 +243,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 as_jr(ra); as_nop(); } - void retn(Imm32 n) { - // pc <- [sp]; sp += n - loadPtr(Address(StackPointer, 0), ra); - addPtr(n, StackPointer); - as_jr(ra); - as_nop(); - } + inline void retn(Imm32 n); void push(Imm32 imm) { ma_li(ScratchRegister, imm); ma_push(ScratchRegister); @@ -340,10 +321,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 branch(code); } - void neg32(Register reg) { - ma_negu(reg, reg); - } - void splitTag(Register src, Register dest) { ma_dsrl(dest, src, Imm32(JSVAL_TAG_SHIFT)); } @@ -610,10 +587,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { ma_b(lhs, imm, label, cond); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subPtr(imm, lhs); - branchPtr(cond, lhs, Imm32(0), label); - } + inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label); // higher level tag testing code Address ToPayload(Address value) { @@ -1089,16 +1063,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 Register temp, Register valueTemp, Register offsetTemp, Register maskTemp, AnyRegister output); - void add32(Register src, Register dest); - void add32(Imm32 imm, Register dest); - void add32(Imm32 imm, const Address& dest); - void add64(Imm32 imm, Register64 dest) { - ma_daddu(dest.reg, imm); - } - - void incrementInt32Value(const Address& addr) { - add32(Imm32(1), addr); - } + inline void incrementInt32Value(const Address& addr); template void branchAdd32(Condition cond, T src, Register dest, Label* overflow) { @@ -1126,10 +1091,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 } } - void addPtr(Register src, Register dest); - void subPtr(Register src, Register dest); - void addPtr(const Address& src, Register dest); - void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); void move64(Register64 src, Register64 dest) { @@ -1266,36 +1227,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void clampIntToUint8(Register reg); - void subPtr(Imm32 imm, const Register dest); - void subPtr(const Address& addr, const Register dest); - void subPtr(Register src, const Address& dest); - void addPtr(Imm32 imm, const Register dest); - void addPtr(Imm32 imm, const Address& dest); - void addPtr(ImmWord imm, const Register dest) { - movePtr(imm, ScratchRegister); - addPtr(ScratchRegister, dest); - } - void addPtr(ImmPtr imm, const Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } - void mulBy3(const Register& src, const Register& dest) { - as_daddu(dest, src, src); - as_daddu(dest, dest, src); - } - - void mul64(Imm64 imm, const Register64& dest) { - MOZ_ASSERT(dest.reg != ScratchRegister); - mov(ImmWord(imm.value), ScratchRegister); - as_dmultu(dest.reg, ScratchRegister); - as_mflo(dest.reg); - } - void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - movePtr(imm, ScratchRegister); - loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); - } void breakpoint(); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 512ae813d68..4120c478ed5 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -234,20 +234,6 @@ class MacroAssemblerNone : public Assembler template void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); } template void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); } - template void add32(T, S) { MOZ_CRASH(); } - template void addPtr(T, S) { MOZ_CRASH(); } - template void add64(T, S) { MOZ_CRASH(); } - template void subPtr(T, S) { MOZ_CRASH(); } - void neg32(Register) { MOZ_CRASH(); } - void mulBy3(Register, Register) { MOZ_CRASH(); } - void mul64(Imm64, const Register64&) { MOZ_CRASH(); } - - void negateDouble(FloatRegister) { MOZ_CRASH(); } - void addDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); } - void subDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); } - void mulDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); } - void divDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); } - template void branch32(Condition, T, S, Label*) { MOZ_CRASH(); } template void branchTest32(Condition, T, S, Label*) { MOZ_CRASH(); } template void branchAdd32(Condition, T, S, Label*) { MOZ_CRASH(); } @@ -402,7 +388,6 @@ class MacroAssemblerNone : public Assembler template void convertInt32ToDouble(T, FloatRegister) { MOZ_CRASH(); } void convertFloat32ToDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); } void convertUInt64ToDouble(Register64, Register, FloatRegister) { MOZ_CRASH(); } - void mulDoublePtr(ImmPtr, Register, FloatRegister) { MOZ_CRASH(); } void branchTruncateDouble(FloatRegister, Register, Label*) { MOZ_CRASH(); } void branchTruncateFloat32(FloatRegister, Register, Label*) { MOZ_CRASH(); } @@ -413,9 +398,7 @@ class MacroAssemblerNone : public Assembler void int32ValueToFloat32(ValueOperand, FloatRegister) { MOZ_CRASH(); } void loadConstantDouble(double, FloatRegister) { MOZ_CRASH(); } - void addConstantDouble(double, FloatRegister) { MOZ_CRASH(); } void loadConstantFloat32(float, FloatRegister) { MOZ_CRASH(); } - void addConstantFloat32(float, FloatRegister) { MOZ_CRASH(); } Condition testInt32Truthy(bool, ValueOperand) { MOZ_CRASH(); } Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); } void branchTestInt32Truthy(bool, ValueOperand, Label*) { MOZ_CRASH(); } @@ -429,7 +412,6 @@ class MacroAssemblerNone : public Assembler void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } - void inc64(AbsoluteAddress) { MOZ_CRASH(); } void incrementInt32Value(Address) { MOZ_CRASH(); } void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); } void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index e606899062e..02b18b4b3bd 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -75,12 +75,117 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::addPtr(Register src, Register dest) +{ + addq(src, dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + addq(imm, dest); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + ScratchRegisterScope scratch(*this); + MOZ_ASSERT(dest != scratch); + if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { + addq(Imm32((int32_t)imm.value), dest); + } else { + mov(imm, scratch); + addq(scratch, dest); + } +} + +void +MacroAssembler::addPtr(Imm32 imm, const Address& dest) +{ + addq(imm, Operand(dest)); +} + +void +MacroAssembler::addPtr(Imm32 imm, const AbsoluteAddress& dest) +{ + addq(imm, Operand(dest)); +} + +void +MacroAssembler::addPtr(const Address& src, Register dest) +{ + addq(Operand(src), dest); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { addq(src.reg, dest.reg); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + addq(imm, dest.reg); +} + +void +MacroAssembler::subPtr(Register src, Register dest) +{ + subq(src, dest); +} + +void +MacroAssembler::subPtr(Register src, const Address& dest) +{ + subq(src, Operand(dest)); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + subq(imm, dest); +} + +void +MacroAssembler::subPtr(const Address& addr, Register dest) +{ + subq(Operand(addr), dest); +} + +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + movq(ImmWord(uintptr_t(imm.value)), ScratchReg); + imulq(ScratchReg, dest.reg); +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + lea(Operand(src, src, TimesTwo), dest); +} + +void +MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) +{ + movq(imm, ScratchReg); + vmulsd(Operand(ScratchReg, 0), dest, dest); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + if (X86Encoding::IsAddressImmediate(dest.addr)) { + addPtr(Imm32(1), dest); + } else { + ScratchRegisterScope scratch(*this); + mov(ImmPtr(dest.addr), scratch); + addPtr(Imm32(1), Address(scratch, 0)); + } +} + // =============================================================== // Shift functions @@ -117,6 +222,12 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +void +MacroAssemblerX64::incrementInt32Value(const Address& addr) +{ + asMasm().addPtr(Imm32(1), addr); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index ca88dcac95e..c72b6b35dd5 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -265,7 +265,7 @@ MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Registe const Nursery& nursery = GetJitContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), scratch); - addPtr(ptr, scratch); + asMasm().addPtr(ptr, scratch); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, scratch, Imm32(nursery.nurserySize()), label); } @@ -287,7 +287,7 @@ MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value ScratchRegisterScope scratch(asMasm()); movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), scratch); - addPtr(value.valueReg(), scratch); + asMasm().addPtr(value.valueReg(), scratch); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, scratch, Imm32(nursery.nurserySize()), label); } diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 7daccb75926..08c51b7d70d 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -543,57 +543,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // Common interface. ///////////////////////////////////////////////////////////////// - void addPtr(Register src, Register dest) { - addq(src, dest); - } - void addPtr(Imm32 imm, Register dest) { - addq(imm, dest); - } - void addPtr(Imm32 imm, const Address& dest) { - addq(imm, Operand(dest)); - } - void addPtr(Imm32 imm, const Operand& dest) { - addq(imm, dest); - } - void addPtr(ImmWord imm, Register dest) { - ScratchRegisterScope scratch(asMasm()); - MOZ_ASSERT(dest != scratch); - if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { - addq(Imm32((int32_t)imm.value), dest); - } else { - mov(imm, scratch); - addq(scratch, dest); - } - } - void addPtr(ImmPtr imm, Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } - void addPtr(const Address& src, Register dest) { - addq(Operand(src), dest); - } - void add64(Imm32 imm, Register64 dest) { - addq(imm, dest.reg); - } - void subPtr(Imm32 imm, Register dest) { - subq(imm, dest); - } - void subPtr(Register src, Register dest) { - subq(src, dest); - } - void subPtr(const Address& addr, Register dest) { - subq(Operand(addr), dest); - } - void subPtr(Register src, const Address& dest) { - subq(src, Operand(dest)); - } - void mulBy3(const Register& src, const Register& dest) { - lea(Operand(src, src, TimesTwo), dest); - } - void mul64(Imm64 imm, const Register64& dest) { - movq(ImmWord(uintptr_t(imm.value)), ScratchReg); - imulq(ScratchReg, dest.reg); - } - void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) { if (X86Encoding::IsAddressImmediate(lhs.addr)) { branch32(cond, Operand(lhs), rhs, label); @@ -704,7 +653,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared j(cond, label); } void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subPtr(imm, lhs); + subq(imm, lhs); j(cond, label); } @@ -1346,24 +1295,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared vcvtsi2sdq(src.reg, dest); } - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - movq(imm, ScratchReg); - vmulsd(Operand(ScratchReg, 0), dest, dest); - } - - void inc64(AbsoluteAddress dest) { - if (X86Encoding::IsAddressImmediate(dest.addr)) { - addPtr(Imm32(1), Operand(dest)); - } else { - ScratchRegisterScope scratch(asMasm()); - mov(ImmPtr(dest.addr), scratch); - addPtr(Imm32(1), Address(scratch, 0)); - } - } - - void incrementInt32Value(const Address& addr) { - addPtr(Imm32(1), addr); - } + inline void incrementInt32Value(const Address& addr); // If source is a double, load it into dest. If source is int32, // convert it to double. Else, branch to failure. diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index d7332ae4b50..f04e3e06836 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -79,6 +79,42 @@ MacroAssembler::xor32(Imm32 imm, Register dest) // =============================================================== // Arithmetic instructions +void +MacroAssembler::add32(Register src, Register dest) +{ + addl(src, dest); +} + +void +MacroAssembler::add32(Imm32 imm, Register dest) +{ + addl(imm, dest); +} + +void +MacroAssembler::add32(Imm32 imm, const Address& dest) +{ + addl(imm, Operand(dest)); +} + +void +MacroAssembler::add32(Imm32 imm, const AbsoluteAddress& dest) +{ + addl(imm, Operand(dest)); +} + +void +MacroAssembler::addFloat32(FloatRegister src, FloatRegister dest) +{ + vaddss(src, dest, dest); +} + +void +MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) +{ + vaddsd(src, dest, dest); +} + void MacroAssembler::sub32(Register src, Register dest) { @@ -97,6 +133,53 @@ MacroAssembler::sub32(const Address& src, Register dest) subl(Operand(src), dest); } +void +MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) +{ + vsubsd(src, dest, dest); +} + +void +MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) +{ + vmulsd(src, dest, dest); +} + +void +MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) +{ + vdivsd(src, dest, dest); +} + +void +MacroAssembler::neg32(Register reg) +{ + negl(reg); +} + +void +MacroAssembler::negateFloat(FloatRegister reg) +{ + ScratchFloat32Scope scratch(*this); + vpcmpeqw(scratch, scratch, scratch); + vpsllq(Imm32(31), scratch, scratch); + + // XOR the float in a float register with -0.0. + vxorps(scratch, reg, reg); // s ^ 0x80000000 +} + +void +MacroAssembler::negateDouble(FloatRegister reg) +{ + // From MacroAssemblerX86Shared::maybeInlineDouble + ScratchDoubleScope scratch(*this); + vpcmpeqw(scratch, scratch, scratch); + vpsllq(Imm32(63), scratch, scratch); + + // XOR the float in a float register with -0.0. + vxorpd(scratch, reg, reg); // s ^ 0x80000000000000 +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 6b889daac86..0ef4774febd 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -175,9 +175,6 @@ class MacroAssemblerX86Shared : public Assembler void move32(Register src, const Operand& dest) { movl(src, dest); } - void neg32(Register reg) { - negl(reg); - } void test32(Register lhs, Register rhs) { testl(rhs, lhs); } @@ -208,21 +205,9 @@ class MacroAssemblerX86Shared : public Assembler CodeOffset cmp32WithPatch(Register lhs, Imm32 rhs) { return cmplWithPatch(rhs, lhs); } - void add32(Register src, Register dest) { - addl(src, dest); - } - void add32(Imm32 imm, Register dest) { - addl(imm, dest); - } - void add32(Imm32 imm, const Operand& dest) { - addl(imm, dest); - } - void add32(Imm32 imm, const Address& dest) { - addl(imm, Operand(dest)); - } template void branchAdd32(Condition cond, T src, Register dest, Label* label) { - add32(src, dest); + addl(src, dest); j(cond, label); } template @@ -917,38 +902,6 @@ class MacroAssemblerX86Shared : public Assembler void zeroFloat32(FloatRegister reg) { vxorps(reg, reg, reg); } - void negateDouble(FloatRegister reg) { - // From MacroAssemblerX86Shared::maybeInlineDouble - ScratchDoubleScope scratch(asMasm()); - vpcmpeqw(scratch, scratch, scratch); - vpsllq(Imm32(63), scratch, scratch); - - // XOR the float in a float register with -0.0. - vxorpd(scratch, reg, reg); // s ^ 0x80000000000000 - } - void negateFloat(FloatRegister reg) { - ScratchFloat32Scope scratch(asMasm()); - vpcmpeqw(scratch, scratch, scratch); - vpsllq(Imm32(31), scratch, scratch); - - // XOR the float in a float register with -0.0. - vxorps(scratch, reg, reg); // s ^ 0x80000000 - } - void addDouble(FloatRegister src, FloatRegister dest) { - vaddsd(src, dest, dest); - } - void subDouble(FloatRegister src, FloatRegister dest) { - vsubsd(src, dest, dest); - } - void mulDouble(FloatRegister src, FloatRegister dest) { - vmulsd(src, dest, dest); - } - void divDouble(FloatRegister src, FloatRegister dest) { - vdivsd(src, dest, dest); - } - void addFloat32(FloatRegister src, FloatRegister dest) { - vaddss(src, dest, dest); - } void convertFloat32ToDouble(FloatRegister src, FloatRegister dest) { vcvtss2sd(src, dest, dest); } diff --git a/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp b/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp index c0714b2bad1..0ecb50815cc 100644 --- a/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp +++ b/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp @@ -440,7 +440,8 @@ MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to, // this clobbers FLAGS! masm.Push(from.base()); masm.Pop(toPopOperand(to)); - masm.addPtr(Imm32(from.disp()), toOperand(to)); + MOZ_ASSERT(to.isMemoryOrEffectiveAddress()); + masm.addPtr(Imm32(from.disp()), toAddress(to)); } } } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 75b8a74720a..3c6342ecc5f 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -16,6 +16,7 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +// Logical functions void MacroAssembler::andPtr(Register src, Register dest) @@ -77,6 +78,42 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Arithmetic functions +void +MacroAssembler::addPtr(Register src, Register dest) +{ + addl(src, dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, Register dest) +{ + addl(imm, dest); +} + +void +MacroAssembler::addPtr(ImmWord imm, Register dest) +{ + addl(Imm32(imm.value), dest); +} + +void +MacroAssembler::addPtr(Imm32 imm, const Address& dest) +{ + addl(imm, Operand(dest)); +} + +void +MacroAssembler::addPtr(Imm32 imm, const AbsoluteAddress& dest) +{ + addl(imm, Operand(dest)); +} + +void +MacroAssembler::addPtr(const Address& src, Register dest) +{ + addl(Operand(src), dest); +} + void MacroAssembler::add64(Register64 src, Register64 dest) { @@ -84,6 +121,105 @@ MacroAssembler::add64(Register64 src, Register64 dest) adcl(src.high, dest.high); } +void +MacroAssembler::add64(Imm32 imm, Register64 dest) +{ + addl(imm, dest.low); + adcl(Imm32(0), dest.high); +} + +void +MacroAssembler::addConstantDouble(double d, FloatRegister dest) +{ + Double* dbl = getDouble(d); + if (!dbl) + return; + masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding()); + propagateOOM(dbl->uses.append(CodeOffset(masm.size()))); +} + +void +MacroAssembler::subPtr(Register src, Register dest) +{ + subl(src, dest); +} + +void +MacroAssembler::subPtr(Register src, const Address& dest) +{ + subl(src, Operand(dest)); +} + +void +MacroAssembler::subPtr(Imm32 imm, Register dest) +{ + subl(imm, dest); +} + +void +MacroAssembler::subPtr(const Address& addr, Register dest) +{ + subl(Operand(addr), dest); +} + +// Note: this function clobbers eax and edx. +void +MacroAssembler::mul64(Imm64 imm, const Register64& dest) +{ + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + MOZ_ASSERT(dest.low != eax && dest.low != edx); + MOZ_ASSERT(dest.high != eax && dest.high != edx); + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + movl(Imm32(imm.value & 0xFFFFFFFFL), edx); + imull(edx, dest.high); + + // edx:eax = LOW(dest) * LOW(imm); + movl(Imm32(imm.value & 0xFFFFFFFFL), edx); + movl(dest.low, eax); + mull(edx); + + // HIGH(dest) += edx; + addl(edx, dest.high); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) + leal(Operand(dest.low, dest.low, TimesFour), edx); + else + MOZ_CRASH("Unsupported imm"); + addl(edx, dest.high); + + // LOW(dest) = eax; + movl(eax, dest.low); +} + +void +MacroAssembler::mulBy3(Register src, Register dest) +{ + lea(Operand(src, src, TimesTwo), dest); +} + +void +MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) +{ + movl(imm, temp); + vmulsd(Operand(temp, 0), dest, dest); +} + +void +MacroAssembler::inc64(AbsoluteAddress dest) +{ + addl(Imm32(1), Operand(dest)); + Label noOverflow; + j(NonZero, &noOverflow); + addl(Imm32(1), Operand(dest.offset(4))); + bind(&noOverflow); +} + // =============================================================== // Shift functions @@ -122,6 +258,29 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +// Note: this function clobbers the source register. +void +MacroAssemblerX86::convertUInt32ToDouble(Register src, FloatRegister dest) +{ + // src is [0, 2^32-1] + subl(Imm32(0x80000000), src); + + // Now src is [-2^31, 2^31-1] - int range, but not the same value. + convertInt32ToDouble(src, dest); + + // dest is now a double with the int range. + // correct the double value by adding 0x80000000. + asMasm().addConstantDouble(2147483648.0, dest); +} + +// Note: this function clobbers the source register. +void +MacroAssemblerX86::convertUInt32ToFloat32(Register src, FloatRegister dest) +{ + convertUInt32ToDouble(src, dest); + convertDoubleToFloat32(dest, dest); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 86196998f0a..30712c28600 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -40,9 +40,9 @@ MacroAssemblerX86::convertUInt64ToDouble(Register64 src, Register temp, FloatReg convertUInt32ToDouble(src.high, dest); movePtr(ImmPtr(&TO_DOUBLE_HIGH_SCALE), temp); loadDouble(Address(temp, 0), ScratchDoubleReg); - mulDouble(ScratchDoubleReg, dest); + asMasm().mulDouble(ScratchDoubleReg, dest); convertUInt32ToDouble(src.low, ScratchDoubleReg); - addDouble(ScratchDoubleReg, dest); + asMasm().addDouble(ScratchDoubleReg, dest); return; } @@ -102,16 +102,6 @@ MacroAssemblerX86::loadConstantDouble(double d, FloatRegister dest) propagateOOM(dbl->uses.append(CodeOffset(masm.size()))); } -void -MacroAssemblerX86::addConstantDouble(double d, FloatRegister dest) -{ - Double* dbl = getDouble(d); - if (!dbl) - return; - masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding()); - propagateOOM(dbl->uses.append(CodeOffset(masm.size()))); -} - void MacroAssemblerX86::loadConstantFloat32(float f, FloatRegister dest) { @@ -124,16 +114,6 @@ MacroAssemblerX86::loadConstantFloat32(float f, FloatRegister dest) propagateOOM(flt->uses.append(CodeOffset(masm.size()))); } -void -MacroAssemblerX86::addConstantFloat32(float f, FloatRegister dest) -{ - Float* flt = getFloat(f); - if (!flt) - return; - masm.vaddss_mr(nullptr, dest.encoding(), dest.encoding()); - propagateOOM(flt->uses.append(CodeOffset(masm.size()))); -} - void MacroAssemblerX86::loadConstantInt32x4(const SimdConstant& v, FloatRegister dest) { @@ -355,7 +335,7 @@ MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Registe const Nursery& nursery = GetJitContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); + asMasm().addPtr(ptr, temp); branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, temp, Imm32(nursery.nurserySize()), label); } diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 0c41692bdac..75aa45aaae6 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -566,79 +566,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared // Common interface. ///////////////////////////////////////////////////////////////// - void addPtr(Register src, Register dest) { - add32(src, dest); - } - void addPtr(Imm32 imm, Register dest) { - add32(imm, dest); - } - void addPtr(ImmWord imm, Register dest) { - add32(Imm32(imm.value), dest); - } - void addPtr(ImmPtr imm, Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } - void addPtr(Imm32 imm, const Address& dest) { - add32(imm, Operand(dest)); - } - void addPtr(Imm32 imm, const Operand& dest) { - add32(imm, dest); - } - void addPtr(const Address& src, Register dest) { - addl(Operand(src), dest); - } - void add64(Imm32 imm, Register64 dest) { - addl(imm, dest.low); - adcl(Imm32(0), dest.high); - } - void subPtr(Imm32 imm, Register dest) { - subl(imm, dest); - } - void subPtr(Register src, Register dest) { - subl(src, dest); - } - void subPtr(const Address& addr, Register dest) { - subl(Operand(addr), dest); - } - void subPtr(Register src, const Address& dest) { - subl(src, Operand(dest)); - } - void mulBy3(const Register& src, const Register& dest) { - lea(Operand(src, src, TimesTwo), dest); - } - // Note: this function clobbers eax and edx. - void mul64(Imm64 imm, const Register64& dest) { - // LOW32 = LOW(LOW(dest) * LOW(imm)); - // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] - // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] - // + HIGH(LOW(dest) * LOW(imm)) [carry] - - MOZ_ASSERT(dest.low != eax && dest.low != edx); - MOZ_ASSERT(dest.high != eax && dest.high != edx); - - // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); - movl(Imm32(imm.value & 0xFFFFFFFFL), edx); - imull(edx, dest.high); - - // edx:eax = LOW(dest) * LOW(imm); - movl(Imm32(imm.value & 0xFFFFFFFFL), edx); - movl(dest.low, eax); - mull(edx); - - // HIGH(dest) += edx; - addl(edx, dest.high); - - // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); - if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) - leal(Operand(dest.low, dest.low, TimesFour), edx); - else - MOZ_CRASH("Unsupported imm"); - addl(edx, dest.high); - - // LOW(dest) = eax; - movl(eax, dest.low); - } - void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) { cmp32(Operand(lhs), rhs); j(cond, label); @@ -723,7 +650,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared j(cond, label); } void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subPtr(imm, lhs); + subl(imm, lhs); j(cond, label); } @@ -1011,9 +938,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } void loadConstantDouble(double d, FloatRegister dest); - void addConstantDouble(double d, FloatRegister dest); void loadConstantFloat32(float f, FloatRegister dest); - void addConstantFloat32(float f, FloatRegister dest); void loadConstantInt32x4(const SimdConstant& v, FloatRegister dest); void loadConstantFloat32x4(const SimdConstant& v, FloatRegister dest); @@ -1098,39 +1023,13 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } // Note: this function clobbers the source register. - void convertUInt32ToDouble(Register src, FloatRegister dest) { - // src is [0, 2^32-1] - subl(Imm32(0x80000000), src); - - // Now src is [-2^31, 2^31-1] - int range, but not the same value. - convertInt32ToDouble(src, dest); - - // dest is now a double with the int range. - // correct the double value by adding 0x80000000. - addConstantDouble(2147483648.0, dest); - } + inline void convertUInt32ToDouble(Register src, FloatRegister dest); // Note: this function clobbers the source register. - void convertUInt32ToFloat32(Register src, FloatRegister dest) { - convertUInt32ToDouble(src, dest); - convertDoubleToFloat32(dest, dest); - } + inline void convertUInt32ToFloat32(Register src, FloatRegister dest); void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); - void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { - movl(imm, temp); - vmulsd(Operand(temp, 0), dest, dest); - } - - void inc64(AbsoluteAddress dest) { - addl(Imm32(1), Operand(dest)); - Label noOverflow; - j(NonZero, &noOverflow); - addl(Imm32(1), Operand(dest.offset(4))); - bind(&noOverflow); - } - void incrementInt32Value(const Address& addr) { addl(Imm32(1), payloadOf(addr)); } diff --git a/js/src/js.msg b/js/src/js.msg index bcc25ebe14f..6fbe70d416b 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -444,6 +444,7 @@ MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in // RegExp MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class") +MSG_DEF(JSMSG_DEPRECATED_REGEXP_MULTILINE, 0, JSEXN_SYNTAXERR, "RegExp.multiline is deprecated. Use m flag instead") MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern") MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group") MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 548c4430a5e..0b77258374b 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -50,6 +50,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = marked(true), warnedAboutFlagsArgument(false), warnedAboutExprClosure(false), + warnedAboutRegExpMultiline(false), addonId(options.addonIdOrNull()), #ifdef DEBUG firedOnNewGlobalObject(false), diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 96938211507..7552cd2cf9d 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -278,6 +278,7 @@ struct JSCompartment bool marked; bool warnedAboutFlagsArgument; bool warnedAboutExprClosure; + bool warnedAboutRegExpMultiline; // A null add-on ID means that the compartment is not associated with an // add-on. diff --git a/js/src/jsprf.cpp b/js/src/jsprf.cpp index 0d367de047c..0cdd27ddfb5 100644 --- a/js/src/jsprf.cpp +++ b/js/src/jsprf.cpp @@ -1021,7 +1021,7 @@ JS_vsnprintf(char* out, uint32_t outlen, const char* fmt, va_list ap) (void) dosprintf(&ss, fmt, ap); uint32_t charsWritten = ss.cur - ss.base; - MOZ_ASSERT(charsWritten > 0); + MOZ_RELEASE_ASSERT(charsWritten > 0); // If we didn't append a null then we must have hit the buffer limit. Write // a null terminator now and return a value indicating that we failed. diff --git a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js index 6fc5dd1d2d3..55770b86ea1 100644 --- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js +++ b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js @@ -101,5 +101,8 @@ testBuiltin(Array, 3.0); testBuiltin(Array, "non-length one-arg"); testBuiltin(Array, 5, 10, 15, "these are elements"); +if (this.SharedArrayBuffer) + testBuiltin(SharedArrayBuffer); + if (typeof reportCompare === 'function') reportCompare(0,0,"OK"); diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 950c7524a4e..f763dcc0982 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -539,7 +539,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); if (!rootCount) return false; - JS::ubi::CensusHandler handler(census, rootCount); + JS::ubi::CensusHandler handler(census, rootCount, cx->runtime()->debuggerMallocSizeOf); Debugger* dbg = memory->getDebugger(); RootedObject dbgObj(cx, dbg->object); @@ -573,7 +573,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) } } - return handler.report(args.rval()); + return handler.report(cx, args.rval()); } diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp index cf5d21aa230..6001808180d 100644 --- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -15,6 +15,7 @@ #include "jstypes.h" #include "builtin/AtomicsObject.h" +#include "gc/Statistics.h" #include "jit/ExecutableAllocator.h" #include "jit/Ion.h" #include "js/Utility.h" @@ -103,6 +104,8 @@ JS_Init(void) if (!FutexRuntime::initialize()) return false; + js::gcstats::Statistics::initialize(); + libraryInitState = InitState::Running; return true; } diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index 31829400027..08236409779 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -63,8 +63,6 @@ class RegExpStatics struct InitBuffer {}; explicit RegExpStatics(InitBuffer) {} - friend class AutoRegExpStaticsBuffer; - public: /* Mutators. */ inline void updateLazily(JSContext* cx, JSLinearString* input, @@ -160,38 +158,6 @@ class RegExpStatics } }; -class MOZ_RAII AutoRegExpStaticsBuffer : private JS::CustomAutoRooter -{ - public: - explicit AutoRegExpStaticsBuffer(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer()) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - RegExpStatics& getStatics() { return statics; } - - private: - virtual void trace(JSTracer* trc) { - if (statics.matchesInput) { - TraceRoot(trc, reinterpret_cast(&statics.matchesInput), - "AutoRegExpStaticsBuffer matchesInput"); - } - if (statics.lazySource) { - TraceRoot(trc, reinterpret_cast(&statics.lazySource), - "AutoRegExpStaticsBuffer lazySource"); - } - if (statics.pendingInput) { - TraceRoot(trc, reinterpret_cast(&statics.pendingInput), - "AutoRegExpStaticsBuffer pendingInput"); - } - } - - RegExpStatics statics; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - inline bool RegExpStatics::createDependent(JSContext* cx, size_t start, size_t end, MutableHandleValue out) { diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 235717fb0d9..97a1491c38c 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -989,10 +989,6 @@ SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp) bool SavedStacks::init() { - mozilla::Array seed; - GenerateXorShift128PlusSeed(seed); - bernoulli.setRandomState(seed[0], seed[1]); - if (!pcLocationMap.init()) return false; @@ -1418,6 +1414,13 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment) } MOZ_ASSERT(foundAnyDebuggers); + if (!bernoulliSeeded) { + mozilla::Array seed; + GenerateXorShift128PlusSeed(seed); + bernoulli.setRandomState(seed[0], seed[1]); + bernoulliSeeded = true; + } + bernoulli.setProbability(probability); } diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 9d343aa3603..3c8e7770052 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -157,6 +157,7 @@ class SavedStacks { public: SavedStacks() : frames(), + bernoulliSeeded(false), bernoulli(1.0, 0x59fdad7f6b4cc573, 0x91adf38db96a9354), creatingSavedFrame(false) { } @@ -181,6 +182,7 @@ class SavedStacks { private: SavedFrame::Set frames; + bool bernoulliSeeded; mozilla::FastBernoulliTrial bernoulli; bool creatingSavedFrame; diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index 20a47c2099e..6c30a8ed8d0 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -239,7 +239,12 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* return false; } - JSObject* bufobj = New(cx, length); + RootedObject proto(cx); + RootedObject newTarget(cx, &args.newTarget().toObject()); + if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + return false; + + JSObject* bufobj = New(cx, length, proto); if (!bufobj) return false; args.rval().setObject(*bufobj); @@ -247,20 +252,21 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* } SharedArrayBufferObject* -SharedArrayBufferObject::New(JSContext* cx, uint32_t length) +SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto) { SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length); if (!buffer) return nullptr; - return New(cx, buffer); + return New(cx, buffer, proto); } SharedArrayBufferObject* -SharedArrayBufferObject::New(JSContext* cx, SharedArrayRawBuffer* buffer) +SharedArrayBufferObject::New(JSContext* cx, SharedArrayRawBuffer* buffer, HandleObject proto) { AutoSetNewObjectMetadata metadata(cx); - Rooted obj(cx, NewBuiltinClassInstance(cx)); + Rooted obj(cx, + NewObjectWithClassProto(cx, proto)); if (!obj) return nullptr; @@ -423,7 +429,7 @@ JS_FRIEND_API(JSObject*) JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes) { MOZ_ASSERT(nbytes <= INT32_MAX); - return SharedArrayBufferObject::New(cx, nbytes); + return SharedArrayBufferObject::New(cx, nbytes, /* proto = */ nullptr); } JS_FRIEND_API(bool) diff --git a/js/src/vm/SharedArrayObject.h b/js/src/vm/SharedArrayObject.h index 5bfc1ef3cc0..d3fa3fbaa28 100644 --- a/js/src/vm/SharedArrayObject.h +++ b/js/src/vm/SharedArrayObject.h @@ -130,10 +130,14 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared static bool class_constructor(JSContext* cx, unsigned argc, Value* vp); // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer. - static SharedArrayBufferObject* New(JSContext* cx, uint32_t length); + static SharedArrayBufferObject* New(JSContext* cx, + uint32_t length, + HandleObject proto = nullptr); // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer. - static SharedArrayBufferObject* New(JSContext* cx, SharedArrayRawBuffer* buffer); + static SharedArrayBufferObject* New(JSContext* cx, + SharedArrayRawBuffer* buffer, + HandleObject proto = nullptr); static void Finalize(FreeOp* fop, JSObject* obj); diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index d156918ea40..16081fedd57 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -370,8 +370,18 @@ class TypedArrayObjectTemplate : public TypedArrayObject // may be in the nursery, so include a barrier to make sure this // object is updated if that typed object moves. if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(buffer->dataPointerEither())) { - MOZ_ASSERT(!isSharedMemory); - cx->runtime()->gc.storeBuffer.putWholeCell(obj); + // Shared buffer data should never be nursery-allocated, so + // we need to fail here if isSharedMemory. However, mmap() + // can place a SharedArrayRawBuffer up against the bottom end + // of the nursery, and a zero-length buffer will erroneously be + // perceived as being inside the nursery; sidestep that. + if (isSharedMemory) { + MOZ_ASSERT(buffer->byteLength() == 0 && + cx->runtime()->gc.nursery.start() == + buffer->dataPointerEither().unwrapValue()); + } else { + cx->runtime()->gc.storeBuffer.putWholeCell(obj); + } } } else { void* data = obj->fixedData(FIXED_DATA_START); diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 3e682a7a33d..251c61c98a1 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -497,7 +497,7 @@ RootList::addRoot(Node node, const char16_t* edgeName) return edges.append(mozilla::Move(Edge(name.release(), node))); } -const char16_t Concrete::concreteTypeName[] = MOZ_UTF16("RootList"); +const char16_t Concrete::concreteTypeName[] = MOZ_UTF16("JS::ubi::RootList"); UniquePtr Concrete::edges(JSRuntime* rt, bool wantNames) const { diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp index 93bb04b6499..1f9b293cb7f 100644 --- a/js/src/vm/UbiNodeCensus.cpp +++ b/js/src/vm/UbiNodeCensus.cpp @@ -54,18 +54,17 @@ class SimpleCount : public CountType { bool reportBytes : 1; public: - SimpleCount(Census& census, - UniquePtr& label, - bool reportCount=true, - bool reportBytes=true) - : CountType(census), + explicit SimpleCount(UniquePtr& label, + bool reportCount=true, + bool reportBytes=true) + : CountType(), label(Move(label)), reportCount(reportCount), reportBytes(reportBytes) { } - explicit SimpleCount(Census& census) - : CountType(census), + explicit SimpleCount() + : CountType(), label(nullptr), reportCount(true), reportBytes(true) @@ -76,45 +75,45 @@ class SimpleCount : public CountType { count.~Count(); } - CountBasePtr makeCount() override { return CountBasePtr(census.new_(*this)); } + CountBasePtr makeCount() override { return CountBasePtr(js_new(*this)); } void traceCount(CountBase& countBase, JSTracer* trc) override { } - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; bool -SimpleCount::count(CountBase& countBase, const Node& node) +SimpleCount::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; if (reportBytes) - count.totalBytes_ += node.size(census.cx->runtime()->debuggerMallocSizeOf); + count.totalBytes_ += node.size(mallocSizeOf); return true; } bool -SimpleCount::report(CountBase& countBase, MutableHandleValue report) +SimpleCount::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - RootedPlainObject obj(census.cx, NewBuiltinClassInstance(census.cx)); + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); if (!obj) return false; - RootedValue countValue(census.cx, NumberValue(count.total_)); - if (reportCount && !DefineProperty(census.cx, obj, census.cx->names().count, countValue)) + RootedValue countValue(cx, NumberValue(count.total_)); + if (reportCount && !DefineProperty(cx, obj, cx->names().count, countValue)) return false; - RootedValue bytesValue(census.cx, NumberValue(count.totalBytes_)); - if (reportBytes && !DefineProperty(census.cx, obj, census.cx->names().bytes, bytesValue)) + RootedValue bytesValue(cx, NumberValue(count.totalBytes_)); + if (reportBytes && !DefineProperty(cx, obj, cx->names().bytes, bytesValue)) return false; if (label) { - JSString* labelString = JS_NewUCStringCopyZ(census.cx, label.get()); + JSString* labelString = JS_NewUCStringCopyZ(cx, label.get()); if (!labelString) return false; - RootedValue labelValue(census.cx, StringValue(labelString)); - if (!DefineProperty(census.cx, obj, census.cx->names().label, labelValue)) + RootedValue labelValue(cx, StringValue(labelString)); + if (!DefineProperty(cx, obj, cx->names().label, labelValue)) return false; } @@ -155,12 +154,11 @@ class ByCoarseType : public CountType { }; public: - ByCoarseType(Census& census, - CountTypePtr& objects, + ByCoarseType(CountTypePtr& objects, CountTypePtr& scripts, CountTypePtr& strings, CountTypePtr& other) - : CountType(census), + : CountType(), objects(Move(objects)), scripts(Move(scripts)), strings(Move(strings)), @@ -174,8 +172,8 @@ class ByCoarseType : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -189,11 +187,11 @@ ByCoarseType::makeCount() if (!objectsCount || !scriptsCount || !stringsCount || !otherCount) return CountBasePtr(nullptr); - return CountBasePtr(census.new_(*this, - objectsCount, - scriptsCount, - stringsCount, - otherCount)); + return CountBasePtr(js_new(*this, + objectsCount, + scriptsCount, + stringsCount, + otherCount)); } void @@ -207,20 +205,20 @@ ByCoarseType::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByCoarseType::count(CountBase& countBase, const Node& node) +ByCoarseType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; switch (node.coarseType()) { case JS::ubi::CoarseType::Object: - return count.objects->count(node); + return count.objects->count(mallocSizeOf, node); case JS::ubi::CoarseType::Script: - return count.scripts->count(node); + return count.scripts->count(mallocSizeOf, node); case JS::ubi::CoarseType::String: - return count.strings->count(node); + return count.strings->count(mallocSizeOf, node); case JS::ubi::CoarseType::Other: - return count.other->count(node); + return count.other->count(mallocSizeOf, node); default: MOZ_CRASH("bad JS::ubi::CoarseType in JS::ubi::ByCoarseType::count"); return false; @@ -228,32 +226,31 @@ ByCoarseType::count(CountBase& countBase, const Node& node) } bool -ByCoarseType::report(CountBase& countBase, MutableHandleValue report) +ByCoarseType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); if (!obj) return false; RootedValue objectsReport(cx); - if (!count.objects->report(&objectsReport) || + if (!count.objects->report(cx, &objectsReport) || !DefineProperty(cx, obj, cx->names().objects, objectsReport)) return false; RootedValue scriptsReport(cx); - if (!count.scripts->report(&scriptsReport) || + if (!count.scripts->report(cx, &scriptsReport) || !DefineProperty(cx, obj, cx->names().scripts, scriptsReport)) return false; RootedValue stringsReport(cx); - if (!count.strings->report(&stringsReport) || + if (!count.strings->report(cx, &stringsReport) || !DefineProperty(cx, obj, cx->names().strings, stringsReport)) return false; RootedValue otherReport(cx); - if (!count.other->report(&otherReport) || + if (!count.other->report(cx, &otherReport) || !DefineProperty(cx, obj, cx->names().other, otherReport)) return false; @@ -320,7 +317,7 @@ cStringCountMapToObject(JSContext* cx, CStringCountMap& map) { for (auto& entry : entries) { CountBasePtr& thenCount = entry->value(); RootedValue thenReport(cx); - if (!thenCount->report(&thenReport)) + if (!thenCount->report(cx, &thenReport)) return nullptr; const char* name = entry->key(); @@ -365,10 +362,8 @@ class ByObjectClass : public CountType { CountTypePtr otherType; public: - ByObjectClass(Census& census, - CountTypePtr& classesType, - CountTypePtr& otherType) - : CountType(census), + ByObjectClass(CountTypePtr& classesType, CountTypePtr& otherType) + : CountType(), classesType(Move(classesType)), otherType(Move(otherType)) { } @@ -380,8 +375,8 @@ class ByObjectClass : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -391,7 +386,7 @@ ByObjectClass::makeCount() if (!otherCount) return nullptr; - UniquePtr count(census.new_(*this, otherCount)); + UniquePtr count(js_new(*this, otherCount)); if (!count || !count->init()) return nullptr; @@ -408,14 +403,14 @@ ByObjectClass::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByObjectClass::count(CountBase& countBase, const Node& node) +ByObjectClass::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; const char* className = node.jsObjectClassName(); if (!className) - return count.other->count(node); + return count.other->count(mallocSizeOf, node); Table::AddPtr p = count.table.lookupForAdd(className); if (!p) { @@ -423,21 +418,20 @@ ByObjectClass::count(CountBase& countBase, const Node& node) if (!classCount || !count.table.add(p, className, Move(classCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByObjectClass::report(CountBase& countBase, MutableHandleValue report) +ByObjectClass::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table)); if (!obj) return false; RootedValue otherReport(cx); - if (!count.other->report(&otherReport) || + if (!count.other->report(cx, &otherReport) || !DefineProperty(cx, obj, cx->names().other, otherReport)) return false; @@ -466,8 +460,8 @@ class ByUbinodeType : public CountType { CountTypePtr entryType; public: - ByUbinodeType(Census& census, CountTypePtr& entryType) - : CountType(census), + explicit ByUbinodeType(CountTypePtr& entryType) + : CountType(), entryType(Move(entryType)) { } @@ -478,14 +472,14 @@ class ByUbinodeType : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr ByUbinodeType::makeCount() { - UniquePtr count(census.new_(*this)); + UniquePtr count(js_new(*this)); if (!count || !count->init()) return nullptr; @@ -501,7 +495,7 @@ ByUbinodeType::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByUbinodeType::count(CountBase& countBase, const Node& node) +ByUbinodeType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; @@ -514,14 +508,13 @@ ByUbinodeType::count(CountBase& countBase, const Node& node) if (!typesCount || !count.table.add(p, key, Move(typesCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByUbinodeType::report(CountBase& countBase, MutableHandleValue report) +ByUbinodeType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; // Build a vector of pointers to entries; sort by total; and then use // that to build the result object. This makes the ordering of entries @@ -541,7 +534,7 @@ ByUbinodeType::report(CountBase& countBase, MutableHandleValue report) Entry& entry = **entryPtr; CountBasePtr& typeCount = entry.value(); RootedValue typeReport(cx); - if (!typeCount->report(&typeReport)) + if (!typeCount->report(cx, &typeReport)) return false; const char16_t* name = entry.key(); @@ -609,8 +602,8 @@ class ByAllocationStack : public CountType { CountTypePtr noStackType; public: - ByAllocationStack(Census& census, CountTypePtr& entryType, CountTypePtr& noStackType) - : CountType(census), + ByAllocationStack(CountTypePtr& entryType, CountTypePtr& noStackType) + : CountType(), entryType(Move(entryType)), noStackType(Move(noStackType)) { } @@ -622,8 +615,8 @@ class ByAllocationStack : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -633,7 +626,7 @@ ByAllocationStack::makeCount() if (!noStackCount) return nullptr; - UniquePtr count(census.new_(*this, noStackCount)); + UniquePtr count(js_new(*this, noStackCount)); if (!count || !count->init()) return nullptr; return CountBasePtr(count.release()); @@ -657,7 +650,7 @@ ByAllocationStack::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByAllocationStack::count(CountBase& countBase, const Node& node) +ByAllocationStack::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; @@ -673,18 +666,17 @@ ByAllocationStack::count(CountBase& countBase, const Node& node) return false; } MOZ_ASSERT(p); - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } // Otherwise, count it in the "no stack" category. - return count.noStack->count(node); + return count.noStack->count(mallocSizeOf, node); } bool -ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) +ByAllocationStack::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; #ifdef DEBUG // Check that nothing rehashes our table while we hold pointers into it. @@ -719,7 +711,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) CountBasePtr& stackCount = entry.value(); RootedValue stackReport(cx); - if (!stackCount->report(&stackReport)) + if (!stackCount->report(cx, &stackReport)) return false; if (!MapObject::set(cx, map, stackVal, stackReport)) @@ -728,7 +720,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) if (count.noStack->total_ > 0) { RootedValue noStackReport(cx); - if (!count.noStack->report(&noStackReport)) + if (!count.noStack->report(cx, &noStackReport)) return false; RootedValue noStack(cx, StringValue(cx->names().noStack)); if (!MapObject::set(cx, map, noStack, noStackReport)) @@ -767,10 +759,8 @@ class ByFilename : public CountType { CountTypePtr noFilenameType; public: - ByFilename(Census& census, - CountTypePtr& thenType, - CountTypePtr& noFilenameType) - : CountType(census), + ByFilename(CountTypePtr& thenType, CountTypePtr& noFilenameType) + : CountType(), thenType(Move(thenType)), noFilenameType(Move(noFilenameType)) { } @@ -782,8 +772,8 @@ class ByFilename : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -797,7 +787,7 @@ ByFilename::makeCount() if (!noFilenameCount) return nullptr; - UniquePtr count(census.new_(*this, Move(thenCount), Move(noFilenameCount))); + UniquePtr count(js_new(*this, Move(thenCount), Move(noFilenameCount))); if (!count || !count->init()) return nullptr; @@ -814,14 +804,14 @@ ByFilename::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByFilename::count(CountBase& countBase, const Node& node) +ByFilename::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; const char* filename = node.scriptFilename(); if (!filename) - return count.noFilename->count(node); + return count.noFilename->count(mallocSizeOf, node); Table::AddPtr p = count.table.lookupForAdd(filename); if (!p) { @@ -829,21 +819,20 @@ ByFilename::count(CountBase& countBase, const Node& node) if (!thenCount || !count.table.add(p, filename, Move(thenCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByFilename::report(CountBase& countBase, MutableHandleValue report) +ByFilename::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table)); if (!obj) return false; RootedValue noFilenameReport(cx); - if (!count.noFilename->report(&noFilenameReport) || + if (!count.noFilename->report(cx, &noFilenameReport) || !DefineProperty(cx, obj, cx->names().noFilename, noFilenameReport)) { return false; @@ -876,11 +865,11 @@ CensusHandler::operator() (BreadthFirst& traversal, Zone* zone = referent.zone(); if (census.targetZones.count() == 0 || census.targetZones.has(zone)) - return rootCount->count(referent); + return rootCount->count(mallocSizeOf, referent); if (zone == census.atomsZone) { traversal.abandonReferent(); - return rootCount->count(referent); + return rootCount->count(mallocSizeOf, referent); } traversal.abandonReferent(); @@ -890,26 +879,21 @@ CensusHandler::operator() (BreadthFirst& traversal, /*** Parsing Breakdowns ***************************************************************************/ -static CountTypePtr ParseBreakdown(Census& census, HandleValue breakdownValue); - static CountTypePtr -ParseChildBreakdown(Census& census, HandleObject breakdown, PropertyName* prop) +ParseChildBreakdown(JSContext* cx, HandleObject breakdown, PropertyName* prop) { - JSContext* cx = census.cx; RootedValue v(cx); if (!GetProperty(cx, breakdown, breakdown, prop, &v)) return nullptr; - return ParseBreakdown(census, v); + return ParseBreakdown(cx, v); } -static CountTypePtr -ParseBreakdown(Census& census, HandleValue breakdownValue) +CountTypePtr +ParseBreakdown(JSContext* cx, HandleValue breakdownValue) { - JSContext* cx = census.cx; - if (breakdownValue.isUndefined()) { // Construct the default type, { by: 'count' } - CountTypePtr simple(census.new_(census)); + CountTypePtr simple(js_new()); return simple; } @@ -967,75 +951,73 @@ ParseBreakdown(Census& census, HandleValue breakdownValue) return nullptr; } - CountTypePtr simple(census.new_(census, - labelUnique, - ToBoolean(countValue), - ToBoolean(bytesValue))); + CountTypePtr simple(js_new(labelUnique, + ToBoolean(countValue), + ToBoolean(bytesValue))); return simple; } if (StringEqualsAscii(by, "objectClass")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other)); + CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other)); if (!otherType) return nullptr; - return CountTypePtr(census.new_(census, thenType, otherType)); + return CountTypePtr(js_new(thenType, otherType)); } if (StringEqualsAscii(by, "coarseType")) { - CountTypePtr objectsType(ParseChildBreakdown(census, breakdown, cx->names().objects)); + CountTypePtr objectsType(ParseChildBreakdown(cx, breakdown, cx->names().objects)); if (!objectsType) return nullptr; - CountTypePtr scriptsType(ParseChildBreakdown(census, breakdown, cx->names().scripts)); + CountTypePtr scriptsType(ParseChildBreakdown(cx, breakdown, cx->names().scripts)); if (!scriptsType) return nullptr; - CountTypePtr stringsType(ParseChildBreakdown(census, breakdown, cx->names().strings)); + CountTypePtr stringsType(ParseChildBreakdown(cx, breakdown, cx->names().strings)); if (!stringsType) return nullptr; - CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other)); + CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other)); if (!otherType) return nullptr; - return CountTypePtr(census.new_(census, - objectsType, - scriptsType, - stringsType, - otherType)); + return CountTypePtr(js_new(objectsType, + scriptsType, + stringsType, + otherType)); } if (StringEqualsAscii(by, "internalType")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - return CountTypePtr(census.new_(census, thenType)); + return CountTypePtr(js_new(thenType)); } if (StringEqualsAscii(by, "allocationStack")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr noStackType(ParseChildBreakdown(census, breakdown, cx->names().noStack)); + CountTypePtr noStackType(ParseChildBreakdown(cx, breakdown, cx->names().noStack)); if (!noStackType) return nullptr; - return CountTypePtr(census.new_(census, thenType, noStackType)); + return CountTypePtr(js_new(thenType, noStackType)); } if (StringEqualsAscii(by, "filename")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr noFilenameType(ParseChildBreakdown(census, breakdown, cx->names().noFilename)); + CountTypePtr noFilenameType(ParseChildBreakdown(cx, breakdown, cx->names().noFilename)); if (!noFilenameType) return nullptr; - return CountTypePtr(census.new_(census, thenType, noFilenameType)); + return CountTypePtr(js_new(thenType, noFilenameType)); } // We didn't recognize the breakdown type; complain. @@ -1059,25 +1041,22 @@ ParseBreakdown(Census& census, HandleValue breakdownValue) // other: { by: "internalType" } // } static CountTypePtr -GetDefaultBreakdown(Census& census) +GetDefaultBreakdown() { - CountTypePtr byClass(census.new_(census)); - CountTypePtr byClassElse(census.new_(census)); - CountTypePtr objects(census.new_(census, - byClass, - byClassElse)); + CountTypePtr byClass(js_new()); + CountTypePtr byClassElse(js_new()); + CountTypePtr objects(js_new(byClass, byClassElse)); - CountTypePtr scripts(census.new_(census)); - CountTypePtr strings(census.new_(census)); + CountTypePtr scripts(js_new()); + CountTypePtr strings(js_new()); - CountTypePtr byType(census.new_(census)); - CountTypePtr other(census.new_(census, byType)); + CountTypePtr byType(js_new()); + CountTypePtr other(js_new(byType)); - return CountTypePtr(census.new_(census, - objects, - scripts, - strings, - other)); + return CountTypePtr(js_new(objects, + scripts, + strings, + other)); } bool @@ -1088,8 +1067,8 @@ ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTyp return false; outResult = breakdown.isUndefined() - ? GetDefaultBreakdown(census) - : ParseBreakdown(census, breakdown); + ? GetDefaultBreakdown() + : ParseBreakdown(cx, breakdown); return !!outResult; } diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 67ad02c37a3..b034d7928b8 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 333; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 334; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 420, +static_assert(JSErr_Limit == 421, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 7a9488c8034..ed4e4f5d6f3 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -6116,7 +6116,7 @@ ContainerState::CreateMaskLayer(Layer *aLayer, container = aLayer->Manager()->CreateImageContainer(); NS_ASSERTION(container, "Could not create image container for mask layer."); - RefPtr image = new CairoImage(surfaceSizeInt, surface); + RefPtr image = new SourceSurfaceImage(surfaceSizeInt, surface); container->SetCurrentImageInTransaction(image); GetMaskLayerImageCache()->PutImage(newKey.forget(), container); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index aacc6a75d96..e50a12f8bde 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -5120,7 +5120,7 @@ nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame, } nscoord perspective = cbDisplay->mChildPerspective.GetCoordValue(); if (perspective <= 0) { - return false; + return true; } TransformReferenceBox refBox(cbFrame); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 4398c900635..d67cbcab316 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6886,6 +6886,44 @@ nsLayoutUtils::IsReallyFixedPos(nsIFrame* aFrame) parentType == nsGkAtoms::pageContentFrame; } +nsLayoutUtils::SurfaceFromElementResult +nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas, + uint32_t aSurfaceFlags, + DrawTarget* aTarget) +{ + SurfaceFromElementResult result; + + bool* isPremultiplied = nullptr; + if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) { + isPremultiplied = &result.mIsPremultiplied; + } + + nsIntSize size = aOffscreenCanvas->GetWidthHeight(); + + result.mSourceSurface = aOffscreenCanvas->GetSurfaceSnapshot(isPremultiplied); + if (!result.mSourceSurface) { + // If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just + // draw nothing, so return an empty surface. + DrawTarget *ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + RefPtr dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height), + SurfaceFormat::B8G8R8A8); + if (dt) { + result.mSourceSurface = dt->Snapshot(); + } + } else if (aTarget) { + RefPtr opt = aTarget->OptimizeSourceSurface(result.mSourceSurface); + if (opt) { + result.mSourceSurface = opt; + } + } + + result.mHasSize = true; + result.mSize = size; + result.mIsWriteOnly = aOffscreenCanvas->IsWriteOnly(); + + return result; +} + nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement, uint32_t aSurfaceFlags, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 06fa26df6f8..0ecf54ff66d 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -74,6 +74,7 @@ class Element; class HTMLImageElement; class HTMLCanvasElement; class HTMLVideoElement; +class OffscreenCanvas; class Selection; } // namespace dom namespace gfx { @@ -2115,6 +2116,11 @@ public: const RefPtr& GetSourceSurface(); }; + // This function can be called on any thread. + static SurfaceFromElementResult + SurfaceFromOffscreenCanvas(mozilla::dom::OffscreenCanvas *aOffscreenCanvas, + uint32_t aSurfaceFlags = 0, + DrawTarget *aTarget = nullptr); static SurfaceFromElementResult SurfaceFromElement(mozilla::dom::Element *aElement, uint32_t aSurfaceFlags = 0, DrawTarget *aTarget = nullptr); diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 0248232ed93..8f5d81e62e0 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -1644,6 +1644,8 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime) AutoRestore restoreTickStart(mTickStart); mTickStart = TimeStamp::Now(); + gfxPlatform::GetPlatform()->UpdateForDeviceReset(); + /* * The timer holds a reference to |this| while calling |Notify|. * However, implementations of |WillRefresh| are permitted to destroy diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 5d16dc198e6..9254b1c0934 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -13,6 +13,7 @@ #include "nsDisplayList.h" #include "nsLayoutUtils.h" #include "nsStyleUtil.h" +#include "ImageLayers.h" #include "Layers.h" #include "ActiveLayerTracker.h" @@ -338,7 +339,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, CanvasLayer* oldLayer = static_cast (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); - RefPtr layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); + RefPtr layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); if (!layer) return nullptr; @@ -357,7 +358,13 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, transform.PreScale(destGFXRect.Width() / canvasSizeInPx.width, destGFXRect.Height() / canvasSizeInPx.height); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); - layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + if (layer->GetType() == layers::Layer::TYPE_CANVAS) { + RefPtr canvasLayer = static_cast(layer.get()); + canvasLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) { + RefPtr imageLayer = static_cast(layer.get()); + imageLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + } return layer.forget(); } diff --git a/layout/reftests/abs-pos/reftest.list b/layout/reftests/abs-pos/reftest.list index f643638141a..f25349535b9 100644 --- a/layout/reftests/abs-pos/reftest.list +++ b/layout/reftests/abs-pos/reftest.list @@ -49,7 +49,7 @@ skip-if((B2G&&browserIsRemote)||Mulet) != table-cell-8.html table-print-1-ref.ht == continuation-positioned-inline-1.html continuation-positioned-inline-ref.html == continuation-positioned-inline-2.html continuation-positioned-inline-ref.html == scrollframe-1.html scrollframe-1-ref.html -skip-if(B2G||Mulet) fuzzy-if(Android,9,185) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,107) == scrollframe-2.html scrollframe-2-ref.html #bug 756530 # Initial mulet triage: parity with B2G/B2G Desktop +fuzzy-if(gtkWidget,1,1) skip-if(B2G||Mulet) fuzzy-if(Android,9,185) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,107) == scrollframe-2.html scrollframe-2-ref.html #bug 756530 # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(gtkWidget,1,8) == select-1.html select-1-ref.html fuzzy-if(gtkWidget,1,8) == select-1-dynamic.html select-1-ref.html == select-2.html select-2-ref.html diff --git a/media/mtransport/third_party/nICEr/src/util/mbslen.c b/media/mtransport/third_party/nICEr/src/util/mbslen.c index 14a45fbb6ea..3645c95cfdb 100644 --- a/media/mtransport/third_party/nICEr/src/util/mbslen.c +++ b/media/mtransport/third_party/nICEr/src/util/mbslen.c @@ -43,17 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#if defined(DARWIN) +#if defined(DARWIN) || defined(__DragonFly__) || defined(__FreeBSD__) #define HAVE_XLOCALE #endif -#ifdef __FreeBSD__ -#include -# if __FreeBSD_version > 900505 -# define HAVE_XLOCALE -# endif -#endif - #ifdef HAVE_XLOCALE #include #endif /* HAVE_XLOCALE */ diff --git a/media/webrtc/trunk/webrtc/base/thread_checker_impl.cc b/media/webrtc/trunk/webrtc/base/thread_checker_impl.cc index 95638ea49cf..7098a51cf6a 100644 --- a/media/webrtc/trunk/webrtc/base/thread_checker_impl.cc +++ b/media/webrtc/trunk/webrtc/base/thread_checker_impl.cc @@ -21,8 +21,6 @@ #if defined(__NetBSD__) #include #elif defined(__FreeBSD__) -#include -#include #include #endif @@ -46,13 +44,7 @@ PlatformThreadId CurrentThreadId() { #elif defined(__OpenBSD__) ret = reinterpret_cast (pthread_self()); #elif defined(__FreeBSD__) -#if __FreeBSD_version > 900030 - ret = pthread_getthreadid_np(); -#else - long lwpid; - thr_self(&lwpid); - ret = lwpid; -#endif + ret = pthread_getthreadid_np(); #else // Default implementation for nacl and solaris. ret = reinterpret_cast(pthread_self()); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm index daa9fc78586..54c8c79276b 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm @@ -102,6 +102,18 @@ bool WindowCapturerMac::GetWindowList(WindowList* windows) { CFNumberRef window_layer = reinterpret_cast( CFDictionaryGetValue(window, kCGWindowLayer)); if (window_title && window_id && window_layer) { + //Skip windows of zero area + CFDictionaryRef bounds_ref = reinterpret_cast( + CFDictionaryGetValue(window,kCGWindowBounds)); + CGRect bounds_rect; + if(!(bounds_ref) || + !(CGRectMakeWithDictionaryRepresentation(bounds_ref,&bounds_rect))){ + continue; + } + bounds_rect = CGRectStandardize(bounds_rect); + if((bounds_rect.size.width <= 0) || (bounds_rect.size.height <= 0)){ + continue; + } // Skip windows with layer=0 (menu, dock). int layer; CFNumberGetValue(window_layer, kCFNumberIntType, &layer); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc index f66a26096ab..132e2a373fd 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc @@ -70,6 +70,12 @@ BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { // Skip windows when we failed to convert the title or it is empty. if (window.title.empty()) return TRUE; + // Skip windows of zero visible area, except IconicWindows + RECT bounds; + if(GetClientRect(hwnd,&bounds) && !IsIconic(hwnd) + && IsRectEmpty(&bounds)){ + return TRUE; + } list->push_back(window); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc index a7ba0c1d41b..f78051b2b92 100755 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc @@ -134,6 +134,16 @@ bool WindowCapturerLinux::GetWindowList(WindowList* windows) { if (app_window && !IsDesktopElement(app_window)) { Window w; w.id = app_window; + + XWindowAttributes window_attr; + if(!XGetWindowAttributes(display(),w.id,&window_attr)){ + LOG(LS_ERROR)<<"Bad request for attributes for window ID:"< 0) } catch (e) { do_throw("Failed to read " + file + " from gre-resources:"+e) diff --git a/netwerk/test/unit/test_inhibit_caching.js b/netwerk/test/unit/test_inhibit_caching.js index 5fa7c297204..7e81eb69684 100644 --- a/netwerk/test/unit/test_inhibit_caching.js +++ b/netwerk/test/unit/test_inhibit_caching.js @@ -1,6 +1,6 @@ Cu.import('resource://gre/modules/LoadContextInfo.jsm'); Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); var first = true; function contentHandler(metadata, response) @@ -35,18 +35,8 @@ function run_test() // Makes a regular request function test_first_response() { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var chan = ios.newChannel2(uri+"/test", - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); - - chan.asyncOpen(new ChannelListener(check_first_response, null), null); + var chan = NetUtil.newChannel({uri: uri+"/test", loadUsingSystemPrincipal: true}); + chan.asyncOpen2(new ChannelListener(check_first_response, null)); } // Checks that we got the appropriate response @@ -71,19 +61,9 @@ function cache_entry_callback(status, entry) { // Makes a request with the INHIBIT_CACHING load flag function test_inhibit_caching() { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var chan = ios.newChannel2(uri+"/test", - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); - + var chan = NetUtil.newChannel({uri: uri+"/test", loadUsingSystemPrincipal: true}); chan.QueryInterface(Ci.nsIRequest).loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; - chan.asyncOpen(new ChannelListener(check_second_response, null), null); + chan.asyncOpen2(new ChannelListener(check_second_response, null)); } // Checks that we got a different response from the first request diff --git a/netwerk/test/unit/test_invalidport.js b/netwerk/test/unit/test_invalidport.js index 08aafbf7584..70d401c84c5 100644 --- a/netwerk/test/unit/test_invalidport.js +++ b/netwerk/test/unit/test_invalidport.js @@ -2,7 +2,7 @@ // Perform the async open several times in order to induce exponential // scheduling behavior bugs. -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); var CC = Components.Constructor; @@ -31,17 +31,8 @@ function run_test() { } function execute_test() { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var chan = ios.newChannel2("http://localhost:75000", - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + var chan = NetUtil.newChannel({uri: "http://localhost:75000", loadUsingSystemPrincipal: true}); chan.QueryInterface(Ci.nsIHttpChannel); - chan.asyncOpen(listener, null); + chan.asyncOpen2(listener); } diff --git a/netwerk/test/unit/test_localstreams.js b/netwerk/test/unit/test_localstreams.js index 1d80143b416..8e926f5712f 100644 --- a/netwerk/test/unit/test_localstreams.js +++ b/netwerk/test/unit/test_localstreams.js @@ -1,5 +1,5 @@ // Tests bug 304414 -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); const PR_RDONLY = 0x1; // see prio.h @@ -69,12 +69,10 @@ function stream_from_channel(file) { var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var uri = ios.newFileURI(file); - return ios.newChannelFromURI2(uri, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER).open(); + return NetUtil.newChannel({ + uri: uri, + loadUsingSystemPrincipal: true + }).open2(); } function run_test() { diff --git a/netwerk/test/unit/test_multipart_streamconv_application_package.js b/netwerk/test/unit/test_multipart_streamconv_application_package.js index ca7907159a3..9d9f0011bc3 100644 --- a/netwerk/test/unit/test_multipart_streamconv_application_package.js +++ b/netwerk/test/unit/test_multipart_streamconv_application_package.js @@ -21,7 +21,7 @@ // - checks that the headers for each part is set correctly Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); var httpserver = null; @@ -30,16 +30,7 @@ XPCOMUtils.defineLazyGetter(this, "uri", function() { }); function make_channel(url) { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - return ios.newChannel2(url, - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}); } function contentHandler(metadata, response) @@ -210,7 +201,7 @@ function test_multipart() { null); var chan = make_channel(uri + "/multipart"); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); } function test_multipart_with_boundary() { @@ -222,7 +213,7 @@ function test_multipart_with_boundary() { null); var chan = make_channel(uri + "/multipart2"); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); } function test_multipart_chunked_headers() { @@ -234,7 +225,7 @@ function test_multipart_chunked_headers() { null); var chan = make_channel(uri + "/multipart3"); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); } function test_multipart_content_type_other() { @@ -247,7 +238,7 @@ function test_multipart_content_type_other() { null); var chan = make_channel(uri + "/multipart4"); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); } function test_multipart_package_header(aChunkSize) { @@ -260,7 +251,7 @@ function test_multipart_package_header(aChunkSize) { null); var chan = make_channel(uri + "/multipart5_" + aChunkSize); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); } // Bug 1212223 - Test multipart with package header and different chunk size. diff --git a/netwerk/test/unit/test_multipart_streamconv_missing_lead_boundary.js b/netwerk/test/unit/test_multipart_streamconv_missing_lead_boundary.js index 46f46cab070..97924ccb16a 100644 --- a/netwerk/test/unit/test_multipart_streamconv_missing_lead_boundary.js +++ b/netwerk/test/unit/test_multipart_streamconv_missing_lead_boundary.js @@ -1,5 +1,5 @@ Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); var httpserver = null; @@ -8,33 +8,11 @@ XPCOMUtils.defineLazyGetter(this, "uri", function() { }); function make_channel(url) { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - return ios.newChannel2(url, - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}); } var multipartBody = "\r\nSome text\r\n--boundary\r\n\r\n\r\n--boundary--"; -function make_channel(url) { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - return ios.newChannel2(url, - "", - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); -} - function contentHandler(metadata, response) { response.setHeader("Content-Type", 'multipart/mixed; boundary="boundary"'); @@ -106,6 +84,6 @@ function run_test() null); var chan = make_channel(uri); - chan.asyncOpen(conv, null); + chan.asyncOpen2(conv); do_test_pending(); } diff --git a/netwerk/test/unit/test_reopen.js b/netwerk/test/unit/test_reopen.js index 40d2b313adc..b3744dfc531 100644 --- a/netwerk/test/unit/test_reopen.js +++ b/netwerk/test/unit/test_reopen.js @@ -2,7 +2,7 @@ // See https://bugzilla.mozilla.org/show_bug.cgi?id=372486 Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); const NS_ERROR_IN_PROGRESS = 0x804b000f; const NS_ERROR_ALREADY_OPENED = 0x804b0049; @@ -22,28 +22,17 @@ var httpserv = null; // Utility functions function makeChan(url) { - var ios = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - return chan = ios.newChannel2(url, - null, - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER) - .QueryInterface(Ci.nsIChannel); + return chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}) + .QueryInterface(Ci.nsIChannel); } function new_file_channel(file) { var ios = Cc["@mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService); - return ios.newChannelFromURI2(ios.newFileURI(file), - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER); + return NetUtil.newChannel({ + uri: ios.newFileURI(file), + loadUsingSystemPrincipal: true + }); } @@ -64,13 +53,13 @@ function check_throws(closure, error) { function check_open_throws(error) { check_throws(function() { - chan.open(listener, null); + chan.open2(listener); }, error); } function check_async_open_throws(error) { check_throws(function() { - chan.asyncOpen(listener, null); + chan.asyncOpen2(listener); }, error); } @@ -102,13 +91,13 @@ function after_channel_closed() { function test_channel(createChanClosure) { // First, synchronous reopening test chan = createChanClosure(); - var inputStream = chan.open(); + var inputStream = chan.open2(); check_open_throws(NS_ERROR_IN_PROGRESS); check_async_open_throws([NS_ERROR_IN_PROGRESS, NS_ERROR_ALREADY_OPENED]); // Then, asynchronous one chan = createChanClosure(); - chan.asyncOpen(listener, null); + chan.asyncOpen2(listener); check_open_throws(NS_ERROR_IN_PROGRESS); check_async_open_throws(NS_ERROR_IN_PROGRESS); } diff --git a/netwerk/test/unit_ipc/child_app_offline.js b/netwerk/test/unit_ipc/child_app_offline.js index a2c5e5003f5..ded06701bbc 100644 --- a/netwerk/test/unit_ipc/child_app_offline.js +++ b/netwerk/test/unit_ipc/child_app_offline.js @@ -1,4 +1,4 @@ -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); function inChildProcess() { return Cc["@mozilla.org/xre/app-info;1"] @@ -7,15 +7,8 @@ function inChildProcess() { } function makeChan(url, appId, inBrowser) { - var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); - var chan = ios.newChannel2(url, - null, - null, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_OTHER).QueryInterface(Ci.nsIHttpChannel); + var chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}) + .QueryInterface(Ci.nsIHttpChannel); chan.notificationCallbacks = { appId: appId, isInBrowserElement: inBrowser, @@ -37,28 +30,28 @@ function makeChan(url, appId, inBrowser) { function run_test() { do_test_pending(); var chan = makeChan("http://localhost:12345/first", 14, false); - chan.asyncOpen(new ChannelListener(checkResponse, "response0"), null); + chan.asyncOpen2(new ChannelListener(checkResponse, "response0")); } // Should return cached result function test1() { do_test_pending(); var chan = makeChan("http://localhost:12345/first", 14, false); - chan.asyncOpen(new ChannelListener(checkResponse, "response0"), null); + chan.asyncOpen2(new ChannelListener(checkResponse, "response0")); } // This request should fail function test2() { do_test_pending(); var chan = makeChan("http://localhost:12345/second", 14, false); - chan.asyncOpen(new ChannelListener(checkResponse, "", CL_EXPECT_FAILURE), null); + chan.asyncOpen2(new ChannelListener(checkResponse, "", CL_EXPECT_FAILURE)); } // This request should succeed function test3() { do_test_pending(); var chan = makeChan("http://localhost:12345/second", 14, false); - chan.asyncOpen(new ChannelListener(checkResponse, "response3"), null); + chan.asyncOpen2(new ChannelListener(checkResponse, "response3")); } function checkResponse(req, buffer, expected) { diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 42da26f9f76..5e8323ff930 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -1319,10 +1319,10 @@ INSTALL_TARGETS += %(prefix)s backend_file.write('INSTALL_TARGETS += %s\n' % target_var) def _process_final_target_pp_files(self, obj, files, backend_file): - # We'd like to install these via manifests as preprocessed files. - # But they currently depend on non-standard flags being added via - # some Makefiles, so for now we just pass them through to the - # underlying Makefile.in. + # Bug 1177710 - We'd like to install these via manifests as + # preprocessed files. But they currently depend on non-standard flags + # being added via some Makefiles, so for now we just pass them through + # to the underlying Makefile.in. for i, (path, files) in enumerate(files.walk()): for f in files: backend_file.write('DIST_FILES_%d += %s\n' % ( diff --git a/testing/web-platform/meta/FileAPI/idlharness.worker.js.ini b/testing/web-platform/meta/FileAPI/idlharness.worker.js.ini index 1519b7d5540..37b8a394992 100644 --- a/testing/web-platform/meta/FileAPI/idlharness.worker.js.ini +++ b/testing/web-platform/meta/FileAPI/idlharness.worker.js.ini @@ -41,136 +41,3 @@ [FileList interface: attribute length] expected: FAIL - - [FileReader interface: existence and properties of interface object] - expected: FAIL - - [FileReader interface object length] - expected: FAIL - - [FileReader interface: existence and properties of interface prototype object] - expected: FAIL - - [FileReader interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [FileReader interface: operation readAsArrayBuffer(Blob)] - expected: FAIL - - [FileReader interface: operation readAsText(Blob,DOMString)] - expected: FAIL - - [FileReader interface: operation readAsDataURL(Blob)] - expected: FAIL - - [FileReader interface: operation abort()] - expected: FAIL - - [FileReader interface: constant EMPTY on interface object] - expected: FAIL - - [FileReader interface: constant EMPTY on interface prototype object] - expected: FAIL - - [FileReader interface: constant LOADING on interface object] - expected: FAIL - - [FileReader interface: constant LOADING on interface prototype object] - expected: FAIL - - [FileReader interface: constant DONE on interface object] - expected: FAIL - - [FileReader interface: constant DONE on interface prototype object] - expected: FAIL - - [FileReader interface: attribute readyState] - expected: FAIL - - [FileReader interface: attribute result] - expected: FAIL - - [FileReader interface: attribute error] - expected: FAIL - - [FileReader interface: attribute onloadstart] - expected: FAIL - - [FileReader interface: attribute onprogress] - expected: FAIL - - [FileReader interface: attribute onload] - expected: FAIL - - [FileReader interface: attribute onabort] - expected: FAIL - - [FileReader interface: attribute onerror] - expected: FAIL - - [FileReader interface: attribute onloadend] - expected: FAIL - - [FileReader must be primary interface of new FileReader()] - expected: FAIL - - [Stringification of new FileReader()] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "readAsArrayBuffer" with the proper type (0)] - expected: FAIL - - [FileReader interface: calling readAsArrayBuffer(Blob) on new FileReader() with too few arguments must throw TypeError] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "readAsText" with the proper type (1)] - expected: FAIL - - [FileReader interface: calling readAsText(Blob,DOMString) on new FileReader() with too few arguments must throw TypeError] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "readAsDataURL" with the proper type (2)] - expected: FAIL - - [FileReader interface: calling readAsDataURL(Blob) on new FileReader() with too few arguments must throw TypeError] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "abort" with the proper type (3)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "EMPTY" with the proper type (4)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "LOADING" with the proper type (5)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "DONE" with the proper type (6)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "readyState" with the proper type (7)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "result" with the proper type (8)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "error" with the proper type (9)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onloadstart" with the proper type (10)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onprogress" with the proper type (11)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onload" with the proper type (12)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onabort" with the proper type (13)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onerror" with the proper type (14)] - expected: FAIL - - [FileReader interface: new FileReader() must inherit property "onloadend" with the proper type (15)] - expected: FAIL - diff --git a/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp b/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp index 03bda7e4786..e73bb097aa1 100644 --- a/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp +++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp @@ -13,6 +13,7 @@ #include "nsILocalFileWin.h" #include "nsArrayUtils.h" #include "nsIXULAppInfo.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WindowsVersion.h" using namespace mozilla; @@ -248,9 +249,7 @@ nsParentalControlsService::RequestURIOverrides(nsIArray *aTargets, nsIInterfaceR // Allocate an array of sub uri int32_t count = arrayLength - 1; - nsAutoArrayPtr arrUrls(new LPCWSTR[count]); - if (!arrUrls) - return NS_ERROR_OUT_OF_MEMORY; + auto arrUrls = MakeUnique(count); uint32_t uriIdx = 0, idx; for (idx = 1; idx < arrayLength; idx++) diff --git a/toolkit/components/reader/ReaderMode.jsm b/toolkit/components/reader/ReaderMode.jsm index 2890e1ebe85..dd1756197a3 100644 --- a/toolkit/components/reader/ReaderMode.jsm +++ b/toolkit/components/reader/ReaderMode.jsm @@ -228,7 +228,18 @@ this.ReaderMode = { } } } - if (xhr.responseURL != url) { + let responseURL = xhr.responseURL; + let givenURL = url; + // Convert these to real URIs to make sure the escaping (or lack + // thereof) is identical: + try { + responseURL = Services.io.newURI(responseURL, null, null).spec; + } catch (ex) { /* Ignore errors - we'll use what we had before */ } + try { + givenURL = Services.io.newURI(givenURL, null, null).spec; + } catch (ex) { /* Ignore errors - we'll use what we had before */ } + + if (responseURL != givenURL) { // We were redirected without a meta refresh tag. // Force redirect to the correct place: reject({newURL: xhr.responseURL}); diff --git a/toolkit/content/aboutProfiles.js b/toolkit/content/aboutProfiles.js index 82ee69f7404..760a0c60849 100644 --- a/toolkit/content/aboutProfiles.js +++ b/toolkit/content/aboutProfiles.js @@ -49,6 +49,12 @@ function refreshUI() { restartNormalModeButton.onclick = function() { restart(false); } } +function openDirectory(dir) { + let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1", + "nsILocalFile", "initWithPath"); + new nsLocalFile(dir).reveal(); +} + function display(profileData) { let parent = document.getElementById('profiles'); @@ -73,7 +79,7 @@ function display(profileData) { let tbody = document.createElement('tbody'); table.appendChild(tbody); - function createItem(title, value) { + function createItem(title, value, dir = false) { let tr = document.createElement('tr'); tbody.appendChild(tr); @@ -85,15 +91,35 @@ function display(profileData) { let td = document.createElement('td'); td.appendChild(document.createTextNode(value)); tr.appendChild(td); + + if (dir) { + td.appendChild(document.createTextNode(' ')); + let button = document.createElement('button'); + let buttonText = document.createTextNode(bundle.GetStringFromName( +#ifdef XP_WIN + 'winOpenDir' +#elif XP_MACOSX + 'macOpenDir' +#else + 'openDir' +#endif + )); + button.appendChild(buttonText); + td.appendChild(button); + + button.addEventListener('click', function(e) { + openDirectory(value); + }); + } } createItem(bundle.GetStringFromName('isDefault'), profileData.isDefault ? bundle.GetStringFromName('yes') : bundle.GetStringFromName('no')); - createItem(bundle.GetStringFromName('rootDir'), profileData.profile.rootDir.path); + createItem(bundle.GetStringFromName('rootDir'), profileData.profile.rootDir.path, true); if (profileData.profile.localDir.path != profileData.profile.rootDir.path) { - createItem(bundle.GetStringFromName('localDir'), profileData.profile.localDir.path); + createItem(bundle.GetStringFromName('localDir'), profileData.profile.localDir.path, true); } let renameButton = document.createElement('button'); diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 1b7d4133a27..2e7ef693515 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -23,7 +23,7 @@ toolkit.jar: #endif content/global/aboutNetworking.js content/global/aboutNetworking.xhtml - content/global/aboutProfiles.js +* content/global/aboutProfiles.js content/global/aboutProfiles.xhtml content/global/aboutServiceWorkers.js content/global/aboutServiceWorkers.xhtml diff --git a/toolkit/locales/en-US/chrome/global/aboutProfiles.properties b/toolkit/locales/en-US/chrome/global/aboutProfiles.properties index e4682527512..69a78c29177 100644 --- a/toolkit/locales/en-US/chrome/global/aboutProfiles.properties +++ b/toolkit/locales/en-US/chrome/global/aboutProfiles.properties @@ -32,3 +32,11 @@ deleteProfileTitle = Delete Profile deleteProfileConfirm = Deleting a profile will remove the profile from the list of available profiles and cannot be undone.\nYou may also choose to delete the profile data files, including your settings, certificates and other user-related data. This option will delete the folder "%S" and cannot be undone.\nWould you like to delete the profile data files? deleteFiles = Delete Files dontDeleteFiles = Don't Delete Files + +openDir = Open Directory +# LOCALIZATION NOTE (macOpenDir): This is the Mac-specific variant of openDir. +# This allows us to use the preferred"Finder" terminology on Mac. +macOpenDir = Show in Finder +# LOCALIZATION NOTE (winOpenDir): This is the Windows-specific variant of +# openDir. +winOpenDir = Show Folder diff --git a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties index bb10918617f..c3453a8de85 100644 --- a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties +++ b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties @@ -28,6 +28,8 @@ profileFinishText=Click Finish to create this new profile. profileFinishTextMac=Click Done to create this new profile. profileMissing=Your %S profile cannot be loaded. It may be missing or inaccessible. profileMissingTitle=Profile Missing +pleaseSelectTitle=Select Profile +pleaseSelect=Please select a profile to begin %S, or create a new profile. # Profile reset # LOCALIZATION NOTE (resetBackupDirectory): Directory name for the profile directory backup created during reset. This directory is placed in a location users will see it (ie. their desktop). %S is the application name. diff --git a/toolkit/mozapps/extensions/test/browser/browser_experiments.js b/toolkit/mozapps/extensions/test/browser/browser_experiments.js index 766ea12edee..3920d667d81 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js +++ b/toolkit/mozapps/extensions/test/browser/browser_experiments.js @@ -98,6 +98,7 @@ add_task(function* initializeState() { registerCleanupFunction(() => { Services.prefs.clearUserPref("experiments.enabled"); + Services.prefs.clearUserPref("toolkit.telemetry.enabled"); if (gHttpServer) { gHttpServer.stop(() => {}); if (gSavedManifestURI !== undefined) { @@ -294,6 +295,7 @@ add_task(function* testActivateExperiment() { // We need to remove the cache file to help ensure consistent state. yield OS.File.remove(gExperiments._cacheFilePath); + Services.prefs.setBoolPref("toolkit.telemetry.enabled", true); Services.prefs.setBoolPref("experiments.enabled", true); info("Initializing experiments service."); @@ -635,6 +637,8 @@ add_task(function* testCleanup() { yield OS.File.remove(gExperiments._cacheFilePath); yield gExperiments.uninit(); yield gExperiments.init(); + + Services.prefs.clearUserPref("toolkit.telemetry.enabled"); } // Check post-conditions. diff --git a/toolkit/profile/content/profileSelection.js b/toolkit/profile/content/profileSelection.js index f880e54b280..898d5ef2980 100644 --- a/toolkit/profile/content/profileSelection.js +++ b/toolkit/profile/content/profileSelection.js @@ -4,11 +4,10 @@ * 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/. */ -Components.utils.import("resource://gre/modules/AppConstants.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -const C = Components.classes; -const I = Components.interfaces; +Cu.import("resource://gre/modules/AppConstants.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); const ToolkitProfileService = "@mozilla.org/toolkit/profile-service;1"; @@ -19,9 +18,9 @@ var gProfileService; function startup() { - gDialogParams = window.arguments[0].QueryInterface(I.nsIDialogParamBlock); + gDialogParams = window.arguments[0].QueryInterface(Ci.nsIDialogParamBlock); - gProfileService = C[ToolkitProfileService].getService(I.nsIToolkitProfileService); + gProfileService = Cc[ToolkitProfileService].getService(Ci.nsIToolkitProfileService); gProfileManagerBundle = document.getElementById("bundle_profileManager"); gBrandBundle = document.getElementById("bundle_brand"); diff --git a/toolkit/profile/content/profileSelection.xul b/toolkit/profile/content/profileSelection.xul index e3315e590cb..872cb0670a4 100644 --- a/toolkit/profile/content/profileSelection.xul +++ b/toolkit/profile/content/profileSelection.xul @@ -22,7 +22,7 @@ title="&windowtitle.label;" orient="vertical" buttons="accept,cancel" - style="width: 80em; height: 40em;" + style="width: 60em; height: 40em;" onload="startup();" ondialogaccept="return acceptDialog()" ondialogcancel="return exitDialog()" diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp index b7cd948f89c..06eb1770885 100644 --- a/toolkit/profile/nsToolkitProfileService.cpp +++ b/toolkit/profile/nsToolkitProfileService.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ArrayUtils.h" +#include "mozilla/UniquePtr.h" #include #include @@ -971,12 +972,10 @@ nsToolkitProfileService::Flush() uint32_t length; const int bufsize = 100+MAXPATHLEN*pCount; - nsAutoArrayPtr buffer (new char[bufsize]); + auto buffer = MakeUnique(bufsize); - NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); - - char *pos = buffer; - char *end = buffer + bufsize; + char *pos = buffer.get(); + char *end = pos + bufsize; pos += snprintf(pos, end - pos, "[General]\n" @@ -1024,13 +1023,11 @@ nsToolkitProfileService::Flush() rv = mListFile->OpenANSIFileDesc("w", &writeFile); NS_ENSURE_SUCCESS(rv, rv); - if (buffer) { - length = pos - buffer; + length = pos - buffer.get(); - if (fwrite(buffer, sizeof(char), length, writeFile) != length) { - fclose(writeFile); - return NS_ERROR_UNEXPECTED; - } + if (fwrite(buffer.get(), sizeof(char), length, writeFile) != length) { + fclose(writeFile); + return NS_ERROR_UNEXPECTED; } fclose(writeFile); diff --git a/toolkit/system/gnome/nsPackageKitService.cpp b/toolkit/system/gnome/nsPackageKitService.cpp index 87b9f354490..b05d483dd4b 100644 --- a/toolkit/system/gnome/nsPackageKitService.cpp +++ b/toolkit/system/gnome/nsPackageKitService.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsArrayUtils.h" -#include "nsAutoPtr.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsISupportsPrimitives.h" @@ -12,6 +11,7 @@ #include "nsString.h" #include "prlink.h" #include "mozilla/unused.h" +#include "mozilla/UniquePtr.h" #include #include @@ -216,7 +216,7 @@ nsPackageKitService::InstallPackages(uint32_t aInstallMethod, // Create the GVariant* parameter from the list of packages. GVariant* parameters = nullptr; - nsAutoArrayPtr packages(new gchar*[arrayLength + 1]); + auto packages = MakeUnique(arrayLength + 1); nsresult rv = NS_OK; for (uint32_t i = 0; i < arrayLength; i++) { diff --git a/toolkit/themes/linux/global/jar.mn b/toolkit/themes/linux/global/jar.mn index 5a5b33016c2..deab55daf71 100644 --- a/toolkit/themes/linux/global/jar.mn +++ b/toolkit/themes/linux/global/jar.mn @@ -57,3 +57,5 @@ toolkit.jar: * skin/classic/global/in-content/common.css (in-content/common.css) * skin/classic/global/in-content/info-pages.css (in-content/info-pages.css) skin/classic/global/toolbar/spring.png (toolbar/spring.png) + skin/classic/global/tree/twisty-clsd.png (tree/twisty-clsd.png) + skin/classic/global/tree/twisty-open.png (tree/twisty-open.png) diff --git a/toolkit/themes/windows/global/tree/twisty-clsd.png b/toolkit/themes/linux/global/tree/twisty-clsd.png similarity index 100% rename from toolkit/themes/windows/global/tree/twisty-clsd.png rename to toolkit/themes/linux/global/tree/twisty-clsd.png diff --git a/toolkit/themes/windows/global/tree/twisty-open.png b/toolkit/themes/linux/global/tree/twisty-open.png similarity index 100% rename from toolkit/themes/windows/global/tree/twisty-open.png rename to toolkit/themes/linux/global/tree/twisty-open.png diff --git a/toolkit/themes/shared/alert-common.css b/toolkit/themes/shared/alert-common.css index af7fd0c5d6e..20d9e7b00cf 100644 --- a/toolkit/themes/shared/alert-common.css +++ b/toolkit/themes/shared/alert-common.css @@ -10,11 +10,6 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); -#alertBox[hasBodyText] > #alertTextBox, -#alertBox[hasOrigin] > #alertTitleBox { - border-bottom: 1px solid ThreeDShadow; -} - #alertBox[animate] { animation-timing-function: cubic-bezier(.12,1.23,.48,1.09); } @@ -59,22 +54,30 @@ } #alertImage { - width: 64px; + width: 80px; + height: 80px; + max-width: 80px; + max-height: 80px; + object-fit: scale-down; + margin: 0 7px 7px; } .alertTextBox { - padding-top: 8px; - padding-inline-start: 8px; + padding-top: 4px; /* The text box width is increased to make up for the lack of image when one - is not provided. 319px is the text box width when a picture is present, - 255px, plus the width of the image, 64px. */ - width: 319px; + is not provided. 349px is the text box width when a picture is present, + 255px, plus the width of the image, 80px, and the margins, 7px each. */ + width: 349px; } #alertBox[hasImage] > box > #alertTextBox { width: 255px; } +#alertBox:not([hasImage]) > box > #alertTextBox { + padding-inline-start: 8px; +} + #alertTextLabel { padding-inline-end: 8px; } @@ -82,13 +85,17 @@ .alertTitle { -moz-box-flex: 1; font-weight: bold; - padding: 6px 8px; + padding: 6px 8px 0; width: 255px; } #alertFooter { - -moz-box-align: end; - padding-bottom: 2px; + -moz-box-align: start; +} + +#alertBox:not([hasOrigin]) > box > #alertTextBox, +#alertFooter { + padding-bottom: 5px; } #alertSourceLabel { @@ -103,7 +110,7 @@ border-width: 0; border-radius: 20px; min-width: 0; - list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities"); + list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities-grayscale"); margin-inline-end: 0; margin-bottom: 0; } diff --git a/toolkit/themes/shared/extensions/utilities.svg b/toolkit/themes/shared/extensions/utilities.svg index bc93fba236f..8bf24458ce0 100644 --- a/toolkit/themes/shared/extensions/utilities.svg +++ b/toolkit/themes/shared/extensions/utilities.svg @@ -13,6 +13,9 @@ use[id$="-native"] { fill: GrayText; } + use[id$="-grayscale"] { + fill: #4d4d4d; + } use[id$="-inverted"] { fill: #ddd; } @@ -22,5 +25,6 @@ + diff --git a/toolkit/themes/shared/non-mac.jar.inc.mn b/toolkit/themes/shared/non-mac.jar.inc.mn index c009ee93e73..a3d1ae46458 100644 --- a/toolkit/themes/shared/non-mac.jar.inc.mn +++ b/toolkit/themes/shared/non-mac.jar.inc.mn @@ -131,14 +131,6 @@ skin/classic/global/tree/sort-dsc.png (../../windows/global/tree/sort-dsc.png) skin/classic/global/tree/sort-asc-classic.png (../../windows/global/tree/sort-asc-classic.png) skin/classic/global/tree/sort-dsc-classic.png (../../windows/global/tree/sort-dsc-classic.png) - skin/classic/global/tree/twisty-clsd.png (../../windows/global/tree/twisty-clsd.png) - skin/classic/global/tree/twisty-clsd-rtl.png (../../windows/global/tree/twisty-clsd-rtl.png) - skin/classic/global/tree/twisty-clsd-hover.png (../../windows/global/tree/twisty-clsd-hover.png) - skin/classic/global/tree/twisty-clsd-hover-rtl.png (../../windows/global/tree/twisty-clsd-hover-rtl.png) - skin/classic/global/tree/twisty-open.png (../../windows/global/tree/twisty-open.png) - skin/classic/global/tree/twisty-open-rtl.png (../../windows/global/tree/twisty-open-rtl.png) - skin/classic/global/tree/twisty-open-hover.png (../../windows/global/tree/twisty-open-hover.png) - skin/classic/global/tree/twisty-open-hover-rtl.png (../../windows/global/tree/twisty-open-hover-rtl.png) skin/classic/help/Toolbar.png (../../windows/help/Toolbar.png) skin/classic/help/Toolbar-rtl.png (../../windows/help/Toolbar-rtl.png) diff --git a/toolkit/themes/windows/global/alerts/alert.css b/toolkit/themes/windows/global/alerts/alert.css index e0667adf84e..ce7f259126a 100644 --- a/toolkit/themes/windows/global/alerts/alert.css +++ b/toolkit/themes/windows/global/alerts/alert.css @@ -30,21 +30,23 @@ border: none !important; } +.alertCloseBox { + /* The close button is larger on Windows and has a large + circle around it, so we add more space between the close + button and the edge of the window. */ + margin-inline-end: 2px; +} + #alertSettings { /* The close button is larger on Windows, so the gear button is moved over to accomodate it and keep the two buttons horizontally aligned together. */ - margin-inline-end: 3px; + margin-inline-end: 5px; } @media (-moz-windows-default-theme) { - #alertBox[hasBodyText] > #alertTextBox, - #alertBox[hasOrigin] > #alertTitleBox { - border-bottom-color: rgba(107,107,107,.4); - } - #alertBox { - border-color: rgba(107,107,107,.4); + border-color: rgba(107,107,107,.3); background-color: rgba(255,255,255,.9); color: rgba(0,0,0,.9); } diff --git a/toolkit/themes/windows/global/button.css b/toolkit/themes/windows/global/button.css index 066196c7bd3..f882f8e0796 100644 --- a/toolkit/themes/windows/global/button.css +++ b/toolkit/themes/windows/global/button.css @@ -138,11 +138,11 @@ button[type="disclosure"] { margin: 0px !important; padding: 0px !important; -moz-appearance: none; - list-style-image: url("chrome://global/skin/tree/twisty-clsd.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd"); min-width: 0px !important; background-color: transparent; } button[type="disclosure"][open="true"] { - list-style-image: url("chrome://global/skin/tree/twisty-open.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#open"); } diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index a6e6bd92098..04509550e94 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -93,8 +93,9 @@ toolkit.jar: skin/classic/global/toolbar/spring-XP.png (toolbar/spring-XP.png) skin/classic/global/tree/sort-asc-XP.png (tree/sort-asc-XP.png) skin/classic/global/tree/sort-dsc-XP.png (tree/sort-dsc-XP.png) - skin/classic/global/tree/twisty-clsd-XP.png (tree/twisty-clsd-XP.png) - skin/classic/global/tree/twisty-open-XP.png (tree/twisty-open-XP.png) + skin/classic/global/tree/twisty.svg (tree/twisty.svg) + skin/classic/global/tree/twisty-XP.svg (tree/twisty-XP.svg) + skin/classic/global/tree/twisty-Vista78.svg (tree/twisty-Vista78.svg) #if MOZ_BUILD_APP == browser [browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: @@ -137,10 +138,20 @@ toolkit.jar: % override chrome://global/skin/toolbar/spring.png chrome://global/skin/toolbar/spring-XP.png osversion<6 % override chrome://global/skin/tree/sort-asc.png chrome://global/skin/tree/sort-asc-XP.png osversion<6 % override chrome://global/skin/tree/sort-dsc.png chrome://global/skin/tree/sort-dsc-XP.png osversion<6 -% override chrome://global/skin/tree/twisty-clsd.png chrome://global/skin/tree/twisty-clsd-XP.png osversion<6 -% override chrome://global/skin/tree/twisty-open.png chrome://global/skin/tree/twisty-open-XP.png osversion<6 % override chrome://global/skin/icons/close.png chrome://global/skin/icons/close-XPVista7.png osversion<=6.1 % override chrome://global/skin/icons/close@2x.png chrome://global/skin/icons/close-XPVista7@2x.png osversion<=6.1 % override chrome://global/skin/icons/close-inverted.png chrome://global/skin/icons/close-inverted-XPVista7.png osversion<=6.1 % override chrome://global/skin/icons/close-inverted@2x.png chrome://global/skin/icons/close-inverted-XPVista7@2x.png osversion<=6.1 + +% override chrome://global/skin/tree/twisty.svg#clsd chrome://global/skin/tree/twisty-Vista78.svg#clsd osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#clsd-rtl chrome://global/skin/tree/twisty-Vista78.svg#clsd-rtl osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#clsd-hover chrome://global/skin/tree/twisty-Vista78.svg#clsd-hover osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#clsd-hover-rtl chrome://global/skin/tree/twisty-Vista78.svg#clsd-hover-rtl osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#open chrome://global/skin/tree/twisty-Vista78.svg#open osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#open-rtl chrome://global/skin/tree/twisty-Vista78.svg#open-rtl osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#open-hover chrome://global/skin/tree/twisty-Vista78.svg#open-hover osversion<=6.3 +% override chrome://global/skin/tree/twisty.svg#open-hover-rtl chrome://global/skin/tree/twisty-Vista78.svg#open-hover-rtl osversion<=6.3 +# to be sure osversion<6 has always higher precedence than osversion<=6.3 we override twisty-Vista78.svg instead of twisty.svg +% override chrome://global/skin/tree/twisty-Vista78.svg#clsd chrome://global/skin/tree/twisty-XP.svg#clsd osversion<6 +% override chrome://global/skin/tree/twisty-Vista78.svg#open chrome://global/skin/tree/twisty-XP.svg#open osversion<6 diff --git a/toolkit/themes/windows/global/tree.css b/toolkit/themes/windows/global/tree.css index 0bed1d66192..56c15b86fcb 100644 --- a/toolkit/themes/windows/global/tree.css +++ b/toolkit/themes/windows/global/tree.css @@ -317,12 +317,11 @@ treechildren::-moz-tree-twisty { -moz-padding-end: 4px; padding-top: 1px; width: 9px; /* The image's width is 9 pixels */ - list-style-image: url("chrome://global/skin/tree/twisty-clsd.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd"); } treechildren::-moz-tree-twisty(open) { - width: 9px; /* The image's width is 9 pixels */ - list-style-image: url("chrome://global/skin/tree/twisty-open.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#open"); } treechildren::-moz-tree-indentation { @@ -373,31 +372,30 @@ treechildren::-moz-tree-cell-text(selected, editing) { treechildren::-moz-tree-twisty { -moz-padding-end: 1px; - width: 9px; } treechildren::-moz-tree-twisty(hover) { - list-style-image: url("chrome://global/skin/tree/twisty-clsd-hover.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover"); } treechildren::-moz-tree-twisty(hover, open) { - list-style-image: url("chrome://global/skin/tree/twisty-open-hover.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#open-hover"); } treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty { - list-style-image: url("chrome://global/skin/tree/twisty-clsd-rtl.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-rtl"); } treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(open) { - list-style-image: url("chrome://global/skin/tree/twisty-open-rtl.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#open-rtl"); } treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(hover) { - list-style-image: url("chrome://global/skin/tree/twisty-clsd-hover-rtl.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover-rtl"); } treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(hover, open) { - list-style-image: url("chrome://global/skin/tree/twisty-open-hover-rtl.png"); + list-style-image: url("chrome://global/skin/tree/twisty.svg#open-hover-rtl"); } @media (-moz-windows-default-theme) { diff --git a/toolkit/themes/windows/global/tree/twisty-Vista78.svg b/toolkit/themes/windows/global/tree/twisty-Vista78.svg new file mode 100644 index 00000000000..0a690863467 --- /dev/null +++ b/toolkit/themes/windows/global/tree/twisty-Vista78.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/themes/windows/global/tree/twisty-XP.svg b/toolkit/themes/windows/global/tree/twisty-XP.svg new file mode 100644 index 00000000000..66219d513e9 --- /dev/null +++ b/toolkit/themes/windows/global/tree/twisty-XP.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/themes/windows/global/tree/twisty-clsd-XP.png b/toolkit/themes/windows/global/tree/twisty-clsd-XP.png deleted file mode 100644 index 7fe7fb542f4..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-clsd-XP.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-clsd-hover-rtl.png b/toolkit/themes/windows/global/tree/twisty-clsd-hover-rtl.png deleted file mode 100644 index 1b651975884..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-clsd-hover-rtl.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-clsd-hover.png b/toolkit/themes/windows/global/tree/twisty-clsd-hover.png deleted file mode 100644 index 763c1da1c18..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-clsd-hover.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-clsd-rtl.png b/toolkit/themes/windows/global/tree/twisty-clsd-rtl.png deleted file mode 100644 index 02f4e32c375..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-clsd-rtl.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-open-XP.png b/toolkit/themes/windows/global/tree/twisty-open-XP.png deleted file mode 100644 index df66d771c34..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-open-XP.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-open-hover-rtl.png b/toolkit/themes/windows/global/tree/twisty-open-hover-rtl.png deleted file mode 100644 index a0157cc3a92..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-open-hover-rtl.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-open-hover.png b/toolkit/themes/windows/global/tree/twisty-open-hover.png deleted file mode 100644 index 31c9478a4da..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-open-hover.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty-open-rtl.png b/toolkit/themes/windows/global/tree/twisty-open-rtl.png deleted file mode 100644 index 4e606d22ed9..00000000000 Binary files a/toolkit/themes/windows/global/tree/twisty-open-rtl.png and /dev/null differ diff --git a/toolkit/themes/windows/global/tree/twisty.svg b/toolkit/themes/windows/global/tree/twisty.svg new file mode 100644 index 00000000000..4eeb029ee3d --- /dev/null +++ b/toolkit/themes/windows/global/tree/twisty.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/toolkit/xre/MacLaunchHelper.mm b/toolkit/xre/MacLaunchHelper.mm index 8d922c728bc..8191e870aff 100644 --- a/toolkit/xre/MacLaunchHelper.mm +++ b/toolkit/xre/MacLaunchHelper.mm @@ -6,8 +6,8 @@ #include "MacLaunchHelper.h" #include "nsMemory.h" -#include "nsAutoPtr.h" #include "nsIAppStartup.h" +#include "mozilla/UniquePtr.h" #include #include @@ -40,7 +40,7 @@ void LaunchChildMac(int aArgc, char** aArgv, { // "posix_spawnp" uses null termination for arguments rather than a count. // Note that we are not duplicating the argument strings themselves. - nsAutoArrayPtr argv_copy(new char*[aArgc + 1]); + auto argv_copy = MakeUnique(aArgc + 1); for (int i = 0; i < aArgc; i++) { argv_copy[i] = aArgv[i]; } @@ -80,7 +80,7 @@ void LaunchChildMac(int aArgc, char** aArgv, envp = *cocoaEnvironment; } - int result = posix_spawnp(pid, argv_copy[0], NULL, &spawnattr, argv_copy, envp); + int result = posix_spawnp(pid, argv_copy[0], NULL, &spawnattr, argv_copy.get(), envp); posix_spawnattr_destroy(&spawnattr); diff --git a/tools/mercurial/eslintvalidate.py b/tools/mercurial/eslintvalidate.py new file mode 100644 index 00000000000..e792741e93f --- /dev/null +++ b/tools/mercurial/eslintvalidate.py @@ -0,0 +1,45 @@ +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import os +import sys +import re +import json +from subprocess import check_output, CalledProcessError + +lintable = re.compile(r'.+\.(?:js|jsm|jsx|xml)$') +ignored = "File ignored because of your .eslintignore file. Use --no-ignore to override." + +def is_lintable(filename): + return lintable.match(filename) + +def display(ui, output): + results = json.loads(output) + for file in results: + path = os.path.relpath(file["filePath"]) + for message in file["messages"]: + if message["message"] == ignored: + continue + + ui.warn("%s:%d:%d %s\n" % (path, message["line"], message["column"], message["message"])) + +def eslinthook(ui, repo, node=None, **opts): + ctx = repo[node] + if len(ctx.parents()) > 1: + return 0 + + deleted = repo.status(ctx.p1().node(), ctx.node()).deleted + files = [f for f in ctx.files() if f not in deleted and is_lintable(f)] + + if len(files) == 0: + return + + try: + output = check_output(["eslint", "--format", "json"] + files) + display(ui, output) + except CalledProcessError as ex: + display(ui, ex.output) + ui.warn("ESLint found problems in your changes, please correct them.\n") + +def reposetup(ui, repo): + ui.setconfig('hooks', 'commit.eslint', eslinthook) diff --git a/xpcom/ds/nsPersistentProperties.cpp b/xpcom/ds/nsPersistentProperties.cpp index f783e21d82e..317e94e39f3 100644 --- a/xpcom/ds/nsPersistentProperties.cpp +++ b/xpcom/ds/nsPersistentProperties.cpp @@ -528,7 +528,7 @@ nsPersistentProperties::SetStringProperty(const nsACString& aKey, if (entry->mKey) { aOldValue = entry->mValue; - NS_WARNING(nsPrintfCString("the property %s already exists\n", + NS_WARNING(nsPrintfCString("the property %s already exists", flatKey.get()).get()); } else { aOldValue.Truncate(); diff --git a/xpcom/io/nsStreamUtils.cpp b/xpcom/io/nsStreamUtils.cpp index 9fdcfcd3ddc..a95dad33e11 100644 --- a/xpcom/io/nsStreamUtils.cpp +++ b/xpcom/io/nsStreamUtils.cpp @@ -12,7 +12,7 @@ #include "nsIPipe.h" #include "nsICloneableInputStream.h" #include "nsIEventTarget.h" -#include "nsIRunnable.h" +#include "nsICancelableRunnable.h" #include "nsISafeOutputStream.h" #include "nsString.h" #include "nsIAsyncInputStream.h" @@ -25,8 +25,11 @@ using namespace mozilla; //----------------------------------------------------------------------------- +// This is a nsICancelableRunnable because we can dispatch it to Workers and +// those can be shut down at any time, and in these cases, Cancel() is called +// instead of Run(). class nsInputStreamReadyEvent final - : public nsIRunnable + : public nsICancelableRunnable , public nsIInputStreamCallback { public: @@ -95,19 +98,28 @@ public: return NS_OK; } + NS_IMETHOD Cancel() override + { + mCallback = nullptr; + return NS_OK; + } + private: nsCOMPtr mStream; nsCOMPtr mCallback; nsCOMPtr mTarget; }; -NS_IMPL_ISUPPORTS(nsInputStreamReadyEvent, nsIRunnable, - nsIInputStreamCallback) +NS_IMPL_ISUPPORTS(nsInputStreamReadyEvent, nsICancelableRunnable, + nsIRunnable, nsIInputStreamCallback) //----------------------------------------------------------------------------- +// This is a nsICancelableRunnable because we can dispatch it to Workers and +// those can be shut down at any time, and in these cases, Cancel() is called +// instead of Run(). class nsOutputStreamReadyEvent final - : public nsIRunnable + : public nsICancelableRunnable , public nsIOutputStreamCallback { public: @@ -176,14 +188,20 @@ public: return NS_OK; } + NS_IMETHOD Cancel() override + { + mCallback = nullptr; + return NS_OK; + } + private: nsCOMPtr mStream; nsCOMPtr mCallback; nsCOMPtr mTarget; }; -NS_IMPL_ISUPPORTS(nsOutputStreamReadyEvent, nsIRunnable, - nsIOutputStreamCallback) +NS_IMPL_ISUPPORTS(nsOutputStreamReadyEvent, nsICancelableRunnable, + nsIRunnable, nsIOutputStreamCallback) //----------------------------------------------------------------------------- @@ -216,7 +234,7 @@ NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback* aCallback, class nsAStreamCopier : public nsIInputStreamCallback , public nsIOutputStreamCallback - , public nsIRunnable + , public nsICancelableRunnable { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -433,6 +451,8 @@ public: return NS_OK; } + NS_IMETHOD Cancel() MOZ_MUST_OVERRIDE override = 0; + nsresult PostContinuationEvent() { // we cannot post a continuation event if there is currently @@ -489,6 +509,7 @@ protected: NS_IMPL_ISUPPORTS(nsAStreamCopier, nsIInputStreamCallback, nsIOutputStreamCallback, + nsICancelableRunnable, nsIRunnable) class nsStreamCopierIB final : public nsAStreamCopier @@ -527,7 +548,8 @@ public: return state->mSinkCondition; } - uint32_t DoCopy(nsresult* aSourceCondition, nsresult* aSinkCondition) + uint32_t DoCopy(nsresult* aSourceCondition, + nsresult* aSinkCondition) override { ReadSegmentsState state; state.mSink = mSink; @@ -539,6 +561,11 @@ public: *aSinkCondition = state.mSinkCondition; return n; } + + NS_IMETHOD Cancel() override + { + return NS_OK; + } }; class nsStreamCopierOB final : public nsAStreamCopier @@ -577,7 +604,8 @@ public: return state->mSourceCondition; } - uint32_t DoCopy(nsresult* aSourceCondition, nsresult* aSinkCondition) + uint32_t DoCopy(nsresult* aSourceCondition, + nsresult* aSinkCondition) override { WriteSegmentsState state; state.mSource = mSource; @@ -589,6 +617,11 @@ public: *aSourceCondition = state.mSourceCondition; return n; } + + NS_IMETHOD Cancel() override + { + return NS_OK; + } }; //----------------------------------------------------------------------------- diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index 9eeda7a93c7..7e032607e7c 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -127,10 +127,23 @@ public: } // namespace -class nsTimerEvent : public nsRunnable +// This is a nsICancelableRunnable because we can dispatch it to Workers and +// those can be shut down at any time, and in these cases, Cancel() is called +// instead of Run(). +class nsTimerEvent : public nsCancelableRunnable { public: - NS_IMETHOD Run(); + NS_IMETHOD Run() override; + + NS_IMETHOD Cancel() override + { + // Since nsTimerImpl is not thread-safe, we should release |mTimer| + // here in the target thread to avoid race condition. Otherwise, + // ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the + // timer thread and result in race condition. + mTimer = nullptr; + return NS_OK; + } nsTimerEvent() : mTimer() @@ -253,6 +266,8 @@ nsTimerEvent::DeleteAllocatorIfNeeded() NS_IMETHODIMP nsTimerEvent::Run() { + MOZ_ASSERT(mTimer); + if (mGeneration != mTimer->GetGeneration()) { return NS_OK; } @@ -265,13 +280,10 @@ nsTimerEvent::Run() } mTimer->Fire(); - // Since nsTimerImpl is not thread-safe, we should release |mTimer| - // here in the target thread to avoid race condition. Otherwise, - // ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the - // timer thread and result in race condition. - mTimer = nullptr; - return NS_OK; + // We call Cancel() to correctly release mTimer. + // Read more in the Cancel() implementation. + return Cancel(); } nsresult diff --git a/xpcom/threads/nsICancelableRunnable.idl b/xpcom/threads/nsICancelableRunnable.idl index 44b9df477c0..11f09650c18 100644 --- a/xpcom/threads/nsICancelableRunnable.idl +++ b/xpcom/threads/nsICancelableRunnable.idl @@ -16,6 +16,7 @@ interface nsICancelableRunnable : nsIRunnable /** * Cancels a pending task. If the task has already been executed this will * be a no-op. Calling this method twice is considered an error. + * If cancel() is called, run() will not be called. * * @throws NS_ERROR_UNEXPECTED * Indicates that the runnable has already been canceled.