This commit is contained in:
Ryan VanderMeulen 2016-04-03 21:41:06 -04:00
Родитель 0c159ab93d 9a90e77971
Коммит 531a5d3749
130 изменённых файлов: 1363 добавлений и 989 удалений

Просмотреть файл

@ -165,7 +165,7 @@ nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX, int32_t aY,
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);
}

Просмотреть файл

@ -838,7 +838,7 @@ var SessionStoreInternal = {
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
@ -3286,6 +3286,9 @@ var SessionStoreInternal = {
* 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")) {
@ -3309,7 +3312,8 @@ var SessionStoreInternal = {
// 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
@ -3332,7 +3336,7 @@ var SessionStoreInternal = {
}
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
{loadArguments: aLoadArguments});
{loadArguments: aLoadArguments, isRemotenessUpdate});
},
/**
@ -3977,11 +3981,17 @@ var SessionStoreInternal = {
/**
* 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);
},

Просмотреть файл

@ -199,9 +199,16 @@ this.StartupPerformance = {
// 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;

Просмотреть файл

@ -167,21 +167,21 @@ var MessageListener = {
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});
}
},

Просмотреть файл

@ -304,7 +304,12 @@ nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
// 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

Просмотреть файл

@ -23,8 +23,9 @@ var testData = [
["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],

Просмотреть файл

@ -18,8 +18,11 @@
[[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']],

Просмотреть файл

@ -193,6 +193,8 @@ skip-if = e10s && debug && (os == 'win' || os == 'mac') # Bug 1243966
[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

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -16,6 +16,7 @@ Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderMo
const promise = require("promise");
const Services = require("Services");
const ErrorDocs = require("devtools/server/actors/errordocs");
loader.lazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
@ -1489,6 +1490,7 @@ WebConsoleFrame.prototype = {
// Select the body of the message node that is displayed in the console
let msgBody = node.getElementsByClassName("message-body")[0];
// Add the more info link node to messages that belong to certain categories
this.addMoreInfoLink(msgBody, scriptError);
@ -1697,11 +1699,14 @@ WebConsoleFrame.prototype = {
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);
}
},
/*

Просмотреть файл

@ -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];

Просмотреть файл

@ -25,6 +25,7 @@ DevToolsModules(
'director-manager.js',
'director-registry.js',
'environment.js',
'errordocs.js',
'eventlooplag.js',
'frame.js',
'framerate.js',

Просмотреть файл

@ -1392,6 +1392,7 @@ WebConsoleActor.prototype =
return {
errorMessage: this._createStringGrip(aPageError.errorMessage),
errorMessageName: aPageError.errorMessageName,
sourceName: aPageError.sourceName,
lineText: lineText,
lineNumber: aPageError.lineNumber,

Просмотреть файл

@ -18,9 +18,10 @@ let expectedPageErrors = [];
function doPageErrors()
{
expectedPageErrors = [
{
expectedPageErrors = {
"document.body.style.color = 'fooColor';": {
errorMessage: /fooColor/,
errorMessageName: undefined,
sourceName: /test_page_errors/,
category: "CSS Parser",
timeStamp: /^\d+$/,
@ -29,8 +30,9 @@ function doPageErrors()
exception: false,
strict: false,
},
{
"document.doTheImpossible();": {
errorMessage: /doTheImpossible/,
errorMessageName: undefined,
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
@ -39,19 +41,101 @@ function doPageErrors()
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()
@ -80,15 +164,15 @@ function onPageError(aState, aType, aPacket)
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() {

Просмотреть файл

@ -774,7 +774,11 @@ nsContentIterator::NextNode(nsINode* aNode, nsTArray<int32_t>* 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;
@ -839,7 +843,11 @@ nsContentIterator::PrevNode(nsINode* aNode, nsTArray<int32_t>* aIndexes)
// 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;

Просмотреть файл

@ -945,7 +945,7 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType,
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);
@ -957,7 +957,7 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType,
RefPtr<Touch> t =
new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
event.touches.AppendElement(t);
event.mTouches.AppendElement(t);
}
nsEventStatus status;

Просмотреть файл

@ -1566,8 +1566,13 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
}
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);

Просмотреть файл

@ -1314,7 +1314,7 @@ EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
// 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

Просмотреть файл

@ -69,8 +69,8 @@ TouchEvent::TouchEvent(EventTarget* aOwner,
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 {
@ -118,9 +118,9 @@ 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]);
@ -128,7 +128,7 @@ TouchEvent::Touches()
}
mTouches = new TouchList(ToSupports(this), unchangedTouches);
} else {
mTouches = new TouchList(ToSupports(this), touchEvent->touches);
mTouches = new TouchList(ToSupports(this), touchEvent->mTouches);
}
}
return mTouches;
@ -140,7 +140,7 @@ 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
@ -162,7 +162,7 @@ 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]);

Просмотреть файл

@ -151,7 +151,7 @@ support-files = bug1017086_inner.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

Просмотреть файл

@ -4,6 +4,7 @@
<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>
@ -39,7 +40,7 @@
</div>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
@ -55,7 +56,12 @@ 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)
@ -65,32 +71,32 @@ function prepareScrollUnits()
}
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);
@ -102,7 +108,7 @@ function prepareScrollUnits()
// 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",
@ -2661,8 +2667,9 @@ function testContinuousTrustedEvents()
// 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,
@ -2714,15 +2721,17 @@ function testContinuousTrustedEvents()
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,
@ -2774,15 +2783,17 @@ function testContinuousTrustedEvents()
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,
@ -2834,15 +2845,17 @@ function testContinuousTrustedEvents()
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,
@ -2894,15 +2907,17 @@ function testContinuousTrustedEvents()
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,
@ -2954,15 +2969,17 @@ function testContinuousTrustedEvents()
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,
@ -3014,8 +3031,9 @@ function testContinuousTrustedEvents()
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);
},
},
];
@ -3145,13 +3163,13 @@ function testContinuousTrustedEvents()
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, " +
@ -3181,60 +3199,49 @@ function testContinuousTrustedEvents()
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>

Просмотреть файл

@ -4242,7 +4242,7 @@ HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor)
CancelRangeThumbDrag();
}
} else {
if (aVisitor.mEvent->AsTouchEvent()->touches.Length() == 1) {
if (aVisitor.mEvent->AsTouchEvent()->mTouches.Length() == 1) {
StartRangeThumbDrag(inputEvent);
} else if (mIsDraggingRange) {
CancelRangeThumbDrag();

Просмотреть файл

@ -2492,6 +2492,10 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission)
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);

Просмотреть файл

@ -1658,9 +1658,9 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
// 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);
}
}
}
@ -1675,8 +1675,8 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
}
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) ?
@ -2778,7 +2778,7 @@ TabParent::InjectTouchEvent(const nsAString& aType,
}
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(
@ -2797,7 +2797,7 @@ TabParent::InjectTouchEvent(const nsAString& aType,
// 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);

Просмотреть файл

@ -620,7 +620,9 @@ AudioCallbackDriver::Init()
// 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)
@ -645,7 +647,9 @@ AudioCallbackDriver::Init()
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());

Просмотреть файл

@ -351,8 +351,6 @@ nsSpeechTask::DispatchStart()
nsresult
nsSpeechTask::DispatchStartInner()
{
CreateAudioChannelAgent();
nsSynthVoiceRegistry::GetInstance()->SetIsSpeaking(true);
return DispatchStartImpl();
}
@ -373,6 +371,8 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
return NS_ERROR_NOT_AVAILABLE;
}
CreateAudioChannelAgent();
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
mUtterance->mChosenVoiceURI = aUri;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("start"), 0, 0,
@ -395,8 +395,6 @@ nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
nsresult
nsSpeechTask::DispatchEndInner(float aElapsedTime, uint32_t aCharIndex)
{
DestroyAudioChannelAgent();
if (!mPreCanceled) {
nsSynthVoiceRegistry::GetInstance()->SpeakNext();
}
@ -409,6 +407,8 @@ 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;

Просмотреть файл

@ -5025,7 +5025,7 @@ nsHTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
// 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);
}
@ -5034,7 +5034,7 @@ nsHTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
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 {

Просмотреть файл

@ -713,6 +713,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
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)
@ -772,7 +773,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetAllowVerticalScrollWithWheel) &&
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsLayersIdRoot) &&
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetUsesContainerScrolling) &&
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsScrollInfoLayer));
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsScrollInfoLayer) &&
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetForceDisableApz));
}
};

Просмотреть файл

@ -74,6 +74,7 @@ public:
, mIsLayersIdRoot(false)
, mUsesContainerScrolling(false)
, mIsScrollInfoLayer(false)
, mForceDisableApz(false)
{
}
@ -113,7 +114,8 @@ public:
mAllowVerticalScrollWithWheel == aOther.mAllowVerticalScrollWithWheel &&
mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
mUsesContainerScrolling == aOther.mUsesContainerScrolling &&
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer &&
mForceDisableApz == aOther.mForceDisableApz;
}
bool operator!=(const FrameMetrics& aOther) const
@ -554,6 +556,13 @@ public:
return mIsScrollInfoLayer;
}
void SetForceDisableApz(bool aForceDisable) {
mForceDisableApz = aForceDisable;
}
bool IsApzForceDisabled() const {
return mForceDisableApz;
}
private:
// A unique ID assigned to each scrollable frame.
ViewID mScrollId;
@ -742,6 +751,10 @@ private:
// 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

Просмотреть файл

@ -1152,10 +1152,11 @@ APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
// 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;
@ -1934,7 +1935,7 @@ APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) c
// 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;
@ -1966,7 +1967,7 @@ APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) co
// 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();

Просмотреть файл

@ -156,6 +156,14 @@ using mozilla::gfx::PointTyped;
* 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
@ -3030,8 +3038,15 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
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();
}
@ -3124,18 +3139,28 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
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();
@ -3170,9 +3195,11 @@ AsyncTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
-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 {
@ -3436,6 +3463,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
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,

Просмотреть файл

@ -162,21 +162,6 @@ public:
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.
@ -222,20 +207,6 @@ public:
*/
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
@ -737,6 +708,53 @@ private:
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
@ -1106,9 +1124,9 @@ public:
}
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.

Просмотреть файл

@ -241,7 +241,7 @@ HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint) const
LayerToParentLayerMatrix4x4 transform = mTransform *
CompleteAsyncTransform(
mApzc
? mApzc->GetCurrentAsyncTransformWithOverscroll()
? mApzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::NORMAL)
: AsyncTransformComponentMatrix());
return UntransformBy(transform.Inverse(), aPoint);
}

Просмотреть файл

@ -96,7 +96,7 @@ protected:
// 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;

Просмотреть файл

@ -252,8 +252,10 @@ public:
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;
}

Просмотреть файл

@ -58,6 +58,12 @@ protected:
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
@ -453,6 +459,48 @@ TEST_F(APZHitTestingTester, TestRepaintFlushOnWheelEvents) {
}
}
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);

Просмотреть файл

@ -501,9 +501,9 @@ APZCCallbackHelper::ApplyCallbackTransform(WidgetEvent& aEvent,
{
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(
@ -806,9 +806,9 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
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,
@ -836,8 +836,10 @@ APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
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);
}

Просмотреть файл

@ -260,8 +260,8 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
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;
@ -322,8 +322,8 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
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;
}
}

Просмотреть файл

@ -845,11 +845,10 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
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;
@ -882,6 +881,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
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() :
@ -1032,7 +1033,8 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
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
@ -1147,7 +1149,9 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
// 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();

Просмотреть файл

@ -488,10 +488,7 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
return;
}
AsyncTransform asyncTransformWithoutOverscroll;
ParentLayerPoint scrollOffset;
controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
scrollOffset);
ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
// Options
const int verticalPadding = 10;
@ -665,8 +662,9 @@ RenderLayers(ContainerT* aContainer,
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;
}
}
}
@ -815,7 +813,7 @@ ContainerRender(ContainerT* aContainer,
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;
}

Просмотреть файл

@ -148,6 +148,7 @@ private:
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);

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
#include "mozilla/ChaosMode.h"
#include "ImageLogging.h"
#include "nsPrintfCString.h"
@ -1772,6 +1773,12 @@ imgLoader::ValidateEntry(imgCacheEntry* aEntry,
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);

Просмотреть файл

@ -624,7 +624,7 @@ 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
@ -654,7 +654,7 @@ 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
@ -756,7 +756,7 @@ namespace js {
struct Class
{
JS_CLASS_MEMBERS(FinalizeOp);
ClassSpec spec;
const ClassSpec* spec;
ClassExtension ext;
const ObjectOps* ops;
@ -804,6 +804,26 @@ struct Class
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; }

Просмотреть файл

@ -96,7 +96,6 @@ enum AsmJSAtomicsBuiltinFunction
AsmJSAtomicsBuiltin_exchange,
AsmJSAtomicsBuiltin_load,
AsmJSAtomicsBuiltin_store,
AsmJSAtomicsBuiltin_fence,
AsmJSAtomicsBuiltin_add,
AsmJSAtomicsBuiltin_sub,
AsmJSAtomicsBuiltin_and,
@ -1735,7 +1734,6 @@ class MOZ_STACK_CLASS ModuleValidator
!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) ||
@ -4106,16 +4104,6 @@ CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNod
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)
{
@ -4309,8 +4297,6 @@ CheckAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSAtomicsB
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:
@ -7371,7 +7357,6 @@ ValidateAtomicsBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleV
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;

Просмотреть файл

@ -275,7 +275,6 @@ enum class Expr
F64Atan2,
// Atomics
AtomicsFence,
I32AtomicsCompareExchange,
I32AtomicsExchange,
I32AtomicsLoad,

Просмотреть файл

@ -577,14 +577,6 @@ class FunctionCompiler
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())
@ -3073,10 +3065,6 @@ EmitExpr(FunctionCompiler& f, MDefinition** def)
SimdSign::Unsigned, def);
// Atomics
case Expr::AtomicsFence:
*def = nullptr;
f.memoryBarrier(MembarFull);
return true;
case Expr::I32AtomicsCompareExchange:
return EmitAtomicsCompareExchange(f, def);
case Expr::I32AtomicsExchange:

Просмотреть файл

@ -52,6 +52,7 @@
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jsnum.h"
#include "asmjs/WasmModule.h"
#include "jit/AtomicOperations.h"
@ -80,7 +81,10 @@ ReportBadArrayType(JSContext* cx)
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;
}
@ -108,22 +112,12 @@ GetSharedTypedArray(JSContext* cx, HandleValue v,
static bool
GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view, uint32_t* offset)
{
RootedId id(cx);
if (!ValueToId<CanGC>(cx, v, &id))
return false;
uint64_t index;
if (!IsTypedArrayIndex(id, &index) || index >= view->length())
if (!js::ToIntegerIndex(cx, v, &index))
return false;
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;
}
@ -754,7 +748,7 @@ class AutoUnlockFutexAPI
} // 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);
@ -797,7 +791,7 @@ js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
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;
}
@ -815,10 +809,18 @@ js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
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);
@ -832,7 +834,7 @@ js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
}
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);
@ -849,10 +851,14 @@ js::atomics_futexWake(JSContext* cx, unsigned argc, Value* vp)
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;
@ -878,120 +884,6 @@ js::atomics_futexWake(JSContext* cx, unsigned argc, Value* vp)
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()
{
@ -1070,7 +962,7 @@ js::FutexRuntime::isWaiting()
}
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());
@ -1127,14 +1019,14 @@ js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWai
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:
@ -1146,10 +1038,10 @@ js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWai
// 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
@ -1175,7 +1067,7 @@ js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWai
if (!retval)
goto finished;
if (state_ == Woken) {
*result = AtomicsObject::FutexOK;
*result = FutexOK;
goto finished;
}
break;
@ -1219,26 +1111,19 @@ const JSFunctionSpec AtomicsMethods[] = {
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)
{
@ -1253,8 +1138,6 @@ AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
if (!JS_DefineFunctions(cx, Atomics, AtomicsMethods))
return nullptr;
if (!JS_DefineConstDoubles(cx, Atomics, AtomicsConstants))
return nullptr;
RootedValue AtomicsValue(cx, ObjectValue(*Atomics));

Просмотреть файл

@ -18,31 +18,20 @@ class AtomicsObject : public JSObject
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);
@ -72,6 +61,12 @@ public:
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.
@ -81,30 +76,30 @@ public:
//
// 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_;

Просмотреть файл

@ -1211,6 +1211,16 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
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),
@ -1226,15 +1236,7 @@ const Class PlainObject::class_ = {
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_;

Просмотреть файл

@ -397,6 +397,14 @@ 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) |
@ -413,13 +421,18 @@ const Class PromiseObject::class_ = {
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_ = {
@ -437,14 +450,5 @@ const Class PromiseObject::protoClass_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
DELEGATED_CLASSSPEC(&PromiseObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
}
&PromiseObjectProtoClassSpec
};

Просмотреть файл

@ -18,6 +18,7 @@
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jsnum.h"
#include "jsprf.h"
#include "builtin/TypedObject.h"
@ -1254,70 +1255,6 @@ Select(JSContext* cx, unsigned argc, Value* vp)
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.
@ -1325,7 +1262,7 @@ 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);
@ -1352,7 +1289,7 @@ TypedArrayFromArgs(JSContext* cx, const CallArgs& args, uint32_t accessBytes,
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.

Просмотреть файл

@ -11,7 +11,6 @@ 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;
@ -24,10 +23,6 @@ var loadModule_int32_code =
var i32a = new stdlib.Int32Array(heap);
function do_fence() {
atomic_fence();
}
// Load element 0
function do_load() {
var v = 0;
@ -204,8 +199,7 @@ var loadModule_int32_code =
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,
@ -238,8 +232,6 @@ function test_int32(heap) {
var size = Int32Array.BYTES_PER_ELEMENT;
i32m.fence();
i32a[0] = 12345;
assertEq(i32m.load(), 12345);
assertEq(i32m.load_i(size*0), 12345);
@ -328,7 +320,6 @@ function test_int32(heap) {
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;
@ -609,7 +600,6 @@ function test_uint32(heap) {
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;
@ -622,10 +612,6 @@ var loadModule_int16_code =
var i16a = new stdlib.Int16Array(heap);
function do_fence() {
atomic_fence();
}
// Load element 0
function do_load() {
var v = 0;
@ -776,8 +762,7 @@ var loadModule_int16_code =
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,
@ -807,8 +792,6 @@ function test_int16(heap) {
var size = Int16Array.BYTES_PER_ELEMENT;
i16m.fence();
i16a[0] = 12345;
assertEq(i16m.load(), 12345);
assertEq(i16m.load_i(size*0), 12345);

Просмотреть файл

@ -3,7 +3,7 @@
// 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");
@ -66,8 +66,6 @@ function testMethod(a, ...indices) {
Atomics.store(a, x, 0);
// val = 0
Atomics.fence();
// val = 0
assertEq(Atomics.add(a, x, 3), 0);
// val = 3
@ -137,8 +135,6 @@ function testFunction(a, ...indices) {
gAtomics_store(a, x, 0);
// val = 0
gAtomics_fence();
// val = 0
assertEq(gAtomics_add(a, x, 3), 0);
// val = 3
@ -211,7 +207,7 @@ 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);
@ -380,7 +376,7 @@ function adHocExchange() {
// 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];
@ -456,6 +452,13 @@ function testUint8Clamped(sab) {
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);
@ -497,7 +500,6 @@ function runTests() {
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;
@ -551,6 +553,7 @@ function runTests() {
// Misc
testIsLockFree();
testIsLockFree2();
testWeirdIndices();
}
if (this.Atomics && this.SharedArrayBuffer)

Просмотреть файл

@ -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);

Просмотреть файл

@ -299,8 +299,11 @@ AtomicOperations::isLockfree(int32_t size)
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

Просмотреть файл

@ -10007,7 +10007,10 @@ CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
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);

Просмотреть файл

@ -22,7 +22,6 @@
_(AtomicsExchange) \
_(AtomicsLoad) \
_(AtomicsStore) \
_(AtomicsFence) \
_(AtomicsAdd) \
_(AtomicsSub) \
_(AtomicsAnd) \

Просмотреть файл

@ -832,7 +832,6 @@ class IonBuilder
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);

Просмотреть файл

@ -4204,13 +4204,6 @@ LIRGenerator::visitRecompileCheck(MRecompileCheck* ins)
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitMemoryBarrier(MMemoryBarrier* ins)
{
LMemoryBarrier* lir = new(alloc()) LMemoryBarrier(ins->type());
add(lir, ins);
}
void
LIRGenerator::visitSimdBox(MSimdBox* ins)
{

Просмотреть файл

@ -286,7 +286,6 @@ class LIRGenerator : public LIRGeneratorSpecific
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);

Просмотреть файл

@ -93,8 +93,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineAtomicsLoad(callInfo);
case InlinableNative::AtomicsStore:
return inlineAtomicsStore(callInfo);
case InlinableNative::AtomicsFence:
return inlineAtomicsFence(callInfo);
case InlinableNative::AtomicsAdd:
case InlinableNative::AtomicsSub:
case InlinableNative::AtomicsAnd:
@ -2915,30 +2913,6 @@ IonBuilder::inlineAtomicsStore(CallInfo& callInfo)
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)
{

Просмотреть файл

@ -9995,7 +9995,21 @@ class MArrayJoin
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
{
@ -10003,7 +10017,7 @@ enum MemoryBarrierRequirement
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
@ -13648,49 +13662,6 @@ class MRecompileCheck : public MNullaryInstruction
}
};
// 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

Просмотреть файл

@ -280,7 +280,6 @@ namespace jit {
_(AsmReinterpret) \
_(NewDerivedTypedObject) \
_(RecompileCheck) \
_(MemoryBarrier) \
_(AsmJSCompareExchangeHeap) \
_(AsmJSAtomicExchangeHeap) \
_(AsmJSAtomicBinopHeap) \

Просмотреть файл

@ -7963,10 +7963,6 @@ class LMemoryBarrier : public LInstructionHelper<0, 0, 0>
MemoryBarrierBits type() const {
return type_;
}
const MMemoryBarrier* mir() const {
return mir_->toMemoryBarrier();
}
};
class LDebugger : public LCallInstructionHelper<0, 0, 2>

Просмотреть файл

@ -497,7 +497,6 @@ MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol t
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}'")

Просмотреть файл

@ -3262,6 +3262,16 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
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,
@ -3277,15 +3287,7 @@ const Class ArrayObject::class_ = {
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
};
/*

Просмотреть файл

@ -3272,6 +3272,16 @@ FinishDateClassInit(JSContext* cx, HandleObject ctor, HandleObject proto)
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) |
@ -3288,15 +3298,18 @@ const Class DateObject::class_ = {
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_ = {
@ -3314,16 +3327,7 @@ const Class DateObject::protoClass_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
DELEGATED_CLASSSPEC(&DateObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
}
&DateObjectProtoClassSpec
};
JSObject*

Просмотреть файл

@ -65,7 +65,7 @@ static const JSFunctionSpec exception_methods[] = {
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) | \
@ -82,60 +82,59 @@ static const JSFunctionSpec exception_methods[] = {
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*

Просмотреть файл

@ -643,7 +643,7 @@ 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
@ -662,7 +662,7 @@ ParentKeyForStandardClass(JSProtoKey key)
// 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;

Просмотреть файл

@ -834,6 +834,15 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
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),
@ -849,14 +858,7 @@ const Class JSFunction::class_ = {
fun_hasInstance,
nullptr, /* construct */
fun_trace,
{
CreateFunctionConstructor,
CreateFunctionPrototype,
nullptr,
nullptr,
function_methods,
function_properties
}
&JSFunctionClassSpec
};
const Class* const js::FunctionClassPtr = &JSFunction::class_;

Просмотреть файл

@ -1748,6 +1748,55 @@ 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,

Просмотреть файл

@ -275,6 +275,26 @@ ToInteger(JSContext* cx, HandleValue v, double* dp)
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)
{

Просмотреть файл

@ -10,7 +10,7 @@ if (!(this.SharedArrayBuffer && this.Atomics)) {
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.
@ -57,9 +57,8 @@ let sab = new SharedArrayBuffer(16);
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);
}
}
@ -71,9 +70,8 @@ let sab = new SharedArrayBuffer(16);
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);
}
}
@ -86,9 +84,8 @@ let sab = new SharedArrayBuffer(16);
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);
}
}
@ -108,10 +105,8 @@ let sab = new SharedArrayBuffer(16);
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);
}
}

Просмотреть файл

@ -17,7 +17,7 @@ function dprint(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);
@ -61,19 +61,34 @@ 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();
}
setSharedArrayBuffer(mem.buffer);
evalInWorker(`
var mem = new Int32Array(getSharedArrayBuffer());
@ -83,40 +98,61 @@ function dprint(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);

Просмотреть файл

@ -1017,6 +1017,7 @@ ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
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

Просмотреть файл

@ -112,6 +112,9 @@
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") \

Просмотреть файл

@ -41,6 +41,10 @@ class ErrorObject : public NativeObject
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;

Просмотреть файл

@ -162,7 +162,7 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// 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;
@ -195,8 +195,8 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// |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;
@ -211,12 +211,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
}
// 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;
}
@ -229,19 +229,19 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// 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;
}
@ -252,10 +252,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
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));
@ -416,11 +418,11 @@ InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey prot
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;

Просмотреть файл

@ -185,6 +185,15 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj)
}
}
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 |
@ -202,16 +211,7 @@ const Class RegExpObject::class_ = {
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*

Просмотреть файл

@ -652,7 +652,7 @@ JSRuntime::requestInterrupt(InterruptMode mode)
// 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);

Просмотреть файл

@ -961,7 +961,7 @@ struct JSRuntime : public JS::shadow::Runtime,
/* 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:

Просмотреть файл

@ -18,6 +18,8 @@ class SavedFrame : public NativeObject {
friend class SavedStacks;
friend struct ::JSStructuredCloneReader;
static const ClassSpec classSpec_;
public:
static const Class class_;
static const JSPropertySpec protoAccessors[];

Просмотреть файл

@ -289,6 +289,17 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject
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 |
@ -307,18 +318,7 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject
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

Просмотреть файл

@ -868,7 +868,7 @@ with_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult
return DeleteProperty(cx, actual, id, result);
}
const ObjectOps DynamicWithObject::objectOps_ = {
static const ObjectOps DynamicWithObjectObjectOps = {
with_LookupProperty,
with_DefineProperty,
with_HasProperty,
@ -900,7 +900,7 @@ const Class DynamicWithObject::class_ = {
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
&DynamicWithObject::objectOps_
&DynamicWithObjectObjectOps
};
/* static */ StaticEvalScope*
@ -1124,20 +1124,6 @@ ClonedBlockObject::thisValue() const
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) |
@ -1156,7 +1142,7 @@ const Class ClonedBlockObject::class_ = {
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
&ClonedBlockObject::objectOps_
JS_NULL_OBJECT_OPS
};
template<XDRMode mode>
@ -1397,7 +1383,7 @@ lexicalError_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, Object
return false;
}
const ObjectOps RuntimeLexicalErrorObject::objectOps_ = {
static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
lexicalError_LookupProperty,
nullptr, /* defineProperty */
lexicalError_HasProperty,
@ -1429,7 +1415,7 @@ const Class RuntimeLexicalErrorObject::class_ = {
nullptr, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
&RuntimeLexicalErrorObject::objectOps_
&RuntimeLexicalErrorObjectObjectOps
};
/*****************************************************************************/

Просмотреть файл

@ -816,8 +816,9 @@ class ModuleEnvironmentObject : public LexicalScopeBase
{
static const uint32_t MODULE_SLOT = 1;
public:
static const ObjectOps objectOps_;
public:
static const Class class_;
static const uint32_t RESERVED_SLOTS = 2;
@ -912,7 +913,6 @@ class DynamicWithObject : public NestedScopeObject
public:
static const unsigned RESERVED_SLOTS = 4;
static const ObjectOps objectOps_;
static const Class class_;
enum WithKind {
@ -1075,7 +1075,6 @@ class RuntimeLexicalErrorObject : public ScopeObject
public:
static const unsigned RESERVED_SLOTS = 2;
static const ObjectOps objectOps_;
static const Class class_;
static RuntimeLexicalErrorObject* create(JSContext* cx, HandleObject enclosing,

Просмотреть файл

@ -861,6 +861,18 @@ TypedArrayObject::staticFunctions[] = {
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,
@ -883,16 +895,7 @@ TypedArrayObject::sharedTypedArrayPrototypeClass = {
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>
@ -1905,24 +1908,36 @@ 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 */ \
@ -1936,19 +1951,43 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
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,
@ -1958,7 +1997,7 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
// 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
@ -1967,8 +2006,8 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
* 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 */ \
@ -1981,28 +2020,19 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
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

Просмотреть файл

@ -120,7 +120,9 @@ class TypedArrayObject : public NativeObject
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());

Просмотреть файл

@ -905,7 +905,7 @@ const Class UnboxedExpandoObject::class_ = {
0
};
const ObjectOps UnboxedPlainObject::objectOps_ = {
static const ObjectOps UnboxedPlainObjectObjectOps = {
UnboxedPlainObject::obj_lookupProperty,
UnboxedPlainObject::obj_defineProperty,
UnboxedPlainObject::obj_hasProperty,
@ -939,7 +939,7 @@ const Class UnboxedPlainObject::class_ = {
UnboxedPlainObject::trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
&UnboxedPlainObject::objectOps_
&UnboxedPlainObjectObjectOps
};
/////////////////////////////////////////////////////////////////////
@ -1591,7 +1591,7 @@ UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector&
return true;
}
const ObjectOps UnboxedArrayObject::objectOps_ = {
static const ObjectOps UnboxedArrayObjectObjectOps = {
UnboxedArrayObject::obj_lookupProperty,
UnboxedArrayObject::obj_defineProperty,
UnboxedArrayObject::obj_hasProperty,
@ -1629,7 +1629,7 @@ const Class UnboxedArrayObject::class_ = {
nullptr, /* weakmapKeyDelegateOp */
UnboxedArrayObject::objectMoved
},
&UnboxedArrayObject::objectOps_
&UnboxedArrayObjectObjectOps
};
/////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -238,7 +238,6 @@ class UnboxedPlainObject : public JSObject
uint8_t data_[1];
public:
static const ObjectOps objectOps_;
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
@ -375,7 +374,6 @@ class UnboxedArrayObject : public JSObject
static uint32_t exactCapacityIndex(uint32_t capacity);
public:
static const ObjectOps objectOps_;
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,

Просмотреть файл

@ -15,7 +15,7 @@
#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 */
@ -68,6 +68,13 @@ interface nsIScriptError : nsIConsoleMessage
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,

Просмотреть файл

@ -21,6 +21,7 @@
nsScriptErrorBase::nsScriptErrorBase()
: mMessage(),
mMessageName(),
mSourceName(),
mLineNumber(0),
mSourceLine(),
@ -152,6 +153,18 @@ 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,

Просмотреть файл

@ -31,6 +31,8 @@
#include "nsIObjectOutputStream.h"
#include "nsScriptSecurityManager.h"
#include "jsfriendapi.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace xpc;
@ -178,7 +180,6 @@ xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aFallbackMessage,
mWindowID = aWindowID;
ErrorReportToMessageString(aReport, mErrorMsg);
if (mErrorMsg.IsEmpty() && aFallbackMessage) {
mErrorMsg.AssignWithConversion(aFallbackMessage);
}
@ -190,6 +191,13 @@ xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aFallbackMessage,
}
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;
@ -248,6 +256,7 @@ xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack)
} else {
errorObject = new nsScriptError();
}
errorObject->SetErrorMessageName(mErrorMsgName);
NS_ENSURE_TRUE_VOID(consoleService && errorObject);
nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine,

Просмотреть файл

@ -2943,6 +2943,7 @@ protected:
InitializeOnMainThread();
nsString mMessage;
nsString mMessageName;
nsString mSourceName;
uint32_t mLineNumber;
nsString mSourceLine;

Просмотреть файл

@ -520,6 +520,7 @@ class ErrorReport {
public:
nsCString mCategory;
nsString mErrorMsgName;
nsString mErrorMsg;
nsString mFileName;
nsString mSourceLine;

Просмотреть файл

@ -573,11 +573,11 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
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;
}
@ -656,13 +656,13 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
// 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;
}
@ -864,11 +864,11 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags
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;
}
}
@ -905,11 +905,11 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags
// 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

Просмотреть файл

@ -545,7 +545,7 @@ AccessibleCaretEventHub::HandleMouseEvent(WidgetMouseEvent* aEvent)
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;
}
@ -553,7 +553,7 @@ AccessibleCaretEventHub::HandleTouchEvent(WidgetTouchEvent* aEvent)
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);
@ -781,7 +781,7 @@ 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;

Просмотреть файл

@ -67,7 +67,7 @@ EvictTouchPoint(RefPtr<dom::Touch>& aTouch,
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;
@ -118,7 +118,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
// 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) {
@ -126,8 +126,8 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
}
}
// 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
@ -141,7 +141,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
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;
@ -185,9 +185,9 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
// 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;
}
}
@ -205,7 +205,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent,
// 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) {

Просмотреть файл

@ -74,7 +74,7 @@ public:
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);
}
@ -163,7 +163,7 @@ public:
RefPtr<dom::Touch> touch(
new dom::Touch(identifier, point, radius, rotationAngle, force));
event->touches.AppendElement(touch);
event->mTouches.AppendElement(touch);
return Move(event);
}

Просмотреть файл

@ -1985,7 +1985,10 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
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();
}

Просмотреть файл

@ -1060,6 +1060,16 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
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)
{
@ -1094,7 +1104,7 @@ GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier)
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 {
@ -8801,6 +8811,10 @@ nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame,
}
}
if (ShouldDisableApzForElement(aContent)) {
metrics.SetForceDisableApz(true);
}
return metadata;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше