Merge m-c to fx-team. a=merge
Merge m-c to fx-team. a=merge
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -160,17 +160,17 @@ nsCoreUtils::DispatchTouchEvent(EventMes
WidgetTouchEvent event(true, aMessage, aRootWidget);
event.mTime = PR_IntervalNow();
// XXX: Touch has an identifier of -1 to hint that it is synthesized.
RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
t->SetTarget(aContent);
- event.touches.AppendElement(t);
+ event.mTouches.AppendElement(t);
nsEventStatus status = nsEventStatus_eIgnore;
aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
}
uint32_t
nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
{
// Accesskeys are registered by @accesskey attribute only. At first check
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -833,17 +833,17 @@ var SessionStoreInternal = {
// monitor the progress of network loads.
if (gDebuggingEnabled) {
Services.obs.notifyObservers(browser, NOTIFY_TAB_RESTORED, null);
}
SessionStoreInternal._resetLocalTabRestoringState(tab);
SessionStoreInternal.restoreNextTab();
- this._sendTabRestoredNotification(tab);
+ this._sendTabRestoredNotification(tab, data.isRemotenessUpdate);
break;
case "SessionStore:crashedTabRevived":
// The browser was revived by navigating to a different page
// manually, so we remove it from the ignored browser set.
this._crashedBrowsers.delete(browser.permanentKey);
break;
case "SessionStore:error":
this.reportInternalError(data);
@@ -3281,16 +3281,19 @@ var SessionStoreInternal = {
/**
* Kicks off restoring the given tab.
*
* @param aTab
* the tab to restore
* @param aLoadArguments
* optional load arguments used for loadURI()
+ * @param aRemotenessSwitch
+ * true if we're restoring a tab's content because we flipped
+ * its remoteness (out-of-process) state.
*/
restoreTabContent: function (aTab, aLoadArguments = null) {
if (aTab.hasAttribute("customizemode")) {
return;
}
let browser = aTab.linkedBrowser;
let window = aTab.ownerDocument.defaultView;
@@ -3304,17 +3307,18 @@ var SessionStoreInternal = {
}
// We have to mark this tab as restoring first, otherwise
// the "pending" attribute will be applied to the linked
// browser, which removes it from the display list. We cannot
// flip the remoteness of any browser that is not being displayed.
this.markTabAsRestoring(aTab);
- if (tabbrowser.updateBrowserRemotenessByURL(browser, uri)) {
+ let isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL(browser, uri);
+ if (isRemotenessUpdate) {
// We updated the remoteness, so we need to send the history down again.
//
// Start a new epoch to discard all frame script messages relating to a
// previous epoch. All async messages that are still on their way to chrome
// will be ignored and don't override any tab data set when restoring.
let epoch = this.startNextEpoch(browser);
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory", {
@@ -3327,17 +3331,17 @@ var SessionStoreInternal = {
// If the restored browser wants to show view source content, start up a
// view source browser that will load the required frame script.
if (uri && ViewSourceBrowser.isViewSource(uri)) {
new ViewSourceBrowser(browser);
}
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
- {loadArguments: aLoadArguments});
+ {loadArguments: aLoadArguments, isRemotenessUpdate});
},
/**
* Marks a given pending tab as restoring.
*
* @param aTab
* the pending tab to mark as restoring
*/
@@ -3972,21 +3976,27 @@ var SessionStoreInternal = {
_sendWindowStateEvent: function ssi_sendWindowStateEvent(aWindow, aType) {
let event = aWindow.document.createEvent("Events");
event.initEvent("SSWindowState" + aType, true, false);
aWindow.dispatchEvent(event);
},
/**
* Dispatch the SSTabRestored event for the given tab.
- * @param aTab the which has been restored
+ * @param aTab
+ * The tab which has been restored
+ * @param aIsRemotenessUpdate
+ * True if this tab was restored due to flip from running from
+ * out-of-main-process to in-main-process or vice-versa.
*/
- _sendTabRestoredNotification: function ssi_sendTabRestoredNotification(aTab) {
- let event = aTab.ownerDocument.createEvent("Events");
- event.initEvent("SSTabRestored", true, false);
+ _sendTabRestoredNotification(aTab, aIsRemotenessUpdate) {
+ let event = aTab.ownerDocument.createEvent("CustomEvent");
+ event.initCustomEvent("SSTabRestored", true, false, {
+ isRemotenessUpdate: aIsRemotenessUpdate,
+ });
aTab.dispatchEvent(event);
},
/**
* @param aWindow
* Window reference
* @returns whether this window's data is still cached in _statesToRestore
* because it's not fully loaded yet
--- a/browser/components/sessionstore/StartupPerformance.jsm
+++ b/browser/components/sessionstore/StartupPerformance.jsm
@@ -194,19 +194,26 @@ this.StartupPerformance = {
this._totalNumberOfWindows += 1;
// Observe the restoration of all tabs. We assume that all tabs of this
// window will have been restored before `COLLECT_RESULTS_AFTER_MS`.
// The last call to `observer` will let us determine how long it took
// to reach that point.
let win = subject;
- let observer = () => {
- this._latestRestoredTimeStamp = Date.now();
- this._totalNumberOfEagerTabs += 1;
+ let observer = (event) => {
+ // We don't care about tab restorations that are due to
+ // a browser flipping from out-of-main-process to in-main-process
+ // or vice-versa. We only care about restorations that are due
+ // to the user switching to a lazily restored tab, or for tabs
+ // that are restoring eagerly.
+ if (!event.detail.isRemotenessUpdate) {
+ this._latestRestoredTimeStamp = Date.now();
+ this._totalNumberOfEagerTabs += 1;
+ }
};
win.gBrowser.tabContainer.addEventListener("SSTabRestored", observer);
this._totalNumberOfTabs += win.gBrowser.tabContainer.itemCount;
// Once we have finished collecting the results, clean up the observers.
this._promiseFinished.then(() => {
if (!win.gBrowser.tabContainer) {
// May be undefined during shutdown and/or some tests.
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -162,31 +162,31 @@ var MessageListener = {
// SessionStore.jsm so that it can run SSTabRestoring. Users of
// SSTabRestoring seem to get confused if chrome and content are out of
// sync about the state of the restore (particularly regarding
// docShell.currentURI). Using a synchronous message is the easiest way
// to temporarily synchronize them.
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch});
},
- restoreTabContent({loadArguments}) {
+ restoreTabContent({loadArguments, isRemotenessUpdate}) {
let epoch = gCurrentEpoch;
// We need to pass the value of didStartLoad back to SessionStore.jsm.
let didStartLoad = gContentRestore.restoreTabContent(loadArguments, () => {
// Tell SessionStore.jsm that it may want to restore some more tabs,
// since it restores a max of MAX_CONCURRENT_TAB_RESTORES at a time.
- sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch});
+ sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch, isRemotenessUpdate});
});
sendAsyncMessage("SessionStore:restoreTabContentStarted", {epoch});
if (!didStartLoad) {
// Pretend that the load succeeded so that event handlers fire correctly.
- sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch});
+ sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch, isRemotenessUpdate});
}
},
flush({id}) {
// Flush the message queue, send the latest updates.
MessageQueue.send({flushID: id});
}
};
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -299,17 +299,22 @@ nsScriptSecurityManager::AppStatusForPri
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsCOMPtr<nsIURI> appURI;
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
// The app could contain a cross-origin iframe - make sure that the content
// is actually same-origin with the app.
MOZ_ASSERT(inIsolatedMozBrowser == false, "Checked this above");
- PrincipalOriginAttributes attrs(appId, false);
+ nsAutoCString suffix;
+ PrincipalOriginAttributes attrs;
+ NS_ENSURE_TRUE(attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(appOrigin), suffix),
+ nsIPrincipal::APP_STATUS_NOT_INSTALLED);
+ attrs.mAppId = appId;
+ attrs.mInIsolatedMozBrowser = false;
nsCOMPtr<nsIPrincipal> appPrin = BasePrincipal::CreateCodebasePrincipal(appURI, attrs);
NS_ENSURE_TRUE(appPrin, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
return aPrin->Equals(appPrin) ? status
: nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
/*
* GetChannelResultPrincipal will return the principal that the resource
--- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
@@ -18,18 +18,19 @@
// ]
var testData = [
["d", {}, "display", 1, 3, false],
["VK_TAB", {}, "", -1, 10, true],
["VK_DOWN", {}, "-moz-box", 0, 10, true],
["n", {}, "none", -1, 0, true],
["VK_TAB", {shiftKey: true}, "display", -1, 0, true],
["VK_BACK_SPACE", {}, "", -1, 0, false],
- ["c", {}, "color", 5, 10, false],
- ["o", {}, "color", 0, 7, false],
+ ["o", {}, "opacity", 6, 10, false],
+ ["u", {}, "outline", 0, 5, false],
+ ["VK_DOWN", {}, "outline-color", 1, 5, false],
["VK_TAB", {}, "none", -1, 0, true],
["r", {}, "rebeccapurple", 0, 6, true],
["VK_DOWN", {}, "red", 1, 6, true],
["VK_DOWN", {}, "rgb", 2, 6, true],
["VK_DOWN", {}, "rgba", 3, 6, true],
["VK_DOWN", {}, "rosybrown", 4, 6, true],
["VK_DOWN", {}, "royalblue", 5, 6, true],
["VK_RIGHT", {}, "royalblue", -1, 0, false],
--- a/devtools/client/sourceeditor/test/css_autocompletion_tests.json
+++ b/devtools/client/sourceeditor/test/css_autocompletion_tests.json
@@ -13,18 +13,21 @@
[[5, 8], ['-moz-animation', '-moz-animation-delay', '-moz-animation-direction',
'-moz-animation-duration', '-moz-animation-fill-mode',
'-moz-animation-iteration-count', '-moz-animation-name',
'-moz-animation-play-state', '-moz-animation-timing-function',
'-moz-appearance']],
[[12, 20], ['none', 'number-input']],
[[12, 22], ['none']],
[[17, 22], ['hsl', 'hsla']],
+ [[19, 10], ['background', 'background-attachment', 'background-blend-mode',
+ 'background-clip', 'background-color', 'background-image',
+ 'background-origin', 'background-position', 'background-repeat',
+ 'background-size']],
[[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
- [[22, 5], ['color', 'color-interpolation', 'color-interpolation-filters']],
[[25, 26], ['.devtools-toolbarbutton > tab',
'.devtools-toolbarbutton > hbox',
'.devtools-toolbarbutton > .toolbarbutton-menubutton-button']],
[[25, 31], ['.devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button']],
[[29, 20], ['.devtools-menulist:after', '.devtools-menulist:active']],
[[30, 10], ['#devtools-anotherone', '#devtools-itjustgoeson', '#devtools-menu',
'#devtools-okstopitnow', '#devtools-toolbarbutton', '#devtools-yetagain']],
[[39, 39], ['.devtools-toolbarbutton:not([label]) > tab']],
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -188,16 +188,18 @@ skip-if = e10s && debug && (os == 'win'
[browser_longstring_hang.js]
[browser_output_breaks_after_console_dir_uninspectable.js]
[browser_output_longstring_expand.js]
[browser_repeated_messages_accuracy.js]
[browser_result_format_as_string.js]
[browser_warn_user_about_replaced_api.js]
[browser_webconsole_allow_mixedcontent_securityerrors.js]
tags = mcb
+[browser_webconsole_script_errordoc_urls.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_webconsole_assert.js]
[browser_webconsole_block_mixedcontent_securityerrors.js]
tags = mcb
[browser_webconsole_bug_579412_input_focus.js]
[browser_webconsole_bug_580001_closing_after_completion.js]
[browser_webconsole_bug_580030_errors_after_page_reload.js]
[browser_webconsole_bug_580454_timestamp_l10n.js]
[browser_webconsole_bug_582201_duplicate_errors.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/browser_webconsole_script_errordoc_urls.js
@@ -0,0 +1,67 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Ensure that [Learn More] links appear alongside any errors listed
+// in "errordocs.js". Note: this only tests script execution.
+
+"use strict";
+
+const ErrorDocs = require("devtools/server/actors/errordocs");
+
+function makeURIData(script) {
+ return `data:text/html;charset=utf8,<script>${script}</script>`
+}
+
+const TestData = [
+ {
+ jsmsg: "JSMSG_READ_ONLY",
+ script: "'use strict'; (Object.freeze({name: 'Elsa', score: 157})).score = 0;",
+ isException: true,
+ },
+ {
+ jsmsg: "JSMSG_STMT_AFTER_RETURN",
+ script: "function a() { return; 1 + 1; };",
+ isException: false,
+ }
+]
+
+add_task(function* () {
+ yield loadTab("data:text/html;charset=utf8,errordoc tests");
+
+ let hud = yield openConsole();
+
+ for (let i = 0; i < TestData.length; i++) {
+ yield testScriptError(hud, TestData[i]);
+ }
+});
+
+function* testScriptError(hud, testData) {
+ if (testData.isException === true) {
+ expectUncaughtException();
+ }
+
+ BrowserTestUtils.loadURI(gBrowser.selectedBrowser, makeURIData(testData.script));
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ category: CATEGORY_JS
+ }
+ ]
+ });
+
+ // grab the most current error doc URL
+ let url = ErrorDocs.GetURL(testData.jsmsg);
+
+ let hrefs = {};
+ for (let link of hud.jsterm.outputNode.querySelectorAll("a")) {
+ hrefs[link.href] = true;
+ }
+
+ ok(url in hrefs, `Expected a link to ${url}.`);
+
+ hud.jsterm.clearOutput();
+}
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -11,16 +11,17 @@ const {Cc, Ci, Cu} = require("chrome");
const {Utils: WebConsoleUtils, CONSOLE_WORKER_IDS} =
require("devtools/shared/webconsole/utils");
const { getSourceNames } = require("devtools/client/shared/source-utils");
const BrowserLoaderModule = {};
Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
const promise = require("promise");
const Services = require("Services");
+const ErrorDocs = require("devtools/server/actors/errordocs");
loader.lazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
loader.lazyRequireGetter(this, "AutocompletePopup", "devtools/client/shared/autocomplete-popup", true);
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/framework/sidebar", true);
loader.lazyRequireGetter(this, "ConsoleOutput", "devtools/client/webconsole/console-output", true);
@@ -1484,16 +1485,17 @@ WebConsoleFrame.prototype = {
private: scriptError.private,
filterDuplicates: true
});
let node = msg.init(this.output).render().element;
// 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, scriptError);
if (objectActors.size > 0) {
node._objectActors = objectActors;
}
return node;
@@ -1692,21 +1694,24 @@ WebConsoleFrame.prototype = {
break;
case "SHA-1 Signature":
url = WEAK_SIGNATURE_ALGORITHM_LEARN_MORE;
break;
case "Tracking Protection":
url = TRACKING_PROTECTION_LEARN_MORE;
break;
default:
- // Unknown category. Return without adding more info node.
- return;
+ // If all else fails check for an error doc URL.
+ url = ErrorDocs.GetURL(scriptError.errorMessageName);
+ break;
}
- this.addLearnMoreWarningNode(node, url);
+ if (url) {
+ this.addLearnMoreWarningNode(node, url);
+ }
},
/*
* Appends a clickable warning node to the node passed
* as a parameter to the function. When a user clicks on the appended
* warning node, the browser navigates to the provided url.
*
* @param node
new file mode 100644
--- /dev/null
+++ b/devtools/server/actors/errordocs.js
@@ -0,0 +1,23 @@
+/* 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/. */
+
+/**
+ * A mapping of error message names to external documentation. Any error message
+ * included here will be displayed alongside its link in the web console.
+ */
+
+"use strict";
+
+const ErrorDocs = {
+ JSMSG_READ_ONLY: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Read-only",
+ JSMSG_BAD_ARRAY_LENGTH: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length",
+ JSMSG_NEGATIVE_REPETITION_COUNT: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Negative_repetition_count",
+ JSMSG_RESULTING_STRING_TOO_LARGE: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Resulting_string_too_large",
+ JSMSG_BAD_RADIX: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Bad_radix",
+ JSMSG_PRECISION_RANGE: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Precision_range",
+ JSMSG_BAD_FORMAL: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Malformed_formal_parameter",
+ JSMSG_STMT_AFTER_RETURN: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Stmt_after_return",
+}
+
+exports.GetURL = (errorName) => ErrorDocs[errorName];
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -20,16 +20,17 @@ DevToolsModules(
'childtab.js',
'chrome.js',
'common.js',
'csscoverage.js',
'device.js',
'director-manager.js',
'director-registry.js',
'environment.js',
+ 'errordocs.js',
'eventlooplag.js',
'frame.js',
'framerate.js',
'gcli.js',
'heap-snapshot-file.js',
'highlighters.css',
'highlighters.js',
'inspector.js',
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -1387,16 +1387,17 @@ WebConsoleActor.prototype =
}
let lineText = aPageError.sourceLine;
if (lineText && lineText.length > DebuggerServer.LONG_STRING_INITIAL_LENGTH) {
lineText = lineText.substr(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
}
return {
errorMessage: this._createStringGrip(aPageError.errorMessage),
+ errorMessageName: aPageError.errorMessageName,
sourceName: aPageError.sourceName,
lineText: lineText,
lineNumber: aPageError.lineNumber,
columnNumber: aPageError.columnNumber,
category: aPageError.category,
timeStamp: aPageError.timeStamp,
warning: !!(aPageError.flags & aPageError.warningFlag),
error: !!(aPageError.flags & aPageError.errorFlag),
--- a/devtools/shared/webconsole/test/test_page_errors.html
+++ b/devtools/shared/webconsole/test/test_page_errors.html
@@ -13,50 +13,134 @@
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let expectedPageErrors = [];
function doPageErrors()
{
- expectedPageErrors = [
- {
+ expectedPageErrors = {
+ "document.body.style.color = 'fooColor';": {
errorMessage: /fooColor/,
+ errorMessageName: undefined,
sourceName: /test_page_errors/,
category: "CSS Parser",
timeStamp: /^\d+$/,
error: false,
warning: true,
exception: false,
strict: false,
},
- {
+ "document.doTheImpossible();": {
errorMessage: /doTheImpossible/,
+ errorMessageName: undefined,
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ strict: false,
+ },
+ "(42).toString(0);": {
+ errorMessage: /radix/,
+ errorMessageName: "JSMSG_BAD_RADIX",
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
strict: false,
},
- ];
+ "'use strict'; (Object.freeze({name: 'Elsa', score: 157})).score = 0;": {
+ errorMessage: /read.only/,
+ errorMessageName: "JSMSG_READ_ONLY",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "([]).length = -1": {
+ errorMessage: /array length/,
+ errorMessageName: "JSMSG_BAD_ARRAY_LENGTH",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "'abc'.repeat(-1);": {
+ errorMessage: /repeat count.*non-negative/,
+ errorMessageName: "JSMSG_NEGATIVE_REPETITION_COUNT",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "'a'.repeat(2**28);": {
+ errorMessage: /repeat count.*less than infinity/,
+ errorMessageName: "JSMSG_RESULTING_STRING_TOO_LARGE",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "77.1234.toExponential(-1);": {
+ errorMessage: /out of range/,
+ errorMessageName: "JSMSG_PRECISION_RANGE",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "var f = Function('x y', 'return x + y;');": {
+ errorMessage: /malformed formal/,
+ errorMessageName: "JSMSG_BAD_FORMAL",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: false,
+ exception: true,
+ },
+ "function a() { return; 1 + 1; }": {
+ errorMessage: /unreachable code/,
+ errorMessageName: "JSMSG_STMT_AFTER_RETURN",
+ sourceName: /test_page_errors/,
+ category: "chrome javascript",
+ timeStamp: /^\d+$/,
+ error: false,
+ warning: true,
+ exception: false,
+ },
+ };
let container = document.createElement("script");
- document.body.appendChild(container);
- container.textContent = "document.body.style.color = 'fooColor';";
- document.body.removeChild(container);
-
- SimpleTest.expectUncaughtException();
-
- container = document.createElement("script");
- document.body.appendChild(container);
- container.textContent = "document.doTheImpossible();";
- document.body.removeChild(container);
+ for (let stmt of Object.keys(expectedPageErrors)) {
+ if (expectedPageErrors[stmt].exception) {
+ SimpleTest.expectUncaughtException();
+ }
+ info("starting stmt: " + stmt);
+ container = document.createElement("script");
+ document.body.appendChild(container);
+ container.textContent = stmt;
+ document.body.removeChild(container);
+ info("ending stmt: " + stmt);
+ }
}
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["PageError"], onAttach);
}
@@ -75,25 +159,25 @@ function onPageError(aState, aType, aPac
if (!aPacket.pageError.sourceName.includes("test_page_errors")) {
info("Ignoring error from unknown source: " + aPacket.pageError.sourceName);
return;
}
is(aPacket.from, aState.actor, "page error actor");
pageErrors.push(aPacket.pageError);
- if (pageErrors.length != expectedPageErrors.length) {
+ if (pageErrors.length != Object.keys(expectedPageErrors).length) {
return;
}
aState.dbgClient.removeListener("pageError", onPageError);
- expectedPageErrors.forEach(function(aMessage, aIndex) {
+ Object.values(expectedPageErrors).forEach(function(aMessage, aIndex) {
info("checking received page error #" + aIndex);
- checkObject(pageErrors[aIndex], expectedPageErrors[aIndex]);
+ checkObject(pageErrors[aIndex], Object.values(expectedPageErrors)[aIndex]);
});
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
--- a/dom/base/nsContentIterator.cpp
+++ b/dom/base/nsContentIterator.cpp
@@ -769,17 +769,21 @@ nsContentIterator::NextNode(nsINode* aNo
}
// else next sibling is next
return GetNextSibling(node, aIndexes);
}
// post-order
nsINode* parent = node->GetParentNode();
- NS_WARN_IF(!parent);
+ if (NS_WARN_IF(!parent)) {
+ MOZ_ASSERT(parent, "The node is the root node but not the last node");
+ mIsDone = true;
+ return node;
+ }
nsIContent* sibling = nullptr;
int32_t indx = 0;
// get the cached index
NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
"ContentIterator stack underflow");
if (aIndexes && !aIndexes->IsEmpty()) {
// use the last entry on the Indexes array for the current index
@@ -834,17 +838,21 @@ nsContentIterator::NextNode(nsINode* aNo
nsINode*
nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
{
nsINode* node = aNode;
// if we are a Pre-order iterator, use pre-order
if (mPre) {
nsINode* parent = node->GetParentNode();
- NS_WARN_IF(!parent);
+ if (NS_WARN_IF(!parent)) {
+ MOZ_ASSERT(parent, "The node is the root node but not the first node");
+ mIsDone = true;
+ return aNode;
+ }
nsIContent* sibling = nullptr;
int32_t indx = 0;
// get the cached index
NS_ASSERTION(!aIndexes || !aIndexes->IsEmpty(),
"ContentIterator stack underflow");
if (aIndexes && !aIndexes->IsEmpty()) {
// use the last entry on the Indexes array for the current index
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -940,29 +940,29 @@ nsDOMWindowUtils::SendTouchEventCommon(c
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
event.widget = widget;
event.mTime = PR_Now();
nsPresContext* presContext = GetPresContext();
if (!presContext) {
return NS_ERROR_FAILURE;
}
- event.touches.SetCapacity(aCount);
+ event.mTouches.SetCapacity(aCount);
for (uint32_t i = 0; i < aCount; ++i) {
LayoutDeviceIntPoint pt =
nsContentUtils::ToWidgetPoint(CSSPoint(aXs[i], aYs[i]), offset, presContext);
LayoutDeviceIntPoint radius =
LayoutDeviceIntPoint::FromAppUnitsRounded(
CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
presContext->AppUnitsPerDevPixel());
RefPtr<Touch> t =
new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
- event.touches.AppendElement(t);
+ event.mTouches.AppendElement(t);
}
nsEventStatus status;
if (aToWindow) {
nsCOMPtr<nsIPresShell> presShell;
nsView* view = nsContentUtils::GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
if (!presShell || !view) {
return NS_ERROR_FAILURE;
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -1561,18 +1561,23 @@ nsXMLHttpRequest::Open(const nsACString&
if (mBaseURI) {
baseURI = mBaseURI;
}
else if (doc) {
baseURI = doc->GetBaseURI();
}
rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, baseURI);
- if (NS_FAILED(rv)) return rv;
-
+
+ if (NS_FAILED(rv)) {
+ if (rv == NS_ERROR_MALFORMED_URI) {
+ return NS_ERROR_DOM_SYNTAX_ERR;
+ }
+ return rv;
+ }
rv = CheckInnerWindowCorrectness();
NS_ENSURE_SUCCESS(rv, rv);
// XXXbz this is wrong: we should only be looking at whether
// user/password were passed, not at the values! See bug 759624.
if (user.WasPassed() && !user.Value().IsEmpty()) {
nsAutoCString userpass;
CopyUTF16toUTF8(user.Value(), userpass);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1309,17 +1309,17 @@ EventStateManager::HandleCrossProcessEve
// This is a touch event with possibly multiple touch points.
// Each touch point may have its own target. So iterate through
// all of them and collect the unique set of targets for event
// forwarding.
//
// This loop is similar to the one used in
// PresShell::DispatchTouchEvent().
const WidgetTouchEvent::TouchArray& touches =
- aEvent->AsTouchEvent()->touches;
+ aEvent->AsTouchEvent()->mTouches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
Touch* touch = touches[i];
// NB: the |mChanged| check is an optimization, subprocesses can
// compute this for themselves. If the touch hasn't changed, we
// may be able to avoid forwarding the event entirely (which is
// not free).
if (!touch || !touch->mChanged) {
continue;
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -64,18 +64,18 @@ TouchEvent::TouchEvent(EventTarget* aOwn
WidgetTouchEvent* aEvent)
: UIEvent(aOwner, aPresContext,
aEvent ? aEvent :
new WidgetTouchEvent(false, eVoidEvent, nullptr))
{
if (aEvent) {
mEventIsInternal = false;
- for (uint32_t i = 0; i < aEvent->touches.Length(); ++i) {
- Touch* touch = aEvent->touches[i];
+ for (uint32_t i = 0; i < aEvent->mTouches.Length(); ++i) {
+ Touch* touch = aEvent->mTouches[i];
touch->InitializePoints(mPresContext, aEvent);
}
} else {
mEventIsInternal = true;
mEvent->mTime = PR_Now();
}
}
@@ -113,39 +113,39 @@ TouchEvent::InitTouchEvent(const nsAStri
}
TouchList*
TouchEvent::Touches()
{
if (!mTouches) {
WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
if (mEvent->mMessage == eTouchEnd || mEvent->mMessage == eTouchCancel) {
- // for touchend events, remove any changed touches from the touches array
+ // for touchend events, remove any changed touches from mTouches
WidgetTouchEvent::AutoTouchArray unchangedTouches;
- const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
if (!touches[i]->mChanged) {
unchangedTouches.AppendElement(touches[i]);
}
}
mTouches = new TouchList(ToSupports(this), unchangedTouches);
} else {
- mTouches = new TouchList(ToSupports(this), touchEvent->touches);
+ mTouches = new TouchList(ToSupports(this), touchEvent->mTouches);
}
}
return mTouches;
}
TouchList*
TouchEvent::TargetTouches()
{
if (!mTargetTouches) {
WidgetTouchEvent::AutoTouchArray targetTouches;
WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
- const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
// for touchend/cancel events, don't append to the target list if this is a
// touch that is ending
if ((mEvent->mMessage != eTouchEnd && mEvent->mMessage != eTouchCancel) ||
!touches[i]->mChanged) {
if (touches[i]->mTarget == mEvent->originalTarget) {
targetTouches.AppendElement(touches[i]);
}
@@ -157,17 +157,17 @@ TouchEvent::TargetTouches()
}
TouchList*
TouchEvent::ChangedTouches()
{
if (!mChangedTouches) {
WidgetTouchEvent::AutoTouchArray changedTouches;
WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent();
- const WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
+ const WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
if (touches[i]->mChanged) {
changedTouches.AppendElement(touches[i]);
}
}
mChangedTouches = new TouchList(ToSupports(this), changedTouches);
}
return mChangedTouches;
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -146,17 +146,17 @@ support-files = bug1017086_inner.html
support-files = bug1017086_inner.html
[test_bug1079236.html]
[test_bug1145910.html]
[test_bug1150308.html]
[test_bug1248459.html]
[test_clickevent_on_input.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_continuous_wheel_events.html]
-skip-if = buildapp == 'b2g' || e10s # b2g(5535 passed, 108 failed - more tests running than desktop) b2g-debug(5535 passed, 108 failed - more tests running than desktop) b2g-desktop(5535 passed, 108 failed - more tests running than desktop)
+skip-if = buildapp == 'b2g' # b2g(5535 passed, 108 failed - more tests running than desktop) b2g-debug(5535 passed, 108 failed - more tests running than desktop) b2g-desktop(5535 passed, 108 failed - more tests running than desktop)
[test_dblclick_explicit_original_target.html]
[test_dom_keyboard_event.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_dom_mouse_event.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_dom_storage_event.html]
[test_dom_wheel_event.html]
skip-if = buildapp == 'b2g' # b2g(456 failed out of 19873, mousewheel test) b2g-debug(456 failed out of 19873, mousewheel test) b2g-desktop(456 failed out of 19873, mousewheel test)
--- a/dom/events/test/test_continuous_wheel_events.html
+++ b/dom/events/test/test_continuous_wheel_events.html
@@ -1,14 +1,15 @@
<!DOCTYPE HTML>
<html style="font-size: 32px;">
<head>
<title>Test for D3E WheelEvent</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="scrollable" style="font-family:monospace; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
<div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
@@ -34,80 +35,85 @@
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
</div>
</div>
<div id="content" style="display: none">
-
+
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests, window);
var gScrollableElement = document.getElementById("scrollable");
var gScrolledElement = document.getElementById("scrolled");
var gLineHeight = 0;
var gHorizontalLine = 0;
var gPageHeight = 0;
var gPageWidth = 0;
-function prepareScrollUnits()
+function sendWheelAndWait(aX, aY, aEvent)
+{
+ sendWheelAndPaint(gScrollableElement, aX, aY, aEvent, continueTest);
+}
+
+function* prepareScrollUnits()
{
var result = -1;
function handler(aEvent)
{
result = aEvent.detail;
aEvent.preventDefault();
}
window.addEventListener("MozMousePixelScroll", handler, true);
- synthesizeWheel(gScrollableElement, 10, 10,
- { deltaMode: WheelEvent.DOM_DELTA_LINE,
- deltaY: 1.0, lineOrPageDeltaY: 1 });
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
gLineHeight = result;
ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
result = -1;
- synthesizeWheel(gScrollableElement, 10, 10,
- { deltaMode: WheelEvent.DOM_DELTA_LINE,
- deltaX: 1.0, lineOrPageDeltaX: 1 });
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
gHorizontalLine = result;
ok(gHorizontalLine > 5 && gHorizontalLine < 16, "prepareScrollUnits: gHorizontalLine may be illegal value, got " + gHorizontalLine);
result = -1;
- synthesizeWheel(gScrollableElement, 10, 10,
- { deltaMode: WheelEvent.DOM_DELTA_PAGE,
- deltaY: 1.0, lineOrPageDeltaY: 1 });
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
gPageHeight = result;
// XXX Cannot we know the actual scroll port size?
ok(gPageHeight >= 150 && gPageHeight <= 200,
"prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
result = -1;
- synthesizeWheel(gScrollableElement, 10, 10,
- { deltaMode: WheelEvent.DOM_DELTA_PAGE,
- deltaX: 1.0, lineOrPageDeltaX: 1 });
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
gPageWidth = result;
ok(gPageWidth >= 150 && gPageWidth <= 200,
"prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
window.removeEventListener("MozMousePixelScroll", handler, true);
}
// Tests continuous trusted wheel events. Trusted wheel events should cause
// legacy mouse scroll events when its lineOrPageDelta value is not zero or
// accumulated delta values of pixel scroll events of pixel only device
// become over the line height.
-function testContinuousTrustedEvents()
+function* testContinuousTrustedEvents()
{
const kSynthesizedWheelEventTests = [
{ description: "Simple horizontal wheel event by pixels (16.0 - 1) #1",
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
@@ -2656,18 +2662,19 @@ function testContinuousTrustedEvents()
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
vertical: { expected: true, preventDefault: false, detail: gPageHeight } },
},
// Tests for accumulation delta when delta_multiplier_is customized.
{ description: "lineOrPageDelta should be recomputed by ESM (pixel) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 200);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 300);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", 300]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: gHorizontalLine / 4, deltaY: gLineHeight / 8, deltaZ: 0,
lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -2709,25 +2716,27 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: false, preventDefault: false, detail: 0 },
vertical: { expected: true, preventDefault: false, detail: 1 } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.floor((gHorizontalLine / 4 + 1) * 2) },
vertical: { expected: true, preventDefault: false, detail: Math.floor((gLineHeight / 8 + 1) * 3) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
},
{ description: "lineOrPageDelta should be recomputed by ESM (pixel, negative, shift) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_x", 200);
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_y", 300);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.with_shift.delta_multiplier_x", 200],
+ ["mousewheel.with_shift.delta_multiplier_y", 300]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: -gHorizontalLine / 4, deltaY: -gLineHeight / 8, deltaZ: 0,
lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -2769,25 +2778,27 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: false, preventDefault: false, detail: 0 },
vertical: { expected: true, preventDefault: false, detail: -1 } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.ceil(-(gHorizontalLine / 4 + 1) * 2) },
vertical: { expected: true, preventDefault: false, detail: Math.ceil(-(gLineHeight / 8 + 1) * 3) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100]]},
+ continueTest);
},
},
{ description: "lineOrPageDelta should be recomputed by ESM (line) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 200);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -2829,25 +2840,27 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: false, preventDefault: false, detail: 0 },
vertical: { expected: true, preventDefault: false, detail: 1 } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine * 0.6) },
vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
},
{ description: "lineOrPageDelta should be recomputed by ESM (line, negative) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 200);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", -100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", -100]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -2889,25 +2902,27 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: false, preventDefault: false, detail: 0 },
vertical: { expected: true, preventDefault: false, detail: 1 } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gHorizontalLine * -0.6) },
vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
},
{ description: "lineOrPageDelta should be recomputed by ESM (page) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 200);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 200]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -2949,25 +2964,27 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth * 0.4) },
vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight * 0.8) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
},
{ description: "lineOrPageDelta should be recomputed by ESM (page, negative) #1",
prepare: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 200);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 200]]},
+ continueTest);
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
isCustomizedByPrefs: false,
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
wheel: {
expected: true, preventDefault: false,
@@ -3009,18 +3026,19 @@ function testContinuousTrustedEvents()
},
DOMMouseScroll: {
horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
MozMousePixelScroll: {
horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gPageWidth * -0.4) },
vertical: { expected: true, preventDefault: false, detail: Math.ceil(gPageHeight * -0.8) } },
finished: function () {
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
},
},
];
var currentWheelEventTest;
var calledHandlers = { wheel: false,
DOMMouseScroll: { horizontal: false, vertical: false },
MozMousePixelScroll: { horizontal: false, vertical: false } };
@@ -3140,23 +3158,23 @@ function testContinuousTrustedEvents()
window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
for (var i = 0; i < kSynthesizedWheelEventTests.length; i++) {
gScrollableElement.scrollTop = gScrollableElement.scrollBottom = 1000;
currentWheelEventTest = kSynthesizedWheelEventTests[i];
if (currentWheelEventTest.prepare) {
- currentWheelEventTest.prepare();
+ yield currentWheelEventTest.prepare();
}
- synthesizeWheel(gScrollableElement, 10, 10, currentWheelEventTest.event);
+ yield sendWheelAndWait(10, 10, currentWheelEventTest.event);
if (currentWheelEventTest.finished) {
- currentWheelEventTest.finished();
+ yield currentWheelEventTest.finished();
}
var description = "testContinuousTrustedEvents, " +
currentWheelEventTest.description + ": ";
is(calledHandlers.wheel, currentWheelEventTest.wheel.expected,
description + "wheel event was fired or not fired");
is(calledHandlers.DOMMouseScroll.horizontal,
currentWheelEventTest.DOMMouseScroll.horizontal.expected,
@@ -3176,66 +3194,55 @@ function testContinuousTrustedEvents()
MozMousePixelScroll: { horizontal: false, vertical: false } };
}
window.removeEventListener("wheel", wheelEventHandler, true);
window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
}
+var gTestContinuation = null;
+
+function continueTest()
+{
+ if (!gTestContinuation) {
+ gTestContinuation = testBody();
+ }
+ var ret = gTestContinuation.next();
+ if (ret.done) {
+ SimpleTest.finish();
+ }
+}
+
+function* testBody()
+{
+ yield* prepareScrollUnits();
+ yield* testContinuousTrustedEvents();
+}
+
function runTests()
{
- SpecialPowers.setIntPref("mousewheel.transaction.timeout", 100000);
-
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_z", 100);
- SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_z", 100);
- SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_z", 100);
- SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_z", 100);
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_z", 100);
- SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_x", 100);
- SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_y", 100);
- SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_z", 100);
-
- prepareScrollUnits();
- testContinuousTrustedEvents();
-
- clearPrefs();
- SimpleTest.finish();
+ SpecialPowers.pushPrefEnv({"set": [
+ ["mousewheel.transaction.timeout", 100000],
+ ["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100],
+ ["mousewheel.default.delta_multiplier_z", 100],
+ ["mousewheel.with_alt.delta_multiplier_x", 100],
+ ["mousewheel.with_alt.delta_multiplier_y", 100],
+ ["mousewheel.with_alt.delta_multiplier_z", 100],
+ ["mousewheel.with_control.delta_multiplier_x", 100],
+ ["mousewheel.with_control.delta_multiplier_y", 100],
+ ["mousewheel.with_control.delta_multiplier_z", 100],
+ ["mousewheel.with_meta.delta_multiplier_x", 100],
+ ["mousewheel.with_meta.delta_multiplier_y", 100],
+ ["mousewheel.with_meta.delta_multiplier_z", 100],
+ ["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100],
+ ["mousewheel.with_shift.delta_multiplier_z", 100],
+ ["mousewheel.with_win.delta_multiplier_x", 100],
+ ["mousewheel.with_win.delta_multiplier_y", 100],
+ ["mousewheel.with_win.delta_multiplier_z", 100]
+ ]}, continueTest);
}
-
-function clearPrefs()
-{
- SpecialPowers.clearUserPref("mousewheel.transaction.timeout");
-
- SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_z");
- SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_z");
- SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_z");
- SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_z");
- SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_z");
- SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_x");
- SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_y");
- SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_z");
-}
-
</script>
</pre>
</body>
</html>
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4237,17 +4237,17 @@ HTMLInputElement::PostHandleEventForRang
if (aVisitor.mEvent->mMessage == eMouseDown) {
if (aVisitor.mEvent->AsMouseEvent()->buttons ==
WidgetMouseEvent::eLeftButtonFlag) {
StartRangeThumbDrag(inputEvent);
} else if (mIsDraggingRange) {
CancelRangeThumbDrag();
}
} else {
- if (aVisitor.mEvent->AsTouchEvent()->touches.Length() == 1) {
+ if (aVisitor.mEvent->AsTouchEvent()->mTouches.Length() == 1) {
StartRangeThumbDrag(inputEvent);
} else if (mIsDraggingRange) {
CancelRangeThumbDrag();
}
}
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
} break;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2487,16 +2487,20 @@ ContentChild::RecvAddPermission(const IP
nsPermissionManager* permissionManager =
static_cast<nsPermissionManager*>(permissionManagerIface.get());
MOZ_ASSERT(permissionManager,
"We have no permissionManager in the Content process !");
nsAutoCString originNoSuffix;
PrincipalOriginAttributes attrs;
attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
+ // we're doing this because we currently don't support isolating permissions
+ // by userContextId.
+ MOZ_ASSERT(attrs.mUserContextId == nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID,
+ "permission user context should be set to default!");
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
// child processes don't care about modification time.
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1653,35 +1653,35 @@ bool TabParent::SendRealTouchEvent(Widge
return false;
}
// PresShell::HandleEventInternal adds touches on touch end/cancel. This
// confuses remote content and the panning and zooming logic into thinking
// that the added touches are part of the touchend/cancel, when actually
// they're not.
if (event.mMessage == eTouchEnd || event.mMessage == eTouchCancel) {
- for (int i = event.touches.Length() - 1; i >= 0; i--) {
- if (!event.touches[i]->mChanged) {
- event.touches.RemoveElementAt(i);
+ for (int i = event.mTouches.Length() - 1; i >= 0; i--) {
+ if (!event.mTouches[i]->mChanged) {
+ event.mTouches.RemoveElementAt(i);
}
}
}
ScrollableLayerGuid guid;
uint64_t blockId;
nsEventStatus apzResponse;
ApzAwareEventRoutingToChild(&guid, &blockId, &apzResponse);
if (mIsDestroyed) {
return false;
}
LayoutDeviceIntPoint offset = GetChildProcessOffset();
- for (uint32_t i = 0; i < event.touches.Length(); i++) {
- event.touches[i]->mRefPoint += offset;
+ for (uint32_t i = 0; i < event.mTouches.Length(); i++) {
+ event.mTouches[i]->mRefPoint += offset;
}
return (event.mMessage == eTouchMove) ?
PBrowserParent::SendRealTouchMoveEvent(event, guid, blockId, apzResponse) :
PBrowserParent::SendRealTouchEvent(event, guid, blockId, apzResponse);
}
bool
@@ -2773,17 +2773,17 @@ TabParent::InjectTouchEvent(const nsAStr
}
nsIDocument* doc = content->OwnerDoc();
if (!doc || !doc->GetShell()) {
return NS_ERROR_FAILURE;
}
nsPresContext* presContext = doc->GetShell()->GetPresContext();
- event.touches.SetCapacity(aCount);
+ event.mTouches.SetCapacity(aCount);
for (uint32_t i = 0; i < aCount; ++i) {
LayoutDeviceIntPoint pt =
LayoutDeviceIntPoint::FromAppUnitsRounded(
CSSPoint::ToAppUnits(CSSPoint(aXs[i], aYs[i])),
presContext->AppUnitsPerDevPixel());
LayoutDeviceIntPoint radius =
LayoutDeviceIntPoint::FromAppUnitsRounded(
@@ -2792,17 +2792,17 @@ TabParent::InjectTouchEvent(const nsAStr
RefPtr<Touch> t =
new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
// Consider all injected touch events as changedTouches. For more details
// about the meaning of changedTouches for each event, see
// https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches
t->mChanged = true;
- event.touches.AppendElement(t);
+ event.mTouches.AppendElement(t);
}
SendRealTouchEvent(event);
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom)
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -615,17 +615,19 @@ AudioCallbackDriver::Init()
input = output;
input.channels = mInputChannels; // change to support optional stereo capture
cubeb_stream* stream = nullptr;
CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
// We have to translate the deviceID values to cubeb devid's since those can be
// freed whenever enumerate is called.
{
+#ifdef MOZ_WEBRTC
StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
+#endif
if ((!mGraphImpl->mInputWanted
#ifdef MOZ_WEBRTC
|| AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)
#endif
) &&
(mGraphImpl->mOutputDeviceID == -1 // pass nullptr for ID for default output
#ifdef MOZ_WEBRTC
// XXX we should figure out how we would use a deviceID for output without webrtc.
@@ -640,17 +642,19 @@ AudioCallbackDriver::Init()
"AudioCallbackDriver",
input_id,
mGraphImpl->mInputWanted ? &input : nullptr,
output_id,
mGraphImpl->mOutputWanted ? &output : nullptr, latency,
DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
mAudioStream.own(stream);
} else {
+#ifdef MOZ_WEBRTC
StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
+#endif
NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
// Fall back to a driver using a normal thread.
MonitorAutoLock lock(GraphImpl()->GetMonitor());
SetNextDriver(new SystemClockDriver(GraphImpl()));
NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
mGraphImpl->SetCurrentDriver(NextDriver());
NextDriver()->Start();
return;
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -346,18 +346,16 @@ nsSpeechTask::DispatchStart()
}
return DispatchStartInner();
}
nsresult
nsSpeechTask::DispatchStartInner()
{
- CreateAudioChannelAgent();
-
nsSynthVoiceRegistry::GetInstance()->SetIsSpeaking(true);
return DispatchStartImpl();
}
nsresult
nsSpeechTask::DispatchStartImpl()
{
return DispatchStartImpl(mChosenVoiceURI);
@@ -368,16 +366,18 @@ nsSpeechTask::DispatchStartImpl(const ns
{
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchStart"));
MOZ_ASSERT(mUtterance);
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING))) {
return NS_ERROR_NOT_AVAILABLE;
}
+ CreateAudioChannelAgent();
+
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
mUtterance->mChosenVoiceURI = aUri;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("start"), 0, 0,
EmptyString());
return NS_OK;
}
@@ -390,30 +390,30 @@ nsSpeechTask::DispatchEnd(float aElapsed
}
return DispatchEndInner(aElapsedTime, aCharIndex);
}
nsresult
nsSpeechTask::DispatchEndInner(float aElapsedTime, uint32_t aCharIndex)
{
- DestroyAudioChannelAgent();
-
if (!mPreCanceled) {
nsSynthVoiceRegistry::GetInstance()->SpeakNext();
}
return DispatchEndImpl(aElapsedTime, aCharIndex);
}
nsresult
nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
{
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchEnd\n"));
+ DestroyAudioChannelAgent();
+
MOZ_ASSERT(mUtterance);
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
return NS_ERROR_NOT_AVAILABLE;
}
// XXX: This should not be here, but it prevents a crash in MSG.
if (mStream) {
mStream->Destroy();
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -5020,26 +5020,26 @@ nsHTMLEditRules::CheckForEmptyBlock(nsIN
if (aAction == nsIEditor::eNext) {
// Adjust selection to be right after it.
res = aSelection->Collapse(blockParent, offset + 1);
NS_ENSURE_SUCCESS(res, res);
// Move to the start of the next node if it's a text.
nsCOMPtr<nsIContent> nextNode = mHTMLEditor->GetNextNode(blockParent,
offset + 1, true);
- if (mHTMLEditor->IsTextNode(nextNode)) {
+ if (nextNode && mHTMLEditor->IsTextNode(nextNode)) {
res = aSelection->Collapse(nextNode, 0);
NS_ENSURE_SUCCESS(res, res);
}
} else {
// Move to the end of the previous node if it's a text.
nsCOMPtr<nsIContent> priorNode = mHTMLEditor->GetPriorNode(blockParent,
offset,
true);
- if (mHTMLEditor->IsTextNode(priorNode)) {
+ if (priorNode && mHTMLEditor->IsTextNode(priorNode)) {
res = aSelection->Collapse(priorNode, priorNode->TextLength());
NS_ENSURE_SUCCESS(res, res);
} else {
res = aSelection->Collapse(blockParent, offset + 1);
NS_ENSURE_SUCCESS(res, res);
}
}
}
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -708,16 +708,17 @@ struct ParamTraits<mozilla::layers::Fram
WriteParam(aMsg, aParam.mHasScrollgrab);
WriteParam(aMsg, aParam.mUpdateScrollOffset);
WriteParam(aMsg, aParam.mDoSmoothScroll);
WriteParam(aMsg, aParam.mUseDisplayPortMargins);
WriteParam(aMsg, aParam.mAllowVerticalScrollWithWheel);
WriteParam(aMsg, aParam.mIsLayersIdRoot);
WriteParam(aMsg, aParam.mUsesContainerScrolling);
WriteParam(aMsg, aParam.mIsScrollInfoLayer);
+ WriteParam(aMsg, aParam.mForceDisableApz);
}
static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
{
nsCString str;
if (!ReadParam(aMsg, aIter, &str)) {
return false;
}
@@ -767,17 +768,18 @@ struct ParamTraits<mozilla::layers::Fram
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsRootContent) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetHasScrollgrab) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetUpdateScrollOffset) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetDoSmoothScroll) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetUseDisplayPortMargins) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetAllowVerticalScrollWithWheel) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsLayersIdRoot) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetUsesContainerScrolling) &&
- ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsScrollInfoLayer));
+ ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsScrollInfoLayer) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetForceDisableApz));
}
};
template <>
struct ParamTraits<mozilla::layers::ScrollSnapInfo>
{
typedef mozilla::layers::ScrollSnapInfo paramType;
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -69,16 +69,17 @@ public:
, mHasScrollgrab(false)
, mUpdateScrollOffset(false)
, mDoSmoothScroll(false)
, mUseDisplayPortMargins(false)
, mAllowVerticalScrollWithWheel(false)
, mIsLayersIdRoot(false)
, mUsesContainerScrolling(false)
, mIsScrollInfoLayer(false)
+ , mForceDisableApz(false)
{
}
// Default copy ctor and operator= are fine
bool operator==(const FrameMetrics& aOther) const
{
// Put mScrollId at the top since it's the most likely one to fail.
@@ -108,17 +109,18 @@ public:
mIsRootContent == aOther.mIsRootContent &&
mHasScrollgrab == aOther.mHasScrollgrab &&
mUpdateScrollOffset == aOther.mUpdateScrollOffset &&
mDoSmoothScroll == aOther.mDoSmoothScroll &&
mUseDisplayPortMargins == aOther.mUseDisplayPortMargins &&
mAllowVerticalScrollWithWheel == aOther.mAllowVerticalScrollWithWheel &&
mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
mUsesContainerScrolling == aOther.mUsesContainerScrolling &&
- mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
+ mIsScrollInfoLayer == aOther.mIsScrollInfoLayer &&
+ mForceDisableApz == aOther.mForceDisableApz;
}
bool operator!=(const FrameMetrics& aOther) const
{
return !operator==(aOther);
}
bool IsScrollable() const
@@ -549,16 +551,23 @@ public:
void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) {
mIsScrollInfoLayer = aIsScrollInfoLayer;
}
bool IsScrollInfoLayer() const {
return mIsScrollInfoLayer;
}
+ void SetForceDisableApz(bool aForceDisable) {
+ mForceDisableApz = aForceDisable;
+ }
+ bool IsApzForceDisabled() const {
+ return mForceDisableApz;
+ }
+
private:
// A unique ID assigned to each scrollable frame.
ViewID mScrollId;
// The ViewID of the scrollable frame to which overscroll should be handed off.
ViewID mScrollParentId;
// The pres-shell resolution that has been induced on the document containing
@@ -737,16 +746,20 @@ private:
// True if scrolling using containers, false otherwise. This can be removed
// when containerful scrolling is eliminated.
bool mUsesContainerScrolling:1;
// Whether or not this frame has a "scroll info layer" to capture events.
bool mIsScrollInfoLayer:1;
+ // Whether or not the compositor should actually do APZ-scrolling on this
+ // scrollframe.
+ bool mForceDisableApz:1;
+
// WARNING!!!!
//
// When adding new fields to FrameMetrics, the following places should be
// updated to include them (as needed):
// FrameMetrics::operator ==
// AsyncPanZoomController::NotifyLayersUpdated
// The ParamTraits specialization in GfxMessageUtils.h
//
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1147,20 +1147,21 @@ APZCTreeManager::ReceiveInputEvent(Widge
case eTouchEventClass: {
WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
MultiTouchInput touchInput(touchEvent);
nsEventStatus result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
// touchInput was modified in-place to possibly remove some
// touch points (if we are overscrolled), and the coordinates were
// modified using the APZ untransform. We need to copy these changes
// back into the WidgetInputEvent.
- touchEvent.touches.Clear();
- touchEvent.touches.SetCapacity(touchInput.mTouches.Length());
+ touchEvent.mTouches.Clear();
+ touchEvent.mTouches.SetCapacity(touchInput.mTouches.Length());
for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
- *touchEvent.touches.AppendElement() = touchInput.mTouches[i].ToNewDOMTouch();
+ *touchEvent.mTouches.AppendElement() =
+ touchInput.mTouches[i].ToNewDOMTouch();
}
touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
return result;
}
case eWheelEventClass: {
WidgetWheelEvent& wheelEvent = *aEvent.AsWheelEvent();
if (WillHandleWheelEvent(&wheelEvent)) {
return ProcessWheelEvent(wheelEvent, aOutTargetGuid, aOutInputBlockId);
@@ -1929,17 +1930,17 @@ APZCTreeManager::GetScreenToApzcTransfor
// result is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
result = ancestorUntransform;
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
// ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
ancestorUntransform = parent->GetAncestorTransform().Inverse();
// asyncUntransform is updated to PA.Inverse() when parent == P
- Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll().Inverse().ToUnknownMatrix();
+ Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::NORMAL).Inverse().ToUnknownMatrix();
// untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
// result is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
result = untransformSinceLastApzc * result;
// The above value for result when parent == P matches the required output
// as explained in the comment above this method. Note that any missing
@@ -1961,17 +1962,17 @@ APZCTreeManager::GetApzcToGeckoTransform
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
// explained in the comment above. This function is called with aApzc at L, and the loop
// below performs one iteration, where parent is at P. The comments explain what values are stored
// in the variables at these two levels. All the comments use standard matrix notation where the
// leftmost matrix in a multiplication is applied first.
// asyncUntransform is LA.Inverse()
- Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll().Inverse().ToUnknownMatrix();
+ Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::NORMAL).Inverse().ToUnknownMatrix();
// aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
// aTransformToGeckoOut is LA.Inverse() * LD * MC * NC * OC * PC * PD * QC * RC
result = result * parent->GetTransformToLastDispatchedPaint() * parent->GetAncestorTransform();
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -151,16 +151,24 @@ using mozilla::gfx::PointTyped;
* goes from y=0...1000 and the visible portion is y=250...750 then
* we're far from checkerboarding. If we get to y=490...990 though then we're
* only 10 pixels away from showing checkerboarding so we are probably in
* a state where we can't keep up with scrolling. The danger zone prefs specify
* how wide this margin is; in the above example a y-axis danger zone of 10
* pixels would make us drop to low-res at y=490...990.\n
* This value is in layer pixels.
*
+ * \li\b apz.disable_for_scroll_linked_effects
+ * Setting this pref to true will disable APZ scrolling on documents where
+ * scroll-linked effects are detected. A scroll linked effect is detected if
+ * positioning or transform properties are updated inside a scroll event
+ * dispatch; we assume that such an update is in response to the scroll event
+ * and is therefore a scroll-linked effect which will be laggy with APZ
+ * scrolling.
+ *
* \li\b apz.displayport_expiry_ms
* While a scrollable frame is scrolling async, we set a displayport on it
* to make sure it is layerized. However this takes up memory, so once the
* scrolling stops we want to remove the displayport. This pref controls how
* long after scrolling stops the displayport is removed. A value of 0 will
* disable the expiry behavior entirely.
* Units: milliseconds
*
@@ -3025,18 +3033,25 @@ bool AsyncPanZoomController::UpdateAnima
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
return true;
}
return false;
}
-AsyncTransformComponentMatrix AsyncPanZoomController::GetOverscrollTransform() const {
+AsyncTransformComponentMatrix
+AsyncPanZoomController::GetOverscrollTransform(AsyncMode aMode) const
+{
ReentrantMonitorAutoEnter lock(mMonitor);
+
+ if (aMode == RESPECT_FORCE_DISABLE && mFrameMetrics.IsApzForceDisabled()) {
+ return AsyncTransformComponentMatrix();
+ }
+
if (!IsOverscrolled()) {
return AsyncTransformComponentMatrix();
}
// The overscroll effect is a uniform stretch along the overscrolled axis,
// with the edge of the content where we have reached the end of the
// scrollable area pinned into place.
@@ -3119,28 +3134,38 @@ bool AsyncPanZoomController::AdvanceAnim
// One of the deferred tasks may have started a new animation. In this case,
// we want to ask the compositor to schedule a new composite.
requestAnimationFrame |= (mAnimation != nullptr);
return requestAnimationFrame;
}
-void AsyncPanZoomController::SampleContentTransformForFrame(AsyncTransform* aOutTransform,
- ParentLayerPoint& aScrollOffset)
+ParentLayerPoint
+AsyncPanZoomController::GetCurrentAsyncScrollOffset(AsyncMode aMode) const
{
ReentrantMonitorAutoEnter lock(mMonitor);
- aScrollOffset = mFrameMetrics.GetScrollOffset() * mFrameMetrics.GetZoom();
- *aOutTransform = GetCurrentAsyncTransform();
+ if (aMode == RESPECT_FORCE_DISABLE && mFrameMetrics.IsApzForceDisabled()) {
+ return mLastContentPaintMetrics.GetScrollOffset() * mLastContentPaintMetrics.GetZoom();
+ }
+
+ return (mFrameMetrics.GetScrollOffset() + mTestAsyncScrollOffset)
+ * mFrameMetrics.GetZoom() * mTestAsyncZoom.scale;
}
-AsyncTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
+AsyncTransform
+AsyncPanZoomController::GetCurrentAsyncTransform(AsyncMode aMode) const
+{
ReentrantMonitorAutoEnter lock(mMonitor);
+ if (aMode == RESPECT_FORCE_DISABLE && mFrameMetrics.IsApzForceDisabled()) {
+ return AsyncTransform();
+ }
+
CSSPoint lastPaintScrollOffset;
if (mLastContentPaintMetrics.IsScrollable()) {
lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
}
CSSPoint currentScrollOffset = mFrameMetrics.GetScrollOffset() +
mTestAsyncScrollOffset;
@@ -3165,19 +3190,21 @@ AsyncTransform AsyncPanZoomController::G
ParentLayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
* mFrameMetrics.GetZoom() * mTestAsyncZoom.scale;
return AsyncTransform(
LayerToParentLayerScale(mFrameMetrics.GetAsyncZoom().scale * mTestAsyncZoom.scale),
-translation);
}
-AsyncTransformComponentMatrix AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll() const {
- return AsyncTransformComponentMatrix(GetCurrentAsyncTransform())
- * GetOverscrollTransform();
+AsyncTransformComponentMatrix
+AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll(AsyncMode aMode) const
+{
+ return AsyncTransformComponentMatrix(GetCurrentAsyncTransform(aMode))
+ * GetOverscrollTransform(aMode);
}
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
ReentrantMonitorAutoEnter lock(mMonitor);
LayerPoint scrollChange =
(mLastContentPaintMetrics.GetScrollOffset() - mExpectedGeckoMetrics.GetScrollOffset())
* mLastContentPaintMetrics.GetDevPixelsPerCSSPixel()
@@ -3431,16 +3458,17 @@ void AsyncPanZoomController::NotifyLayer
mFrameMetrics.SetLineScrollAmount(aLayerMetrics.GetLineScrollAmount());
mFrameMetrics.SetPageScrollAmount(aLayerMetrics.GetPageScrollAmount());
mScrollMetadata.SetSnapInfo(ScrollSnapInfo(aScrollMetadata.GetSnapInfo()));
mScrollMetadata.SetClipRect(aScrollMetadata.GetClipRect());
mScrollMetadata.SetMaskLayerIndex(aScrollMetadata.GetMaskLayerIndex());
mFrameMetrics.SetIsLayersIdRoot(aLayerMetrics.IsLayersIdRoot());
mFrameMetrics.SetUsesContainerScrolling(aLayerMetrics.UsesContainerScrolling());
mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer());
+ mFrameMetrics.SetForceDisableApz(aLayerMetrics.IsApzForceDisabled());
if (scrollOffsetUpdated) {
APZC_LOG("%p updating scroll offset from %s to %s\n", this,
ToString(mFrameMetrics.GetScrollOffset()).c_str(),
ToString(aLayerMetrics.GetScrollOffset()).c_str());
// Send an acknowledgement with the new scroll generation so that any
// repaint requests later in this function go through.
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -158,31 +158,16 @@ public:
* should continue. If true, the compositor should schedule another composite.
*/
bool AdvanceAnimations(const TimeStamp& aSampleTime);
bool UpdateAnimation(const TimeStamp& aSampleTime,
Vector<Task*>* aOutDeferredTasks);
/**
- * Query the transforms that should be applied to the layer corresponding
- * to this APZC due to asynchronous panning and zooming.
- * This function returns the async transform via the |aOutTransform|
- * out parameter.
- */
- void SampleContentTransformForFrame(AsyncTransform* aOutTransform,
- ParentLayerPoint& aScrollOffset);
-
- /**
- * Return a visual effect that reflects this apzc's
- * overscrolled state, if any.
- */
- AsyncTransformComponentMatrix GetOverscrollTransform() const;
-
- /**
* A shadow layer update has arrived. |aScrollMetdata| is the new ScrollMetadata
* for the container layer corresponding to this APZC.
* |aIsFirstPaint| is a flag passed from the shadow
* layers code indicating that the scroll metadata being sent with this call are
* the initial metadata and the initial paint of the frame has just happened.
*/
void NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata, bool aIsFirstPaint,
bool aThisLayerTreeUpdated);
@@ -218,30 +203,16 @@ public:
void Destroy();
/**
* Returns true if Destroy() has already been called on this APZC instance.
*/
bool IsDestroyed() const;
/**
- * Returns the incremental transformation corresponding to the async pan/zoom
- * in progress. That is, when this transform is multiplied with the layer's
- * existing transform, it will make the layer appear with the desired pan/zoom
- * amount.
- */
- AsyncTransform GetCurrentAsyncTransform() const;
-
- /**
- * Returns the same transform as GetCurrentAsyncTransform(), but includes
- * any transform due to axis over-scroll.
- */
- AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll() const;
-
- /**
* Returns the transform to take something from the coordinate space of the
* last thing we know gecko painted, to the coordinate space of the last thing
* we asked gecko to paint. In cases where that last request has not yet been
* processed, this is needed to transform input events properly into a space
* gecko will understand.
*/
Matrix4x4 GetTransformToLastDispatchedPaint() const;
@@ -732,16 +703,63 @@ private:
// to allow panning by moving multiple fingers (thus moving the focus point).
ParentLayerPoint mLastZoomFocus;
RefPtr<AsyncPanZoomAnimation> mAnimation;
friend class Axis;
+ /* ===================================================================
+ * The functions and members in this section are used to expose
+ * the current async transform state to callers.
+ */
+public:
+ /**
+ * Allows callers to specify which type of async transform they want:
+ * NORMAL provides the actual async transforms of the APZC, whereas
+ * RESPECT_FORCE_DISABLE will provide empty async transforms if and only if
+ * the metrics has the mForceDisableApz flag set. In general the latter should
+ * only be used by call sites that are applying the transform to update
+ * a layer's position.
+ */
+ enum AsyncMode {
+ NORMAL,
+ RESPECT_FORCE_DISABLE,
+ };
+
+ /**
+ * Query the transforms that should be applied to the layer corresponding
+ * to this APZC due to asynchronous panning and zooming.
+ * This function returns the async transform via the |aOutTransform|
+ * out parameter.
+ */
+ ParentLayerPoint GetCurrentAsyncScrollOffset(AsyncMode aMode) const;
+
+ /**
+ * Return a visual effect that reflects this apzc's
+ * overscrolled state, if any.
+ */
+ AsyncTransformComponentMatrix GetOverscrollTransform(AsyncMode aMode) const;
+
+ /**
+ * Returns the incremental transformation corresponding to the async pan/zoom
+ * in progress. That is, when this transform is multiplied with the layer's
+ * existing transform, it will make the layer appear with the desired pan/zoom
+ * amount.
+ */
+ AsyncTransform GetCurrentAsyncTransform(AsyncMode aMode) const;
+
+ /**
+ * Returns the same transform as GetCurrentAsyncTransform(), but includes
+ * any transform due to axis over-scroll.
+ */
+ AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(AsyncMode aMode) const;
+
+
/* ===================================================================
* The functions and members in this section are used to manage
* the state that tracks what this APZC is doing with the input events.
*/
protected:
enum PanZoomState {
NOTHING, /* no touch-start events received */
@@ -1101,19 +1119,19 @@ public:
}
uint64_t GetLayersId() const
{
return mLayersId;
}
private:
- // Extra offset to add in SampleContentTransformForFrame for testing
+ // Extra offset to add to the async scroll position for testing
CSSPoint mTestAsyncScrollOffset;
- // Extra zoom to include in SampleContentTransformForFrame for testing
+ // Extra zoom to include in the aync zoom for testing
LayerToParentLayerScale mTestAsyncZoom;
// Flag to track whether or not the APZ transform is not used. This
// flag is recomputed for every composition frame.
bool mAsyncTransformAppliedToContent;
/* ===================================================================
* The functions and members in this section are used for checkerboard
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -236,17 +236,17 @@ HitTestingTreeNode::IsOutsideClip(const
Maybe<LayerPoint>
HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint) const
{
// convert into Layer coordinate space
LayerToParentLayerMatrix4x4 transform = mTransform *
CompleteAsyncTransform(
mApzc
- ? mApzc->GetCurrentAsyncTransformWithOverscroll()
+ ? mApzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::NORMAL)
: AsyncTransformComponentMatrix());
return UntransformBy(transform.Inverse(), aPoint);
}
HitTestResult
HitTestingTreeNode::HitTest(const ParentLayerPoint& aPoint) const
{
// This should only ever get called if the point is inside the clip region
--- a/gfx/layers/apz/test/gtest/APZCBasicTester.h
+++ b/gfx/layers/apz/test/gtest/APZCBasicTester.h
@@ -91,17 +91,17 @@ protected:
ParentLayerPoint pointOut;
AsyncTransform viewTransformOut;
while (apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut)) {
// The reported scroll offset should be the same throughout.
EXPECT_EQ(aExpectedScrollOffset, pointOut);
// Trigger computation of the overscroll tranform, to make sure
// no assetions fire during the calculation.
- apzc->GetOverscrollTransform();
+ apzc->GetOverscrollTransform(AsyncPanZoomController::NORMAL);
if (!apzc->IsOverscrolled()) {
recoveredFromOverscroll = true;
}
mcc->AdvanceBy(increment);
}
EXPECT_TRUE(recoveredFromOverscroll);
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -247,18 +247,20 @@ public:
}
}
bool SampleContentTransformForFrame(AsyncTransform* aOutTransform,
ParentLayerPoint& aScrollOffset,
const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(0)) {
mcc->AdvanceBy(aIncrement);
bool ret = AdvanceAnimations(mcc->Time());
- AsyncPanZoomController::SampleContentTransformForFrame(
- aOutTransform, aScrollOffset);
+ if (aOutTransform) {
+ *aOutTransform = GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL);
+ }
+ aScrollOffset = GetCurrentAsyncScrollOffset(AsyncPanZoomController::NORMAL);
return ret;
}
void SetWaitForMainThread() {
mWaitForMainThread = true;
}
private:
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -53,16 +53,22 @@ protected:
};
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 80, 80));
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 80, 80));
}
+ void DisableApzOn(Layer* aLayer) {
+ ScrollMetadata m = aLayer->GetScrollMetadata(0);
+ m.GetMetrics().SetForceDisableApz(true);
+ aLayer->SetScrollMetadata(m);
+ }
+
void CreateComplexMultiLayerTree() {
const char* layerTreeSyntax = "c(tc(t)tc(c(t)tt))";
// LayerID 0 12 3 45 6 7 89
nsIntRegion layerVisibleRegion[] = {
nsIntRegion(IntRect(0,0,300,400)), // root(0)
nsIntRegion(IntRect(0,0,100,100)), // thebes(1) in top-left
nsIntRegion(IntRect(50,50,200,300)), // container(2) centered in root(0)
nsIntRegion(IntRect(50,50,200,300)), // thebes(3) fully occupying parent container(2)
@@ -448,16 +454,58 @@ TEST_F(APZHitTestingTester, TestRepaintF
EXPECT_EQ((i + 1) * 10, point.y);
EXPECT_EQ(0, viewTransform.mTranslation.x);
EXPECT_EQ((i + 1) * -10, viewTransform.mTranslation.y);
mcc->AdvanceByMillis(5);
}
}
+TEST_F(APZHitTestingTester, TestForceDisableApz) {
+ CreateSimpleScrollingLayer();
+ DisableApzOn(root);
+ ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
+ manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
+ TestAsyncPanZoomController* apzcroot = ApzcOf(root);
+
+ ScreenPoint origin(100, 50);
+ ScrollWheelInput swi(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
+ ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
+ origin, 0, 10, false);
+ EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
+ EXPECT_EQ(origin, swi.mOrigin);
+
+ AsyncTransform viewTransform;
+ ParentLayerPoint point;
+ apzcroot->SampleContentTransformForFrame(&viewTransform, point);
+ // Since APZ is force-disabled, we expect to see the async transform via
+ // the NORMAL AsyncMode, but not via the RESPECT_FORCE_DISABLE AsyncMode.
+ EXPECT_EQ(0, point.x);
+ EXPECT_EQ(10, point.y);
+ EXPECT_EQ(0, viewTransform.mTranslation.x);
+ EXPECT_EQ(-10, viewTransform.mTranslation.y);
+ viewTransform = apzcroot->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
+ point = apzcroot->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
+ EXPECT_EQ(0, point.x);
+ EXPECT_EQ(0, point.y);
+ EXPECT_EQ(0, viewTransform.mTranslation.x);
+ EXPECT_EQ(0, viewTransform.mTranslation.y);
+
+ mcc->AdvanceByMillis(10);
+
+ // With untransforming events we should get normal behaviour (in this case,
+ // no noticeable untransform, because the repaint request already got
+ // flushed).
+ swi = ScrollWheelInput(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
+ ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
+ origin, 0, 0, false);
+ EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
+ EXPECT_EQ(origin, swi.mOrigin);
+}
+
TEST_F(APZHitTestingTester, Bug1148350) {
CreateBug1148350LayerTree();
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
MockFunction<void(std::string checkPointName)> check;
{
InSequence s;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -496,19 +496,19 @@ APZCCallbackHelper::ApplyCallbackTransfo
void
APZCCallbackHelper::ApplyCallbackTransform(WidgetEvent& aEvent,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale)
{
if (aEvent.AsTouchEvent()) {
WidgetTouchEvent& event = *(aEvent.AsTouchEvent());
- for (size_t i = 0; i < event.touches.Length(); i++) {
- event.touches[i]->mRefPoint = ApplyCallbackTransform(
- event.touches[i]->mRefPoint, aGuid, aScale);
+ for (size_t i = 0; i < event.mTouches.Length(); i++) {
+ event.mTouches[i]->mRefPoint = ApplyCallbackTransform(
+ event.mTouches[i]->mRefPoint, aGuid, aScale);
}
} else {
aEvent.refPoint = ApplyCallbackTransform(
aEvent.refPoint, aGuid, aScale);
}
}
nsEventStatus
@@ -801,19 +801,19 @@ APZCCallbackHelper::SendSetTargetAPZCNot
}
sLastTargetAPZCNotificationInputBlock = aInputBlockId;
if (nsIPresShell* shell = aDocument->GetShell()) {
if (nsIFrame* rootFrame = shell->GetRootFrame()) {
bool waitForRefresh = false;
nsTArray<ScrollableLayerGuid> targets;
if (const WidgetTouchEvent* touchEvent = aEvent.AsTouchEvent()) {
- for (size_t i = 0; i < touchEvent->touches.Length(); i++) {
+ for (size_t i = 0; i < touchEvent->mTouches.Length(); i++) {
waitForRefresh |= PrepareForSetTargetAPZCNotification(aWidget, aGuid,
- rootFrame, touchEvent->touches[i]->mRefPoint, &targets);
+ rootFrame, touchEvent->mTouches[i]->mRefPoint, &targets);
}
} else if (const WidgetWheelEvent* wheelEvent = aEvent.AsWheelEvent()) {
waitForRefresh = PrepareForSetTargetAPZCNotification(aWidget, aGuid,
rootFrame, wheelEvent->refPoint, &targets);
}
// TODO: Do other types of events need to be handled?
if (!targets.IsEmpty()) {
@@ -831,18 +831,20 @@ APZCCallbackHelper::SendSetTargetAPZCNot
void
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
nsIWidget* aWidget,
const WidgetTouchEvent& aEvent,
uint64_t aInputBlockId,
const SetAllowedTouchBehaviorCallback& aCallback)
{
nsTArray<TouchBehaviorFlags> flags;
- for (uint32_t i = 0; i < aEvent.touches.Length(); i++) {
- flags.AppendElement(widget::ContentHelper::GetAllowedTouchBehavior(aWidget, aEvent.touches[i]->mRefPoint));
+ for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
+ flags.AppendElement(
+ widget::ContentHelper::GetAllowedTouchBehavior(
+ aWidget, aEvent.mTouches[i]->mRefPoint));
}
aCallback(aInputBlockId, flags);
}
void
APZCCallbackHelper::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
{
nsCOMPtr<nsIContent> targetContent = nsLayoutUtils::FindContentFor(aScrollId);
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -255,18 +255,18 @@ APZEventState::ProcessLongTap(const nsCO
void
APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
nsEventStatus aApzResponse,
nsEventStatus aContentResponse)
{
- if (aEvent.mMessage == eTouchStart && aEvent.touches.Length() > 0) {
- mActiveElementManager->SetTargetElement(aEvent.touches[0]->GetTarget());
+ if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() > 0) {
+ mActiveElementManager->SetTargetElement(aEvent.mTouches[0]->GetTarget());
}
bool isTouchPrevented = aContentResponse == nsEventStatus_eConsumeNoDefault;
bool sentContentResponse = false;
APZES_LOG("Handling event type %d\n", aEvent.mMessage);
switch (aEvent.mMessage) {
case eTouchStart: {
mTouchEndCancelled = false;
@@ -317,18 +317,18 @@ APZEventState::ProcessTouchEvent(const W
}
if (sentContentResponse &&
aApzResponse == nsEventStatus_eConsumeDoDefault &&
gfxPrefs::PointerEventsEnabled()) {
WidgetTouchEvent cancelEvent(aEvent);
cancelEvent.mMessage = eTouchCancel;
cancelEvent.mFlags.mCancelable = false; // mMessage != eTouchCancel;
- for (uint32_t i = 0; i < cancelEvent.touches.Length(); ++i) {
- if (mozilla::dom::Touch* touch = cancelEvent.touches[i]) {
+ for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
+ if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
touch->convertToPointer = true;
}
}
nsEventStatus status;
cancelEvent.widget->DispatchEvent(&cancelEvent, status);
}
}
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -840,21 +840,20 @@ AsyncCompositionManager::ApplyAsyncConte
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
if (!controller) {
continue;
}
hasAsyncTransform = true;
- AsyncTransform asyncTransformWithoutOverscroll;
- ParentLayerPoint scrollOffset;
- controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
- scrollOffset);
- AsyncTransformComponentMatrix overscrollTransform = controller->GetOverscrollTransform();
+ AsyncTransform asyncTransformWithoutOverscroll =
+ controller->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
+ AsyncTransformComponentMatrix overscrollTransform =
+ controller->GetOverscrollTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
AsyncTransformComponentMatrix asyncTransform =
AsyncTransformComponentMatrix(asyncTransformWithoutOverscroll)
* overscrollTransform;
if (!aLayer->IsScrollInfoLayer()) {
controller->MarkAsyncTransformAppliedToContent();
}
@@ -877,16 +876,18 @@ AsyncCompositionManager::ApplyAsyncConte
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
if (mIsFirstPaint) {
LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
mContentRect = metrics.GetScrollableRect();
SetFirstPaintViewport(scrollOffsetLayerPixels,
geckoZoom,
mContentRect);
} else {
+ ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(
+ AsyncPanZoomController::RESPECT_FORCE_DISABLE);
// Compute the painted displayport in document-relative CSS pixels.
CSSRect displayPort(metrics.GetCriticalDisplayPort().IsEmpty() ?
metrics.GetDisplayPort() :
metrics.GetCriticalDisplayPort());
displayPort += metrics.GetScrollOffset();
SyncFrameMetrics(scrollOffset,
geckoZoom * asyncTransformWithoutOverscroll.mScale,
metrics.GetScrollableRect(), displayPort, geckoZoom, mLayersUpdated,
@@ -1027,17 +1028,18 @@ ApplyAsyncTransformToScrollbarForContent
// disparity between scrollbars and visible content.
if (aContent.IsScrollInfoLayer()) {
return;
}
const FrameMetrics& metrics = aContent.Metrics();
AsyncPanZoomController* apzc = aContent.GetApzc();
- AsyncTransformComponentMatrix asyncTransform = apzc->GetCurrentAsyncTransform();
+ AsyncTransformComponentMatrix asyncTransform =
+ apzc->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
// |asyncTransform| represents the amount by which we have scrolled and
// zoomed since the last paint. Because the scrollbar was sized and positioned based
// on the painted content, we need to adjust it based on asyncTransform so that
// it reflects what the user is actually seeing now.
AsyncTransformComponentMatrix scrollbarTransform;
if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
const ParentLayerCoord asyncScrollY = asyncTransform._42;
@@ -1142,17 +1144,19 @@ ApplyAsyncTransformToScrollbarForContent
// transform, and without this adjustment the scrollbar will end up in the
// wrong place.
//
// Note that since the async transform is applied on top of the content's
// regular transform, we need to make sure to unapply the async transform in
// the same coordinate space. This requires applying the content transform
// and then unapplying it after unapplying the async transform.
if (aScrollbarIsDescendant) {
- Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse().ToUnknownMatrix();
+ AsyncTransformComponentMatrix overscroll =
+ apzc->GetOverscrollTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
+ Matrix4x4 asyncUntransform = (asyncTransform * overscroll).Inverse().ToUnknownMatrix();
Matrix4x4 contentTransform = aContent.GetTransform();
Matrix4x4 contentUntransform = contentTransform.Inverse();
AsyncTransformComponentMatrix asyncCompensation =
ViewAs<AsyncTransformComponentMatrix>(
contentTransform
* asyncUntransform
* contentUntransform);
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -483,20 +483,17 @@ RenderMinimap(ContainerT* aContainer, La
return;
}
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
if (!controller) {
return;
}
- AsyncTransform asyncTransformWithoutOverscroll;
- ParentLayerPoint scrollOffset;
- controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
- scrollOffset);
+ ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
// Options
const int verticalPadding = 10;
const int horizontalPadding = 5;
gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
gfx::Color tileActiveColor(1, 1, 1, 0.4f);
gfx::Color tileBorderColor(0, 0, 0, 0.1f);
gfx::Color pageBorderColor(0, 0, 0);
@@ -660,18 +657,19 @@ RenderLayers(ContainerT* aContainer,
// Since the composition bounds are in the parent layer's coordinates,
// use the parent's effective transform rather than the layer's own.
ParentLayerRect compositionBounds = layer->GetFrameMetrics(i - 1).GetCompositionBounds();
aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER,
compositionBounds.ToUnknownRect(),
gfx::Rect(aClipRect.ToUnknownRect()),
asyncTransform * aContainer->GetEffectiveTransform());
if (AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i - 1)) {
- asyncTransform = apzc->GetCurrentAsyncTransformWithOverscroll().ToUnknownMatrix()
- * asyncTransform;
+ asyncTransform =
+ apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::RESPECT_FORCE_DISABLE).ToUnknownMatrix()
+ * asyncTransform;
}
}
}
if (gfxPrefs::APZMinimap()) {
RenderMinimap(aContainer, aManager, aClipRect, layer);
}
@@ -810,17 +808,17 @@ ContainerRender(ContainerT* aContainer,
// enabled).
if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollInfoLayer()) {
// Since aContainer doesn't have any children we can just iterate from the top metrics
// on it down to the bottom using GetFirstChild and not worry about walking onto another
// underlying layer.
for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
if (AsyncPanZoomController* apzc = i.GetApzc()) {
if (!apzc->GetAsyncTransformAppliedToContent()
- && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform()).IsIdentity()) {
+ && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL)).IsIdentity()) {
aManager->UnusedApzTransformWarning();
break;
}
}
}
}
}
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -143,16 +143,17 @@ private:
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle", APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.lock_angle", APZAxisLockAngle, float, float(M_PI / 6.0) /* 30 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.mode", APZAxisLockMode, int32_t, 0);
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.danger_zone_x", APZDangerZoneX, int32_t, 50);
DECL_GFX_PREF(Live, "apz.danger_zone_y", APZDangerZoneY, int32_t, 100);
+ DECL_GFX_PREF(Live, "apz.disable_for_scroll_linked_effects", APZDisableForScrollLinkedEffects, bool, false);
DECL_GFX_PREF(Live, "apz.displayport_expiry_ms", APZDisplayPortExpiryTime, uint32_t, 15000);
DECL_GFX_PREF(Live, "apz.drag.enabled", APZDragEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false);
DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x1", APZCurveFunctionX1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x2", APZCurveFunctionX2, float, 1.0f);
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Attributes.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
+ #include "mozilla/ChaosMode.h"
#include "ImageLogging.h"
#include "nsPrintfCString.h"
#include "imgLoader.h"
#include "imgRequestProxy.h"
#include "nsCOMPtr.h"
@@ -1767,16 +1768,22 @@ imgLoader::ValidateEntry(imgCacheEntry*
void *key = (void*) aCX;
if (request->LoadId() != key) {
// If we would need to revalidate this entry, but we're being told to
// bypass the cache, we don't allow this entry to be used.
if (aLoadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
return false;
}
+ if (MOZ_UNLIKELY(ChaosMode::isActive(ChaosFeature::ImageCache))) {
+ if (ChaosMode::randomUint32LessThan(4) < 1) {
+ return false;
+ }
+ }
+
// Determine whether the cache aEntry must be revalidated...
validateRequest = ShouldRevalidateEntry(aEntry, aLoadFlags, hasExpired);
MOZ_LOG(gImgLog, LogLevel::Debug,
("imgLoader::ValidateEntry validating cache entry. "
"validateRequest = %d", validateRequest));
} else if (!key && MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
nsAutoCString spec;
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -619,17 +619,17 @@ struct ClassExtension
*/
JSObjectMovedOp objectMovedOp;
};
inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
}
-#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
+#define JS_NULL_CLASS_SPEC nullptr
#define JS_NULL_CLASS_EXT {false,nullptr}
struct ObjectOps
{
LookupPropertyOp lookupProperty;
DefinePropertyOp defineProperty;
HasPropertyOp hasProperty;
GetPropertyOp getProperty;
@@ -649,17 +649,17 @@ struct ObjectOps
// Classes, objects, and properties.
typedef void (*JSClassInternal)();
struct JSClass {
JS_CLASS_MEMBERS(JSFinalizeOp);
- void* reserved[12];
+ void* reserved[5];
};
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
#define JSCLASS_DELAY_METADATA_CALLBACK (1<<1) // class's initialization code
// will call
// SetNewObjectMetadata itself
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*)
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
@@ -751,17 +751,17 @@ struct JSClass {
#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
namespace js {
struct Class
{
JS_CLASS_MEMBERS(FinalizeOp);
- ClassSpec spec;
+ const ClassSpec* spec;
ClassExtension ext;
const ObjectOps* ops;
/*
* Objects of this class aren't native objects. They don't have Shapes that
* describe their properties and layout. Classes using this flag must
* provide their own property behavior, either by being proxy classes (do
* this) or by overriding all the ObjectOps except getElements, watch and
@@ -799,16 +799,36 @@ struct Class
}
bool shouldDelayMetadataCallback() const {
return flags & JSCLASS_DELAY_METADATA_CALLBACK;
}
static size_t offsetOfFlags() { return offsetof(Class, flags); }
+ bool specDefined() const { return spec ? spec->defined() : false; }
+ bool specDependent() const { return spec ? spec->dependent() : false; }
+ JSProtoKey specParentKey() const { return spec ? spec->parentKey() : JSProto_Null; }
+ bool specShouldDefineConstructor()
+ const { return spec ? spec->shouldDefineConstructor() : true; }
+ ClassObjectCreationOp specCreateConstructorHook()
+ const { return spec ? spec->createConstructorHook() : nullptr; }
+ ClassObjectCreationOp specCreatePrototypeHook()
+ const { return spec ? spec->createPrototypeHook() : nullptr; }
+ const JSFunctionSpec* specConstructorFunctions()
+ const { return spec ? spec->constructorFunctions() : nullptr; }
+ const JSPropertySpec* specConstructorProperties()
+ const { return spec ? spec->constructorProperties() : nullptr; }
+ const JSFunctionSpec* specPrototypeFunctions()
+ const { return spec ? spec->prototypeFunctions() : nullptr; }
+ const JSPropertySpec* specPrototypeProperties()
+ const { return spec ? spec->prototypeProperties() : nullptr; }
+ FinishClassInitOp specFinishInitHook()
+ const { return spec ? spec->finishInitHook() : nullptr; }
+
LookupPropertyOp getOpsLookupProperty() const { return ops ? ops->lookupProperty : nullptr; }
DefinePropertyOp getOpsDefineProperty() const { return ops ? ops->defineProperty : nullptr; }
HasPropertyOp getOpsHasProperty() const { return ops ? ops->hasProperty : nullptr; }
GetPropertyOp getOpsGetProperty() const { return ops ? ops->getProperty : nullptr; }
SetPropertyOp getOpsSetProperty() const { return ops ? ops->setProperty : nullptr; }
GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
const { return ops ? ops->getOwnPropertyDescriptor
: nullptr; }
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -91,17 +91,16 @@ enum AsmJSMathBuiltinFunction
// The asm.js spec will recognize this set of builtin Atomics functions.
enum AsmJSAtomicsBuiltinFunction
{
AsmJSAtomicsBuiltin_compareExchange,
AsmJSAtomicsBuiltin_exchange,
AsmJSAtomicsBuiltin_load,
AsmJSAtomicsBuiltin_store,
- AsmJSAtomicsBuiltin_fence,
AsmJSAtomicsBuiltin_add,
AsmJSAtomicsBuiltin_sub,
AsmJSAtomicsBuiltin_and,
AsmJSAtomicsBuiltin_or,
AsmJSAtomicsBuiltin_xor,
AsmJSAtomicsBuiltin_isLockFree
};
@@ -1730,17 +1729,16 @@ class MOZ_STACK_CLASS ModuleValidator
return false;
}
if (!standardLibraryAtomicsNames_.init() ||
!addStandardLibraryAtomicsName("compareExchange", AsmJSAtomicsBuiltin_compareExchange) ||
!addStandardLibraryAtomicsName("exchange", AsmJSAtomicsBuiltin_exchange) ||
!addStandardLibraryAtomicsName("load", AsmJSAtomicsBuiltin_load) ||
!addStandardLibraryAtomicsName("store", AsmJSAtomicsBuiltin_store) ||
- !addStandardLibraryAtomicsName("fence", AsmJSAtomicsBuiltin_fence) ||
!addStandardLibraryAtomicsName("add", AsmJSAtomicsBuiltin_add) ||
!addStandardLibraryAtomicsName("sub", AsmJSAtomicsBuiltin_sub) ||
!addStandardLibraryAtomicsName("and", AsmJSAtomicsBuiltin_and) ||
!addStandardLibraryAtomicsName("or", AsmJSAtomicsBuiltin_or) ||
!addStandardLibraryAtomicsName("xor", AsmJSAtomicsBuiltin_xor) ||
!addStandardLibraryAtomicsName("isLockFree", AsmJSAtomicsBuiltin_isLockFree))
{
return false;
@@ -4102,26 +4100,16 @@ CheckSharedArrayAtomicAccess(FunctionVal
default:
return f.failf(viewName, "not an integer array");
}
return true;
}
static bool
-CheckAtomicsFence(FunctionValidator& f, ParseNode* call, Type* type)
-{
- if (CallArgListLength(call) != 0)
- return f.fail(call, "Atomics.fence must be passed 0 arguments");
-
- *type = Type::Void;
- return f.encoder().writeExpr(Expr::AtomicsFence);
-}
-
-static bool
WriteAtomicOperator(FunctionValidator& f, Expr opcode, size_t* viewTypeAt)
{
return f.encoder().writeExpr(opcode) &&
f.encoder().writePatchableFixedU8(viewTypeAt);
}
static bool
CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type)
@@ -4304,18 +4292,16 @@ CheckAtomicsBuiltinCall(FunctionValidato
case AsmJSAtomicsBuiltin_compareExchange:
return CheckAtomicsCompareExchange(f, callNode, type);
case AsmJSAtomicsBuiltin_exchange:
return CheckAtomicsExchange(f, callNode, type);
case AsmJSAtomicsBuiltin_load:
return CheckAtomicsLoad(f, callNode, type);
case AsmJSAtomicsBuiltin_store:
return CheckAtomicsStore(f, callNode, type);
- case AsmJSAtomicsBuiltin_fence:
- return CheckAtomicsFence(f, callNode, type);
case AsmJSAtomicsBuiltin_add:
return CheckAtomicsBinop(f, callNode, type, AtomicFetchAddOp);
case AsmJSAtomicsBuiltin_sub:
return CheckAtomicsBinop(f, callNode, type, AtomicFetchSubOp);
case AsmJSAtomicsBuiltin_and:
return CheckAtomicsBinop(f, callNode, type, AtomicFetchAndOp);
case AsmJSAtomicsBuiltin_or:
return CheckAtomicsBinop(f, callNode, type, AtomicFetchOrOp);
@@ -7366,17 +7352,16 @@ ValidateAtomicsBuiltinFunction(JSContext
return false;
Native native = nullptr;
switch (global.atomicsBuiltinFunction()) {
case AsmJSAtomicsBuiltin_compareExchange: native = atomics_compareExchange; break;
case AsmJSAtomicsBuiltin_exchange: native = atomics_exchange; break;
case AsmJSAtomicsBuiltin_load: native = atomics_load; break;
case AsmJSAtomicsBuiltin_store: native = atomics_store; break;
- case AsmJSAtomicsBuiltin_fence: native = atomics_fence; break;
case AsmJSAtomicsBuiltin_add: native = atomics_add; break;
case AsmJSAtomicsBuiltin_sub: native = atomics_sub; break;
case AsmJSAtomicsBuiltin_and: native = atomics_and; break;
case AsmJSAtomicsBuiltin_or: native = atomics_or; break;
case AsmJSAtomicsBuiltin_xor: native = atomics_xor; break;
case AsmJSAtomicsBuiltin_isLockFree: native = atomics_isLockFree; break;
}
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -270,17 +270,16 @@ enum class Expr
F64Acos,
F64Atan,
F64Exp,
F64Log,
F64Pow,
F64Atan2,
// Atomics
- AtomicsFence,
I32AtomicsCompareExchange,
I32AtomicsExchange,
I32AtomicsLoad,
I32AtomicsStore,
I32AtomicsBinOp,
// SIMD
#define SIMD_OPCODE(TYPE, OP) TYPE##OP,
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -572,24 +572,16 @@ class FunctionCompiler
return;
MOZ_ASSERT(Scalar::isSimdType(access.accessType()),
"storeSimdHeap can only load from a SIMD view");
MAsmJSStoreHeap* store = MAsmJSStoreHeap::New(alloc(), base, access, v);
curBlock_->add(store);
}
- void memoryBarrier(MemoryBarrierBits type)
- {
- if (inDeadCode())
- return;
- MMemoryBarrier* ins = MMemoryBarrier::New(alloc(), type);
- curBlock_->add(ins);
- }
-
MDefinition* atomicLoadHeap(MDefinition* base, const MAsmJSHeapAccess& access)
{
if (inDeadCode())
return nullptr;
MAsmJSLoadHeap* load = MAsmJSLoadHeap::New(alloc(), base, access);
curBlock_->add(load);
return load;
@@ -3068,20 +3060,16 @@ EmitExpr(FunctionCompiler& f, MDefinitio
case Expr::I32x4greaterThanOrEqualU:
return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual,
SimdSign::Unsigned, def);
case Expr::I32x4fromFloat32x4U:
return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4,
SimdSign::Unsigned, def);
// Atomics
- case Expr::AtomicsFence:
- *def = nullptr;
- f.memoryBarrier(MembarFull);
- return true;
case Expr::I32AtomicsCompareExchange:
return EmitAtomicsCompareExchange(f, def);
case Expr::I32AtomicsExchange:
return EmitAtomicsExchange(f, def);
case Expr::I32AtomicsLoad:
return EmitAtomicsLoad(f, def);
case Expr::I32AtomicsStore:
return EmitAtomicsStore(f, def);
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -47,16 +47,17 @@
#include "builtin/AtomicsObject.h"
#include "mozilla/Atomics.h"
#include "mozilla/FloatingPoint.h"
#include "jsapi.h"
#include "jsfriendapi.h"
+#include "jsnum.h"
#include "asmjs/WasmModule.h"
#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/Class.h"
#include "vm/GlobalObject.h"
#include "vm/Time.h"
#include "vm/TypedArrayObject.h"
@@ -75,17 +76,20 @@ ReportBadArrayType(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_BAD_ARRAY);
return false;
}
static bool
ReportOutOfRange(JSContext* cx)
{
- JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_BAD_INDEX);
+ // Use JSMSG_BAD_INDEX here even if it is generic, since that is
+ // the message used by ToIntegerIndex for its initial range
+ // checking.
+ JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
return false;
}
static bool
ReportCannotWait(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED);
return false;
@@ -103,32 +107,22 @@ GetSharedTypedArray(JSContext* cx, Handl
if (!viewp->isSharedMemory())
return ReportBadArrayType(cx);
return true;
}
static bool
GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view, uint32_t* offset)
{
- RootedId id(cx);
- if (!ValueToId<CanGC>(cx, v, &id))
+ uint64_t index;
+ if (!js::ToIntegerIndex(cx, v, &index))
return false;
- uint64_t index;
- if (!IsTypedArrayIndex(id, &index) || index >= view->length())
+ if (index >= view->length())
return ReportOutOfRange(cx);
- *offset = (uint32_t)index;
- return true;
-}
-
-bool
-js::atomics_fence(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- jit::AtomicOperations::fenceSeqCst();
- args.rval().setUndefined();
+ *offset = uint32_t(index);
return true;
}
static int32_t
CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate,
SharedMem<void*> viewData, uint32_t offset, bool* badArrayType = nullptr)
{
switch (viewType) {
@@ -749,17 +743,17 @@ class AutoUnlockFutexAPI
~AutoUnlockFutexAPI() {
FutexRuntime::lock();
}
};
} // namespace js
bool
-js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
+js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue objv = args.get(0);
HandleValue idxv = args.get(1);
HandleValue valv = args.get(2);
HandleValue timeoutv = args.get(3);
MutableHandleValue r = args.rval();
@@ -792,17 +786,17 @@ js::atomics_futexWait(JSContext* cx, uns
return ReportCannotWait(cx);
// This lock also protects the "waiters" field on SharedArrayRawBuffer,
// and it provides the necessary memory fence.
AutoLockFutexAPI lock;
SharedMem<int32_t*>(addr) = view->viewDataShared().cast<int32_t*>() + offset;
if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) {
- r.setInt32(AtomicsObject::FutexNotequal);
+ r.setString(cx->names().futexNotEqual);
return true;
}
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
FutexWaiter w(offset, rt);
if (FutexWaiter* waiters = sarb->waiters()) {
@@ -810,54 +804,66 @@ js::atomics_futexWait(JSContext* cx, uns
w.back = waiters->back;
waiters->back->lower_pri = &w;
waiters->back = &w;
} else {
w.lower_pri = w.back = &w;
sarb->setWaiters(&w);
}
- AtomicsObject::FutexWaitResult result = AtomicsObject::FutexOK;
+ FutexRuntime::WaitResult result = FutexRuntime::FutexOK;
bool retval = rt->fx.wait(cx, timeout_ms, &result);
- if (retval)
- r.setInt32(result);
+ if (retval) {
+ switch (result) {
+ case FutexRuntime::FutexOK:
+ r.setString(cx->names().futexOK);
+ break;
+ case FutexRuntime::FutexTimedOut:
+ r.setString(cx->names().futexTimedOut);
+ break;
+ }
+ }
if (w.lower_pri == &w) {
sarb->setWaiters(nullptr);
} else {
w.lower_pri->back = w.back;
w.back->lower_pri = w.lower_pri;
if (sarb->waiters() == &w)
sarb->setWaiters(w.lower_pri);
}
return retval;
}
bool
-js::atomics_futexWake(JSContext* cx, unsigned argc, Value* vp)
+js::atomics_wake(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue objv = args.get(0);
HandleValue idxv = args.get(1);
HandleValue countv = args.get(2);
MutableHandleValue r = args.rval();
Rooted<TypedArrayObject*> view(cx, nullptr);
if (!GetSharedTypedArray(cx, objv, &view))
return false;
if (view->type() != Scalar::Int32)
return ReportBadArrayType(cx);
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
double count;
- if (!ToInteger(cx, countv, &count))
- return false;
- if (count < 0)
- count = 0;
+ if (countv.isUndefined()) {
+ count = mozilla::PositiveInfinity<double>();
+ } else {
+ if (!ToInteger(cx, countv, &count))
+ return false;
+ if (count < 0.0)
+ count = 0.0;
+ }
AutoLockFutexAPI lock;
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
int32_t woken = 0;
FutexWaiter* waiters = sarb->waiters();
@@ -873,130 +879,16 @@ js::atomics_futexWake(JSContext* cx, uns
--count;
} while (count > 0 && iter != waiters);
}
r.setInt32(woken);
return true;
}
-bool
-js::atomics_futexWakeOrRequeue(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- HandleValue objv = args.get(0);
- HandleValue idx1v = args.get(1);
- HandleValue countv = args.get(2);
- HandleValue idx2v = args.get(3);
- HandleValue valv = args.get(4);
- MutableHandleValue r = args.rval();
-
- Rooted<TypedArrayObject*> view(cx, nullptr);
- if (!GetSharedTypedArray(cx, objv, &view))
- return false;
- if (view->type() != Scalar::Int32)
- return ReportBadArrayType(cx);
- uint32_t offset1;
- if (!GetTypedArrayIndex(cx, idx1v, view, &offset1))
- return false;
- double count;
- if (!ToInteger(cx, countv, &count))
- return false;
- if (count < 0)
- count = 0;
- int32_t value;
- if (!ToInt32(cx, valv, &value))
- return false;
- uint32_t offset2;
- if (!GetTypedArrayIndex(cx, idx2v, view, &offset2))
- return false;
-
- AutoLockFutexAPI lock;
-
- SharedMem<int32_t*> addr = view->viewDataShared().cast<int32_t*>() + offset1;
- if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) {
- r.setInt32(AtomicsObject::FutexNotequal);
- return true;
- }
-
- Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
- SharedArrayRawBuffer* sarb = sab->rawBufferObject();
-
- // Walk the list of waiters looking for those waiting on offset1.
- // Wake some and requeue the others. There may already be other
- // waiters on offset2, so those that are requeued must be moved to
- // the back of the list. Offset1 may equal offset2. The list's
- // first node may change, and the list may be emptied out by the
- // operation.
-
- FutexWaiter* waiters = sarb->waiters();
- if (!waiters) {
- r.setInt32(0);
- return true;
- }
-
- int32_t woken = 0;
- FutexWaiter whead((uint32_t)-1, nullptr); // Header node for waiters
- FutexWaiter* first = waiters;
- FutexWaiter* last = waiters->back;
- whead.lower_pri = first;
- whead.back = last;
- first->back = &whead;
- last->lower_pri = &whead;
-
- FutexWaiter rhead((uint32_t)-1, nullptr); // Header node for requeued
- rhead.lower_pri = rhead.back = &rhead;
-
- FutexWaiter* iter = whead.lower_pri;
- while (iter != &whead) {
- FutexWaiter* c = iter;
- iter = iter->lower_pri;
- if (c->offset != offset1 || !c->rt->fx.isWaiting())
- continue;
- if (count > 0) {
- c->rt->fx.wake(FutexRuntime::WakeExplicit);
- ++woken;
- --count;
- } else {
- c->offset = offset2;
-
- // Remove the node from the waiters list.
- c->back->lower_pri = c->lower_pri;
- c->lower_pri->back = c->back;
-
- // Insert the node at the back of the requeuers list.
- c->lower_pri = &rhead;
- c->back = rhead.back;
- rhead.back->lower_pri = c;
- rhead.back = c;
- }
- }
-
- // If there are any requeuers, append them to the waiters.
- if (rhead.lower_pri != &rhead) {
- whead.back->lower_pri = rhead.lower_pri;
- rhead.lower_pri->back = whead.back;
-
- whead.back = rhead.back;
- rhead.back->lower_pri = &whead;
- }
-
- // Make the final list and install it.
- waiters = nullptr;
- if (whead.lower_pri != &whead) {
- whead.back->lower_pri = whead.lower_pri;
- whead.lower_pri->back = whead.back;
- waiters = whead.lower_pri;
- }
- sarb->setWaiters(waiters);
-
- r.setInt32(woken);
- return true;
-}
-
/* static */ bool
js::FutexRuntime::initialize()
{
MOZ_ASSERT(!lock_);
lock_ = PR_NewLock();
return lock_ != nullptr;
}
@@ -1065,17 +957,17 @@ js::FutexRuntime::isWaiting()
// wakes up and goes into WaitingInterrupted. In those states the
// worker is still waiting, and if an explicit wake arrives the
// worker transitions to Woken. See further comments in
// FutexRuntime::wait().
return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt;
}
bool
-js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWaitResult* result)
+js::FutexRuntime::wait(JSContext* cx, double timeout_ms, WaitResult* result)
{
MOZ_ASSERT(&cx->runtime()->fx == this);
MOZ_ASSERT(cx->runtime()->fx.canWait());
MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
MOZ_ASSERT(state_ == Idle || state_ == WaitingInterrupted);
// Disallow waiting when a runtime is processing an interrupt.
// See explanation below.
@@ -1122,39 +1014,39 @@ js::FutexRuntime::wait(JSContext* cx, do
lockHolder_ = holder;
#endif
switch (state_) {
case FutexRuntime::Waiting:
// Timeout or spurious wakeup.
if (timed) {
uint64_t now = PRMJ_Now();
if (now >= finalEnd) {
- *result = AtomicsObject::FutexTimedout;
+ *result = FutexTimedOut;
goto finished;
}
}
break;
case FutexRuntime::Woken:
- *result = AtomicsObject::FutexOK;
+ *result = FutexOK;
goto finished;
case FutexRuntime::WaitingNotifiedForInterrupt:
// The interrupt handler may reenter the engine. In that case
// there are two complications:
//
// - The waiting thread is not actually waiting on the
// condition variable so we have to record that it
// should be woken when the interrupt handler returns.
// To that end, we flag the thread as interrupted around
// the interrupt and check state_ when the interrupt
- // handler returns. A futexWake() call that reaches the
+ // handler returns. A wake() call that reaches the
// runtime during the interrupt sets state_ to Woken.
//
- // - It is in principle possible for futexWait() to be
+ // - It is in principle possible for wait() to be
// reentered on the same thread/runtime and waiting on the
// same location and to yet again be interrupted and enter
// the interrupt handler. In this case, it is important
// that when another agent wakes waiters, all waiters using
// the same runtime on the same location are woken in LIFO
// order; FIFO may be the required order, but FIFO would
// fail to wake up the innermost call. Interrupts are
// outside any spec anyway. Also, several such suspended
@@ -1170,17 +1062,17 @@ js::FutexRuntime::wait(JSContext* cx, do
state_ = WaitingInterrupted;
{
AutoUnlockFutexAPI unlock;
retval = cx->runtime()->handleInterrupt(cx);
}
if (!retval)
goto finished;
if (state_ == Woken) {
- *result = AtomicsObject::FutexOK;
+ *result = FutexOK;
goto finished;
}
break;
default:
MOZ_CRASH();
}
}
@@ -1214,52 +1106,43 @@ js::FutexRuntime::wake(WakeReason reason
PR_NotifyCondVar(cond_);
}
const JSFunctionSpec AtomicsMethods[] = {
JS_INLINABLE_FN("compareExchange", atomics_compareExchange, 4,0, AtomicsCompareExchange),
JS_INLINABLE_FN("load", atomics_load, 2,0, AtomicsLoad),
JS_INLINABLE_FN("store", atomics_store, 3,0, AtomicsStore),
JS_INLINABLE_FN("exchange", atomics_exchange, 3,0, AtomicsExchange),
- JS_INLINABLE_FN("fence", atomics_fence, 0,0, AtomicsFence),
JS_INLINABLE_FN("add", atomics_add, 3,0, AtomicsAdd),
JS_INLINABLE_FN("sub", atomics_sub, 3,0, AtomicsSub),
JS_INLINABLE_FN("and", atomics_and, 3,0, AtomicsAnd),
JS_INLINABLE_FN("or", atomics_or, 3,0, AtomicsOr),
JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor),
JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree),
- JS_FN("futexWait", atomics_futexWait, 4,0),
- JS_FN("futexWake", atomics_futexWake, 3,0),
- JS_FN("futexWakeOrRequeue", atomics_futexWakeOrRequeue, 5,0),
+ JS_FN("wait", atomics_wait, 4,0),
+ JS_FN("futexWait", atomics_wait, 4,0),
+ JS_FN("wake", atomics_wake, 3,0),
+ JS_FN("futexWake", atomics_wake, 3,0),
JS_FS_END
};
-static const JSConstDoubleSpec AtomicsConstants[] = {
- {"OK", AtomicsObject::FutexOK},
- {"TIMEDOUT", AtomicsObject::FutexTimedout},
- {"NOTEQUAL", AtomicsObject::FutexNotequal},
- {0, 0}
-};
-
JSObject*
AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
{
// Create Atomics Object.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
if (!objProto)
return nullptr;
RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto,
SingletonObject));
if (!Atomics)
return nullptr;
if (!JS_DefineFunctions(cx, Atomics, AtomicsMethods))
return nullptr;
- if (!JS_DefineConstDoubles(cx, Atomics, AtomicsConstants))
- return nullptr;
RootedValue AtomicsValue(cx, ObjectValue(*Atomics));
// Everything is set up, install Atomics on the global object.
if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr,
JSPROP_RESOLVING))
{
return nullptr;
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -13,41 +13,30 @@
namespace js {
class AtomicsObject : public JSObject
{
public:
static const Class class_;
static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
static bool toString(JSContext* cx, unsigned int argc, Value* vp);
-
- // Defined return values for futexWait.
- // The error values must be negative because APIs such as futexWaitOrRequeue
- // return a value that is either the number of tasks woken or an error code.
- enum FutexWaitResult : int32_t {
- FutexOK = 0,
- FutexNotequal = -1,
- FutexTimedout = -2
- };
};
bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_fence(JSContext* cx, unsigned argc, Value* vp);
bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_futexWait(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_futexWake(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_futexWakeOrRequeue(JSContext* cx, unsigned argc, Value* vp);
+bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
+bool atomics_wake(JSContext* cx, unsigned argc, Value* vp);
/* asm.js callouts */
int32_t atomics_add_asm_callout(int32_t vt, int32_t offset, int32_t value);
int32_t atomics_sub_asm_callout(int32_t vt, int32_t offset, int32_t value);
int32_t atomics_and_asm_callout(int32_t vt, int32_t offset, int32_t value);
int32_t atomics_or_asm_callout(int32_t vt, int32_t offset, int32_t value);
int32_t atomics_xor_asm_callout(int32_t vt, int32_t offset, int32_t value);
int32_t atomics_cmpxchg_asm_callout(int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
@@ -67,49 +56,55 @@ public:
void destroyInstance();
// Parameters to wake().
enum WakeReason {
WakeExplicit, // Being asked to wake up by another thread
WakeForJSInterrupt // Interrupt requested
};
+ // Result code from wait().
+ enum WaitResult {
+ FutexOK,
+ FutexTimedOut
+ };
+
// Block the calling thread and wait.
//
// The futex lock must be held around this call.
//
// The timeout is the number of milliseconds, with fractional
// times allowed; specify positive infinity for an indefinite wait.
//
// wait() will not wake up spuriously. It will return true and
// set *result to a return code appropriate for
- // Atomics.futexWait() on success, and return false on error.
- bool wait(JSContext* cx, double timeout, AtomicsObject::FutexWaitResult* result);
+ // Atomics.wait() on success, and return false on error.
+ bool wait(JSContext* cx, double timeout, WaitResult* result);
// Wake the thread represented by this Runtime.
//
// The futex lock must be held around this call. (The sleeping
- // thread will not wake up until the caller of futexWake()
+ // thread will not wake up until the caller of Atomics.wake()
// releases the lock.)
//
// If the thread is not waiting then this method does nothing.
//
- // If the thread is waiting in a call to futexWait() and the
- // reason is WakeExplicit then the futexWait() call will return
+ // If the thread is waiting in a call to wait() and the
+ // reason is WakeExplicit then the wait() call will return
// with Woken.
//
- // If the thread is waiting in a call to futexWait() and the
- // reason is WakeForJSInterrupt then the futexWait() will return
+ // If the thread is waiting in a call to wait() and the
+ // reason is WakeForJSInterrupt then the wait() will return
// with WaitingNotifiedForInterrupt; in the latter case the caller
- // of futexWait() must handle the interrupt.
+ // of wait() must handle the interrupt.
void wake(WakeReason reason);
bool isWaiting();
- // If canWait() returns false (the default) then futexWait is disabled
+ // If canWait() returns false (the default) then wait() is disabled
// on the runtime to which the FutexRuntime belongs.
bool canWait() {
return canWait_;
}
void setCanWait(bool flag) {
canWait_ = flag;
}
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1206,35 +1206,37 @@ FinishObjectClassInit(JSContext* cx, JS:
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (global->shouldSplicePrototype(cx)) {
if (!global->splicePrototype(cx, global->getClass(), tagged))
return false;
}
return true;
}
+static const ClassSpec PlainObjectClassSpec = {
+ CreateObjectConstructor,
+ CreateObjectPrototype,
+ object_static_methods,
+ nullptr,
+ object_methods,
+ object_properties,
+ FinishObjectClassInit
+};
+
const Class PlainObject::class_ = {
js_Object_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- CreateObjectConstructor,
- CreateObjectPrototype,
- object_static_methods,
- nullptr,
- object_methods,
- object_properties,
- FinishObjectClassInit
- }
+ &PlainObjectClassSpec
};
const Class* const js::ObjectClassPtr = &PlainObject::class_;
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -392,39 +392,52 @@ PromiseObject::reject(JSContext* cx, Han
} // namespace js
static JSObject*
CreatePromisePrototype(JSContext* cx, JSProtoKey key)
{
return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
}
+static const ClassSpec PromiseObjectClassSpec = {
+ GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
+ CreatePromisePrototype,
+ promise_static_methods,
+ promise_static_properties,
+ promise_methods
+};
+
const Class PromiseObject::class_ = {
"Promise",
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
JSCLASS_HAS_XRAYED_CONSTRUCTOR,
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
- CreatePromisePrototype,
- promise_static_methods,
- promise_static_properties,
- promise_methods
- }
+ &PromiseObjectClassSpec
+};
+
+static const ClassSpec PromiseObjectProtoClassSpec = {
+ DELEGATED_CLASSSPEC(PromiseObject::class_.spec),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ ClassSpec::IsDelegated
};
const Class PromiseObject::protoClass_ = {
"PromiseProto",
JSCLASS_HAS_CACHED_PROTO(JSProto_Promise),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
@@ -432,19 +445,10 @@ const Class PromiseObject::protoClass_ =
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- DELEGATED_CLASSSPEC(&PromiseObject::class_.spec),
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- ClassSpec::IsDelegated
- }
+ &PromiseObjectProtoClassSpec
};
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -13,16 +13,17 @@
#include "builtin/SIMD.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/IntegerTypeTraits.h"
#include "jsapi.h"
#include "jsfriendapi.h"
+#include "jsnum.h"
#include "jsprf.h"
#include "builtin/TypedObject.h"
#include "jit/InlinableNatives.h"
#include "js/Value.h"
#include "jsobjinlines.h"
@@ -1249,88 +1250,24 @@ Select(JSContext* cx, unsigned argc, Val
Elem result[V::lanes];
for (unsigned i = 0; i < V::lanes; i++)
result[i] = mask[i] ? tv[i] : fv[i];
return StoreResult<V>(cx, args, result);
}
-// Get an integer array index from a function argument. Coerce if necessary.
-//
-// When a JS function argument represents an integer index into an array, it is
-// laundered like this:
-//
-// 1. numericIndex = ToNumber(argument) (may throw TypeError)
-// 2. intIndex = ToInteger(numericIndex)
-// 3. if intIndex != numericIndex throw RangeError
-//
-// This function additionally bounds the range to the non-negative contiguous
-// integers:
-//
-// 4. if intIndex < 0 or intIndex > 2^53 throw RangeError
-//
-// Return true and set |*index| to the integer value if |argument| is a valid
-// array index argument. Otherwise report an TypeError or RangeError and return
-// false.
-//
-// The returned index will always be in the range 0 <= *index <= 2^53.
-static bool
-ArgumentToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
-{
- // Fast common case.
- if (v.isInt32()) {
- int32_t i = v.toInt32();
- if (i >= 0) {
- *index = i;
- return true;
- }
- }
-
- // Slow case. Use ToNumber() to coerce. This may throw a TypeError.
- double d;
- if (!ToNumber(cx, v, &d))
- return false;
-
- // Check that |d| is an integer in the valid range.
- //
- // Not all floating point integers fit in the range of a uint64_t, so we
- // need a rough range check before the real range check in our caller. We
- // could limit indexes to UINT64_MAX, but this would mean that our callers
- // have to be very careful about integer overflow. The contiguous integer
- // floating point numbers end at 2^53, so make that our upper limit. If we
- // ever support arrays with more than 2^53 elements, this will need to
- // change.
- //
- // Reject infinities, NaNs, and numbers outside the contiguous integer range
- // with a RangeError.
-
- // Write relation so NaNs throw a RangeError.
- if (!(0 <= d && d <= (uint64_t(1) << 53)))
- return ErrorBadIndex(cx);
-
- // Check that d is an integer, throw a RangeError if not.
- // Note that this conversion could invoke undefined behaviour without the
- // range check above.
- uint64_t i(d);
- if (d != double(i))
- return ErrorBadIndex(cx);
-
- *index = i;
- return true;
-}
-
// Extract an integer lane index from a function argument.
//
// Register an exception and return false if the argument is not suitable.
static bool
ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane)
{
uint64_t arg;
- if (!ArgumentToIntegerIndex(cx, v, &arg))
+ if (!ToIntegerIndex(cx, v, &arg))
return false;
if (arg >= limit)
return ErrorBadIndex(cx);
*lane = unsigned(arg);
return true;
}
@@ -1347,17 +1284,17 @@ TypedArrayFromArgs(JSContext* cx, const
JSObject& argobj = args[0].toObject();
if (!argobj.is<TypedArrayObject>())
return ErrorBadArgs(cx);
typedArray.set(&argobj);
uint64_t index;
- if (!ArgumentToIntegerIndex(cx, args[1], &index))
+ if (!ToIntegerIndex(cx, args[1], &index))
return false;
// Do the range check in 64 bits even when size_t is 32 bits.
// This can't overflow because index <= 2^53.
uint64_t bytes = index * typedArray->as<TypedArrayObject>().bytesPerElement();
// Keep in sync with AsmJS OnOutOfBounds function.
if ((bytes + accessBytes) > typedArray->as<TypedArrayObject>().byteLength())
return ErrorBadIndex(cx);
--- a/js/src/jit-test/tests/asm.js/testAtomics.js
+++ b/js/src/jit-test/tests/asm.js/testAtomics.js
@@ -6,33 +6,28 @@ if (!this.SharedArrayBuffer || !this.Ato
// The code duplication below is very far from elegant but provides
// flexibility that comes in handy several places.
load(libdir + "asm.js");
load(libdir + "asserts.js");
var loadModule_int32_code =
USE_ASM + `
- var atomic_fence = stdlib.Atomics.fence;
var atomic_load = stdlib.Atomics.load;
var atomic_store = stdlib.Atomics.store;
var atomic_cmpxchg = stdlib.Atomics.compareExchange;
var atomic_exchange = stdlib.Atomics.exchange;
var atomic_add = stdlib.Atomics.add;
var atomic_sub = stdlib.Atomics.sub;
var atomic_and = stdlib.Atomics.and;
var atomic_or = stdlib.Atomics.or;
var atomic_xor = stdlib.Atomics.xor;
var i32a = new stdlib.Int32Array(heap);
- function do_fence() {
- atomic_fence();
- }
-
// Load element 0
function do_load() {
var v = 0;
v = atomic_load(i32a, 0);
return v|0;
}
// Load element i
@@ -199,18 +194,17 @@ var loadModule_int32_code =
// CAS element i: -1 -> 0x5A5A5A5A
function do_cas2_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i32a, i>>2, -1, 0x5A5A5A5A);
return v|0;
}
- return { fence: do_fence,
- load: do_load,
+ return { load: do_load,
load_i: do_load_i,
store: do_store,
store_i: do_store_i,
xchg: do_xchg,
xchg_i: do_xchg_i,
xchg_intish: do_xchg_intish,
add: do_add,
add_i: do_add_i,
@@ -233,18 +227,16 @@ var loadModule_int32_code =
var loadModule_int32 = asmCompile('stdlib', 'foreign', 'heap', loadModule_int32_code);
function test_int32(heap) {
var i32a = new Int32Array(heap);
var i32m = asmLink(loadModule_int32, this, {}, heap);
var size = Int32Array.BYTES_PER_ELEMENT;
- i32m.fence();
-
i32a[0] = 12345;
assertEq(i32m.load(), 12345);
assertEq(i32m.load_i(size*0), 12345);
assertEq(i32m.store(), 37);
assertEq(i32a[0], 37);
assertEq(i32m.store_i(size*0), 37);
@@ -323,17 +315,16 @@ function test_int32(heap) {
assertEq(i32m.store_i((i32a.length-1)*4), 37);
assertEq(i32m.add_i((i32a.length-1)*4), 37);
assertEq(i32m.load_i((i32a.length-1)*4), 37+37);
i32a[i32a.length-1] = 0;
}
var loadModule_uint32_code =
USE_ASM + `
- var atomic_fence = stdlib.Atomics.fence;
var atomic_load = stdlib.Atomics.load;
var atomic_store = stdlib.Atomics.store;
var atomic_cmpxchg = stdlib.Atomics.compareExchange;
var atomic_exchange = stdlib.Atomics.exchange;
var atomic_add = stdlib.Atomics.add;
var atomic_sub = stdlib.Atomics.sub;
var atomic_and = stdlib.Atomics.and;
var atomic_or = stdlib.Atomics.or;
@@ -604,33 +595,28 @@ function test_uint32(heap) {
assertEq(i32m.store_i((i32a.length-1)*4), 37);
assertEq(i32m.add_i((i32a.length-1)*4), 37);
assertEq(i32m.load_i((i32a.length-1)*4), 37+37);
i32a[i32a.length-1] = 0;
}
var loadModule_int16_code =
USE_ASM + `
- var atomic_fence = stdlib.Atomics.fence;
var atomic_load = stdlib.Atomics.load;
var atomic_store = stdlib.Atomics.store;
var atomic_cmpxchg = stdlib.Atomics.compareExchange;
var atomic_exchange = stdlib.Atomics.exchange;
var atomic_add = stdlib.Atomics.add;
var atomic_sub = stdlib.Atomics.sub;
var atomic_and = stdlib.Atomics.and;
var atomic_or = stdlib.Atomics.or;
var atomic_xor = stdlib.Atomics.xor;
var i16a = new stdlib.Int16Array(heap);
- function do_fence() {
- atomic_fence();
- }
-
// Load element 0
function do_load() {
var v = 0;
v = atomic_load(i16a, 0);
return v|0;
}
// Load element i
@@ -771,18 +757,17 @@ var loadModule_int16_code =
// CAS element i: -1 -> 0x5A5A
function do_cas2_i(i) {
i = i|0;
var v = 0;
v = atomic_cmpxchg(i16a, i>>1, -1, 0x5A5A);
return v|0;
}
- return { fence: do_fence,
- load: do_load,
+ return { load: do_load,
load_i: do_load_i,
store: do_store,
store_i: do_store_i,
xchg: do_xchg,
xchg_i: do_xchg_i,
add: do_add,
add_i: do_add_i,
sub: do_sub,
@@ -802,18 +787,16 @@ var loadModule_int16_code =
var loadModule_int16 = asmCompile('stdlib', 'foreign', 'heap', loadModule_int16_code);
function test_int16(heap) {
var i16a = new Int16Array(heap);
var i16m = loadModule_int16(this, {}, heap);
var size = Int16Array.BYTES_PER_ELEMENT;
- i16m.fence();
-
i16a[0] = 12345;
assertEq(i16m.load(), 12345);
assertEq(i16m.load_i(size*0), 12345);
i16a[0] = -38;
assertEq(i16m.load(), -38);
assertEq(i16m.load_i(size*0), -38);
--- a/js/src/jit-test/tests/atomics/basic-tests.js
+++ b/js/src/jit-test/tests/atomics/basic-tests.js
@@ -1,14 +1,14 @@
// Basic functional tests for the Atomics primitives.
//
// These do not test atomicity, just that calling and coercions and
// indexing and exception behavior all work right.
//
-// These do not test the futex operations.
+// These do not test the wait/wake operations.
load(libdir + "asserts.js");
var DEBUG = false; // Set to true for useful printouts
function dprint(...xs) {
if (!DEBUG)
return;
@@ -61,18 +61,16 @@ function testMethod(a, ...indices) {
// val = 9
assertEq(Atomics.store(a, x, 14), 14); // What about coercion?
// val = 14
assertEq(Atomics.load(a, x), 14);
// val = 14
Atomics.store(a, x, 0);
// val = 0
- Atomics.fence();
-
// val = 0
assertEq(Atomics.add(a, x, 3), 0);
// val = 3
assertEq(Atomics.sub(a, x, 2), 3);
// val = 1
assertEq(Atomics.or(a, x, 6), 1);
// val = 7
assertEq(Atomics.and(a, x, 14), 7);
@@ -132,18 +130,16 @@ function testFunction(a, ...indices) {
// val = 9
assertEq(gAtomics_store(a, x, 14), 14); // What about coercion?
// val = 14
assertEq(gAtomics_load(a, x), 14);
// val = 14
gAtomics_store(a, x, 0);
// val = 0
- gAtomics_fence();
-
// val = 0
assertEq(gAtomics_add(a, x, 3), 0);
// val = 3
assertEq(gAtomics_sub(a, x, 2), 3);
// val = 1
assertEq(gAtomics_or(a, x, 6), 1);
// val = 7
assertEq(gAtomics_and(a, x, 14), 7);
@@ -206,17 +202,17 @@ function testTypeBinop(a, op) {
op(a, 0);
}
var globlength = 0; // Will be set later
function testRangeCAS(a) {
dprint("Range: " + a.constructor.name);
- var msg = /out-of-range index for atomic access/;
+ var msg = /out-of-range index/; // A generic message
assertErrorMessage(() => Atomics.compareExchange(a, -1, 0, 1), RangeError, msg);
assertEq(a[0], 0);
assertErrorMessage(() => Atomics.compareExchange(a, "hi", 0, 1), RangeError, msg);
assertEq(a[0], 0);
assertErrorMessage(() => Atomics.compareExchange(a, a.length + 5, 0, 1), RangeError, msg);
@@ -375,17 +371,17 @@ function adHocExchange() {
assertEq(exchangeLoop(a), -100000);
}
// isLockFree(n) may return true only if there is an integer array
// on which atomic operations is allowed whose byte size is n,
// ie, it must return false for n=8.
//
// SpiderMonkey has isLockFree(1), isLockFree(2), isLockFree(4) on all
-// supported platforms, though this is not guaranteed by the spec.
+// supported platforms, only the last is guaranteed by the spec.
var sizes = [ 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12];
var answers = [ true, true, false, true, false, false, false, false,
false, false, false, false];
function testIsLockFree() {
// This ought to defeat most compile-time resolution.
@@ -451,16 +447,23 @@ function testUint8Clamped(sab) {
}
catch (e) {
thrown = true;
assertEq(e instanceof TypeError, true);
}
assertEq(thrown, true);
}
+function testWeirdIndices() {
+ var a = new Int8Array(new SharedArrayBuffer(16));
+ a[3] = 10;
+ assertEq(Atomics.load(a, "0x03"), 10);
+ assertEq(Atomics.load(a, {valueOf: () => 3}), 10);
+}
+
function isLittleEndian() {
var xxx = new ArrayBuffer(2);
var xxa = new Int16Array(xxx);
var xxb = new Int8Array(xxx);
xxa[0] = 37;
var is_little = xxb[0] == 37;
return is_little;
}
@@ -492,17 +495,16 @@ function runTests() {
CLONE(testMethod)(new Int32Array(sab), 0, 42, 1023);
CLONE(testMethod)(new Uint32Array(sab), 0, 42, 1023);
// Test that invoking as v = Atomics.whatever; v() works, on correct arguments.
gAtomics_compareExchange = Atomics.compareExchange;
gAtomics_exchange = Atomics.exchange;
gAtomics_load = Atomics.load;
gAtomics_store = Atomics.store;
- gAtomics_fence = Atomics.fence;
gAtomics_add = Atomics.add;
gAtomics_sub = Atomics.sub;
gAtomics_and = Atomics.and;
gAtomics_or = Atomics.or;
gAtomics_xor = Atomics.xor;
CLONE(testFunction)(new Int8Array(sab), 0, 42, 4095);
CLONE(testFunction)(new Uint8Array(sab), 0, 42, 4095);
@@ -546,12 +548,13 @@ function runTests() {
testUint8Clamped(sab);
// Misc ad-hoc tests
adHocExchange();
// Misc
testIsLockFree();
testIsLockFree2();
+ testWeirdIndices();
}
if (this.Atomics && this.SharedArrayBuffer)
runTests();
deleted file mode 100644
--- a/js/src/jit-test/tests/atomics/inline-fence.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// |jit-test| slow;
-//
-// This is intended to be run manually with IONFLAGS=logs and
-// postprocessing by iongraph to verify manually (by inspecting the
-// MIR) that:
-//
-// - the fence operation is inlined as it should be
-// - loads and stores are not moved across the fence
-//
-// Be sure to run with --ion-eager --ion-offthread-compile=off.
-
-function fence(ta) {
- var x = ta[0];
- Atomics.fence();
- var y = ta[1];
- var z = y + 1;
- var w = x + z;
- return w;
-}
-
-if (!this.SharedArrayBuffer || !this.Atomics)
- quit(0);
-
-var sab = new SharedArrayBuffer(4096);
-var ia = new Int32Array(sab);
-for ( var i=0, limit=ia.length ; i < limit ; i++ )
- ia[i] = 37;
-var v = 0;
-for ( var i=0 ; i < 1000 ; i++ )
- v += fence(ia);
-//print(v);
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -294,18 +294,21 @@ class RegionLock
inline bool
AtomicOperations::isLockfree(int32_t size)
{
// Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp.
switch (size) {
case 1:
+ return true;
case 2:
+ return true;
case 4:
+ // The spec requires Atomics.isLockFree(4) to return true.
return true;
case 8:
// The spec requires Atomics.isLockFree(n) to return false
// unless n is the BYTES_PER_ELEMENT value of some integer
// TypedArray that admits atomic operations. At the time of
// writing (February 2016) there is no such array with n=8.
// return AtomicOperations::isLockfree8();
return false;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10002,17 +10002,20 @@ CodeGenerator::visitStoreTypedArrayEleme
void
CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
{
Register value = ToRegister(lir->value());
Register output = ToRegister(lir->output());
// Keep this in sync with isLockfree() in jit/AtomicOperations.h.
- MOZ_ASSERT(!AtomicOperations::isLockfree(8));
+ MOZ_ASSERT(AtomicOperations::isLockfree(1)); // Implementation artifact
+ MOZ_ASSERT(AtomicOperations::isLockfree(2)); // Implementation artifact
+ MOZ_ASSERT(AtomicOperations::isLockfree(4)); // Spec requirement
+ MOZ_ASSERT(!AtomicOperations::isLockfree(8)); // Implementation invariant, for now
Label Ldone, Lfailed;
masm.move32(Imm32(1), output);
masm.branch32(Assembler::Equal, value, Imm32(4), &Ldone);
masm.branch32(Assembler::Equal, value, Imm32(2), &Ldone);
masm.branch32(Assembler::Equal, value, Imm32(1), &Ldone);
masm.move32(Imm32(0), output);
masm.bind(&Ldone);
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -17,17 +17,16 @@
_(ArrayConcat) \
_(ArraySlice) \
_(ArraySplice) \
\
_(AtomicsCompareExchange) \
_(AtomicsExchange) \
_(AtomicsLoad) \
_(AtomicsStore) \
- _(AtomicsFence) \
_(AtomicsAdd) \
_(AtomicsSub) \
_(AtomicsAnd) \
_(AtomicsOr) \
_(AtomicsXor) \
_(AtomicsIsLockFree) \
\
_(MathAbs) \
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -827,17 +827,16 @@ class IonBuilder
InliningStatus inlineObjectCreate(CallInfo& callInfo);
InliningStatus inlineDefineDataProperty(CallInfo& callInfo);
// Atomics natives.
InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo);
InliningStatus inlineAtomicsExchange(CallInfo& callInfo);
InliningStatus inlineAtomicsLoad(CallInfo& callInfo);
InliningStatus inlineAtomicsStore(CallInfo& callInfo);
- InliningStatus inlineAtomicsFence(CallInfo& callInfo);
InliningStatus inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target);
InliningStatus inlineAtomicsIsLockFree(CallInfo& callInfo);
// Slot intrinsics.
InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
MIRType knownValueType);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4200,23 +4200,16 @@ void
LIRGenerator::visitRecompileCheck(MRecompileCheck* ins)
{
LRecompileCheck* lir = new(alloc()) LRecompileCheck(temp());
add(lir, ins);
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitMemoryBarrier(MMemoryBarrier* ins)
-{
- LMemoryBarrier* lir = new(alloc()) LMemoryBarrier(ins->type());
- add(lir, ins);
-}
-
-void
LIRGenerator::visitSimdBox(MSimdBox* ins)
{
MOZ_ASSERT(IsSimdType(ins->input()->type()));
LUse in = useRegister(ins->input());
LSimdBox* lir = new(alloc()) LSimdBox(in, temp());
define(lir, ins);
assignSafepoint(lir, ins);
}
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -281,17 +281,16 @@ class LIRGenerator : public LIRGenerator
void visitAsmJSReturn(MAsmJSReturn* ins);
void visitAsmJSVoidReturn(MAsmJSVoidReturn* ins);
void visitAsmJSPassStackArg(MAsmJSPassStackArg* ins);
void visitAsmJSCall(MAsmJSCall* ins);
void visitSetDOMProperty(MSetDOMProperty* ins);
void visitGetDOMProperty(MGetDOMProperty* ins);
void visitGetDOMMember(MGetDOMMember* ins);
void visitRecompileCheck(MRecompileCheck* ins);
- void visitMemoryBarrier(MMemoryBarrier* ins);
void visitSimdBox(MSimdBox* ins);
void visitSimdUnbox(MSimdUnbox* ins);
void visitSimdExtractElement(MSimdExtractElement* ins);
void visitSimdInsertElement(MSimdInsertElement* ins);
void visitSimdSwizzle(MSimdSwizzle* ins);
void visitSimdGeneralShuffle(MSimdGeneralShuffle* ins);
void visitSimdShuffle(MSimdShuffle* ins);
void visitSimdUnaryArith(MSimdUnaryArith* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -88,18 +88,16 @@ IonBuilder::inlineNativeCall(CallInfo& c
case InlinableNative::AtomicsCompareExchange:
return inlineAtomicsCompareExchange(callInfo);
case InlinableNative::AtomicsExchange:
return inlineAtomicsExchange(callInfo);
case InlinableNative::AtomicsLoad:
return inlineAtomicsLoad(callInfo);
case InlinableNative::AtomicsStore:
return inlineAtomicsStore(callInfo);
- case InlinableNative::AtomicsFence:
- return inlineAtomicsFence(callInfo);
case InlinableNative::AtomicsAdd:
case InlinableNative::AtomicsSub:
case InlinableNative::AtomicsAnd:
case InlinableNative::AtomicsOr:
case InlinableNative::AtomicsXor:
return inlineAtomicsBinop(callInfo, inlNative);
case InlinableNative::AtomicsIsLockFree:
return inlineAtomicsIsLockFree(callInfo);
@@ -2911,40 +2909,16 @@ IonBuilder::inlineAtomicsStore(CallInfo&
if (!resumeAfter(store))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
-IonBuilder::inlineAtomicsFence(CallInfo& callInfo)
-{
- if (callInfo.argc() != 0 || callInfo.constructing()) {
- trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
- return InliningStatus_NotInlined;
- }
-
- if (!JitSupportsAtomics())
- return InliningStatus_NotInlined;
-
- callInfo.setImplicitlyUsedUnchecked();
-
- MMemoryBarrier* fence = MMemoryBarrier::New(alloc());
- current->add(fence);
- pushConstant(UndefinedValue());
-
- // Fences are considered effectful (they execute a memory barrier).
- if (!resumeAfter(fence))
- return InliningStatus_Error;
-
- return InliningStatus_Inlined;
-}
-
-IonBuilder::InliningStatus
IonBuilder::inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target)
{
if (callInfo.argc() != 3 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MDefinition* value = callInfo.getArg(2);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9990,25 +9990,39 @@ class MArrayJoin
virtual AliasSet getAliasSet() const override {
// Array.join might coerce the elements of the Array to strings. This
// coercion might cause the evaluation of the some JavaScript code.
return AliasSet::Store(AliasSet::Any);
}
MDefinition* foldsTo(TempAllocator& alloc) override;
};
-// See comments above MMemoryBarrier, below.
+// All barriered operations - MCompareExchangeTypedArrayElement,
+// MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as
+// well as MLoadUnboxedScalar and MStoreUnboxedScalar when they are
+// marked as requiring a memory barrer - have the following
+// attributes:
+//
+// - Not movable
+// - Not removable
+// - Not congruent with any other instruction
+// - Effectful (they alias every TypedArray store)
+//
+// The intended effect of those constraints is to prevent all loads
+// and stores preceding the barriered operation from being moved to
+// after the barriered operation, and vice versa, and to prevent the
+// barriered operation from being removed or hoisted.
enum MemoryBarrierRequirement
{
DoesNotRequireMemoryBarrier,
DoesRequireMemoryBarrier
};
-// Also see comments above MMemoryBarrier, below.
+// Also see comments at MMemoryBarrierRequirement, above.
// Load an unboxed scalar value from a typed array or other object.
class MLoadUnboxedScalar
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
Scalar::Type storageType_;
Scalar::Type readType_;
@@ -13643,59 +13657,16 @@ class MRecompileCheck : public MNullaryI
return increaseWarmUpCounter_;
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
-// All barriered operations - MMemoryBarrier, MCompareExchangeTypedArrayElement,
-// MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as well as
-// MLoadUnboxedScalar and MStoreUnboxedScalar when they are marked as requiring
-// a memory barrer - have the following attributes:
-//
-// - Not movable
-// - Not removable
-// - Not congruent with any other instruction
-// - Effectful (they alias every TypedArray store)
-//
-// The intended effect of those constraints is to prevent all loads
-// and stores preceding the barriered operation from being moved to
-// after the barriered operation, and vice versa, and to prevent the
-// barriered operation from being removed or hoisted.
-
-class MMemoryBarrier
- : public MNullaryInstruction
-{
- // The type is a combination of the memory barrier types in AtomicOp.h.
- const MemoryBarrierBits type_;
-
- explicit MMemoryBarrier(MemoryBarrierBits type)
- : type_(type)
- {
- MOZ_ASSERT((type_ & ~MembarAllbits) == MembarNobits);
- setGuard(); // Not removable
- }
-
- public:
- INSTRUCTION_HEADER(MemoryBarrier)
-
- static MMemoryBarrier* New(TempAllocator& alloc, MemoryBarrierBits type = MembarFull) {
- return new(alloc) MMemoryBarrier(type);
- }
- MemoryBarrierBits type() const {
- return type_;
- }
-
- AliasSet getAliasSet() const override {
- return AliasSet::Store(AliasSet::UnboxedElement);
- }
-};
-
class MAtomicIsLockFree
: public MUnaryInstruction,
public ConvertToInt32Policy<0>::Data
{
explicit MAtomicIsLockFree(MDefinition* value)
: MUnaryInstruction(value)
{
setResultType(MIRType_Boolean);
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -275,17 +275,16 @@ namespace jit {
_(AsmJSParameter) \
_(AsmJSVoidReturn) \
_(AsmJSPassStackArg) \
_(AsmJSCall) \
_(AsmSelect) \
_(AsmReinterpret) \
_(NewDerivedTypedObject) \
_(RecompileCheck) \
- _(MemoryBarrier) \
_(AsmJSCompareExchangeHeap) \
_(AsmJSAtomicExchangeHeap) \
_(AsmJSAtomicBinopHeap) \
_(UnknownValue) \
_(LexicalCheck) \
_(ThrowRuntimeLexicalError) \
_(GlobalNameConflictsCheck) \
_(Debugger) \
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7958,20 +7958,16 @@ class LMemoryBarrier : public LInstructi
explicit LMemoryBarrier(MemoryBarrierBits type) : type_(type)
{
MOZ_ASSERT((type_ & ~MembarAllbits) == MembarNobits);
}
MemoryBarrierBits type() const {
return type_;
}
-
- const MMemoryBarrier* mir() const {
- return mir_->toMemoryBarrier();
- }
};
class LDebugger : public LCallInstructionHelper<0, 0, 2>
{
public:
LIR_HEADER(Debugger)
LDebugger(const LDefinition& temp1, const LDefinition& temp2) {
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -492,17 +492,16 @@ MSG_DEF(JSMSG_BAD_PARSE_NODE, 0
// Symbol
MSG_DEF(JSMSG_SYMBOL_TO_STRING, 0, JSEXN_TYPEERR, "can't convert symbol to string")
MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol to number")
// Atomics and futexes
MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation")
MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large")
MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread")
-MSG_DEF(JSMSG_ATOMICS_BAD_INDEX, 0, JSEXN_RANGEERR, "out-of-range index for atomic access")
// XPConnect wrappers and DOM bindings
MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't define elements on a Window object")
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object")
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object")
MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object")
MSG_DEF(JSMSG_NO_NAMED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have a named property setter for '{1}'")
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3257,40 +3257,42 @@ array_proto_finish(JSContext* cx, JS::Ha
return false;
}
RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().get(JS::SymbolCode::unscopables)));
value.setObject(*unscopables);
return DefineProperty(cx, proto, id, value, nullptr, nullptr, JSPROP_READONLY);
}
+static const ClassSpec ArrayObjectClassSpec = {
+ GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
+ CreateArrayPrototype,
+ array_static_methods,
+ nullptr,
+ array_methods,
+ nullptr,
+ array_proto_finish
+};
+
const Class ArrayObject::class_ = {
"Array",
JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_CALLBACK,
array_addProperty,
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
- CreateArrayPrototype,
- array_static_methods,
- nullptr,
- array_methods,
- nullptr,
- array_proto_finish
- }
+ &ArrayObjectClassSpec
};
/*
* Array allocation functions.
*/
static inline bool
EnsureNewArrayElements(ExclusiveContext* cx, ArrayObject* obj, uint32_t length)
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3267,41 +3267,54 @@ FinishDateClassInit(JSContext* cx, Handl
RootedValue toUTCStringFun(cx);
RootedId toUTCStringId(cx, NameToId(cx->names().toUTCString));
RootedId toGMTStringId(cx, NameToId(cx->names().toGMTString));
return NativeGetProperty(cx, proto.as<NativeObject>(), toUTCStringId, &toUTCStringFun) &&
NativeDefineProperty(cx, proto.as<NativeObject>(), toGMTStringId, toUTCStringFun,
nullptr, nullptr, 0);
}
+static const ClassSpec DateObjectClassSpec = {
+ GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
+ CreateDatePrototype,
+ date_static_methods,
+ nullptr,
+ date_methods,
+ nullptr,
+ FinishDateClassInit
+};
+
const Class DateObject::class_ = {
js_Date_str,
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
- CreateDatePrototype,
- date_static_methods,
- nullptr,
- date_methods,
- nullptr,
- FinishDateClassInit
- }
+ &DateObjectClassSpec
+};
+
+static const ClassSpec DateObjectProtoClassSpec = {
+ DELEGATED_CLASSSPEC(DateObject::class_.spec),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ ClassSpec::IsDelegated
};
const Class DateObject::protoClass_ = {
js_Object_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
@@ -3309,26 +3322,17 @@ const Class DateObject::protoClass_ = {
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- DELEGATED_CLASSSPEC(&DateObject::class_.spec),
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- ClassSpec::IsDelegated
- }
+ &DateObjectProtoClassSpec
};
JSObject*
js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
{
JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
if (!obj)
return nullptr;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -60,87 +60,86 @@ static const JSPropertySpec exception_pr
static const JSFunctionSpec exception_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, exn_toSource, 0, 0),
#endif
JS_SELF_HOSTED_FN(js_toString_str, "ErrorToString", 0,0),
JS_FS_END
};
-#define IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, extraClassSpecFlags) \
+#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
{ \
js_Error_str, /* yes, really */ \
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
nullptr, /* getProperty */ \
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
exn_finalize, \
nullptr, /* call */ \
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
nullptr, /* trace */ \
- { \
- ErrorObject::createConstructor, \
- ErrorObject::createProto, \
- nullptr, \
- nullptr, \
- exception_methods, \
- exception_properties, \
- nullptr, \
- JSProto_Error | extraClassSpecFlags \
- } \
+ classSpecPtr \
}
-#define IMPLEMENT_ERROR_SUBCLASS(name) \
- IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, 0)
+const ClassSpec
+ErrorObject::errorClassSpec_ = {
+ ErrorObject::createConstructor,
+ ErrorObject::createProto,
+ nullptr,
+ nullptr,
+ exception_methods,
+ exception_properties,
+ nullptr,
+ 0
+};
+
+const ClassSpec
+ErrorObject::subErrorClassSpec_ = {
+ ErrorObject::createConstructor,
+ ErrorObject::createProto,
+ nullptr,
+ nullptr,
+ exception_methods,
+ exception_properties,
+ nullptr,
+ JSProto_Error
+};
+
+const ClassSpec
+ErrorObject::debuggeeWouldRunClassSpec_ = {
+ ErrorObject::createConstructor,
+ ErrorObject::createProto,
+ nullptr,
+ nullptr,
+ exception_methods,
+ exception_properties,
+ nullptr,
+ JSProto_Error | ClassSpec::DontDefineConstructor
+};
const Class
ErrorObject::classes[JSEXN_LIMIT] = {
- {
- js_Error_str,
- JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
- JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- exn_finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- nullptr, /* trace */
- {
- ErrorObject::createConstructor,
- ErrorObject::createProto,
- nullptr,
- nullptr,
- exception_methods,
- exception_properties,
- nullptr
- }
- },
- IMPLEMENT_ERROR_SUBCLASS(InternalError),
- IMPLEMENT_ERROR_SUBCLASS(EvalError),
- IMPLEMENT_ERROR_SUBCLASS(RangeError),
- IMPLEMENT_ERROR_SUBCLASS(ReferenceError),
- IMPLEMENT_ERROR_SUBCLASS(SyntaxError),
- IMPLEMENT_ERROR_SUBCLASS(TypeError),
- IMPLEMENT_ERROR_SUBCLASS(URIError),
+ IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_),
+ IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_),
// DebuggeeWouldRun is a subclass of Error but is accessible via the
// Debugger constructor, not the global.
- IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(DebuggeeWouldRun, ClassSpec::DontDefineConstructor),
+ IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::debuggeeWouldRunClassSpec_)
};
JSErrorReport*
js::CopyErrorReport(JSContext* cx, JSErrorReport* report)
{
/*
* We use a single malloc block to make a deep copy of JSErrorReport with
* the following layout:
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -638,17 +638,17 @@ ProtoKeyToClass(JSProtoKey key);
// Returns true if the standard class identified by |key| inherits from
// another standard class (in addition to Object) along its proto chain.
//
// In practice, this only returns true for Error subtypes.
inline bool
StandardClassIsDependent(JSProtoKey key)
{
const Class* clasp = ProtoKeyToClass(key);
- return clasp && clasp->spec.defined() && clasp->spec.dependent();
+ return clasp && clasp->specDefined() && clasp->specDependent();
}
// Returns the key for the class inherited by a given standard class (that
// is to say, the prototype of this standard class's prototype).
//
// You must be sure that this corresponds to a standard class with a cached
// JSProtoKey before calling this function. In general |key| will match the
// cached proto key, except in cases where multiple JSProtoKeys share a
@@ -657,17 +657,17 @@ inline JSProtoKey
ParentKeyForStandardClass(JSProtoKey key)
{
// [Object] has nothing to inherit from.
if (key == JSProto_Object)
return JSProto_Null;
// If we're dependent, return the key of the class we depend on.
if (StandardClassIsDependent(key))
- return ProtoKeyToClass(key)->spec.parentKey();
+ return ProtoKeyToClass(key)->specParentKey();
// Otherwise, we inherit [Object].
return JSProto_Object;
}
JS_FRIEND_API(bool)
IsFunctionObject(JSObject* obj);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -829,39 +829,41 @@ CreateFunctionPrototype(JSContext* cx, J
if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
return nullptr;
self->setThrowTypeError(throwTypeError);
return functionProto;
}
+static const ClassSpec JSFunctionClassSpec = {
+ CreateFunctionConstructor,
+ CreateFunctionPrototype,
+ nullptr,
+ nullptr,
+ function_methods,
+ function_properties
+};
+
const Class JSFunction::class_ = {
js_Function_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
fun_enumerate,
fun_resolve,
fun_mayResolve,
nullptr, /* finalize */
nullptr, /* call */
fun_hasInstance,
nullptr, /* construct */
fun_trace,
- {
- CreateFunctionConstructor,
- CreateFunctionPrototype,
- nullptr,
- nullptr,
- function_methods,
- function_properties
- }
+ &JSFunctionClassSpec
};
const Class* const js::FunctionClassPtr = &JSFunction::class_;
/* Find the body of a function (not including braces). */
bool
js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
size_t* bodyEnd)
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1743,16 +1743,65 @@ js::ToLengthClamped(T* cx, HandleValue v
return true;
}
template bool
js::ToLengthClamped<JSContext>(JSContext*, HandleValue, uint32_t*, bool*);
template bool
js::ToLengthClamped<ExclusiveContext>(ExclusiveContext*, HandleValue, uint32_t*, bool*);
+bool
+js::ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
+{
+ // Fast common case.
+ if (v.isInt32()) {
+ int32_t i = v.toInt32();
+ if (i >= 0) {
+ *index = i;
+ return true;
+ }
+ }
+
+ // Slow case. Use ToNumber() to coerce. This may throw a TypeError.
+ double d;
+ if (!ToNumber(cx, v, &d))
+ return false;
+
+ // Check that |d| is an integer in the valid range.
+ //
+ // Not all floating point integers fit in the range of a uint64_t, so we
+ // need a rough range check before the real range check in our caller. We
+ // could limit indexes to UINT64_MAX, but this would mean that our callers
+ // have to be very careful about integer overflow. The contiguous integer
+ // floating point numbers end at 2^53, so make that our upper limit. If we
+ // ever support arrays with more than 2^53 elements, this will need to
+ // change.
+ //
+ // Reject infinities, NaNs, and numbers outside the contiguous integer range
+ // with a RangeError.
+
+ // Write relation so NaNs throw a RangeError.
+ if (!(0 <= d && d <= (uint64_t(1) << 53))) {
+ JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+ return false;
+ }
+
+ // Check that d is an integer, throw a RangeError if not.
+ // Note that this conversion could invoke undefined behaviour without the
+ // range check above.
+ uint64_t i(d);
+ if (d != double(i)) {
+ JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+ return false;
+ }
+
+ *index = i;
+ return true;
+}
+
template <typename CharT>
bool
js_strtod(ExclusiveContext* cx, const CharT* begin, const CharT* end, const CharT** dEnd,
double* d)
{
const CharT* s = SkipSpace(begin, end);
size_t length = end - s;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -270,16 +270,36 @@ ToInteger(JSContext* cx, HandleValue v,
* return value is false then *overflow will be true iff the value was
* not clampable to uint32_t range.
*
* For JSContext and ExclusiveContext.
*/
template<typename T>
bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* overflow);
+/* Convert and range check an index value as for DataView, SIMD, and Atomics
+ * operations, eg ES7 24.2.1.1, DataView's GetViewValue():
+ *
+ * 1. numericIndex = ToNumber(argument) (may throw TypeError)
+ * 2. intIndex = ToInteger(numericIndex)
+ * 3. if intIndex != numericIndex throw RangeError
+ *
+ * This function additionally bounds the range to the non-negative contiguous
+ * integers:
+ *
+ * 4. if intIndex < 0 or intIndex > 2^53 throw RangeError
+ *
+ * Return true and set |*index| to the integer value if |argument| is a valid
+ * array index argument. Otherwise report an TypeError or RangeError and return
+ * false.
+ *
+ * The returned index will always be in the range 0 <= *index <= 2^53.
+ */
+bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index);
+
inline bool
SafeAdd(int32_t one, int32_t two, int32_t* res)
{
#if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow)
// Using compiler's builtin function.
return !__builtin_sadd_overflow(one, two, res);
#else
// Use unsigned for the 32-bit operation since signed overflow gets
--- a/js/src/tests/shell/futex-apis.js
+++ b/js/src/tests/shell/futex-apis.js
@@ -5,17 +5,17 @@
* http://creativecommons.org/licenses/publicdomain/
*/
if (!(this.SharedArrayBuffer && this.Atomics)) {
reportCompare(true,true);
quit(0);
}
-// Checks for parameter validation of futex API. ALl of these test
+// Checks for parameter validation of wait/wake API. All of these test
// cases should throw exceptions during parameter validation, before
// we check whether any waiting should be done.
let ab = new ArrayBuffer(16);
let sab = new SharedArrayBuffer(16);
//////////////////////////////////////////////////////////////////////
//
@@ -52,48 +52,45 @@ let sab = new SharedArrayBuffer(16);
Object,
Int32Array,
Date,
Math,
Atomics ];
for ( let i=0 ; i < values.length ; i++ ) {
let view = values[i];
- assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWakeOrRequeue(view, 0, 0, 1, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
}
}
// Check against TypedArray on non-shared memory cases.
{
let views = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array];
for ( let View of views ) {
let view = new View(ab);
- assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWakeOrRequeue(view, 0, 0, 1, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
}
}
// Check against TypedArray on shared memory, but wrong view type
{
let views = [Int8Array, Uint8Array, Int16Array, Uint16Array, Uint32Array,
Uint8ClampedArray, Float32Array, Float64Array];
for ( let View of views ) {
let view = new View(sab);
- assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
- assertThrowsInstanceOf(() => Atomics.futexWakeOrRequeue(view, 0, 0, 1, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+ assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
}
}
//////////////////////////////////////////////////////////////////////
//
// The indices must be in the range of the array
{
@@ -103,16 +100,14 @@ let sab = new SharedArrayBuffer(16);
(view) => view.length,
(view) => view.length*2,
(view) => undefined,
(view) => '3.5',
(view) => { password: "qumquat" } ];
for ( let iidx=0 ; iidx < indices.length ; iidx++ ) {
let Idx = indices[iidx](view);
- assertThrowsInstanceOf(() => Atomics.futexWait(view, Idx, 10), RangeError);
- assertThrowsInstanceOf(() => Atomics.futexWake(view, Idx), RangeError);
- assertThrowsInstanceOf(() => Atomics.futexWakeOrRequeue(view, Idx, 5, 0, 0), RangeError);
- assertThrowsInstanceOf(() => Atomics.futexWakeOrRequeue(view, 0, 5, Idx, 0), RangeError);
+ assertThrowsInstanceOf(() => Atomics.wait(view, Idx, 10), RangeError);
+ assertThrowsInstanceOf(() => Atomics.wake(view, Idx), RangeError);
}
}
reportCompare(true,true);
--- a/js/src/tests/shell/futex.js
+++ b/js/src/tests/shell/futex.js
@@ -12,17 +12,17 @@ if (!(this.SharedArrayBuffer && this.get
var DEBUG = false;
function dprint(s) {
if (DEBUG) print(s);
}
// Tests the SharedArrayBuffer mailbox in the shell.
-// Tests the futex functionality in the shell.
+// Tests the wait/wake functionality in the shell.
var sab = new SharedArrayBuffer(12);
var mem = new Int32Array(sab);
// SharedArrayBuffer mailbox tests
assertEq(getSharedArrayBuffer(), null); // Mbx starts empty
@@ -56,67 +56,103 @@ assertThrowsInstanceOf(() => setSharedAr
assertThrowsInstanceOf(() => setSharedArrayBuffer(false), Error);
assertThrowsInstanceOf(() => setSharedArrayBuffer(3.14), Error);
assertThrowsInstanceOf(() => setSharedArrayBuffer(mem), Error);
assertThrowsInstanceOf(() => setSharedArrayBuffer("abracadabra"), Error);
assertThrowsInstanceOf(() => setSharedArrayBuffer(() => 37), Error);
// Futex test
+if (helperThreadCount() === 0) {
+ // Abort if there is no helper thread.
+ reportCompare(true,true);
+ quit();
+}
+
+////////////////////////////////////////////////////////////
+
+// wait() returns "not-equal" if the value is not the expected one.
+
+mem[0] = 42;
+
+assertEq(Atomics.wait(mem, 0, 33), "not-equal");
+
+// wait() returns "timed-out" if it times out
+
+assertEq(Atomics.wait(mem, 0, 42, 100), "timed-out");
+
+////////////////////////////////////////////////////////////
+
// Main is sharing the buffer with the worker; the worker is clearing
// the buffer.
mem[0] = 42;
mem[1] = 37;
mem[2] = DEBUG;
+
setSharedArrayBuffer(mem.buffer);
-if (helperThreadCount() === 0) {
- // Abort if there is no helper thread.
- reportCompare(true,true);
- quit();
-}
-
evalInWorker(`
var mem = new Int32Array(getSharedArrayBuffer());
function dprint(s) {
if (mem[2]) print(s);
}
assertEq(mem[0], 42); // what was written in the main thread
assertEq(mem[1], 37); // is read in the worker
mem[1] = 1337;
-dprint("Sleeping for 3 seconds");
-sleep(3);
+dprint("Sleeping for 2 seconds");
+sleep(2);
dprint("Waking the main thread now");
setSharedArrayBuffer(null);
-Atomics.futexWake(mem, 0, 1);
+assertEq(Atomics.wake(mem, 0, 1), 1); // Can fail spuriously but very unlikely
`);
var then = Date.now();
-assertEq(Atomics.futexWait(mem, 0, 42), Atomics.OK);
+assertEq(Atomics.wait(mem, 0, 42), "ok");
dprint("Woke up as I should have in " + (Date.now() - then)/1000 + "s");
assertEq(mem[1], 1337); // what was written in the worker is read in the main thread
assertEq(getSharedArrayBuffer(), null); // The worker's clearing of the mbx is visible
+////////////////////////////////////////////////////////////
+
+// Test the default argument to atomics.wake()
+
+setSharedArrayBuffer(mem.buffer);
+
+evalInWorker(`
+var mem = new Int32Array(getSharedArrayBuffer());
+sleep(2); // Probably long enough to avoid a spurious error next
+assertEq(Atomics.wake(mem, 0), 1); // Last argument to wake should default to +Infinity
+`);
+
+var then = Date.now();
+dprint("Main thread waiting on wakeup (2s)");
+assertEq(Atomics.wait(mem, 0, 42), "ok");
+dprint("Woke up as I should have in " + (Date.now() - then)/1000 + "s");
+
+////////////////////////////////////////////////////////////
+
// A tricky case: while in the wait there will be an interrupt, and in
-// the interrupt handler we will execute a futexWait. This is
+// the interrupt handler we will execute a wait. This is
// explicitly prohibited (for now), so there should be a catchable exception.
timeout(2, function () {
- dprint("In the interrupt, starting inner wait");
- Atomics.futexWait(mem, 0, 42); // Should throw and propagate all the way out
+ dprint("In the interrupt, starting inner wait with timeout 2s");
+ Atomics.wait(mem, 0, 42); // Should throw and propagate all the way out
});
var exn = false;
try {
dprint("Starting outer wait");
- assertEq(Atomics.futexWait(mem, 0, 42, 5000), Atomics.OK);
+ assertEq(Atomics.wait(mem, 0, 42, 5000), "ok");
}
catch (e) {
- dprint("Got the exception!");
+ dprint("Got the timeout exception!");
exn = true;
}
finally {
timeout(-1);
}
assertEq(exn, true);
-dprint("Done");
+
+////////////////////////////////////////////////////////////
+dprint("Done");
reportCompare(true,true);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -1012,16 +1012,17 @@ ArrayBufferViewObject::trace(JSTracer* t
TraceEdge(trc, &bufSlot, "typedarray.buffer");
// Update obj's data pointer if it moved.
if (bufSlot.isObject()) {
if (IsArrayBuffer(&bufSlot.toObject())) {
ArrayBufferObject& buf = AsArrayBuffer(MaybeForwarded(&bufSlot.toObject()));
uint32_t offset = uint32_t(obj->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT).toInt32());
MOZ_ASSERT(buf.dataPointer() != nullptr);
+ MOZ_ASSERT(offset <= INT32_MAX);
if (buf.forInlineTypedObject()) {
// The data is inline with an InlineTypedObject associated with the
// buffer. Get a new address for the typed object if it moved.
JSObject* view = buf.firstView();
// Mark the object to move it into the tenured space.
TraceManuallyBarrieredEdge(trc, &view, "typed array nursery owner");
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -107,16 +107,19 @@
macro(float64, float64, "float64") \
macro(Float64x2, Float64x2, "Float64x2") \
macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
macro(forEach, forEach, "forEach") \
macro(format, format, "format") \
macro(formatToParts, formatToParts, "formatToParts") \
macro(frame, frame, "frame") \
macro(from, from, "from") \
+ macro(futexOK, futexOK, "ok") \
+ macro(futexNotEqual, futexNotEqual, "not-equal") \
+ macro(futexTimedOut, futexTimedOut, "timed-out") \
macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
macro(get, get, "get") \
macro(getInternals, getInternals, "getInternals") \
macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
macro(global, global, "global") \
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -36,16 +36,20 @@ class ErrorObject : public NativeObject
static bool
init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
uint32_t lineNumber, uint32_t columnNumber, HandleString message);
static bool checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName,
MutableHandle<ErrorObject*> error);
+ static const ClassSpec errorClassSpec_;
+ static const ClassSpec subErrorClassSpec_;
+ static const ClassSpec debuggeeWouldRunClassSpec_;
+
protected:
static const uint32_t EXNTYPE_SLOT = 0;
static const uint32_t STACK_SLOT = EXNTYPE_SLOT + 1;
static const uint32_t ERROR_REPORT_SLOT = STACK_SLOT + 1;
static const uint32_t FILENAME_SLOT = ERROR_REPORT_SLOT + 1;
static const uint32_t LINENUMBER_SLOT = FILENAME_SLOT + 1;
static const uint32_t COLUMNNUMBER_SLOT = LINENUMBER_SLOT + 1;
static const uint32_t MESSAGE_SLOT = COLUMNNUMBER_SLOT + 1;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -157,17 +157,17 @@ GlobalObject::resolveConstructor(JSConte
return true;
// Some classes have no init routine, which means that they're disabled at
// compile-time. We could try to enforce that callers never pass such keys
// to resolveConstructor, but that would cramp the style of consumers like
// GlobalObject::initStandardClasses that want to just carpet-bomb-call
// ensureConstructor with every JSProtoKey. So it's easier to just handle
// it here.
- bool haveSpec = clasp && clasp->spec.defined();
+ bool haveSpec = clasp && clasp->specDefined();
if (!init && !haveSpec)
return true;
// See if there's an old-style initialization hook.
if (init) {
MOZ_ASSERT(!haveSpec);
return init(cx, global);
}
@@ -190,77 +190,79 @@ GlobalObject::resolveConstructor(JSConte
// Function will also be resolved before we return.
if (key == JSProto_Function && global->getPrototype(JSProto_Object).isUndefined())
return resolveConstructor(cx, global, JSProto_Object);
// We don't always have a prototype (i.e. Math and JSON). If we don't,
// |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
// should all be null.
RootedObject proto(cx);
- if (clasp->spec.createPrototypeHook()) {
- proto = clasp->spec.createPrototypeHook()(cx, key);
+ if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
+ proto = createPrototype(cx, key);
if (!proto)
return false;
// Make sure that creating the prototype didn't recursively resolve our
// own constructor. We can't just assert that there's no prototype; OOMs
// can result in incomplete resolutions in which the prototype is saved
// but not the constructor. So use the same criteria that protects entry
// into this function.
MOZ_ASSERT(!global->isStandardClassResolved(key));
global->setPrototype(key, ObjectValue(*proto));
}
// Create the constructor.
- RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, key));
+ RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
if (!ctor)
return false;
RootedId id(cx, NameToId(ClassName(key, cx)));
- if (clasp->spec.shouldDefineConstructor()) {
+ if (clasp->specShouldDefineConstructor()) {
if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
return false;
}
global->setConstructor(key, ObjectValue(*ctor));
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
// Define any specified functions and properties, unless we're a dependent
// standard class (in which case they live on the prototype), or we're
// operating on the self-hosting global, in which case we don't want any
// functions and properties on the builtins and their prototypes.
if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
- if (const JSFunctionSpec* funs = clasp->spec.prototypeFunctions()) {
+ if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
if (!JS_DefineFunctions(cx, proto, funs))
return false;
}
- if (const JSPropertySpec* props = clasp->spec.prototypeProperties()) {
+ if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
if (!JS_DefineProperties(cx, proto, props))
return false;
}
- if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions()) {
+ if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
if (!JS_DefineFunctions(cx, ctor, funs))
return false;
}
- if (const JSPropertySpec* props = clasp->spec.constructorProperties()) {
+ if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
if (!JS_DefineProperties(cx, ctor, props))
return false;
}
}
// If the prototype exists, link it with the constructor.
if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
return false;
// Call the post-initialization hook, if provided.
- if (clasp->spec.finishInitHook() && !clasp->spec.finishInitHook()(cx, ctor, proto))
- return false;
+ if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
+ if (!finishInit(cx, ctor, proto))
+ return false;
+ }
- if (clasp->spec.shouldDefineConstructor()) {
+ if (clasp->specShouldDefineConstructor()) {
// Stash type information, so that what we do here is equivalent to
// initBuiltinConstructor.
AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
}
return true;
}
@@ -411,21 +413,21 @@ GlobalObject::initStandardClasses(JSCont
* self-hosted builtins.
*/
static bool
InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey protoKey)
{
MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
const Class* clasp = ProtoKeyToClass(protoKey);
RootedObject proto(cx);
- proto = clasp->spec.createPrototypeHook()(cx, protoKey);
+ proto = clasp->specCreatePrototypeHook()(cx, protoKey);
if (!proto)
return false;
- RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, protoKey));
+ RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, protoKey));
if (!ctor)
return false;
return GlobalObject::initBuiltinConstructor(cx, global, protoKey, ctor, proto);
}
/**
* The self-hosting global only gets a small subset of all standard classes.
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -180,16 +180,25 @@ RegExpObject::trace(JSTracer* trc, JSObj
!obj->asTenured().zone()->isPreservingCode())
{
obj->as<RegExpObject>().NativeObject::setPrivate(nullptr);
} else {
shared->trace(trc);
}
}
+static const ClassSpec RegExpObjectClassSpec = {
+ GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
+ CreateRegExpPrototype,
+ nullptr,
+ js::regexp_static_props,
+ js::regexp_methods,
+ js::regexp_properties
+};
+
const Class RegExpObject::class_ = {
js_RegExp_str,
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
@@ -197,26 +206,17 @@ const Class RegExpObject::class_ = {
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
RegExpObject::trace,
-
- // ClassSpec
- {
- GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
- CreateRegExpPrototype,
- nullptr,
- js::regexp_static_props,
- js::regexp_methods,
- js::regexp_properties
- }
+ &RegExpObjectClassSpec
};
RegExpObject*
RegExpObject::create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
TokenStream* tokenStream, LifoAlloc& alloc)
{
RootedAtom source(cx, AtomizeChars(cx, chars, length));
if (!source)
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -647,17 +647,17 @@ JSRuntime::requestInterrupt(InterruptMod
interrupt_ = true;
jitStackLimit_ = UINTPTR_MAX;
if (mode == JSRuntime::RequestInterruptUrgent) {
// If this interrupt is urgent (slow script dialog and garbage
// collection among others), take additional steps to
// interrupt corner cases where the above fields are not
// regularly polled. Wake both ilooping JIT code and
- // futexWait.
+ // Atomics.wait().
fx.lock();
if (fx.isWaiting())
fx.wake(FutexRuntime::WakeForJSInterrupt);
fx.unlock();
InterruptRunningJitCode(this);
}
}
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -956,17 +956,17 @@ struct JSRuntime : public JS::shadow::Ru
const JSLocaleCallbacks* localeCallbacks;
/* Default locale for Internationalization API */
char* defaultLocale;
/* Default JSVersion. */
JSVersion defaultVersion_;
- /* Futex state, used by futexWait and futexWake on the Atomics object */
+ /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */
js::FutexRuntime fx;
private:
/* See comment for JS_AbortIfWrongThread in jsapi.h. */
void* ownerThread_;
size_t ownerThreadNative_;
friend bool js::CurrentThreadCanAccessRuntime(JSRuntime* rt);
public:
--- a/js/src/vm/SavedFrame.h
+++ b/js/src/vm/SavedFrame.h
@@ -13,16 +13,18 @@
#include "js/UbiNode.h"
namespace js {
class SavedFrame : public NativeObject {
friend class SavedStacks;
friend struct ::JSStructuredCloneReader;
+ static const ClassSpec classSpec_;
+
public:
static const Class class_;
static const JSPropertySpec protoAccessors[];
static const JSFunctionSpec protoFunctions[];
static const JSFunctionSpec staticFunctions[];
// Prototype methods and properties to be exposed to JS.
static bool construct(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -284,16 +284,27 @@ SavedFrame::finishSavedFrameInit(JSConte
{
// The only object with the SavedFrame::class_ that doesn't have a source
// should be the prototype.
proto->as<NativeObject>().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
return FreezeObject(cx, proto);
}
+const ClassSpec SavedFrame::classSpec_ = {
+ GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
+ GenericCreatePrototype,
+ SavedFrame::staticFunctions,
+ nullptr,
+ SavedFrame::protoFunctions,
+ SavedFrame::protoAccessors,
+ SavedFrame::finishSavedFrameInit,
+ ClassSpec::DontDefineConstructor
+};
+
/* static */ const Class SavedFrame::class_ = {
"SavedFrame",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
JSCLASS_IS_ANONYMOUS,
nullptr, // addProperty
nullptr, // delProperty
@@ -302,28 +313,17 @@ SavedFrame::finishSavedFrameInit(JSConte
nullptr, // enumerate
nullptr, // resolve
nullptr, // mayResolve
SavedFrame::finalize, // finalize
nullptr, // call
nullptr, // hasInstance
nullptr, // construct
nullptr, // trace
-
- // ClassSpec
- {
- GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
- GenericCreatePrototype,
- SavedFrame::staticFunctions,
- nullptr,
- SavedFrame::protoFunctions,
- SavedFrame::protoAccessors,
- SavedFrame::finishSavedFrameInit,
- ClassSpec::DontDefineConstructor
- }
+ &SavedFrame::classSpec_
};
/* static */ const JSFunctionSpec
SavedFrame::staticFunctions[] = {
JS_FS_END
};
/* static */ const JSFunctionSpec
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -863,17 +863,17 @@ with_GetOwnPropertyDescriptor(JSContext*
static bool
with_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
{
MOZ_ASSERT(!JSID_IS_ATOM(id, cx->names().dotThis));
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
return DeleteProperty(cx, actual, id, result);
}
-const ObjectOps DynamicWithObject::objectOps_ = {
+static const ObjectOps DynamicWithObjectObjectOps = {
with_LookupProperty,
with_DefineProperty,
with_HasProperty,
with_GetProperty,
with_SetProperty,
with_GetOwnPropertyDescriptor,
with_DeleteProperty,
nullptr, nullptr, /* watch/unwatch */
@@ -895,17 +895,17 @@ const Class DynamicWithObject::class_ =
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
- &DynamicWithObject::objectOps_
+ &DynamicWithObjectObjectOps
};
/* static */ StaticEvalScope*
StaticEvalScope::create(JSContext* cx, HandleObject enclosing)
{
StaticEvalScope* obj =
NewObjectWithNullTaggedProto<StaticEvalScope>(cx, TenuredObject, BaseShape::DELEGATE);
if (!obj)
@@ -1119,30 +1119,16 @@ ClonedBlockObject::thisValue() const
return ObjectValue(*ToWindowProxyIfWindow(&v.toObject()));
}
return v;
}
static_assert(StaticBlockScope::RESERVED_SLOTS == ClonedBlockObject::RESERVED_SLOTS,
"static block scopes and dynamic block environments share a Class");
-const ObjectOps ClonedBlockObject::objectOps_ = {
- nullptr, /* lookupProperty */
- nullptr, /* defineProperty */
- nullptr, /* hasProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* getOwnPropertyDescriptor */
- nullptr, /* deleteProperty */
- nullptr, nullptr, /* watch/unwatch */
- nullptr, /* getElements */
- nullptr, /* enumerate (native enumeration of target doesn't work) */
- nullptr,
-};
-
const Class ClonedBlockObject::class_ = {
"Block",
JSCLASS_HAS_RESERVED_SLOTS(ClonedBlockObject::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS,
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
@@ -1151,17 +1137,17 @@ const Class ClonedBlockObject::class_ =
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
- &ClonedBlockObject::objectOps_
+ JS_NULL_OBJECT_OPS
};
template<XDRMode mode>
bool
js::XDRStaticBlockScope(XDRState<mode>* xdr, HandleObject enclosingScope,
MutableHandle<StaticBlockScope*> objp)
{
/* NB: Keep this in sync with CloneStaticBlockScope. */
@@ -1392,17 +1378,17 @@ lexicalError_GetOwnPropertyDescriptor(JS
static bool
lexicalError_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
{
ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
return false;
}
-const ObjectOps RuntimeLexicalErrorObject::objectOps_ = {
+static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
lexicalError_LookupProperty,
nullptr, /* defineProperty */
lexicalError_HasProperty,
lexicalError_GetProperty,
lexicalError_SetProperty,
lexicalError_GetOwnPropertyDescriptor,
lexicalError_DeleteProperty,
nullptr, nullptr, /* watch/unwatch */
@@ -1424,17 +1410,17 @@ const Class RuntimeLexicalErrorObject::c
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
- &RuntimeLexicalErrorObject::objectOps_
+ &RuntimeLexicalErrorObjectObjectOps
};
/*****************************************************************************/
// Any name atom for a function which will be added as a DeclEnv object to the
// scope chain above call objects for fun.
static inline JSAtom*
CallObjectLambdaName(JSFunction& fun)
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -811,18 +811,19 @@ class CallObject : public LexicalScopeBa
return CALLEE_SLOT;
}
};
class ModuleEnvironmentObject : public LexicalScopeBase
{
static const uint32_t MODULE_SLOT = 1;
+ static const ObjectOps objectOps_;
+
public:
- static const ObjectOps objectOps_;
static const Class class_;
static const uint32_t RESERVED_SLOTS = 2;
static ModuleEnvironmentObject* create(ExclusiveContext* cx, HandleModuleObject module);
ModuleObject& module();
IndirectBindingMap& importBindings();
@@ -907,17 +908,16 @@ class NestedScopeObject : public ScopeOb
class DynamicWithObject : public NestedScopeObject
{
static const unsigned OBJECT_SLOT = 1;
static const unsigned THIS_SLOT = 2;
static const unsigned KIND_SLOT = 3;
public:
static const unsigned RESERVED_SLOTS = 4;
- static const ObjectOps objectOps_;
static const Class class_;
enum WithKind {
SyntacticWith,
NonSyntacticWith
};
static DynamicWithObject*
@@ -1070,17 +1070,16 @@ class ClonedBlockObject : public NestedS
// ES6 'const' bindings induce a runtime error when assigned to outside
// of initialization, regardless of strictness.
class RuntimeLexicalErrorObject : public ScopeObject
{
static const unsigned ERROR_SLOT = 1;
public:
static const unsigned RESERVED_SLOTS = 2;
- static const ObjectOps objectOps_;
static const Class class_;
static RuntimeLexicalErrorObject* create(JSContext* cx, HandleObject enclosing,
unsigned errorNumber);
unsigned errorNumber() {
return getReservedSlot(ERROR_SLOT).toInt32();
}
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -856,16 +856,28 @@ TypedArrayObject::protoFunctions[] = {
/* static */ const JSFunctionSpec
TypedArrayObject::staticFunctions[] = {
JS_SELF_HOSTED_FN("from", "TypedArrayStaticFrom", 3, 0),
JS_SELF_HOSTED_FN("of", "TypedArrayStaticOf", 0, 0),
JS_FS_END
};
+static const ClassSpec
+TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
+ GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
+ GenericCreatePrototype,
+ TypedArrayObject::staticFunctions,
+ nullptr,
+ TypedArrayObject::protoFunctions,
+ TypedArrayObject::protoAccessors,
+ nullptr,
+ ClassSpec::DontDefineConstructor
+};
+
/* static */ const Class
TypedArrayObject::sharedTypedArrayPrototypeClass = {
// Actually ({}).toString.call(%TypedArray%.prototype) should throw,
// because %TypedArray%.prototype lacks the the typed array internal
// slots. (It's not clear this is desirable -- particularly applied to
// the actual typed array prototypes, see below -- but it's what ES6
// draft 20140824 requires.) But this is about as much as we can do
// until we implement @@toStringTag.
@@ -878,26 +890,17 @@ TypedArrayObject::sharedTypedArrayProtot
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
- {
- GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
- GenericCreatePrototype,
- TypedArrayObject::staticFunctions,
- nullptr,
- TypedArrayObject::protoFunctions,
- TypedArrayObject::protoAccessors,
- nullptr,
- ClassSpec::DontDefineConstructor
- }
+ &TypedArrayObjectSharedTypedArrayPrototypeClassSpec
};
template<typename T>
bool
ArrayBufferObject::createTypedArrayFromBufferImpl(JSContext* cx, const CallArgs& args)
{
typedef TypedArrayObjectTemplate<T> ArrayType;
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
@@ -1900,114 +1903,141 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uin
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped, uint8_t, uint8_clamped)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16, int16_t, int16_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16, uint16_t, uint16_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
-#define TYPED_ARRAY_CLASS_SPEC(_typedArray) \
+#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \
{ \
- _typedArray::createConstructor, \
- _typedArray::createPrototype, \
+ _type##Array::createConstructor, \
+ _type##Array::createPrototype, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
- _typedArray::finishClassInit, \
+ _type##Array::finishClassInit, \
JSProto_TypedArray \
}
-#define IMPL_TYPED_ARRAY_CLASS(_typedArray) \
+static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_CLASS(_type) \
{ \
- #_typedArray, \
+ #_type "Array", \
JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | \
JSCLASS_HAS_PRIVATE | \
- JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) | \
+ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \
JSCLASS_DELAY_METADATA_CALLBACK, \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
nullptr, /* getProperty */ \
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* finalize */ \
nullptr, /* call */ \
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
TypedArrayObject::trace, /* trace */ \
- TYPED_ARRAY_CLASS_SPEC(_typedArray) \
+ &TypedArrayObjectClassSpecs[Scalar::Type::_type] \
}
const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
- IMPL_TYPED_ARRAY_CLASS(Int8Array),
- IMPL_TYPED_ARRAY_CLASS(Uint8Array),
- IMPL_TYPED_ARRAY_CLASS(Int16Array),
- IMPL_TYPED_ARRAY_CLASS(Uint16Array),
- IMPL_TYPED_ARRAY_CLASS(Int32Array),
- IMPL_TYPED_ARRAY_CLASS(Uint32Array),
- IMPL_TYPED_ARRAY_CLASS(Float32Array),
- IMPL_TYPED_ARRAY_CLASS(Float64Array),
- IMPL_TYPED_ARRAY_CLASS(Uint8ClampedArray)
+ IMPL_TYPED_ARRAY_CLASS(Int8),
+ IMPL_TYPED_ARRAY_CLASS(Uint8),
+ IMPL_TYPED_ARRAY_CLASS(Int16),
+ IMPL_TYPED_ARRAY_CLASS(Uint16),
+ IMPL_TYPED_ARRAY_CLASS(Int32),
+ IMPL_TYPED_ARRAY_CLASS(Uint32),
+ IMPL_TYPED_ARRAY_CLASS(Float32),
+ IMPL_TYPED_ARRAY_CLASS(Float64),
+ IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(_type) \
+{ \
+ DELEGATED_CLASSSPEC(TypedArrayObject::classes[Scalar::Type::_type].spec), \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ JSProto_TypedArray | ClassSpec::IsDelegated \
+}
+
+static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped)
};
// The various typed array prototypes are supposed to 1) be normal objects,
// 2) stringify to "[object <name of constructor>]", and 3) (Gecko-specific)
// be xrayable. The first and second requirements mandate (in the absence of
// @@toStringTag) a custom class. The third requirement mandates that each
// prototype's class have the relevant typed array's cached JSProtoKey in them.
// Thus we need one class with cached prototype per kind of typed array, with a
// delegated ClassSpec.
-#define IMPL_TYPED_ARRAY_PROTO_CLASS(typedArray, i) \
+#define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \
{ \
/*
* Actually ({}).toString.call(Uint8Array.prototype) should throw, because
* Uint8Array.prototype lacks the the typed array internal slots. (Same as
* with %TypedArray%.prototype.) It's not clear this is desirable (see
* above), but it's what we've always done, so keep doing it till we
* implement @@toStringTag or ES6 changes.
*/ \
- #typedArray "Prototype", \
- JSCLASS_HAS_CACHED_PROTO(JSProto_##typedArray), \
+ #_type "ArrayPrototype", \
+ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
nullptr, /* getProperty */ \
nullptr, /* setProperty */ \
nullptr, /* enumerate */ \
nullptr, /* resolve */ \
nullptr, /* mayResolve */ \
nullptr, /* finalize */ \
nullptr, /* call */ \
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
nullptr, /* trace */ \
- { \
- DELEGATED_CLASSSPEC(&TypedArrayObject::classes[i].spec), \
- nullptr, \
- nullptr, \
- nullptr, \
- nullptr, \
- nullptr, \
- nullptr, \
- JSProto_TypedArray | ClassSpec::IsDelegated \
- } \
+ &TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \
}
const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
- IMPL_TYPED_ARRAY_PROTO_CLASS(Int8Array, 0),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Array, 1),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Int16Array, 2),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16Array, 3),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Int32Array, 4),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32Array, 5),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Float32Array, 6),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Float64Array, 7),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray, 8)
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
};
/* static */ bool
TypedArrayObject::isOriginalLengthGetter(Native native)
{
return native == TypedArray_lengthGetter;
}
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -115,17 +115,19 @@ class TypedArrayObject : public NativeOb
inline Scalar::Type type() const;
inline size_t bytesPerElement() const;
static Value bufferValue(TypedArrayObject* tarr) {
return tarr->getFixedSlot(BUFFER_SLOT);
}
static Value byteOffsetValue(TypedArrayObject* tarr) {
- return tarr->getFixedSlot(BYTEOFFSET_SLOT);
+ Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
}
static Value byteLengthValue(TypedArrayObject* tarr) {
return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
}
static Value lengthValue(TypedArrayObject* tarr) {
return tarr->getFixedSlot(LENGTH_SLOT);
}
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -900,17 +900,17 @@ UnboxedPlainObject::obj_enumerate(JSCont
return true;
}
const Class UnboxedExpandoObject::class_ = {
"UnboxedExpandoObject",
0
};
-const ObjectOps UnboxedPlainObject::objectOps_ = {
+static const ObjectOps UnboxedPlainObjectObjectOps = {
UnboxedPlainObject::obj_lookupProperty,
UnboxedPlainObject::obj_defineProperty,
UnboxedPlainObject::obj_hasProperty,
UnboxedPlainObject::obj_getProperty,
UnboxedPlainObject::obj_setProperty,
UnboxedPlainObject::obj_getOwnPropertyDescriptor,
UnboxedPlainObject::obj_deleteProperty,
UnboxedPlainObject::obj_watch,
@@ -934,17 +934,17 @@ const Class UnboxedPlainObject::class_ =
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
UnboxedPlainObject::trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
- &UnboxedPlainObject::objectOps_
+ &UnboxedPlainObjectObjectOps
};
/////////////////////////////////////////////////////////////////////
// UnboxedArrayObject
/////////////////////////////////////////////////////////////////////
template <JSValueType Type>
DenseElementResult
@@ -1586,17 +1586,17 @@ UnboxedArrayObject::obj_enumerate(JSCont
}
if (!enumerableOnly && !properties.append(NameToId(cx->names().length)))
return false;
return true;
}
-const ObjectOps UnboxedArrayObject::objectOps_ = {
+static const ObjectOps UnboxedArrayObjectObjectOps = {
UnboxedArrayObject::obj_lookupProperty,
UnboxedArrayObject::obj_defineProperty,
UnboxedArrayObject::obj_hasProperty,
UnboxedArrayObject::obj_getProperty,
UnboxedArrayObject::obj_setProperty,
UnboxedArrayObject::obj_getOwnPropertyDescriptor,
UnboxedArrayObject::obj_deleteProperty,
UnboxedArrayObject::obj_watch,
@@ -1624,17 +1624,17 @@ const Class UnboxedArrayObject::class_ =
nullptr, /* construct */
UnboxedArrayObject::trace,
JS_NULL_CLASS_SPEC,
{
false, /* isWrappedNative */
nullptr, /* weakmapKeyDelegateOp */
UnboxedArrayObject::objectMoved
},
- &UnboxedArrayObject::objectOps_
+ &UnboxedArrayObjectObjectOps
};
/////////////////////////////////////////////////////////////////////
// API
/////////////////////////////////////////////////////////////////////
static bool
UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype)
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -233,17 +233,16 @@ class UnboxedPlainObject : public JSObje
// not automatically barriered to avoid problems if the object is converted
// to a native. See ensureExpando().
UnboxedExpandoObject* expando_;
// Start of the inline data, which immediately follows the group and extra properties.
uint8_t data_[1];
public:
- static const ObjectOps objectOps_;
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
@@ -370,17 +369,16 @@ class UnboxedArrayObject : public JSObje
return length;
return CapacityArray[index];
}
static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
static uint32_t exactCapacityIndex(uint32_t capacity);
public:
- static const ObjectOps objectOps_;
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
--- a/js/xpconnect/idl/nsIScriptError.idl
+++ b/js/xpconnect/idl/nsIScriptError.idl
@@ -10,17 +10,17 @@
#include "nsISupports.idl"
#include "nsIConsoleMessage.idl"
%{C++
#include "nsStringGlue.h" // for nsDependentCString
%}
-[scriptable, uuid(18bdefde-e57b-11e4-832a-000c29a57fff)]
+[scriptable, uuid(361be358-76f0-47aa-b37b-6ad833599e8d)]
interface nsIScriptError : nsIConsoleMessage
{
/** pseudo-flag for default case */
const unsigned long errorFlag = 0x0;
/** message is warning */
const unsigned long warningFlag = 0x1;
@@ -63,16 +63,23 @@ interface nsIScriptError : nsIConsoleMes
/* Get the inner window id this was initialized with. Zero will be
returned if init() was used instead of initWithWindowID(). */
readonly attribute unsigned long long innerWindowID;
readonly attribute boolean isFromPrivateWindow;
attribute jsval stack;
+ /**
+ * The name of a template string, as found in js.msg, associated with the
+ * error message.
+ */
+ attribute AString errorMessageName;
+
+
void init(in AString message,
in AString sourceName,
in AString sourceLine,
in uint32_t lineNumber,
in uint32_t columnNumber,
in uint32_t flags,
in string category);
--- a/js/xpconnect/src/nsScriptError.cpp
+++ b/js/xpconnect/src/nsScriptError.cpp
@@ -16,16 +16,17 @@
#include "nsGlobalWindow.h"
#include "nsPIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIDocShell.h"
#include "nsISensitiveInfoHiddenURI.h"
nsScriptErrorBase::nsScriptErrorBase()
: mMessage(),
+ mMessageName(),
mSourceName(),
mLineNumber(0),
mSourceLine(),
mColumnNumber(0),
mFlags(0),
mCategory(),
mOuterWindowID(0),
mInnerWindowID(0),
@@ -148,16 +149,28 @@ nsScriptErrorBase::GetStack(JS::MutableH
}
NS_IMETHODIMP
nsScriptErrorBase::SetStack(JS::HandleValue aStack) {
return NS_OK;
}
NS_IMETHODIMP
+nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) {
+ aErrorMessageName = mMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
+ mMessageName = aErrorMessageName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsScriptErrorBase::Init(const nsAString& message,
const nsAString& sourceName,
const nsAString& sourceLine,
uint32_t lineNumber,
uint32_t columnNumber,
uint32_t flags,
const char* category)
{
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -26,16 +26,18 @@
#include "nsDOMMutationObserver.h"
#include "nsICycleCollectorListener.h"
#include "mozilla/XPTInterfaceInfoManager.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsScriptSecurityManager.h"
+#include "jsfriendapi.h"
+
using namespace mozilla;
using namespace mozilla::dom;
using namespace xpc;
using namespace JS;
NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
nsXPConnect* nsXPConnect::gSelf = nullptr;
@@ -173,28 +175,34 @@ void
xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aFallbackMessage,
bool aIsChrome, uint64_t aWindowID)
{
mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
: NS_LITERAL_CSTRING("content javascript");
mWindowID = aWindowID;
ErrorReportToMessageString(aReport, mErrorMsg);
-
if (mErrorMsg.IsEmpty() && aFallbackMessage) {
mErrorMsg.AssignWithConversion(aFallbackMessage);
}
if (!aReport->filename) {
mFileName.SetIsVoid(true);
} else {
mFileName.AssignWithConversion(aReport->filename);
}
mSourceLine.Assign(aReport->linebuf(), aReport->linebufLength());
+ const JSErrorFormatString* efs = js::GetErrorMessage(nullptr, aReport->errorNumber);
+
+ if (efs == nullptr) {
+ mErrorMsgName.AssignASCII("");
+ } else {
+ mErrorMsgName.AssignASCII(efs->name);
+ }
mLineNumber = aReport->lineno;
mColumn = aReport->column;
mFlags = aReport->flags;
mIsMuted = aReport->isMuted;
}
static LazyLogModule gJSDiagnostics("JSDiagnostics");
@@ -243,16 +251,17 @@ xpc::ErrorReport::LogToConsoleWithStack(
// Only set stack on messages related to a document
// As we cache messages in the console service,
// we have to ensure not leaking them after the related
// context is destroyed and we only track document lifecycle for now.
errorObject = new nsScriptErrorWithStack(aStack);
} else {
errorObject = new nsScriptError();
}
+ errorObject->SetErrorMessageName(mErrorMsgName);
NS_ENSURE_TRUE_VOID(consoleService && errorObject);
nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine,
mLineNumber, mColumn, mFlags,
mCategory, mWindowID);
NS_ENSURE_SUCCESS_VOID(rv);
consoleService->LogMessage(errorObject);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2938,16 +2938,17 @@ public:
protected:
virtual ~nsScriptErrorBase();
void
InitializeOnMainThread();
nsString mMessage;
+ nsString mMessageName;
nsString mSourceName;
uint32_t mLineNumber;
nsString mSourceLine;
uint32_t mColumnNumber;
uint32_t mFlags;
nsCString mCategory;
// mOuterWindowID is set on the main thread from InitializeOnMainThread().
uint64_t mOuterWindowID;
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -515,16 +515,17 @@ class ErrorReport {
// that this may produce an empty string if aReport doesn't have a
// message attached.
static void ErrorReportToMessageString(JSErrorReport* aReport,
nsAString& aString);
public:
nsCString mCategory;
+ nsString mErrorMsgName;
nsString mErrorMsg;
nsString mFileName;
nsString mSourceLine;
uint64_t mWindowID;
uint32_t mLineNumber;
uint32_t mColumn;
uint32_t mFlags;
bool mIsMuted;
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -568,21 +568,21 @@ JSXrayTraits::resolveOwnProperty(JSConte
return false;
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
ObjectValue(*standardProto));
return true;
}
if (ShouldResolveStaticProperties(standardConstructor)) {
const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
- MOZ_ASSERT(clasp->spec.defined());
+ MOZ_ASSERT(clasp->specDefined());
if (!TryResolvePropertyFromSpecs(cx, id, holder,
- clasp->spec.constructorFunctions(),
- clasp->spec.constructorProperties(), desc)) {
+ clasp->specConstructorFunctions(),
+ clasp->specConstructorProperties(), desc)) {
return false;
}
if (desc.object()) {
desc.object().set(wrapper);
return true;
}
}
@@ -651,23 +651,23 @@ JSXrayTraits::resolveOwnProperty(JSConte
}
// Handle the 'lastIndex' property for RegExp prototypes.
if (key == JSProto_RegExp && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX))
return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc);
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
const js::Class* clasp = js::GetObjectClass(target);
- MOZ_ASSERT(clasp->spec.defined());
+ MOZ_ASSERT(clasp->specDefined());
// Indexed array properties are handled above, so we can just work with the
// class spec here.
if (!TryResolvePropertyFromSpecs(cx, id, holder,
- clasp->spec.prototypeFunctions(),
- clasp->spec.prototypeProperties(),
+ clasp->specPrototypeFunctions(),
+ clasp->specPrototypeProperties(),
desc)) {
return false;
}
if (desc.object()) {
desc.object().set(wrapper);
}
@@ -859,21 +859,21 @@ JSXrayTraits::enumerateNames(JSContext*
// constructors.
JSProtoKey standardConstructor = constructorFor(holder);
if (standardConstructor != JSProto_Null) {
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)))
return false;
if (ShouldResolveStaticProperties(standardConstructor)) {
const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
- MOZ_ASSERT(clasp->spec.defined());
+ MOZ_ASSERT(clasp->specDefined());
if (!AppendNamesFromFunctionAndPropertySpecs(
- cx, clasp->spec.constructorFunctions(),
- clasp->spec.constructorProperties(), flags, props)) {
+ cx, clasp->specConstructorFunctions(),
+ clasp->specConstructorProperties(), flags, props)) {
return false;
}
}
}
} else if (IsErrorObjectKey(key)) {
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_FILENAME)) ||
!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LINENUMBER)) ||
!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_COLUMNNUMBER)) ||
@@ -900,21 +900,21 @@ JSXrayTraits::enumerateNames(JSContext*
return false;
// For RegExp protoypes, add the 'lastIndex' property.
if (key == JSProto_RegExp && !props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)))
return false;
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
const js::Class* clasp = js::GetObjectClass(target);
- MOZ_ASSERT(clasp->spec.defined());
+ MOZ_ASSERT(clasp->specDefined());
return AppendNamesFromFunctionAndPropertySpecs(
- cx, clasp->spec.prototypeFunctions(),
- clasp->spec.prototypeProperties(), flags, props);
+ cx, clasp->specPrototypeFunctions(),
+ clasp->specPrototypeProperties(), flags, props);
}
bool
JSXrayTraits::construct(JSContext* cx, HandleObject wrapper,
const JS::CallArgs& args, const js::Wrapper& baseInstance)
{
JSXrayTraits& self = JSXrayTraits::singleton;
JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));
--- a/layout/base/AccessibleCaretEventHub.cpp
+++ b/layout/base/AccessibleCaretEventHub.cpp
@@ -540,25 +540,25 @@ AccessibleCaretEventHub::HandleMouseEven
}
return rv;
}
nsEventStatus
AccessibleCaretEventHub::HandleTouchEvent(WidgetTouchEvent* aEvent)
{
- if (aEvent->touches.IsEmpty()) {
+ if (aEvent->mTouches.IsEmpty()) {
AC_LOG("%s: Receive a touch event without any touch data!", __FUNCTION__);
return nsEventStatus_eIgnore;
}
nsEventStatus rv = nsEventStatus_eIgnore;
int32_t id =
- (mActiveTouchId == kInvalidTouchId ? aEvent->touches[0]->Identifier()
+ (mActiveTouchId == kInvalidTouchId ? aEvent->mTouches[0]->Identifier()
: mActiveTouchId);
nsPoint point = GetTouchEventPosition(aEvent, id);
switch (aEvent->mMessage) {
case eTouchStart:
AC_LOGV("Before eTouchStart, state: %s", mState->Name());
rv = mState->OnPress(this, point, id);
AC_LOGV("After eTouchStart, state: %s, consume: %d", mState->Name(), rv);
@@ -776,17 +776,17 @@ AccessibleCaretEventHub::NotifyBlur(bool
AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
mState->OnBlur(this, aIsLeavingDocument);
}
nsPoint
AccessibleCaretEventHub::GetTouchEventPosition(WidgetTouchEvent* aEvent,
int32_t aIdentifier) const
{
- for (dom::Touch* touch : aEvent->touches) {
+ for (dom::Touch* touch : aEvent->mTouches) {
if (touch->Identifier() == aIdentifier) {
LayoutDeviceIntPoint touchIntPoint = touch->mRefPoint;
// Get event coordinate relative to root frame.
nsIFrame* rootFrame = mPresShell->GetRootFrame();
return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touchIntPoint,
rootFrame);
}
--- a/layout/base/TouchManager.cpp
+++ b/layout/base/TouchManager.cpp
@@ -62,17 +62,17 @@ EvictTouchPoint(RefPtr<dom::Touch>& aTou
nsIFrame* frame = presShell->GetRootFrame();
if (frame) {
nsPoint pt(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
nsCOMPtr<nsIWidget> widget = frame->GetView()->GetNearestWidget(&pt);
if (widget) {
WidgetTouchEvent event(true, eTouchEnd, widget);
event.widget = widget;
event.mTime = PR_IntervalNow();
- event.touches.AppendElement(aTouch);
+ event.mTouches.AppendElement(aTouch);
nsEventStatus status;
widget->DispatchEvent(&event, status);
return;
}
}
}
}
}
@@ -113,40 +113,40 @@ TouchManager::PreHandleEvent(WidgetEvent
{
switch (aEvent->mMessage) {
case eTouchStart: {
aIsHandlingUserInput = true;
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// if there is only one touch in this touchstart event, assume that it is
// the start of a new touch session and evict any old touches in the
// queue
- if (touchEvent->touches.Length() == 1) {
+ if (touchEvent->mTouches.Length() == 1) {
WidgetTouchEvent::AutoTouchArray touches;
AppendToTouchList(&touches);
for (uint32_t i = 0; i < touches.Length(); ++i) {
EvictTouchPoint(touches[i]);
}
}
// Add any new touches to the queue
- for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
- dom::Touch* touch = touchEvent->touches[i];
+ for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
+ dom::Touch* touch = touchEvent->mTouches[i];
int32_t id = touch->Identifier();
if (!gCaptureTouchList->Get(id, nullptr)) {
// If it is not already in the queue, it is a new touch
touch->mChanged = true;
}
touch->mMessage = aEvent->mMessage;
gCaptureTouchList->Put(id, touch);
}
break;
}
case eTouchMove: {
// Check for touches that changed. Mark them add to queue
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
- WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
+ WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
bool haveChanged = false;
for (int32_t i = touches.Length(); i; ) {
--i;
dom::Touch* touch = touches[i];
if (!touch) {
continue;
}
int32_t id = touch->Identifier();
@@ -180,19 +180,19 @@ TouchManager::PreHandleEvent(WidgetEvent
if (!haveChanged) {
if (aTouchIsNew) {
// however, if this is the first touchmove after a touchstart,
// it is special in that preventDefault is allowed on it, so
// we must dispatch it to content even if nothing changed. we
// arbitrarily pick the first touch point to be the "changed"
// touch because firing an event with no changed events doesn't
// work.
- for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
- if (touchEvent->touches[i]) {
- touchEvent->touches[i]->mChanged = true;
+ for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
+ if (touchEvent->mTouches[i]) {
+ touchEvent->mTouches[i]->mChanged = true;
break;
}
}
} else {
return false;
}
}
break;
@@ -200,17 +200,17 @@ TouchManager::PreHandleEvent(WidgetEvent
case eTouchEnd:
aIsHandlingUserInput = true;
// Fall through to touchcancel code
MOZ_FALLTHROUGH;
case eTouchCancel: {
// Remove the changed touches
// need to make sure we only remove touches that are ending here
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
- WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
+ WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
dom::Touch* touch = touches[i];
if (!touch) {
continue;
}
touch->mMessage = aEvent->mMessage;
touch->mChanged = true;
--- a/layout/base/gtest/TestAccessibleCaretEventHub.cpp
+++ b/layout/base/gtest/TestAccessibleCaretEventHub.cpp
@@ -69,17 +69,17 @@ public:
mManager = MakeUnique<MockAccessibleCaretManager>();
mInitialized = true;
}
virtual nsPoint GetTouchEventPosition(WidgetTouchEvent* aEvent,
int32_t aIdentifier) const override
{
// Return the device point directly.
- LayoutDeviceIntPoint touchIntPoint = aEvent->touches[0]->mRefPoint;
+ LayoutDeviceIntPoint touchIntPoint = aEvent->mTouches[0]->mRefPoint;
return nsPoint(touchIntPoint.x, touchIntPoint.y);
}
virtual nsPoint GetMouseEventPosition(WidgetMouseEvent* aEvent) const override
{
// Return the device point directly.
LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->refPoint;
return nsPoint(mouseIntPoint.x, mouseIntPoint.y);
@@ -158,17 +158,17 @@ public:
int32_t identifier = 0;
LayoutDeviceIntPoint point(aX, aY);
LayoutDeviceIntPoint radius(19, 19);
float rotationAngle = 0;
float force = 1;
RefPtr<dom::Touch> touch(
new dom::Touch(identifier, point, radius, rotationAngle, force));
- event->touches.AppendElement(touch);
+ event->mTouches.AppendElement(touch);
return Move(event);
}
static UniquePtr<WidgetEvent> CreateTouchStartEvent(nscoord aX, nscoord aY)
{
return CreateTouchEvent(eTouchStart, aX, aY);
}
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1980,17 +1980,20 @@ nsCSSRendering::DetermineBackgroundColor
nsStyleContext* aStyleContext,
nsIFrame* aFrame,
bool& aDrawBackgroundImage,
bool& aDrawBackgroundColor)
{
aDrawBackgroundImage = true;
aDrawBackgroundColor = true;
- if (aFrame->HonorPrintBackgroundSettings()) {
+ const nsStyleVisibility* visibility = aStyleContext->StyleVisibility();
+
+ if (visibility->mColorAdjust != NS_STYLE_COLOR_ADJUST_EXACT &&
+ aFrame->HonorPrintBackgroundSettings()) {
aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
}
const nsStyleBackground *bg = aStyleContext->StyleBackground();
nscolor bgColor;
if (aDrawBackgroundColor) {
bgColor =
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1056,16 +1056,26 @@ GetDisplayPortFromMarginsData(nsIContent
nsRect expandedScrollableRect =
nsLayoutUtils::CalculateExpandedScrollableRect(frame);
result = result.MoveInsideAndClamp(expandedScrollableRect - scrollPos);
return result;
}
static bool
+ShouldDisableApzForElement(nsIContent* aContent)
+{
+ if (gfxPrefs::APZDisableForScrollLinkedEffects() && aContent) {
+ nsIDocument* doc = aContent->GetComposedDoc();
+ return (doc && doc->HasScrollLinkedEffect());
+ }
+ return false;
+}
+
+static bool
GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier)
{
DisplayPortPropertyData* rectData =
static_cast<DisplayPortPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPort));
DisplayPortMarginsPropertyData* marginsData =
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
if (!rectData && !marginsData) {
@@ -1089,17 +1099,17 @@ GetDisplayPortImpl(nsIContent* aContent,
}
NS_ASSERTION((rectData == nullptr) != (marginsData == nullptr),
"Only one of rectData or marginsData should be set!");
nsRect result;
if (rectData) {
result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
- } else if (APZCCallbackHelper::IsDisplayportSuppressed()) {
+ } else if (APZCCallbackHelper::IsDisplayportSuppressed() || ShouldDisableApzForElement(aContent)) {
DisplayPortMarginsPropertyData noMargins(ScreenMargin(), 1);
result = GetDisplayPortFromMarginsData(aContent, &noMargins, aMultiplier);
} else {
result = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
}
if (!gfxPrefs::LayersTilesEnabled()) {
// Either we should have gotten a valid rect directly from the displayport
@@ -8796,16 +8806,20 @@ nsLayoutUtils::ComputeScrollMetadata(nsI
nsStyleContext* backgroundStyle;
if (nsCSSRendering::FindBackground(aScrollFrame, &backgroundStyle)) {
metrics.SetBackgroundColor(Color::FromABGR(
backgroundStyle->StyleBackground()->mBackgroundColor));
}
}
}
+ if (ShouldDisableApzForElement(aContent)) {
+ metrics.SetForceDisableApz(true);
+ }
+
return metadata;
}
/* static */ bool
nsLayoutUtils::ContainsMetricsWithId(const Layer* aLayer, const ViewID& aScrollId)
{
for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) {
if (aLayer->GetFrameMetrics(i-1).GetScrollId() == aScrollId) {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6886,18 +6886,18 @@ DispatchPointerFromMouseOrTouch(PresShel
break;
case eTouchCancel:
pointerMessage = ePointerCancel;
break;
default:
return NS_OK;
}
- for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
- mozilla::dom::Touch* touch = touchEvent->touches[i];
+ for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
+ mozilla::dom::Touch* touch = touchEvent->mTouches[i];
if (!touch || !touch->convertToPointer) {
continue;
}
WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
touchEvent->widget);
event.isPrimary = i == 0;
event.pointerId = touch->Identifier();
@@ -7539,34 +7539,35 @@ PresShell::HandleEvent(nsIFrame* aFrame,
uint32_t flags = 0;
if (aEvent->mMessage == eTouchStart) {
flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// if this is a continuing session, ensure that all these events are
// in the same document by taking the target of the events already in
// the capture list
nsCOMPtr<nsIContent> anyTarget;
- if (TouchManager::gCaptureTouchList->Count() > 0 && touchEvent->touches.Length() > 1) {
+ if (TouchManager::gCaptureTouchList->Count() > 0 &&
+ touchEvent->mTouches.Length() > 1) {
for (auto iter = TouchManager::gCaptureTouchList->Iter();
!iter.Done();
iter.Next()) {
RefPtr<dom::Touch>& touch = iter.Data();
if (touch) {
dom::EventTarget* target = touch->GetTarget();
if (target) {
anyTarget = do_QueryInterface(target);
break;
}
}
}
}
- for (int32_t i = touchEvent->touches.Length(); i; ) {
+ for (int32_t i = touchEvent->mTouches.Length(); i; ) {
--i;
- dom::Touch* touch = touchEvent->touches[i];
+ dom::Touch* touch = touchEvent->mTouches[i];
int32_t id = touch->Identifier();
if (!TouchManager::gCaptureTouchList->Get(id, nullptr)) {
// find the target for this touch
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
touch->mRefPoint,
frame);
nsIFrame* target = FindFrameTargetedByInputEvent(aEvent,
@@ -7590,20 +7591,20 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// We must be in a subdocument so jump directly to the root frame.
// GetParentOrPlaceholderForCrossDoc gets called immediately to
// jump up to the containing document.
f = f->PresContext()->GetPresShell()->GetRootFrame();
}
// if we couldn't find a target frame in the same document as
// anyTarget, remove the touch from the capture touch list, as
- // well as the event->touches array. touchmove events that aren't
+ // well as the event->mTouches array. touchmove events that aren't
// in the captured touch list will be discarded
if (!newTargetFrame) {
- touchEvent->touches.RemoveElementAt(i);
+ touchEvent->mTouches.RemoveElementAt(i);
} else {
target = newTargetFrame;
nsCOMPtr<nsIContent> targetContent;
target->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
while (targetContent && !targetContent->IsElement()) {
targetContent = targetContent->GetParent();
}
touch->SetTarget(targetContent);
@@ -7723,17 +7724,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
PresShell* shell =
static_cast<PresShell*>(frame->PresContext()->PresShell());
switch (aEvent->mMessage) {
case eTouchMove:
case eTouchCancel:
case eTouchEnd: {
// get the correct shell to dispatch to
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
- for (dom::Touch* touch : touchEvent->touches) {
+ for (dom::Touch* touch : touchEvent->mTouches) {
if (!touch) {
break;
}
RefPtr<dom::Touch> oldTouch =
TouchManager::gCaptureTouchList->GetWeak(touch->Identifier());
if (!oldTouch) {
break;
@@ -8336,17 +8337,17 @@ PresShell::DispatchTouchEventToDOM(Widge
bool canPrevent = (aEvent->mMessage == eTouchStart) ||
(aEvent->mMessage == eTouchMove && aTouchIsNew) ||
(aEvent->mMessage == eTouchEnd);
bool preventDefault = false;
nsEventStatus tmpStatus = nsEventStatus_eIgnore;
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// loop over all touches and dispatch events on any that have changed
- for (dom::Touch* touch : touchEvent->touches) {
+ for (dom::Touch* touch : touchEvent->mTouches) {
if (!touch || !touch->mChanged) {
continue;
}
nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
if (!content) {
continue;
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -530,19 +530,19 @@ nsRangeFrame::GetValueAtEventPoint(Widge
"type=range should have a default maximum/minimum");
if (maximum <= minimum) {
return minimum;
}
Decimal range = maximum - minimum;
LayoutDeviceIntPoint absPoint;
if (aEvent->mClass == eTouchEventClass) {
- MOZ_ASSERT(aEvent->AsTouchEvent()->touches.Length() == 1,
- "Unexpected number of touches");
- absPoint = aEvent->AsTouchEvent()->touches[0]->mRefPoint;
+ MOZ_ASSERT(aEvent->AsTouchEvent()->mTouches.Length() == 1,
+ "Unexpected number of mTouches");
+ absPoint = aEvent->AsTouchEvent()->mTouches[0]->mRefPoint;
} else {
absPoint = aEvent->refPoint;
}
nsPoint point =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, absPoint, this);
if (point == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
// We don't want to change the current value for this error state.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/disable-apz-for-sle-pages-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>Check that the apz.disable_for_sle_pages pref behaves as expected</title>
+ <script>
+ addEventListener('load', function() {
+ window.scrollTo(0, 100);
+ setTimeout(done, 0);
+ }, false);
+
+ function done() {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ </script>
+ </head>
+ <body style="height: 5000px; background-image:url(repeatable-diagonal-gradient.png);">
+ <div id="fake-fixed" style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px; background-color: green"></div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/disable-apz-for-sle-pages.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait" reftest-async-scroll
+ reftest-async-scroll-y="200">
+ <head>
+ <title>Check that the apz.disable_for_sle_pages pref behaves as expected</title>
+ <script>
+ // Upon load, this page scrolls to (0, 100). This triggers a scroll event,
+ // which runs the scroll listener below. The scroll listener updates the
+ // position of the div to simulate position:fixed using a scroll-linked
+ // effect. The scroll-linked effect detector should then report that the
+ // document contains such an effect, which will disable APZ on the page.
+ // That in turn will cause the reftest-async-scroll-y to get ignored, and
+ // that's what the reftest checks for.
+
+ addEventListener('scroll', function() {
+ document.getElementById('fake-fixed').style.top = window.scrollY + "px";
+ }, false);
+
+ addEventListener('load', function() {
+ window.scrollTo(0, 100);
+ setTimeout(done, 0);
+ }, false);
+
+ function done() {
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ </script>
+ </head>
+ <body style="height: 5000px; background-image:url(repeatable-diagonal-gradient.png);">
+ <div id="fake-fixed" style="position: absolute; top: 0; left: 100px; width: 100px; height: 100px; background-color: green"></div>
+ </body>
+</html>
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -34,16 +34,17 @@ skip-if(!asyncPan) == position-sticky-tr
skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
+pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html
# for the following tests, we want to disable the low-precision buffer
# as it will expand the displayport beyond what the test specifies in
# its reftest-displayport attributes, and interfere with where we expect
# checkerboarding to occur
default-preferences pref(layers.low-precision-buffer,false)
skip-if(!asyncPan) == checkerboard-1.html checkerboard-1-ref.html
skip-if(!asyncPan) == checkerboard-2.html checkerboard-2-ref.html
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -243,26 +243,28 @@ CSS_KEY(double-circle, double_circle)
CSS_KEY(double-struck, double_struck)
CSS_KEY(drag, drag)
CSS_KEY(drop-shadow, drop_shadow)
CSS_KEY(e-resize, e_resize)
CSS_KEY(ease, ease)
CSS_KEY(ease-in, ease_in)
CSS_KEY(ease-in-out, ease_in_out)
CSS_KEY(ease-out, ease_out)
+CSS_KEY(economy, economy)
CSS_KEY(element, element)
CSS_KEY(elements, elements)
CSS_KEY(ellipse, ellipse)
CSS_KEY(ellipsis, ellipsis)
CSS_KEY(em, em)
CSS_KEY(embed, embed)
CSS_KEY(enabled, enabled)
CSS_KEY(end, end)
CSS_KEY(ethiopic-numeric, ethiopic_numeric)
CSS_KEY(ex, ex)
+CSS_KEY(exact, exact)
CSS_KEY(exclude, exclude)
CSS_KEY(exclusion, exclusion)
CSS_KEY(expanded, expanded)
CSS_KEY(extends, extends)
CSS_KEY(extra-condensed, extra_condensed)
CSS_KEY(extra-expanded, extra_expanded)
CSS_KEY(ew-resize, ew_resize)
CSS_KEY(fallback, fallback)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1383,16 +1383,26 @@ CSS_PROP_COLOR(
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
CSS_PROPERTY_HASHLESS_COLOR_QUIRK,
"",
VARIANT_HC,
nullptr,
offsetof(nsStyleColor, mColor),
eStyleAnimType_Color)
+CSS_PROP_VISIBILITY(
+ color-adjust,
+ color_adjust,
+ ColorAdjust,
+ CSS_PROPERTY_PARSE_VALUE,
+ "layout.css.color-adjust.enabled",
+ VARIANT_HK,
+ kColorAdjustKTable,
+ CSS_PROP_NO_OFFSET,
+ eStyleAnimType_None)
CSS_PROP_SHORTHAND(
-moz-columns,
_moz_columns,
CSS_PROP_DOMPROP_PREFIXED(Columns),
CSS_PROPERTY_PARSE_FUNCTION,
"")
CSS_PROP_COLUMN(
-moz-column-count,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2361,16 +2361,22 @@ const KTableEntry nsCSSProps::kTextRende
};
const KTableEntry nsCSSProps::kVectorEffectKTable[] = {
{ eCSSKeyword_none, NS_STYLE_VECTOR_EFFECT_NONE },
{ eCSSKeyword_non_scaling_stroke, NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE },
{ eCSSKeyword_UNKNOWN, -1 }
};
+const KTableEntry nsCSSProps::kColorAdjustKTable[] = {
+ { eCSSKeyword_economy, NS_STYLE_COLOR_ADJUST_ECONOMY },
+ { eCSSKeyword_exact, NS_STYLE_COLOR_ADJUST_EXACT },
+ { eCSSKeyword_UNKNOWN, -1 }
+};
+
const KTableEntry nsCSSProps::kColorInterpolationKTable[] = {
{ eCSSKeyword_auto, NS_STYLE_COLOR_INTERPOLATION_AUTO },
{ eCSSKeyword_srgb, NS_STYLE_COLOR_INTERPOLATION_SRGB },
{ eCSSKeyword_linearrgb, NS_STYLE_COLOR_INTERPOLATION_LINEARRGB },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kColumnFillKTable[] = {
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -702,16 +702,17 @@ public:
static const KTableEntry kImageRenderingKTable[];
static const KTableEntry kShapeRenderingKTable[];
static const KTableEntry kStrokeLinecapKTable[];
static const KTableEntry kStrokeLinejoinKTable[];
static const KTableEntry kStrokeContextValueKTable[];
static const KTableEntry kVectorEffectKTable[];
static const KTableEntry kTextAnchorKTable[];
static const KTableEntry kTextRenderingKTable[];
+ static const KTableEntry kColorAdjustKTable[];
static const KTableEntry kColorInterpolationKTable[];
static const KTableEntry kColumnFillKTable[];
static const KTableEntry kBoxPropSourceKTable[];
static const KTableEntry kBoxShadowTypeKTable[];
static const KTableEntry kBoxSizingKTable[];
static const KTableEntry kCaptionSideKTable[];
// Not const because we modify its entries when the pref
// "layout.css.float-logical-values.enabled" changes:
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -975,16 +975,26 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetColor()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetToRGBAColor(val, StyleColor()->mColor);
return val.forget();
}
already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColorAdjust()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mColorAdjust,
+ nsCSSProps::kColorAdjustKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetOpacity()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetNumber(StyleDisplay()->mOpacity);
return val.forget();
}
already_AddRefed<CSSValue>
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -423,16 +423,17 @@ private:
already_AddRefed<CSSValue> DoGetWordBreak();
already_AddRefed<CSSValue> DoGetWordWrap();
already_AddRefed<CSSValue> DoGetHyphens();
already_AddRefed<CSSValue> DoGetTabSize();
already_AddRefed<CSSValue> DoGetTextSizeAdjust();
already_AddRefed<CSSValue> DoGetWebkitTextFillColor();
/* Visibility properties */
+ already_AddRefed<CSSValue> DoGetColorAdjust();
already_AddRefed<CSSValue> DoGetOpacity();
already_AddRefed<CSSValue> DoGetPointerEvents();
already_AddRefed<CSSValue> DoGetVisibility();
already_AddRefed<CSSValue> DoGetWritingMode();
/* Direction properties */
already_AddRefed<CSSValue> DoGetDirection();
already_AddRefed<CSSValue> DoGetUnicodeBidi();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -97,16 +97,17 @@ COMPUTED_STYLE_PROP(border_top_width,
COMPUTED_STYLE_PROP(bottom, Bottom)
COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak)
COMPUTED_STYLE_PROP(box_shadow, BoxShadow)
COMPUTED_STYLE_PROP(box_sizing, BoxSizing)
COMPUTED_STYLE_PROP(caption_side, CaptionSide)
COMPUTED_STYLE_PROP(clear, Clear)
COMPUTED_STYLE_PROP(clip, Clip)
COMPUTED_STYLE_PROP(color, Color)
+COMPUTED_STYLE_PROP(color_adjust, ColorAdjust)
COMPUTED_STYLE_PROP(contain, Contain)
COMPUTED_STYLE_PROP(content, Content)
COMPUTED_STYLE_PROP(counter_increment, CounterIncrement)
COMPUTED_STYLE_PROP(counter_reset, CounterReset)
COMPUTED_STYLE_PROP(cursor, Cursor)
COMPUTED_STYLE_PROP(direction, Direction)
COMPUTED_STYLE_PROP(display, Display)
COMPUTED_STYLE_PROP(empty_cells, EmptyCells)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6456,16 +6456,22 @@ nsRuleNode::ComputeVisibilityData(void*
break;
default:
NS_NOTREACHED("Invalid image-orientation enumerated value");
}
} else {
MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
}
+ SetDiscrete(*aRuleData->ValueForColorAdjust(), visibility->mColorAdjust,
+ conditions,
+ SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
+ parentVisibility->mColorAdjust,
+ NS_STYLE_COLOR_ADJUST_ECONOMY, 0, 0, 0, 0);
+
COMPUTE_END_INHERITED(Visibility, visibility)
}
const void*
nsRuleNode::ComputeColorData(void* aStartStruct,
const nsRuleData* aRuleData,
nsStyleContext* aContext,
nsRuleNode* aHighestNode,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -1116,16 +1116,20 @@ enum class FillMode : uint32_t;
#define NS_STYLE_TEXT_EMPHASIS_STYLE_STRING 255
// text-rendering
#define NS_STYLE_TEXT_RENDERING_AUTO 0
#define NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED 1
#define NS_STYLE_TEXT_RENDERING_OPTIMIZELEGIBILITY 2
#define NS_STYLE_TEXT_RENDERING_GEOMETRICPRECISION 3
+// adjust-color
+#define NS_STYLE_COLOR_ADJUST_ECONOMY 0
+#define NS_STYLE_COLOR_ADJUST_EXACT 1
+
// color-interpolation and color-interpolation-filters
#define NS_STYLE_COLOR_INTERPOLATION_AUTO 0
#define NS_STYLE_COLOR_INTERPOLATION_SRGB 1
#define NS_STYLE_COLOR_INTERPOLATION_LINEARRGB 2
// vector-effect
#define NS_STYLE_VECTOR_EFFECT_NONE 0
#define NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE 1
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3167,27 +3167,29 @@ nsStyleVisibility::nsStyleVisibility(nsP
mDirection = NS_STYLE_DIRECTION_RTL;
else
mDirection = NS_STYLE_DIRECTION_LTR;
mVisible = NS_STYLE_VISIBILITY_VISIBLE;
mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
mTextOrientation = NS_STYLE_TEXT_ORIENTATION_MIXED;
+ mColorAdjust = NS_STYLE_COLOR_ADJUST_ECONOMY;
}
nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
{
MOZ_COUNT_CTOR(nsStyleVisibility);
mImageOrientation = aSource.mImageOrientation;
mDirection = aSource.mDirection;
mVisible = aSource.mVisible;
mPointerEvents = aSource.mPointerEvents;
mWritingMode = aSource.mWritingMode;
mTextOrientation = aSource.mTextOrientation;
+ mColorAdjust = aSource.mColorAdjust;
}
nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
{
nsChangeHint hint = nsChangeHint(0);
if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
// It's important that a change in mWritingMode results in frame
@@ -3212,16 +3214,20 @@ nsChangeHint nsStyleVisibility::CalcDiff
}
if (mPointerEvents != aOther.mPointerEvents) {
// nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
// of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
// GetHitTestFlags. (Only a reflow, no visual change.)
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
}
+ if (mColorAdjust != aOther.mColorAdjust) {
+ // color-adjust only affects media where dynamic changes can't happen.
+ NS_UpdateHint(hint, nsChangeHint_NeutralChange);
+ }
}
return hint;
}
nsStyleContentData::~nsStyleContentData()
{
MOZ_ASSERT(!mImageTracked,
"nsStyleContentData being destroyed while still tracking image!");
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2104,32 +2104,34 @@ struct nsStyleVisibility
void Destroy(nsPresContext* aContext) {
this->~nsStyleVisibility();
aContext->PresShell()->
FreeByObjectID(mozilla::eArenaObjectID_nsStyleVisibility, this);
}
nsChangeHint CalcDifference(const nsStyleVisibility& aOther) const;
static nsChangeHint MaxDifference() {
- return NS_STYLE_HINT_FRAMECHANGE;
+ return NS_STYLE_HINT_FRAMECHANGE |
+ nsChangeHint_NeutralChange;
}
static nsChangeHint DifferenceAlwaysHandledForDescendants() {
// CalcDifference never returns the reflow hints that are sometimes
// handled for descendants as hints not handled for descendants.
return nsChangeHint_NeedReflow |
nsChangeHint_ReflowChangesSizeOrPosition |
nsChangeHint_ClearAncestorIntrinsics;
}
nsStyleImageOrientation mImageOrientation; // [inherited]
uint8_t mDirection; // [inherited] see nsStyleConsts.h NS_STYLE_DIRECTION_*
uint8_t mVisible; // [inherited]
uint8_t mPointerEvents; // [inherited] see nsStyleConsts.h
uint8_t mWritingMode; // [inherited] see nsStyleConsts.h
uint8_t mTextOrientation; // [inherited] see nsStyleConsts.h
+ uint8_t mColorAdjust; // [inherited] see nsStyleConsts.h
bool IsVisible() const {
return (mVisible == NS_STYLE_VISIBILITY_VISIBLE);
}
bool IsVisibleOrCollapsed() const {
return ((mVisible == NS_STYLE_VISIBILITY_VISIBLE) ||
(mVisible == NS_STYLE_VISIBILITY_COLLAPSE));
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1363,16 +1363,24 @@ var gCSSProperties = {
},
"-moz-box-sizing": {
domProp: "MozBoxSizing",
inherited: false,
type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
alias_for: "box-sizing",
subproperties: [ "box-sizing" ],
},
+ "color-adjust": {
+ domProp: "colorAdjust",
+ inherited: true,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: [ "economy" ],
+ other_values: [ "exact" ],
+ invalid_values: []
+ },
"-moz-columns": {
domProp: "MozColumns",
inherited: false,
type: CSS_TYPE_TRUE_SHORTHAND,
subproperties: [ "-moz-column-count", "-moz-column-width" ],
initial_values: [ "auto", "auto auto" ],
other_values: [ "3", "20px", "2 10px", "10px 2", "2 auto", "auto 2", "auto 50px", "50px auto" ],
invalid_values: [ "5%", "-1px", "-1", "3 5", "10px 4px", "10 2px 5in", "30px -1",
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -2088,21 +2088,21 @@ nsBoxFrame::GetEventPoint(WidgetGUIEvent
bool
nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, LayoutDeviceIntPoint& aPoint) {
NS_ENSURE_TRUE(aEvent, false);
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
if (touchEvent) {
// return false if there is more than one touch on the page, or if
// we can't find a touch point
- if (touchEvent->touches.Length() != 1) {
+ if (touchEvent->mTouches.Length() != 1) {
return false;
}
- dom::Touch* touch = touchEvent->touches.SafeElementAt(0);
+ dom::Touch* touch = touchEvent->mTouches.SafeElementAt(0);
if (!touch) {
return false;
}
aPoint = touch->mRefPoint;
} else {
aPoint = aEvent->refPoint;
}
return true;
--- a/mfbt/ChaosMode.h
+++ b/mfbt/ChaosMode.h
@@ -22,16 +22,18 @@ enum ChaosFeature {
// Altering network request scheduling.
NetworkScheduling = 0x2,
// Altering timer scheduling.
TimerScheduling = 0x4,
// Read and write less-than-requested amounts.
IOAmounts = 0x8,
// Iterate over hash tables in random order.
HashTableIteration = 0x10,
+ // Randomly refuse to use cached version of image (when allowed by spec).
+ ImageCache = 0x20,
Any = 0xffffffff,
};
namespace detail {
extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
extern MFBT_DATA ChaosFeature gChaosFeatures;
} // namespace detail
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -562,16 +562,17 @@ pref("apz.axis_lock.mode", 0);
pref("apz.axis_lock.lock_angle", "0.5235987"); // PI / 6 (30 degrees)
pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches
pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees)
pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees)
pref("apz.content_response_timeout", 300);
pref("apz.drag.enabled", false);
pref("apz.danger_zone_x", 50);
pref("apz.danger_zone_y", 100);
+pref("apz.disable_for_scroll_linked_effects", false);
pref("apz.displayport_expiry_ms", 15000);
pref("apz.enlarge_displayport_when_clipped", false);
pref("apz.fling_accel_base_mult", "1.0");
pref("apz.fling_accel_interval_ms", 500);
pref("apz.fling_accel_supplemental_mult", "1.0");
pref("apz.fling_curve_function_x1", "0.0");
pref("apz.fling_curve_function_y1", "0.0");
pref("apz.fling_curve_function_x2", "1.0");
@@ -5262,8 +5263,11 @@ pref("webextensions.tests", false);
// Allow customization of the fallback directory for file uploads
pref("dom.input.fallbackUploadDir", "");
// Turn rewriting of youtube embeds on/off
pref("plugins.rewrite_youtube_embeds", true);
// Disable browser frames by default
pref("dom.mozBrowserFramesEnabled", false);
+
+// Is support for 'color-adjust' CSS property enabled?
+pref("layout.css.color-adjust.enabled", true);
--- a/testing/firefox-ui/mach_commands.py
+++ b/testing/firefox-ui/mach_commands.py
@@ -24,21 +24,24 @@ def setup_argument_parser_functional():
def setup_argument_parser_update():
from firefox_ui_harness.arguments.update import UpdateArguments
return UpdateArguments()
def run_firefox_ui_test(testtype=None, topsrcdir=None, **kwargs):
- import argparse
-
from mozlog.structured import commandline
import firefox_ui_harness
+ if testtype == 'functional':
+ parser = setup_argument_parser_functional()
+ else:
+ parser = setup_argument_parser_update()
+
test_types = {
'functional': {
'default_tests': [
os.path.join('puppeteer', 'manifest.ini'),
os.path.join('functional', 'manifest.ini'),
],
'cli_module': firefox_ui_harness.cli_functional,
},
@@ -52,24 +55,34 @@ def run_firefox_ui_test(testtype=None, t
fxui_dir = os.path.join(topsrcdir, 'testing', 'firefox-ui')
# Set the resources path which is used to serve test data via wptserve
if not kwargs['server_root']:
kwargs['server_root'] = os.path.join(fxui_dir, 'resources')
# If no tests have been selected, set default ones
- if not kwargs.get('tests'):
- kwargs['tests'] = [os.path.join(fxui_dir, 'tests', test)
+ if kwargs.get('tests'):
+ tests = kwargs.get('tests')
+ else:
+ tests = [os.path.join(fxui_dir, 'tests', test)
for test in test_types[testtype]['default_tests']]
kwargs['logger'] = commandline.setup_logging('Firefox UI - {} Tests'.format(testtype),
{"mach": sys.stdout})
- failed = test_types[testtype]['cli_module'].cli(args=kwargs)
+ args = parser.parse_args(args=tests)
+
+ for k, v in kwargs.iteritems():
+ setattr(args, k, v)
+
+ parser.verify_usage(args)
+
+ failed = test_types[testtype]['cli_module'].cli(args=vars(args))
+
if failed > 0:
return 1
else:
return 0
@CommandProvider
class MachCommands(MachCommandBase):
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -572,17 +572,17 @@ function sendWheelAndPaint(aTarget, aOff
// just wait for the paint to complete.
aWindow.waitForAllPaintsFlushed(function() {
sendWheelAndPaint(aTarget, aOffsetX, aOffsetY, aEvent, aCallback, aWindow);
});
return;
}
var onwheel = function() {
- window.removeEventListener("wheel", onwheel);
+ SpecialPowers.removeSystemEventListener(window, "wheel", onwheel);
// Wait one frame since the wheel event has not caused a refresh observer
// to be added yet.
setTimeout(function() {
utils.advanceTimeAndRefresh(1000);
if (!aCallback) {
utils.advanceTimeAndRefresh(0);
@@ -599,17 +599,19 @@ function sendWheelAndPaint(aTarget, aOff
SpecialPowers.Services.obs.addObserver(waitForPaints, "apz-repaints-flushed", false);
if (!utils.flushApzRepaints(aWindow)) {
waitForPaints();
}
}, 0);
};
- aWindow.addEventListener("wheel", onwheel);
+ // Listen for the system wheel event, because it happens after all of
+ // the other wheel events, including legacy events.
+ SpecialPowers.addSystemEventListener(aWindow, "wheel", onwheel);
synthesizeWheel(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
}
function synthesizeNativeMouseMove(aTarget, aOffsetX, aOffsetY, aCallback, aWindow = window) {
var utils = _getDOMWindowUtils(aWindow);
if (!utils)
return;
--- a/testing/web-platform/meta/XMLHttpRequest/open-url-bogus.htm.ini
+++ b/testing/web-platform/meta/XMLHttpRequest/open-url-bogus.htm.ini
@@ -1,8 +1,5 @@
[open-url-bogus.htm]
type: testharness
[XMLHttpRequest: open() - bogus URLs (http:)]
expected: FAIL
- [XMLHttpRequest: open() - bogus URLs (http://a a/)]
- expected: FAIL
-
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -189,18 +189,18 @@ MultiTouchInput::MultiTouchInput(const W
case eTouchCancel:
mType = MULTITOUCH_CANCEL;
break;
default:
MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
break;
}
- for (size_t i = 0; i < aTouchEvent.touches.Length(); i++) {
- const Touch* domTouch = aTouchEvent.touches[i];
+ for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) {
+ const Touch* domTouch = aTouchEvent.mTouches[i];
// Extract data from weird interfaces.
int32_t identifier = domTouch->Identifier();
int32_t radiusX = domTouch->RadiusX();
int32_t radiusY = domTouch->RadiusY();
float rotationAngle = domTouch->RotationAngle();
float force = domTouch->Force();
@@ -246,17 +246,17 @@ MultiTouchInput::ToWidgetTouchEvent(nsIW
}
event.mModifiers = this->modifiers;
event.mTime = this->mTime;
event.mTimeStamp = this->mTimeStamp;
event.mFlags.mHandledByAPZ = mHandledByAPZ;
for (size_t i = 0; i < mTouches.Length(); i++) {
- *event.touches.AppendElement() = mTouches[i].ToNewDOMTouch();
+ *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
}
return event;
}
WidgetMouseEvent
MultiTouchInput::ToWidgetMouseEvent(nsIWidget* aWidget) const
{
--- a/widget/TouchEvents.h
+++ b/widget/TouchEvents.h
@@ -169,17 +169,17 @@ public:
WidgetTouchEvent(const WidgetTouchEvent& aOther)
: WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.widget,
eTouchEventClass)
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
mModifiers = aOther.mModifiers;
mTime = aOther.mTime;
mTimeStamp = aOther.mTimeStamp;
- touches.AppendElements(aOther.touches);
+ mTouches.AppendElements(aOther.mTouches);
mFlags.mCancelable = mMessage != eTouchCancel;
mFlags.mHandledByAPZ = aOther.mFlags.mHandledByAPZ;
}
WidgetTouchEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetInputEvent(aIsTrusted, aMessage, aWidget, eTouchEventClass)
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
@@ -197,23 +197,23 @@ public:
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetTouchEvent* result = new WidgetTouchEvent(false, mMessage, nullptr);
result->AssignTouchEventData(*this, true);
result->mFlags = mFlags;
return result;
}
- TouchArray touches;
+ TouchArray mTouches;
void AssignTouchEventData(const WidgetTouchEvent& aEvent, bool aCopyTargets)
{
AssignInputEventData(aEvent, aCopyTargets);
// Assign*EventData() assume that they're called only new instance.
- MOZ_ASSERT(touches.IsEmpty());
- touches.AppendElements(aEvent.touches);
+ MOZ_ASSERT(mTouches.IsEmpty());
+ mTouches.AppendElements(aEvent.mTouches);
}
};
} // namespace mozilla
#endif // mozilla_TouchEvents_h__
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -606,17 +606,17 @@ AndroidGeckoEvent::MakeTouchEvent(nsIWid
// An event we don't know about
return event;
}
event.mModifiers = DOMModifiers();
event.mTime = Time();
const LayoutDeviceIntPoint& offset = widget->WidgetToScreenOffset();
- event.touches.SetCapacity(endIndex - startIndex);
+ event.mTouches.SetCapacity(endIndex - startIndex);
for (int i = startIndex; i < endIndex; i++) {
// In this code branch, we are dispatching this event directly
// into Gecko (as opposed to going through the AsyncPanZoomController),
// and the Points() array has points in CSS pixels, which we need
// to convert.
CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
LayoutDeviceIntPoint pt(
(Points()[i].x * scale.scale) - offset.x,
@@ -624,17 +624,17 @@ AndroidGeckoEvent::MakeTouchEvent(nsIWid
LayoutDeviceIntPoint radius(
PointRadii()[i].x * scale.scale,
PointRadii()[i].y * scale.scale);
RefPtr<Touch> t = new Touch(PointIndicies()[i],
pt,
radius,
Orientations()[i],
Pressures()[i]);
- event.touches.AppendElement(t);
+ event.mTouches.AppendElement(t);
}
return event;
}
MultiTouchInput
AndroidGeckoEvent::MakeMultiTouchInput(nsIWidget* widget)
{
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2002,24 +2002,24 @@ nsWindow::OnLongTapEvent(AndroidGeckoEve
event.ignoreRootScrollFrame = true;
DispatchEvent(&event);
}
void
nsWindow::DispatchHitTest(const WidgetTouchEvent& aEvent)
{
- if (aEvent.mMessage == eTouchStart && aEvent.touches.Length() == 1) {
+ if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() == 1) {
// Since touch events don't get retargeted by PositionedEventTargeting.cpp
// code on Fennec, we dispatch a dummy mouse event that *does* get
// retargeted. The Fennec browser.js code can use this to activate the
// highlight element in case the this touchstart is the start of a tap.
WidgetMouseEvent hittest(true, eMouseHitTest, this,
WidgetMouseEvent::eReal);
- hittest.refPoint = aEvent.touches[0]->mRefPoint;
+ hittest.refPoint = aEvent.mTouches[0]->mRefPoint;
hittest.ignoreRootScrollFrame = true;
hittest.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
nsEventStatus status;
DispatchEvent(&hittest, status);
if (mAPZEventState && hittest.hitCluster) {
mAPZEventState->ProcessClusterHit();
}
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -3441,21 +3441,21 @@ nsWindow::OnTouchEvent(GdkEventTouch* aE
WidgetTouchEvent event(true, msg, this);
KeymapWrapper::InitInputEvent(event, aEvent->state);
event.mTime = aEvent->time;
if (aEvent->type == GDK_TOUCH_BEGIN || aEvent->type == GDK_TOUCH_UPDATE) {
mTouches.Put(aEvent->sequence, touch.forget());
// add all touch points to event object
for (auto iter = mTouches.Iter(); !iter.Done(); iter.Next()) {
- event.touches.AppendElement(new dom::Touch(*iter.UserData()));
+ event.mTouches.AppendElement(new dom::Touch(*iter.UserData()));
}
} else if (aEvent->type == GDK_TOUCH_END ||
aEvent->type == GDK_TOUCH_CANCEL) {
- *event.touches.AppendElement() = touch.forget();
+ *event.mTouches.AppendElement() = touch.forget();
}
DispatchInputEvent(&event);
return TRUE;
}
#endif
static void
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -298,18 +298,18 @@ template<>
struct ParamTraits<mozilla::WidgetTouchEvent>
{
typedef mozilla::WidgetTouchEvent paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<const mozilla::WidgetInputEvent&>(aParam));
// Sigh, Touch bites us again! We want to be able to do
- // WriteParam(aMsg, aParam.touches);
- const paramType::TouchArray& touches = aParam.touches;
+ // WriteParam(aMsg, aParam.mTouches);
+ const paramType::TouchArray& touches = aParam.mTouches;
WriteParam(aMsg, touches.Length());
for (uint32_t i = 0; i < touches.Length(); ++i) {
mozilla::dom::Touch* touch = touches[i];
WriteParam(aMsg, touch->mIdentifier);
WriteParam(aMsg, touch->mRefPoint);
WriteParam(aMsg, touch->mRadius);
WriteParam(aMsg, touch->mRotationAngle);
WriteParam(aMsg, touch->mForce);
@@ -332,17 +332,17 @@ struct ParamTraits<mozilla::WidgetTouchE
float force;
if (!ReadParam(aMsg, aIter, &identifier) ||
!ReadParam(aMsg, aIter, &refPoint) ||
!ReadParam(aMsg, aIter, &radius) ||
!ReadParam(aMsg, aIter, &rotationAngle) ||
!ReadParam(aMsg, aIter, &force)) {
return false;
}
- aResult->touches.AppendElement(
+ aResult->mTouches.AppendElement(
new mozilla::dom::Touch(
identifier, refPoint, radius, rotationAngle, force));
}
return true;
}
};
template<>
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -165,30 +165,30 @@ private:
}
- (void)sendTouchEvent:(EventMessage) aType touches:(NSSet*)aTouches widget:(nsWindow*)aWindow
{
WidgetTouchEvent event(true, aType, aWindow);
//XXX: I think nativeEvent.timestamp * 1000 is probably usable here but
// I don't care that much right now.
event.mTime = PR_IntervalNow();
- event.touches.SetCapacity(aTouches.count);
+ event.mTouches.SetCapacity(aTouches.count);
for (UITouch* touch in aTouches) {
LayoutDeviceIntPoint loc = UIKitPointsToDevPixels([touch locationInView:self], [self contentScaleFactor]);
LayoutDeviceIntPoint radius = UIKitPointsToDevPixels([touch majorRadius], [touch majorRadius]);
void* value;
if (!CFDictionaryGetValueIfPresent(mTouches, touch, (const void**)&value)) {
// This shouldn't happen.
NS_ASSERTION(false, "Got a touch that we didn't know about");
continue;
}
int id = reinterpret_cast<int>(value);
RefPtr<Touch> t = new Touch(id, loc, radius, 0.0f, 1.0f);
event.refPoint = loc;
- event.touches.AppendElement(t);
+ event.mTouches.AppendElement(t);
}
aWindow->DispatchInputEvent(&event);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
ALOG("[ChildView[%p] touchesBegan", self);
if (!mGeckoChild)