зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
3ccafa2b66
|
@ -1047,11 +1047,7 @@ pref("dom.ipc.plugins.sandbox-level.flash", 0);
|
|||
// On windows these levels are:
|
||||
// See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
|
||||
// SetSecurityLevelForContentProcess() for what the different settings mean.
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("security.sandbox.content.level", 5);
|
||||
#else
|
||||
pref("security.sandbox.content.level", 4);
|
||||
#endif
|
||||
|
||||
// This controls the depth of stack trace that is logged when Windows sandbox
|
||||
// logging is turned on. This is only currently available for the content
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const { getColor } = require("devtools/client/shared/theme");
|
||||
|
||||
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
|
||||
const { Provider } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
|
||||
const FontsApp = createFactory(require("./components/FontsApp"));
|
||||
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
|
@ -193,6 +191,11 @@ class FontInspector {
|
|||
previewFillStyle: getColor("body-color")
|
||||
};
|
||||
|
||||
// Add the includeVariations argument into the option to get font variation data.
|
||||
if (this.pageStyle.supportsFontVariations) {
|
||||
options.includeVariations = true;
|
||||
}
|
||||
|
||||
fonts = await this.getFontsForNode(node, options);
|
||||
otherFonts = await this.getFontsNotInNode(fonts, options);
|
||||
|
||||
|
|
|
@ -6,6 +6,45 @@
|
|||
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
/**
|
||||
* A font variation axis.
|
||||
*/
|
||||
const fontVariationAxis = exports.fontVariationAxis = {
|
||||
// The OpenType tag name of the variation axis
|
||||
tag: PropTypes.string,
|
||||
|
||||
// The axis name of the variation axis
|
||||
name: PropTypes.string,
|
||||
|
||||
// The minimum value of the variation axis
|
||||
minValue: PropTypes.number,
|
||||
|
||||
// The maximum value of the variation axis
|
||||
maxValue: PropTypes.number,
|
||||
|
||||
// The default value of the variation axis
|
||||
defaultValue: PropTypes.number,
|
||||
};
|
||||
|
||||
const fontVariationInstanceValue = exports.fontVariationInstanceValue = {
|
||||
// The axis name of the variation axis
|
||||
axis: PropTypes.string,
|
||||
|
||||
// The value of the variation axis
|
||||
value: PropTypes.number,
|
||||
};
|
||||
|
||||
/**
|
||||
* A font variation instance.
|
||||
*/
|
||||
const fontVariationInstance = exports.fontVariationInstance = {
|
||||
// The variation instance name of the font
|
||||
axis: PropTypes.string,
|
||||
|
||||
// The font variation values for the variation instance of the font
|
||||
values: PropTypes.arrayOf(PropTypes.shape(fontVariationInstanceValue)),
|
||||
};
|
||||
|
||||
/**
|
||||
* A single font.
|
||||
*/
|
||||
|
@ -27,6 +66,12 @@ const font = exports.font = {
|
|||
|
||||
// The URI of the font file
|
||||
URI: PropTypes.string,
|
||||
|
||||
// The variation axes of the font
|
||||
variationAxes: PropTypes.arrayOf(PropTypes.shape(fontVariationAxis)),
|
||||
|
||||
// The variation instances of the font
|
||||
variationInstances: PropTypes.arrayOf(PropTypes.shape(fontVariationInstance))
|
||||
};
|
||||
|
||||
exports.fontOptions = {
|
||||
|
@ -35,7 +80,7 @@ exports.fontOptions = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Font data
|
||||
* Font data.
|
||||
*/
|
||||
exports.fontData = {
|
||||
// The fonts used in the current element.
|
||||
|
|
|
@ -91,7 +91,7 @@ class SnapshotListItem extends Component {
|
|||
className: "save",
|
||||
}, L10N.getStr("snapshot.io.save"));
|
||||
|
||||
let deleteButton = !snapshot.path ? void 0 : dom.div({
|
||||
let deleteButton = !snapshot.path ? void 0 : dom.button({
|
||||
onClick: () => onDelete(snapshot),
|
||||
className: "delete",
|
||||
title: L10N.getStr("snapshot.io.delete")
|
||||
|
|
|
@ -811,7 +811,7 @@ class TreeNodeClass extends Component {
|
|||
id: this.props.id,
|
||||
className: classList.join(" "),
|
||||
role: "treeitem",
|
||||
"aria-level": this.props.depth,
|
||||
"aria-level": this.props.depth + 1,
|
||||
onClick: this.props.onClick,
|
||||
"aria-expanded": ariaExpanded,
|
||||
"data-expanded": this.props.expanded ? "" : undefined,
|
||||
|
|
|
@ -96,7 +96,9 @@ function isAccessibleTree(tree, options = {}) {
|
|||
for (let node of treeNodes) {
|
||||
ok(node.id, "TreeNode has an id");
|
||||
is(node.getAttribute("role"), "treeitem", "Tree item semantics is present");
|
||||
ok(node.hasAttribute("aria-level"), "Aria level attribute is set");
|
||||
is(parseInt(node.getAttribute("aria-level"), 10),
|
||||
parseInt(node.getAttribute("data-depth"), 10) + 1,
|
||||
"Aria level attribute is set correctly");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,9 +209,13 @@ html, body, #app, #memory-tool {
|
|||
|
||||
.snapshot-list-item .delete {
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
min-height: 1em;
|
||||
min-width: 1.3em;
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.snapshot-list-item .delete::before {
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
|
||||
|
||||
/**
|
||||
* A helper class that does all the work related to accessibility service
|
||||
* lifecycle (initialization, shutdown, consumer changes, etc) in parent
|
||||
* parent process. It is not guaranteed that the AccessibilityActor starts in
|
||||
* parent process and thus triggering these lifecycle functions directly is
|
||||
* extremely unreliable.
|
||||
*/
|
||||
class AccessibilityParent {
|
||||
constructor(mm, prefix) {
|
||||
this._msgName = `debug:${prefix}accessibility`;
|
||||
this.onAccessibilityMessage = this.onAccessibilityMessage.bind(this);
|
||||
this.setMessageManager(mm);
|
||||
|
||||
this.userPref = Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
|
||||
Services.obs.addObserver(this, "a11y-consumers-changed");
|
||||
Services.prefs.addObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
|
||||
|
||||
if (this.enabled && !this.accService) {
|
||||
// Set a local reference to an accessibility service if accessibility was
|
||||
// started elsewhere to ensure that parent process a11y service does not
|
||||
// get GC'ed away.
|
||||
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
}
|
||||
|
||||
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
|
||||
topic: "initialized",
|
||||
data: {
|
||||
canBeDisabled: this.canBeDisabled,
|
||||
canBeEnabled: this.canBeEnabled
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up message manager listener to listen for messages coming from the
|
||||
* AccessibilityActor when it is instantiated in the child process.
|
||||
*
|
||||
* @param {Object} mm
|
||||
* Message manager that corresponds to the current content tab.
|
||||
*/
|
||||
setMessageManager(mm) {
|
||||
if (this.messageManager === mm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.messageManager) {
|
||||
// If the browser was swapped we need to reset the message manager.
|
||||
let oldMM = this.messageManager;
|
||||
oldMM.removeMessageListener(this._msgName, this.onAccessibilityMessage);
|
||||
}
|
||||
|
||||
this.messageManager = mm;
|
||||
if (mm) {
|
||||
mm.addMessageListener(this._msgName, this.onAccessibilityMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Content AccessibilityActor message listener.
|
||||
*
|
||||
* @param {String} msg
|
||||
* Name of the action to perform.
|
||||
*/
|
||||
onAccessibilityMessage(msg) {
|
||||
let { action } = msg.json;
|
||||
switch (action) {
|
||||
case "enable":
|
||||
this.enable();
|
||||
break;
|
||||
|
||||
case "disable":
|
||||
this.disable();
|
||||
break;
|
||||
|
||||
case "disconnect":
|
||||
this.destroy();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic === "a11y-consumers-changed") {
|
||||
// This event is fired when accessibility service consumers change. Since
|
||||
// this observer lives in parent process there are 2 possible consumers of
|
||||
// a11y service: XPCOM and PlatformAPI (e.g. screen readers). We only care
|
||||
// about PlatformAPI consumer changes because when set, we can no longer
|
||||
// disable accessibility service.
|
||||
let { PlatformAPI } = JSON.parse(data);
|
||||
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
|
||||
topic: "can-be-disabled-change",
|
||||
data: !PlatformAPI
|
||||
});
|
||||
} else if (!this.disabling && topic === "nsPref:changed" &&
|
||||
data === PREF_ACCESSIBILITY_FORCE_DISABLED) {
|
||||
// PREF_ACCESSIBILITY_FORCE_DISABLED preference change event. When set to
|
||||
// >=1, it means that the user wants to disable accessibility service and
|
||||
// prevent it from starting in the future. Note: we also check
|
||||
// this.disabling state when handling this pref change because this is how
|
||||
// we disable the accessibility inspector itself.
|
||||
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
|
||||
topic: "can-be-enabled-change",
|
||||
data: Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter that indicates if accessibility service is enabled.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True if accessibility service is on.
|
||||
*/
|
||||
get enabled() {
|
||||
return Services.appinfo.accessibilityEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter that indicates if the accessibility service can be disabled.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True if accessibility service can be disabled.
|
||||
*/
|
||||
get canBeDisabled() {
|
||||
if (this.enabled) {
|
||||
let a11yService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
let { PlatformAPI } = JSON.parse(a11yService.getConsumers());
|
||||
return !PlatformAPI;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter that indicates if the accessibility service can be enabled.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True if accessibility service can be enabled.
|
||||
*/
|
||||
get canBeEnabled() {
|
||||
return Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable accessibility service (via XPCOM service).
|
||||
*/
|
||||
enable() {
|
||||
if (this.enabled || !this.canBeEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force disable accessibility service. This method removes the reference to
|
||||
* the XPCOM a11y service object and flips the
|
||||
* PREF_ACCESSIBILITY_FORCE_DISABLED preference on and off to shutdown a11y
|
||||
* service.
|
||||
*/
|
||||
disable() {
|
||||
if (!this.enabled || !this.canBeDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.disabling = true;
|
||||
this.accService = null;
|
||||
// Set PREF_ACCESSIBILITY_FORCE_DISABLED to 1 to force disable
|
||||
// accessibility service. This is the only way to guarantee an immediate
|
||||
// accessibility service shutdown in all processes. This also prevents
|
||||
// accessibility service from starting up in the future.
|
||||
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
|
||||
// Set PREF_ACCESSIBILITY_FORCE_DISABLED back to previous default or user
|
||||
// set value. This will not start accessibility service until the user
|
||||
// activates it again. It simply ensures that accessibility service can
|
||||
// start again (when value is below 1).
|
||||
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, this.userPref);
|
||||
delete this.disabling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy thie helper class, remove all listeners and if possible disable
|
||||
* accessibility service in the parent process.
|
||||
*/
|
||||
destroy() {
|
||||
Services.obs.removeObserver(this, "a11y-consumers-changed");
|
||||
Services.prefs.removeObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
|
||||
this.setMessageManager(null);
|
||||
this.accService = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup function that runs in parent process and setups AccessibleActor bits
|
||||
* that must always run in parent process.
|
||||
*
|
||||
* @param {Object} options.mm
|
||||
* Message manager that corresponds to the current content tab.
|
||||
* @param {String} options.prefix
|
||||
* Unique prefix for message manager messages.
|
||||
* @return {Object}
|
||||
* Defines event listeners for when client disconnects or browser gets
|
||||
* swapped.
|
||||
*/
|
||||
function setupParentProcess({ mm, prefix }) {
|
||||
let accessibility = new AccessibilityParent(mm, prefix);
|
||||
|
||||
return {
|
||||
onBrowserSwap: newMM => accessibility.setMessageManager(newMM),
|
||||
onDisconnected: () => {
|
||||
accessibility.destroy();
|
||||
accessibility = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.setupParentProcess = setupParentProcess;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -13,6 +13,7 @@ DIRS += [
|
|||
]
|
||||
|
||||
DevToolsModules(
|
||||
'accessibility-parent.js',
|
||||
'accessibility.js',
|
||||
'actor-registry.js',
|
||||
'addon.js',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"use strict";
|
||||
|
||||
const {Ci} = require("chrome");
|
||||
const Services = require("Services");
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const {LongStringActor} = require("devtools/server/actors/string");
|
||||
const InspectorUtils = require("InspectorUtils");
|
||||
|
@ -29,6 +30,9 @@ loader.lazyRequireGetter(this, "UPDATE_GENERAL",
|
|||
loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => {
|
||||
return InspectorUtils.getCSSPseudoElementNames();
|
||||
});
|
||||
loader.lazyGetter(this, "FONT_VARIATIONS_ENABLED", () => {
|
||||
return Services.prefs.getBoolPref("layout.css.font-variations.enabled");
|
||||
});
|
||||
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const FONT_PREVIEW_TEXT = "Abc";
|
||||
|
@ -115,7 +119,10 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
|||
// been fixed must make sure cssLogic.highlight(node) was called before.
|
||||
getAppliedCreatesStyleCache: true,
|
||||
// Whether addNewRule accepts the editAuthored argument.
|
||||
authoredStyles: true
|
||||
authoredStyles: true,
|
||||
// Whether getAllUsedFontFaces/getUsedFontFaces accepts the includeVariations
|
||||
// argument.
|
||||
fontVariations: FONT_VARIATIONS_ENABLED,
|
||||
}
|
||||
};
|
||||
},
|
||||
|
@ -320,6 +327,12 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
|||
size: size
|
||||
};
|
||||
}
|
||||
|
||||
if (options.includeVariations && FONT_VARIATIONS_ENABLED) {
|
||||
fontFace.variationAxes = font.getVariationAxes();
|
||||
fontFace.variationInstances = font.getVariationInstances();
|
||||
}
|
||||
|
||||
fontsArray.push(fontFace);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ support-files =
|
|||
!/devtools/server/tests/mochitest/hello-actor.js
|
||||
!/devtools/client/framework/test/shared-head.js
|
||||
|
||||
[browser_accessibility_node_events.js]
|
||||
[browser_accessibility_node.js]
|
||||
[browser_accessibility_node_events.js]
|
||||
[browser_accessibility_simple.js]
|
||||
[browser_accessibility_walker.js]
|
||||
[browser_animation_emitMutations.js]
|
||||
|
|
|
@ -10,7 +10,8 @@ add_task(async function () {
|
|||
let {client, walker, accessibility} =
|
||||
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
|
||||
|
||||
let a11yWalker = await accessibility.getWalker(walker);
|
||||
let a11yWalker = await accessibility.getWalker();
|
||||
await accessibility.enable();
|
||||
let buttonNode = await walker.querySelector(walker.rootNode, "#button");
|
||||
let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
|
||||
|
||||
|
@ -22,38 +23,23 @@ add_task(async function () {
|
|||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
domNodeType: 1
|
||||
domNodeType: 1,
|
||||
indexInParent: 1,
|
||||
states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
|
||||
actions: [ "Press" ],
|
||||
attributes: {
|
||||
"margin-top": "0px",
|
||||
display: "inline-block",
|
||||
"text-align": "center",
|
||||
"text-indent": "0px",
|
||||
"margin-left": "0px",
|
||||
tag: "button",
|
||||
"margin-right": "0px",
|
||||
id: "button",
|
||||
"margin-bottom": "0px"
|
||||
}
|
||||
});
|
||||
|
||||
info("Actions");
|
||||
let actions = await accessibleFront.getActions();
|
||||
is(actions.length, 1, "Accessible Front has correct number of actions");
|
||||
is(actions[0], "Press", "Accessible Front default action is correct");
|
||||
|
||||
info("Index in parent");
|
||||
let index = await accessibleFront.getIndexInParent();
|
||||
is(index, 1, "Accessible Front has correct index in parent");
|
||||
|
||||
info("State");
|
||||
let state = await accessibleFront.getState();
|
||||
SimpleTest.isDeeply(state,
|
||||
["focusable", "selectable text", "opaque", "enabled", "sensitive"],
|
||||
"Accessible Front has correct states");
|
||||
|
||||
info("Attributes");
|
||||
let attributes = await accessibleFront.getAttributes();
|
||||
SimpleTest.isDeeply(attributes, {
|
||||
"margin-top": "0px",
|
||||
display: "inline-block",
|
||||
"text-align": "center",
|
||||
"text-indent": "0px",
|
||||
"margin-left": "0px",
|
||||
tag: "button",
|
||||
"margin-right": "0px",
|
||||
id: "button",
|
||||
"margin-bottom": "0px"
|
||||
}, "Accessible Front has correct attributes");
|
||||
|
||||
info("Children");
|
||||
let children = await accessibleFront.children();
|
||||
is(children.length, 1, "Accessible Front has correct number of children");
|
||||
|
@ -62,13 +48,8 @@ add_task(async function () {
|
|||
role: "text leaf"
|
||||
});
|
||||
|
||||
info("DOM Node");
|
||||
let node = await accessibleFront.getDOMNode(walker);
|
||||
is(node, buttonNode, "Accessible Front has correct DOM node");
|
||||
|
||||
let a11yShutdown = waitForA11yShutdown();
|
||||
await accessibility.disable();
|
||||
await waitForA11yShutdown();
|
||||
await client.close();
|
||||
forceCollections();
|
||||
await a11yShutdown;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -10,8 +10,10 @@ add_task(async function () {
|
|||
let {client, walker, accessibility} =
|
||||
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
|
||||
|
||||
let a11yWalker = await accessibility.getWalker(walker);
|
||||
let a11yDoc = await a11yWalker.getDocument();
|
||||
let a11yWalker = await accessibility.getWalker();
|
||||
await accessibility.enable();
|
||||
let rootNode = await walker.getRootNode();
|
||||
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
|
||||
let buttonNode = await walker.querySelector(walker.rootNode, "#button");
|
||||
let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
|
||||
let sliderNode = await walker.querySelector(walker.rootNode, "#slider");
|
||||
|
@ -26,7 +28,21 @@ add_task(async function () {
|
|||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
domNodeType: 1
|
||||
domNodeType: 1,
|
||||
indexInParent: 1,
|
||||
states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
|
||||
actions: [ "Press" ],
|
||||
attributes: {
|
||||
"margin-top": "0px",
|
||||
display: "inline-block",
|
||||
"text-align": "center",
|
||||
"text-indent": "0px",
|
||||
"margin-left": "0px",
|
||||
tag: "button",
|
||||
"margin-right": "0px",
|
||||
id: "button",
|
||||
"margin-bottom": "0px"
|
||||
}
|
||||
});
|
||||
|
||||
info("Name change event");
|
||||
|
@ -45,27 +61,35 @@ add_task(async function () {
|
|||
content.document.getElementById("button").removeAttribute("aria-describedby")));
|
||||
|
||||
info("State change event");
|
||||
let states = await accessibleFront.getState();
|
||||
let expectedStates = ["unavailable", "selectable text", "opaque"];
|
||||
SimpleTest.isDeeply(states, ["focusable", "selectable text", "opaque",
|
||||
"enabled", "sensitive"], "States are correct");
|
||||
await emitA11yEvent(accessibleFront, "state-change",
|
||||
newStates => SimpleTest.isDeeply(newStates, expectedStates,
|
||||
"States are updated"),
|
||||
() => ContentTask.spawn(browser, null, () =>
|
||||
await emitA11yEvent(accessibleFront, "states-change",
|
||||
newStates => {
|
||||
checkA11yFront(accessibleFront, { states: expectedStates });
|
||||
SimpleTest.isDeeply(newStates, expectedStates, "States are updated");
|
||||
}, () => ContentTask.spawn(browser, null, () =>
|
||||
content.document.getElementById("button").setAttribute("disabled", true)));
|
||||
states = await accessibleFront.getState();
|
||||
SimpleTest.isDeeply(states, expectedStates, "States are updated");
|
||||
|
||||
info("Attributes change event");
|
||||
let attrs = await accessibleFront.getAttributes();
|
||||
ok(!attrs.live, "Attribute is not present");
|
||||
await emitA11yEvent(accessibleFront, "attributes-change",
|
||||
newAttrs => is(newAttrs.live, "polite", "Attributes are updated"),
|
||||
() => ContentTask.spawn(browser, null, () =>
|
||||
newAttrs => {
|
||||
checkA11yFront(accessibleFront, { attributes: {
|
||||
"container-live": "polite",
|
||||
display: "inline-block",
|
||||
"event-from-input": "false",
|
||||
"explicit-name": "true",
|
||||
id: "button",
|
||||
live: "polite",
|
||||
"margin-bottom": "0px",
|
||||
"margin-left": "0px",
|
||||
"margin-right": "0px",
|
||||
"margin-top": "0px",
|
||||
tag: "button",
|
||||
"text-align": "center",
|
||||
"text-indent": "0px"
|
||||
}});
|
||||
is(newAttrs.live, "polite", "Attributes are updated");
|
||||
}, () => ContentTask.spawn(browser, null, () =>
|
||||
content.document.getElementById("button").setAttribute("aria-live", "polite")));
|
||||
attrs = await accessibleFront.getAttributes();
|
||||
is(attrs.live, "polite", "Attributes are updated");
|
||||
|
||||
info("Value change event");
|
||||
checkA11yFront(accessibleSliderFront, { value: "5" });
|
||||
|
@ -76,18 +100,29 @@ add_task(async function () {
|
|||
|
||||
info("Reorder event");
|
||||
is(accessibleSliderFront.childCount, 1, "Slider has only 1 child");
|
||||
let [firstChild, ] = await accessibleSliderFront.children();
|
||||
is(firstChild.indexInParent, 0, "Slider's first child has correct index in parent");
|
||||
await emitA11yEvent(accessibleSliderFront, "reorder",
|
||||
childCount => is(childCount, 2, "Child count is updated"),
|
||||
() => ContentTask.spawn(browser, null, () => {
|
||||
let button = content.document.createElement("button");
|
||||
childCount => {
|
||||
is(childCount, 2, "Child count is updated");
|
||||
is(accessibleSliderFront.childCount, 2, "Child count is updated");
|
||||
is(firstChild.indexInParent, 1,
|
||||
"Slider's first child has an updated index in parent");
|
||||
}, () => ContentTask.spawn(browser, null, () => {
|
||||
let doc = content.document;
|
||||
let slider = doc.getElementById("slider");
|
||||
let button = doc.createElement("button");
|
||||
button.innerText = "Slider button";
|
||||
content.document.getElementById("slider").appendChild(button);
|
||||
content.document.getElementById("slider").insertBefore(button, slider.firstChild);
|
||||
}));
|
||||
is(accessibleSliderFront.childCount, 2, "Child count is updated");
|
||||
|
||||
let a11yShutdown = waitForA11yShutdown();
|
||||
await emitA11yEvent(firstChild, "index-in-parent-change", indexInParent =>
|
||||
is(indexInParent, 0, "Slider's first child has an updated index in parent"), () =>
|
||||
ContentTask.spawn(browser, null, () =>
|
||||
content.document.getElementById("slider").firstChild.remove()));
|
||||
|
||||
await accessibility.disable();
|
||||
await waitForA11yShutdown();
|
||||
await client.close();
|
||||
forceCollections();
|
||||
await a11yShutdown;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -4,10 +4,19 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
|
||||
|
||||
function checkAccessibilityState(accessibility, expected) {
|
||||
let { enabled, canBeDisabled, canBeEnabled } = accessibility;
|
||||
is(enabled, expected.enabled, "Enabled state is correct.");
|
||||
is(canBeDisabled, expected.canBeDisabled, "canBeDisabled state is correct.");
|
||||
is(canBeEnabled, expected.canBeEnabled, "canBeEnabled state is correct.");
|
||||
}
|
||||
|
||||
// Simple checks for the AccessibilityActor and AccessibleWalkerActor
|
||||
|
||||
add_task(async function () {
|
||||
let {client, accessibility} = await initAccessibilityFrontForUrl(
|
||||
let { walker: domWalker, client, accessibility} = await initAccessibilityFrontForUrl(
|
||||
"data:text/html;charset=utf-8,<title>test</title><div></div>");
|
||||
|
||||
ok(accessibility, "The AccessibilityFront was created");
|
||||
|
@ -16,6 +25,44 @@ add_task(async function () {
|
|||
let a11yWalker = await accessibility.getWalker();
|
||||
ok(a11yWalker, "The AccessibleWalkerFront was returned");
|
||||
|
||||
checkAccessibilityState(accessibility,
|
||||
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
|
||||
|
||||
info("Force disable accessibility service: updates canBeEnabled flag");
|
||||
let onEvent = accessibility.once("can-be-enabled-change");
|
||||
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
|
||||
await onEvent;
|
||||
checkAccessibilityState(accessibility,
|
||||
{ enabled: false, canBeDisabled: true, canBeEnabled: false });
|
||||
|
||||
info("Clear force disable accessibility service: updates canBeEnabled flag");
|
||||
onEvent = accessibility.once("can-be-enabled-change");
|
||||
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
|
||||
await onEvent;
|
||||
checkAccessibilityState(accessibility,
|
||||
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
|
||||
|
||||
info("Initialize accessibility service");
|
||||
let initEvent = accessibility.once("init");
|
||||
await accessibility.enable();
|
||||
await waitForA11yInit();
|
||||
await initEvent;
|
||||
checkAccessibilityState(accessibility,
|
||||
{ enabled: true, canBeDisabled: true, canBeEnabled: true });
|
||||
|
||||
a11yWalker = await accessibility.getWalker();
|
||||
let rootNode = await domWalker.getRootNode();
|
||||
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
|
||||
ok(a11yDoc, "Accessible document actor is created");
|
||||
|
||||
info("Shutdown accessibility service");
|
||||
let shutdownEvent = accessibility.once("shutdown");
|
||||
await accessibility.disable();
|
||||
await waitForA11yShutdown();
|
||||
await shutdownEvent;
|
||||
checkAccessibilityState(accessibility,
|
||||
{ enabled: false, canBeDisabled: true, canBeEnabled: true });
|
||||
|
||||
await client.close();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -10,10 +10,12 @@ add_task(async function () {
|
|||
let {client, walker, accessibility} =
|
||||
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
|
||||
|
||||
let a11yWalker = await accessibility.getWalker(walker);
|
||||
let a11yWalker = await accessibility.getWalker();
|
||||
ok(a11yWalker, "The AccessibleWalkerFront was returned");
|
||||
|
||||
let a11yDoc = await a11yWalker.getDocument();
|
||||
await accessibility.enable();
|
||||
let rootNode = await walker.getRootNode();
|
||||
let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
|
||||
ok(a11yDoc, "The AccessibleFront for root doc is created");
|
||||
|
||||
let children = await a11yWalker.children();
|
||||
|
@ -30,6 +32,15 @@ add_task(async function () {
|
|||
role: "pushbutton"
|
||||
});
|
||||
|
||||
let ancestry = await a11yWalker.getAncestry(accessibleFront);
|
||||
is(ancestry.length, 1, "Button is a direct child of a root document.");
|
||||
is(ancestry[0].accessible, a11yDoc,
|
||||
"Button's only ancestor is a root document");
|
||||
is(ancestry[0].children.length, 3,
|
||||
"Root doc should have correct number of children");
|
||||
ok(ancestry[0].children.includes(accessibleFront),
|
||||
"Button accessible front is in root doc's children");
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
// Ensure name-change event is emitted by walker when cached accessible's name
|
||||
|
@ -67,9 +78,55 @@ add_task(async function () {
|
|||
() => ContentTask.spawn(browser, null, () =>
|
||||
content.document.getElementById("button").remove()));
|
||||
|
||||
let a11yShutdown = waitForA11yShutdown();
|
||||
let shown = await a11yWalker.highlightAccessible(docChildren[0]);
|
||||
ok(shown, "AccessibleHighlighter highlighted the node");
|
||||
|
||||
shown = await a11yWalker.highlightAccessible(a11yDoc);
|
||||
ok(!shown, "AccessibleHighlighter does not highlight an accessible with no bounds");
|
||||
await a11yWalker.unhighlight();
|
||||
|
||||
info("Checking AccessibleWalker picker functionality");
|
||||
ok(a11yWalker.pick, "AccessibleWalker pick method exists");
|
||||
ok(a11yWalker.pickAndFocus, "AccessibleWalker pickAndFocus method exists");
|
||||
ok(a11yWalker.cancelPick, "AccessibleWalker cancelPick method exists");
|
||||
|
||||
let onPickerEvent = a11yWalker.once("picker-accessible-hovered");
|
||||
await a11yWalker.pick();
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
|
||||
let acc = await onPickerEvent;
|
||||
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
|
||||
|
||||
onPickerEvent = a11yWalker.once("picker-accessible-previewed");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { shiftKey: true }, browser);
|
||||
acc = await onPickerEvent;
|
||||
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
|
||||
|
||||
onPickerEvent = a11yWalker.once("picker-accessible-canceled");
|
||||
await BrowserTestUtils.synthesizeKey("VK_ESCAPE", { type: "keydown" }, browser);
|
||||
await onPickerEvent;
|
||||
|
||||
onPickerEvent = a11yWalker.once("picker-accessible-hovered");
|
||||
await a11yWalker.pick();
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
|
||||
await onPickerEvent;
|
||||
|
||||
onPickerEvent = a11yWalker.once("picker-accessible-picked");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { }, browser);
|
||||
acc = await onPickerEvent;
|
||||
checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
|
||||
|
||||
await a11yWalker.cancelPick();
|
||||
|
||||
info("Checking document-ready event fired by walker when top level accessible " +
|
||||
"document is recreated.");
|
||||
let reloaded = BrowserTestUtils.browserLoaded(browser);
|
||||
let documentReady = a11yWalker.once("document-ready");
|
||||
browser.reload();
|
||||
await reloaded;
|
||||
await documentReady;
|
||||
|
||||
await accessibility.disable();
|
||||
await waitForA11yShutdown();
|
||||
await client.close();
|
||||
forceCollections();
|
||||
await a11yShutdown;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -89,6 +89,8 @@ async function initAccessibilityFrontForUrl(url) {
|
|||
let walker = await inspector.getWalker();
|
||||
let accessibility = AccessibilityFront(client, form);
|
||||
|
||||
await accessibility.bootstrap();
|
||||
|
||||
return {inspector, walker, accessibility, client};
|
||||
}
|
||||
|
||||
|
@ -308,24 +310,47 @@ function checkA11yFront(front, expected, expectedFront) {
|
|||
}
|
||||
|
||||
for (let key in expected) {
|
||||
is(front[key], expected[key], `accessibility front has correct ${key}`);
|
||||
if (["actions", "states", "attributes"].includes(key)) {
|
||||
SimpleTest.isDeeply(front[key], expected[key],
|
||||
`Accessible Front has correct ${key}`);
|
||||
} else {
|
||||
is(front[key], expected[key], `accessibility front has correct ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getA11yInitOrShutdownPromise() {
|
||||
return new Promise(resolve => {
|
||||
let observe = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
|
||||
resolve(data);
|
||||
};
|
||||
Services.obs.addObserver(observe, "a11y-init-or-shutdown");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for accessibility service to shut down. We consider it shut down when
|
||||
* an "a11y-init-or-shutdown" event is received with a value of "0".
|
||||
*/
|
||||
async function waitForA11yShutdown() {
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, {}, () =>
|
||||
new Promise(resolve => {
|
||||
let observe = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
|
||||
if (!Services.appinfo.accessibilityEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data === "0") {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(observe, "a11y-init-or-shutdown");
|
||||
}));
|
||||
await getA11yInitOrShutdownPromise().then(data =>
|
||||
data === "0" ? Promise.resolve() : Promise.reject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for accessibility service to initialize. We consider it initialized when
|
||||
* an "a11y-init-or-shutdown" event is received with a value of "1".
|
||||
*/
|
||||
async function waitForA11yInit() {
|
||||
if (Services.appinfo.accessibilityEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await getA11yInitOrShutdownPromise().then(data =>
|
||||
data === "1" ? Promise.resolve() : Promise.reject());
|
||||
}
|
||||
|
|
|
@ -3,50 +3,74 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const {
|
||||
custom,
|
||||
Front,
|
||||
FrontClassWithSpec,
|
||||
preEvent,
|
||||
types
|
||||
preEvent
|
||||
} = require("devtools/shared/protocol.js");
|
||||
const {
|
||||
accessibleSpec,
|
||||
accessibleWalkerSpec,
|
||||
accessibilitySpec
|
||||
} = require("devtools/shared/specs/accessibility");
|
||||
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const ACCESSIBLE_PROPERTIES = [
|
||||
"role",
|
||||
"name",
|
||||
"value",
|
||||
"description",
|
||||
"help",
|
||||
"keyboardShortcut",
|
||||
"childCount",
|
||||
"domNodeType"
|
||||
];
|
||||
|
||||
const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
|
||||
initialize(client, form) {
|
||||
Front.prototype.initialize.call(this, client, form);
|
||||
|
||||
// Define getters for accesible properties that are received from the actor.
|
||||
// Note: we would like accessible properties to be iterable for a11y
|
||||
// clients.
|
||||
for (let key of ACCESSIBLE_PROPERTIES) {
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
return this._form[key];
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
marshallPool() {
|
||||
return this.walker;
|
||||
return this.parent();
|
||||
},
|
||||
|
||||
get role() {
|
||||
return this._form.role;
|
||||
},
|
||||
|
||||
get name() {
|
||||
return this._form.name;
|
||||
},
|
||||
|
||||
get value() {
|
||||
return this._form.value;
|
||||
},
|
||||
|
||||
get description() {
|
||||
return this._form.description;
|
||||
},
|
||||
|
||||
get help() {
|
||||
return this._form.help;
|
||||
},
|
||||
|
||||
get keyboardShortcut() {
|
||||
return this._form.keyboardShortcut;
|
||||
},
|
||||
|
||||
get childCount() {
|
||||
return this._form.childCount;
|
||||
},
|
||||
|
||||
get domNodeType() {
|
||||
return this._form.domNodeType;
|
||||
},
|
||||
|
||||
get indexInParent() {
|
||||
return this._form.indexInParent;
|
||||
},
|
||||
|
||||
get states() {
|
||||
return this._form.states;
|
||||
},
|
||||
|
||||
get actions() {
|
||||
return this._form.actions;
|
||||
},
|
||||
|
||||
get attributes() {
|
||||
return this._form.attributes;
|
||||
},
|
||||
|
||||
form(form, detail) {
|
||||
|
@ -57,25 +81,14 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
|
|||
|
||||
this.actorID = form.actor;
|
||||
this._form = form;
|
||||
DevToolsUtils.defineLazyGetter(this, "walker", () =>
|
||||
types.getType("accessiblewalker").read(this._form.walker, this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a dom node front from accessible actor's raw accessible object's
|
||||
* DONNode property.
|
||||
*/
|
||||
getDOMNode(domWalker) {
|
||||
return domWalker.getNodeFromActor(this.actorID,
|
||||
["rawAccessible", "DOMNode"]);
|
||||
},
|
||||
|
||||
nameChange: preEvent("name-change", function (name, parent) {
|
||||
nameChange: preEvent("name-change", function (name, parent, walker) {
|
||||
this._form.name = name;
|
||||
// Name change event affects the tree rendering, we fire this event on
|
||||
// accessibility walker as the point of interaction for UI.
|
||||
if (this.walker) {
|
||||
events.emit(this.walker, "name-change", this, parent);
|
||||
if (walker) {
|
||||
events.emit(walker, "name-change", this, parent);
|
||||
}
|
||||
}),
|
||||
|
||||
|
@ -95,21 +108,37 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
|
|||
this._form.keyboardShortcut = keyboardShortcut;
|
||||
}),
|
||||
|
||||
reorder: preEvent("reorder", function (childCount) {
|
||||
reorder: preEvent("reorder", function (childCount, walker) {
|
||||
this._form.childCount = childCount;
|
||||
// Reorder event affects the tree rendering, we fire this event on
|
||||
// accessibility walker as the point of interaction for UI.
|
||||
if (this.walker) {
|
||||
events.emit(this.walker, "reorder", this);
|
||||
if (walker) {
|
||||
events.emit(walker, "reorder", this);
|
||||
}
|
||||
}),
|
||||
|
||||
textChange: preEvent("text-change", function () {
|
||||
textChange: preEvent("text-change", function (walker) {
|
||||
// Text event affects the tree rendering, we fire this event on
|
||||
// accessibility walker as the point of interaction for UI.
|
||||
if (this.walker) {
|
||||
events.emit(this.walker, "text-change", this);
|
||||
if (walker) {
|
||||
events.emit(walker, "text-change", this);
|
||||
}
|
||||
}),
|
||||
|
||||
indexInParentChange: preEvent("index-in-parent-change", function (indexInParent) {
|
||||
this._form.indexInParent = indexInParent;
|
||||
}),
|
||||
|
||||
statesChange: preEvent("states-change", function (states) {
|
||||
this._form.states = states;
|
||||
}),
|
||||
|
||||
actionsChange: preEvent("actions-change", function (actions) {
|
||||
this._form.actions = actions;
|
||||
}),
|
||||
|
||||
attributesChange: preEvent("attributes-change", function (attributes) {
|
||||
this._form.attributes = attributes;
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -120,7 +149,17 @@ const AccessibleWalkerFront = FrontClassWithSpec(accessibleWalkerSpec, {
|
|||
|
||||
form(json) {
|
||||
this.actorID = json.actor;
|
||||
}
|
||||
},
|
||||
|
||||
pick: custom(function (doFocus) {
|
||||
if (doFocus) {
|
||||
return this.pickAndFocus();
|
||||
}
|
||||
|
||||
return this._pick();
|
||||
}, {
|
||||
impl: "_pick"
|
||||
})
|
||||
});
|
||||
|
||||
const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
|
||||
|
@ -128,7 +167,33 @@ const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
|
|||
Front.prototype.initialize.call(this, client, form);
|
||||
this.actorID = form.accessibilityActor;
|
||||
this.manage(this);
|
||||
}
|
||||
},
|
||||
|
||||
bootstrap: custom(function () {
|
||||
return this._bootstrap().then(state => {
|
||||
this.enabled = state.enabled;
|
||||
this.canBeEnabled = state.canBeEnabled;
|
||||
this.canBeDisabled = state.canBeDisabled;
|
||||
});
|
||||
}, {
|
||||
impl: "_bootstrap"
|
||||
}),
|
||||
|
||||
init: preEvent("init", function () {
|
||||
this.enabled = true;
|
||||
}),
|
||||
|
||||
shutdown: preEvent("shutdown", function () {
|
||||
this.enabled = false;
|
||||
}),
|
||||
|
||||
canBeEnabled: preEvent("can-be-enabled-change", function (canBeEnabled) {
|
||||
this.canBeEnabled = canBeEnabled;
|
||||
}),
|
||||
|
||||
canBeDisabled: preEvent("can-be-disabled-change", function (canBeDisabled) {
|
||||
this.canBeDisabled = canBeDisabled;
|
||||
})
|
||||
});
|
||||
|
||||
exports.AccessibleFront = AccessibleFront;
|
||||
|
|
|
@ -47,6 +47,10 @@ const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
|
|||
return this._form.traits && this._form.traits.authoredStyles;
|
||||
},
|
||||
|
||||
get supportsFontVariations() {
|
||||
return this._form.traits && this._form.traits.fontVariations;
|
||||
},
|
||||
|
||||
getMatchedSelectors: custom(function (node, property, options) {
|
||||
return this._getMatchedSelectors(node, property, options).then(ret => {
|
||||
return ret.matched;
|
||||
|
|
|
@ -9,6 +9,17 @@ const { Arg, generateActorSpec, RetVal, types } = protocol;
|
|||
|
||||
types.addActorType("accessible");
|
||||
|
||||
/**
|
||||
* Accessible with children listed in the ancestry structure calculated by the
|
||||
* walker.
|
||||
*/
|
||||
types.addDictType("accessibleWithChildren", {
|
||||
// Accessible
|
||||
accessible: "accessible",
|
||||
// Accessible's children
|
||||
children: "array:accessible"
|
||||
});
|
||||
|
||||
const accessibleSpec = generateActorSpec({
|
||||
typeName: "accessible",
|
||||
|
||||
|
@ -20,7 +31,8 @@ const accessibleSpec = generateActorSpec({
|
|||
"name-change": {
|
||||
type: "nameChange",
|
||||
name: Arg(0, "string"),
|
||||
parent: Arg(1, "nullable:accessible")
|
||||
parent: Arg(1, "nullable:accessible"),
|
||||
walker: Arg(2, "nullable:accessiblewalker")
|
||||
},
|
||||
"value-change": {
|
||||
type: "valueChange",
|
||||
|
@ -30,13 +42,13 @@ const accessibleSpec = generateActorSpec({
|
|||
type: "descriptionChange",
|
||||
description: Arg(0, "string")
|
||||
},
|
||||
"state-change": {
|
||||
type: "stateChange",
|
||||
"states-change": {
|
||||
type: "statesChange",
|
||||
states: Arg(0, "array:string")
|
||||
},
|
||||
"attributes-change": {
|
||||
type: "attributesChange",
|
||||
states: Arg(0, "json")
|
||||
attributes: Arg(0, "json")
|
||||
},
|
||||
"help-change": {
|
||||
type: "helpChange",
|
||||
|
@ -48,38 +60,20 @@ const accessibleSpec = generateActorSpec({
|
|||
},
|
||||
"reorder": {
|
||||
type: "reorder",
|
||||
childCount: Arg(0, "number")
|
||||
childCount: Arg(0, "number"),
|
||||
walker: Arg(1, "nullable:accessiblewalker")
|
||||
},
|
||||
"text-change": {
|
||||
type: "textChange"
|
||||
type: "textChange",
|
||||
walker: Arg(0, "nullable:accessiblewalker")
|
||||
},
|
||||
"index-in-parent-change": {
|
||||
type: "indexInParentChange",
|
||||
indexInParent: Arg(0, "number")
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getActions: {
|
||||
request: {},
|
||||
response: {
|
||||
actions: RetVal("array:string")
|
||||
}
|
||||
},
|
||||
getIndexInParent: {
|
||||
request: {},
|
||||
response: {
|
||||
indexInParent: RetVal("number")
|
||||
}
|
||||
},
|
||||
getState: {
|
||||
request: {},
|
||||
response: {
|
||||
states: RetVal("array:string")
|
||||
}
|
||||
},
|
||||
getAttributes: {
|
||||
request: {},
|
||||
response: {
|
||||
attributes: RetVal("json")
|
||||
}
|
||||
},
|
||||
children: {
|
||||
request: {},
|
||||
response: {
|
||||
|
@ -96,6 +90,24 @@ const accessibleWalkerSpec = generateActorSpec({
|
|||
"accessible-destroy": {
|
||||
type: "accessibleDestroy",
|
||||
accessible: Arg(0, "accessible")
|
||||
},
|
||||
"document-ready": {
|
||||
type: "documentReady",
|
||||
},
|
||||
"picker-accessible-picked": {
|
||||
type: "pickerAccessiblePicked",
|
||||
accessible: Arg(0, "nullable:accessible")
|
||||
},
|
||||
"picker-accessible-previewed": {
|
||||
type: "pickerAccessiblePreviewed",
|
||||
accessible: Arg(0, "nullable:accessible")
|
||||
},
|
||||
"picker-accessible-hovered": {
|
||||
type: "pickerAccessibleHovered",
|
||||
accessible: Arg(0, "nullable:accessible")
|
||||
},
|
||||
"picker-accessible-canceled": {
|
||||
type: "pickerAccessibleCanceled"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -106,30 +118,76 @@ const accessibleWalkerSpec = generateActorSpec({
|
|||
children: RetVal("array:accessible")
|
||||
}
|
||||
},
|
||||
getDocument: {
|
||||
request: {},
|
||||
response: {
|
||||
document: RetVal("accessible")
|
||||
}
|
||||
},
|
||||
getAccessibleFor: {
|
||||
request: { node: Arg(0, "domnode") },
|
||||
response: {
|
||||
accessible: RetVal("accessible")
|
||||
}
|
||||
}
|
||||
},
|
||||
getAncestry: {
|
||||
request: { accessible: Arg(0, "accessible") },
|
||||
response: {
|
||||
ancestry: RetVal("array:accessibleWithChildren")
|
||||
}
|
||||
},
|
||||
highlightAccessible: {
|
||||
request: {
|
||||
accessible: Arg(0, "accessible"),
|
||||
options: Arg(1, "nullable:json")
|
||||
},
|
||||
response: {
|
||||
value: RetVal("nullable:boolean")
|
||||
}
|
||||
},
|
||||
unhighlight: {
|
||||
request: {}
|
||||
},
|
||||
pick: {},
|
||||
pickAndFocus: {},
|
||||
cancelPick: {}
|
||||
}
|
||||
});
|
||||
|
||||
const accessibilitySpec = generateActorSpec({
|
||||
typeName: "accessibility",
|
||||
|
||||
events: {
|
||||
"init": {
|
||||
type: "init"
|
||||
},
|
||||
"shutdown": {
|
||||
type: "shutdown"
|
||||
},
|
||||
"can-be-disabled-change": {
|
||||
type: "canBeDisabledChange",
|
||||
canBeDisabled: Arg(0, "boolean")
|
||||
},
|
||||
"can-be-enabled-change": {
|
||||
type: "canBeEnabledChange",
|
||||
canBeEnabled: Arg(0, "boolean")
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
bootstrap: {
|
||||
request: {},
|
||||
response: {
|
||||
state: RetVal("json")
|
||||
}
|
||||
},
|
||||
getWalker: {
|
||||
request: {},
|
||||
response: {
|
||||
walker: RetVal("accessiblewalker")
|
||||
}
|
||||
},
|
||||
enable: {
|
||||
request: {},
|
||||
response: {}
|
||||
},
|
||||
disable: {
|
||||
request: {},
|
||||
response: {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -58,6 +58,24 @@ types.addDictType("fontpreview", {
|
|||
size: "json"
|
||||
});
|
||||
|
||||
types.addDictType("fontvariationaxis", {
|
||||
tag: "string",
|
||||
name: "string",
|
||||
minValue: "number",
|
||||
maxValue: "number",
|
||||
defaultValue: "number"
|
||||
});
|
||||
|
||||
types.addDictType("fontvariationinstancevalue", {
|
||||
axis: "string",
|
||||
value: "number"
|
||||
});
|
||||
|
||||
types.addDictType("fontvariationinstance", {
|
||||
name: "string",
|
||||
values: "array:fontvariationinstancevalue"
|
||||
});
|
||||
|
||||
types.addDictType("fontface", {
|
||||
name: "string",
|
||||
CSSFamilyName: "string",
|
||||
|
@ -67,7 +85,9 @@ types.addDictType("fontface", {
|
|||
format: "string",
|
||||
preview: "nullable:fontpreview",
|
||||
localName: "string",
|
||||
metadata: "string"
|
||||
metadata: "string",
|
||||
variationAxes: "array:fontvariationaxis",
|
||||
variationInstances: "array:fontvariationinstance"
|
||||
});
|
||||
|
||||
const pageStyleSpec = generateActorSpec({
|
||||
|
@ -95,6 +115,7 @@ const pageStyleSpec = generateActorSpec({
|
|||
getAllUsedFontFaces: {
|
||||
request: {
|
||||
includePreviews: Option(0, "boolean"),
|
||||
includeVariations: Option(1, "boolean"),
|
||||
previewText: Option(0, "string"),
|
||||
previewFontSize: Option(0, "string"),
|
||||
previewFillStyle: Option(0, "string")
|
||||
|
@ -107,6 +128,7 @@ const pageStyleSpec = generateActorSpec({
|
|||
request: {
|
||||
node: Arg(0, "domnode"),
|
||||
includePreviews: Option(1, "boolean"),
|
||||
includeVariations: Option(1, "boolean"),
|
||||
previewText: Option(1, "string"),
|
||||
previewFontSize: Option(1, "string"),
|
||||
previewFillStyle: Option(1, "string")
|
||||
|
|
|
@ -423,6 +423,11 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!definition->mCallbacks) {
|
||||
// definition has been unlinked. Don't try to mess with it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto callback =
|
||||
|
|
|
@ -1102,7 +1102,12 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|||
nsContentUtils::Retarget(relatedTargetAsNode, this);
|
||||
nsCOMPtr<nsINode> targetInKnownToBeHandledScope =
|
||||
FindChromeAccessOnlySubtreeOwner(aVisitor.mTargetInKnownToBeHandledScope);
|
||||
if (nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
||||
// If aVisitor.mTargetInKnownToBeHandledScope wasn't nsINode,
|
||||
// targetInKnownToBeHandledScope will be null. This may happen when
|
||||
// dispatching event to Window object in a content page and
|
||||
// propagating the event to a chrome Element.
|
||||
if (targetInKnownToBeHandledScope &&
|
||||
nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
||||
this, targetInKnownToBeHandledScope->SubtreeRoot())) {
|
||||
// Part of step 11.4.
|
||||
// "If target's root is a shadow-including inclusive ancestor of
|
||||
|
|
|
@ -1445,8 +1445,8 @@ nsIDocument::nsIDocument()
|
|||
mHasHadScriptHandlingObject(false),
|
||||
mIsBeingUsedAsImage(false),
|
||||
mIsSyntheticDocument(false),
|
||||
mHasLinksToUpdate(false),
|
||||
mHasLinksToUpdateRunnable(false),
|
||||
mFlushingPendingLinkUpdates(false),
|
||||
mMayHaveDOMMutationObservers(false),
|
||||
mMayHaveAnimationObservers(false),
|
||||
mHasMixedActiveContentLoaded(false),
|
||||
|
@ -1491,7 +1491,6 @@ nsIDocument::nsIDocument()
|
|||
mType(eUnknown),
|
||||
mDefaultElementType(0),
|
||||
mAllowXULXBL(eTriUnset),
|
||||
mIsLinkUpdateRegistrationsForbidden(false),
|
||||
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
|
||||
mSandboxFlags(0),
|
||||
mPartID(0),
|
||||
|
@ -9612,15 +9611,13 @@ nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator,
|
|||
void
|
||||
nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
|
||||
|
||||
if (aLink->HasPendingLinkUpdate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
aLink->SetHasPendingLinkUpdate();
|
||||
|
||||
if (!mHasLinksToUpdateRunnable) {
|
||||
if (!mHasLinksToUpdateRunnable && !mFlushingPendingLinkUpdates) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NewRunnableMethod("nsIDocument::FlushPendingLinkUpdatesFromRunnable",
|
||||
this,
|
||||
|
@ -9637,7 +9634,6 @@ nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
|
|||
}
|
||||
|
||||
mLinksToUpdate.InfallibleAppend(aLink);
|
||||
mHasLinksToUpdate = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9651,24 +9647,26 @@ nsIDocument::FlushPendingLinkUpdatesFromRunnable()
|
|||
void
|
||||
nsIDocument::FlushPendingLinkUpdates()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
|
||||
if (!mHasLinksToUpdate)
|
||||
if (mFlushingPendingLinkUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden);
|
||||
mIsLinkUpdateRegistrationsForbidden = true;
|
||||
for (auto iter = mLinksToUpdate.Iter(); !iter.Done(); iter.Next()) {
|
||||
Link* link = iter.Get();
|
||||
Element* element = link->GetElement();
|
||||
if (element->OwnerDoc() == this) {
|
||||
link->ClearHasPendingLinkUpdate();
|
||||
if (element->IsInComposedDoc()) {
|
||||
element->UpdateLinkState(link->LinkState());
|
||||
auto restore = MakeScopeExit([&] { mFlushingPendingLinkUpdates = false; });
|
||||
mFlushingPendingLinkUpdates = true;
|
||||
|
||||
while (!mLinksToUpdate.IsEmpty()) {
|
||||
LinksToUpdateList links(Move(mLinksToUpdate));
|
||||
for (auto iter = links.Iter(); !iter.Done(); iter.Next()) {
|
||||
Link* link = iter.Get();
|
||||
Element* element = link->GetElement();
|
||||
if (element->OwnerDoc() == this) {
|
||||
link->ClearHasPendingLinkUpdate();
|
||||
if (element->IsInComposedDoc()) {
|
||||
element->UpdateLinkState(link->LinkState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mLinksToUpdate.Clear();
|
||||
mHasLinksToUpdate = false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument>
|
||||
|
|
|
@ -3344,10 +3344,13 @@ protected:
|
|||
// The array of all links that need their status resolved. Links must add themselves
|
||||
// to this set by calling RegisterPendingLinkUpdate when added to a document.
|
||||
static const size_t kSegmentSize = 128;
|
||||
mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>,
|
||||
kSegmentSize,
|
||||
InfallibleAllocPolicy>
|
||||
mLinksToUpdate;
|
||||
|
||||
typedef mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>,
|
||||
kSegmentSize,
|
||||
InfallibleAllocPolicy>
|
||||
LinksToUpdateList;
|
||||
|
||||
LinksToUpdateList mLinksToUpdate;
|
||||
|
||||
// SMIL Animation Controller, lazily-initialized in GetAnimationController
|
||||
RefPtr<nsSMILAnimationController> mAnimationController;
|
||||
|
@ -3441,12 +3444,12 @@ protected:
|
|||
// file, etc.
|
||||
bool mIsSyntheticDocument : 1;
|
||||
|
||||
// True if this document has links whose state needs updating
|
||||
bool mHasLinksToUpdate : 1;
|
||||
|
||||
// True is there is a pending runnable which will call FlushPendingLinkUpdates().
|
||||
bool mHasLinksToUpdateRunnable : 1;
|
||||
|
||||
// True if we're flushing pending link updates.
|
||||
bool mFlushingPendingLinkUpdates : 1;
|
||||
|
||||
// True if a DOMMutationObserver is perhaps attached to a node in the document.
|
||||
bool mMayHaveDOMMutationObservers : 1;
|
||||
|
||||
|
@ -3595,12 +3598,6 @@ protected:
|
|||
|
||||
Tri mAllowXULXBL;
|
||||
|
||||
/**
|
||||
* This is true while FlushPendingLinkUpdates executes. Calls to
|
||||
* [Un]RegisterPendingLinkUpdate will assert when this is true.
|
||||
*/
|
||||
bool mIsLinkUpdateRegistrationsForbidden;
|
||||
|
||||
// The document's script global object, the object from which the
|
||||
// document can get its script context and scope. This is the
|
||||
// *inner* window object.
|
||||
|
|
|
@ -23,10 +23,6 @@ class nsICycleCollectorListener;
|
|||
class nsScriptNameSpaceManager;
|
||||
class nsIDocShell;
|
||||
|
||||
namespace JS {
|
||||
class AutoValueVector;
|
||||
} // namespace JS
|
||||
|
||||
namespace mozilla {
|
||||
template <class> class Maybe;
|
||||
struct CycleCollectorResults;
|
||||
|
|
|
@ -208,7 +208,9 @@ ClientSource::WorkerExecutionReady(WorkerPrivate* aWorkerPrivate)
|
|||
// execution ready. We can't reliably determine what our storage policy
|
||||
// is before execution ready, unfortunately.
|
||||
if (mController.isSome()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed());
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed() ||
|
||||
StringBeginsWith(aWorkerPrivate->ScriptURL(),
|
||||
NS_LITERAL_STRING("blob:")));
|
||||
}
|
||||
|
||||
// Its safe to store the WorkerPrivate* here because the ClientSource
|
||||
|
@ -236,34 +238,36 @@ ClientSource::WindowExecutionReady(nsPIDOMWindowInner* aInnerWindow)
|
|||
}
|
||||
|
||||
nsIDocument* doc = aInnerWindow->GetExtantDoc();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsIURI* uri = doc->GetOriginalURI();
|
||||
NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Don't use nsAutoCString here since IPC requires a full nsCString anyway.
|
||||
nsCString spec;
|
||||
nsresult rv = uri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// A client without access to storage should never be controlled by
|
||||
// a service worker. Check this here in case we were controlled before
|
||||
// execution ready. We can't reliably determine what our storage policy
|
||||
// is before execution ready, unfortunately.
|
||||
//
|
||||
// Note, explicitly avoid checking storage policy for windows that inherit
|
||||
// service workers from their parent. If a user opens a controlled window
|
||||
// and then blocks storage, that window will continue to be controlled by
|
||||
// the SW until the window is closed. Any about:blank or blob URL should
|
||||
// continue to inherit the SW as well. We need to avoid triggering the
|
||||
// assertion in this corner case.
|
||||
if (mController.isSome()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(aInnerWindow) ==
|
||||
MOZ_DIAGNOSTIC_ASSERT(spec.LowerCaseEqualsLiteral("about:blank") ||
|
||||
StringBeginsWith(spec, NS_LITERAL_CSTRING("blob:")) ||
|
||||
nsContentUtils::StorageAllowedForWindow(aInnerWindow) ==
|
||||
nsContentUtils::StorageAccess::eAllow);
|
||||
}
|
||||
|
||||
// Don't use nsAutoCString here since IPC requires a full nsCString anyway.
|
||||
nsCString spec;
|
||||
|
||||
nsIURI* uri = doc->GetOriginalURI();
|
||||
if (uri) {
|
||||
nsresult rv = uri->GetSpec(spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
nsPIDOMWindowOuter* outer = aInnerWindow->GetOuterWindow();
|
||||
if (NS_WARN_IF(!outer)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED);
|
||||
|
||||
FrameType frameType = FrameType::Top_level;
|
||||
if (!outer->IsTopLevelWindow()) {
|
||||
|
@ -386,11 +390,19 @@ ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
|
|||
// A client without access to storage should never be controlled a
|
||||
// a service worker. If we are already execution ready with a real
|
||||
// window or worker, then verify assert the storage policy is correct.
|
||||
//
|
||||
// Note, explicitly avoid checking storage policy for clients that inherit
|
||||
// service workers from their parent. This basically means blob: URLs
|
||||
// and about:blank windows.
|
||||
if (GetInnerWindow()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
|
||||
MOZ_DIAGNOSTIC_ASSERT(Info().URL().LowerCaseEqualsLiteral("about:blank") ||
|
||||
StringBeginsWith(Info().URL(), NS_LITERAL_CSTRING("blob:")) ||
|
||||
nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
|
||||
nsContentUtils::StorageAccess::eAllow);
|
||||
} else if (GetWorkerPrivate()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed());
|
||||
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed() ||
|
||||
StringBeginsWith(GetWorkerPrivate()->ScriptURL(),
|
||||
NS_LITERAL_STRING("blob:")));
|
||||
}
|
||||
|
||||
if (mController.isSome() && mController.ref() == aServiceWorker) {
|
||||
|
|
|
@ -2074,7 +2074,9 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
|
|||
aOptions->setMutedErrors(!subsumes);
|
||||
}
|
||||
|
||||
if (!aRequest->IsModuleRequest()) {
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
aOptions->hideScriptFromDebugger = true;
|
||||
} else {
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> elementVal(cx);
|
||||
MOZ_ASSERT(aRequest->mElement);
|
||||
|
@ -2245,6 +2247,10 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
|||
rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->mElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
moduleScript->SetSourceElementAssociated();
|
||||
|
||||
// The script is now ready to be exposed to the debugger.
|
||||
JS::Rooted<JSScript*> script(cx, JS::GetModuleScript(module));
|
||||
JS::ExposeScriptToDebugger(cx, script);
|
||||
}
|
||||
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||
|
|
|
@ -43,13 +43,17 @@ NS_IMPL_ISUPPORTS(CSPService, nsIContentPolicy, nsIChannelEventSink)
|
|||
// Helper function to identify protocols and content types not subject to CSP.
|
||||
bool
|
||||
subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
|
||||
|
||||
nsContentPolicyType contentType =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(aContentType);
|
||||
|
||||
// These content types are not subject to CSP content policy checks:
|
||||
// TYPE_CSP_REPORT -- csp can't block csp reports
|
||||
// TYPE_REFRESH -- never passed to ShouldLoad (see nsIContentPolicy.idl)
|
||||
// TYPE_DOCUMENT -- used for frame-ancestors
|
||||
if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
|
||||
aContentType == nsIContentPolicy::TYPE_REFRESH ||
|
||||
aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
if (contentType == nsIContentPolicy::TYPE_CSP_REPORT ||
|
||||
contentType == nsIContentPolicy::TYPE_REFRESH ||
|
||||
contentType == nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -90,12 +94,16 @@ subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
|
|||
// hence we use protocol flags to accomplish that, but we also
|
||||
// want resource:, chrome: and moz-icon to be subject to CSP
|
||||
// (which also use URI_IS_LOCAL_RESOURCE).
|
||||
// Exception to the rule are images and styles using a scheme
|
||||
// of resource: or chrome:
|
||||
bool isImgOrStyle = contentType == nsIContentPolicy::TYPE_IMAGE ||
|
||||
contentType == nsIContentPolicy::TYPE_STYLESHEET;
|
||||
rv = aURI->SchemeIs("resource", &match);
|
||||
if (NS_SUCCEEDED(rv) && match) {
|
||||
if (NS_SUCCEEDED(rv) && match && !isImgOrStyle) {
|
||||
return true;
|
||||
}
|
||||
rv = aURI->SchemeIs("chrome", &match);
|
||||
if (NS_SUCCEEDED(rv) && match) {
|
||||
if (NS_SUCCEEDED(rv) && match && !isImgOrStyle) {
|
||||
return true;
|
||||
}
|
||||
rv = aURI->SchemeIs("moz-icon", &match);
|
||||
|
|
|
@ -95,6 +95,148 @@ add_task(async function test_session_permission() {
|
|||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
});
|
||||
|
||||
// Test to verify an about:blank iframe successfully inherits the
|
||||
// parent's controller when storage is blocked between opening the
|
||||
// parent page and creating the iframe.
|
||||
add_task(async function test_block_storage_before_blank_iframe() {
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller, "page should be controlled with storage allowed");
|
||||
|
||||
let controller2 = await ContentTask.spawn(browser, null, async function() {
|
||||
let f = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(f);
|
||||
await new Promise(resolve => f.onload = resolve);
|
||||
return !!f.contentWindow.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller2, "page should be controlled with storage allowed");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
|
||||
]});
|
||||
|
||||
let controller3 = await ContentTask.spawn(browser, null, async function() {
|
||||
let f = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(f);
|
||||
await new Promise(resolve => f.onload = resolve);
|
||||
return !!f.contentWindow.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller3, "page should be controlled with storage allowed");
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
// Test to verify a blob URL iframe successfully inherits the
|
||||
// parent's controller when storage is blocked between opening the
|
||||
// parent page and creating the iframe.
|
||||
add_task(async function test_block_storage_before_blob_iframe() {
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller, "page should be controlled with storage allowed");
|
||||
|
||||
let controller2 = await ContentTask.spawn(browser, null, async function() {
|
||||
let b = new content.Blob(["<!DOCTYPE html><html></html>"], { type: "text/html" });
|
||||
let f = content.document.createElement("iframe");
|
||||
// No need to call revokeObjectURL() since the window will be closed shortly.
|
||||
f.src = content.URL.createObjectURL(b);
|
||||
content.document.body.appendChild(f);
|
||||
await new Promise(resolve => f.onload = resolve);
|
||||
return !!f.contentWindow.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller2, "page should be controlled with storage allowed");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
|
||||
]});
|
||||
|
||||
let controller3 = await ContentTask.spawn(browser, null, async function() {
|
||||
let b = new content.Blob(["<!DOCTYPE html><html></html>"], { type: "text/html" });
|
||||
let f = content.document.createElement("iframe");
|
||||
// No need to call revokeObjectURL() since the window will be closed shortly.
|
||||
f.src = content.URL.createObjectURL(b);
|
||||
content.document.body.appendChild(f);
|
||||
await new Promise(resolve => f.onload = resolve);
|
||||
return !!f.contentWindow.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller3, "page should be controlled with storage allowed");
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
// Test to verify a blob worker script does not hit our service
|
||||
// worker storage assertions when storage is blocked between opening
|
||||
// the parent page and creating the worker. Note, we cannot
|
||||
// explicitly check if the worker is controlled since we don't expose
|
||||
// WorkerNavigator.serviceWorkers.controller yet.
|
||||
add_task(async function test_block_storage_before_blob_worker() {
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller, "page should be controlled with storage allowed");
|
||||
|
||||
let scriptURL = await ContentTask.spawn(browser, null, async function() {
|
||||
let b = new content.Blob(["self.postMessage(self.location.href);self.close()"],
|
||||
{ type: "application/javascript" });
|
||||
// No need to call revokeObjectURL() since the window will be closed shortly.
|
||||
let u = content.URL.createObjectURL(b);
|
||||
let w = new content.Worker(u);
|
||||
return await new Promise(resolve => {
|
||||
w.onmessage = e => resolve(e.data);
|
||||
});
|
||||
});
|
||||
|
||||
ok(scriptURL.startsWith("blob:"), "blob URL worker should run");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT],
|
||||
]});
|
||||
|
||||
let scriptURL2 = await ContentTask.spawn(browser, null, async function() {
|
||||
let b = new content.Blob(["self.postMessage(self.location.href);self.close()"],
|
||||
{ type: "application/javascript" });
|
||||
// No need to call revokeObjectURL() since the window will be closed shortly.
|
||||
let u = content.URL.createObjectURL(b);
|
||||
let w = new content.Worker(u);
|
||||
return await new Promise(resolve => {
|
||||
w.onmessage = e => resolve(e.data);
|
||||
});
|
||||
});
|
||||
|
||||
ok(scriptURL2.startsWith("blob:"), "blob URL worker should run");
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function cleanup() {
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
|
||||
|
|
|
@ -20,6 +20,22 @@
|
|||
// ];
|
||||
//
|
||||
// See createInterfaceMap() below for a complete list of properties.
|
||||
//
|
||||
// The values of the properties need to be either literal true/false
|
||||
// (e.g. indicating whether something is enabled on a particular
|
||||
// channel/OS) or one of the is* constants below (in cases when
|
||||
// exposure is affected by channel or OS in a nontrivial way).
|
||||
|
||||
const version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
|
||||
const isNightly = version.endsWith("a1");
|
||||
const isEarlyBetaOrEarlier = SpecialPowers.EARLY_BETA_OR_EARLIER;
|
||||
const isRelease = !version.includes("a");
|
||||
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||
const isMac = /Mac OS/.test(navigator.oscpu);
|
||||
const isWindows = /Windows/.test(navigator.oscpu);
|
||||
const isAndroid = navigator.userAgent.includes("Android");
|
||||
const isLinux = /Linux/.test(navigator.oscpu) && !isAndroid;
|
||||
const isInsecureContext = !window.isSecureContext;
|
||||
|
||||
// IMPORTANT: Do not change this list without review from
|
||||
// a JavaScript Engine peer!
|
||||
|
@ -29,8 +45,8 @@ var ecmaGlobals =
|
|||
{name: "ArrayBuffer", insecureContext: true},
|
||||
{name: "Atomics", insecureContext: true, disabled: true},
|
||||
{name: "Boolean", insecureContext: true},
|
||||
{name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()},
|
||||
{name: "CountQueuingStrategy", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()},
|
||||
{name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: true},
|
||||
{name: "CountQueuingStrategy", insecureContext: true, disabled: true},
|
||||
{name: "DataView", insecureContext: true},
|
||||
{name: "Date", insecureContext: true},
|
||||
{name: "Error", insecureContext: true},
|
||||
|
@ -56,7 +72,7 @@ var ecmaGlobals =
|
|||
{name: "Promise", insecureContext: true},
|
||||
{name: "Proxy", insecureContext: true},
|
||||
{name: "RangeError", insecureContext: true},
|
||||
{name: "ReadableStream", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().streamsAreEnabled()},
|
||||
{name: "ReadableStream", insecureContext: true, disabled: true},
|
||||
{name: "ReferenceError", insecureContext: true},
|
||||
{name: "Reflect", insecureContext: true},
|
||||
{name: "RegExp", insecureContext: true},
|
||||
|
@ -75,7 +91,7 @@ var ecmaGlobals =
|
|||
{name: "URIError", insecureContext: true},
|
||||
{name: "WeakMap", insecureContext: true},
|
||||
{name: "WeakSet", insecureContext: true},
|
||||
{name: "WebAssembly", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()}
|
||||
{name: "WebAssembly", insecureContext: true, disabled: !SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupportedByHardware()},
|
||||
];
|
||||
// IMPORTANT: Do not change the list above without review from
|
||||
// a JavaScript Engine peer!
|
||||
|
@ -723,7 +739,7 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "OfflineAudioContext", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "OfflineResourceList", insecureContext: SpecialPowers.getBoolPref("browser.cache.offline.insecure.enable")},
|
||||
{name: "OfflineResourceList", insecureContext: !isEarlyBetaOrEarlier},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "Option", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -1267,16 +1283,6 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change the list above without review from a DOM peer!
|
||||
|
||||
function createInterfaceMap(isXBLScope) {
|
||||
var version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
|
||||
var isNightly = version.endsWith("a1");
|
||||
var isRelease = !version.includes("a");
|
||||
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||
var isMac = /Mac OS/.test(navigator.oscpu);
|
||||
var isWindows = /Windows/.test(navigator.oscpu);
|
||||
var isAndroid = navigator.userAgent.includes("Android");
|
||||
var isLinux = /Linux/.test(navigator.oscpu) && !isAndroid;
|
||||
var isInsecureContext = !window.isSecureContext;
|
||||
|
||||
var interfaceMap = {};
|
||||
|
||||
function addInterfaces(interfaces)
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
// ];
|
||||
//
|
||||
// See createInterfaceMap() below for a complete list of properties.
|
||||
//
|
||||
// The values of the properties need to be literal true/false
|
||||
// (e.g. indicating whether something is enabled on a particular
|
||||
// channel/OS). If we ever end up in a situation where a propert
|
||||
// value needs to depend on channel or OS, we will need to make sure
|
||||
// we have that information before setting up the property lists.
|
||||
|
||||
// IMPORTANT: Do not change this list without review from
|
||||
// a JavaScript Engine peer!
|
||||
|
@ -27,8 +33,8 @@ var ecmaGlobals =
|
|||
{name: "ArrayBuffer", insecureContext: true},
|
||||
{name: "Atomics", insecureContext: true, disabled: true},
|
||||
{name: "Boolean", insecureContext: true},
|
||||
{name: "ByteLengthQueuingStrategy", insecureContext: true, optional: true},
|
||||
{name: "CountQueuingStrategy", insecureContext: true, optional: true},
|
||||
{name: "ByteLengthQueuingStrategy", insecureContext: true, disabled: true},
|
||||
{name: "CountQueuingStrategy", insecureContext: true, disabled: true},
|
||||
{name: "DataView", insecureContext: true},
|
||||
{name: "Date", insecureContext: true},
|
||||
{name: "Error", insecureContext: true},
|
||||
|
@ -51,7 +57,7 @@ var ecmaGlobals =
|
|||
{name: "Promise", insecureContext: true},
|
||||
{name: "Proxy", insecureContext: true},
|
||||
{name: "RangeError", insecureContext: true},
|
||||
{name: "ReadableStream", insecureContext: true, optional: true},
|
||||
{name: "ReadableStream", insecureContext: true, disabled: true},
|
||||
{name: "ReferenceError", insecureContext: true},
|
||||
{name: "Reflect", insecureContext: true},
|
||||
{name: "RegExp", insecureContext: true},
|
||||
|
@ -70,7 +76,11 @@ var ecmaGlobals =
|
|||
{name: "URIError", insecureContext: true},
|
||||
{name: "WeakMap", insecureContext: true},
|
||||
{name: "WeakSet", insecureContext: true},
|
||||
{name: "WebAssembly", insecureContext: true, optional: true}
|
||||
// WebAssembly is not supported on some hardware configurations,
|
||||
// but we have no way to check that from here. Just give up for
|
||||
// now and don't check for it at all. Do NOT add any other uses
|
||||
// of "optional"!
|
||||
{name: "WebAssembly", insecureContext: true, optional: true},
|
||||
];
|
||||
// IMPORTANT: Do not change the list above without review from
|
||||
// a JavaScript Engine peer!
|
||||
|
|
|
@ -94,8 +94,8 @@ txExprLexer::nextIsOperatorToken(Token* aToken)
|
|||
nsresult
|
||||
txExprLexer::parse(const nsAString& aPattern)
|
||||
{
|
||||
iterator start, end;
|
||||
start = aPattern.BeginReading(mPosition);
|
||||
iterator end;
|
||||
aPattern.BeginReading(mPosition);
|
||||
aPattern.EndReading(end);
|
||||
|
||||
//-- initialize previous token, this will automatically get
|
||||
|
@ -125,7 +125,7 @@ txExprLexer::parse(const nsAString& aPattern)
|
|||
// NCName, can get QName or OperatorName;
|
||||
// FunctionName, NodeName, and AxisSpecifier may want whitespace,
|
||||
// and are dealt with below
|
||||
start = mPosition;
|
||||
iterator start = mPosition;
|
||||
while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
|
||||
/* just go */
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ txExprLexer::parse(const nsAString& aPattern)
|
|||
newToken = new Token(start, mPosition, defType);
|
||||
}
|
||||
else if (isXPathDigit(*mPosition)) {
|
||||
start = mPosition;
|
||||
iterator start = mPosition;
|
||||
while (++mPosition < end && isXPathDigit(*mPosition)) {
|
||||
/* just go */
|
||||
}
|
||||
|
@ -193,7 +193,8 @@ txExprLexer::parse(const nsAString& aPattern)
|
|||
break;
|
||||
case S_QUOTE :
|
||||
case D_QUOTE :
|
||||
start = mPosition;
|
||||
{
|
||||
iterator start = mPosition;
|
||||
while (++mPosition < end && *mPosition != *start) {
|
||||
// eat literal
|
||||
}
|
||||
|
@ -203,14 +204,15 @@ txExprLexer::parse(const nsAString& aPattern)
|
|||
}
|
||||
newToken = new Token(start + 1, mPosition, Token::LITERAL);
|
||||
++mPosition;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PERIOD:
|
||||
// period can be .., .(DIGITS)+ or ., check next
|
||||
if (++mPosition == end) {
|
||||
newToken = new Token(mPosition - 1, Token::SELF_NODE);
|
||||
}
|
||||
else if (isXPathDigit(*mPosition)) {
|
||||
start = mPosition - 1;
|
||||
iterator start = mPosition - 1;
|
||||
while (++mPosition < end && isXPathDigit(*mPosition)) {
|
||||
/* just go */
|
||||
}
|
||||
|
|
|
@ -174,7 +174,13 @@ gfxFT2FontBase::GetCharWidth(char aChar, gfxFloat* aWidth)
|
|||
{
|
||||
FT_UInt gid = GetGlyph(aChar);
|
||||
if (gid) {
|
||||
*aWidth = FLOAT_FROM_16_16(GetFTGlyphAdvance(gid));
|
||||
int32_t width;
|
||||
if (!GetFTGlyphAdvance(gid, &width)) {
|
||||
cairo_text_extents_t extents;
|
||||
GetGlyphExtents(gid, &extents);
|
||||
width = NS_lround(0x10000 * extents.x_advance);
|
||||
}
|
||||
*aWidth = FLOAT_FROM_16_16(width);
|
||||
}
|
||||
return gid;
|
||||
}
|
||||
|
@ -526,35 +532,42 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
|
|||
return GetGlyph(unicode);
|
||||
}
|
||||
|
||||
FT_Fixed
|
||||
gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID)
|
||||
bool
|
||||
gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID, int32_t* aAdvance)
|
||||
{
|
||||
gfxFT2LockedFace face(this);
|
||||
MOZ_ASSERT(face.get());
|
||||
if (!face.get()) {
|
||||
// Failed to get the FT_Face? Give up already.
|
||||
return 0;
|
||||
NS_WARNING("failed to get FT_Face!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Due to bugs like 1435234 and 1440938, we currently prefer to fall back
|
||||
// to reading the advance from cairo extents, unless we're dealing with
|
||||
// a variation font (for which cairo metrics may be wrong, due to FreeType
|
||||
// bug 52683).
|
||||
if (!(face.get()->face_flags & FT_FACE_FLAG_SCALABLE) ||
|
||||
!(face.get()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hinting = gfxPlatform::GetPlatform()->FontHintingEnabled();
|
||||
int32_t flags =
|
||||
hinting ? FT_LOAD_ADVANCE_ONLY
|
||||
: FT_LOAD_ADVANCE_ONLY | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
|
||||
FT_Error ftError = FT_Load_Glyph(face.get(), aGID, flags);
|
||||
MOZ_ASSERT(!ftError);
|
||||
if (ftError != FT_Err_Ok) {
|
||||
// FT_Face was somehow broken/invalid? Don't try to access glyph slot.
|
||||
return 0;
|
||||
// This probably shouldn't happen, but does: see bug 1440938.
|
||||
NS_WARNING("failed to load glyph!");
|
||||
return false;
|
||||
}
|
||||
FT_Fixed advance = 0;
|
||||
|
||||
// Due to freetype bug 52683 we MUST use the linearHoriAdvance field when
|
||||
// dealing with a variation font; also use it for scalable fonts when not
|
||||
// applying hinting. Otherwise, prefer hinted width from glyph->advance.x.
|
||||
if ((face.get()->face_flags & FT_FACE_FLAG_SCALABLE) &&
|
||||
(!hinting || (face.get()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS))) {
|
||||
advance = face.get()->glyph->linearHoriAdvance;
|
||||
} else {
|
||||
advance = face.get()->glyph->advance.x << 10; // convert 26.6 to 16.16
|
||||
}
|
||||
// dealing with a variation font. (And other fonts would have returned
|
||||
// earlier, so only variation fonts currently reach here.)
|
||||
FT_Fixed advance = face.get()->glyph->linearHoriAdvance;
|
||||
|
||||
// If freetype emboldening is being used, and it's not a zero-width glyph,
|
||||
// adjust the advance to account for the increased width.
|
||||
|
@ -569,9 +582,9 @@ gfxFT2FontBase::GetFTGlyphAdvance(uint16_t aGID)
|
|||
|
||||
// Round the 16.16 fixed-point value to whole pixels for better consistency
|
||||
// with how cairo renders the glyphs.
|
||||
advance = (advance + 0x8000) & 0xffff0000u;
|
||||
*aAdvance = (advance + 0x8000) & 0xffff0000u;
|
||||
|
||||
return advance;
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -587,7 +600,11 @@ gfxFT2FontBase::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
|
|||
return width;
|
||||
}
|
||||
|
||||
width = GetFTGlyphAdvance(aGID);
|
||||
if (!GetFTGlyphAdvance(aGID, &width)) {
|
||||
cairo_text_extents_t extents;
|
||||
GetGlyphExtents(aGID, &extents);
|
||||
width = NS_lround(0x10000 * extents.x_advance);
|
||||
}
|
||||
mGlyphWidths->Put(aGID, width);
|
||||
|
||||
return width;
|
||||
|
|
|
@ -45,7 +45,12 @@ public:
|
|||
private:
|
||||
uint32_t GetCharExtents(char aChar, cairo_text_extents_t* aExtents);
|
||||
uint32_t GetCharWidth(char aChar, gfxFloat* aWidth);
|
||||
FT_Fixed GetFTGlyphAdvance(uint16_t aGID);
|
||||
|
||||
// Get advance of a single glyph from FreeType, and return true;
|
||||
// or return false if we should fall back to getting the glyph
|
||||
// extents from cairo instead.
|
||||
bool GetFTGlyphAdvance(uint16_t aGID, int32_t* aWidth);
|
||||
|
||||
void InitMetrics();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -701,7 +701,30 @@ MessageChannel::Clear()
|
|||
if (!Unsound_IsClosed()) {
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"),
|
||||
nsDependentCString(mName));
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed");
|
||||
switch (mChannelState) {
|
||||
case ChannelOpening:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
||||
"(mChannelState == ChannelOpening).");
|
||||
break;
|
||||
case ChannelConnected:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
||||
"(mChannelState == ChannelConnected).");
|
||||
break;
|
||||
case ChannelTimeout:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
||||
"(mChannelState == ChannelTimeout).");
|
||||
break;
|
||||
case ChannelClosing:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
||||
"(mChannelState == ChannelClosing).");
|
||||
break;
|
||||
case ChannelError:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed " \
|
||||
"(mChannelState == ChannelError).");
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("MessageChannel destroyed without being closed.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -40,8 +40,6 @@ extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
|
|||
|
||||
namespace JS {
|
||||
|
||||
class AutoIdVector;
|
||||
|
||||
/**
|
||||
* The answer to a successful query as to whether an object is an Array per
|
||||
* ES6's internal |IsArray| operation (as exposed by |Array.isArray|).
|
||||
|
|
|
@ -99,14 +99,14 @@ class GCVector
|
|||
return vector.infallibleAppend(aBegin, aLength);
|
||||
}
|
||||
|
||||
template<typename U, size_t O, class BP>
|
||||
MOZ_MUST_USE bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vector.appendAll(aU); }
|
||||
template<typename U, size_t O, class BP>
|
||||
MOZ_MUST_USE bool appendAll(const GCVector<U, O, BP>& aU) {
|
||||
return vector.append(aU.begin(), aU.length());
|
||||
template<typename U>
|
||||
MOZ_MUST_USE bool appendAll(const U& aU) {
|
||||
return vector.append(aU.begin(), aU.end());
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool appendN(const T& val, size_t count) { return vector.appendN(val, count); }
|
||||
MOZ_MUST_USE bool appendN(const T& val, size_t count) {
|
||||
return vector.appendN(val, count);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
|
||||
|
@ -219,10 +219,8 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrappe
|
|||
MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) {
|
||||
return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
|
||||
}
|
||||
template<typename U, size_t O, class BP>
|
||||
MOZ_MUST_USE bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vec().appendAll(aU); }
|
||||
template<typename U, size_t O, class BP>
|
||||
MOZ_MUST_USE bool appendAll(const JS::GCVector<U, O, BP>& aU) { return vec().appendAll(aU); }
|
||||
template<typename U>
|
||||
MOZ_MUST_USE bool appendAll(const U& aU) { return vec().appendAll(aU); }
|
||||
MOZ_MUST_USE bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); }
|
||||
template<typename U>
|
||||
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
|
||||
|
@ -253,4 +251,17 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrappe
|
|||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
// An automatically rooted vector for stack use.
|
||||
template <typename T>
|
||||
class AutoVector : public Rooted<GCVector<T, 8>> {
|
||||
using Vec = GCVector<T, 8>;
|
||||
using Base = Rooted<Vec>;
|
||||
public:
|
||||
explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {}
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_GCVector_h
|
||||
|
|
|
@ -895,19 +895,12 @@ class JS_PUBLIC_API(AutoGCRooter)
|
|||
#if defined(JS_BUILD_BINAST)
|
||||
BINPARSER = -4, /* js::frontend::BinSource */
|
||||
#endif // defined(JS_BUILD_BINAST)
|
||||
VALVECTOR = -10, /* js::AutoValueVector */
|
||||
IDVECTOR = -11, /* js::AutoIdVector */
|
||||
OBJVECTOR = -14, /* js::AutoObjectVector */
|
||||
IONMASM = -19, /* js::jit::MacroAssembler */
|
||||
WRAPVECTOR = -20, /* js::AutoWrapperVector */
|
||||
WRAPPER = -21, /* js::AutoWrapperRooter */
|
||||
CUSTOM = -26 /* js::CustomAutoRooter */
|
||||
};
|
||||
|
||||
static ptrdiff_t GetTag(const Value& value) { return VALVECTOR; }
|
||||
static ptrdiff_t GetTag(const jsid& id) { return IDVECTOR; }
|
||||
static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; }
|
||||
|
||||
private:
|
||||
AutoGCRooter ** const stackTop;
|
||||
|
||||
|
|
|
@ -475,6 +475,7 @@ const OPAQUE_TYPES: &'static [&'static str] = &[
|
|||
"mozilla::BufferList",
|
||||
"mozilla::UniquePtr.*",
|
||||
"JS::Rooted<JS::Auto.*Vector.*>",
|
||||
"JS::Auto.*Vector"
|
||||
];
|
||||
|
||||
/// Types for which we should NEVER generate bindings, even if it is used within
|
||||
|
|
|
@ -30,9 +30,9 @@ class TwoByteCharsZ;
|
|||
class UTF8Chars;
|
||||
class UTF8CharsZ;
|
||||
|
||||
class AutoValueVector;
|
||||
class AutoIdVector;
|
||||
class AutoObjectVector;
|
||||
using AutoValueVector = AutoVector<Value>;
|
||||
using AutoIdVector = AutoVector<jsid>;
|
||||
using AutoObjectVector = AutoVector<JSObject*>;
|
||||
|
||||
using ValueVector = JS::GCVector<JS::Value>;
|
||||
using IdVector = JS::GCVector<jsid>;
|
||||
|
|
|
@ -529,6 +529,14 @@ WasmIsSupported(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmIsSupportedByHardware(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
args.rval().setBoolean(wasm::HasCompilerSupport(cx));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -5375,6 +5383,10 @@ gc::ZealModeHelpText),
|
|||
"wasmIsSupported()",
|
||||
" Returns a boolean indicating whether WebAssembly is supported on the current device."),
|
||||
|
||||
JS_FN_HELP("wasmIsSupportedByHardware", WasmIsSupportedByHardware, 0, 0,
|
||||
"wasmIsSupportedByHardware()",
|
||||
" Returns a boolean indicating whether WebAssembly is supported on the current hardware (regardless of whether we've enabled support)."),
|
||||
|
||||
JS_FN_HELP("wasmDebuggingIsSupported", WasmDebuggingIsSupported, 0, 0,
|
||||
"wasmDebuggingIsSupported()",
|
||||
" Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n"
|
||||
|
|
|
@ -183,7 +183,11 @@ js::AllocateString(JSContext* cx, InitialHeap heap)
|
|||
if (!rt->gc.checkAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
if (cx->nursery().isEnabled() && heap != TenuredHeap && cx->nursery().canAllocateStrings()) {
|
||||
if (cx->nursery().isEnabled() &&
|
||||
heap != TenuredHeap &&
|
||||
cx->nursery().canAllocateStrings() &&
|
||||
cx->zone()->allocNurseryStrings)
|
||||
{
|
||||
auto str = static_cast<StringAllocT*>(rt->gc.tryNewNurseryString<allowGC>(cx, size, kind));
|
||||
if (str)
|
||||
return str;
|
||||
|
|
|
@ -2777,18 +2777,21 @@ js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const
|
|||
return;
|
||||
|
||||
if (kind() == ElementKind) {
|
||||
int32_t initLen = obj->getDenseInitializedLength();
|
||||
int32_t numShifted = obj->getElementsHeader()->numShiftedElements();
|
||||
int32_t clampedStart = Min(Max(0, start_ - numShifted), initLen);
|
||||
int32_t clampedEnd = Min(Max(0, start_ + count_ - numShifted), initLen);
|
||||
MOZ_ASSERT(clampedStart >= 0);
|
||||
uint32_t initLen = obj->getDenseInitializedLength();
|
||||
uint32_t numShifted = obj->getElementsHeader()->numShiftedElements();
|
||||
uint32_t clampedStart = start_;
|
||||
clampedStart = numShifted < clampedStart ? clampedStart - numShifted : 0;
|
||||
clampedStart = Min(clampedStart, initLen);
|
||||
uint32_t clampedEnd = start_ + count_;
|
||||
clampedEnd = numShifted < clampedEnd ? clampedEnd - numShifted : 0;
|
||||
clampedEnd = Min(clampedEnd, initLen);
|
||||
MOZ_ASSERT(clampedStart <= clampedEnd);
|
||||
mover.traceSlots(static_cast<HeapSlot*>(obj->getDenseElements() + clampedStart)
|
||||
->unsafeUnbarrieredForTracing(), clampedEnd - clampedStart);
|
||||
} else {
|
||||
int32_t start = Min(uint32_t(start_), obj->slotSpan());
|
||||
int32_t end = Min(uint32_t(start_) + count_, obj->slotSpan());
|
||||
MOZ_ASSERT(end >= start);
|
||||
uint32_t start = Min(start_, obj->slotSpan());
|
||||
uint32_t end = Min(start_ + count_, obj->slotSpan());
|
||||
MOZ_ASSERT(start <= end);
|
||||
mover.traceObjectSlots(obj, start, end - start);
|
||||
}
|
||||
}
|
||||
|
@ -3200,6 +3203,7 @@ js::TenuringTracer::moveToTenured(JSString* src)
|
|||
|
||||
AllocKind dstKind = src->getAllocKind();
|
||||
Zone* zone = src->zone();
|
||||
zone->tenuredStrings++;
|
||||
|
||||
TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind));
|
||||
if (!t) {
|
||||
|
|
|
@ -132,9 +132,9 @@ js::Nursery::Nursery(JSRuntime* rt)
|
|||
, lastCanary_(nullptr)
|
||||
#endif
|
||||
{
|
||||
const char* env = getenv("MOZ_ENABLE_NURSERY_STRINGS");
|
||||
const char* env = getenv("MOZ_NURSERY_STRINGS");
|
||||
if (env && *env)
|
||||
canAllocateStrings_ = true;
|
||||
canAllocateStrings_ = (*env == '1');
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -738,21 +738,40 @@ js::Nursery::collect(JS::gcreason::Reason reason)
|
|||
bool validPromotionRate;
|
||||
const float promotionRate = calcPromotionRate(&validPromotionRate);
|
||||
uint32_t pretenureCount = 0;
|
||||
if (validPromotionRate) {
|
||||
if (promotionRate > 0.8 || IsFullStoreBufferReason(reason)) {
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (auto& entry : tenureCounts.entries) {
|
||||
if (entry.count >= 3000) {
|
||||
ObjectGroup* group = entry.group;
|
||||
if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) {
|
||||
AutoCompartment ac(cx, group);
|
||||
group->setShouldPreTenure(cx);
|
||||
pretenureCount++;
|
||||
}
|
||||
bool shouldPretenure = (validPromotionRate && promotionRate > 0.6) ||
|
||||
IsFullStoreBufferReason(reason);
|
||||
|
||||
if (shouldPretenure) {
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (auto& entry : tenureCounts.entries) {
|
||||
if (entry.count >= 3000) {
|
||||
ObjectGroup* group = entry.group;
|
||||
if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) {
|
||||
AutoCompartment ac(cx, group);
|
||||
group->setShouldPreTenure(cx);
|
||||
pretenureCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
|
||||
JSRuntime::AutoProhibitActiveContextChange apacc(rt);
|
||||
CancelOffThreadIonCompile(zone);
|
||||
bool preserving = zone->isPreservingCode();
|
||||
zone->setPreservingCode(false);
|
||||
zone->discardJitCode(rt->defaultFreeOp());
|
||||
zone->setPreservingCode(preserving);
|
||||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
||||
if (jit::JitCompartment* jitComp = c->jitCompartment()) {
|
||||
jitComp->discardStubs();
|
||||
jitComp->stringsCanBeInNursery = false;
|
||||
}
|
||||
}
|
||||
zone->allocNurseryStrings = false;
|
||||
}
|
||||
zone->tenuredStrings = 0;
|
||||
}
|
||||
endProfile(ProfileKey::Pretenure);
|
||||
|
||||
// We ignore gcMaxBytes when allocating for minor collection. However, if we
|
||||
|
@ -1086,7 +1105,7 @@ js::Nursery::setStartPosition()
|
|||
void
|
||||
js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
|
||||
{
|
||||
static const double GrowThreshold = 0.05;
|
||||
static const double GrowThreshold = 0.03;
|
||||
static const double ShrinkThreshold = 0.01;
|
||||
unsigned newMaxNurseryChunks;
|
||||
|
||||
|
|
|
@ -179,13 +179,13 @@ AutoGCRooter::trace(JSTracer* trc)
|
|||
}
|
||||
|
||||
case WRAPVECTOR: {
|
||||
AutoWrapperVector::VectorImpl& vector = static_cast<AutoWrapperVector*>(this)->vector;
|
||||
auto vector = static_cast<AutoWrapperVector*>(this);
|
||||
/*
|
||||
* We need to use TraceManuallyBarrieredEdge here because we trace
|
||||
* wrapper roots in every slice. This is because of some rule-breaking
|
||||
* in RemapAllWrappersForObject; see comment there.
|
||||
*/
|
||||
for (WrapperValue* p = vector.begin(); p < vector.end(); p++)
|
||||
for (WrapperValue* p = vector->begin(); p < vector->end(); p++)
|
||||
TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -276,17 +276,17 @@ class StoreBuffer
|
|||
const static int ElementKind = 1;
|
||||
|
||||
uintptr_t objectAndKind_; // NativeObject* | Kind
|
||||
int32_t start_;
|
||||
int32_t count_;
|
||||
uint32_t start_;
|
||||
uint32_t count_;
|
||||
|
||||
SlotsEdge() : objectAndKind_(0), start_(0), count_(0) {}
|
||||
SlotsEdge(NativeObject* object, int kind, int32_t start, int32_t count)
|
||||
SlotsEdge(NativeObject* object, int kind, uint32_t start, uint32_t count)
|
||||
: objectAndKind_(uintptr_t(object) | kind), start_(start), count_(count)
|
||||
{
|
||||
MOZ_ASSERT((uintptr_t(object) & 1) == 0);
|
||||
MOZ_ASSERT(kind <= 1);
|
||||
MOZ_ASSERT(start >= 0);
|
||||
MOZ_ASSERT(count > 0);
|
||||
MOZ_ASSERT(start + count > start);
|
||||
}
|
||||
|
||||
NativeObject* object() const { return reinterpret_cast<NativeObject*>(objectAndKind_ & ~1); }
|
||||
|
@ -313,10 +313,12 @@ class StoreBuffer
|
|||
// is particularly useful for coalescing a series of increasing or
|
||||
// decreasing single index writes 0, 1, 2, ..., N into a SlotsEdge
|
||||
// range of elements [0, N].
|
||||
auto end = start_ + count_ + 1;
|
||||
auto start = start_ - 1;
|
||||
uint32_t end = start_ + count_ + 1;
|
||||
uint32_t start = start_ > 0 ? start_ - 1 : 0;
|
||||
MOZ_ASSERT(start < end);
|
||||
|
||||
auto otherEnd = other.start_ + other.count_;
|
||||
uint32_t otherEnd = other.start_ + other.count_;
|
||||
MOZ_ASSERT(other.start_ <= otherEnd);
|
||||
return (start <= other.start_ && other.start_ <= end) ||
|
||||
(start <= otherEnd && otherEnd <= end);
|
||||
}
|
||||
|
@ -326,7 +328,7 @@ class StoreBuffer
|
|||
// overlap.
|
||||
void merge(const SlotsEdge& other) {
|
||||
MOZ_ASSERT(overlaps(other));
|
||||
auto end = Max(start_ + count_, other.start_ + other.count_);
|
||||
uint32_t end = Max(start_ + count_, other.start_ + other.count_);
|
||||
start_ = Min(start_, other.start_);
|
||||
count_ = end - start_;
|
||||
}
|
||||
|
@ -416,7 +418,7 @@ class StoreBuffer
|
|||
void unputValue(JS::Value* vp) { unput(bufferVal, ValueEdge(vp)); }
|
||||
void putCell(Cell** cellp) { put(bufferCell, CellPtrEdge(cellp)); }
|
||||
void unputCell(Cell** cellp) { unput(bufferCell, CellPtrEdge(cellp)); }
|
||||
void putSlot(NativeObject* obj, int kind, int32_t start, int32_t count) {
|
||||
void putSlot(NativeObject* obj, int kind, uint32_t start, uint32_t count) {
|
||||
SlotsEdge edge(obj, kind, start, count);
|
||||
if (bufferSlot.last_.overlaps(edge))
|
||||
bufferSlot.last_.merge(edge);
|
||||
|
|
|
@ -46,6 +46,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
|
|||
usage(&rt->gc.usage),
|
||||
threshold(),
|
||||
gcDelayBytes(0),
|
||||
tenuredStrings(group, 0),
|
||||
allocNurseryStrings(group, true),
|
||||
propertyTree_(group, this),
|
||||
baseShapes_(group, this),
|
||||
initialShapes_(group, this),
|
||||
|
|
|
@ -482,6 +482,9 @@ struct Zone : public JS::shadow::Zone,
|
|||
// the current GC.
|
||||
js::UnprotectedData<size_t> gcDelayBytes;
|
||||
|
||||
js::ZoneGroupData<uint32_t> tenuredStrings;
|
||||
js::ZoneGroupData<bool> allocNurseryStrings;
|
||||
|
||||
private:
|
||||
// Shared Shape property tree.
|
||||
js::ZoneGroupData<js::PropertyTree> propertyTree_;
|
||||
|
|
|
@ -283,9 +283,7 @@ BaselineCacheIRCompiler::emitGuardCompartment()
|
|||
return false;
|
||||
|
||||
Address addr(stubAddress(reader.stubOffset()));
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, addr, scratch, failure->label());
|
||||
masm.branchTestObjCompartment(Assembler::NotEqual, obj, addr, scratch, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -300,10 +298,7 @@ BaselineCacheIRCompiler::emitGuardAnyClass()
|
|||
return false;
|
||||
|
||||
Address testAddr(stubAddress(reader.stubOffset()));
|
||||
|
||||
masm.loadObjGroup(obj, scratch);
|
||||
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, testAddr, scratch, failure->label());
|
||||
masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, testAddr, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -528,9 +523,7 @@ BaselineCacheIRCompiler::emitMegamorphicLoadSlotResult()
|
|||
return false;
|
||||
|
||||
// The object must be Native.
|
||||
masm.loadObjClass(obj, scratch3);
|
||||
masm.branchTest32(Assembler::NonZero, Address(scratch3, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), failure->label());
|
||||
masm.branchIfNonNativeObj(obj, scratch3, failure->label());
|
||||
|
||||
masm.Push(UndefinedValue());
|
||||
masm.moveStackPtrTo(scratch3.get());
|
||||
|
@ -1176,27 +1169,22 @@ BaselineCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
|
|||
// per the acquired properties analysis. Only change the group if the
|
||||
// old group still has a newScript. This only applies to PlainObjects.
|
||||
Label noGroupChange;
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch1);
|
||||
masm.branchPtr(Assembler::Equal,
|
||||
Address(scratch1, ObjectGroup::offsetOfAddendum()),
|
||||
ImmWord(0),
|
||||
&noGroupChange);
|
||||
masm.branchIfObjGroupHasNoAddendum(obj, scratch1, &noGroupChange);
|
||||
|
||||
// Reload the new group from the cache.
|
||||
// Update the object's group.
|
||||
masm.loadPtr(newGroupAddr, scratch1);
|
||||
|
||||
Address groupAddr(obj, JSObject::offsetOfGroup());
|
||||
EmitPreBarrier(masm, groupAddr, MIRType::ObjectGroup);
|
||||
masm.storePtr(scratch1, groupAddr);
|
||||
masm.storeObjGroup(scratch1, obj, [](MacroAssembler& masm, const Address& addr) {
|
||||
EmitPreBarrier(masm, addr, MIRType::ObjectGroup);
|
||||
});
|
||||
|
||||
masm.bind(&noGroupChange);
|
||||
}
|
||||
|
||||
// Update the object's shape.
|
||||
Address shapeAddr(obj, ShapedObject::offsetOfShape());
|
||||
masm.loadPtr(newShapeAddr, scratch1);
|
||||
EmitPreBarrier(masm, shapeAddr, MIRType::Shape);
|
||||
masm.storePtr(scratch1, shapeAddr);
|
||||
masm.storeObjShape(scratch1, obj, [](MacroAssembler& masm, const Address& addr) {
|
||||
EmitPreBarrier(masm, addr, MIRType::Shape);
|
||||
});
|
||||
|
||||
// Perform the store. No pre-barrier required since this is a new
|
||||
// initialization.
|
||||
|
|
|
@ -426,11 +426,10 @@ ICTypeUpdate_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
// Guard on the object's ObjectGroup.
|
||||
Register obj = masm.extractObject(R0, R1.scratchReg());
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg());
|
||||
|
||||
Register scratch = R1.scratchReg();
|
||||
Register obj = masm.extractObject(R0, scratch);
|
||||
Address expectedGroup(ICStubReg, ICTypeUpdate_ObjectGroup::offsetOfGroup());
|
||||
masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure);
|
||||
masm.branchTestObjGroup(Assembler::NotEqual, obj, expectedGroup, scratch, &failure);
|
||||
|
||||
// Group matches, load true into R1.scratchReg() and return.
|
||||
masm.mov(ImmWord(1), R1.scratchReg());
|
||||
|
@ -775,9 +774,7 @@ LoadTypedThingLength(MacroAssembler& masm, TypedThingLayout layout, Register obj
|
|||
break;
|
||||
case Layout_OutlineTypedObject:
|
||||
case Layout_InlineTypedObject:
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), result);
|
||||
masm.loadPtr(Address(result, ObjectGroup::offsetOfAddendum()), result);
|
||||
masm.unboxInt32(Address(result, ArrayTypeDescr::offsetOfLength()), result);
|
||||
masm.loadTypedObjectLength(obj, result);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
|
@ -3432,11 +3429,9 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
// Ensure the callee's class matches the one in this stub.
|
||||
Register callee = masm.extractObject(R1, ExtractTemp0);
|
||||
Register scratch = regs.takeAny();
|
||||
masm.loadObjClass(callee, scratch);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(ICStubReg, ICCall_ClassHook::offsetOfClass()),
|
||||
scratch, &failure);
|
||||
|
||||
masm.branchTestObjClass(Assembler::NotEqual, callee, scratch,
|
||||
Address(ICStubReg, ICCall_ClassHook::offsetOfClass()),
|
||||
&failure);
|
||||
regs.add(R1);
|
||||
regs.takeUnchecked(callee);
|
||||
|
||||
|
|
|
@ -1472,9 +1472,7 @@ CacheIRCompiler::emitGuardIsNativeObject()
|
|||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
masm.loadObjClass(obj, scratch);
|
||||
masm.branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), failure->label());
|
||||
masm.branchIfNonNativeObj(obj, scratch, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2668,9 +2666,7 @@ CacheIRCompiler::emitMegamorphicLoadSlotByValueResult()
|
|||
return false;
|
||||
|
||||
// The object must be Native.
|
||||
masm.loadObjClass(obj, scratch);
|
||||
masm.branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), failure->label());
|
||||
masm.branchIfNonNativeObj(obj, scratch, failure->label());
|
||||
|
||||
// idVal will be in vp[0], result will be stored in vp[1].
|
||||
masm.reserveStack(sizeof(Value));
|
||||
|
|
|
@ -959,8 +959,7 @@ CodeGenerator::visitFunctionDispatch(LFunctionDispatch* lir)
|
|||
MOZ_ASSERT(i < mir->numCases());
|
||||
LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
|
||||
if (ObjectGroup* funcGroup = mir->getCaseObjectGroup(i)) {
|
||||
masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfGroup()),
|
||||
ImmGCPtr(funcGroup), target->label());
|
||||
masm.branchTestObjGroup(Assembler::Equal, input, funcGroup, target->label());
|
||||
} else {
|
||||
JSFunction* func = mir->getCase(i);
|
||||
masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
|
||||
|
@ -979,7 +978,7 @@ CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch* lir)
|
|||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
// Load the incoming ObjectGroup in temp.
|
||||
masm.loadPtr(Address(input, JSObject::offsetOfGroup()), temp);
|
||||
masm.loadObjGroupUnsafe(input, temp);
|
||||
|
||||
// Compare ObjectGroups.
|
||||
MacroAssembler::BranchGCPtr lastBranch;
|
||||
|
@ -2518,8 +2517,7 @@ CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
|
|||
RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape();
|
||||
masm.loadPtr(Address(temp, offset), temp);
|
||||
|
||||
masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
|
||||
masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, temp, ool->entry());
|
||||
masm.move32(Imm32(0x1), output);
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
|
@ -2579,8 +2577,7 @@ CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
|
|||
RegExpCompartment::offsetOfOptimizableRegExpInstanceShape();
|
||||
masm.loadPtr(Address(temp, offset), temp);
|
||||
|
||||
masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
|
||||
masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, temp, ool->entry());
|
||||
masm.move32(Imm32(0x1), output);
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
|
@ -3716,11 +3713,8 @@ CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir)
|
|||
OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir,
|
||||
ArgList(object), StoreNothing());
|
||||
|
||||
if (lir->mir()->checkNative()) {
|
||||
masm.loadObjClass(object, temp);
|
||||
masm.branchTest32(Assembler::NonZero, Address(temp, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), ool->rejoin());
|
||||
}
|
||||
if (lir->mir()->checkNative())
|
||||
masm.branchIfNonNativeObj(object, temp, ool->rejoin());
|
||||
|
||||
masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp);
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
|
@ -4302,17 +4296,8 @@ LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv, DOMObjectKind
|
|||
masm.branchTestObjectIsProxy(true, obj, priv, &isProxy);
|
||||
|
||||
if (kind != DOMObjectKind::Proxy) {
|
||||
#ifdef DEBUG
|
||||
// If it's a native object, the value must be in a fixed slot.
|
||||
Label hasFixedSlots;
|
||||
masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), priv);
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
Address(priv, Shape::offsetOfSlotInfo()),
|
||||
Imm32(Shape::fixedSlotsMask()),
|
||||
&hasFixedSlots);
|
||||
masm.assumeUnreachable("Expected a fixed slot");
|
||||
masm.bind(&hasFixedSlots);
|
||||
#endif
|
||||
masm.debugAssertObjHasFixedSlots(obj, priv);
|
||||
masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), priv);
|
||||
if (kind == DOMObjectKind::Unknown)
|
||||
masm.jump(&done);
|
||||
|
@ -4888,10 +4873,10 @@ CodeGenerator::emitApplyGeneric(T* apply)
|
|||
|
||||
// Unless already known, guard that calleereg is actually a function object.
|
||||
if (!apply->hasSingleTarget()) {
|
||||
masm.loadObjClass(calleereg, objreg);
|
||||
|
||||
ImmPtr ptr = ImmPtr(&JSFunction::class_);
|
||||
bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, calleereg, objreg, &JSFunction::class_,
|
||||
&bail);
|
||||
bailoutFrom(&bail, apply->snapshot());
|
||||
}
|
||||
|
||||
// Copy the arguments of the current function.
|
||||
|
@ -6378,38 +6363,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
|
|||
Register temp = ToRegister(lir->temp());
|
||||
Label bail;
|
||||
|
||||
// obj->group()
|
||||
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp);
|
||||
|
||||
// Guard that the object has the same representation as the one produced for
|
||||
// SIMD value-type.
|
||||
Address clasp(temp, ObjectGroup::offsetOfClasp());
|
||||
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
|
||||
masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
|
||||
&bail);
|
||||
|
||||
// obj->type()->typeDescr()
|
||||
// The previous class pointer comparison implies that the addendumKind is
|
||||
// Addendum_TypeDescr.
|
||||
masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp);
|
||||
|
||||
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
|
||||
// Value which is equivalent to the object class check.
|
||||
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
|
||||
masm.assertTestInt32(Assembler::Equal, typeDescrKind,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
|
||||
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
|
||||
|
||||
SimdType type = lir->mir()->simdType();
|
||||
|
||||
// Check if the SimdTypeDescr /Type/ match the specialization of this
|
||||
// MSimdUnbox instruction.
|
||||
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
|
||||
masm.assertTestInt32(Assembler::Equal, typeDescrType,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
|
||||
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(int32_t(type)), &bail);
|
||||
masm.branchIfNotSimdObject(object, temp, lir->mir()->simdType(), &bail);
|
||||
|
||||
// Load the value from the data of the InlineTypedObject.
|
||||
Address objectData(object, InlineTypedObject::offsetOfDataStart());
|
||||
|
@ -7095,9 +7049,7 @@ CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr* lir)
|
|||
{
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register out = ToRegister(lir->output());
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), out);
|
||||
masm.loadPtr(Address(out, ObjectGroup::offsetOfAddendum()), out);
|
||||
masm.loadTypedObjectDescr(obj, out);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7110,9 +7062,7 @@ CodeGenerator::visitTypedObjectElements(LTypedObjectElements* lir)
|
|||
masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
|
||||
} else {
|
||||
Label inlineObject, done;
|
||||
masm.loadObjClass(obj, out);
|
||||
masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
|
||||
masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
|
||||
masm.branchIfInlineTypedObject(obj, out, &inlineObject);
|
||||
|
||||
masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
|
||||
masm.jump(&done);
|
||||
|
@ -7135,9 +7085,7 @@ CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset* lir)
|
|||
masm.loadPtr(Address(object, OutlineTypedObject::offsetOfOwner()), temp0);
|
||||
|
||||
Label inlineObject, done;
|
||||
masm.loadObjClass(temp0, temp1);
|
||||
masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
|
||||
masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
|
||||
masm.branchIfInlineTypedObject(temp0, temp1, &inlineObject);
|
||||
|
||||
masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0);
|
||||
masm.jump(&done);
|
||||
|
@ -9323,8 +9271,7 @@ CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative*
|
|||
OutOfLineCode* ool = oolCallVM(ConvertUnboxedPlainObjectToNativeInfo,
|
||||
lir, ArgList(object), StoreNothing());
|
||||
|
||||
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
|
||||
ImmGCPtr(lir->mir()->group()), ool->entry());
|
||||
masm.branchTestObjGroup(Assembler::Equal, object, lir->mir()->group(), ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
|
@ -9521,8 +9468,7 @@ CodeGenerator::visitArraySlice(LArraySlice* lir)
|
|||
masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
|
||||
|
||||
// Fixup the group of the result in case it doesn't match the template object.
|
||||
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp2);
|
||||
masm.storePtr(temp2, Address(temp1, JSObject::offsetOfGroup()));
|
||||
masm.copyObjGroupNoPreBarrier(object, temp1, temp2);
|
||||
|
||||
masm.jump(&call);
|
||||
{
|
||||
|
@ -12140,7 +12086,7 @@ void
|
|||
CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
|
||||
{
|
||||
Label notFunction, hasCOps, done;
|
||||
masm.loadObjClass(object, output);
|
||||
masm.loadObjClassUnsafe(object, output);
|
||||
|
||||
// Just skim proxies off. Their notion of isCallable()/isConstructor() is
|
||||
// more complicated.
|
||||
|
@ -12319,7 +12265,7 @@ static void
|
|||
EmitObjectIsArray(MacroAssembler& masm, OutOfLineCode* ool, Register obj, Register output,
|
||||
Label* notArray = nullptr)
|
||||
{
|
||||
masm.loadObjClass(obj, output);
|
||||
masm.loadObjClassUnsafe(obj, output);
|
||||
|
||||
Label isArray;
|
||||
masm.branchPtr(Assembler::Equal, output, ImmPtr(&ArrayObject::class_), &isArray);
|
||||
|
@ -12380,7 +12326,7 @@ CodeGenerator::visitIsTypedArray(LIsTypedArray* lir)
|
|||
const Class* firstTypedArrayClass = TypedArrayObject::classForType(Scalar::Int8);
|
||||
const Class* lastTypedArrayClass = TypedArrayObject::classForType(Scalar::Uint8Clamped);
|
||||
|
||||
masm.loadObjClass(object, output);
|
||||
masm.loadObjClassUnsafe(object, output);
|
||||
masm.branchPtr(Assembler::Below, output, ImmPtr(firstTypedArrayClass), ¬TypedArray);
|
||||
masm.branchPtr(Assembler::Above, output, ImmPtr(lastTypedArrayClass), ¬TypedArray);
|
||||
|
||||
|
@ -12434,7 +12380,7 @@ CodeGenerator::visitHasClass(LHasClass* ins)
|
|||
Register lhs = ToRegister(ins->lhs());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
masm.loadObjClass(lhs, output);
|
||||
masm.loadObjClassUnsafe(lhs, output);
|
||||
masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,9 @@ CompileZone::addressOfStringNurseryCurrentEnd()
|
|||
bool
|
||||
CompileZone::canNurseryAllocateStrings()
|
||||
{
|
||||
return nurseryExists() && zone()->group()->nursery().canAllocateStrings();
|
||||
return nurseryExists() &&
|
||||
zone()->group()->nursery().canAllocateStrings() &&
|
||||
zone()->allocNurseryStrings;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -2229,6 +2229,12 @@ IsRegExpHoistable(MIRGenerator* mir, MDefinition* regexp, MDefinitionVector& wor
|
|||
bool
|
||||
jit::MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph)
|
||||
{
|
||||
// If we are compiling try blocks, regular expressions may be observable
|
||||
// from catch blocks (which Ion does not compile). For now just disable the
|
||||
// pass in this case.
|
||||
if (graph.hasTryBlock())
|
||||
return true;
|
||||
|
||||
MDefinitionVector worklist(graph.alloc());
|
||||
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
|
|
|
@ -699,9 +699,8 @@ IonCacheIRCompiler::emitGuardCompartment()
|
|||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, scratch, ImmPtr(compartment), failure->label());
|
||||
masm.branchTestObjCompartment(Assembler::NotEqual, obj, compartment, scratch,
|
||||
failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -935,9 +934,7 @@ IonCacheIRCompiler::emitMegamorphicLoadSlotResult()
|
|||
return false;
|
||||
|
||||
// The object must be Native.
|
||||
masm.loadObjClass(obj, scratch3);
|
||||
masm.branchTest32(Assembler::NonZero, Address(scratch3, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), failure->label());
|
||||
masm.branchIfNonNativeObj(obj, scratch3, failure->label());
|
||||
|
||||
masm.Push(UndefinedValue());
|
||||
masm.moveStackPtrTo(scratch3.get());
|
||||
|
@ -1652,23 +1649,20 @@ IonCacheIRCompiler::emitAddAndStoreSlotShared(CacheOp op)
|
|||
// per the acquired properties analysis. Only change the group if the
|
||||
// old group still has a newScript. This only applies to PlainObjects.
|
||||
Label noGroupChange;
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch1);
|
||||
masm.branchPtr(Assembler::Equal,
|
||||
Address(scratch1, ObjectGroup::offsetOfAddendum()),
|
||||
ImmWord(0),
|
||||
&noGroupChange);
|
||||
masm.branchIfObjGroupHasNoAddendum(obj, scratch1, &noGroupChange);
|
||||
|
||||
Address groupAddr(obj, JSObject::offsetOfGroup());
|
||||
EmitPreBarrier(masm, groupAddr, MIRType::ObjectGroup);
|
||||
masm.storePtr(ImmGCPtr(newGroup), groupAddr);
|
||||
// Update the object's group.
|
||||
masm.storeObjGroup(newGroup, obj, [](MacroAssembler& masm, const Address& addr) {
|
||||
EmitPreBarrier(masm, addr, MIRType::ObjectGroup);
|
||||
});
|
||||
|
||||
masm.bind(&noGroupChange);
|
||||
}
|
||||
|
||||
// Update the object's shape.
|
||||
Address shapeAddr(obj, ShapedObject::offsetOfShape());
|
||||
EmitPreBarrier(masm, shapeAddr, MIRType::Shape);
|
||||
masm.storePtr(ImmGCPtr(newShape), shapeAddr);
|
||||
masm.storeObjShape(newShape, obj, [](MacroAssembler& masm, const Address& addr) {
|
||||
EmitPreBarrier(masm, addr, MIRType::Shape);
|
||||
});
|
||||
|
||||
// Perform the store. No pre-barrier required since this is a new
|
||||
// initialization.
|
||||
|
|
|
@ -621,6 +621,11 @@ class JitCompartment
|
|||
|
||||
void sweep(JSCompartment* compartment);
|
||||
|
||||
void discardStubs() {
|
||||
for (ReadBarrieredJitCode& stubRef : stubs_)
|
||||
stubRef = nullptr;
|
||||
}
|
||||
|
||||
JitCode* stringConcatStubNoBarrier(uint32_t* requiredBarriersOut) const {
|
||||
return getStubNoBarrier(StringConcat, requiredBarriersOut);
|
||||
}
|
||||
|
|
|
@ -467,7 +467,7 @@ MacroAssembler::branchIfObjectEmulatesUndefined(Register objReg, Register scratc
|
|||
{
|
||||
// The branches to out-of-line code here implement a conservative version
|
||||
// of the JSObject::isWrapper test performed in EmulatesUndefined.
|
||||
loadObjClass(objReg, scratch);
|
||||
loadObjClassUnsafe(objReg, scratch);
|
||||
|
||||
branchTestClassIsProxy(true, scratch, slowCheck);
|
||||
|
||||
|
@ -492,13 +492,22 @@ MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class* clasp,
|
||||
Label* label)
|
||||
MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch,
|
||||
const js::Class* clasp, Label* label)
|
||||
{
|
||||
loadObjGroup(obj, scratch);
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjClass(Condition cond, Register obj, Register scratch,
|
||||
const Address& clasp, Label* label)
|
||||
{
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
|
||||
branchPtr(cond, clasp, scratch, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label)
|
||||
{
|
||||
|
@ -512,7 +521,8 @@ MacroAssembler::branchTestObjShape(Condition cond, Register obj, Register shape,
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjGroup(Condition cond, Register obj, ObjectGroup* group, Label* label)
|
||||
MacroAssembler::branchTestObjGroup(Condition cond, Register obj, const ObjectGroup* group,
|
||||
Label* label)
|
||||
{
|
||||
branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label);
|
||||
}
|
||||
|
@ -534,7 +544,7 @@ MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp, Label* label)
|
|||
void
|
||||
MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label)
|
||||
{
|
||||
loadObjClass(object, scratch);
|
||||
loadObjClassUnsafe(object, scratch);
|
||||
branchTestClassIsProxy(proxy, scratch, label);
|
||||
}
|
||||
|
||||
|
@ -733,6 +743,44 @@ MacroAssembler::reserveStack(uint32_t amount)
|
|||
}
|
||||
#endif // !JS_CODEGEN_ARM64
|
||||
|
||||
template <typename EmitPreBarrier>
|
||||
void
|
||||
MacroAssembler::storeObjGroup(Register group, Register obj, EmitPreBarrier emitPreBarrier)
|
||||
{
|
||||
MOZ_ASSERT(group != obj);
|
||||
Address groupAddr(obj, JSObject::offsetOfGroup());
|
||||
emitPreBarrier(*this, groupAddr);
|
||||
storePtr(group, groupAddr);
|
||||
}
|
||||
|
||||
template <typename EmitPreBarrier>
|
||||
void
|
||||
MacroAssembler::storeObjGroup(ObjectGroup* group, Register obj, EmitPreBarrier emitPreBarrier)
|
||||
{
|
||||
Address groupAddr(obj, JSObject::offsetOfGroup());
|
||||
emitPreBarrier(*this, groupAddr);
|
||||
storePtr(ImmGCPtr(group), groupAddr);
|
||||
}
|
||||
|
||||
template <typename EmitPreBarrier>
|
||||
void
|
||||
MacroAssembler::storeObjShape(Register shape, Register obj, EmitPreBarrier emitPreBarrier)
|
||||
{
|
||||
MOZ_ASSERT(shape != obj);
|
||||
Address shapeAddr(obj, ShapedObject::offsetOfShape());
|
||||
emitPreBarrier(*this, shapeAddr);
|
||||
storePtr(shape, shapeAddr);
|
||||
}
|
||||
|
||||
template <typename EmitPreBarrier>
|
||||
void
|
||||
MacroAssembler::storeObjShape(Shape* shape, Register obj, EmitPreBarrier emitPreBarrier)
|
||||
{
|
||||
Address shapeAddr(obj, ShapedObject::offsetOfShape());
|
||||
emitPreBarrier(*this, shapeAddr);
|
||||
storePtr(ImmGCPtr(shape), shapeAddr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::storeObjectOrNull(Register src, const T& dest)
|
||||
|
|
|
@ -1751,7 +1751,7 @@ void
|
|||
MacroAssembler::typeOfObject(Register obj, Register scratch, Label* slow,
|
||||
Label* isObject, Label* isCallable, Label* isUndefined)
|
||||
{
|
||||
loadObjClass(obj, scratch);
|
||||
loadObjClassUnsafe(obj, scratch);
|
||||
|
||||
// Proxies can emulate undefined and have complex isCallable behavior.
|
||||
branchTestClassIsProxy(true, scratch, slow);
|
||||
|
@ -3200,6 +3200,128 @@ MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch
|
|||
branchTest32(Assembler::Zero, scratch, Imm32(bits), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjGroup(Condition cond, Register obj, const Address& group,
|
||||
Register scratch, Label* label)
|
||||
{
|
||||
// Note: obj and scratch registers may alias.
|
||||
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
branchPtr(cond, group, scratch, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjCompartment(Condition cond, Register obj, const Address& compartment,
|
||||
Register scratch, Label* label)
|
||||
{
|
||||
MOZ_ASSERT(obj != scratch);
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
branchPtr(cond, compartment, scratch, label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchTestObjCompartment(Condition cond, Register obj,
|
||||
const JSCompartment* compartment, Register scratch,
|
||||
Label* label)
|
||||
{
|
||||
MOZ_ASSERT(obj != scratch);
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
branchPtr(cond, scratch, ImmPtr(compartment), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchIfObjGroupHasNoAddendum(Register obj, Register scratch, Label* label)
|
||||
{
|
||||
MOZ_ASSERT(obj != scratch);
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
branchPtr(Assembler::Equal,
|
||||
Address(scratch, ObjectGroup::offsetOfAddendum()),
|
||||
ImmWord(0),
|
||||
label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchIfPretenuredGroup(const ObjectGroup* group, Register scratch, Label* label)
|
||||
{
|
||||
movePtr(ImmGCPtr(group), scratch);
|
||||
branchTest32(Assembler::NonZero, Address(scratch, ObjectGroup::offsetOfFlags()),
|
||||
Imm32(OBJECT_FLAG_PRE_TENURE), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchIfNonNativeObj(Register obj, Register scratch, Label* label)
|
||||
{
|
||||
loadObjClassUnsafe(obj, scratch);
|
||||
branchTest32(Assembler::NonZero, Address(scratch, Class::offsetOfFlags()),
|
||||
Imm32(Class::NON_NATIVE), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchIfInlineTypedObject(Register obj, Register scratch, Label* label)
|
||||
{
|
||||
loadObjClassUnsafe(obj, scratch);
|
||||
branchPtr(Assembler::Equal, scratch, ImmPtr(&InlineOpaqueTypedObject::class_), label);
|
||||
branchPtr(Assembler::Equal, scratch, ImmPtr(&InlineTransparentTypedObject::class_), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::branchIfNotSimdObject(Register obj, Register scratch, SimdType simdType,
|
||||
Label* label)
|
||||
{
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
|
||||
// Guard that the object has the same representation as the one produced for
|
||||
// SIMD value-type.
|
||||
Address clasp(scratch, ObjectGroup::offsetOfClasp());
|
||||
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
|
||||
branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
|
||||
label);
|
||||
|
||||
// obj->type()->typeDescr()
|
||||
// The previous class pointer comparison implies that the addendumKind is
|
||||
// Addendum_TypeDescr.
|
||||
loadPtr(Address(scratch, ObjectGroup::offsetOfAddendum()), scratch);
|
||||
|
||||
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
|
||||
// Value which is equivalent to the object class check.
|
||||
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrKind(scratch, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
|
||||
assertTestInt32(Assembler::Equal, typeDescrKind,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
|
||||
branch32(Assembler::NotEqual, ToPayload(typeDescrKind), Imm32(js::type::Simd), label);
|
||||
|
||||
// Check if the SimdTypeDescr /Type/ matches the specialization of this
|
||||
// MSimdUnbox instruction.
|
||||
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrType(scratch, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
|
||||
assertTestInt32(Assembler::Equal, typeDescrType,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
|
||||
branch32(Assembler::NotEqual, ToPayload(typeDescrType), Imm32(int32_t(simdType)), label);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::copyObjGroupNoPreBarrier(Register sourceObj, Register destObj, Register scratch)
|
||||
{
|
||||
loadPtr(Address(sourceObj, JSObject::offsetOfGroup()), scratch);
|
||||
storePtr(scratch, Address(destObj, JSObject::offsetOfGroup()));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::loadTypedObjectDescr(Register obj, Register dest)
|
||||
{
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
|
||||
loadPtr(Address(dest, ObjectGroup::offsetOfAddendum()), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::loadTypedObjectLength(Register obj, Register dest)
|
||||
{
|
||||
loadTypedObjectDescr(obj, dest);
|
||||
unboxInt32(Address(dest, ArrayTypeDescr::offsetOfLength()), dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label)
|
||||
{
|
||||
|
@ -3570,6 +3692,21 @@ MacroAssembler::debugAssertIsObject(const ValueOperand& val)
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::debugAssertObjHasFixedSlots(Register obj, Register scratch)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Label hasFixedSlots;
|
||||
loadPtr(Address(obj, ShapedObject::offsetOfShape()), scratch);
|
||||
branchTest32(Assembler::NonZero,
|
||||
Address(scratch, Shape::offsetOfSlotInfo()),
|
||||
Imm32(Shape::fixedSlotsMask()),
|
||||
&hasFixedSlots);
|
||||
assumeUnreachable("Expected a fixed slot");
|
||||
bind(&hasFixedSlots);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreMaskIndex(Register index, Register length, Register output)
|
||||
{
|
||||
|
|
|
@ -1177,13 +1177,32 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void branchIfObjectEmulatesUndefined(Register objReg, Register scratch, Label* slowCheck,
|
||||
Label* label);
|
||||
|
||||
inline void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class* clasp,
|
||||
Label* label);
|
||||
inline void branchTestObjClass(Condition cond, Register obj, Register scratch,
|
||||
const js::Class* clasp, Label* label);
|
||||
inline void branchTestObjClass(Condition cond, Register obj, Register scratch,
|
||||
const Address& clasp, Label* label);
|
||||
inline void branchTestObjShape(Condition cond, Register obj, const Shape* shape, Label* label);
|
||||
inline void branchTestObjShape(Condition cond, Register obj, Register shape, Label* label);
|
||||
inline void branchTestObjGroup(Condition cond, Register obj, ObjectGroup* group, Label* label);
|
||||
inline void branchTestObjGroup(Condition cond, Register obj, const ObjectGroup* group,
|
||||
Label* label);
|
||||
inline void branchTestObjGroup(Condition cond, Register obj, Register group, Label* label);
|
||||
|
||||
void branchTestObjGroup(Condition cond, Register obj, const Address& group, Register scratch,
|
||||
Label* label);
|
||||
|
||||
void branchTestObjCompartment(Condition cond, Register obj, const Address& compartment,
|
||||
Register scratch, Label* label);
|
||||
void branchTestObjCompartment(Condition cond, Register obj, const JSCompartment* compartment,
|
||||
Register scratch, Label* label);
|
||||
void branchIfObjGroupHasNoAddendum(Register obj, Register scratch, Label* label);
|
||||
void branchIfPretenuredGroup(const ObjectGroup* group, Register scratch, Label* label);
|
||||
|
||||
void branchIfNonNativeObj(Register obj, Register scratch, Label* label);
|
||||
|
||||
void branchIfInlineTypedObject(Register obj, Register scratch, Label* label);
|
||||
|
||||
void branchIfNotSimdObject(Register obj, Register scratch, SimdType simdType, Label* label);
|
||||
|
||||
inline void branchTestClassIsProxy(bool proxy, Register clasp, Label* label);
|
||||
|
||||
inline void branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label);
|
||||
|
@ -1191,6 +1210,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline void branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch,
|
||||
const void* handlerp, Label* label);
|
||||
|
||||
void copyObjGroupNoPreBarrier(Register sourceObj, Register destObj, Register scratch);
|
||||
|
||||
void loadTypedObjectDescr(Register obj, Register dest);
|
||||
void loadTypedObjectLength(Register obj, Register dest);
|
||||
|
||||
// Emit type case branch on tag matching if the type tag in the definition
|
||||
// might actually be that type.
|
||||
void maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label);
|
||||
|
@ -1951,21 +1975,25 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
Label* label);
|
||||
#endif
|
||||
|
||||
void loadObjShape(Register objReg, Register dest) {
|
||||
loadPtr(Address(objReg, ShapedObject::offsetOfShape()), dest);
|
||||
// Unsafe here means the caller is responsible for Spectre mitigations if
|
||||
// needed. Prefer branchTestObjGroup or one of the other masm helpers!
|
||||
void loadObjGroupUnsafe(Register obj, Register dest) {
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
|
||||
}
|
||||
void loadObjGroup(Register objReg, Register dest) {
|
||||
loadPtr(Address(objReg, JSObject::offsetOfGroup()), dest);
|
||||
}
|
||||
void loadBaseShape(Register objReg, Register dest) {
|
||||
loadObjShape(objReg, dest);
|
||||
loadPtr(Address(dest, Shape::offsetOfBase()), dest);
|
||||
}
|
||||
void loadObjClass(Register objReg, Register dest) {
|
||||
loadObjGroup(objReg, dest);
|
||||
void loadObjClassUnsafe(Register obj, Register dest) {
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), dest);
|
||||
loadPtr(Address(dest, ObjectGroup::offsetOfClasp()), dest);
|
||||
}
|
||||
|
||||
template <typename EmitPreBarrier>
|
||||
inline void storeObjGroup(Register group, Register obj, EmitPreBarrier emitPreBarrier);
|
||||
template <typename EmitPreBarrier>
|
||||
inline void storeObjGroup(ObjectGroup* group, Register obj, EmitPreBarrier emitPreBarrier);
|
||||
template <typename EmitPreBarrier>
|
||||
inline void storeObjShape(Register shape, Register obj, EmitPreBarrier emitPreBarrier);
|
||||
template <typename EmitPreBarrier>
|
||||
inline void storeObjShape(Shape* shape, Register obj, EmitPreBarrier emitPreBarrier);
|
||||
|
||||
void loadObjPrivate(Register obj, uint32_t nfixed, Register dest) {
|
||||
loadPtr(Address(obj, NativeObject::getPrivateDataOffset(nfixed)), dest);
|
||||
}
|
||||
|
@ -2192,6 +2220,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
const ConstantOrRegister& value, Label* failure);
|
||||
|
||||
void debugAssertIsObject(const ValueOperand& val);
|
||||
void debugAssertObjHasFixedSlots(Register obj, Register scratch);
|
||||
|
||||
using MacroAssemblerSpecific::extractTag;
|
||||
Register extractTag(const TypedOrValueRegister& reg, Register scratch) {
|
||||
|
|
|
@ -2540,10 +2540,9 @@ ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
// Guard on the object's ObjectGroup.
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg());
|
||||
|
||||
Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
|
||||
masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure);
|
||||
masm.branchTestObjGroup(Assembler::NotEqual, obj, expectedGroup, R1.scratchReg(),
|
||||
&failure);
|
||||
MaybeWorkAroundAmdBug(masm);
|
||||
|
||||
EmitReturnFromIC(masm);
|
||||
|
@ -2765,9 +2764,7 @@ GenerateNewObjectWithTemplateCode(JSContext* cx, JSObject* templateObject)
|
|||
Label failure;
|
||||
Register objReg = R0.scratchReg();
|
||||
Register tempReg = R1.scratchReg();
|
||||
masm.movePtr(ImmGCPtr(templateObject->group()), tempReg);
|
||||
masm.branchTest32(Assembler::NonZero, Address(tempReg, ObjectGroup::offsetOfFlags()),
|
||||
Imm32(OBJECT_FLAG_PRE_TENURE), &failure);
|
||||
masm.branchIfPretenuredGroup(templateObject->group(), tempReg, &failure);
|
||||
masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataBuilder()),
|
||||
ImmWord(0), &failure);
|
||||
masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, &failure);
|
||||
|
|
|
@ -721,7 +721,10 @@ PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
|
|||
if (InBounds == IndexInBounds::Yes) {
|
||||
MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
|
||||
} else {
|
||||
if (MOZ_UNLIKELY(!obj->is<NativeObject>() || index < 0)) {
|
||||
if (MOZ_UNLIKELY(!obj->is<NativeObject>() ||
|
||||
index < 0 ||
|
||||
uint32_t(index) >= NativeObject::MAX_DENSE_ELEMENTS_COUNT))
|
||||
{
|
||||
rt->gc.storeBuffer().putWholeCell(obj);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1746,29 +1746,20 @@ void
|
|||
CodeGeneratorARM::visitGuardShape(LGuardShape* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
ScratchRegisterScope scratch(masm);
|
||||
masm.ma_ldr(DTRAddr(obj, DtrOffImm(ShapedObject::offsetOfShape())), tmp);
|
||||
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()), scratch);
|
||||
|
||||
bailoutIf(Assembler::NotEqual, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorARM::visitGuardObjectGroup(LGuardObjectGroup* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
MOZ_ASSERT(obj != tmp);
|
||||
|
||||
ScratchRegisterScope scratch(masm);
|
||||
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfGroup())), tmp);
|
||||
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->group()), scratch);
|
||||
|
||||
Assembler::Condition cond =
|
||||
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
|
||||
bailoutIf(cond, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1776,12 +1767,9 @@ CodeGeneratorARM::visitGuardClass(LGuardClass* guard)
|
|||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
ScratchRegisterScope scratch(masm);
|
||||
|
||||
masm.loadObjClass(obj, tmp);
|
||||
masm.ma_cmp(tmp, Imm32((uint32_t)guard->mir()->getClass()), scratch);
|
||||
bailoutIf(Assembler::NotEqual, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -383,14 +383,13 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
|
|||
}
|
||||
};
|
||||
|
||||
class LGuardShape : public LInstructionHelper<0, 1, 1>
|
||||
class LGuardShape : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GuardShape);
|
||||
|
||||
LGuardShape(const LAllocation& in, const LDefinition& temp) {
|
||||
explicit LGuardShape(const LAllocation& in) {
|
||||
setOperand(0, in);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
const MGuardShape* mir() const {
|
||||
return mir_->toGuardShape();
|
||||
|
@ -400,14 +399,13 @@ class LGuardShape : public LInstructionHelper<0, 1, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LGuardObjectGroup : public LInstructionHelper<0, 1, 1>
|
||||
class LGuardObjectGroup : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GuardObjectGroup);
|
||||
|
||||
LGuardObjectGroup(const LAllocation& in, const LDefinition& temp) {
|
||||
explicit LGuardObjectGroup(const LAllocation& in) {
|
||||
setOperand(0, in);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
const MGuardObjectGroup* mir() const {
|
||||
return mir_->toGuardObjectGroup();
|
||||
|
|
|
@ -485,8 +485,7 @@ LIRGeneratorARM::visitGuardShape(MGuardShape* ins)
|
|||
{
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
|
||||
LDefinition tempObj = temp(LDefinition::OBJECT);
|
||||
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()), tempObj);
|
||||
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()));
|
||||
assignSnapshot(guard, ins->bailoutKind());
|
||||
add(guard, ins);
|
||||
redefine(ins, ins->object());
|
||||
|
@ -497,8 +496,7 @@ LIRGeneratorARM::visitGuardObjectGroup(MGuardObjectGroup* ins)
|
|||
{
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
|
||||
LDefinition tempObj = temp(LDefinition::OBJECT);
|
||||
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()), tempObj);
|
||||
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()));
|
||||
assignSnapshot(guard, ins->bailoutKind());
|
||||
add(guard, ins);
|
||||
redefine(ins, ins->object());
|
||||
|
|
|
@ -1772,25 +1772,20 @@ void
|
|||
CodeGeneratorMIPSShared::visitGuardShape(LGuardShape* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), tmp);
|
||||
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()),
|
||||
guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPSShared::visitGuardObjectGroup(LGuardObjectGroup* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
MOZ_ASSERT(obj != tmp);
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp);
|
||||
Assembler::Condition cond = guard->mir()->bailOnEquality()
|
||||
? Assembler::Equal
|
||||
: Assembler::NotEqual;
|
||||
bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->group()), guard->snapshot());
|
||||
Assembler::Condition cond =
|
||||
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
|
||||
Label bail;
|
||||
masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1798,10 +1793,9 @@ CodeGeneratorMIPSShared::visitGuardClass(LGuardClass* guard)
|
|||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
masm.loadObjClass(obj, tmp);
|
||||
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()),
|
||||
guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -210,14 +210,13 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
|
|||
}
|
||||
};
|
||||
|
||||
class LGuardShape : public LInstructionHelper<0, 1, 1>
|
||||
class LGuardShape : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GuardShape);
|
||||
|
||||
LGuardShape(const LAllocation& in, const LDefinition& temp) {
|
||||
explicit LGuardShape(const LAllocation& in) {
|
||||
setOperand(0, in);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
const MGuardShape* mir() const {
|
||||
return mir_->toGuardShape();
|
||||
|
@ -227,14 +226,13 @@ class LGuardShape : public LInstructionHelper<0, 1, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LGuardObjectGroup : public LInstructionHelper<0, 1, 1>
|
||||
class LGuardObjectGroup : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GuardObjectGroup);
|
||||
|
||||
LGuardObjectGroup(const LAllocation& in, const LDefinition& temp) {
|
||||
explicit LGuardObjectGroup(const LAllocation& in) {
|
||||
setOperand(0, in);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
const MGuardObjectGroup* mir() const {
|
||||
return mir_->toGuardObjectGroup();
|
||||
|
|
|
@ -292,8 +292,7 @@ LIRGeneratorMIPSShared::visitGuardShape(MGuardShape* ins)
|
|||
{
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
|
||||
LDefinition tempObj = temp(LDefinition::OBJECT);
|
||||
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()), tempObj);
|
||||
LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->object()));
|
||||
assignSnapshot(guard, ins->bailoutKind());
|
||||
add(guard, ins);
|
||||
redefine(ins, ins->object());
|
||||
|
@ -304,8 +303,7 @@ LIRGeneratorMIPSShared::visitGuardObjectGroup(MGuardObjectGroup* ins)
|
|||
{
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
|
||||
LDefinition tempObj = temp(LDefinition::OBJECT);
|
||||
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()), tempObj);
|
||||
LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->object()));
|
||||
assignSnapshot(guard, ins->bailoutKind());
|
||||
add(guard, ins);
|
||||
redefine(ins, ins->object());
|
||||
|
|
|
@ -2376,21 +2376,20 @@ void
|
|||
CodeGeneratorX86Shared::visitGuardShape(LGuardShape* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
masm.cmpPtr(Operand(obj, ShapedObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
|
||||
|
||||
bailoutIf(Assembler::NotEqual, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, guard->mir()->shape(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitGuardObjectGroup(LGuardObjectGroup* guard)
|
||||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
|
||||
masm.cmpPtr(Operand(obj, JSObject::offsetOfGroup()), ImmGCPtr(guard->mir()->group()));
|
||||
|
||||
Assembler::Condition cond =
|
||||
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
|
||||
bailoutIf(cond, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjGroup(cond, obj, guard->mir()->group(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2398,10 +2397,9 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass* guard)
|
|||
{
|
||||
Register obj = ToRegister(guard->input());
|
||||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp);
|
||||
masm.cmpPtr(Operand(tmp, ObjectGroup::offsetOfClasp()), ImmPtr(guard->mir()->getClass()));
|
||||
bailoutIf(Assembler::NotEqual, guard->snapshot());
|
||||
Label bail;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, obj, tmp, guard->mir()->getClass(), &bail);
|
||||
bailoutFrom(&bail, guard->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -3993,6 +3993,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp
|
|||
introductionOffset = rhs.introductionOffset;
|
||||
hasIntroductionInfo = rhs.hasIntroductionInfo;
|
||||
isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode;
|
||||
hideScriptFromDebugger = rhs.hideScriptFromDebugger;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -4678,6 +4679,17 @@ JS::InitScriptSourceElement(JSContext* cx, HandleScript script,
|
|||
return ScriptSourceObject::initElementProperties(cx, sso, element, elementAttrName);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::ExposeScriptToDebugger(JSContext* cx, HandleScript script)
|
||||
{
|
||||
MOZ_ASSERT(cx);
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
|
||||
|
||||
MOZ_ASSERT(script->hideScriptFromDebugger());
|
||||
script->clearHideScriptFromDebugger();
|
||||
Debugger::onNewScript(cx, script);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
JS_DecompileScript(JSContext* cx, HandleScript script)
|
||||
{
|
||||
|
|
136
js/src/jsapi.h
136
js/src/jsapi.h
|
@ -102,133 +102,6 @@ class MOZ_RAII AutoValueArray : public AutoGCRooter
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter
|
||||
{
|
||||
typedef js::Vector<T, 8> VectorImpl;
|
||||
VectorImpl vector;
|
||||
|
||||
public:
|
||||
explicit AutoVectorRooterBase(JSContext* cx, ptrdiff_t tag
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoGCRooter(cx, tag), vector(cx)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
typedef T ElementType;
|
||||
typedef typename VectorImpl::Range Range;
|
||||
|
||||
size_t length() const { return vector.length(); }
|
||||
bool empty() const { return vector.empty(); }
|
||||
|
||||
MOZ_MUST_USE bool append(const T& v) { return vector.append(v); }
|
||||
MOZ_MUST_USE bool appendN(const T& v, size_t len) { return vector.appendN(v, len); }
|
||||
MOZ_MUST_USE bool append(const T* ptr, size_t len) { return vector.append(ptr, len); }
|
||||
MOZ_MUST_USE bool appendAll(const AutoVectorRooterBase<T>& other) {
|
||||
return vector.appendAll(other.vector);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool insert(T* p, const T& val) { return vector.insert(p, val); }
|
||||
|
||||
/* For use when space has already been reserved. */
|
||||
void infallibleAppend(const T& v) { vector.infallibleAppend(v); }
|
||||
|
||||
void popBack() { vector.popBack(); }
|
||||
T popCopy() { return vector.popCopy(); }
|
||||
|
||||
MOZ_MUST_USE bool growBy(size_t inc) {
|
||||
size_t oldLength = vector.length();
|
||||
if (!vector.growByUninitialized(inc))
|
||||
return false;
|
||||
makeRangeGCSafe(oldLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool resize(size_t newLength) {
|
||||
size_t oldLength = vector.length();
|
||||
if (newLength <= oldLength) {
|
||||
vector.shrinkBy(oldLength - newLength);
|
||||
return true;
|
||||
}
|
||||
if (!vector.growByUninitialized(newLength - oldLength))
|
||||
return false;
|
||||
makeRangeGCSafe(oldLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear() { vector.clear(); }
|
||||
|
||||
MOZ_MUST_USE bool reserve(size_t newLength) {
|
||||
return vector.reserve(newLength);
|
||||
}
|
||||
|
||||
JS::MutableHandle<T> operator[](size_t i) {
|
||||
return JS::MutableHandle<T>::fromMarkedLocation(&vector[i]);
|
||||
}
|
||||
JS::Handle<T> operator[](size_t i) const {
|
||||
return JS::Handle<T>::fromMarkedLocation(&vector[i]);
|
||||
}
|
||||
|
||||
const T* begin() const { return vector.begin(); }
|
||||
T* begin() { return vector.begin(); }
|
||||
|
||||
const T* end() const { return vector.end(); }
|
||||
T* end() { return vector.end(); }
|
||||
|
||||
Range all() { return vector.all(); }
|
||||
|
||||
const T& back() const { return vector.back(); }
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer* trc);
|
||||
|
||||
private:
|
||||
void makeRangeGCSafe(size_t oldLength) {
|
||||
T* t = vector.begin() + oldLength;
|
||||
for (size_t i = oldLength; i < vector.length(); ++i, ++t)
|
||||
memset(t, 0, sizeof(T));
|
||||
}
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase<T>
|
||||
{
|
||||
public:
|
||||
explicit AutoVectorRooter(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoVectorRooterBase<T>(cx, this->GetTag(T()))
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoValueVector : public Rooted<GCVector<Value, 8>> {
|
||||
using Vec = GCVector<Value, 8>;
|
||||
using Base = Rooted<Vec>;
|
||||
public:
|
||||
explicit AutoValueVector(JSContext* cx) : Base(cx, Vec(cx)) {}
|
||||
};
|
||||
|
||||
class AutoIdVector : public Rooted<GCVector<jsid, 8>> {
|
||||
using Vec = GCVector<jsid, 8>;
|
||||
using Base = Rooted<Vec>;
|
||||
public:
|
||||
explicit AutoIdVector(JSContext* cx) : Base(cx, Vec(cx)) {}
|
||||
|
||||
bool appendAll(const AutoIdVector& other) { return this->Base::appendAll(other.get()); }
|
||||
};
|
||||
|
||||
class AutoObjectVector : public Rooted<GCVector<JSObject*, 8>> {
|
||||
using Vec = GCVector<JSObject*, 8>;
|
||||
using Base = Rooted<Vec>;
|
||||
public:
|
||||
explicit AutoObjectVector(JSContext* cx) : Base(cx, Vec(cx)) {}
|
||||
};
|
||||
|
||||
using ValueVector = JS::GCVector<JS::Value>;
|
||||
using IdVector = JS::GCVector<jsid>;
|
||||
using ScriptVector = JS::GCVector<JSScript*>;
|
||||
|
@ -3692,6 +3565,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
|
|||
sourceIsLazy(false),
|
||||
allowHTMLComments(true),
|
||||
isProbablySystemOrAddonCode(false),
|
||||
hideScriptFromDebugger(false),
|
||||
introductionType(nullptr),
|
||||
introductionLineno(0),
|
||||
introductionOffset(0),
|
||||
|
@ -3727,6 +3601,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
|
|||
bool sourceIsLazy;
|
||||
bool allowHTMLComments;
|
||||
bool isProbablySystemOrAddonCode;
|
||||
bool hideScriptFromDebugger;
|
||||
|
||||
// |introductionType| is a statically allocated C string:
|
||||
// one of "eval", "Function", or "GeneratorFunction".
|
||||
|
@ -4134,6 +4009,13 @@ extern JS_PUBLIC_API(bool)
|
|||
InitScriptSourceElement(JSContext* cx, HandleScript script,
|
||||
HandleObject element, HandleString elementAttrName = nullptr);
|
||||
|
||||
/*
|
||||
* For a script compiled with the hideScriptFromDebugger option, expose the
|
||||
* script to the debugger by calling the debugger's onNewScript hook.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
ExposeScriptToDebugger(JSContext* cx, HandleScript script);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
extern JS_PUBLIC_API(JSString*)
|
||||
|
|
|
@ -29,7 +29,11 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
class AutoIdVector;
|
||||
template <typename T> class AutoVector;
|
||||
using AutoIdVector = AutoVector<jsid>;
|
||||
using AutoValueVector = AutoVector<Value>;
|
||||
using AutoObjectVector = AutoVector<JSObject*>;
|
||||
|
||||
class CallArgs;
|
||||
|
||||
class JS_FRIEND_API(CompileOptions);
|
||||
|
|
|
@ -9085,7 +9085,8 @@ main(int argc, char** argv, char** envp)
|
|||
|| !op.addBoolOption('\0', "no-ggc", "Disable Generational GC")
|
||||
|| !op.addBoolOption('\0', "no-cgc", "Disable Compacting GC")
|
||||
|| !op.addBoolOption('\0', "no-incremental-gc", "Disable Incremental GC")
|
||||
|| !op.addBoolOption('\0', "nursery-strings", "Allocate strings in the nursery")
|
||||
|| !op.addStringOption('\0', "nursery-strings", "on/off",
|
||||
"Allocate strings in the nursery")
|
||||
|| !op.addIntOption('\0', "available-memory", "SIZE",
|
||||
"Select GC settings based on available memory (MB)", 0)
|
||||
|| !op.addStringOption('\0', "arm-hwcap", "[features]",
|
||||
|
@ -9233,8 +9234,14 @@ main(int argc, char** argv, char** envp)
|
|||
|
||||
js::UseInternalJobQueues(cx);
|
||||
|
||||
if (op.getBoolOption("nursery-strings"))
|
||||
cx->runtime()->gc.nursery().enableStrings();
|
||||
if (const char* opt = op.getStringOption("nursery-strings")) {
|
||||
if (strcmp(opt, "on") == 0)
|
||||
cx->runtime()->gc.nursery().enableStrings();
|
||||
else if (strcmp(opt, "off") == 0)
|
||||
cx->runtime()->gc.nursery().disableStrings();
|
||||
else
|
||||
MOZ_CRASH("invalid option value for --nursery-strings, must be on/off");
|
||||
}
|
||||
|
||||
if (!JS::InitSelfHostedCode(cx))
|
||||
return 1;
|
||||
|
|
|
@ -1800,6 +1800,11 @@ Debugger::onNewScript(JSContext* cx, HandleScript script)
|
|||
MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() &&
|
||||
!script->selfHosted(),
|
||||
script->compartment()->firedOnNewGlobalObject);
|
||||
|
||||
// The script may not be ready to be interrogated by the debugger.
|
||||
if (script->hideScriptFromDebugger())
|
||||
return;
|
||||
|
||||
if (script->compartment()->isDebuggee())
|
||||
slowPathOnNewScript(cx, script);
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ GetSelectorRuntime(const CompilationSelector& selector)
|
|||
{
|
||||
JSRuntime* match(JSScript* script) { return script->runtimeFromActiveCooperatingThread(); }
|
||||
JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); }
|
||||
JSRuntime* match(Zone* zone) { return zone->runtimeFromActiveCooperatingThread(); }
|
||||
JSRuntime* match(ZonesInState zbs) { return zbs.runtime; }
|
||||
JSRuntime* match(JSRuntime* runtime) { return runtime; }
|
||||
JSRuntime* match(AllCompilations all) { return nullptr; }
|
||||
|
@ -234,6 +235,7 @@ JitDataStructuresExist(const CompilationSelector& selector)
|
|||
{
|
||||
bool match(JSScript* script) { return !!script->compartment()->jitCompartment(); }
|
||||
bool match(JSCompartment* comp) { return !!comp->jitCompartment(); }
|
||||
bool match(Zone* zone) { return !!zone->jitZone(); }
|
||||
bool match(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); }
|
||||
bool match(JSRuntime* runtime) { return runtime->hasJitRuntime(); }
|
||||
bool match(AllCompilations all) { return true; }
|
||||
|
@ -252,6 +254,7 @@ IonBuilderMatches(const CompilationSelector& selector, jit::IonBuilder* builder)
|
|||
|
||||
bool match(JSScript* script) { return script == builder_->script(); }
|
||||
bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); }
|
||||
bool match(Zone* zone) { return zone == builder_->script()->zone(); }
|
||||
bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); }
|
||||
bool match(AllCompilations all) { return true; }
|
||||
bool match(ZonesInState zbs) {
|
||||
|
|
|
@ -516,6 +516,7 @@ struct CompilationsUsingNursery { JSRuntime* runtime; };
|
|||
|
||||
using CompilationSelector = mozilla::Variant<JSScript*,
|
||||
JSCompartment*,
|
||||
Zone*,
|
||||
ZonesInState,
|
||||
JSRuntime*,
|
||||
CompilationsUsingNursery,
|
||||
|
@ -539,6 +540,12 @@ CancelOffThreadIonCompile(JSCompartment* comp)
|
|||
CancelOffThreadIonCompile(CompilationSelector(comp), true);
|
||||
}
|
||||
|
||||
inline void
|
||||
CancelOffThreadIonCompile(Zone* zone)
|
||||
{
|
||||
CancelOffThreadIonCompile(CompilationSelector(zone), true);
|
||||
}
|
||||
|
||||
inline void
|
||||
CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state)
|
||||
{
|
||||
|
|
|
@ -1384,16 +1384,20 @@ struct WrapperValue
|
|||
Value value;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
|
||||
class MOZ_RAII AutoWrapperVector : public JS::GCVector<WrapperValue, 8>,
|
||||
private JS::AutoGCRooter
|
||||
{
|
||||
public:
|
||||
explicit AutoWrapperVector(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: AutoVectorRooterBase<WrapperValue>(cx, WRAPVECTOR)
|
||||
: JS::GCVector<WrapperValue, 8>(cx),
|
||||
JS::AutoGCRooter(cx, WRAPVECTOR)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer* trc);
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
|
|
|
@ -541,7 +541,15 @@ class JSObject : public js::gc::Cell
|
|||
void dump() const;
|
||||
#endif
|
||||
|
||||
/* JIT Accessors */
|
||||
// Maximum size in bytes of a JSObject.
|
||||
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
|
||||
|
||||
protected:
|
||||
// JIT Accessors.
|
||||
//
|
||||
// To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
|
||||
// to call the method below.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
static constexpr size_t offsetOfGroup() {
|
||||
return offsetof(JSObject, group_);
|
||||
|
@ -550,9 +558,6 @@ class JSObject : public js::gc::Cell
|
|||
return offsetof(JSObject, shapeOrExpando_);
|
||||
}
|
||||
|
||||
// Maximum size in bytes of a JSObject.
|
||||
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
|
||||
|
||||
private:
|
||||
JSObject() = delete;
|
||||
JSObject(const JSObject& other) = delete;
|
||||
|
|
|
@ -2732,6 +2732,8 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
|||
script->toStringStart_ = toStringStart;
|
||||
script->toStringEnd_ = toStringEnd;
|
||||
|
||||
script->hideScriptFromDebugger_ = options.hideScriptFromDebugger;
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
|
||||
#endif
|
||||
|
@ -3625,6 +3627,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
|||
dst->isAsync_ = src->isAsync_;
|
||||
dst->hasRest_ = src->hasRest_;
|
||||
dst->isExprBody_ = src->isExprBody_;
|
||||
dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_;
|
||||
|
||||
if (nconsts != 0) {
|
||||
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
|
||||
|
|
|
@ -1142,6 +1142,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
bool hasRest_:1;
|
||||
bool isExprBody_:1;
|
||||
|
||||
// True if the debugger's onNewScript hook has not yet been called.
|
||||
bool hideScriptFromDebugger_:1;
|
||||
|
||||
// Add padding so JSScript is gc::Cell aligned. Make padding protected
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
protected:
|
||||
|
@ -1463,6 +1466,13 @@ class JSScript : public js::gc::TenuredCell
|
|||
isExprBody_ = true;
|
||||
}
|
||||
|
||||
bool hideScriptFromDebugger() const {
|
||||
return hideScriptFromDebugger_;
|
||||
}
|
||||
void clearHideScriptFromDebugger() {
|
||||
hideScriptFromDebugger_ = false;
|
||||
}
|
||||
|
||||
void setNeedsHomeObject() {
|
||||
needsHomeObject_ = true;
|
||||
}
|
||||
|
|
|
@ -459,6 +459,10 @@ class ObjectGroup : public gc::TenuredCell
|
|||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
|
||||
|
||||
private:
|
||||
// See JSObject::offsetOfGroup() comment.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
static inline uint32_t offsetOfClasp() {
|
||||
return offsetof(ObjectGroup, clasp_);
|
||||
}
|
||||
|
@ -479,6 +483,7 @@ class ObjectGroup : public gc::TenuredCell
|
|||
return offsetof(ObjectGroup, flags_);
|
||||
}
|
||||
|
||||
public:
|
||||
const ObjectGroupFlags* addressOfFlags() const {
|
||||
return &flags_;
|
||||
}
|
||||
|
|
|
@ -1800,12 +1800,12 @@ Shape::fixupDictionaryShapeAfterMovingGC()
|
|||
|
||||
if (listpPointsIntoShape) {
|
||||
// listp points to the parent field of the next shape.
|
||||
Shape* next = reinterpret_cast<Shape*>(uintptr_t(listp) - offsetof(Shape, parent));
|
||||
Shape* next = Shape::fromParentFieldPointer(uintptr_t(listp));
|
||||
if (gc::IsForwarded(next))
|
||||
listp = &gc::Forwarded(next)->parent;
|
||||
} else {
|
||||
// listp points to the shape_ field of an object.
|
||||
JSObject* last = reinterpret_cast<JSObject*>(uintptr_t(listp) - ShapedObject::offsetOfShape());
|
||||
JSObject* last = ShapedObject::fromShapeFieldPointer(uintptr_t(listp));
|
||||
if (gc::IsForwarded(last))
|
||||
listp = gc::Forwarded(last)->as<NativeObject>().shapePtr();
|
||||
}
|
||||
|
|
|
@ -1169,15 +1169,20 @@ class Shape : public gc::TenuredCell
|
|||
void fixupGetterSetterForBarrier(JSTracer* trc);
|
||||
void updateBaseShapeAfterMovingGC();
|
||||
|
||||
/* For JIT usage */
|
||||
static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
|
||||
#ifdef DEBUG
|
||||
// For JIT usage.
|
||||
static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); }
|
||||
static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
void fixupDictionaryShapeAfterMovingGC();
|
||||
void fixupShapeTreeAfterMovingGC();
|
||||
|
||||
static Shape* fromParentFieldPointer(uintptr_t p) {
|
||||
return reinterpret_cast<Shape*>(p - offsetof(Shape, parent));
|
||||
}
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
|
||||
JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
|
||||
|
|
|
@ -50,6 +50,14 @@ class ShapedObject : public JSObject
|
|||
TraceEdge(trc, shapePtr(), "shape");
|
||||
}
|
||||
|
||||
static JSObject* fromShapeFieldPointer(uintptr_t p) {
|
||||
return reinterpret_cast<JSObject*>(p - ShapedObject::offsetOfShape());
|
||||
}
|
||||
|
||||
private:
|
||||
// See JSObject::offsetOfGroup() comment.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
static constexpr size_t offsetOfShape() {
|
||||
static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape),
|
||||
"shadow shape must match actual shape");
|
||||
|
|
|
@ -525,7 +525,8 @@ JSRope::flattenInternal(JSContext* maybecx)
|
|||
Nursery& nursery = zone()->group()->nursery();
|
||||
if (!nursery.registerMallocedBuffer(wholeChars)) {
|
||||
js_free(wholeChars);
|
||||
ReportOutOfMemory(maybecx);
|
||||
if (maybecx)
|
||||
ReportOutOfMemory(maybecx);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,15 +87,25 @@ wasm::HasCompilerSupport(JSContext* cx)
|
|||
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
|
||||
return false;
|
||||
#else
|
||||
return BaselineCanCompile() || IonCanCompile();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return whether wasm compilation is allowed by prefs. This check
|
||||
// only makes sense if HasCompilerSupport() is true.
|
||||
static bool
|
||||
HasAvailableCompilerTier(JSContext* cx)
|
||||
{
|
||||
return (cx->options().wasmBaseline() && BaselineCanCompile()) ||
|
||||
(cx->options().wasmIon() && IonCanCompile());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::HasSupport(JSContext* cx)
|
||||
{
|
||||
return cx->options().wasm() && HasCompilerSupport(cx);
|
||||
return cx->options().wasm() &&
|
||||
HasCompilerSupport(cx) &&
|
||||
HasAvailableCompilerTier(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -12,10 +12,6 @@
|
|||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/Wrapper.h"
|
||||
|
||||
namespace JS {
|
||||
class AutoIdVector;
|
||||
} // namespace JS
|
||||
|
||||
namespace xpc {
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
|
|
|
@ -200,12 +200,6 @@ IsReversedDirectionFrame(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
#include "nsILineIterator.h"
|
||||
|
||||
//non Hack prototypes
|
||||
#if 0
|
||||
static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
|
||||
#endif
|
||||
|
||||
#include "prenv.h"
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics)
|
||||
|
|
|
@ -921,7 +921,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-003.xht css-writ
|
|||
== css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-htb-in-vlr-007-ref.xht
|
||||
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-htb-in-vlr-008-ref.xht
|
||||
fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-htb-in-vlr-008-ref.xht
|
||||
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-009.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-010.xht css-writing-modes/sizing-orthog-htb-in-vlr-010-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-011.xht css-writing-modes/sizing-orthog-htb-in-vlr-011-ref.xht
|
||||
|
@ -931,7 +931,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-015.xht css-writ
|
|||
== css-writing-modes/sizing-orthog-htb-in-vlr-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-018.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-019.xht css-writing-modes/sizing-orthog-htb-in-vlr-019-ref.xht
|
||||
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vlr-020.xht css-writing-modes/sizing-orthog-htb-in-vlr-020-ref.xht
|
||||
fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vlr-020.xht css-writing-modes/sizing-orthog-htb-in-vlr-020-ref.xht
|
||||
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vlr-021.xht css-writing-modes/sizing-orthog-htb-in-vlr-015-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-022.xht css-writing-modes/sizing-orthog-htb-in-vlr-022-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vlr-023.xht css-writing-modes/sizing-orthog-htb-in-vlr-023-ref.xht
|
||||
|
@ -941,7 +941,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-003.xht css-writ
|
|||
fails == css-writing-modes/sizing-orthog-htb-in-vrl-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-006.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-007.xht css-writing-modes/sizing-orthog-htb-in-vrl-007-ref.xht
|
||||
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vrl-008.xht css-writing-modes/sizing-orthog-htb-in-vrl-008-ref.xht
|
||||
fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vrl-008.xht css-writing-modes/sizing-orthog-htb-in-vrl-008-ref.xht
|
||||
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-009.xht css-writing-modes/sizing-orthog-htb-in-vrl-003-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-010.xht css-writing-modes/sizing-orthog-htb-in-vrl-010-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-011.xht css-writing-modes/sizing-orthog-htb-in-vrl-011-ref.xht
|
||||
|
@ -951,7 +951,7 @@ fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-015.xht css-writ
|
|||
== css-writing-modes/sizing-orthog-htb-in-vrl-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-018.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-019.xht css-writing-modes/sizing-orthog-htb-in-vrl-019-ref.xht
|
||||
fails-if(OSX||winWidget) == css-writing-modes/sizing-orthog-htb-in-vrl-020.xht css-writing-modes/sizing-orthog-htb-in-vrl-020-ref.xht
|
||||
fails-if(OSX||winWidget||Android) == css-writing-modes/sizing-orthog-htb-in-vrl-020.xht css-writing-modes/sizing-orthog-htb-in-vrl-020-ref.xht
|
||||
fails-if(Android) == css-writing-modes/sizing-orthog-htb-in-vrl-021.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-022.xht css-writing-modes/sizing-orthog-htb-in-vrl-022-ref.xht
|
||||
== css-writing-modes/sizing-orthog-htb-in-vrl-023.xht css-writing-modes/sizing-orthog-htb-in-vrl-023-ref.xht
|
||||
|
|
|
@ -139,6 +139,11 @@ public:
|
|||
aIdealSegmentSize - sizeof(Segment) < sizeof(T));
|
||||
}
|
||||
|
||||
SegmentedVector(SegmentedVector&& aOther)
|
||||
: mSegments(mozilla::Move(aOther.mSegments))
|
||||
{
|
||||
}
|
||||
|
||||
~SegmentedVector() { Clear(); }
|
||||
|
||||
bool IsEmpty() const { return !mSegments.getFirst(); }
|
||||
|
|
|
@ -3596,7 +3596,7 @@ public class BrowserApp extends GeckoApp
|
|||
super.closeOptionsMenu();
|
||||
}
|
||||
|
||||
@Override // GeckoView.ContentListener
|
||||
@Override // GeckoView.ContentDelegate
|
||||
public void onFullScreen(final GeckoSession session, final boolean fullscreen) {
|
||||
super.onFullScreen(session, fullscreen);
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
BundleEventListener,
|
||||
GeckoMenu.Callback,
|
||||
GeckoMenu.MenuPresenter,
|
||||
GeckoSession.ContentListener,
|
||||
GeckoSession.ContentDelegate,
|
||||
ScreenOrientationDelegate,
|
||||
Tabs.OnTabsChangedListener,
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
|
@ -873,19 +873,19 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
return inSampleSize;
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onTitleChange(final GeckoSession session, final String title) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onFocusRequest(final GeckoSession session) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onCloseRequest(final GeckoSession session) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onFullScreen(final GeckoSession session, final boolean fullScreen) {
|
||||
if (fullScreen) {
|
||||
SnackbarBuilder.builder(this)
|
||||
|
@ -1087,7 +1087,7 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
|
||||
session.getSettings().setString(GeckoSessionSettings.CHROME_URI,
|
||||
"chrome://browser/content/browser.xul");
|
||||
session.setContentListener(this);
|
||||
session.setContentDelegate(this);
|
||||
|
||||
GeckoAccessibility.setDelegate(mLayerView);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.mozilla.gecko.SiteIdentity;
|
|||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.toolbar.SecurityModeUtil;
|
||||
import org.mozilla.gecko.util.ColorUtil;
|
||||
import org.mozilla.geckoview.GeckoSession.ProgressListener.SecurityInformation;
|
||||
import org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation;
|
||||
import org.mozilla.geckoview.GeckoView;
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,9 +73,9 @@ import java.util.List;
|
|||
public class CustomTabsActivity extends AppCompatActivity
|
||||
implements ActionModePresenter,
|
||||
GeckoMenu.Callback,
|
||||
GeckoSession.ContentListener,
|
||||
GeckoSession.NavigationListener,
|
||||
GeckoSession.ProgressListener {
|
||||
GeckoSession.ContentDelegate,
|
||||
GeckoSession.NavigationDelegate,
|
||||
GeckoSession.ProgressDelegate {
|
||||
|
||||
private static final String LOGTAG = "CustomTabsActivity";
|
||||
|
||||
|
@ -134,9 +134,9 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
mGeckoSession = new GeckoSession();
|
||||
mGeckoView.setSession(mGeckoSession);
|
||||
|
||||
mGeckoSession.setNavigationListener(this);
|
||||
mGeckoSession.setProgressListener(this);
|
||||
mGeckoSession.setContentListener(this);
|
||||
mGeckoSession.setNavigationDelegate(this);
|
||||
mGeckoSession.setProgressDelegate(this);
|
||||
mGeckoSession.setContentDelegate(this);
|
||||
|
||||
mPromptService = new PromptService(this, mGeckoView.getEventDispatcher());
|
||||
mDoorHangerPopup = new DoorHangerPopup(this, mGeckoView.getEventDispatcher());
|
||||
|
@ -591,7 +591,7 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
return null;
|
||||
}
|
||||
|
||||
/* GeckoSession.NavigationListener */
|
||||
/* GeckoSession.NavigationDelegate */
|
||||
@Override
|
||||
public void onLocationChange(GeckoSession session, String url) {
|
||||
mCurrentUrl = url;
|
||||
|
@ -656,7 +656,7 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
throw new IllegalStateException("Unexpected new session");
|
||||
}
|
||||
|
||||
/* GeckoSession.ProgressListener */
|
||||
/* GeckoSession.ProgressDelegate */
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String url) {
|
||||
mCurrentUrl = url;
|
||||
|
@ -679,7 +679,7 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
updateActionBar();
|
||||
}
|
||||
|
||||
/* GeckoSession.ContentListener */
|
||||
/* GeckoSession.ContentDelegate */
|
||||
@Override
|
||||
public void onTitleChange(GeckoSession session, String title) {
|
||||
mCurrentTitle = title;
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.mozilla.gecko.util.ThreadUtils;
|
|||
import org.mozilla.gecko.widget.AnchoredPopup;
|
||||
import org.mozilla.gecko.widget.DoorHanger;
|
||||
import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener;
|
||||
import org.mozilla.geckoview.GeckoSession.ProgressListener.SecurityInformation;
|
||||
import org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation;
|
||||
import org.mozilla.geckoview.GeckoView;
|
||||
|
||||
import android.app.Activity;
|
||||
|
|
|
@ -53,8 +53,8 @@ import org.mozilla.geckoview.GeckoView;
|
|||
|
||||
public class WebAppActivity extends AppCompatActivity
|
||||
implements ActionModePresenter,
|
||||
GeckoSession.ContentListener,
|
||||
GeckoSession.NavigationListener {
|
||||
GeckoSession.ContentDelegate,
|
||||
GeckoSession.NavigationDelegate {
|
||||
private static final String LOGTAG = "WebAppActivity";
|
||||
|
||||
public static final String MANIFEST_PATH = "MANIFEST_PATH";
|
||||
|
@ -103,9 +103,9 @@ public class WebAppActivity extends AppCompatActivity
|
|||
mGeckoSession = new GeckoSession();
|
||||
mGeckoView.setSession(mGeckoSession);
|
||||
|
||||
mGeckoSession.setNavigationListener(this);
|
||||
mGeckoSession.setContentListener(this);
|
||||
mGeckoSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mGeckoSession.setNavigationDelegate(this);
|
||||
mGeckoSession.setContentDelegate(this);
|
||||
mGeckoSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String url) {
|
||||
|
||||
|
@ -332,36 +332,36 @@ public class WebAppActivity extends AppCompatActivity
|
|||
mGeckoView.getSettings().setInt(GeckoSessionSettings.DISPLAY_MODE, mode);
|
||||
}
|
||||
|
||||
@Override // GeckoSession.NavigationListener
|
||||
@Override // GeckoSession.NavigationDelegate
|
||||
public void onLocationChange(GeckoSession session, String url) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.NavigationListener
|
||||
@Override // GeckoSession.NavigationDelegate
|
||||
public void onCanGoBack(GeckoSession session, boolean canGoBack) {
|
||||
mCanGoBack = canGoBack;
|
||||
}
|
||||
|
||||
@Override // GeckoSession.NavigationListener
|
||||
@Override // GeckoSession.NavigationDelegate
|
||||
public void onCanGoForward(GeckoSession session, boolean canGoForward) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onTitleChange(GeckoSession session, String title) {
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onFocusRequest(GeckoSession session) {
|
||||
Intent intent = new Intent(getIntent());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onCloseRequest(GeckoSession session) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onContextMenu(GeckoSession session, int screenX, int screenY,
|
||||
String uri, String elementSrc) {
|
||||
final String content = uri != null ? uri : elementSrc != null ? elementSrc : "";
|
||||
|
@ -373,7 +373,7 @@ public class WebAppActivity extends AppCompatActivity
|
|||
WebApps.openInFennec(validUri, WebAppActivity.this);
|
||||
}
|
||||
|
||||
@Override // GeckoSession.ContentListener
|
||||
@Override // GeckoSession.ContentDelegate
|
||||
public void onFullScreen(GeckoSession session, boolean fullScreen) {
|
||||
updateFullScreenContent(fullScreen);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public class BaseGeckoViewTest {
|
|||
|
||||
protected void loadTestPage(final String url, final Runnable finished) {
|
||||
final String path = Uri.parse(url).getPath();
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String loadingUrl) {
|
||||
assertTrue("Loaded url should end with " + path, loadingUrl.endsWith(path));
|
||||
|
@ -72,7 +72,7 @@ public class BaseGeckoViewTest {
|
|||
@Override
|
||||
public void onPageStop(GeckoSession session, boolean success) {
|
||||
assertTrue("Load should succeed", success);
|
||||
mSession.setProgressListener(null);
|
||||
mSession.setProgressDelegate(null);
|
||||
finished.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ inline fun GeckoSession.loadTestPath(path: String) =
|
|||
|
||||
/**
|
||||
* Test for the GeckoSessionTestRule class, to ensure it properly sets up a session for
|
||||
* each test, and to ensure it can properly wait for and assert listener/delegate
|
||||
* each test, and to ensure it can properly wait for and assert delegate
|
||||
* callbacks.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
|
@ -75,9 +75,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test fun includesAllCallbacks() {
|
||||
for (ifce in GeckoSession::class.java.classes) {
|
||||
if (!ifce.isInterface || (
|
||||
!ifce.simpleName.endsWith("Listener") &&
|
||||
!ifce.simpleName.endsWith("Delegate"))) {
|
||||
if (!ifce.isInterface || !ifce.simpleName.endsWith("Delegate")) {
|
||||
continue
|
||||
}
|
||||
assertThat("Callbacks.All should include interface " + ifce.simpleName,
|
||||
|
@ -91,7 +89,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
counter++
|
||||
}
|
||||
|
@ -102,7 +100,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test(expected = AssertionError::class)
|
||||
fun waitForPageStop_throwOnChangedCallback() {
|
||||
sessionRule.session.progressListener = Callbacks.Default
|
||||
sessionRule.session.progressDelegate = Callbacks.Default
|
||||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
counter++
|
||||
}
|
||||
|
@ -125,11 +123,11 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test fun waitUntilCalled_anyInterfaceMethod() {
|
||||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitUntilCalled(GeckoSession.ProgressListener::class)
|
||||
sessionRule.waitUntilCalled(GeckoSession.ProgressDelegate::class)
|
||||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
}
|
||||
|
@ -139,7 +137,7 @@ class GeckoSessionTestRuleTest {
|
|||
}
|
||||
|
||||
override fun onSecurityChange(session: GeckoSession,
|
||||
securityInfo: GeckoSession.ProgressListener.SecurityInformation) {
|
||||
securityInfo: GeckoSession.ProgressDelegate.SecurityInformation) {
|
||||
counter++
|
||||
}
|
||||
})
|
||||
|
@ -149,12 +147,12 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test fun waitUntilCalled_specificInterfaceMethod() {
|
||||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitUntilCalled(GeckoSession.ProgressListener::class,
|
||||
sessionRule.waitUntilCalled(GeckoSession.ProgressDelegate::class,
|
||||
"onPageStart", "onPageStop")
|
||||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
}
|
||||
|
@ -178,7 +176,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener {
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
}
|
||||
|
@ -188,7 +186,7 @@ class GeckoSessionTestRuleTest {
|
|||
}
|
||||
|
||||
override fun onSecurityChange(session: GeckoSession,
|
||||
securityInfo: GeckoSession.ProgressListener.SecurityInformation) {
|
||||
securityInfo: GeckoSession.ProgressDelegate.SecurityInformation) {
|
||||
counter++
|
||||
}
|
||||
})
|
||||
|
@ -201,7 +199,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener {
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -222,7 +220,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener {
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -243,7 +241,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressListener {
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 2, order = intArrayOf(1, 2))
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
val info = sessionRule.currentCall
|
||||
|
@ -265,7 +263,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
counter++
|
||||
}
|
||||
|
@ -279,7 +277,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(GeckoSession.ScrollListener { _, _, _ -> })
|
||||
sessionRule.forCallbacksDuringWait(GeckoSession.ScrollDelegate { _, _, _ -> })
|
||||
}
|
||||
|
||||
@Test fun forCallbacksDuringWait_specificMethod() {
|
||||
|
@ -288,7 +286,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -310,7 +308,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -331,7 +329,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(
|
||||
GeckoSession.ScrollListener @AssertCalled { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled { _, _, _ -> })
|
||||
}
|
||||
|
||||
@Test fun forCallbacksDuringWait_specificCount() {
|
||||
|
@ -341,7 +339,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
var counter = 0
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -362,7 +360,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.reload()
|
||||
sessionRule.waitForPageStops(2)
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -377,7 +375,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(order = intArrayOf(1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -393,7 +391,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(order = intArrayOf(2))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -409,7 +407,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.reload()
|
||||
sessionRule.waitForPageStops(2)
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(order = intArrayOf(1, 3, 1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -426,7 +424,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.reload()
|
||||
sessionRule.waitForPageStops(2)
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(order = intArrayOf(1, 2, 1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -442,7 +440,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(
|
||||
GeckoSession.ScrollListener @AssertCalled(false) { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled(false) { _, _, _ -> })
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError::class)
|
||||
|
@ -450,7 +448,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(false)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
}
|
||||
|
@ -472,7 +470,7 @@ class GeckoSessionTestRuleTest {
|
|||
var counter = 0
|
||||
|
||||
// assert should only apply to callbacks within range (loadUri, first reload].
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -491,7 +489,7 @@ class GeckoSessionTestRuleTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
val info = sessionRule.currentCall
|
||||
|
@ -512,7 +510,7 @@ class GeckoSessionTestRuleTest {
|
|||
@Test fun delegateUntilTestEnd() {
|
||||
var counter = 0
|
||||
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -532,19 +530,19 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test fun delegateUntilTestEnd_notCalled() {
|
||||
sessionRule.delegateUntilTestEnd(
|
||||
GeckoSession.ScrollListener @AssertCalled(false) { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled(false) { _, _, _ -> })
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError::class)
|
||||
fun delegateUntilTestEnd_throwOnNotCalled() {
|
||||
sessionRule.delegateUntilTestEnd(
|
||||
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
|
||||
sessionRule.performTestEndCheck()
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError::class)
|
||||
fun delegateUntilTestEnd_throwOnCallingNoCall() {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(false)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
}
|
||||
|
@ -556,7 +554,7 @@ class GeckoSessionTestRuleTest {
|
|||
|
||||
@Test(expected = AssertionError::class)
|
||||
fun delegateUntilTestEnd_throwOnWrongOrder() {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(2))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
}
|
||||
|
@ -571,7 +569,7 @@ class GeckoSessionTestRuleTest {
|
|||
}
|
||||
|
||||
@Test fun delegateUntilTestEnd_currentCall() {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
val info = sessionRule.currentCall
|
||||
|
@ -590,7 +588,7 @@ class GeckoSessionTestRuleTest {
|
|||
@Test fun delegateDuringNextWait() {
|
||||
var counter = 0
|
||||
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
counter++
|
||||
|
@ -616,7 +614,7 @@ class GeckoSessionTestRuleTest {
|
|||
@Test(expected = AssertionError::class)
|
||||
fun delegateDuringNextWait_throwOnNotCalled() {
|
||||
sessionRule.delegateDuringNextWait(
|
||||
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
|
||||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
}
|
||||
|
@ -624,7 +622,7 @@ class GeckoSessionTestRuleTest {
|
|||
@Test(expected = AssertionError::class)
|
||||
fun delegateDuringNextWait_throwOnNotCalledAtTestEnd() {
|
||||
sessionRule.delegateDuringNextWait(
|
||||
GeckoSession.ScrollListener @AssertCalled(count = 1) { _, _, _ -> })
|
||||
GeckoSession.ScrollDelegate @AssertCalled(count = 1) { _, _, _ -> })
|
||||
sessionRule.performTestEndCheck()
|
||||
}
|
||||
|
||||
|
@ -632,8 +630,8 @@ class GeckoSessionTestRuleTest {
|
|||
var testCounter = 0
|
||||
var waitCounter = 0
|
||||
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressListener,
|
||||
Callbacks.NavigationListener {
|
||||
sessionRule.delegateUntilTestEnd(object : Callbacks.ProgressDelegate,
|
||||
Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(2))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
testCounter++
|
||||
|
@ -655,7 +653,7 @@ class GeckoSessionTestRuleTest {
|
|||
}
|
||||
})
|
||||
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
waitCounter++
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.junit.runner.RunWith
|
|||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class NavigationListenerTest {
|
||||
class NavigationDelegateTest {
|
||||
companion object {
|
||||
const val HELLO_HTML_PATH = "/assets/www/hello.html";
|
||||
const val HELLO2_HTML_PATH = "/assets/www/hello2.html";
|
||||
|
@ -39,16 +39,16 @@ class NavigationListenerTest {
|
|||
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onLoadUri(session: GeckoSession, uri: String,
|
||||
where: GeckoSession.NavigationListener.TargetWindow): Boolean {
|
||||
where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
|
||||
assertThat("Session should not be null", session, notNullValue())
|
||||
assertThat("URI should not be null", uri, notNullValue())
|
||||
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
|
||||
assertThat("Where should not be null", where, notNullValue())
|
||||
assertThat("Where should match", where,
|
||||
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT))
|
||||
equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -85,13 +85,13 @@ class NavigationListenerTest {
|
|||
sessionRule.session.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onLoadUri(session: GeckoSession, uri: String,
|
||||
where: GeckoSession.NavigationListener.TargetWindow): Boolean {
|
||||
where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
|
||||
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
|
||||
assertThat("Where should match", where,
|
||||
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT))
|
||||
equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ class NavigationListenerTest {
|
|||
sessionRule.session.loadTestPath(HELLO2_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onLocationChange(session: GeckoSession, url: String) {
|
||||
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))
|
||||
|
@ -134,13 +134,13 @@ class NavigationListenerTest {
|
|||
sessionRule.session.goBack()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onLoadUri(session: GeckoSession, uri: String,
|
||||
where: GeckoSession.NavigationListener.TargetWindow): Boolean {
|
||||
where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
|
||||
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
|
||||
assertThat("Where should match", where,
|
||||
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT))
|
||||
equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -168,13 +168,13 @@ class NavigationListenerTest {
|
|||
sessionRule.session.goForward()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onLoadUri(session: GeckoSession, uri: String,
|
||||
where: GeckoSession.NavigationListener.TargetWindow): Boolean {
|
||||
where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
|
||||
assertThat("URI should match", uri, endsWith(HELLO2_HTML_PATH))
|
||||
assertThat("Where should match", where,
|
||||
equalTo(GeckoSession.NavigationListener.TargetWindow.CURRENT))
|
||||
equalTo(GeckoSession.NavigationDelegate.TargetWindow.CURRENT))
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -201,10 +201,10 @@ class NavigationListenerTest {
|
|||
}
|
||||
|
||||
@Test fun onLoadUri_returnTrueCancelsLoad() {
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationListener {
|
||||
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onLoadUri(session: GeckoSession, uri: String,
|
||||
where: GeckoSession.NavigationListener.TargetWindow): Boolean {
|
||||
where: GeckoSession.NavigationDelegate.TargetWindow): Boolean {
|
||||
return uri.endsWith(HELLO_HTML_PATH)
|
||||
}
|
||||
})
|
||||
|
@ -213,7 +213,7 @@ class NavigationListenerTest {
|
|||
sessionRule.session.loadTestPath(HELLO2_HTML_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressListener {
|
||||
sessionRule.forCallbacksDuringWait(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1, order = intArrayOf(1))
|
||||
override fun onPageStart(session: GeckoSession, url: String) {
|
||||
assertThat("URL should match", url, endsWith(HELLO2_HTML_PATH))
|
||||
|
|
|
@ -37,7 +37,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
@Override public void run() {
|
||||
loadTestPath("hello2.html", new Runnable() {
|
||||
@Override public void run() {
|
||||
mSession.setNavigationListener(new GeckoSession.NavigationListener() {
|
||||
mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
|
||||
@Override
|
||||
public void onLocationChange(GeckoSession session, String url) {
|
||||
assertTrue("URL should end with " + startPath + ", got " + url, url.endsWith(startPath));
|
||||
|
@ -78,7 +78,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
public void testReload() {
|
||||
loadTestPath("hello.html", new Runnable() {
|
||||
@Override public void run() {
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String url) {
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
|
||||
@Test
|
||||
public void testExpiredCert() {
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
private boolean mNotBlank;
|
||||
|
||||
@Override
|
||||
|
@ -133,7 +133,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
|
||||
@Test
|
||||
public void testValidTLS() {
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
private boolean mNotBlank;
|
||||
|
||||
@Override
|
||||
|
@ -162,7 +162,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
|
||||
@Test
|
||||
public void testOnNewSession() {
|
||||
mSession.setNavigationListener(new GeckoSession.NavigationListener() {
|
||||
mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
|
||||
@Override
|
||||
public void onLocationChange(GeckoSession session, String url) {
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
@Override
|
||||
public void onNewSession(GeckoSession session, String uri, GeckoSession.Response<GeckoSession> response) {
|
||||
final GeckoSession newSession = new GeckoSession(session.getSettings());
|
||||
newSession.setContentListener(new GeckoSession.ContentListener() {
|
||||
newSession.setContentDelegate(new GeckoSession.ContentDelegate() {
|
||||
@Override
|
||||
public void onTitleChange(GeckoSession session, String title) {
|
||||
|
||||
|
@ -218,7 +218,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
}
|
||||
});
|
||||
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String url) {
|
||||
|
||||
|
@ -245,10 +245,10 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testOnNewSessionNoExisting() {
|
||||
// This makes sure that we get an exception if you try to return
|
||||
// an existing GeckoSession instance from the NavigationListener.onNewSession()
|
||||
// an existing GeckoSession instance from the NavigationDelegate.onNewSession()
|
||||
// implementation.
|
||||
|
||||
mSession.setNavigationListener(new GeckoSession.NavigationListener() {
|
||||
mSession.setNavigationDelegate(new GeckoSession.NavigationDelegate() {
|
||||
@Override
|
||||
public void onLocationChange(GeckoSession session, String url) {
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ public class NavigationTests extends BaseGeckoViewTest {
|
|||
}
|
||||
});
|
||||
|
||||
mSession.setProgressListener(new GeckoSession.ProgressListener() {
|
||||
mSession.setProgressDelegate(new GeckoSession.ProgressDelegate() {
|
||||
@Override
|
||||
public void onPageStart(GeckoSession session, String url) {
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче