зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
e06ba10d0b
|
@ -107,7 +107,7 @@
|
|||
is(anode, node.accessibleNode, "an AccessibleNode is properly cached");
|
||||
|
||||
// Adopting node to another document doesn't change .accessibleNode
|
||||
anotherDoc = document.implementation.createDocument("", "", null);
|
||||
let anotherDoc = document.implementation.createDocument("", "", null);
|
||||
let adopted_node = anotherDoc.adoptNode(node);
|
||||
is(anode, adopted_node.accessibleNode, "adopting node to another document doesn't change node.accessibleNode");
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ exports.ORDERED_PROPS = [
|
|||
"value",
|
||||
"DOMNode",
|
||||
"description",
|
||||
"help",
|
||||
"keyboardShortcut",
|
||||
"childCount",
|
||||
"indexInParent",
|
||||
|
@ -52,7 +51,6 @@ exports.ACCESSIBLE_EVENTS = [
|
|||
"actions-change",
|
||||
"attributes-change",
|
||||
"description-change",
|
||||
"help-change",
|
||||
"name-change",
|
||||
"reorder",
|
||||
"shortcut-change",
|
||||
|
|
|
@ -4,6 +4,8 @@ subsuite = devtools
|
|||
support-files =
|
||||
head.js
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/test-actor.js
|
||||
!/devtools/client/shared/test/test-actor-registry.js
|
||||
!/devtools/client/inspector/test/shared-head.js
|
||||
!/devtools/client/shared/test/shared-redux-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
|
|
|
@ -50,7 +50,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
indexInParent: 1,
|
||||
|
|
|
@ -29,7 +29,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 0,
|
||||
indexInParent: 0,
|
||||
|
|
|
@ -36,7 +36,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 2,
|
||||
indexInParent: 0,
|
||||
|
@ -81,7 +80,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
indexInParent: 0,
|
||||
|
@ -98,7 +96,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 0,
|
||||
indexInParent: 0,
|
||||
|
@ -119,7 +116,6 @@ const tests = [{
|
|||
actions: [],
|
||||
value: "",
|
||||
description: "",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 2,
|
||||
indexInParent: 0,
|
||||
|
|
|
@ -54,6 +54,7 @@ const PORTRAIT_MODE_WIDTH_THRESHOLD = 700;
|
|||
// mode.
|
||||
const SIDE_PORTAIT_MODE_WIDTH_THRESHOLD = 1000;
|
||||
|
||||
const THREE_PANE_FIRST_RUN_PREF = "devtools.inspector.three-pane-first-run";
|
||||
const SHOW_THREE_PANE_ONBOARDING_PREF = "devtools.inspector.show-three-pane-tooltip";
|
||||
const THREE_PANE_ENABLED_PREF = "devtools.inspector.three-pane-enabled";
|
||||
const THREE_PANE_ENABLED_SCALAR = "devtools.inspector.three_pane_enabled";
|
||||
|
@ -120,6 +121,7 @@ function Inspector(toolbox) {
|
|||
this.previousURL = this.target.url;
|
||||
|
||||
this.is3PaneModeEnabled = Services.prefs.getBoolPref(THREE_PANE_ENABLED_PREF);
|
||||
this.is3PaneModeFirstRun = Services.prefs.getBoolPref(THREE_PANE_FIRST_RUN_PREF);
|
||||
this.show3PaneTooltip = Services.prefs.getBoolPref(SHOW_THREE_PANE_ONBOARDING_PREF);
|
||||
|
||||
this.nodeMenuTriggerInfo = null;
|
||||
|
@ -250,6 +252,14 @@ Inspector.prototype = {
|
|||
this._updateDebuggerPausedWarning();
|
||||
}
|
||||
|
||||
// Resets the inspector sidebar widths if this is the first run of the 3 pane mode.
|
||||
if (this.is3PaneModeFirstRun) {
|
||||
Services.prefs.clearUserPref("devtools.toolsidebar-width.inspector");
|
||||
Services.prefs.clearUserPref("devtools.toolsidebar-height.inspector");
|
||||
Services.prefs.clearUserPref("devtools.toolsidebar-width.inspector.splitsidebar");
|
||||
Services.prefs.setBoolPref(THREE_PANE_FIRST_RUN_PREF, false);
|
||||
}
|
||||
|
||||
this._initMarkup();
|
||||
this.isReady = false;
|
||||
|
||||
|
@ -1396,6 +1406,7 @@ Inspector.prototype = {
|
|||
this._toolbox = null;
|
||||
this.breadcrumbs = null;
|
||||
this.is3PaneModeEnabled = null;
|
||||
this.is3PaneModeFirstRun = null;
|
||||
this.panelDoc = null;
|
||||
this.panelWin.inspector = null;
|
||||
this.panelWin = null;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
@ -8,31 +6,31 @@
|
|||
|
||||
const promise = require("promise");
|
||||
const Rule = require("devtools/client/inspector/rules/models/rule");
|
||||
const {promiseWarn} = require("devtools/client/inspector/shared/utils");
|
||||
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
|
||||
const {getCssProperties, isCssVariable} = require("devtools/shared/fronts/css-properties");
|
||||
const UserProperties = require("devtools/client/inspector/rules/models/user-properties");
|
||||
const { promiseWarn } = require("devtools/client/inspector/shared/utils");
|
||||
const { getCssProperties, isCssVariable } = require("devtools/shared/fronts/css-properties");
|
||||
const { ELEMENT_STYLE } = require("devtools/shared/specs/styles");
|
||||
|
||||
/**
|
||||
* ElementStyle is responsible for the following:
|
||||
* Keeps track of which properties are overridden.
|
||||
* Maintains a list of Rule objects for a given element.
|
||||
*
|
||||
* @param {Element} element
|
||||
* The element whose style we are viewing.
|
||||
* @param {CssRuleView} ruleView
|
||||
* The instance of the rule-view panel.
|
||||
* @param {Object} store
|
||||
* The ElementStyle can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
* @param {PageStyleFront} pageStyle
|
||||
* Front for the page style actor that will be providing
|
||||
* the style information.
|
||||
* @param {Boolean} showUserAgentStyles
|
||||
* Should user agent styles be inspected?
|
||||
* @param {Element} element
|
||||
* The element whose style we are viewing.
|
||||
* @param {CssRuleView} ruleView
|
||||
* The instance of the rule-view panel.
|
||||
* @param {Object} store
|
||||
* The ElementStyle can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
* @param {PageStyleFront} pageStyle
|
||||
* Front for the page style actor that will be providing
|
||||
* the style information.
|
||||
* @param {Boolean} showUserAgentStyles
|
||||
* Should user agent styles be inspected?
|
||||
*/
|
||||
function ElementStyle(element, ruleView, store, pageStyle,
|
||||
showUserAgentStyles) {
|
||||
function ElementStyle(element, ruleView, store, pageStyle, showUserAgentStyles) {
|
||||
this.element = element;
|
||||
this.ruleView = ruleView;
|
||||
this.store = store || {};
|
||||
|
@ -54,13 +52,11 @@ function ElementStyle(element, ruleView, store, pageStyle,
|
|||
}
|
||||
|
||||
ElementStyle.prototype = {
|
||||
// The element we're looking at.
|
||||
element: null,
|
||||
|
||||
destroy: function() {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
|
||||
for (const rule of this.rules) {
|
||||
|
@ -93,17 +89,12 @@ ElementStyle.prototype = {
|
|||
matchedSelectors: true,
|
||||
filter: this.showUserAgentStyles ? "ua" : undefined,
|
||||
}).then(entries => {
|
||||
if (this.destroyed) {
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (this.populated !== populated) {
|
||||
// Don't care anymore.
|
||||
if (this.destroyed || this.populated !== populated) {
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Store the current list of rules (if any) during the population
|
||||
// process. They will be reused if possible.
|
||||
// process. They will be reused if possible.
|
||||
const existingRules = this.rules;
|
||||
|
||||
this.rules = [];
|
||||
|
@ -141,7 +132,7 @@ ElementStyle.prototype = {
|
|||
* Get the font families in use by the element.
|
||||
*
|
||||
* Returns a promise that will be resolved to a list of CSS family
|
||||
* names. The list might have duplicates.
|
||||
* names. The list might have duplicates.
|
||||
*/
|
||||
getUsedFontFamilies: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -167,25 +158,21 @@ ElementStyle.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Add a rule if it's one we care about. Filters out duplicates and
|
||||
* Add a rule if it's one we care about. Filters out duplicates and
|
||||
* inherited styles with no inherited properties.
|
||||
*
|
||||
* @param {Object} options
|
||||
* Options for creating the Rule, see the Rule constructor.
|
||||
* @param {Array} existingRules
|
||||
* Rules to reuse if possible. If a rule is reused, then it
|
||||
* it will be deleted from this array.
|
||||
* @param {Object} options
|
||||
* Options for creating the Rule, see the Rule constructor.
|
||||
* @param {Array} existingRules
|
||||
* Rules to reuse if possible. If a rule is reused, then it
|
||||
* it will be deleted from this array.
|
||||
* @return {Boolean} true if we added the rule.
|
||||
*/
|
||||
_maybeAddRule: function(options, existingRules) {
|
||||
// If we've already included this domRule (for example, when a
|
||||
// common selector is inherited), ignore it.
|
||||
if (options.rule &&
|
||||
this.rules.some(rule => rule.domRule === options.rule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.system) {
|
||||
if (options.system ||
|
||||
(options.rule && this.rules.some(rule => rule.domRule === options.rule))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -232,9 +219,9 @@ ElementStyle.prototype = {
|
|||
* Mark the properties listed in this.rules for a given pseudo element
|
||||
* with an overridden flag if an earlier property overrides it.
|
||||
*
|
||||
* @param {String} pseudo
|
||||
* Which pseudo element to flag as overridden.
|
||||
* Empty string or undefined will default to no pseudo element.
|
||||
* @param {String} pseudo
|
||||
* Which pseudo element to flag as overridden.
|
||||
* Empty string or undefined will default to no pseudo element.
|
||||
*/
|
||||
markOverridden: function(pseudo = "") {
|
||||
// Gather all the text properties applied by these rules, ordered
|
||||
|
@ -262,7 +249,7 @@ ElementStyle.prototype = {
|
|||
computedProps = computedProps.concat(textProp.computed);
|
||||
}
|
||||
|
||||
// Walk over the computed properties. As we see a property name
|
||||
// Walk over the computed properties. As we see a property name
|
||||
// for the first time, mark that property's name as taken by this
|
||||
// property.
|
||||
//
|
||||
|
@ -291,13 +278,14 @@ ElementStyle.prototype = {
|
|||
computedProp.overridden = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
let overridden;
|
||||
if (earlier &&
|
||||
computedProp.priority === "important" &&
|
||||
earlier.priority !== "important" &&
|
||||
(earlier.textProp.rule.inherited ||
|
||||
!computedProp.textProp.rule.inherited)) {
|
||||
// New property is higher priority. Mark the earlier property
|
||||
// New property is higher priority. Mark the earlier property
|
||||
// overridden (which will reverse its dirty state).
|
||||
earlier._overriddenDirty = !earlier._overriddenDirty;
|
||||
earlier.overridden = true;
|
||||
|
@ -309,6 +297,7 @@ ElementStyle.prototype = {
|
|||
computedProp._overriddenDirty =
|
||||
(!!computedProp.overridden !== overridden);
|
||||
computedProp.overridden = overridden;
|
||||
|
||||
if (!computedProp.overridden && computedProp.textProp.enabled) {
|
||||
taken[computedProp.name] = computedProp;
|
||||
|
||||
|
@ -319,8 +308,8 @@ ElementStyle.prototype = {
|
|||
}
|
||||
|
||||
// For each TextProperty, mark it overridden if all of its
|
||||
// computed properties are marked overridden. Update the text
|
||||
// property's associated editor, if any. This will clear the
|
||||
// computed properties are marked overridden. Update the text
|
||||
// property's associated editor, if any. This will clear the
|
||||
// _overriddenDirty state on all computed properties.
|
||||
for (const textProp of textProps) {
|
||||
// _updatePropertyOverridden will return true if the
|
||||
|
@ -333,21 +322,23 @@ ElementStyle.prototype = {
|
|||
|
||||
/**
|
||||
* Mark a given TextProperty as overridden or not depending on the
|
||||
* state of its computed properties. Clears the _overriddenDirty state
|
||||
* state of its computed properties. Clears the _overriddenDirty state
|
||||
* on all computed properties.
|
||||
*
|
||||
* @param {TextProperty} prop
|
||||
* The text property to update.
|
||||
* @param {TextProperty} prop
|
||||
* The text property to update.
|
||||
* @return {Boolean} true if the TextProperty's overridden state (or any of
|
||||
* its computed properties overridden state) changed.
|
||||
*/
|
||||
_updatePropertyOverridden: function(prop) {
|
||||
let overridden = true;
|
||||
let dirty = false;
|
||||
|
||||
for (const computedProp of prop.computed) {
|
||||
if (!computedProp.overridden) {
|
||||
overridden = false;
|
||||
}
|
||||
|
||||
dirty = computedProp._overriddenDirty || dirty;
|
||||
delete computedProp._overriddenDirty;
|
||||
}
|
||||
|
@ -371,82 +362,4 @@ ElementStyle.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Store of CSSStyleDeclarations mapped to properties that have been changed by
|
||||
* the user.
|
||||
*/
|
||||
function UserProperties() {
|
||||
this.map = new Map();
|
||||
}
|
||||
|
||||
UserProperties.prototype = {
|
||||
/**
|
||||
* Get a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property is mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to get.
|
||||
* @param {String} value
|
||||
* Default value.
|
||||
* @return {String}
|
||||
* The property value if it has previously been set by the user, null
|
||||
* otherwise.
|
||||
*/
|
||||
getProperty: function(style, name, value) {
|
||||
const key = this.getKey(style);
|
||||
const entry = this.map.get(key, null);
|
||||
|
||||
if (entry && name in entry) {
|
||||
return entry[name];
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property is to be mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to set.
|
||||
* @param {String} userValue
|
||||
* The value of the property to set.
|
||||
*/
|
||||
setProperty: function(style, name, userValue) {
|
||||
const key = this.getKey(style, name);
|
||||
const entry = this.map.get(key, null);
|
||||
|
||||
if (entry) {
|
||||
entry[name] = userValue;
|
||||
} else {
|
||||
const props = {};
|
||||
props[name] = userValue;
|
||||
this.map.set(key, props);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether a named property for a given CSSStyleDeclaration is stored.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property would be mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to check.
|
||||
*/
|
||||
contains: function(style, name) {
|
||||
const key = this.getKey(style, name);
|
||||
const entry = this.map.get(key, null);
|
||||
return !!entry && name in entry;
|
||||
},
|
||||
|
||||
getKey: function(style, name) {
|
||||
return style.actorID + ":" + name;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this.map.clear();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ElementStyle;
|
||||
|
|
|
@ -8,4 +8,5 @@ DevToolsModules(
|
|||
'element-style.js',
|
||||
'rule.js',
|
||||
'text-property.js',
|
||||
'user-properties.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* 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";
|
||||
|
||||
/**
|
||||
* Store of CSSStyleDeclarations mapped to properties that have been changed by
|
||||
* the user.
|
||||
*/
|
||||
function UserProperties() {
|
||||
this.map = new Map();
|
||||
}
|
||||
|
||||
UserProperties.prototype = {
|
||||
/**
|
||||
* Get a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property is mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to get.
|
||||
* @param {String} value
|
||||
* Default value.
|
||||
* @return {String}
|
||||
* The property value if it has previously been set by the user, null
|
||||
* otherwise.
|
||||
*/
|
||||
getProperty: function(style, name, value) {
|
||||
const key = this.getKey(style);
|
||||
const entry = this.map.get(key, null);
|
||||
|
||||
if (entry && name in entry) {
|
||||
return entry[name];
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property is to be mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to set.
|
||||
* @param {String} userValue
|
||||
* The value of the property to set.
|
||||
*/
|
||||
setProperty: function(style, name, userValue) {
|
||||
const key = this.getKey(style, name);
|
||||
const entry = this.map.get(key, null);
|
||||
|
||||
if (entry) {
|
||||
entry[name] = userValue;
|
||||
} else {
|
||||
const props = {};
|
||||
props[name] = userValue;
|
||||
this.map.set(key, props);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether a named property for a given CSSStyleDeclaration is stored.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} style
|
||||
* The CSSStyleDeclaration against which the property would be mapped.
|
||||
* @param {String} name
|
||||
* The name of the property to check.
|
||||
*/
|
||||
contains: function(style, name) {
|
||||
const key = this.getKey(style, name);
|
||||
const entry = this.map.get(key, null);
|
||||
return !!entry && name in entry;
|
||||
},
|
||||
|
||||
getKey: function(style, name) {
|
||||
return style.actorID + ":" + name;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this.map.clear();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = UserProperties;
|
|
@ -215,6 +215,8 @@ devtools.jar:
|
|||
skin/images/tool-application.svg (themes/images/tool-application.svg)
|
||||
skin/images/close.svg (themes/images/close.svg)
|
||||
skin/images/clear.svg (themes/images/clear.svg)
|
||||
skin/images/close-3-pane.svg (themes/images/close-3-pane.svg)
|
||||
skin/images/open-3-pane.svg (themes/images/open-3-pane.svg)
|
||||
skin/images/vview-delete.png (themes/images/vview-delete.png)
|
||||
skin/images/vview-delete@2x.png (themes/images/vview-delete@2x.png)
|
||||
skin/images/vview-edit.png (themes/images/vview-edit.png)
|
||||
|
|
|
@ -44,7 +44,9 @@ pref("devtools.inspector.show-three-pane-tooltip", false);
|
|||
#endif
|
||||
// Enable the 3 pane mode in the inspector
|
||||
pref("devtools.inspector.three-pane-enabled", true);
|
||||
|
||||
// Whether or not this is the first run of the 3 pane mode. Used to reset the default
|
||||
// inspector sidebar widths for its first run.
|
||||
pref("devtools.inspector.three-pane-first-run", true);
|
||||
// Collapse pseudo-elements by default in the rule-view
|
||||
pref("devtools.inspector.show_pseudo_elements", false);
|
||||
// The default size for image preview tooltips in the rule-view/computed-view/markup-view
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="context-fill #0b0b0b">
|
||||
<rect width="3" height="10" x="11" y="3" fill-opacity=".2"/>
|
||||
<path d="M2,3.00247329 L2,3.00247329 L2,12.9975267 C2,12.9944441 2.00555363,13 2.00684547,13 L13.9931545,13 C13.9983241,13 14,12.9983304 14,12.9975267 L14,3.00247329 C14,3.00555595 13.9944464,3 13.9931545,3 L2.00684547,3 C2.00167589,3 2,3.00166957 2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 Z M1,3.00247329 C1,2.44882258 1.44994876,2 2.00684547,2 L13.9931545,2 C14.5492199,2 15,2.45576096 15,3.00247329 L15,12.9975267 C15,13.5511774 14.5500512,14 13.9931545,14 L2.00684547,14 C1.45078007,14 1,13.544239 1,12.9975267 L1,3.00247329 Z M10,3.45454545 L10,12.5454545 L10,13 L11,13 L11,12.5454545 L11,3.45454545 L11,3 L10,3 L10,3.45454545 Z"/>
|
||||
<polygon points="4 10.75 4 6 8.5 8.375"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,10 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="context-fill #0b0b0b">
|
||||
<rect width="5" height="10" x="10" y="3" fill-opacity=".2"/>
|
||||
<path d="M2,3.00247329 L2,3.00247329 L2,12.9975267 C2,12.9944441 2.00601643,13 2.00741593,13 L14.9925841,13 C14.9981844,13 15,12.9983304 15,12.9975267 L15,3.00247329 C15,3.00555595 14.9939836,3 14.9925841,3 L2.00741593,3 C2.00181555,3 2,3.00166957 2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 L2,3.00247329 Z M2.07876301,2 L14.921237,2 C15.5170213,2 16,2.45576096 16,3.00247329 L16,12.9975267 C16,13.5511774 15.517912,14 14.921237,14 L2.07876301,14 C1.48297865,14 1,13.544239 1,12.9975267 L1,3.00247329 C1,2.44882258 1.48208795,2 2.07876301,2 Z M12,12.5454545 L12,13 L13,13 L13,12.5454545 L13,3.45454545 L13,3 L12,3 L12,3.45454545 L12,12.5454545 Z M9,3.45454545 L9,12.5454545 L9,13 L10,13 L10,12.5454545 L10,3.45454545 L10,3 L9,3 L9,3.45454545 Z"/>
|
||||
<polygon points="3 10.75 3 6 7.5 8.375" transform="rotate(-180 5.25 8.375)"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -64,9 +64,14 @@ window {
|
|||
}
|
||||
|
||||
#inspector-splitter-box .sidebar-toggle::before {
|
||||
background-image: url("chrome://devtools/skin/images/close-3-pane.svg");
|
||||
transform: unset;
|
||||
}
|
||||
|
||||
#inspector-splitter-box .sidebar-toggle.pane-collapsed::before {
|
||||
background-image: url("chrome://devtools/skin/images/open-3-pane.svg");
|
||||
}
|
||||
|
||||
/* Use flex layout for the Inspector toolbar. For now, it's done
|
||||
specifically for the Inspector toolbar since general rule applied
|
||||
on .devtools-toolbar breaks breadcrumbs and also toolbars in other
|
||||
|
|
|
@ -37,7 +37,6 @@ const {
|
|||
EVENT_DEFACTION_CHANGE,
|
||||
EVENT_DESCRIPTION_CHANGE,
|
||||
EVENT_DOCUMENT_ATTRIBUTES_CHANGED,
|
||||
EVENT_HELP_CHANGE,
|
||||
EVENT_HIDE,
|
||||
EVENT_NAME_CHANGE,
|
||||
EVENT_OBJECT_ATTRIBUTE_CHANGED,
|
||||
|
@ -234,18 +233,16 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
|
|||
return this.rawAccessible.description;
|
||||
},
|
||||
|
||||
get help() {
|
||||
if (this.isDefunct) {
|
||||
return null;
|
||||
}
|
||||
return this.rawAccessible.help;
|
||||
},
|
||||
|
||||
get keyboardShortcut() {
|
||||
if (this.isDefunct) {
|
||||
return null;
|
||||
}
|
||||
return this.rawAccessible.keyboardShortcut;
|
||||
// Gecko accessibility exposes two key bindings: Accessible::AccessKey and
|
||||
// Accessible::KeyboardShortcut. The former is used for accesskey, where the latter
|
||||
// is used for global shortcuts defined by XUL menu items, etc. Here - do what the
|
||||
// Windows implementation does: try AccessKey first, and if that's empty, use
|
||||
// KeyboardShortcut.
|
||||
return this.rawAccessible.accessKey || this.rawAccessible.keyboardShortcut;
|
||||
},
|
||||
|
||||
get childCount() {
|
||||
|
@ -361,7 +358,6 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
|
|||
name: this.name,
|
||||
value: this.value,
|
||||
description: this.description,
|
||||
help: this.help,
|
||||
keyboardShortcut: this.keyboardShortcut,
|
||||
childCount: this.childCount,
|
||||
domNodeType: this.domNodeType,
|
||||
|
@ -644,11 +640,6 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
|||
events.emit(accessible, "description-change", rawAccessible.description);
|
||||
}
|
||||
break;
|
||||
case EVENT_HELP_CHANGE:
|
||||
if (accessible) {
|
||||
events.emit(accessible, "help-change", rawAccessible.help);
|
||||
}
|
||||
break;
|
||||
case EVENT_REORDER:
|
||||
if (accessible) {
|
||||
accessible.children().forEach(child =>
|
||||
|
@ -684,9 +675,10 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
|||
events.emit(accessible, "attributes-change", accessible.attributes);
|
||||
}
|
||||
break;
|
||||
// EVENT_ACCELERATOR_CHANGE is currently not fired by gecko accessibility.
|
||||
case EVENT_ACCELERATOR_CHANGE:
|
||||
if (accessible) {
|
||||
events.emit(accessible, "shortcut-change", rawAccessible.keyboardShortcut);
|
||||
events.emit(accessible, "shortcut-change", accessible.keyboardShortcut);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
add_task(async function() {
|
||||
const {client, walker, accessibility} =
|
||||
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
|
||||
const modifiers = Services.appinfo.OS === "Darwin" ? "\u2303\u2325" : "Alt+Shift+";
|
||||
|
||||
const a11yWalker = await accessibility.getWalker();
|
||||
await accessibility.enable();
|
||||
|
@ -20,8 +21,7 @@ add_task(async function() {
|
|||
role: "pushbutton",
|
||||
value: "",
|
||||
description: "Accessibility Test",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
keyboardShortcut: modifiers + "b",
|
||||
childCount: 1,
|
||||
domNodeType: 1,
|
||||
indexInParent: 1,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
add_task(async function() {
|
||||
const {client, walker, accessibility} =
|
||||
await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
|
||||
const modifiers = Services.appinfo.OS === "Darwin" ? "\u2303\u2325" : "Alt+Shift+";
|
||||
|
||||
const a11yWalker = await accessibility.getWalker();
|
||||
await accessibility.enable();
|
||||
|
@ -25,8 +26,7 @@ add_task(async function() {
|
|||
role: "pushbutton",
|
||||
value: "",
|
||||
description: "Accessibility Test",
|
||||
help: "",
|
||||
keyboardShortcut: "",
|
||||
keyboardShortcut: modifiers + "b",
|
||||
childCount: 1,
|
||||
domNodeType: 1,
|
||||
indexInParent: 1,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<h1 id="h1">Accessibility Test</h1>
|
||||
<button id="button" aria-describedby="h1">Accessible Button</button>
|
||||
<button id="button" aria-describedby="h1" accesskey="b">Accessible Button</button>
|
||||
<div id="slider" role="slider" aria-valuenow="5"
|
||||
aria-valuemin="0" aria-valuemax="7">slider</div>
|
||||
</body>
|
||||
|
|
|
@ -41,10 +41,6 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
|
|||
return this._form.description;
|
||||
},
|
||||
|
||||
get help() {
|
||||
return this._form.help;
|
||||
},
|
||||
|
||||
get keyboardShortcut() {
|
||||
return this._form.keyboardShortcut;
|
||||
},
|
||||
|
@ -100,10 +96,6 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
|
|||
this._form.description = description;
|
||||
}),
|
||||
|
||||
helpChange: preEvent("help-change", function(help) {
|
||||
this._form.help = help;
|
||||
}),
|
||||
|
||||
shortcutChange: preEvent("shortcut-change", function(keyboardShortcut) {
|
||||
this._form.keyboardShortcut = keyboardShortcut;
|
||||
}),
|
||||
|
|
|
@ -50,10 +50,6 @@ const accessibleSpec = generateActorSpec({
|
|||
type: "attributesChange",
|
||||
attributes: Arg(0, "json")
|
||||
},
|
||||
"help-change": {
|
||||
type: "helpChange",
|
||||
help: Arg(0, "string")
|
||||
},
|
||||
"shortcut-change": {
|
||||
type: "shortcutChange",
|
||||
shortcut: Arg(0, "string")
|
||||
|
|
|
@ -228,7 +228,9 @@ AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
|
|||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> cs =
|
||||
new nsComputedDOMStyle(element, NS_LITERAL_STRING(""), shell,
|
||||
new nsComputedDOMStyle(element,
|
||||
NS_LITERAL_STRING(""),
|
||||
element->OwnerDoc(),
|
||||
nsComputedDOMStyle::eAll);
|
||||
aRv = cs->GetPropertyValue(aPropertyName, aResult);
|
||||
}
|
||||
|
|
|
@ -289,18 +289,6 @@ Attr::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Attr::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
Attr::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Attr::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -63,9 +63,6 @@ public:
|
|||
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
|
||||
bool aPreallocateChildren) const override;
|
||||
|
|
|
@ -634,19 +634,6 @@ CharacterData::InsertChildBefore(nsIContent* aKid,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CharacterData::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CharacterData::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CharacterData::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -105,9 +105,6 @@ public:
|
|||
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
OOMReporter& aError) override
|
||||
|
|
|
@ -1225,27 +1225,6 @@ FragmentOrElement::InsertChildBefore(nsIContent* aKid,
|
|||
return doInsertChildAt(aKid, index, aNotify, mAttrsAndChildren);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FragmentOrElement::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(aKid, "null ptr");
|
||||
|
||||
return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
|
||||
}
|
||||
|
||||
void
|
||||
FragmentOrElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
|
||||
NS_ASSERTION(oldKid == GetChildAt_Deprecated(aIndex), "Unexpected child in RemoveChildAt_Deprecated");
|
||||
|
||||
if (oldKid) {
|
||||
doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FragmentOrElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -98,9 +98,6 @@ public:
|
|||
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
mozilla::OOMReporter& aError) override;
|
||||
|
|
|
@ -4109,46 +4109,6 @@ nsIDocument::InsertChildBefore(nsIContent* aKid,
|
|||
return doInsertChildAt(aKid, index, aNotify, mChildren);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIDocument::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aKid->IsElement() && GetRootElement()) {
|
||||
NS_WARNING("Inserting root element when we already have one");
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsCOMPtr<nsIContent> oldKid = GetChildAt_Deprecated(aIndex);
|
||||
if (!oldKid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldKid->IsElement()) {
|
||||
// Destroy the link map up front before we mess with the child list.
|
||||
DestroyElementMaps();
|
||||
}
|
||||
|
||||
// Preemptively clear mCachedRootElement, since we may be about to remove it
|
||||
// from our child list, and we don't want to return this maybe-obsolete value
|
||||
// from any GetRootElement() calls that happen inside of doRemoveChildAt().
|
||||
// (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
|
||||
// GetRootElement() calls until after it's removed the child from mChildren.
|
||||
// Any call before that point would restore this soon-to-be-obsolete cached
|
||||
// answer, and our clearing here would be fruitless.)
|
||||
mCachedRootElement = nullptr;
|
||||
doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
|
||||
MOZ_ASSERT(mCachedRootElement != oldKid,
|
||||
"Stale pointer in mCachedRootElement, after we tried to clear it "
|
||||
"(maybe somebody called GetRootElement() too early?)");
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -6691,35 +6691,12 @@ nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
|
|||
const nsAString& aPseudoElt,
|
||||
bool aDefaultStylesOnly)
|
||||
{
|
||||
if (!mDocShell) {
|
||||
if (!mDoc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
|
||||
|
||||
if (!presShell) {
|
||||
// Try flushing frames on our parent in case there's a pending
|
||||
// style change that will create the presshell.
|
||||
auto* parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
|
||||
if (!parent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
parent->FlushPendingNotifications(FlushType::Frames);
|
||||
|
||||
// Might have killed mDocShell
|
||||
if (!mDocShell) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
presShell = mDocShell->GetPresShell();
|
||||
if (!presShell) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<nsICSSDeclaration> compStyle =
|
||||
NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
|
||||
NS_NewComputedDOMStyle(&aElt, aPseudoElt, mDoc,
|
||||
aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
|
||||
nsComputedDOMStyle::eAll);
|
||||
|
||||
|
|
|
@ -548,9 +548,6 @@ public:
|
|||
|
||||
nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) final;
|
||||
void RemoveChildNode(nsIContent* aKid, bool aNotify) final;
|
||||
nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo,
|
||||
nsINode **aResult,
|
||||
|
|
|
@ -533,7 +533,7 @@ nsINode::GetNodeValueInternal(nsAString& aNodeValue)
|
|||
nsINode*
|
||||
nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError)
|
||||
{
|
||||
if (IsCharacterData()) {
|
||||
if (!aOldChild.IsContent()) {
|
||||
// aOldChild can't be one of our children.
|
||||
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
return nullptr;
|
||||
|
@ -543,14 +543,16 @@ nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError)
|
|||
nsContentUtils::MaybeFireNodeRemoved(&aOldChild, this);
|
||||
}
|
||||
|
||||
int32_t index = ComputeIndexOf(&aOldChild);
|
||||
if (index == -1) {
|
||||
// Check again, we may not be the child's parent anymore.
|
||||
// Can be triggered by dom/base/crashtests/293388-1.html
|
||||
if (aOldChild.AsContent()->IsRootOfAnonymousSubtree() ||
|
||||
aOldChild.GetParentNode() != this) {
|
||||
// aOldChild isn't one of our children.
|
||||
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RemoveChildAt_Deprecated(index, true);
|
||||
RemoveChildNode(aOldChild.AsContent(), true);
|
||||
return &aOldChild;
|
||||
}
|
||||
|
||||
|
@ -640,7 +642,7 @@ nsINode::Normalize()
|
|||
"Should always have a parent unless "
|
||||
"mutation events messed us up");
|
||||
if (parent) {
|
||||
parent->RemoveChildAt_Deprecated(parent->ComputeIndexOf(node), true);
|
||||
parent->RemoveChildNode(node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1997,11 +1999,12 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
}
|
||||
|
||||
// Record the node to insert before, if any
|
||||
nsINode* nodeToInsertBefore;
|
||||
nsIContent* nodeToInsertBefore;
|
||||
if (aReplace) {
|
||||
nodeToInsertBefore = aRefChild->GetNextSibling();
|
||||
} else {
|
||||
nodeToInsertBefore = aRefChild;
|
||||
// Since aRefChild is our child, it must be an nsIContent object.
|
||||
nodeToInsertBefore = aRefChild ? aRefChild->AsContent() : nullptr;
|
||||
}
|
||||
if (nodeToInsertBefore == aNewChild) {
|
||||
// We're going to remove aNewChild from its parent, so use its next sibling
|
||||
|
@ -2015,14 +2018,6 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
nsIContent* newContent = aNewChild->AsContent();
|
||||
nsCOMPtr<nsINode> oldParent = newContent->GetParentNode();
|
||||
if (oldParent) {
|
||||
int32_t removeIndex = oldParent->ComputeIndexOf(newContent);
|
||||
if (removeIndex < 0) {
|
||||
// newContent is anonymous. We can't deal with this, so just bail
|
||||
NS_ERROR("How come our flags didn't catch this?");
|
||||
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Hold a strong ref to nodeToInsertBefore across the removal of newContent
|
||||
nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
|
||||
|
||||
|
@ -2034,11 +2029,14 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
{
|
||||
mozAutoDocUpdate batch(newContent->GetComposedDoc(), true);
|
||||
nsAutoMutationBatch mb(oldParent, true, true);
|
||||
oldParent->RemoveChildAt_Deprecated(removeIndex, true);
|
||||
// ScriptBlocker ensures previous and next stay alive.
|
||||
nsIContent* previous = aNewChild->GetPreviousSibling();
|
||||
nsIContent* next = aNewChild->GetNextSibling();
|
||||
oldParent->RemoveChildNode(aNewChild->AsContent(), true);
|
||||
if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
|
||||
mb.RemovalDone();
|
||||
mb.SetPrevSibling(oldParent->GetChildAt_Deprecated(removeIndex - 1));
|
||||
mb.SetNextSibling(oldParent->GetChildAt_Deprecated(removeIndex));
|
||||
mb.SetPrevSibling(previous);
|
||||
mb.SetNextSibling(next);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2077,7 +2075,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
if (aReplace) {
|
||||
nodeToInsertBefore = aRefChild->GetNextSibling();
|
||||
} else {
|
||||
nodeToInsertBefore = aRefChild;
|
||||
nodeToInsertBefore = aRefChild ? aRefChild->AsContent() : nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2112,8 +2110,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
mozAutoDocUpdate batch(newContent->GetComposedDoc(), true);
|
||||
nsAutoMutationBatch mb(newContent, false, true);
|
||||
|
||||
for (uint32_t i = count; i > 0;) {
|
||||
newContent->RemoveChildAt_Deprecated(--i, true);
|
||||
while (newContent->HasChildren()) {
|
||||
newContent->RemoveChildNode(newContent->GetLastChild(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2151,7 +2149,8 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
if (aReplace) {
|
||||
nodeToInsertBefore = aRefChild->GetNextSibling();
|
||||
} else {
|
||||
nodeToInsertBefore = aRefChild;
|
||||
// If aRefChild has 'this' as a parent, it must be an nsIContent.
|
||||
nodeToInsertBefore = aRefChild ? aRefChild->AsContent() : nullptr;
|
||||
}
|
||||
|
||||
// And verify that newContent is still allowed as our child. Sadly, we
|
||||
|
@ -2182,23 +2181,6 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
mozAutoDocUpdate batch(GetComposedDoc(), true);
|
||||
nsAutoMutationBatch mb;
|
||||
|
||||
// Figure out which index we want to insert at. Note that we use
|
||||
// nodeToInsertBefore to determine this, because it's possible that
|
||||
// aRefChild == aNewChild, in which case we just removed it from the
|
||||
// parent list.
|
||||
int32_t insPos;
|
||||
if (nodeToInsertBefore) {
|
||||
insPos = ComputeIndexOf(nodeToInsertBefore);
|
||||
if (insPos < 0) {
|
||||
// XXXbz How the heck would _that_ happen, exactly?
|
||||
aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
insPos = GetChildCount();
|
||||
}
|
||||
|
||||
// If we're replacing and we haven't removed aRefChild yet, do so now
|
||||
if (aReplace && aRefChild != aNewChild) {
|
||||
mb.Init(this, true, true);
|
||||
|
@ -2208,11 +2190,11 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
NS_ASSERTION(aRefChild->GetNextSibling() == nodeToInsertBefore,
|
||||
"Unexpected nodeToInsertBefore");
|
||||
|
||||
// An since nodeToInsertBefore is at index insPos, we want to remove
|
||||
// at the previous index.
|
||||
NS_ASSERTION(insPos >= 1, "insPos too small");
|
||||
RemoveChildAt_Deprecated(insPos-1, true);
|
||||
--insPos;
|
||||
nsIContent* toBeRemoved = nodeToInsertBefore ?
|
||||
nodeToInsertBefore->GetPreviousSibling() : GetLastChild();
|
||||
MOZ_ASSERT(toBeRemoved);
|
||||
|
||||
RemoveChildNode(toBeRemoved, true);
|
||||
}
|
||||
|
||||
// Move new child over to our document if needed. Do this after removing
|
||||
|
@ -2246,8 +2228,9 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
nsAutoMutationBatch* mutationBatch = nsAutoMutationBatch::GetCurrentBatch();
|
||||
if (mutationBatch) {
|
||||
mutationBatch->RemovalDone();
|
||||
mutationBatch->SetPrevSibling(GetChildAt_Deprecated(insPos - 1));
|
||||
mutationBatch->SetNextSibling(GetChildAt_Deprecated(insPos));
|
||||
mutationBatch->SetPrevSibling(nodeToInsertBefore ?
|
||||
nodeToInsertBefore->GetPreviousSibling() : GetLastChild());
|
||||
mutationBatch->SetNextSibling(nodeToInsertBefore);
|
||||
}
|
||||
|
||||
uint32_t count = fragChildren->Length();
|
||||
|
@ -2255,16 +2238,16 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
return result;
|
||||
}
|
||||
|
||||
bool appending = !IsDocument() && uint32_t(insPos) == GetChildCount();
|
||||
bool appending = !IsDocument() && !nodeToInsertBefore;
|
||||
nsIContent* firstInsertedContent = fragChildren->ElementAt(0);
|
||||
|
||||
// Iterate through the fragment's children, and insert them in the new
|
||||
// parent
|
||||
for (uint32_t i = 0; i < count; ++i, ++insPos) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
// XXXbz how come no reparenting here? That seems odd...
|
||||
// Insert the child.
|
||||
aError = InsertChildAt_Deprecated(fragChildren->ElementAt(i), insPos,
|
||||
!appending);
|
||||
aError = InsertChildBefore(fragChildren->ElementAt(i), nodeToInsertBefore,
|
||||
!appending);
|
||||
if (aError.Failed()) {
|
||||
// Make sure to notify on any children that we did succeed to insert
|
||||
if (appending && i != 0) {
|
||||
|
@ -2300,13 +2283,13 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||
// We need to reparent here for nodes for which the parent of their
|
||||
// wrapper is not the wrapper for their ownerDocument (XUL elements,
|
||||
// form controls, ...). Also applies in the fragment code above.
|
||||
|
||||
if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
|
||||
mb.RemovalDone();
|
||||
mb.SetPrevSibling(GetChildAt_Deprecated(insPos - 1));
|
||||
mb.SetNextSibling(GetChildAt_Deprecated(insPos));
|
||||
mb.SetPrevSibling(nodeToInsertBefore ?
|
||||
nodeToInsertBefore->GetPreviousSibling() : GetLastChild());
|
||||
mb.SetNextSibling(nodeToInsertBefore);
|
||||
}
|
||||
aError = InsertChildAt_Deprecated(newContent, insPos, true);
|
||||
aError = InsertChildBefore(newContent, nodeToInsertBefore, true);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -821,29 +821,6 @@ public:
|
|||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) = 0;
|
||||
|
||||
/**
|
||||
* Insert a content node at a particular index. This method handles calling
|
||||
* BindToTree on the child appropriately.
|
||||
*
|
||||
* @param aKid the content to insert
|
||||
* @param aIndex the index it is being inserted at (the index it will have
|
||||
* after it is inserted)
|
||||
* @param aNotify whether to notify the document (current document for
|
||||
* nsIContent, and |this| for nsIDocument) that the insert has
|
||||
* occurred
|
||||
*
|
||||
* @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
|
||||
* than one element node as a child of a document. Doing this will also
|
||||
* assert -- you shouldn't be doing it! Check with
|
||||
* nsIDocument::GetRootElement() first if you're not sure. Apart from this
|
||||
* one constraint, this doesn't do any checking on whether aKid is a valid
|
||||
* child of |this|.
|
||||
*
|
||||
* @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
|
||||
*/
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) = 0;
|
||||
|
||||
/**
|
||||
* Append a content node to the end of the child list. This method handles
|
||||
* calling BindToTree on the child appropriately.
|
||||
|
@ -864,25 +841,9 @@ public:
|
|||
*/
|
||||
nsresult AppendChildTo(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
return InsertChildAt_Deprecated(aKid, GetChildCount(), aNotify);
|
||||
return InsertChildBefore(aKid, nullptr, aNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: this function is going to be removed soon (hopefully!) Don't use it
|
||||
* in new code.
|
||||
*
|
||||
* Remove a child from this node. This method handles calling UnbindFromTree
|
||||
* on the child appropriately.
|
||||
*
|
||||
* @param aIndex the index of the child to remove
|
||||
* @param aNotify whether to notify the document (current document for
|
||||
* nsIContent, and |this| for nsIDocument) that the remove has
|
||||
* occurred
|
||||
*
|
||||
* Note: If there is no child at aIndex, this method will simply do nothing.
|
||||
*/
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) = 0;
|
||||
|
||||
/**
|
||||
* Remove a child from this node. This method handles calling UnbindFromTree
|
||||
* on the child appropriately.
|
||||
|
|
|
@ -236,11 +236,13 @@ public:
|
|||
MOZ_ASSERT(aTouchEvent,
|
||||
"mRetargetedTouchTargets should be empty when dispatching non-touch events.");
|
||||
|
||||
WidgetTouchEvent::TouchArray& touches = aTouchEvent->mTouches;
|
||||
MOZ_ASSERT(!touches.Length() ||
|
||||
touches.Length() == mRetargetedTouchTargets->Length());
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
touches[i]->mTarget = mRetargetedTouchTargets->ElementAt(i);
|
||||
if (mRetargetedTouchTargets.isSome()) {
|
||||
WidgetTouchEvent::TouchArray& touches = aTouchEvent->mTouches;
|
||||
MOZ_ASSERT(!touches.Length() ||
|
||||
touches.Length() == mRetargetedTouchTargets->Length());
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
touches[i]->mTarget = mRetargetedTouchTargets->ElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (aDOMEvent) {
|
||||
|
|
|
@ -171,64 +171,6 @@ HTMLFieldSetElement::InsertChildBefore(nsIContent* aChild,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLFieldSetElement::InsertChildAt_Deprecated(nsIContent* aChild,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
bool firstLegendHasChanged = false;
|
||||
|
||||
if (aChild->IsHTMLElement(nsGkAtoms::legend)) {
|
||||
if (!mFirstLegend) {
|
||||
mFirstLegend = aChild;
|
||||
// We do not want to notify the first time mFirstElement is set.
|
||||
} else {
|
||||
// If mFirstLegend is before aIndex, we do not change it.
|
||||
// Otherwise, mFirstLegend is now aChild.
|
||||
if (int32_t(aIndex) <= ComputeIndexOf(mFirstLegend)) {
|
||||
mFirstLegend = aChild;
|
||||
firstLegendHasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
nsGenericHTMLFormElement::InsertChildAt_Deprecated(aChild, aIndex, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (firstLegendHasChanged) {
|
||||
NotifyElementsForFirstLegendChange(aNotify);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
bool firstLegendHasChanged = false;
|
||||
|
||||
if (mFirstLegend && (GetChildAt_Deprecated(aIndex) == mFirstLegend)) {
|
||||
// If we are removing the first legend we have to found another one.
|
||||
nsIContent* child = mFirstLegend->GetNextSibling();
|
||||
mFirstLegend = nullptr;
|
||||
firstLegendHasChanged = true;
|
||||
|
||||
for (; child; child = child->GetNextSibling()) {
|
||||
if (child->IsHTMLElement(nsGkAtoms::legend)) {
|
||||
mFirstLegend = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLFormElement::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
|
||||
if (firstLegendHasChanged) {
|
||||
NotifyElementsForFirstLegendChange(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLFieldSetElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -42,9 +42,6 @@ public:
|
|||
|
||||
virtual nsresult InsertChildBefore(nsIContent* aChild, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aChild, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
|
||||
// nsIFormControl
|
||||
|
|
|
@ -86,28 +86,6 @@ HTMLOptGroupElement::InsertChildBefore(nsIContent* aKid,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLOptGroupElement::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(GetSelect(), this, aKid, aIndex, aNotify);
|
||||
nsresult rv = nsGenericHTMLElement::InsertChildAt_Deprecated(aKid, aIndex,
|
||||
aNotify);
|
||||
if (NS_FAILED(rv)) {
|
||||
safeMutation.MutationFailed();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptGroupElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr, aIndex,
|
||||
aNotify);
|
||||
nsGenericHTMLElement::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOptGroupElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -28,9 +28,6 @@ public:
|
|||
// nsINode
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
|
||||
// nsIContent
|
||||
|
|
|
@ -30,32 +30,6 @@ HTMLPictureElement::~HTMLPictureElement()
|
|||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLPictureElement)
|
||||
|
||||
void
|
||||
HTMLPictureElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsCOMPtr<nsIContent> child = GetChildAt_Deprecated(aIndex);
|
||||
|
||||
if (child && child->IsHTMLElement(nsGkAtoms::img)) {
|
||||
HTMLImageElement* img = HTMLImageElement::FromNode(child);
|
||||
if (img) {
|
||||
img->PictureSourceRemoved(child->AsContent());
|
||||
}
|
||||
} else if (child && child->IsHTMLElement(nsGkAtoms::source)) {
|
||||
// Find all img siblings after this <source> to notify them of its demise
|
||||
nsCOMPtr<nsIContent> nextSibling = child->GetNextSibling();
|
||||
if (nextSibling && nextSibling->GetParentNode() == this) {
|
||||
do {
|
||||
HTMLImageElement* img = HTMLImageElement::FromNode(nextSibling);
|
||||
if (img) {
|
||||
img->PictureSourceRemoved(child->AsContent());
|
||||
}
|
||||
} while ( (nextSibling = nextSibling->GetNextSibling()) );
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLPictureElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
@ -111,35 +85,6 @@ HTMLPictureElement::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLPictureElement::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::InsertChildAt_Deprecated(aKid, aIndex, aNotify);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(aKid, rv);
|
||||
|
||||
if (aKid->IsHTMLElement(nsGkAtoms::img)) {
|
||||
HTMLImageElement* img = HTMLImageElement::FromNode(aKid);
|
||||
if (img) {
|
||||
img->PictureSourceAdded(aKid->AsContent());
|
||||
}
|
||||
} else if (aKid->IsHTMLElement(nsGkAtoms::source)) {
|
||||
// Find all img siblings after this <source> to notify them of its insertion
|
||||
nsCOMPtr<nsIContent> nextSibling = aKid->GetNextSibling();
|
||||
if (nextSibling && nextSibling->GetParentNode() == this) {
|
||||
do {
|
||||
HTMLImageElement* img = HTMLImageElement::FromNode(nextSibling);
|
||||
if (img) {
|
||||
img->PictureSourceAdded(aKid->AsContent());
|
||||
}
|
||||
} while ( (nextSibling = nextSibling->GetNextSibling()) );
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLPictureElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
|
|
@ -23,12 +23,9 @@ public:
|
|||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
|
||||
bool aPreallocateChildren) const override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLPictureElement();
|
||||
|
|
|
@ -217,28 +217,6 @@ HTMLSelectElement::InsertChildBefore(nsIContent* aKid,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLSelectElement::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(this, this, aKid, aIndex, aNotify);
|
||||
nsresult rv =
|
||||
nsGenericHTMLFormElementWithState::InsertChildAt_Deprecated(aKid, aIndex,
|
||||
aNotify);
|
||||
if (NS_FAILED(rv)) {
|
||||
safeMutation.MutationFailed();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
SafeOptionListMutation safeMutation(this, this, nullptr, aIndex, aNotify);
|
||||
nsGenericHTMLFormElementWithState::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -247,9 +247,6 @@ public:
|
|||
virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override;
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
|
|
|
@ -50,23 +50,6 @@ SVGDocument::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
|||
return XMLDocument::InsertChildBefore(aKid, aBeforeThis, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGDocument::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aKid->IsElement() && !aKid->IsSVGElement()) {
|
||||
// We can get here when well formed XML with a non-SVG root element is
|
||||
// served with the SVG MIME type, for example. In that case we need to load
|
||||
// the non-SVG UA sheets or else we can get bugs like bug 1016145. Note
|
||||
// that we have to do this _before_ the
|
||||
// XMLDocument::InsertChildAt_Deprecated call, since that can try to
|
||||
// construct frames, and we need to have the sheets loaded by then.
|
||||
EnsureNonSVGUserAgentStyleSheetsLoaded();
|
||||
}
|
||||
|
||||
return XMLDocument::InsertChildAt_Deprecated(aKid, aIndex, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
|
||||
bool aPreallocateChildren) const
|
||||
|
|
|
@ -35,8 +35,6 @@ public:
|
|||
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
|
||||
bool aPreallocateChildren) const override;
|
||||
|
||||
|
|
|
@ -93,26 +93,6 @@ SVGSwitchElement::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGSwitchElement::InsertChildAt_Deprecated(nsIContent* aKid,
|
||||
uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = SVGSwitchElementBase::InsertChildAt_Deprecated(aKid, aIndex,
|
||||
aNotify);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MaybeInvalidate();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
SVGSwitchElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
SVGSwitchElementBase::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
MaybeInvalidate();
|
||||
}
|
||||
|
||||
void
|
||||
SVGSwitchElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -42,9 +42,6 @@ public:
|
|||
// nsINode
|
||||
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
|
||||
bool aNotify) override;
|
||||
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
|
||||
// nsIContent
|
||||
|
|
|
@ -827,103 +827,6 @@ nsXULElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
|
||||
{
|
||||
nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
|
||||
if (!oldKid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
|
||||
// the possibility exists that some of the items in the removed subtree
|
||||
// are selected (and therefore need to be deselected). We need to account for this.
|
||||
nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
|
||||
nsCOMPtr<nsIListBoxObject> listBox;
|
||||
bool fireSelectionHandler = false;
|
||||
|
||||
// -1 = do nothing, -2 = null out current item
|
||||
// anything else = index to re-set as current
|
||||
int32_t newCurrentIndex = -1;
|
||||
|
||||
if (oldKid->NodeInfo()->Equals(nsGkAtoms::listitem, kNameSpaceID_XUL)) {
|
||||
// This is the nasty case. We have (potentially) a slew of selected items
|
||||
// and cells going away.
|
||||
// First, retrieve the tree.
|
||||
// Check first whether this element IS the tree
|
||||
controlElement = do_QueryObject(this);
|
||||
|
||||
// If it's not, look at our parent
|
||||
if (!controlElement)
|
||||
GetParentTree(getter_AddRefs(controlElement));
|
||||
nsCOMPtr<nsIContent> controlContent(do_QueryInterface(controlElement));
|
||||
RefPtr<nsXULElement> xulElement = FromNodeOrNull(controlContent);
|
||||
|
||||
if (xulElement) {
|
||||
// Iterate over all of the items and find out if they are contained inside
|
||||
// the removed subtree.
|
||||
int32_t length;
|
||||
controlElement->GetSelectedCount(&length);
|
||||
for (int32_t i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
|
||||
controlElement->MultiGetSelectedItem(i, getter_AddRefs(item));
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(item);
|
||||
if (node == oldKid &&
|
||||
NS_SUCCEEDED(controlElement->RemoveItemFromSelection(item))) {
|
||||
length--;
|
||||
i--;
|
||||
fireSelectionHandler = true;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
|
||||
controlElement->GetCurrentItem(getter_AddRefs(curItem));
|
||||
nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
|
||||
if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, oldKid)) {
|
||||
// Current item going away
|
||||
nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(IgnoreErrors());
|
||||
listBox = do_QueryInterface(box);
|
||||
if (listBox) {
|
||||
listBox->GetIndexOfItem(oldKid->AsElement(), &newCurrentIndex);
|
||||
}
|
||||
|
||||
// If any of this fails, we'll just set the current item to null
|
||||
if (newCurrentIndex == -1)
|
||||
newCurrentIndex = -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsStyledElement::RemoveChildAt_Deprecated(aIndex, aNotify);
|
||||
|
||||
if (newCurrentIndex == -2) {
|
||||
controlElement->SetCurrentItem(nullptr);
|
||||
} else if (newCurrentIndex > -1) {
|
||||
// Make sure the index is still valid
|
||||
int32_t treeRows;
|
||||
listBox->GetRowCount(&treeRows);
|
||||
if (treeRows > 0) {
|
||||
newCurrentIndex = std::min((treeRows - 1), newCurrentIndex);
|
||||
RefPtr<Element> newCurrentItem;
|
||||
listBox->GetItemAtIndex(newCurrentIndex, getter_AddRefs(newCurrentItem));
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> xulCurItem = do_QueryInterface(newCurrentItem);
|
||||
if (xulCurItem)
|
||||
controlElement->SetCurrentItem(xulCurItem);
|
||||
} else {
|
||||
controlElement->SetCurrentItem(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* doc;
|
||||
if (fireSelectionHandler && (doc = GetComposedDoc())) {
|
||||
nsContentUtils::DispatchTrustedEvent(doc,
|
||||
static_cast<nsIContent*>(this),
|
||||
NS_LITERAL_STRING("select"),
|
||||
false,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
|
||||
{
|
||||
|
|
|
@ -368,7 +368,6 @@ public:
|
|||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
|
||||
virtual void DestroyContent() override;
|
||||
|
||||
|
|
|
@ -556,11 +556,8 @@ CSSEditUtils::GetComputedStyle(Element* aElement)
|
|||
nsIDocument* doc = aElement->GetComposedDoc();
|
||||
NS_ENSURE_TRUE(doc, nullptr);
|
||||
|
||||
nsIPresShell* presShell = doc->GetShell();
|
||||
NS_ENSURE_TRUE(presShell, nullptr);
|
||||
|
||||
RefPtr<nsComputedDOMStyle> style =
|
||||
NS_NewComputedDOMStyle(aElement, EmptyString(), presShell);
|
||||
NS_NewComputedDOMStyle(aElement, EmptyString(), doc);
|
||||
|
||||
return style.forget();
|
||||
}
|
||||
|
|
|
@ -384,6 +384,9 @@ GPUParent::RecvSimulateDeviceReset(GPUDeviceData* aOut)
|
|||
#if defined(XP_WIN)
|
||||
DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED);
|
||||
DeviceManagerDx::Get()->MaybeResetAndReacquireDevices();
|
||||
if (gfxVars::UseWebRender()) {
|
||||
wr::RenderThread::Get()->SimulateDeviceReset();
|
||||
}
|
||||
#endif
|
||||
RecvGetDeviceStatus(aOut);
|
||||
return IPC_OK();
|
||||
|
|
|
@ -972,7 +972,9 @@ static float* qcms_modular_transform_data(struct qcms_modular_transform *transfo
|
|||
assert(0 && "Unsupported transform module");
|
||||
return NULL;
|
||||
}
|
||||
if (transform->grid_size <= 0) {
|
||||
if (transform->grid_size <= 0 &&
|
||||
(transform_fn == qcms_transform_module_clut ||
|
||||
transform_fn == qcms_transform_module_clut_only)) {
|
||||
assert(0 && "Invalid transform");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ static Mutex* gGfxPlatformPrefsLock = nullptr;
|
|||
static qcms_profile *gCMSOutputProfile = nullptr;
|
||||
static qcms_profile *gCMSsRGBProfile = nullptr;
|
||||
|
||||
static bool gCMSRGBTransformFailed = false;
|
||||
static qcms_transform *gCMSRGBTransform = nullptr;
|
||||
static qcms_transform *gCMSInverseRGBTransform = nullptr;
|
||||
static qcms_transform *gCMSRGBATransform = nullptr;
|
||||
|
@ -2088,7 +2089,7 @@ gfxPlatform::GetCMSsRGBProfile()
|
|||
qcms_transform *
|
||||
gfxPlatform::GetCMSRGBTransform()
|
||||
{
|
||||
if (!gCMSRGBTransform) {
|
||||
if (!gCMSRGBTransform && !gCMSRGBTransformFailed) {
|
||||
qcms_profile *inProfile, *outProfile;
|
||||
outProfile = GetCMSOutputProfile();
|
||||
inProfile = GetCMSsRGBProfile();
|
||||
|
@ -2099,6 +2100,9 @@ gfxPlatform::GetCMSRGBTransform()
|
|||
gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
|
||||
outProfile, QCMS_DATA_RGB_8,
|
||||
QCMS_INTENT_PERCEPTUAL);
|
||||
if (!gCMSRGBTransform) {
|
||||
gCMSRGBTransformFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return gCMSRGBTransform;
|
||||
|
|
|
@ -311,7 +311,7 @@ bool
|
|||
RenderCompositorANGLE::BeginFrame()
|
||||
{
|
||||
if (mDevice->GetDeviceRemovedReason() != S_OK) {
|
||||
RenderThread::Get()->HandleDeviceReset("BeginFrame");
|
||||
RenderThread::Get()->HandleDeviceReset("BeginFrame", /* aNotify */ true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ RenderCompositorANGLE::BeginFrame()
|
|||
if (mSyncObject) {
|
||||
if (!mSyncObject->Synchronize()) {
|
||||
// It's timeout or other error. Handle the device-reset here.
|
||||
RenderThread::Get()->HandleDeviceReset("SyncObject");
|
||||
RenderThread::Get()->HandleDeviceReset("SyncObject", /* aNotify */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -552,7 +552,7 @@ RenderThread::ProgramCacheTask()
|
|||
}
|
||||
|
||||
void
|
||||
RenderThread::HandleDeviceReset(const char* aWhere)
|
||||
RenderThread::HandleDeviceReset(const char* aWhere, bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
|
||||
|
@ -560,9 +560,11 @@ RenderThread::HandleDeviceReset(const char* aWhere)
|
|||
return;
|
||||
}
|
||||
|
||||
gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
|
||||
if (XRE_IsGPUProcess()) {
|
||||
gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
|
||||
if (aNotify) {
|
||||
gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
|
||||
if (XRE_IsGPUProcess()) {
|
||||
gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -584,6 +586,21 @@ RenderThread::IsHandlingDeviceReset()
|
|||
return mHandlingDeviceReset;
|
||||
}
|
||||
|
||||
void
|
||||
RenderThread::SimulateDeviceReset()
|
||||
{
|
||||
if (!IsInRenderThread()) {
|
||||
Loop()->PostTask(NewRunnableMethod(
|
||||
"RenderThread::SimulateDeviceReset",
|
||||
this, &RenderThread::SimulateDeviceReset
|
||||
));
|
||||
} else {
|
||||
// When this function is called GPUProcessManager::SimulateDeviceReset() already
|
||||
// triggers destroying all CompositorSessions before re-creating them.
|
||||
HandleDeviceReset("SimulateDeviceReset", /* aNotify */ false);
|
||||
}
|
||||
}
|
||||
|
||||
WebRenderProgramCache*
|
||||
RenderThread::ProgramCache()
|
||||
{
|
||||
|
|
|
@ -168,9 +168,11 @@ public:
|
|||
WebRenderProgramCache* ProgramCache();
|
||||
|
||||
/// Can only be called from the render thread.
|
||||
void HandleDeviceReset(const char* aWhere);
|
||||
void HandleDeviceReset(const char* aWhere, bool aNotify);
|
||||
/// Can only be called from the render thread.
|
||||
bool IsHandlingDeviceReset();
|
||||
/// Can be called from any thread.
|
||||
void SimulateDeviceReset();
|
||||
|
||||
size_t RendererCount();
|
||||
|
||||
|
|
|
@ -2968,7 +2968,7 @@ GCRuntime::updateZonePointersToRelocatedCells(Zone* zone)
|
|||
* Update runtime-wide pointers to relocated cells.
|
||||
*/
|
||||
void
|
||||
GCRuntime::updateRuntimePointersToRelocatedCells(AutoTraceSession& session)
|
||||
GCRuntime::updateRuntimePointersToRelocatedCells(AutoGCSession& session)
|
||||
{
|
||||
MOZ_ASSERT(!rt->isBeingDestroyed());
|
||||
|
||||
|
@ -4262,8 +4262,7 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
|
|||
}
|
||||
|
||||
bool
|
||||
GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut,
|
||||
AutoLockForExclusiveAccess& lock)
|
||||
GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* Assert that zone state is as we expect */
|
||||
|
@ -4355,7 +4354,7 @@ PurgeShapeTablesForShrinkingGC(JSRuntime* rt)
|
|||
{
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::PURGE_SHAPE_TABLES);
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
if (zone->keepShapeTables() || zone->isSelfHostingZone())
|
||||
if (!CanRelocateZone(zone) || zone->keepShapeTables())
|
||||
continue;
|
||||
for (auto baseShape = zone->cellIter<BaseShape>(); !baseShape.done(); baseShape.next())
|
||||
baseShape->maybePurgeTable();
|
||||
|
@ -4384,21 +4383,19 @@ BufferGrayRoots(GCParallelTask* task)
|
|||
}
|
||||
|
||||
bool
|
||||
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoTraceSession& session)
|
||||
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoGCSession& session)
|
||||
{
|
||||
MOZ_ASSERT(session.maybeLock.isSome());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (fullCompartmentChecks)
|
||||
checkForCompartmentMismatches();
|
||||
#endif
|
||||
|
||||
if (!prepareZonesForCollection(reason, &isFull.ref(), session.lock()))
|
||||
if (!prepareZonesForCollection(reason, &isFull.ref()))
|
||||
return false;
|
||||
|
||||
/* If we're not collecting the atoms zone we can release the lock now. */
|
||||
if (!atomsZone->isCollecting())
|
||||
session.maybeLock.reset();
|
||||
/* * Check it's safe to access the atoms zone if we are collecting it. */
|
||||
if (atomsZone->isCollecting())
|
||||
session.maybeCheckAtomsAccess.emplace(rt);
|
||||
|
||||
/*
|
||||
* In an incremental GC, clear the area free lists to ensure that subsequent
|
||||
|
@ -4666,7 +4663,7 @@ class js::gc::MarkingValidator
|
|||
public:
|
||||
explicit MarkingValidator(GCRuntime* gc);
|
||||
~MarkingValidator();
|
||||
void nonIncrementalMark(AutoTraceSession& session);
|
||||
void nonIncrementalMark(AutoGCSession& session);
|
||||
void validate();
|
||||
|
||||
private:
|
||||
|
@ -4692,7 +4689,7 @@ js::gc::MarkingValidator::~MarkingValidator()
|
|||
}
|
||||
|
||||
void
|
||||
js::gc::MarkingValidator::nonIncrementalMark(AutoTraceSession& session)
|
||||
js::gc::MarkingValidator::nonIncrementalMark(AutoGCSession& session)
|
||||
{
|
||||
/*
|
||||
* Perform a non-incremental mark for all collecting zones and record
|
||||
|
@ -4908,7 +4905,7 @@ js::gc::MarkingValidator::validate()
|
|||
#endif // JS_GC_ZEAL
|
||||
|
||||
void
|
||||
GCRuntime::computeNonIncrementalMarkingForValidation(AutoTraceSession& session)
|
||||
GCRuntime::computeNonIncrementalMarkingForValidation(AutoGCSession& session)
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
MOZ_ASSERT(!markingValidator);
|
||||
|
@ -5884,7 +5881,7 @@ GCRuntime::endSweepingSweepGroup(FreeOp* fop, SliceBudget& budget)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::beginSweepPhase(JS::gcreason::Reason reason, AutoTraceSession& session)
|
||||
GCRuntime::beginSweepPhase(JS::gcreason::Reason reason, AutoGCSession& session)
|
||||
{
|
||||
/*
|
||||
* Sweep phase.
|
||||
|
@ -6759,7 +6756,7 @@ GCRuntime::beginCompactPhase()
|
|||
|
||||
IncrementalProgress
|
||||
GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
||||
AutoTraceSession& session)
|
||||
AutoGCSession& session)
|
||||
{
|
||||
assertBackgroundSweepingFinished();
|
||||
MOZ_ASSERT(startedCompacting);
|
||||
|
@ -6870,7 +6867,7 @@ HeapStateToLabel(JS::HeapState heapState)
|
|||
}
|
||||
|
||||
/* Start a new heap session. */
|
||||
AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
|
||||
AutoHeapSession::AutoHeapSession(JSRuntime* rt, JS::HeapState heapState)
|
||||
: runtime(rt),
|
||||
prevState(rt->heapState_),
|
||||
profilingStackFrame(rt->mainContextFromOwnThread(), HeapStateToLabel(heapState),
|
||||
|
@ -6881,13 +6878,10 @@ AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
|
|||
MOZ_ASSERT(heapState != JS::HeapState::Idle);
|
||||
MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, rt->gc.nursery().isEmpty());
|
||||
|
||||
// Session always begins with lock held, see comment in class definition.
|
||||
maybeLock.emplace(rt);
|
||||
|
||||
rt->heapState_ = heapState;
|
||||
}
|
||||
|
||||
AutoTraceSession::~AutoTraceSession()
|
||||
AutoHeapSession::~AutoHeapSession()
|
||||
{
|
||||
MOZ_ASSERT(JS::RuntimeHeapIsBusy());
|
||||
runtime->heapState_ = prevState;
|
||||
|
@ -6900,7 +6894,7 @@ JS::RuntimeHeapState()
|
|||
}
|
||||
|
||||
GCRuntime::IncrementalResult
|
||||
GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoTraceSession& session)
|
||||
GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoGCSession& session)
|
||||
{
|
||||
MOZ_ASSERT(reason != gc::AbortReason::None);
|
||||
|
||||
|
@ -7092,15 +7086,8 @@ ShouldCleanUpEverything(JS::gcreason::Reason reason, JSGCInvocationKind gckind)
|
|||
|
||||
void
|
||||
GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
|
||||
AutoTraceSession& session)
|
||||
AutoGCSession& session)
|
||||
{
|
||||
/*
|
||||
* Drop the exclusive access lock if we are in an incremental collection
|
||||
* that does not touch the atoms zone.
|
||||
*/
|
||||
if (isIncrementalGCInProgress() && !atomsZone->isCollecting())
|
||||
session.maybeLock.reset();
|
||||
|
||||
AutoDisableBarriers disableBarriers(rt);
|
||||
|
||||
bool destroyingRuntime = (reason == JS::gcreason::DESTROY_RUNTIME);
|
||||
|
@ -7328,7 +7315,7 @@ CheckZoneIsScheduled(Zone* zone, JS::gcreason::Reason reason, const char* trigge
|
|||
|
||||
GCRuntime::IncrementalResult
|
||||
GCRuntime::budgetIncrementalGC(bool nonincrementalByAPI, JS::gcreason::Reason reason,
|
||||
SliceBudget& budget, AutoTraceSession& session)
|
||||
SliceBudget& budget, AutoGCSession& session)
|
||||
{
|
||||
if (nonincrementalByAPI) {
|
||||
stats().nonincremental(gc::AbortReason::NonIncrementalRequested);
|
||||
|
@ -7495,7 +7482,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
|||
|
||||
minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY_FOR_MAJOR_GC);
|
||||
|
||||
AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
|
||||
AutoGCSession session(rt, JS::HeapState::MajorCollecting);
|
||||
|
||||
majorGCTriggerReason = JS::gcreason::NO_REASON;
|
||||
|
||||
|
@ -7528,8 +7515,9 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
|||
}
|
||||
|
||||
// We don't allow off-thread parsing to start while we're doing an
|
||||
// incremental GC.
|
||||
MOZ_ASSERT_IF(rt->activeGCInAtomsZone(), !rt->hasHelperThreadZones());
|
||||
// incremental GC of the atoms zone.
|
||||
if (rt->activeGCInAtomsZone())
|
||||
session.maybeCheckAtomsAccess.emplace(rt);
|
||||
|
||||
auto result = budgetIncrementalGC(nonincrementalByAPI, reason, budget, session);
|
||||
|
||||
|
@ -7973,12 +7961,6 @@ js::gc::FinishGC(JSContext* cx)
|
|||
cx->nursery().waitBackgroundFreeEnd();
|
||||
}
|
||||
|
||||
AutoPrepareForTracing::AutoPrepareForTracing(JSContext* cx)
|
||||
{
|
||||
js::gc::FinishGC(cx);
|
||||
session_.emplace(cx->runtime());
|
||||
}
|
||||
|
||||
Realm*
|
||||
js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& options)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "gc/GC.h"
|
||||
#include "gc/RelocationOverlay.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "vm/HelperThreads.h"
|
||||
|
@ -22,43 +23,94 @@
|
|||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* This class should be used by any code that needs to exclusive access to the
|
||||
* heap in order to trace through it...
|
||||
*/
|
||||
class MOZ_RAII AutoTraceSession
|
||||
class MOZ_RAII AutoCheckCanAccessAtomsDuringGC
|
||||
{
|
||||
public:
|
||||
explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing);
|
||||
~AutoTraceSession();
|
||||
|
||||
// Constructing an AutoTraceSession takes the exclusive access lock, but GC
|
||||
// may release it during a trace session if we're not collecting the atoms
|
||||
// zone.
|
||||
mozilla::Maybe<AutoLockForExclusiveAccess> maybeLock;
|
||||
|
||||
AutoLockForExclusiveAccess& lock() {
|
||||
return maybeLock.ref();
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
JSRuntime* runtime;
|
||||
|
||||
private:
|
||||
AutoTraceSession(const AutoTraceSession&) = delete;
|
||||
void operator=(const AutoTraceSession&) = delete;
|
||||
public:
|
||||
explicit AutoCheckCanAccessAtomsDuringGC(JSRuntime* rt)
|
||||
: runtime(rt)
|
||||
{
|
||||
// Ensure we're only used from within the GC.
|
||||
MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting());
|
||||
|
||||
// Ensure there is no off-thread parsing running.
|
||||
MOZ_ASSERT(!rt->hasHelperThreadZones());
|
||||
|
||||
// Set up a check to assert if we try to start an off-thread parse.
|
||||
runtime->setOffThreadParsingBlocked(true);
|
||||
}
|
||||
~AutoCheckCanAccessAtomsDuringGC() {
|
||||
runtime->setOffThreadParsingBlocked(false);
|
||||
}
|
||||
#else
|
||||
public:
|
||||
explicit AutoCheckCanAccessAtomsDuringGC(JSRuntime* rt) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Abstract base class for exclusive heap access for tracing or GC.
|
||||
class MOZ_RAII AutoHeapSession
|
||||
{
|
||||
public:
|
||||
~AutoHeapSession();
|
||||
|
||||
protected:
|
||||
AutoHeapSession(JSRuntime* rt, JS::HeapState state);
|
||||
|
||||
private:
|
||||
AutoHeapSession(const AutoHeapSession&) = delete;
|
||||
void operator=(const AutoHeapSession&) = delete;
|
||||
|
||||
JSRuntime* runtime;
|
||||
JS::HeapState prevState;
|
||||
AutoGeckoProfilerEntry profilingStackFrame;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoPrepareForTracing
|
||||
class MOZ_RAII AutoGCSession : public AutoHeapSession
|
||||
{
|
||||
mozilla::Maybe<AutoTraceSession> session_;
|
||||
|
||||
public:
|
||||
explicit AutoPrepareForTracing(JSContext* cx);
|
||||
AutoTraceSession& session() { return session_.ref(); }
|
||||
explicit AutoGCSession(JSRuntime* rt, JS::HeapState state)
|
||||
: AutoHeapSession(rt, state)
|
||||
{}
|
||||
|
||||
AutoCheckCanAccessAtomsDuringGC& checkAtomsAccess() {
|
||||
return maybeCheckAtomsAccess.ref();
|
||||
}
|
||||
|
||||
// During a GC we can check that it's not possible for anything else to be
|
||||
// using the atoms zone.
|
||||
mozilla::Maybe<AutoCheckCanAccessAtomsDuringGC> maybeCheckAtomsAccess;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoTraceSession : public AutoLockForExclusiveAccess,
|
||||
public AutoHeapSession
|
||||
{
|
||||
public:
|
||||
explicit AutoTraceSession(JSRuntime* rt)
|
||||
: AutoLockForExclusiveAccess(rt),
|
||||
AutoHeapSession(rt, JS::HeapState::Tracing)
|
||||
{}
|
||||
};
|
||||
|
||||
struct MOZ_RAII AutoFinishGC
|
||||
{
|
||||
explicit AutoFinishGC(JSContext* cx) {
|
||||
FinishGC(cx);
|
||||
}
|
||||
};
|
||||
|
||||
// This class should be used by any code that needs to exclusive access to the
|
||||
// heap in order to trace through it.
|
||||
class MOZ_RAII AutoPrepareForTracing : private AutoFinishGC,
|
||||
public AutoTraceSession
|
||||
{
|
||||
public:
|
||||
explicit AutoPrepareForTracing(JSContext* cx)
|
||||
: AutoFinishGC(cx),
|
||||
AutoTraceSession(cx->runtime())
|
||||
{}
|
||||
};
|
||||
|
||||
AbortReason
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
class AutoAccessAtomsZone;
|
||||
class WeakMapBase;
|
||||
|
||||
static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
|
||||
|
@ -281,7 +282,7 @@ class GCMarker : public JSTracer
|
|||
void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
const AutoLockForExclusiveAccess& lock) const;
|
||||
const AutoAccessAtomsZone& access) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
class AutoAccessAtomsZone;
|
||||
class AutoLockGC;
|
||||
class AutoLockGCBgAlloc;
|
||||
class AutoLockHelperThreadState;
|
||||
|
@ -37,6 +38,7 @@ using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>;
|
|||
using ZoneVector = Vector<JS::Zone*, 4, SystemAllocPolicy>;
|
||||
|
||||
class AutoCallGCCallbacks;
|
||||
class AutoGCSession;
|
||||
class AutoRunParallelTask;
|
||||
class AutoTraceSession;
|
||||
class MarkingValidator;
|
||||
|
@ -264,7 +266,7 @@ class GCRuntime
|
|||
MarkRuntime
|
||||
};
|
||||
void traceRuntime(JSTracer* trc, AutoTraceSession& session);
|
||||
void traceRuntimeForMinorGC(JSTracer* trc, AutoTraceSession& session);
|
||||
void traceRuntimeForMinorGC(JSTracer* trc, AutoGCSession& session);
|
||||
|
||||
void purgeRuntimeForMinorGC();
|
||||
|
||||
|
@ -540,8 +542,8 @@ class GCRuntime
|
|||
void requestMajorGC(JS::gcreason::Reason reason);
|
||||
SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
|
||||
IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI, JS::gcreason::Reason reason,
|
||||
SliceBudget& budget, AutoTraceSession& session);
|
||||
IncrementalResult resetIncrementalGC(AbortReason reason, AutoTraceSession& session);
|
||||
SliceBudget& budget, AutoGCSession& session);
|
||||
IncrementalResult resetIncrementalGC(AbortReason reason, AutoGCSession& session);
|
||||
|
||||
// Assert if the system state is such that we should never
|
||||
// receive a request to do GC work.
|
||||
|
@ -557,23 +559,21 @@ class GCRuntime
|
|||
JS::gcreason::Reason reason);
|
||||
bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
|
||||
void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
|
||||
AutoTraceSession& session);
|
||||
AutoGCSession& session);
|
||||
|
||||
friend class AutoCallGCCallbacks;
|
||||
void maybeCallGCCallback(JSGCStatus status);
|
||||
|
||||
void pushZealSelectedObjects();
|
||||
void purgeRuntime();
|
||||
MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason, AutoTraceSession& session);
|
||||
bool prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut,
|
||||
AutoLockForExclusiveAccess& lock);
|
||||
MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason, AutoGCSession& session);
|
||||
bool prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut);
|
||||
bool shouldPreserveJITCode(JS::Realm* realm, int64_t currentTime,
|
||||
JS::gcreason::Reason reason, bool canAllocateMoreCode);
|
||||
void traceRuntimeForMajorGC(JSTracer* trc, AutoTraceSession& session);
|
||||
void traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock);
|
||||
void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
|
||||
void traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& atomsAccess);
|
||||
void traceKeptAtoms(JSTracer* trc);
|
||||
void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
|
||||
AutoTraceSession& session);
|
||||
void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark);
|
||||
void maybeDoCycleCollection();
|
||||
void markCompartments();
|
||||
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::PhaseKind phase);
|
||||
|
@ -585,7 +585,7 @@ class GCRuntime
|
|||
void markAllWeakReferences(gcstats::PhaseKind phase);
|
||||
void markAllGrayReferences(gcstats::PhaseKind phase);
|
||||
|
||||
void beginSweepPhase(JS::gcreason::Reason reason, AutoTraceSession& session);
|
||||
void beginSweepPhase(JS::gcreason::Reason reason, AutoGCSession& session);
|
||||
void groupZonesForSweeping(JS::gcreason::Reason reason);
|
||||
MOZ_MUST_USE bool findInterZoneEdges();
|
||||
void getNextSweepGroup();
|
||||
|
@ -618,7 +618,7 @@ class GCRuntime
|
|||
bool shouldCompact();
|
||||
void beginCompactPhase();
|
||||
IncrementalProgress compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
||||
AutoTraceSession& session);
|
||||
AutoGCSession& session);
|
||||
void endCompactPhase();
|
||||
void sweepTypesAfterCompacting(Zone* zone);
|
||||
void sweepZoneAfterCompacting(Zone* zone);
|
||||
|
@ -628,14 +628,14 @@ class GCRuntime
|
|||
void updateCellPointers(Zone* zone, AllocKinds kinds, size_t bgTaskCount);
|
||||
void updateAllCellPointers(MovingTracer* trc, Zone* zone);
|
||||
void updateZonePointersToRelocatedCells(Zone* zone);
|
||||
void updateRuntimePointersToRelocatedCells(AutoTraceSession& session);
|
||||
void updateRuntimePointersToRelocatedCells(AutoGCSession& session);
|
||||
void protectAndHoldArenas(Arena* arenaList);
|
||||
void unprotectHeldRelocatedArenas();
|
||||
void releaseRelocatedArenas(Arena* arenaList);
|
||||
void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLockGC& lock);
|
||||
void finishCollection();
|
||||
|
||||
void computeNonIncrementalMarkingForValidation(AutoTraceSession& session);
|
||||
void computeNonIncrementalMarkingForValidation(AutoGCSession& session);
|
||||
void validateIncrementalMarking();
|
||||
void finishMarkingValidation();
|
||||
|
||||
|
@ -992,7 +992,6 @@ class GCRuntime
|
|||
|
||||
friend class js::GCHelperState;
|
||||
friend class MarkingValidator;
|
||||
friend class AutoTraceSession;
|
||||
friend class AutoEnterIteration;
|
||||
};
|
||||
|
||||
|
|
|
@ -2563,7 +2563,7 @@ GCMarker::checkZone(void* p)
|
|||
|
||||
size_t
|
||||
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
const AutoLockForExclusiveAccess& lock) const
|
||||
const AutoAccessAtomsZone& access) const
|
||||
{
|
||||
size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
|
||||
|
|
|
@ -772,7 +772,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
|
|||
}
|
||||
}
|
||||
|
||||
mozilla::Maybe<AutoTraceSession> session;
|
||||
mozilla::Maybe<AutoGCSession> session;
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
|
||||
if (!session.isSome())
|
||||
|
@ -846,7 +846,7 @@ void
|
|||
js::Nursery::doCollection(JS::gcreason::Reason reason, TenureCountCache& tenureCounts)
|
||||
{
|
||||
JSRuntime* rt = runtime();
|
||||
AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
|
||||
AutoGCSession session(rt, JS::HeapState::MinorCollecting);
|
||||
AutoSetThreadIsPerformingGC performingGC;
|
||||
AutoStopVerifyingBarriers av(rt, false);
|
||||
AutoDisableProxyCheck disableStrictProxyChecking;
|
||||
|
|
|
@ -51,7 +51,7 @@ js::IterateHeapUnbarriered(JSContext* cx, void* data,
|
|||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback)
|
||||
{
|
||||
AutoPrepareForTracing prop(cx);
|
||||
AutoPrepareForTracing prep(cx);
|
||||
|
||||
for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) {
|
||||
(*zoneCallback)(cx->runtime(), data, zone);
|
||||
|
@ -67,7 +67,7 @@ js::IterateHeapUnbarrieredForZone(JSContext* cx, Zone* zone, void* data,
|
|||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback)
|
||||
{
|
||||
AutoPrepareForTracing prop(cx);
|
||||
AutoPrepareForTracing prep(cx);
|
||||
|
||||
(*zoneCallback)(cx->runtime(), data, zone);
|
||||
IterateRealmsArenasCellsUnbarriered(cx, zone, data,
|
||||
|
|
|
@ -262,10 +262,9 @@ PropertyDescriptor::trace(JSTracer* trc)
|
|||
}
|
||||
|
||||
void
|
||||
js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoTraceSession& session)
|
||||
js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session)
|
||||
{
|
||||
MOZ_ASSERT(!TlsContext.get()->suppressGC);
|
||||
MOZ_ASSERT_IF(atomsZone->isCollecting(), session.maybeLock.isSome());
|
||||
|
||||
// FinishRoots will have asserted that every root that we do not expect
|
||||
// is gone, so we can simply skip traceRuntime here.
|
||||
|
@ -274,14 +273,14 @@ js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoTraceSession& sessi
|
|||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
if (atomsZone->isCollecting())
|
||||
traceRuntimeAtoms(trc, session.lock());
|
||||
traceRuntimeAtoms(trc, session.checkAtomsAccess());
|
||||
traceKeptAtoms(trc);
|
||||
Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(trc);
|
||||
traceRuntimeCommon(trc, MarkRuntime, session);
|
||||
traceRuntimeCommon(trc, MarkRuntime);
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoTraceSession& session)
|
||||
js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoGCSession& session)
|
||||
{
|
||||
MOZ_ASSERT(!TlsContext.get()->suppressGC);
|
||||
|
||||
|
@ -296,7 +295,7 @@ js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoTraceSession& sessi
|
|||
|
||||
jit::JitRuntime::TraceJitcodeGlobalTableForMinorGC(trc);
|
||||
|
||||
traceRuntimeCommon(trc, TraceRuntime, session);
|
||||
traceRuntimeCommon(trc, TraceRuntime);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -308,7 +307,7 @@ js::TraceRuntime(JSTracer* trc)
|
|||
rt->gc.evictNursery();
|
||||
AutoPrepareForTracing prep(rt->mainContextFromOwnThread());
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
rt->gc.traceRuntime(trc, prep.session());
|
||||
rt->gc.traceRuntime(trc, prep);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -317,18 +316,19 @@ js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoTraceSession& session)
|
|||
MOZ_ASSERT(!rt->isBeingDestroyed());
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
traceRuntimeAtoms(trc, session.lock());
|
||||
traceRuntimeCommon(trc, TraceRuntime, session);
|
||||
|
||||
traceRuntimeAtoms(trc, session);
|
||||
traceRuntimeCommon(trc, TraceRuntime);
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
||||
js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& access)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA);
|
||||
TracePermanentAtoms(trc);
|
||||
TraceAtoms(trc, lock);
|
||||
TraceAtoms(trc, access);
|
||||
TraceWellKnownSymbols(trc);
|
||||
jit::JitRuntime::Trace(trc, lock);
|
||||
jit::JitRuntime::Trace(trc, access);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -344,8 +344,7 @@ js::gc::GCRuntime::traceKeptAtoms(JSTracer* trc)
|
|||
}
|
||||
|
||||
void
|
||||
js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
|
||||
AutoTraceSession& session)
|
||||
js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark)
|
||||
{
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
|
||||
|
@ -386,7 +385,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
|||
r->traceRoots(trc, traceOrMark);
|
||||
|
||||
// Trace helper thread roots.
|
||||
HelperThreadState().trace(trc, session);
|
||||
HelperThreadState().trace(trc);
|
||||
|
||||
// Trace the embedding's black and gray roots.
|
||||
if (!JS::RuntimeHeapIsMinorCollecting()) {
|
||||
|
@ -450,9 +449,9 @@ js::gc::GCRuntime::finishRoots()
|
|||
grayRootTracer = Callback<JSTraceDataOp>(nullptr, nullptr);
|
||||
|
||||
AssertNoRootsTracer trc(rt, TraceWeakMapKeysValues);
|
||||
AutoPrepareForTracing prep(TlsContext.get());
|
||||
AutoTraceSession session(rt);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
traceRuntime(&trc, prep.session());
|
||||
traceRuntime(&trc, session);
|
||||
|
||||
// Restore the wrapper tracing so that we leak instead of leaving dangling
|
||||
// pointers.
|
||||
|
|
|
@ -221,7 +221,7 @@ gc::GCRuntime::startVerifyPreBarriers()
|
|||
incrementalState = State::MarkRoots;
|
||||
|
||||
/* Make all the roots be edges emanating from the root node. */
|
||||
traceRuntime(trc, prep.session());
|
||||
traceRuntime(trc, prep);
|
||||
|
||||
VerifyNode* node;
|
||||
node = trc->curnode;
|
||||
|
@ -655,7 +655,7 @@ CheckHeapTracer::check(AutoTraceSession& session)
|
|||
void
|
||||
js::gc::CheckHeapAfterGC(JSRuntime* rt)
|
||||
{
|
||||
AutoTraceSession session(rt, JS::HeapState::Tracing);
|
||||
AutoTraceSession session(rt);
|
||||
CheckHeapTracer tracer(rt);
|
||||
if (tracer.init())
|
||||
tracer.check(session);
|
||||
|
@ -724,7 +724,7 @@ js::CheckGrayMarkingState(JSRuntime* rt)
|
|||
return true;
|
||||
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
AutoTraceSession session(rt, JS::HeapState::Tracing);
|
||||
AutoTraceSession session(rt);
|
||||
CheckGrayMarkingTracer tracer(rt);
|
||||
if (!tracer.init())
|
||||
return true; // Ignore failure
|
||||
|
|
|
@ -61,12 +61,12 @@ JS::Zone::Zone(JSRuntime* rt)
|
|||
data(this, nullptr),
|
||||
isSystem(this, false),
|
||||
#ifdef DEBUG
|
||||
gcLastSweepGroupIndex(this, 0),
|
||||
gcLastSweepGroupIndex(0),
|
||||
#endif
|
||||
jitZone_(this, nullptr),
|
||||
gcScheduled_(false),
|
||||
gcScheduledSaved_(false),
|
||||
gcPreserveCode_(this, false),
|
||||
gcPreserveCode_(false),
|
||||
keepShapeTables_(this, false),
|
||||
listNext_(NotOnList)
|
||||
{
|
||||
|
|
|
@ -583,7 +583,7 @@ class Zone : public JS::shadow::Zone,
|
|||
js::ZoneData<bool> isSystem;
|
||||
|
||||
#ifdef DEBUG
|
||||
js::ZoneData<unsigned> gcLastSweepGroupIndex;
|
||||
js::MainThreadData<unsigned> gcLastSweepGroupIndex;
|
||||
#endif
|
||||
|
||||
static js::HashNumber UniqueIdToHash(uint64_t uid) {
|
||||
|
@ -737,11 +737,11 @@ class Zone : public JS::shadow::Zone,
|
|||
uint32_t detachedTypedObjects = 0;
|
||||
|
||||
private:
|
||||
js::ZoneData<js::jit::JitZone*> jitZone_;
|
||||
js::ZoneOrGCTaskData<js::jit::JitZone*> jitZone_;
|
||||
|
||||
js::MainThreadData<bool> gcScheduled_;
|
||||
js::MainThreadData<bool> gcScheduledSaved_;
|
||||
js::ZoneData<bool> gcPreserveCode_;
|
||||
js::MainThreadData<bool> gcPreserveCode_;
|
||||
js::ZoneData<bool> keepShapeTables_;
|
||||
|
||||
// Allow zones to be linked into a list
|
||||
|
|
|
@ -582,7 +582,7 @@ jit::LazyLinkTopActivation(JSContext* cx, LazyLinkExitFrameLayout* frame)
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
JitRuntime::Trace(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
||||
JitRuntime::Trace(JSTracer* trc, const AutoAccessAtomsZone& access)
|
||||
{
|
||||
MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
|
||||
|
||||
|
@ -591,7 +591,7 @@ JitRuntime::Trace(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
|||
if (trc->runtime()->atomsAreFinished())
|
||||
return;
|
||||
|
||||
Zone* zone = trc->runtime()->atomsZone(lock);
|
||||
Zone* zone = trc->runtime()->atomsZone(access);
|
||||
for (auto i = zone->cellIter<JitCode>(); !i.done(); i.next()) {
|
||||
JitCode* code = i;
|
||||
TraceRoot(trc, &code, "wrapper");
|
||||
|
|
|
@ -193,7 +193,7 @@ class JitRuntime
|
|||
~JitRuntime();
|
||||
MOZ_MUST_USE bool initialize(JSContext* cx, js::AutoLockForExclusiveAccess& lock);
|
||||
|
||||
static void Trace(JSTracer* trc, js::AutoLockForExclusiveAccess& lock);
|
||||
static void Trace(JSTracer* trc, const js::AutoAccessAtomsZone& access);
|
||||
static void TraceJitcodeGlobalTableForMinorGC(JSTracer* trc);
|
||||
static MOZ_MUST_USE bool MarkJitcodeGlobalTableIteratively(GCMarker* marker);
|
||||
static void SweepJitcodeGlobalTable(JSRuntime* rt);
|
||||
|
|
|
@ -1252,9 +1252,9 @@ js::DumpHeap(JSContext* cx, FILE* fp, js::DumpHeapNurseryBehaviour nurseryBehavi
|
|||
fprintf(dtrc.output, "# Roots.\n");
|
||||
{
|
||||
JSRuntime* rt = cx->runtime();
|
||||
js::gc::AutoPrepareForTracing prep(cx);
|
||||
js::gc::AutoTraceSession session(rt);
|
||||
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
|
||||
rt->gc.traceRuntime(&dtrc, prep.session());
|
||||
rt->gc.traceRuntime(&dtrc, session);
|
||||
}
|
||||
|
||||
fprintf(dtrc.output, "# Weak maps.\n");
|
||||
|
|
|
@ -65,17 +65,19 @@ CheckZone<Helper>::check() const
|
|||
if (OnHelperThread<Helper>())
|
||||
return;
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
JSRuntime* runtime = TlsContext.get()->runtime();
|
||||
if (zone->isAtomsZone()) {
|
||||
// The atoms zone is protected by the exclusive access lock.
|
||||
MOZ_ASSERT(cx->runtime()->currentThreadHasExclusiveAccess());
|
||||
// The atoms zone is protected by the exclusive access lock, but can be
|
||||
// also accessed when off-thread parsing is blocked.
|
||||
MOZ_ASSERT(runtime->currentThreadHasExclusiveAccess() ||
|
||||
(!runtime->isOffThreadParseRunning() && runtime->isOffThreadParsingBlocked()));
|
||||
} else if (zone->usedByHelperThread()) {
|
||||
// This may only be accessed by the helper thread using this zone.
|
||||
MOZ_ASSERT(zone->ownedByCurrentHelperThread());
|
||||
} else {
|
||||
// The main thread is permitted access to all zones. These accesses
|
||||
// are threadsafe if the zone is not in use by a helper thread.
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,24 @@
|
|||
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# include <pthread_np.h>
|
||||
# endif
|
||||
# if defined(SOLARIS) || defined(AIX)
|
||||
# include <ucontext.h>
|
||||
# endif
|
||||
# if defined(ANDROID) && !defined(__aarch64__)
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
# if defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
|
||||
# include <dlfcn.h>
|
||||
# include <sys/syscall.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
static pid_t
|
||||
gettid()
|
||||
{
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
# error "Unsupported platform"
|
||||
#endif
|
||||
|
@ -34,8 +48,6 @@ js::GetNativeStackBaseImpl()
|
|||
|
||||
#elif defined(SOLARIS)
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0);
|
||||
|
||||
void*
|
||||
|
@ -48,8 +60,6 @@ js::GetNativeStackBaseImpl()
|
|||
|
||||
#elif defined(AIX)
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0);
|
||||
|
||||
void*
|
||||
|
@ -61,6 +71,52 @@ js::GetNativeStackBaseImpl()
|
|||
context.uc_stack.ss_size;
|
||||
}
|
||||
|
||||
#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
|
||||
void*
|
||||
js::GetNativeStackBaseImpl()
|
||||
{
|
||||
|
||||
// On the main thread, get stack base from glibc's __libc_stack_end rather than pthread APIs
|
||||
// to avoid filesystem calls /proc/self/maps. Non-main threads spawned with pthreads can read
|
||||
// this information directly from their pthread struct, but the main thread must go parse
|
||||
// /proc/self/maps to figure the mapped stack address space ranges. We want to avoid reading
|
||||
// from /proc/ so that firefox can run in sandboxed environments where /proc may not be mounted
|
||||
if (gettid() == getpid()) {
|
||||
void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end");
|
||||
|
||||
// If __libc_stack_end is not found, architecture specific frame pointer hopping will need
|
||||
// to be implemented.
|
||||
MOZ_RELEASE_ASSERT(pLibcStackEnd, "__libc_stack_end unavailable, unable to setup stack range for JS");
|
||||
void* stackBase = *pLibcStackEnd;
|
||||
MOZ_RELEASE_ASSERT(stackBase, "invalid stack base, unable to setup stack range for JS");
|
||||
|
||||
// We don't need to fix stackBase, as it already roughly points to beginning of the stack
|
||||
return stackBase;
|
||||
}
|
||||
|
||||
// Non-main threads have the required info stored in memory, so no filesystem calls are made.
|
||||
pthread_t thread = pthread_self();
|
||||
pthread_attr_t sattr;
|
||||
pthread_attr_init(&sattr);
|
||||
pthread_getattr_np(thread, &sattr);
|
||||
|
||||
// stackBase will be the *lowest* address on all architectures.
|
||||
void* stackBase = nullptr;
|
||||
size_t stackSize = 0;
|
||||
int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
|
||||
if (rc) {
|
||||
MOZ_CRASH("call to pthread_attr_getstack failed, unable to setup stack range for JS");
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(stackBase, "invalid stack base, unable to setup stack range for JS");
|
||||
pthread_attr_destroy(&sattr);
|
||||
|
||||
# if JS_STACK_GROWTH_DIRECTION > 0
|
||||
return stackBase;
|
||||
# else
|
||||
return static_cast<char*>(stackBase) + stackSize;
|
||||
# endif
|
||||
}
|
||||
|
||||
#else /* XP_UNIX */
|
||||
|
||||
void*
|
||||
|
|
|
@ -2896,6 +2896,7 @@ GenerateLcovInfo(JSContext* cx, JS::Realm* realm, GenericPrinter& out)
|
|||
{
|
||||
js::gc::AutoPrepareForTracing apft(cx);
|
||||
}
|
||||
|
||||
Rooted<ScriptVector> topScripts(cx, ScriptVector(cx));
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (auto script = zone->cellIter<JSScript>(); !script.done(); script.next()) {
|
||||
|
|
|
@ -2099,9 +2099,12 @@ HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
|
|||
currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy());
|
||||
ParseTask* task = parseTask();
|
||||
|
||||
JSRuntime* runtime = task->parseGlobal->runtimeFromAnyThread();
|
||||
runtime->incOffThreadParsesRunning();
|
||||
|
||||
{
|
||||
AutoUnlockHelperThreadState unlock(locked);
|
||||
AutoSetContextRuntime ascr(task->parseGlobal->runtimeFromAnyThread());
|
||||
AutoSetContextRuntime ascr(runtime);
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
|
||||
|
@ -2125,6 +2128,8 @@ HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
|
|||
// migrate it into the correct compartment.
|
||||
HelperThreadState().parseFinishedList(locked).insertBack(task);
|
||||
|
||||
runtime->decOffThreadParsesRunning();
|
||||
|
||||
currentTask.reset();
|
||||
|
||||
// Notify the main thread in case it is waiting for the parse/emit to finish.
|
||||
|
@ -2267,7 +2272,7 @@ js::StartOffThreadPromiseHelperTask(PromiseHelperTask* task)
|
|||
}
|
||||
|
||||
void
|
||||
GlobalHelperThreadState::trace(JSTracer* trc, gc::AutoTraceSession& session)
|
||||
GlobalHelperThreadState::trace(JSTracer* trc)
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
for (auto builder : ionWorklist(lock))
|
||||
|
|
|
@ -311,7 +311,7 @@ class GlobalHelperThreadState
|
|||
|
||||
void mergeParseTaskRealm(JSContext* cx, ParseTask* parseTask, JS::Realm* dest);
|
||||
|
||||
void trace(JSTracer* trc, js::gc::AutoTraceSession& session);
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
JSScript* finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token);
|
||||
JSScript* finishScriptDecodeTask(JSContext* cx, JS::OffThreadToken* token);
|
||||
|
|
|
@ -255,14 +255,14 @@ TracePinnedAtoms(JSTracer* trc, const AtomSet& atoms)
|
|||
}
|
||||
|
||||
void
|
||||
js::TraceAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
||||
js::TraceAtoms(JSTracer* trc, const AutoAccessAtomsZone& access)
|
||||
{
|
||||
JSRuntime* rt = trc->runtime();
|
||||
|
||||
if (rt->atomsAreFinished())
|
||||
return;
|
||||
|
||||
TracePinnedAtoms(trc, rt->atoms(lock));
|
||||
TracePinnedAtoms(trc, rt->atoms(access));
|
||||
if (rt->atomsAddedWhileSweeping())
|
||||
TracePinnedAtoms(trc, *rt->atomsAddedWhileSweeping());
|
||||
}
|
||||
|
|
|
@ -39,13 +39,13 @@ FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
|
|||
|
||||
namespace js {
|
||||
|
||||
class AutoLockForExclusiveAccess;
|
||||
class AutoAccessAtomsZone;
|
||||
|
||||
/*
|
||||
* Atom tracing and garbage collection hooks.
|
||||
*/
|
||||
void
|
||||
TraceAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock);
|
||||
TraceAtoms(JSTracer* trc, const AutoAccessAtomsZone& atomsAccess);
|
||||
|
||||
void
|
||||
TracePermanentAtoms(JSTracer* trc);
|
||||
|
|
|
@ -34,6 +34,7 @@ class DebugModeOSRVolatileJitFrameIter;
|
|||
} // namespace jit
|
||||
|
||||
namespace gc {
|
||||
class AutoCheckCanAccessAtomsDuringGC;
|
||||
class AutoSuppressNurseryCellAlloc;
|
||||
}
|
||||
|
||||
|
@ -264,14 +265,14 @@ struct JSContext : public JS::RootingContext,
|
|||
inline js::Handle<js::GlobalObject*> global() const;
|
||||
|
||||
// Methods to access runtime data that must be protected by locks.
|
||||
js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
|
||||
return runtime_->atoms(lock);
|
||||
js::AtomSet& atoms(const js::AutoAccessAtomsZone& access) {
|
||||
return runtime_->atoms(access);
|
||||
}
|
||||
const JS::Zone* atomsZone(js::AutoLockForExclusiveAccess& lock) {
|
||||
return runtime_->atomsZone(lock);
|
||||
const JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) {
|
||||
return runtime_->atomsZone(access);
|
||||
}
|
||||
js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
|
||||
return runtime_->symbolRegistry(lock);
|
||||
js::SymbolRegistry& symbolRegistry(const js::AutoAccessAtomsZone& access) {
|
||||
return runtime_->symbolRegistry(access);
|
||||
}
|
||||
js::ScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
|
||||
return runtime_->scriptDataTable(lock);
|
||||
|
@ -540,6 +541,8 @@ struct JSContext : public JS::RootingContext,
|
|||
js::ThreadData<unsigned> compactingDisabledCount;
|
||||
|
||||
bool canCollectAtoms() const {
|
||||
// TODO: We may be able to improve this by collecting if
|
||||
// !isOffThreadParseRunning() (bug 1468422).
|
||||
return !runtime()->hasHelperThreadZones();
|
||||
}
|
||||
|
||||
|
@ -1170,6 +1173,22 @@ class MOZ_RAII AutoLockScriptData
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
// A token used to prove you can safely access the atoms zone. This zone is
|
||||
// accessed by the main thread and by off-thread parsing. There are two
|
||||
// situations in which it is safe:
|
||||
//
|
||||
// - the current thread holds the exclusive access lock (off-thread parsing may
|
||||
// be running and this must also take the lock for access)
|
||||
//
|
||||
// - the GC is running and is collecting the atoms zone (this cannot be started
|
||||
// while off-thread parsing is happening)
|
||||
class MOZ_STACK_CLASS AutoAccessAtomsZone
|
||||
{
|
||||
public:
|
||||
MOZ_IMPLICIT AutoAccessAtomsZone(const AutoLockForExclusiveAccess& lock) {}
|
||||
MOZ_IMPLICIT AutoAccessAtomsZone(const gc::AutoCheckCanAccessAtomsDuringGC& canAccess) {}
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoKeepAtoms
|
||||
{
|
||||
JSContext* cx;
|
||||
|
|
|
@ -166,6 +166,10 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
jitSupportsSimd(false),
|
||||
offthreadIonCompilationEnabled_(true),
|
||||
parallelParsingEnabled_(true),
|
||||
#ifdef DEBUG
|
||||
offThreadParsesRunning_(0),
|
||||
offThreadParsingBlocked_(false),
|
||||
#endif
|
||||
autoWritableJitCodeActive_(false),
|
||||
oomCallback(nullptr),
|
||||
debuggerMallocSizeOf(ReturnZeroSize),
|
||||
|
@ -808,6 +812,7 @@ JSRuntime::setUsedByHelperThread(Zone* zone)
|
|||
{
|
||||
MOZ_ASSERT(!zone->usedByHelperThread());
|
||||
MOZ_ASSERT(!zone->wasGCStarted());
|
||||
MOZ_ASSERT(!isOffThreadParsingBlocked());
|
||||
zone->setUsedByHelperThread();
|
||||
numActiveHelperThreadZones++;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ class EnterDebuggeeNoExecute;
|
|||
class TraceLoggerThread;
|
||||
#endif
|
||||
|
||||
namespace gc {
|
||||
class AutoHeapSession;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
struct DtoaState;
|
||||
|
@ -702,15 +706,15 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
private:
|
||||
// Set of all atoms other than those in permanentAtoms and staticStrings.
|
||||
// Reading or writing this set requires the calling thread to use
|
||||
// AutoLockForExclusiveAccess.
|
||||
// AutoAccessAtomsZone.
|
||||
js::ExclusiveAccessLockOrGCTaskData<js::AtomSet*> atoms_;
|
||||
|
||||
// Set of all atoms added while the main atoms table is being swept.
|
||||
js::ExclusiveAccessLockData<js::AtomSet*> atomsAddedWhileSweeping_;
|
||||
js::ExclusiveAccessLockOrGCTaskData<js::AtomSet*> atomsAddedWhileSweeping_;
|
||||
|
||||
// Set of all live symbols produced by Symbol.for(). All such symbols are
|
||||
// allocated in the atomsZone. Reading or writing the symbol registry
|
||||
// requires the calling thread to use AutoLockForExclusiveAccess.
|
||||
// allocated in the atoms zone. Reading or writing the symbol registry
|
||||
// requires the calling thread to use AutoAccessAtomsZone.
|
||||
js::ExclusiveAccessLockOrGCTaskData<js::SymbolRegistry> symbolRegistry_;
|
||||
|
||||
public:
|
||||
|
@ -723,7 +727,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
return atoms_;
|
||||
}
|
||||
|
||||
js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
|
||||
js::AtomSet& atoms(const js::AutoAccessAtomsZone& access) {
|
||||
MOZ_ASSERT(atoms_);
|
||||
return *atoms_;
|
||||
}
|
||||
|
@ -738,10 +742,10 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
return atomsAddedWhileSweeping_;
|
||||
}
|
||||
|
||||
const JS::Zone* atomsZone(const js::AutoLockForExclusiveAccess& lock) const {
|
||||
const JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) const {
|
||||
return gc.atomsZone;
|
||||
}
|
||||
JS::Zone* atomsZone(const js::AutoLockForExclusiveAccess& lock) {
|
||||
JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) {
|
||||
return gc.atomsZone;
|
||||
}
|
||||
JS::Zone* unsafeAtomsZone() {
|
||||
|
@ -754,7 +758,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
|
||||
bool activeGCInAtomsZone();
|
||||
|
||||
js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
|
||||
js::SymbolRegistry& symbolRegistry(const js::AutoAccessAtomsZone& access) {
|
||||
return symbolRegistry_.ref();
|
||||
}
|
||||
js::SymbolRegistry& unsafeSymbolRegistry() {
|
||||
|
@ -857,6 +861,11 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
|
||||
mozilla::Atomic<bool> parallelParsingEnabled_;
|
||||
|
||||
#ifdef DEBUG
|
||||
mozilla::Atomic<uint32_t> offThreadParsesRunning_;
|
||||
mozilla::Atomic<bool> offThreadParsingBlocked_;
|
||||
#endif
|
||||
|
||||
js::MainThreadData<bool> autoWritableJitCodeActive_;
|
||||
|
||||
public:
|
||||
|
@ -876,6 +885,38 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
return parallelParsingEnabled_;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
bool isOffThreadParseRunning() const {
|
||||
return offThreadParsesRunning_;
|
||||
}
|
||||
|
||||
void incOffThreadParsesRunning() {
|
||||
MOZ_ASSERT(!isOffThreadParsingBlocked());
|
||||
offThreadParsesRunning_++;
|
||||
}
|
||||
|
||||
void decOffThreadParsesRunning() {
|
||||
MOZ_ASSERT(isOffThreadParseRunning());
|
||||
offThreadParsesRunning_--;
|
||||
}
|
||||
|
||||
bool isOffThreadParsingBlocked() const {
|
||||
return offThreadParsingBlocked_;
|
||||
}
|
||||
void setOffThreadParsingBlocked(bool blocked) {
|
||||
MOZ_ASSERT(offThreadParsingBlocked_ != blocked);
|
||||
MOZ_ASSERT(!isOffThreadParseRunning());
|
||||
offThreadParsingBlocked_ = blocked;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void incOffThreadParsesRunning() {}
|
||||
void decOffThreadParsesRunning() {}
|
||||
|
||||
#endif
|
||||
|
||||
void toggleAutoWritableJitCodeActive(bool b) {
|
||||
MOZ_ASSERT(autoWritableJitCodeActive_ != b, "AutoWritableJitCode should not be nested.");
|
||||
autoWritableJitCodeActive_ = b;
|
||||
|
@ -921,7 +962,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
}
|
||||
|
||||
// For inherited heap state accessors.
|
||||
friend class js::gc::AutoTraceSession;
|
||||
friend class js::gc::AutoHeapSession;
|
||||
friend class JS::AutoEnterCycleCollection;
|
||||
|
||||
private:
|
||||
|
|
|
@ -20,9 +20,9 @@ using namespace js;
|
|||
|
||||
Symbol*
|
||||
Symbol::newInternal(JSContext* cx, JS::SymbolCode code, uint32_t hash, JSAtom* description,
|
||||
AutoLockForExclusiveAccess& lock)
|
||||
const AutoAccessAtomsZone& access)
|
||||
{
|
||||
MOZ_ASSERT(cx->zone() == cx->atomsZone(lock));
|
||||
MOZ_ASSERT(cx->zone() == cx->atomsZone(access));
|
||||
|
||||
// Following js::AtomizeString, we grudgingly forgo last-ditch GC here.
|
||||
Symbol* p = Allocate<JS::Symbol, NoGC>(cx);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "vm/StringType.h"
|
||||
|
||||
namespace js {
|
||||
class AutoLockForExclusiveAccess;
|
||||
class AutoAccessAtomsZone;
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
@ -60,7 +60,7 @@ class Symbol : public js::gc::TenuredCell
|
|||
|
||||
static Symbol*
|
||||
newInternal(JSContext* cx, SymbolCode code, js::HashNumber hash,
|
||||
JSAtom* description, js::AutoLockForExclusiveAccess& lock);
|
||||
JSAtom* description, const js::AutoAccessAtomsZone& access);
|
||||
|
||||
public:
|
||||
static Symbol* new_(JSContext* cx, SymbolCode code, JSString* description);
|
||||
|
|
|
@ -511,12 +511,6 @@ SERVO_BINDING_FUNC(Servo_AnimationValue_Compute,
|
|||
ComputedStyleBorrowed style,
|
||||
RawServoStyleSetBorrowed raw_data)
|
||||
|
||||
// There's no reason we couldn't expose more stuff here, but GetCssText is
|
||||
// pretty much all we'd ever want.
|
||||
SERVO_BINDING_FUNC(Servo_UnlockedDeclarationBlock_GetCssText, void,
|
||||
const RawServoUnlockedDeclarationBlock* declarations,
|
||||
nsAString* result)
|
||||
|
||||
// Style attribute
|
||||
SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
|
||||
const nsACString* data,
|
||||
|
|
|
@ -83,19 +83,12 @@ typedef nsTArray<nsCSSPropertyID> RawGeckoCSSPropertyIDList;
|
|||
typedef mozilla::gfx::Float RawGeckoGfxMatrix4x4[16];
|
||||
typedef mozilla::dom::StyleChildrenIterator RawGeckoStyleChildrenIterator;
|
||||
|
||||
// A struct which to be used as an opaque pointer to a DeclarationBlock that has
|
||||
// been read.
|
||||
//
|
||||
// This is effectively a *const PropertyDeclarationBlock in Rust.
|
||||
struct RawServoUnlockedDeclarationBlock;
|
||||
|
||||
// A callback that can be sent via FFI which will be invoked _right before_
|
||||
// being mutated, and at most once.
|
||||
struct DeclarationBlockMutationClosure
|
||||
{
|
||||
// The callback function, first argument is the unlocked servo declaration
|
||||
// block, second is `data`.
|
||||
void (*function)(const RawServoUnlockedDeclarationBlock*, void*) = nullptr;
|
||||
// The callback function. The argument is `data`.
|
||||
void (*function)(void*) = nullptr;
|
||||
void* data = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -425,7 +425,6 @@ mapped-generic-types = [
|
|||
{ generic = false, gecko = "mozilla::ServoComputedValueFlags", servo = "::properties::computed_value_flags::ComputedValueFlags" },
|
||||
{ generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::servo_arc::RawOffsetArc" },
|
||||
{ generic = false, gecko = "ComputedStyleStrong", servo = "::gecko_bindings::sugar::ownership::Strong<::properties::ComputedValues>" },
|
||||
{ generic = false, gecko = "RawServoUnlockedDeclarationBlock", servo = "::properties::PropertyDeclarationBlock" },
|
||||
]
|
||||
fixups = [
|
||||
{ pat = "\\broot\\s*::\\s*nsString\\b", rep = "::nsstring::nsStringRepr" },
|
||||
|
@ -469,7 +468,6 @@ structs-types = [
|
|||
"mozilla::UniquePtr",
|
||||
"ServoRawOffsetArc",
|
||||
"DeclarationBlockMutationClosure",
|
||||
"RawServoUnlockedDeclarationBlock",
|
||||
"nsIContent",
|
||||
"nsINode",
|
||||
"nsIDocument",
|
||||
|
|
|
@ -68,12 +68,13 @@ using namespace mozilla::dom;
|
|||
*/
|
||||
|
||||
already_AddRefed<nsComputedDOMStyle>
|
||||
NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
|
||||
nsIPresShell* aPresShell,
|
||||
NS_NewComputedDOMStyle(dom::Element* aElement,
|
||||
const nsAString& aPseudoElt,
|
||||
nsIDocument* aDocument,
|
||||
nsComputedDOMStyle::StyleType aStyleType)
|
||||
{
|
||||
RefPtr<nsComputedDOMStyle> computedStyle =
|
||||
new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, aStyleType);
|
||||
new nsComputedDOMStyle(aElement, aPseudoElt, aDocument, aStyleType);
|
||||
return computedStyle.forget();
|
||||
}
|
||||
|
||||
|
@ -117,7 +118,7 @@ DocumentNeedsRestyle(
|
|||
nsPresContext* presContext = shell->GetPresContext();
|
||||
MOZ_ASSERT(presContext);
|
||||
|
||||
// Unfortunately we don't know if the sheet change affects mContent or not, so
|
||||
// Unfortunately we don't know if the sheet change affects mElement or not, so
|
||||
// just assume it will and that we need to flush normally.
|
||||
ServoStyleSet* styleSet = shell->StyleSet();
|
||||
if (styleSet->StyleSheetsHaveChanged()) {
|
||||
|
@ -312,7 +313,7 @@ ComputedStyleMap::Update()
|
|||
|
||||
nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
|
||||
const nsAString& aPseudoElt,
|
||||
nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument,
|
||||
StyleType aStyleType)
|
||||
: mDocumentWeak(nullptr)
|
||||
, mOuterFrame(nullptr)
|
||||
|
@ -326,11 +327,12 @@ nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
|
|||
, mFlushedPendingReflows(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aElement && aPresShell);
|
||||
MOZ_ASSERT(aPresShell->GetPresContext());
|
||||
|
||||
mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
|
||||
mContent = aElement;
|
||||
MOZ_ASSERT(aElement);
|
||||
MOZ_ASSERT(aDocument);
|
||||
// TODO(emilio, bug 548397, https://github.com/w3c/csswg-drafts/issues/2403):
|
||||
// Should use aElement->OwnerDoc() instead.
|
||||
mDocumentWeak = do_GetWeakReference(aDocument);
|
||||
mElement = aElement;
|
||||
mPseudo = nsCSSPseudoElements::GetPseudoAtom(aPseudoElt);
|
||||
}
|
||||
|
||||
|
@ -342,13 +344,13 @@ nsComputedDOMStyle::~nsComputedDOMStyle()
|
|||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsComputedDOMStyle)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle)
|
||||
tmp->ClearComputedStyle(); // remove observer before clearing mContent
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
|
||||
tmp->ClearComputedStyle(); // remove observer before clearing mElement
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsComputedDOMStyle)
|
||||
|
@ -412,15 +414,17 @@ nsComputedDOMStyle::SetCssText(const nsAString& aCssText,
|
|||
uint32_t
|
||||
nsComputedDOMStyle::Length()
|
||||
{
|
||||
uint32_t length = GetComputedStyleMap()->Length();
|
||||
|
||||
// Make sure we have up to date style so that we can include custom
|
||||
// properties.
|
||||
UpdateCurrentStyleSources(false);
|
||||
if (mComputedStyle) {
|
||||
length += Servo_GetCustomPropertiesCount(mComputedStyle);
|
||||
if (!mComputedStyle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t length =
|
||||
GetComputedStyleMap()->Length() +
|
||||
Servo_GetCustomPropertiesCount(mComputedStyle);
|
||||
|
||||
ClearCurrentStyleSources();
|
||||
|
||||
return length;
|
||||
|
@ -452,7 +456,7 @@ nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
|
|||
const bool layoutFlushIsNeeded = entry && entry->IsLayoutFlushNeeded();
|
||||
UpdateCurrentStyleSources(layoutFlushIsNeeded);
|
||||
if (!mComputedStyle) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto cleanup = mozilla::MakeScopeExit([&] {
|
||||
|
@ -759,7 +763,6 @@ nsComputedDOMStyle::GetCSSImageURLs(const nsAString& aPropertyName,
|
|||
UpdateCurrentStyleSources(false);
|
||||
|
||||
if (!mComputedStyle) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -800,7 +803,7 @@ nsComputedDOMStyle::ClearComputedStyle()
|
|||
{
|
||||
if (mResolvedComputedStyle) {
|
||||
mResolvedComputedStyle = false;
|
||||
mContent->RemoveMutationObserver(this);
|
||||
mElement->RemoveMutationObserver(this);
|
||||
}
|
||||
mComputedStyle = nullptr;
|
||||
}
|
||||
|
@ -811,7 +814,7 @@ nsComputedDOMStyle::SetResolvedComputedStyle(RefPtr<ComputedStyle>&& aContext,
|
|||
{
|
||||
if (!mResolvedComputedStyle) {
|
||||
mResolvedComputedStyle = true;
|
||||
mContent->AddMutationObserver(this);
|
||||
mElement->AddMutationObserver(this);
|
||||
}
|
||||
mComputedStyle = aContext;
|
||||
mComputedStyleGeneration = aGeneration;
|
||||
|
@ -829,7 +832,7 @@ nsComputedDOMStyle::SetFrameComputedStyle(mozilla::ComputedStyle* aStyle,
|
|||
bool
|
||||
nsComputedDOMStyle::NeedsToFlush(nsIDocument* aDocument) const
|
||||
{
|
||||
// If mContent is not in the same document, we could do some checks to know if
|
||||
// If mElement is not in the same document, we could do some checks to know if
|
||||
// there are some pending restyles can be ignored across documents (since we
|
||||
// will use the caller document's style), but it can be complicated and should
|
||||
// be an edge case, so we just don't bother to do the optimization in this
|
||||
|
@ -837,10 +840,10 @@ nsComputedDOMStyle::NeedsToFlush(nsIDocument* aDocument) const
|
|||
//
|
||||
// FIXME(emilio): This is likely to want GetComposedDoc() instead of
|
||||
// OwnerDoc().
|
||||
if (aDocument != mContent->OwnerDoc()) {
|
||||
if (aDocument != mElement->OwnerDoc()) {
|
||||
return true;
|
||||
}
|
||||
if (DocumentNeedsRestyle(aDocument, mContent->AsElement(), mPseudo)) {
|
||||
if (DocumentNeedsRestyle(aDocument, mElement, mPseudo)) {
|
||||
return true;
|
||||
}
|
||||
// If parent document is there, also needs to check if there is some change
|
||||
|
@ -875,7 +878,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
if (needsToFlush) {
|
||||
// Flush _before_ getting the presshell, since that could create a new
|
||||
// presshell. Also note that we want to flush the style on the document
|
||||
// we're computing style in, not on the document mContent is in -- the two
|
||||
// we're computing style in, not on the document mElement is in -- the two
|
||||
// may be different.
|
||||
document->FlushPendingNotifications(
|
||||
aNeedsLayoutFlush ? FlushType::Layout : FlushType::Style);
|
||||
|
@ -886,7 +889,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
#endif
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShellForContent =
|
||||
nsContentUtils::GetPresShellForContent(mContent);
|
||||
nsContentUtils::GetPresShellForContent(mElement);
|
||||
if (presShellForContent && presShellForContent->GetDocument() != document) {
|
||||
presShellForContent->GetDocument()->FlushPendingNotifications(FlushType::Style);
|
||||
if (presShellForContent->IsDestroying()) {
|
||||
|
@ -913,13 +916,13 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
mPresShell->GetPresContext()->GetUndisplayedRestyleGeneration();
|
||||
|
||||
if (mComputedStyle) {
|
||||
// We can't rely on the undisplayed restyle generation if mContent is
|
||||
// We can't rely on the undisplayed restyle generation if mElement is
|
||||
// out-of-document, since that generation is not incremented for DOM changes
|
||||
// on out-of-document elements.
|
||||
//
|
||||
// So we always need to update the style to ensure it it up-to-date.
|
||||
if (mComputedStyleGeneration == currentGeneration
|
||||
&& mContent->IsInComposedDoc()) {
|
||||
if (mComputedStyleGeneration == currentGeneration &&
|
||||
mElement->IsInComposedDoc()) {
|
||||
// Our cached style is still valid.
|
||||
return;
|
||||
}
|
||||
|
@ -927,21 +930,21 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
mComputedStyle = nullptr;
|
||||
}
|
||||
|
||||
// XXX the !mContent->IsHTMLElement(nsGkAtoms::area)
|
||||
// XXX the !mElement->IsHTMLElement(nsGkAtoms::area)
|
||||
// check is needed due to bug 135040 (to avoid using
|
||||
// mPrimaryFrame). Remove it once that's fixed.
|
||||
if (mStyleType == eAll && !mContent->IsHTMLElement(nsGkAtoms::area)) {
|
||||
if (mStyleType == eAll && !mElement->IsHTMLElement(nsGkAtoms::area)) {
|
||||
mOuterFrame = nullptr;
|
||||
|
||||
if (!mPseudo) {
|
||||
mOuterFrame = mContent->GetPrimaryFrame();
|
||||
mOuterFrame = mElement->GetPrimaryFrame();
|
||||
} else if (mPseudo == nsCSSPseudoElements::before ||
|
||||
mPseudo == nsCSSPseudoElements::after) {
|
||||
nsAtom* property = mPseudo == nsCSSPseudoElements::before
|
||||
? nsGkAtoms::beforePseudoProperty
|
||||
: nsGkAtoms::afterPseudoProperty;
|
||||
|
||||
auto* pseudo = static_cast<Element*>(mContent->GetProperty(property));
|
||||
auto* pseudo = static_cast<Element*>(mElement->GetProperty(property));
|
||||
mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
|
@ -967,7 +970,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
// Need to resolve a style.
|
||||
RefPtr<ComputedStyle> resolvedComputedStyle =
|
||||
DoGetComputedStyleNoFlush(
|
||||
mContent->AsElement(),
|
||||
mElement,
|
||||
mPseudo,
|
||||
presShellForContent ? presShellForContent.get() : mPresShell,
|
||||
mStyleType);
|
||||
|
@ -5695,7 +5698,7 @@ nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
|
|||
|
||||
// lie about font size inflation since we lie about font size (since
|
||||
// the inflation only applies to text)
|
||||
aCoord = ReflowInput::CalcLineHeight(mContent,
|
||||
aCoord = ReflowInput::CalcLineHeight(mElement,
|
||||
mComputedStyle,
|
||||
presContext,
|
||||
blockHeight, 1.0f);
|
||||
|
@ -7174,7 +7177,7 @@ MarkComputedStyleMapDirty(const char* aPref, void* aData)
|
|||
void
|
||||
nsComputedDOMStyle::ParentChainChanged(nsIContent* aContent)
|
||||
{
|
||||
NS_ASSERTION(mContent == aContent, "didn't we register mContent?");
|
||||
NS_ASSERTION(mElement == aContent, "didn't we register mElement?");
|
||||
NS_ASSERTION(mResolvedComputedStyle,
|
||||
"should have only registered an observer when "
|
||||
"mResolvedComputedStyle is true");
|
||||
|
|
|
@ -80,12 +80,12 @@ public:
|
|||
|
||||
nsComputedDOMStyle(mozilla::dom::Element* aElement,
|
||||
const nsAString& aPseudoElt,
|
||||
nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument,
|
||||
StyleType aStyleType);
|
||||
|
||||
virtual nsINode *GetParentObject() override
|
||||
nsINode* GetParentObject() override
|
||||
{
|
||||
return mContent;
|
||||
return mElement;
|
||||
}
|
||||
|
||||
static already_AddRefed<mozilla::ComputedStyle>
|
||||
|
@ -718,9 +718,9 @@ private:
|
|||
|
||||
// We don't really have a good immutable representation of "presentation".
|
||||
// Given the way GetComputedStyle is currently used, we should just grab the
|
||||
// 0th presshell, if any, from the document.
|
||||
// presshell, if any, from the document.
|
||||
nsWeakPtr mDocumentWeak;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
RefPtr<mozilla::dom::Element> mElement;
|
||||
|
||||
/**
|
||||
* Strong reference to the ComputedStyle we access data from. This can be
|
||||
|
@ -786,7 +786,7 @@ private:
|
|||
already_AddRefed<nsComputedDOMStyle>
|
||||
NS_NewComputedDOMStyle(mozilla::dom::Element* aElement,
|
||||
const nsAString& aPseudoElt,
|
||||
nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument,
|
||||
nsComputedDOMStyle::StyleType aStyleType =
|
||||
nsComputedDOMStyle::eAll);
|
||||
|
||||
|
|
|
@ -33,13 +33,27 @@ INSTANTIATE(int, int, prim1, 2 * sizeof(int));
|
|||
INSTANTIATE(int, long, prim2, 2 * sizeof(long));
|
||||
|
||||
struct EmptyClass { explicit EmptyClass(int) {} };
|
||||
struct NonEmpty { char mC; explicit NonEmpty(int) {} };
|
||||
struct NonEmpty
|
||||
{
|
||||
char mC;
|
||||
explicit NonEmpty(int)
|
||||
: mC('\0')
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE(int, EmptyClass, both1, sizeof(int));
|
||||
INSTANTIATE(int, NonEmpty, both2, 2 * sizeof(int));
|
||||
INSTANTIATE(EmptyClass, NonEmpty, both3, 1);
|
||||
|
||||
struct A { char dummy; explicit A(int) {} };
|
||||
struct A
|
||||
{
|
||||
char dummy;
|
||||
explicit A(int)
|
||||
: dummy('\0')
|
||||
{
|
||||
}
|
||||
};
|
||||
struct B : A { explicit B(int aI) : A(aI) {} };
|
||||
|
||||
INSTANTIATE(A, A, class1, 2);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "CTPolicyEnforcer.h"
|
||||
#include "CTVerifyResult.h"
|
||||
#include "OCSPCache.h"
|
||||
#include "RootCertificateTelemetryUtils.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
@ -78,11 +79,16 @@ enum class NetscapeStepUpPolicy : uint32_t;
|
|||
class PinningTelemetryInfo
|
||||
{
|
||||
public:
|
||||
PinningTelemetryInfo() { Reset(); }
|
||||
PinningTelemetryInfo()
|
||||
: certPinningResultBucket(0)
|
||||
, rootBucket(ROOT_CERTIFICATE_UNKNOWN)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Should we accumulate pinning telemetry for the result?
|
||||
bool accumulateResult;
|
||||
Telemetry::HistogramID certPinningResultHistogram;
|
||||
Maybe<Telemetry::HistogramID> certPinningResultHistogram;
|
||||
int32_t certPinningResultBucket;
|
||||
// Should we accumulate telemetry for the root?
|
||||
bool accumulateForRoot;
|
||||
|
@ -94,7 +100,12 @@ public:
|
|||
class CertificateTransparencyInfo
|
||||
{
|
||||
public:
|
||||
CertificateTransparencyInfo() { Reset(); }
|
||||
CertificateTransparencyInfo()
|
||||
: enabled(false)
|
||||
, policyCompliance(mozilla::ct::CTPolicyCompliance::Unknown)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Was CT enabled?
|
||||
bool enabled;
|
||||
|
|
|
@ -305,7 +305,7 @@ CheckPinsForHostname(const RefPtr<nsNSSCertList>& certList, const char* hostname
|
|||
enforceTestModeResult ? 1 : 0;
|
||||
}
|
||||
pinningTelemetryInfo->accumulateResult = true;
|
||||
pinningTelemetryInfo->certPinningResultHistogram = histogram;
|
||||
pinningTelemetryInfo->certPinningResultHistogram = Some(histogram);
|
||||
}
|
||||
|
||||
// We only collect per-CA pinning statistics upon failures.
|
||||
|
|
|
@ -1431,7 +1431,8 @@ AuthCertificate(CertVerifier& certVerifier,
|
|||
}
|
||||
|
||||
if (pinningTelemetryInfo.accumulateResult) {
|
||||
Telemetry::Accumulate(pinningTelemetryInfo.certPinningResultHistogram,
|
||||
MOZ_ASSERT(pinningTelemetryInfo.certPinningResultHistogram.isSome());
|
||||
Telemetry::Accumulate(pinningTelemetryInfo.certPinningResultHistogram.value(),
|
||||
pinningTelemetryInfo.certPinningResultBucket);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ EXPORTS += [
|
|||
'nsRandomGenerator.h',
|
||||
'nsSecurityHeaderParser.h',
|
||||
'NSSErrorsService.h',
|
||||
'RootCertificateTelemetryUtils.h',
|
||||
'ScopedNSSTypes.h',
|
||||
'SharedCertVerifier.h',
|
||||
]
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
, stapledOCSPResponse(aStapledOCSPResponse)
|
||||
, subCACount(aSubCACount)
|
||||
, deferredSubjectError(aDeferredSubjectError)
|
||||
, subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized)
|
||||
, result(Result::FATAL_ERROR_LIBRARY_FAILURE)
|
||||
, resultWasSet(false)
|
||||
, buildForwardCallBudget(aBuildForwardCallBudget)
|
||||
|
|
|
@ -117,7 +117,11 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain,
|
|||
// for any curve that we support, the chances of us encountering a curve
|
||||
// during path building is too low to be worth bothering with.
|
||||
break;
|
||||
|
||||
case der::PublicKeyAlgorithm::Uninitialized:
|
||||
{
|
||||
assert(false);
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
|
||||
|
|
|
@ -457,7 +457,7 @@ CertificateSerialNumber(Reader& input, /*out*/ Input& value)
|
|||
|
||||
// x.509 and OCSP both use this same version numbering scheme, though OCSP
|
||||
// only supports v1.
|
||||
enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3 };
|
||||
enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3, Uninitialized = 255 };
|
||||
|
||||
// X.509 Certificate and OCSP ResponseData both use
|
||||
// "[0] EXPLICIT Version DEFAULT v1". Although an explicit encoding of v1 is
|
||||
|
@ -522,6 +522,7 @@ enum class PublicKeyAlgorithm
|
|||
{
|
||||
RSA_PKCS1,
|
||||
ECDSA,
|
||||
Uninitialized
|
||||
};
|
||||
|
||||
Result SignatureAlgorithmIdentifierValue(
|
||||
|
|
|
@ -42,11 +42,13 @@ class BackCert final
|
|||
{
|
||||
public:
|
||||
// certDER and childCert must be valid for the lifetime of BackCert.
|
||||
BackCert(Input aCertDER, EndEntityOrCA aEndEntityOrCA,
|
||||
BackCert(Input aCertDER,
|
||||
EndEntityOrCA aEndEntityOrCA,
|
||||
const BackCert* aChildCert)
|
||||
: der(aCertDER)
|
||||
, endEntityOrCA(aEndEntityOrCA)
|
||||
, childCert(aChildCert)
|
||||
, version(der::Version::Uninitialized)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@ VerifySignedDigest(TrustDomain& trustDomain,
|
|||
case der::PublicKeyAlgorithm::RSA_PKCS1:
|
||||
return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest,
|
||||
signerSubjectPublicKeyInfo);
|
||||
case der::PublicKeyAlgorithm::Uninitialized:
|
||||
assert(false);
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
}
|
||||
|
|
|
@ -564,51 +564,71 @@ impl PropertyDeclarationBlock {
|
|||
true
|
||||
}
|
||||
|
||||
/// Returns the first declaration that would be removed by removing
|
||||
/// `property`.
|
||||
#[inline]
|
||||
pub fn first_declaration_to_remove(
|
||||
&self,
|
||||
property: &PropertyId,
|
||||
) -> Option<usize> {
|
||||
if let Some(id) = property.longhand_id() {
|
||||
if !self.longhands.contains(id) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
self.declarations.iter().position(|declaration| {
|
||||
declaration.id().is_or_is_longhand_of(property)
|
||||
})
|
||||
}
|
||||
|
||||
/// Removes a given declaration at a given index.
|
||||
#[inline]
|
||||
fn remove_declaration_at(&mut self, i: usize) {
|
||||
{
|
||||
let id = self.declarations[i].id();
|
||||
if let PropertyDeclarationId::Longhand(id) = id {
|
||||
self.longhands.remove(id);
|
||||
}
|
||||
self.declarations_importance.remove(i);
|
||||
}
|
||||
self.declarations.remove(i);
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty>
|
||||
///
|
||||
/// Returns whether any declaration was actually removed.
|
||||
pub fn remove_property<C>(
|
||||
/// `first_declaration` needs to be the result of
|
||||
/// `first_declaration_to_remove`.
|
||||
#[inline]
|
||||
pub fn remove_property(
|
||||
&mut self,
|
||||
property: &PropertyId,
|
||||
mut before_change_callback: C,
|
||||
) -> bool
|
||||
where
|
||||
C: FnMut(&Self),
|
||||
{
|
||||
let longhand_id = property.longhand_id();
|
||||
if let Some(id) = longhand_id {
|
||||
if !self.longhands.contains(id) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
let mut removed_at_least_one = false;
|
||||
let mut i = 0;
|
||||
first_declaration: usize,
|
||||
) {
|
||||
debug_assert_eq!(
|
||||
Some(first_declaration),
|
||||
self.first_declaration_to_remove(property)
|
||||
);
|
||||
debug_assert!(self.declarations[first_declaration].id().is_or_is_longhand_of(property));
|
||||
|
||||
self.remove_declaration_at(first_declaration);
|
||||
|
||||
let shorthand = match property.as_shorthand() {
|
||||
Ok(s) => s,
|
||||
Err(_longhand_or_custom) => return,
|
||||
};
|
||||
|
||||
let mut i = first_declaration;
|
||||
let mut len = self.len();
|
||||
while i < len {
|
||||
{
|
||||
let id = self.declarations[i].id();
|
||||
if !id.is_or_is_longhand_of(property) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !removed_at_least_one {
|
||||
before_change_callback(&*self);
|
||||
}
|
||||
removed_at_least_one = true;
|
||||
if let PropertyDeclarationId::Longhand(id) = id {
|
||||
self.longhands.remove(id);
|
||||
}
|
||||
self.declarations_importance.remove(i);
|
||||
if !self.declarations[i].id().is_longhand_of(shorthand) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
self.declarations.remove(i);
|
||||
|
||||
self.remove_declaration_at(i);
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
if longhand_id.is_some() {
|
||||
debug_assert!(removed_at_least_one);
|
||||
}
|
||||
removed_at_least_one
|
||||
}
|
||||
|
||||
/// Take a declaration block known to contain a single property and serialize it.
|
||||
|
@ -727,9 +747,7 @@ impl PropertyDeclarationBlock {
|
|||
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertyDeclarationBlock {
|
||||
/// Like the method on ToCss, but without the type parameter to avoid
|
||||
/// accidentally monomorphizing this large function multiple times for
|
||||
/// different writers.
|
||||
|
|
|
@ -167,14 +167,14 @@ use super::error_reporter::ErrorReporter;
|
|||
use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
|
||||
|
||||
trait ClosureHelper {
|
||||
fn invoke(&self, decls: &PropertyDeclarationBlock);
|
||||
fn invoke(&self);
|
||||
}
|
||||
|
||||
impl ClosureHelper for DeclarationBlockMutationClosure {
|
||||
#[inline]
|
||||
fn invoke(&self, decls: &PropertyDeclarationBlock) {
|
||||
fn invoke(&self) {
|
||||
if let Some(function) = self.function.as_ref() {
|
||||
unsafe { function(decls, self.data) };
|
||||
unsafe { function(self.data) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1603,7 +1603,9 @@ pub extern "C" fn Servo_StyleSheet_GetSourceURL(
|
|||
}
|
||||
|
||||
fn read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
|
||||
where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R
|
||||
where
|
||||
Locked<T>: HasArcFFI,
|
||||
F: FnOnce(&T) -> R,
|
||||
{
|
||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||
let guard = global_style_data.shared_lock.read();
|
||||
|
@ -3411,15 +3413,6 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_GetCssText(
|
|||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_UnlockedDeclarationBlock_GetCssText(
|
||||
declarations: *const structs::RawServoUnlockedDeclarationBlock,
|
||||
result: *mut nsAString,
|
||||
) {
|
||||
(*declarations).to_css(&mut *result).unwrap()
|
||||
}
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
|
||||
declarations: RawServoDeclarationBlockBorrowed,
|
||||
|
@ -3567,9 +3560,10 @@ fn set_property(
|
|||
return false;
|
||||
}
|
||||
|
||||
before_change_closure.invoke();
|
||||
|
||||
let importance = if is_important { Importance::Important } else { Importance::Normal };
|
||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
||||
before_change_closure.invoke(&*decls);
|
||||
decls.extend(
|
||||
source_declarations.drain(),
|
||||
importance,
|
||||
|
@ -3647,11 +3641,22 @@ fn remove_property(
|
|||
property_id: PropertyId,
|
||||
before_change_closure: DeclarationBlockMutationClosure,
|
||||
) -> bool {
|
||||
let first_declaration =
|
||||
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
|
||||
decls.first_declaration_to_remove(&property_id)
|
||||
});
|
||||
|
||||
let first_declaration = match first_declaration {
|
||||
Some(i) => i,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
before_change_closure.invoke();
|
||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
||||
decls.remove_property(&property_id, |decls| {
|
||||
before_change_closure.invoke(decls)
|
||||
})
|
||||
})
|
||||
decls.remove_property(&property_id, first_declaration)
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
@ -44,3 +44,15 @@ bench-sixspeed:
|
|||
export JSSHELL=$USE_ARTIFACT_PATH/build/jsshell/js &&
|
||||
cd $GECKO_PATH &&
|
||||
./mach jsshell-bench --binary $JSSHELL --perfherder six-speed
|
||||
|
||||
bench-asmjsapps:
|
||||
description: asm.js Apps shell benchmark suite
|
||||
treeherder:
|
||||
symbol: js-bench(asm.js-apps)
|
||||
run:
|
||||
command: >
|
||||
cd $USE_ARTIFACT_PATH/build &&
|
||||
unzip -q -d jsshell target.jsshell.zip &&
|
||||
export JSSHELL=$USE_ARTIFACT_PATH/build/jsshell/js &&
|
||||
cd $GECKO_PATH &&
|
||||
./mach jsshell-bench --binary $JSSHELL --perfherder asmjs-apps
|
||||
|
|
|
@ -199,9 +199,66 @@ class SixSpeed(Benchmark):
|
|||
self.suite['value'] = bench_total
|
||||
|
||||
|
||||
class AsmJSApps(Benchmark):
|
||||
name = 'asmjsapps'
|
||||
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'asmjs-apps')
|
||||
units = 'ms'
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
if not self.args:
|
||||
self.args = []
|
||||
full_args = ['bash', 'harness.sh', self.shell + " " + " ".join(self.args)]
|
||||
return full_args
|
||||
|
||||
def reset(self):
|
||||
super(AsmJSApps, self).reset()
|
||||
|
||||
# Scores are of the form:
|
||||
# {<bench_name>: {<score_name>: [<values>]}}
|
||||
self.scores = defaultdict(lambda: defaultdict(list))
|
||||
|
||||
def process_results(self, output):
|
||||
total = 0.0
|
||||
tests = []
|
||||
for line in output.splitlines():
|
||||
m = re.search("(.+) - (\d+(\.\d+)?)", line)
|
||||
if not m:
|
||||
continue
|
||||
name = m.group(1)
|
||||
score = m.group(2)
|
||||
total += float(score)
|
||||
tests.append({ 'name': name, 'time': score })
|
||||
tests.append({ 'name': '__total__', 'time': total })
|
||||
return tests
|
||||
|
||||
def process_line(self, output):
|
||||
m = re.search("(.+) - (\d+(\.\d+)?)", output)
|
||||
if not m:
|
||||
return
|
||||
subtest = m.group(1)
|
||||
score = m.group(2)
|
||||
if subtest not in self.scores[self.name]:
|
||||
self.scores[self.name][subtest] = []
|
||||
self.scores[self.name][subtest].append(int(score))
|
||||
|
||||
|
||||
def collect_results(self):
|
||||
bench_total = 0
|
||||
# NOTE: for this benchmark we run the test once, so we have a single value array
|
||||
for bench, scores in self.scores.items():
|
||||
for score, values in scores.items():
|
||||
test_name = "{}-{}".format(self.name, score)
|
||||
total = sum(values) / len(values)
|
||||
self.suite['subtests'].append({'name': test_name, 'value': total})
|
||||
bench_total += int(sum(values))
|
||||
self.suite['value'] = bench_total
|
||||
|
||||
|
||||
all_benchmarks = {
|
||||
'ares6': Ares6,
|
||||
'six-speed': SixSpeed,
|
||||
'asmjs-apps': AsmJSApps,
|
||||
}
|
||||
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче