Merge mozilla-central to mozilla-inbound. CLOSED TREE

This commit is contained in:
Csoregi Natalia 2018-11-07 18:22:28 +02:00
Родитель 76e211c34b ce0127e7c1
Коммит ec50e0e5af
74 изменённых файлов: 1997 добавлений и 1073 удалений

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

@ -288,15 +288,15 @@ window:not([chromehidden~="toolbar"]) #nav-bar[nonemptyoverflow] > .overflow-but
%ifdef MENUBAR_CAN_AUTOHIDE
#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-item,
#toolbar-menubar:not([autohide=true]) + #TabsToolbar .titlebar-placeholder,
#toolbar-menubar:not([autohide=true]) + #TabsToolbar .titlebar-spacer,
%endif
%ifndef MOZ_WIDGET_COCOA
#main-window:not([sizemode=normal]) .titlebar-placeholder[type="pre-tabs"],
#main-window:not([sizemode=normal]) .titlebar-spacer[type="pre-tabs"],
%endif
#main-window:not([chromemargin]) .titlebar-buttonbox-container,
#main-window[inFullscreen] .titlebar-buttonbox-container,
#main-window[inFullscreen] .titlebar-placeholder,
#main-window:not([tabsintitlebar]) .titlebar-placeholder {
#main-window[inFullscreen] .titlebar-spacer,
#main-window:not([tabsintitlebar]) .titlebar-spacer {
display: none;
}

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

@ -760,7 +760,7 @@ xmlns="http://www.w3.org/1999/xhtml"
<spacer flex="1000"/>
<hbox id="TabsToolbar-customization-target" flex="1">
<hbox class="titlebar-placeholder" type="pre-tabs"
<hbox class="titlebar-spacer" type="pre-tabs"
skipintoolbarset="true"/>
<tabs id="tabbrowser-tabs"
@ -791,7 +791,7 @@ xmlns="http://www.w3.org/1999/xhtml"
tooltiptext="&listAllTabs.label;"
removable="false"/>
<hbox class="titlebar-placeholder" type="post-tabs"
<hbox class="titlebar-spacer" type="post-tabs"
ordinal="1000"
skipintoolbarset="true"/>
</hbox>

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

@ -843,7 +843,7 @@ var CustomizableUIInternal = {
// node is not removable, we leave it where it is. However, we can only
// safely touch elements that have an ID - both because we depend on
// IDs (or are specials), and because such elements are not intended to
// be widgets (eg, titlebar-placeholder elements).
// be widgets (eg, titlebar-spacer elements).
if ((node.id || this.isSpecialWidget(node)) &&
node.getAttribute("skipintoolbarset") != "true") {
if (this.isWidgetRemovable(node)) {

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

@ -1027,7 +1027,8 @@ BrowserGlue.prototype = {
name: gBrowserBundle.GetStringFromName("lightTheme.name"),
description: gBrowserBundle.GetStringFromName("lightTheme.description"),
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
textcolor: "#18191a",
textcolor: "rgb(24, 25, 26)",
icon_color: "rgb(24, 25, 26, 0.7)",
accentcolor: "#E3E4E6",
popup: "#fff",
popup_text: "#0c0c0d",
@ -1045,6 +1046,7 @@ BrowserGlue.prototype = {
description: gBrowserBundle.GetStringFromName("darkTheme.description"),
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
textcolor: "rgb(249, 249, 250)",
icon_color: "rgb(249, 249, 250, 0.7)",
accentcolor: "hsl(240, 5%, 5%)",
popup: "#4a4a4f",
popup_text: "rgb(249, 249, 250)",

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

@ -621,7 +621,7 @@ notification[value="translation"] menulist > .menulist-dropmarker {
* and enable it for desktop environment which do that by default.
* See nsWindow::TopLevelWindowUseARGBVisual() for details. */
@media (-moz-gtk-csd-transparent-background) {
:root[tabsintitlebar]:not(:-moz-lwtheme) {
:root[tabsintitlebar][sizemode="normal"]:not(:-moz-lwtheme) {
background-color: transparent;
-moz-appearance: none;
}

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

@ -4,14 +4,3 @@
%include ../shared/compacttheme.inc.css
/* The menubar and tabs toolbar should match the devedition theme */
#TabsToolbar,
#toolbar-menubar {
-moz-appearance: none !important;
}
#main-menubar > menu:not([open]) {
color: inherit;
}

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

@ -112,7 +112,7 @@
/* The fullscreen button doesnt show on Yosemite(10.10) or above so dont give it a
border there */
@media (-moz-mac-yosemite-theme: 0) {
.titlebar-placeholder[type="fullscreen-button"] {
.titlebar-spacer[type="fullscreen-button"] {
margin-right: 4px;
}
}

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

@ -10,8 +10,6 @@
--toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
--toolbar-non-lwt-textcolor: var(--lwt-text-color);
--toolbar-non-lwt-bgimage: none;
--toolbarbutton-icon-fill-opacity: .7;
}
:root:-moz-lwtheme-brighttext {

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

@ -629,20 +629,20 @@
/* Drag space */
.titlebar-placeholder[type="pre-tabs"],
.titlebar-placeholder[type="post-tabs"] {
.titlebar-spacer[type="pre-tabs"],
.titlebar-spacer[type="post-tabs"] {
width: 40px;
}
@media (max-width: 500px) {
.titlebar-placeholder[type="post-tabs"] {
.titlebar-spacer[type="post-tabs"] {
display: none;
}
}
/* Tab separators */
.titlebar-placeholder[type="pre-tabs"] {
.titlebar-spacer[type="pre-tabs"] {
border-inline-end: 1px solid var(--lwt-background-tab-separator-color, currentColor);
opacity: 0.2;
}

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

@ -59,9 +59,9 @@
}
@media (-moz-windows-glass) {
/* Set to full fill-opacity to improve visibility of toolbar buttons on aero glass. */
/* Use opaque white icons on Aero Glass. */
#TabsToolbar {
--toolbarbutton-icon-fill-opacity: 1;
--lwt-toolbarbutton-icon-fill: white;
}
/* Make the menubar text readable on aero glass (copied from browser-aero.css). */

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

@ -26,7 +26,7 @@ class CSSDeclaration extends PureComponent {
render() {
const { property, value, className } = this.props;
return dom.div({ className },
return dom.div({ className: `declaration ${className}` },
dom.span({ className: "declaration-name theme-fg-color5"}, property),
":",
dom.span({ className: "declaration-value theme-fg-color1"}, value),

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

@ -35,11 +35,21 @@ class ChangesApp extends PureComponent {
renderDeclarations(remove = {}, add = {}) {
const removals = Object.entries(remove).map(([property, value]) => {
return CSSDeclaration({ className: "level diff-remove", property, value });
return CSSDeclaration({
key: "remove-" + property,
className: "level diff-remove",
property,
value,
});
});
const additions = Object.entries(add).map(([property, value]) => {
return CSSDeclaration({ className: "level diff-add", property, value });
return CSSDeclaration({
key: "add-" + property,
className: "level diff-add",
property,
value,
});
});
return [removals, additions];
@ -55,13 +65,21 @@ class ChangesApp extends PureComponent {
// Mark this rule as rendered so we don't render it again.
this.renderedRules.push(ruleId);
let diffClass = "";
if (rule.changeType === "rule-add") {
diffClass = "diff-add";
} else if (rule.changeType === "rule-remove") {
diffClass = "diff-remove";
}
return dom.div(
{
key: ruleId,
className: "rule",
},
dom.div(
{
className: "level selector",
className: `level selector ${diffClass}`,
title: selector,
},
selector,
@ -73,7 +91,7 @@ class ChangesApp extends PureComponent {
}),
// Render any changed CSS declarations.
this.renderDeclarations(rule.remove, rule.add),
dom.span({ className: "level bracket-close" }, "}")
dom.div({ className: `level bracket-close ${diffClass}` }, "}")
);
}
@ -85,6 +103,7 @@ class ChangesApp extends PureComponent {
return dom.details(
{
key: sourceId,
className: "source devtools-monospace",
open: true,
},

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

@ -133,6 +133,7 @@ function removeRule(ruleId, rules) {
* rules: {
* <ruleId>: {
* selector: "" // String CSS selector or CSS at-rule text
* changeType: // Optional string: "rule-add" or "rule-remove"
* children: [] // Array of <ruleId> for child rules of this rule.
* parent: // <ruleId> of the parent rule
* add: {
@ -166,9 +167,12 @@ const reducers = {
state = cloneState(state);
const { type, href, index } = change.source;
const { selector, ancestors, ruleIndex } = change;
const { selector, ancestors, ruleIndex, type: changeType } = change;
const sourceId = getSourceHash(change.source);
const ruleId = getRuleHash({ selector, ancestors, ruleIndex });
// Type coerce to boolean: `false` if value is undefined or `null`, `true` otherwise.
const hasAdd = !!change.add;
const hasRemove = !!change.remove;
// Copy or create object identifying the source (styelsheet/element) for this change.
const source = Object.assign({}, state[sourceId], { type, href, index });
@ -178,37 +182,41 @@ const reducers = {
let rule = rules[ruleId];
if (!rule) {
rule = createRule({ selector, ancestors, ruleIndex }, rules);
if (changeType.startsWith("rule-")) {
rule.changeType = changeType;
}
}
// Copy or create collection of all CSS declarations ever added to this rule.
const add = Object.assign({}, rule.add);
// Copy or create collection of all CSS declarations ever removed from this rule.
const remove = Object.assign({}, rule.remove);
if (change.remove && change.remove.property) {
// Track the remove operation only if the property was not previously introduced
// by an add operation. This ensures repeated changes of the same property
// register as a single remove operation of its original value.
if (!add[change.remove.property]) {
remove[change.remove.property] = change.remove.value;
}
if (hasRemove) {
Object.entries(change.remove).forEach(([property, value]) => {
// Track the remove operation only if the property was not previously introduced
// by an add operation. This ensures repeated changes of the same property
// register as a single remove operation of its original value.
if (!add[property]) {
remove[property] = value;
}
// Delete any previous add operation which would be canceled out by this remove.
if (add[change.remove.property] === change.remove.value) {
delete add[change.remove.property];
}
// Delete any previous add operation which would be canceled out by this remove.
if (add[property] === value) {
delete add[property];
}
});
}
if (change.add && change.add.property) {
add[change.add.property] = change.add.value;
}
if (hasAdd) {
Object.entries(change.add).forEach(([property, value]) => {
add[property] = value;
const property = change.add && change.add.property ||
change.remove && change.remove.property;
// Remove tracked operations if they cancel each other out.
if (add[property] === remove[property]) {
delete add[property];
delete remove[property];
// Remove previously tracked declarations if they cancel each other out.
if (add[property] === remove[property]) {
delete add[property];
delete remove[property];
}
});
}
// Remove information about the rule if none its declarations changed.

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

@ -15,3 +15,4 @@ support-files =
[browser_changes_declaration_disable.js]
[browser_changes_declaration_edit_value.js]
[browser_changes_declaration_remove.js]
[browser_changes_rule_selector.js]

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

@ -0,0 +1,66 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that renaming the selector of a CSS declaration in the Rule view is tracked as
// one rule removal with the old selector and one rule addition with the new selector.
const TEST_URI = `
<style type='text/css'>
div {
color: red;
}
</style>
<div></div>
`;
add_task(async function() {
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, view: ruleView } = await openRuleView();
const { document: doc, store } = selectChangesView(inspector);
const panel = doc.querySelector("#sidebar-panel-changes");
await selectNode("div", inspector);
const ruleEditor = getRuleViewRuleEditor(ruleView, 1);
info("Focusing the first rule's selector name in the Rule view");
const editor = await focusEditableField(ruleView, ruleEditor.selectorText);
info("Entering a new selector name");
editor.input.value = ".test";
// Expect two "TRACK_CHANGE" actions: one for rule removal, one for rule addition.
const onTrackChange = waitUntilAction(store, "TRACK_CHANGE", 2);
const onRuleViewChanged = once(ruleView, "ruleview-changed");
info("Pressing Enter key to commit the change");
EventUtils.synthesizeKey("KEY_Enter");
info("Waiting for rule view to update");
await onRuleViewChanged;
info("Wait for the change to be tracked");
await onTrackChange;
const rules = panel.querySelectorAll(".rule");
is(rules.length, 2, "Two rules were tracked as changed");
const firstSelector = rules.item(0).querySelector(".selector");
is(firstSelector.title, "div", "Old selector name was tracked.");
ok(firstSelector.classList.contains("diff-remove"), "Old selector was removed.");
const secondSelector = rules.item(1).querySelector(".selector");
is(secondSelector.title, ".test", "New selector name was tracked.");
ok(secondSelector.classList.contains("diff-add"), "New selector was added.");
info("Checking that the two rules have identical declarations");
const firstDecl = rules.item(0).querySelectorAll(".declaration");
is(firstDecl.length, 1, "First rule has only one declaration");
is(firstDecl.item(0).textContent, "color:red;", "First rule has correct declaration");
ok(firstDecl.item(0).classList.contains("diff-remove"),
"First rule has declaration tracked as removed");
const secondDecl = rules.item(1).querySelectorAll(".declaration");
is(secondDecl.length, 1, "Second rule has only one declaration");
is(secondDecl.item(0).textContent, "color:red;", "Second rule has correct declaration");
ok(secondDecl.item(0).classList.contains("diff-add"),
"Second rule has declaration tracked as added");
});

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

@ -86,8 +86,8 @@ class FlexItemSizingProperties extends PureComponent {
const flexBasisValue = properties["flex-basis"];
const dimensionValue = properties[dimension];
let title = getStr("flexbox.itemSizing.baseSizeSectionHeader");
let property = null;
let reason = null;
if (flexBasisValue) {
// If flex-basis is defined, then that's what is used for the base size.
@ -97,19 +97,18 @@ class FlexItemSizingProperties extends PureComponent {
property = this.renderCssProperty(dimension, dimensionValue);
} else {
// Finally, if nothing is set, then the base size is the max-content size.
reason = this.renderReasons(
[getStr("flexbox.itemSizing.itemBaseSizeFromContent")]);
// In this case replace the section's title.
title = getStr("flexbox.itemSizing.itemContentSize");
}
const className = "section base";
return (
dom.li({ className: className + (property ? "" : " no-property") },
dom.span({ className: "name" },
getStr("flexbox.itemSizing.baseSizeSectionHeader"),
title,
property
),
this.renderSize(mainBaseSize),
reason
this.renderSize(mainBaseSize)
)
);
}
@ -120,7 +119,6 @@ class FlexItemSizingProperties extends PureComponent {
mainBaseSize,
mainFinalSize,
lineGrowthState,
clampState,
} = flexItemSizing;
// Don't display anything if all interesting sizes are 0.
@ -139,7 +137,6 @@ class FlexItemSizingProperties extends PureComponent {
const computedFlexGrow = computedStyle.flexGrow;
const definedFlexShrink = properties["flex-shrink"];
const computedFlexShrink = computedStyle.flexShrink;
const wasClamped = clampState !== "unclamped";
const reasons = [];
@ -159,35 +156,15 @@ class FlexItemSizingProperties extends PureComponent {
let property = null;
if (grew) {
// If the item grew.
if (definedFlexGrow) {
// It's normally because it was set to grow (flex-grow is non 0).
property = this.renderCssProperty("flex-grow", definedFlexGrow);
}
if (wasClamped && clampState === "clamped_to_max") {
// It may have wanted to grow more than it did, because it was later max-clamped.
reasons.push(getStr("flexbox.itemSizing.growthAttemptButMaxClamped"));
} else if (wasClamped && clampState === "clamped_to_min") {
// Or it may have wanted to grow less, but was later min-clamped to a larger size.
reasons.push(getStr("flexbox.itemSizing.growthAttemptButMinClamped"));
}
} else if (shrank) {
// If the item shrank.
if (definedFlexShrink && computedFlexShrink) {
// It's either because flex-shrink is non 0.
property = this.renderCssProperty("flex-shrink", definedFlexShrink);
} else if (computedFlexShrink) {
// Or also because it's default value is 1 anyway.
property = this.renderCssProperty("flex-shrink", computedFlexShrink, true);
}
if (wasClamped) {
// It might have wanted to shrink more (to accomodate all items) but couldn't
// because it was later min-clamped.
reasons.push(getStr("flexbox.itemSizing.shrinkAttemptWhenClamped"));
}
if (grew && definedFlexGrow && computedFlexGrow) {
// If the item grew it's normally because it was set to grow (flex-grow is non 0).
property = this.renderCssProperty("flex-grow", definedFlexGrow);
} else if (shrank && definedFlexShrink && computedFlexShrink) {
// If the item shrank it's either because flex-shrink is non 0.
property = this.renderCssProperty("flex-shrink", definedFlexShrink);
} else if (shrank && computedFlexShrink) {
// Or also because it's default value is 1 anyway.
property = this.renderCssProperty("flex-shrink", computedFlexShrink, true);
}
// Don't display the section at all if there's nothing useful to show users.
@ -208,14 +185,24 @@ class FlexItemSizingProperties extends PureComponent {
);
}
renderMinimumSizeSection({ clampState, mainMinSize }, properties, dimension) {
renderMinimumSizeSection(flexItemSizing, properties, dimension) {
const { clampState, mainMinSize, mainDeltaSize } = flexItemSizing;
const grew = mainDeltaSize > 0;
const shrank = mainDeltaSize < 0;
const minDimensionValue = properties[`min-${dimension}`];
// We only display the minimum size when the item actually violates that size during
// layout & is clamped.
if (clampState !== "clamped_to_min") {
return null;
}
const minDimensionValue = properties[`min-${dimension}`];
const reasons = [];
if (grew || shrank) {
// The item may have wanted to grow less, but was min-clamped to a larger size.
// Or the item may have wanted to shrink more but was min-clamped to a larger size.
reasons.push(getStr("flexbox.itemSizing.clampedToMin"));
}
return (
dom.li({ className: "section min" },
@ -223,17 +210,26 @@ class FlexItemSizingProperties extends PureComponent {
getStr("flexbox.itemSizing.minSizeSectionHeader"),
this.renderCssProperty(`min-${dimension}`, minDimensionValue)
),
this.renderSize(mainMinSize)
this.renderSize(mainMinSize),
this.renderReasons(reasons)
)
);
}
renderMaximumSizeSection({ clampState, mainMaxSize }, properties, dimension) {
renderMaximumSizeSection(flexItemSizing, properties, dimension) {
const { clampState, mainMaxSize, mainDeltaSize } = flexItemSizing;
const grew = mainDeltaSize > 0;
const maxDimensionValue = properties[`max-${dimension}`];
if (clampState !== "clamped_to_max") {
return null;
}
const maxDimensionValue = properties[`max-${dimension}`];
const reasons = [];
if (grew) {
// The item may have wanted to grow more than it did, because it was max-clamped.
reasons.push(getStr("flexbox.itemSizing.clampedToMax"));
}
return (
dom.li({ className: "section max" },
@ -241,7 +237,8 @@ class FlexItemSizingProperties extends PureComponent {
getStr("flexbox.itemSizing.maxSizeSectionHeader"),
this.renderCssProperty(`max-${dimension}`, maxDimensionValue)
),
this.renderSize(mainMaxSize)
this.renderSize(mainMaxSize),
this.renderReasons(reasons)
)
);
}

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

@ -30,6 +30,6 @@ add_task(async function() {
const allSections = [...flexSizingContainer.querySelectorAll(".section .name")];
is(allSections.length, 2, "There are 2 parts in the sizing section");
is(allSections[0].textContent, "Base Size", "The first part is the base size");
is(allSections[0].textContent, "Content Size", "The first part is the content size");
is(allSections[1].textContent, "Final Size", "The second part is the final size");
});

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

@ -27,9 +27,9 @@ add_task(async function() {
ok(outlineContainer.style.gridTemplateColumns.includes("[final-end max]"),
"The final and max points are at the same position");
info("Check that the flexibility sizing section displays the right info");
info("Check that the maximum sizing section displays the right info");
const reasons = [...sizingContainer.querySelectorAll(".reasons li")];
const expectedReason = getStr("flexbox.itemSizing.growthAttemptButMaxClamped");
const expectedReason = getStr("flexbox.itemSizing.clampedToMax");
ok(reasons.some(r => r.textContent === expectedReason),
"The 'wanted to grow but was clamped' reason was found");
"The clampedToMax reason was found");
});

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

@ -25,13 +25,6 @@ flexbox.noFlexboxeOnThisPage=Select a Flex container or item to continue.
# properties in the Flexbox panel.
flexbox.flexContainerProperties=Flex Container Properties
# LOCALIZATION NOTE (flexbox.contentWidth, flexbox.contentHeight, flexbox.finalWidth,
# flexbox.finalHeight): Labels for the flex item sizing properties in the Flexbox panel.
flexbox.contentWidth=Content width:
flexbox.contentHeight=Content height:
flexbox.finalWidth=Final width:
flexbox.finalHeight=Final height:
# LOCALIZATION NOTE (flexbox.itemSizing.baseSizeSectionHeader): Header label displayed
# at the start of the flex item sizing Base Size section.
flexbox.itemSizing.baseSizeSectionHeader=Base Size
@ -52,36 +45,26 @@ flexbox.itemSizing.maxSizeSectionHeader=Maximum Size
# the start of the flex item sizing Final Size section.
flexbox.itemSizing.finalSizeSectionHeader=Final Size
# LOCALIZATION NOTE (flexbox.itemSizing.itemBaseSizeFromContent): Label shown in the flex
# item sizing panel. It tells users that a given items base size was calculated from its
# LOCALIZATION NOTE (flexbox.itemSizing.itemContentSize): Label shown in the flex item
# sizing panel. It tells users that a given items base size was calculated from its
# content size when unconstrained.
flexbox.itemSizing.itemBaseSizeFromContent=The items content size when unconstrained.
flexbox.itemSizing.itemContentSize=Content Size
# LOCALIZATION NOTE (flexbox.itemSizing.itemMinSizeFromItemMinContent): Label shown in the
# flex item sizing panel. It tells users that a given items minimum size is coming from
# its min-content size.
flexbox.itemSizing.itemMinSizeFromItemMinContent=This is the elements minimum content size.
# LOCALIZATION NOTE (flexbox.itemSizing.growthAttemptButMaxClamped): Label shown in the
# flexbox item sizing panel. It tells users that a given item attempted to grow by a
# certain amount but ended up being clamped to a smaller max size.
# LOCALIZATION NOTE (flexbox.itemSizing.clampedToMax): Label shown in the flexbox item
# sizing panel. It tells users that a given item attempted to grow but ended up being
# clamped to a smaller max size.
# (Note that clamp is a common word in flexbox terminology. It refers to constraining an
# item's size to some defined min/max-width/height set on the element, even though there
# might have been room for it to grow, or reason for it to shrink more).
flexbox.itemSizing.growthAttemptButMaxClamped=The item wanted to grow more, but it was clamped to its maximum size.
flexbox.itemSizing.clampedToMax=The item was clamped to its maximum size.
# LOCALIZATION NOTE (flexbox.itemSizing.growthAttemptButMinClamped): Label shown in the
# flexbox item sizing panel. It tells users that a given item attempted to grow by a
# certain amount but ended up being clamped to a larger min size.
# LOCALIZATION NOTE (flexbox.itemSizing.clampedToMin): Label shown in the flexbox item
# sizing panel. It tells users that a given item attempted to grow but ended up being
# clamped to a larger min size.
# (Note that clamp is a common word in flexbox terminology. It refers to constraining an
# item's size to some defined min/max-width/height set on the element, even though there
# might have been room for it to grow, or reason for it to shrink more).
flexbox.itemSizing.growthAttemptButMinClamped=The item wanted to grow less, but it was clamped to its minimum size.
# LOCALIZATION NOTE (flexbox.itemSizing.shrinkAttemptWhenClamped): Label shown in the
# flexbox item sizing panel. It tells users that a given item attempted to shrink by a
# certain amount but ended up being clamped by a min size.
flexbox.itemSizing.shrinkAttemptWhenClamped=The item wanted to shrink, but it was clamped.
flexbox.itemSizing.clampedToMin=The item was clamped to its minimum size.
# LOCALIZATION NOTE (flexbox.itemSizing.setToGrow): Label shown in the flex item sizing
# panel. It tells users that a given item was set to grow.

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

@ -43,14 +43,16 @@ function waitUntilState(store, predicate) {
/**
* Wait until a particular action has been emitted by the store.
* @param Store store
* @param {Store} store
* The Redux store being used.
* @param string actionType
* @param {String} actionType
* The expected action to wait for.
* @param {Number} count
* Number of times to expect the action to occur. Default is once.
* @return Promise
* Resolved once the expected action is emitted by the store.
*/
function waitUntilAction(store, actionType) {
function waitUntilAction(store, actionType, count = 1) {
const deferred = defer();
const unsubscribe = store.subscribe(check);
const history = store.history;
@ -61,8 +63,11 @@ function waitUntilAction(store, actionType) {
const action = history[index++];
if (action && action.type === actionType) {
info(`Found action "${actionType}"`);
unsubscribe();
deferred.resolve(store.getState());
count--;
if (count === 0) {
unsubscribe();
deferred.resolve(store.getState());
}
}
}

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

@ -54,8 +54,8 @@
padding-left: calc(var(--diff-level-offset) * 4);
}
#sidebar-panel-changes .rule .selector,
#sidebar-panel-changes .rule .bracket-close {
#sidebar-panel-changes .rule .selector:not(.diff-remove):not(.diff-add),
#sidebar-panel-changes .rule .bracket-close:not(.diff-remove):not(.diff-add) {
margin-left: calc(-1 * var(--diff-level-offset) + 5px);
}

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

@ -164,10 +164,11 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
// Clear the pattern cache to avoid dead object exceptions (Bug 1342051).
this.clearCache();
this.axes = null;
this.crossAxisDirection = null;
this.flexData = null;
this.mainAxisDirection = null;
this.crossAxisDirection = null;
this.axes = null;
this.transform = null;
AutoRefreshHighlighter.prototype.destroy.call(this);
}
@ -337,6 +338,10 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
this.justifyContentValue = this.computedStyle.justifyContent;
const newJustifyContent = this.justifyContentValue;
const oldTransform = this.transformValue;
this.transformValue = this.computedStyle.transform;
const newTransform = this.transformValue;
return hasMoved ||
hasFlexDataChanged ||
oldAlignItems !== newAlignItems ||
@ -344,7 +349,8 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
oldFlexWrap !== newFlexWrap ||
oldJustifyContent !== newJustifyContent ||
oldCrossAxisDirection !== newCrossAxisDirection ||
oldMainAxisDirection !== newMainAxisDirection;
oldMainAxisDirection !== newMainAxisDirection ||
oldTransform !== newTransform;
}
_hide() {
@ -530,8 +536,8 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
this.ctx.strokeStyle = this.color;
this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio);
const { bounds } = this.currentQuads.content[0];
drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix);
const { clientWidth, clientHeight } = this.currentNode;
drawRect(this.ctx, 0, 0, clientWidth, clientHeight, this.currentMatrix);
// Find current angle of outer flex element by measuring the angle of two arbitrary
// points, then rotate canvas, so the hash pattern stays 45deg to the boundary.
@ -556,6 +562,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
const zoom = getCurrentZoom(this.win);
const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
const containerOffsets = getNodeRect(this.currentNode);
this.ctx.save();
this.ctx.translate(offset - canvasX, offset - canvasY);
@ -563,21 +570,18 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
this.ctx.lineWidth = lineWidth;
this.ctx.strokeStyle = this.color;
const { bounds } = this.currentQuads.content[0];
for (const flexLine of this.flexData.lines) {
for (const flexItem of flexLine.items) {
const quads = flexItem.quads;
if (!quads.length) {
const offsets = getNodeRect(flexItem.node);
if (!offsets) {
continue;
}
// Adjust the flex item bounds relative to the current quads.
const { bounds: flexItemBounds } = quads[0];
const left = Math.round(flexItemBounds.left / zoom - bounds.left);
const top = Math.round(flexItemBounds.top / zoom - bounds.top);
const right = Math.round(flexItemBounds.right / zoom - bounds.left);
const bottom = Math.round(flexItemBounds.bottom / zoom - bounds.top);
const left = offsets.left - containerOffsets.left;
const top = offsets.top - containerOffsets.top;
const right = offsets.right - containerOffsets.left;
const bottom = offsets.bottom - containerOffsets.top;
clearRect(this.ctx, left, top, right, bottom, this.currentMatrix);
drawRect(this.ctx, left, top, right, bottom, this.currentMatrix);
@ -599,15 +603,14 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
const zoom = getCurrentZoom(this.win);
const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
const { clientWidth, clientHeight } = this.currentNode;
const options = { matrix: this.currentMatrix };
this.ctx.save();
this.ctx.translate(offset - canvasX, offset - canvasY);
this.ctx.lineWidth = lineWidth;
this.ctx.strokeStyle = this.color;
const { bounds } = this.currentQuads.content[0];
const options = { matrix: this.currentMatrix };
for (const flexLine of this.flexData.lines) {
const { crossStart, crossSize } = flexLine;
@ -616,56 +619,56 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
case "horizontal-lr vertical-bt":
case "horizontal-rl vertical-tb":
case "horizontal-rl vertical-bt":
clearRect(this.ctx, 0, crossStart, bounds.width, crossStart + crossSize,
clearRect(this.ctx, 0, crossStart, clientWidth, crossStart + crossSize,
this.currentMatrix);
// Avoid drawing the start flex line when they overlap with the flex container.
if (crossStart != 0) {
drawLine(this.ctx, 0, crossStart, bounds.width, crossStart, options);
drawLine(this.ctx, 0, crossStart, clientWidth, crossStart, options);
this.ctx.stroke();
}
// Avoid drawing the end flex line when they overlap with the flex container.
if (bounds.height - crossStart - crossSize >= lineWidth) {
drawLine(this.ctx, 0, crossStart + crossSize, bounds.width,
if (clientHeight - crossStart - crossSize >= lineWidth) {
drawLine(this.ctx, 0, crossStart + crossSize, clientWidth,
crossStart + crossSize, options);
this.ctx.stroke();
}
break;
case "vertical-tb horizontal-lr":
case "vertical-bt horizontal-rl":
clearRect(this.ctx, crossStart, 0, crossStart + crossSize, bounds.height,
clearRect(this.ctx, crossStart, 0, crossStart + crossSize, clientHeight,
this.currentMatrix);
// Avoid drawing the start flex line when they overlap with the flex container.
if (crossStart != 0) {
drawLine(this.ctx, crossStart, 0, crossStart, bounds.height, options);
drawLine(this.ctx, crossStart, 0, crossStart, clientHeight, options);
this.ctx.stroke();
}
// Avoid drawing the end flex line when they overlap with the flex container.
if (bounds.width - crossStart - crossSize >= lineWidth) {
if (clientWidth - crossStart - crossSize >= lineWidth) {
drawLine(this.ctx, crossStart + crossSize, 0, crossStart + crossSize,
bounds.height, options);
clientHeight, options);
this.ctx.stroke();
}
break;
case "vertical-bt horizontal-lr":
case "vertical-tb horizontal-rl":
clearRect(this.ctx, bounds.width - crossStart, 0,
bounds.width - crossStart - crossSize, bounds.height, this.currentMatrix);
clearRect(this.ctx, clientWidth - crossStart, 0,
clientWidth - crossStart - crossSize, clientHeight, this.currentMatrix);
// Avoid drawing the start flex line when they overlap with the flex container.
if (crossStart != 0) {
drawLine(this.ctx, bounds.width - crossStart, 0, bounds.width - crossStart,
bounds.height, options);
drawLine(this.ctx, clientWidth - crossStart, 0, clientWidth - crossStart,
clientHeight, options);
this.ctx.stroke();
}
// Avoid drawing the end flex line when they overlap with the flex container.
if (bounds.width - crossStart - crossSize >= lineWidth) {
drawLine(this.ctx, bounds.width - crossStart - crossSize, 0,
bounds.width - crossStart - crossSize, bounds.height, options);
if (clientWidth - crossStart - crossSize >= lineWidth) {
drawLine(this.ctx, clientWidth - crossStart - crossSize, 0,
clientWidth - crossStart - crossSize, clientHeight, options);
this.ctx.stroke();
}
break;
@ -683,27 +686,27 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
return;
}
const zoom = getCurrentZoom(this.win);
const { bounds } = this.currentQuads.content[0];
const lineWidth = getDisplayPixelRatio(this.win);
const { clientWidth, clientHeight } = this.currentNode;
const containerOffsets = getNodeRect(this.currentNode);
// Draw a justify content pattern over the whole flex container.
this.drawJustifyContent(0, 0, bounds.width, bounds.height, this.currentMatrix);
this.drawJustifyContent(0, 0, clientWidth, clientHeight);
for (const flexLine of this.flexData.lines) {
const { crossStart, crossSize } = flexLine;
for (const flexItem of flexLine.items) {
const quads = flexItem.quads;
if (!quads.length) {
const offsets = getNodeRect(flexItem.node);
if (!offsets) {
continue;
}
// Adjust the flex item bounds relative to the current quads.
const { bounds: flexItemBounds } = quads[0];
const left = Math.round(flexItemBounds.left / zoom - bounds.left);
const top = Math.round(flexItemBounds.top / zoom - bounds.top);
const right = Math.round(flexItemBounds.right / zoom - bounds.left);
const bottom = Math.round(flexItemBounds.bottom / zoom - bounds.top);
const left = offsets.left - containerOffsets.left;
const top = offsets.top - containerOffsets.top;
const right = offsets.right - containerOffsets.left;
const bottom = offsets.bottom - containerOffsets.top;
// Clear a rectangular are covering the alignment container.
switch (this.axes) {
@ -711,18 +714,22 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
case "horizontal-lr vertical-bt":
case "horizontal-rl vertical-tb":
case "horizontal-rl vertical-bt":
clearRect(this.ctx, left, Math.round(crossStart) + 2, right,
Math.round(crossStart + crossSize) - 2, this.currentMatrix);
clearRect(this.ctx,
left, Math.round(crossStart) + 2 * lineWidth, right,
Math.round(crossStart + crossSize) - 2 * lineWidth, this.currentMatrix);
break;
case "vertical-tb horizontal-lr":
case "vertical-bt horizontal-rl":
clearRect(this.ctx, Math.round(crossStart) + 1, top,
Math.round(crossStart + crossSize), bottom, this.currentMatrix);
clearRect(this.ctx,
Math.round(crossStart) + lineWidth * 2, top,
Math.round(crossStart + crossSize) - lineWidth, bottom, this.currentMatrix);
break;
case "vertical-bt horizontal-lr":
case "vertical-tb horizontal-rl":
clearRect(this.ctx, Math.round(bounds.width - crossStart - crossSize) + 1,
top, Math.round(bounds.width - crossStart), bottom, this.currentMatrix);
clearRect(this.ctx,
Math.round(clientWidth - crossStart - crossSize) + lineWidth * 2, top,
Math.round(clientWidth - crossStart) - lineWidth, bottom,
this.currentMatrix);
break;
}
}
@ -888,4 +895,55 @@ function compareFlexData(oldFlexData, newFlexData) {
return false;
}
/**
* Get the untransformed coordinates for a node.
*
* @param {DOMNode} node
* The node for which the coordinates are to be returned.
*
* @returns {Object}
* {
* left: left, // The absolute left coordinates of the node.
* top: top, // The absolute top coordinates of the node.
* right: right, // The absolute right coordinates of the node.
* bottom: bottom, // The absolute left coordinates of the node.
* width: width, // The width of the node.
* height, // The Height of the node.
* }
*/
function getNodeRect(node) {
if (node.nodeType === node.TEXT_NODE) {
// For now ignore text node flex items because we cannot get the
// untransformed position and dimensions of a text node
// (see https://bugzil.la/1505079).
return null;
}
const win = node.ownerGlobal;
const style = win.getComputedStyle(node);
const borderLeft = parseInt(style.borderLeftWidth, 10) || 0;
const borderTop = parseInt(style.borderTopWidth, 10) || 0;
const width = node.offsetWidth;
const height = node.offsetHeight;
let left = 0;
let top = 0;
while (node) {
left += node.offsetLeft - node.scrollLeft + node.clientLeft;
top += node.offsetTop - node.scrollTop + node.clientTop;
node = node.offsetParent;
}
return {
left: left - borderLeft,
top: top - borderTop,
right: left + width - borderLeft,
bottom: top + height - borderTop,
width: width,
height: height,
};
}
exports.FlexboxHighlighter = FlexboxHighlighter;

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

@ -1071,6 +1071,72 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
return ancestors;
},
/**
* Return an object with information about this rule used for tracking changes.
* It will be decorated with information about a CSS change before being tracked.
*
* It contains:
* - the rule selector (or generated selectror for inline styles)
* - the rule's host stylesheet (or element for inline styles)
* - the rule's ancestor rules (@media, @supports, @keyframes), if any
* - the rule's position within its ancestor tree, if any
*
* @return {Object}
*/
get metadata() {
const data = {};
// Collect information about the rule's ancestors (@media, @supports, @keyframes).
// Used to show context for this change in the UI and to match the rule for undo/redo.
data.ancestors = this.ancestorRules.map(rule => {
return {
// Rule type as number defined by CSSRule.type (ex: 4, 7, 12)
// @see https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
type: rule.rawRule.type,
// Rule type as human-readable string (ex: "@media", "@supports", "@keyframes")
typeName: CSSRuleTypeName[rule.rawRule.type],
// Conditions of @media and @supports rules (ex: "min-width: 1em")
conditionText: rule.rawRule.conditionText,
// Name of @keyframes rule; refrenced by the animation-name CSS property.
name: rule.rawRule.name,
// Selector of individual @keyframe rule within a @keyframes rule (ex: 0%, 100%).
keyText: rule.rawRule.keyText,
// Array with the indexes of this rule and its ancestors within the CSS rule tree.
ruleIndex: rule._ruleIndex,
};
});
// For changes in element style attributes, generate a unique selector.
if (this.type === ELEMENT_STYLE) {
// findCssSelector() fails on XUL documents. Catch and silently ignore that error.
try {
data.selector = findCssSelector(this.rawNode);
} catch (err) {}
data.source = {
type: "element",
// Used to differentiate between elements which match the same generated selector
// but live in different documents (ex: host document and iframe).
href: this.rawNode.baseURI,
// Element style attributes don't have a rule index; use the generated selector.
index: data.selector,
};
data.ruleIndex = 0;
} else {
data.selector = (this.type === CSSRule.KEYFRAME_RULE)
? this.rawRule.keyText
: this.rawRule.selectorText;
data.source = {
type: "stylesheet",
href: this.sheetActor.href,
index: this.sheetActor.styleSheetIndex,
};
// Used to differentiate between changes to rules with identical selectors.
data.ruleIndex = this._ruleIndex;
}
return data;
},
getDocument: function(sheet) {
if (sheet.ownerNode) {
return sheet.ownerNode.nodeType == sheet.ownerNode.DOCUMENT_NODE ?
@ -1346,7 +1412,7 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
}
// Log the changes before applying them so we have access to the previous values.
modifications.map(mod => this.logChange(mod));
modifications.map(mod => this.logDeclarationChange(mod));
if (this.type === ELEMENT_STYLE) {
// For element style rules, set the node's style attribute.
@ -1406,7 +1472,7 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
const tempElement = document.createElementNS(XHTML_NS, "div");
for (const mod of modifications) {
this.logChange(mod);
this.logDeclarationChange(mod);
if (mod.type === "set") {
tempElement.style.setProperty(mod.name, mod.value, mod.priority || "");
this.rawStyle.setProperty(mod.name,
@ -1482,13 +1548,13 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
},
/**
* Take an object with instructions to modify a CSS declaration and emit a
* "track-change" event with normalized metadata which describes the change.
* Take an object with instructions to modify a CSS declaration and log an object with
* normalized metadata which describes the change in the context of this rule.
*
* @param {Object} change
* Data about a modification to a rule. @see |modifyProperties()|
*/
logChange(change) {
logDeclarationChange(change) {
// Destructure properties from the previous CSS declaration at this index, if any,
// to new variable names to indicate the previous state.
let {
@ -1503,59 +1569,11 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
// Append the "!important" string if defined in the previous priority flag.
prevValue = (prevValue && prevPriority) ? `${prevValue} !important` : prevValue;
// Metadata about a change.
const data = {};
// Collect information about the rule's ancestors (@media, @supports, @keyframes).
// Used to show context for this change in the UI and to match the rule for undo/redo.
data.ancestors = this.ancestorRules.map(rule => {
return {
// Rule type as number defined by CSSRule.type (ex: 4, 7, 12)
// @see https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
type: rule.rawRule.type,
// Rule type as human-readable string (ex: "@media", "@supports", "@keyframes")
typeName: CSSRuleTypeName[rule.rawRule.type],
// Conditions of @media and @supports rules (ex: "min-width: 1em")
conditionText: rule.rawRule.conditionText,
// Name of @keyframes rule; refrenced by the animation-name CSS property.
name: rule.rawRule.name,
// Selector of individual @keyframe rule within a @keyframes rule (ex: 0%, 100%).
keyText: rule.rawRule.keyText,
// Array with the indexes of this rule and its ancestors within the CSS rule tree.
ruleIndex: rule._ruleIndex,
};
});
// For changes in element style attributes, generate a unique selector.
if (this.type === ELEMENT_STYLE) {
// findCssSelector() fails on XUL documents. Catch and silently ignore that error.
try {
data.selector = findCssSelector(this.rawNode);
} catch (err) {}
data.source = {
type: "element",
// Used to differentiate between elements which match the same generated selector
// but live in different documents (ex: host document and iframe).
href: this.rawNode.baseURI,
// Element style attributes don't have a rule index; use the generated selector.
index: data.selector,
};
data.ruleIndex = 0;
} else {
data.selector = (this.type === CSSRule.KEYFRAME_RULE)
? this.rawRule.keyText
: this.rawRule.selectorText;
data.source = {
type: "stylesheet",
href: this.sheetActor.href,
index: this.sheetActor.styleSheetIndex,
};
// Used to differentiate between changes to rules with identical selectors.
data.ruleIndex = this._ruleIndex;
}
const data = this.metadata;
switch (change.type) {
case "set":
data.type = prevValue ? "declaration-add" : "declaration-update";
// If `change.newName` is defined, use it because the property is being renamed.
// Otherwise, a new declaration is being created or the value of an existing
// declaration is being updated. In that case, use the provided `change.name`.
@ -1566,11 +1584,11 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
// Otherwise, use the incoming value string.
const value = change.newName ? prevValue : newValue;
data.add = { property: name, value };
data.add = { [name]: value };
// If there is a previous value, log its removal together with the previous
// property name. Using the previous name handles the case for renaming a property
// and is harmless when updating an existing value (the name stays the same).
data.remove = prevValue ? { property: prevName, value: prevValue } : null;
data.remove = prevValue ? { [prevName]: prevValue } : null;
// When toggling a declaration from OFF to ON, if not renaming the property,
// do not mark the previous declaration for removal, otherwise the add and
@ -1583,14 +1601,52 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
break;
case "remove":
data.type = "declaration-remove";
data.add = null;
data.remove = { property: change.name, value: prevValue };
data.remove = { [change.name]: prevValue };
break;
}
TrackChangeEmitter.trackChange(data);
},
/**
* Helper method for tracking CSS changes. Logs the change of this rule's selector as
* two operations: a rule removal, including its CSS declarations, using the old
* selector and a rule addition using the new selector.
*
* @param {String} oldSelector
* This rule's previous selector.
* @param {String} newSelector
* This rule's new selector.
*/
logSelectorChange(oldSelector, newSelector) {
// Build a collection of CSS declarations existing on this rule.
const declarations = this._declarations.reduce((acc, decl) => {
acc[decl.name] = decl.priority ? decl.value + " !important" : decl.value;
return acc;
}, {});
// Logging two distinct operations to remove the old rule and add a new one.
// TODO: Make TrackChangeEmitter support transactions so these two operations are
// grouped together when implementing undo/redo.
TrackChangeEmitter.trackChange({
...this.metadata,
type: "rule-remove",
add: null,
remove: declarations,
selector: oldSelector,
});
TrackChangeEmitter.trackChange({
...this.metadata,
type: "rule-add",
add: declarations,
remove: null,
selector: newSelector,
});
},
/**
* Calls modifySelector2() which needs to be kept around for backwards compatibility.
* TODO: Once Firefox 64 is no longer supported, inline that mehtod's content,
@ -1628,11 +1684,14 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
return { ruleProps: null, isMatching: true };
}
// The rule's previous selector is lost after calling _addNewSelector(). Save it now.
const oldValue = this.rawRule.selectorText;
let selectorPromise = this._addNewSelector(value, editAuthored);
if (editAuthored) {
selectorPromise = selectorPromise.then((newCssRule) => {
if (newCssRule) {
this.logSelectorChange(oldValue, value);
const style = this.pageStyle._styleRef(newCssRule);
// See the comment in |form| to understand this.
return style.getAuthoredCssText().then(() => newCssRule);

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

@ -85,6 +85,7 @@ var DebuggerServer = {
this._nextConnID = 0;
this._initialized = true;
this._onSocketListenerAccepted = this._onSocketListenerAccepted.bind(this);
},
get protocol() {
@ -225,6 +226,7 @@ var DebuggerServer = {
* SocketListeners. This is called by a SocketListener after it is opened.
*/
_addListener(listener) {
listener.on("accepted", this._onSocketListenerAccepted);
this._listeners.push(listener);
},
@ -233,7 +235,16 @@ var DebuggerServer = {
* SocketListeners. This is called by a SocketListener after it is closed.
*/
_removeListener(listener) {
// Remove connections that were accepted in the listener.
for (const connID of Object.getOwnPropertyNames(this._connections)) {
const connection = this._connections[connID];
if (connection.isAcceptedBy(listener)) {
connection.close();
}
}
this._listeners = this._listeners.filter(l => l !== listener);
listener.off("accepted", this._onSocketListenerAccepted);
},
/**
@ -254,6 +265,10 @@ var DebuggerServer = {
return true;
},
_onSocketListenerAccepted(transport, listener) {
this._onConnection(transport, null, false, listener);
},
/**
* Creates a new connection to the local debugger speaking over a fake
* transport. This connection results in straightforward calls to the onPacket
@ -863,7 +878,7 @@ var DebuggerServer = {
* that all our actors have names beginning with |forwardingPrefix + '/'|.
* In particular, the root actor's name will be |forwardingPrefix + '/root'|.
*/
_onConnection(transport, forwardingPrefix, noRootActor = false) {
_onConnection(transport, forwardingPrefix, noRootActor = false, socketListener = null) {
let connID;
if (forwardingPrefix) {
connID = forwardingPrefix + "/";
@ -875,7 +890,7 @@ var DebuggerServer = {
connID = "server" + loader.id + ".conn" + this._nextConnID++ + ".";
}
const conn = new DebuggerServerConnection(connID, transport);
const conn = new DebuggerServerConnection(connID, transport, socketListener);
this._connections[connID] = conn;
// Create a root actor for the connection and send the hello packet.
@ -974,12 +989,16 @@ exports.DebuggerServer = DebuggerServer;
* with prefix.
* @param transport transport
* Packet transport for the debugging protocol.
* @param socketListener SocketListener
* SocketListener which accepted the transport.
* If this is null, the transport is not that was accepted by SocketListener.
*/
function DebuggerServerConnection(prefix, transport) {
function DebuggerServerConnection(prefix, transport, socketListener) {
this._prefix = prefix;
this._transport = transport;
this._transport.hooks = this;
this._nextID = 1;
this._socketListener = socketListener;
this._actorPool = new Pool(this);
this._extraPools = [this._actorPool];
@ -1225,6 +1244,17 @@ DebuggerServerConnection.prototype = {
});
},
/**
* This function returns whether the connection was accepted by passed SocketListener.
*
* @param {SocketListener} socketListener
* @return {Boolean} return true if this connection was accepted by socketListener,
* else returns false.
*/
isAcceptedBy(socketListener) {
return this._socketListener === socketListener;
},
/* Forwarding packets to other transports based on actor name prefixes. */
/*

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

@ -32,6 +32,7 @@ loader.lazyRequireGetter(this, "Authenticators",
"devtools/shared/security/auth", true);
loader.lazyRequireGetter(this, "AuthenticationResult",
"devtools/shared/security/auth", true);
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
DevToolsUtils.defineLazyGetter(this, "nsFile", () => {
return CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
@ -366,7 +367,9 @@ function _storeCertOverride(s, host, port) {
* This helps contain and organize the parts of the server that may differ or
* are particular to one given listener mechanism vs. another.
*/
function SocketListener() {}
function SocketListener() {
EventEmitter.decorate(this);
}
SocketListener.prototype = {
@ -544,11 +547,17 @@ SocketListener.prototype = {
};
},
onAllowedConnection(transport) {
dumpn("onAllowedConnection, transport: " + transport);
this.emit("accepted", transport, this);
},
// nsIServerSocketListener implementation
onSocketAccepted:
DevToolsUtils.makeInfallible(function(socket, socketTransport) {
new ServerSocketConnection(this, socketTransport);
const connection = new ServerSocketConnection(this, socketTransport);
connection.once("allowed", this.onAllowedConnection.bind(this));
}, "SocketListener.onSocketAccepted"),
onStopListening: function(socket, status) {
@ -572,6 +581,7 @@ function ServerSocketConnection(listener, socketTransport) {
this._listener = listener;
this._socketTransport = socketTransport;
this._handle();
EventEmitter.decorate(this);
}
ServerSocketConnection.prototype = {
@ -628,15 +638,17 @@ ServerSocketConnection.prototype = {
* the connection is denied. If the entire process resolves successfully,
* the connection is finally handed off to the |DebuggerServer|.
*/
_handle() {
async _handle() {
dumpn("Debugging connection starting authentication on " + this.address);
const self = this;
(async function() {
self._listenForTLSHandshake();
await self._createTransport();
await self._awaitTLSHandshake();
await self._authenticate();
})().then(() => this.allow()).catch(e => this.deny(e));
try {
this._listenForTLSHandshake();
await this._createTransport();
await this._awaitTLSHandshake();
await this._authenticate();
this.allow();
} catch (e) {
this.deny(e);
}
},
/**
@ -774,7 +786,7 @@ ServerSocketConnection.prototype = {
return;
}
dumpn("Debugging connection allowed on " + this.address);
DebuggerServer._onConnection(this._transport);
this.emit("allowed", this._transport);
this.destroy();
},

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

@ -148,19 +148,23 @@ void KeyboardEvent::GetInitDict(KeyboardEventInit& aParam)
bool
KeyboardEvent::ShouldUseSameValueForCharCodeAndKeyCode(
const WidgetKeyboardEvent& aWidgetKeyboardEvent,
CallerType aCallerType) const
{
// - If this event is initialized by JS, we don't need to return same value
// for keyCode and charCode since they can be initialized separately.
// - If this is not a keypress event, we shouldn't return same value for
// keyCode and charCode.
// - If we need to return legacy keyCode and charCode values for the web
// app due to in the blacklist.
// - If this event is referred by default handler, i.e., the caller is
// system or this event is now in the system group, we don't need to use
// hack for web-compat.
if (mInitializedByJS ||
mEvent->mMessage != eKeyPress ||
aWidgetKeyboardEvent.mMessage != eKeyPress ||
aWidgetKeyboardEvent.mUseLegacyKeyCodeAndCharCodeValues ||
aCallerType == CallerType::System ||
mEvent->mFlags.mInSystemGroup) {
aWidgetKeyboardEvent.mFlags.mInSystemGroup) {
return false;
}
@ -193,7 +197,8 @@ KeyboardEvent::CharCode(CallerType aCallerType)
// value.
if (widgetKeyboardEvent->mKeyNameIndex != KEY_NAME_INDEX_USE_STRING &&
ShouldUseSameValueForCharCodeAndKeyCode(aCallerType)) {
ShouldUseSameValueForCharCodeAndKeyCode(*widgetKeyboardEvent,
aCallerType)) {
return ComputeTraditionalKeyCode(*widgetKeyboardEvent, aCallerType);
}
@ -226,7 +231,8 @@ KeyboardEvent::KeyCode(CallerType aCallerType)
// for keyCode value if this is a "keypress" event.
if (widgetKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
ShouldUseSameValueForCharCodeAndKeyCode(aCallerType)) {
ShouldUseSameValueForCharCodeAndKeyCode(*widgetKeyboardEvent,
aCallerType)) {
return widgetKeyboardEvent->mCharCode;
}

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

@ -130,7 +130,9 @@ private:
* ShouldUseSameValueForCharCodeAndKeyCode() returns true if KeyCode() and
* CharCode() should return same value.
*/
bool ShouldUseSameValueForCharCodeAndKeyCode(CallerType aCallerType) const;
bool ShouldUseSameValueForCharCodeAndKeyCode(
const WidgetKeyboardEvent& aKeyboardEvent,
CallerType aCallerType) const;
};
} // namespace dom

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

@ -10,6 +10,11 @@
* liability, trademark and document use rules apply.
*/
enum AutomationRate {
"a-rate",
"k-rate"
};
[Pref="dom.webaudio.enabled"]
interface AudioParam {

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

@ -712,6 +712,56 @@ TextEditor::DeleteSelectionAsAction(EDirection aDirection,
return NS_ERROR_NOT_INITIALIZED;
}
// If there is an existing selection when an extended delete is requested,
// platforms that use "caret-style" caret positioning collapse the
// selection to the start and then create a new selection.
// Platforms that use "selection-style" caret positioning just delete the
// existing selection without extending it.
if (!SelectionRefPtr()->IsCollapsed()) {
switch (aDirection) {
case eNextWord:
case ePreviousWord:
case eToBeginningOfLine:
case eToEndOfLine: {
if (mCaretStyle != 1) {
aDirection = eNone;
break;
}
ErrorResult error;
SelectionRefPtr()->CollapseToStart(error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
break;
}
default:
break;
}
}
// If Selection is still NOT collapsed, it does not important removing
// range of the operation since we'll remove the selected content. However,
// information of direction (backward or forward) may be important for
// web apps. E.g., web apps may want to mark selected range as "deleted"
// and move caret before or after the range. Therefore, we should forget
// only the range information but keep range information. See discussion
// of the spec issue for the detail:
// https://github.com/w3c/input-events/issues/82
if (!SelectionRefPtr()->IsCollapsed()) {
switch (editAction) {
case EditAction::eDeleteWordBackward:
case EditAction::eDeleteToBeginningOfSoftLine:
editActionData.UpdateEditAction(EditAction::eDeleteBackward);
break;
case EditAction::eDeleteWordForward:
case EditAction::eDeleteToEndOfSoftLine:
editActionData.UpdateEditAction(EditAction::eDeleteForward);
break;
default:
break;
}
}
// delete placeholder txns merge.
AutoPlaceholderBatch treatAsOneTransaction(*this, *nsGkAtoms::DeleteTxnName);
nsresult rv = DeleteSelectionAsSubAction(aDirection, aStripWrappers);
@ -737,33 +787,6 @@ TextEditor::DeleteSelectionAsSubAction(EDirection aDirection,
// Protect the edit rules object from dying
RefPtr<TextEditRules> rules(mRules);
// If there is an existing selection when an extended delete is requested,
// platforms that use "caret-style" caret positioning collapse the
// selection to the start and then create a new selection.
// Platforms that use "selection-style" caret positioning just delete the
// existing selection without extending it.
if (!SelectionRefPtr()->IsCollapsed()) {
switch (aDirection) {
case eNextWord:
case ePreviousWord:
case eToBeginningOfLine:
case eToEndOfLine: {
if (mCaretStyle != 1) {
aDirection = eNone;
break;
}
ErrorResult error;
SelectionRefPtr()->CollapseToStart(error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
break;
}
default:
break;
}
}
AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
*this,
EditSubAction::eDeleteSelectedContent,

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

@ -1557,7 +1557,9 @@ impl Device {
debug_assert!(self.inside_frame);
debug_assert!(dst.width >= src.width);
debug_assert!(dst.height >= src.height);
debug_assert!(dst.layer_count >= src.layer_count);
// Note that zip() truncates to the shorter of the two iterators.
let rect = DeviceIntRect::new(DeviceIntPoint::zero(), src.get_dimensions().to_i32());
for (read_fbo, draw_fbo) in src.fbos.iter().zip(&dst.fbos) {
self.bind_read_target_impl(*read_fbo);

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

@ -110,48 +110,138 @@ pub enum TextureUpdateSource {
Bytes { data: Arc<Vec<u8>> },
}
/// Command to allocate, reallocate, or free a texture for the texture cache.
#[derive(Debug)]
pub enum TextureUpdateOp {
Create {
width: u32,
height: u32,
format: ImageFormat,
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
layer_count: i32,
},
Update {
rect: DeviceUintRect,
stride: Option<u32>,
offset: u32,
layer_index: i32,
source: TextureUpdateSource,
},
pub struct TextureCacheAllocation {
/// The virtual ID (i.e. distinct from device ID) of the texture.
pub id: CacheTextureId,
/// Details corresponding to the operation in question.
pub kind: TextureCacheAllocationKind,
}
/// Information used when allocating / reallocating.
#[derive(Debug)]
pub struct TextureCacheAllocInfo {
pub width: u32,
pub height: u32,
pub layer_count: i32,
pub format: ImageFormat,
pub filter: TextureFilter,
}
/// Sub-operation-specific information for allocation operations.
#[derive(Debug)]
pub enum TextureCacheAllocationKind {
/// Performs an initial texture allocation.
Alloc(TextureCacheAllocInfo),
/// Reallocates the texture. The existing live texture with the same id
/// will be deallocated and its contents blitted over. The new size must
/// be greater than the old size.
Realloc(TextureCacheAllocInfo),
/// Frees the texture and the corresponding cache ID.
Free,
}
/// Command to update the contents of the texture cache.
#[derive(Debug)]
pub struct TextureUpdate {
pub struct TextureCacheUpdate {
pub id: CacheTextureId,
pub op: TextureUpdateOp,
pub rect: DeviceUintRect,
pub stride: Option<u32>,
pub offset: u32,
pub layer_index: i32,
pub source: TextureUpdateSource,
}
/// Atomic set of commands to manipulate the texture cache, generated on the
/// RenderBackend thread and executed on the Renderer thread.
///
/// The list of allocation operations is processed before the updates. This is
/// important to allow coalescing of certain allocation operations.
#[derive(Default)]
pub struct TextureUpdateList {
pub updates: Vec<TextureUpdate>,
/// Commands to alloc/realloc/free the textures. Processed first.
pub allocations: Vec<TextureCacheAllocation>,
/// Commands to update the contents of the textures. Processed second.
pub updates: Vec<TextureCacheUpdate>,
}
impl TextureUpdateList {
/// Mints a new `TextureUpdateList`.
pub fn new() -> Self {
TextureUpdateList {
allocations: Vec::new(),
updates: Vec::new(),
}
}
/// Pushes an update operation onto the list.
#[inline]
pub fn push(&mut self, update: TextureUpdate) {
pub fn push_update(&mut self, update: TextureCacheUpdate) {
self.updates.push(update);
}
/// Pushes an allocation operation onto the list.
pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
debug_assert!(!self.allocations.iter().any(|x| x.id == id));
self.allocations.push(TextureCacheAllocation {
id,
kind: TextureCacheAllocationKind::Alloc(info),
});
}
/// Pushes a reallocation operation onto the list, potentially coalescing
/// with previous operations.
pub fn push_realloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
self.debug_assert_coalesced(id);
// Coallesce this realloc into a previous alloc or realloc, if available.
if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
match cur.kind {
TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
TextureCacheAllocationKind::Realloc(ref mut i) => *i = info,
TextureCacheAllocationKind::Free => panic!("Reallocating freed texture"),
}
return;
}
self.allocations.push(TextureCacheAllocation {
id,
kind: TextureCacheAllocationKind::Realloc(info),
});
}
/// Pushes a free operation onto the list, potentially coalescing with
/// previous operations.
pub fn push_free(&mut self, id: CacheTextureId) {
self.debug_assert_coalesced(id);
// Drop any unapplied updates to the to-be-freed texture.
self.updates.retain(|x| x.id != id);
// Drop any allocations for it as well. If we happen to be allocating and
// freeing in the same batch, we can collapse them to a no-op.
let idx = self.allocations.iter().position(|x| x.id == id);
let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
match removed_kind {
Some(TextureCacheAllocationKind::Alloc(..)) => { /* no-op! */ },
Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
Some(TextureCacheAllocationKind::Realloc(..)) | None => {
self.allocations.push(TextureCacheAllocation {
id,
kind: TextureCacheAllocationKind::Free,
});
}
};
}
fn debug_assert_coalesced(&self, id: CacheTextureId) {
debug_assert!(
self.allocations.iter().filter(|x| x.id == id).count() <= 1,
"Allocations should have been coalesced",
);
}
}
/// Wraps a tiling::Frame, but conceptually could hold more information

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

@ -53,8 +53,8 @@ use gpu_cache::GpuDebugChunk;
use gpu_glyph_renderer::GpuGlyphRenderer;
use gpu_types::ScalingInstance;
use internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg};
use internal_types::{LayerIndex, TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
use internal_types::{CacheTextureId, DebugOutput, FastHashMap, LayerIndex, RenderedDocument, ResultMsg};
use internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource};
use internal_types::{RenderTargetInfo, SavedTargetIndex};
use prim_store::DeferredResolve;
use profiler::{BackendProfileCounters, FrameProfileCounters,
@ -2800,90 +2800,92 @@ impl Renderer {
let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
for update_list in pending_texture_updates.drain(..) {
for update in update_list.updates {
match update.op {
TextureUpdateOp::Create {
width,
height,
layer_count,
format,
filter,
render_target,
} => {
for allocation in update_list.allocations {
let is_realloc = matches!(allocation.kind, TextureCacheAllocationKind::Realloc(..));
match allocation.kind {
TextureCacheAllocationKind::Alloc(info) |
TextureCacheAllocationKind::Realloc(info) => {
// Create a new native texture, as requested by the texture cache.
//
// Ensure no PBO is bound when creating the texture storage,
// or GL will attempt to read data from there.
let texture = self.device.create_texture(
TextureTarget::Array,
format,
width,
height,
filter,
render_target,
layer_count,
);
self.texture_resolver.texture_cache_map.insert(update.id, texture);
}
TextureUpdateOp::Update {
rect,
source,
stride,
layer_index,
offset,
} => {
let texture = &self.texture_resolver.texture_cache_map[&update.id];
let mut uploader = self.device.upload_texture(
texture,
&self.texture_cache_upload_pbo,
0,
info.format,
info.width,
info.height,
info.filter,
// This needs to be a render target because some render
// tasks get rendered into the texture cache.
Some(RenderTargetInfo { has_depth: false }),
info.layer_count,
);
let bytes_uploaded = match source {
TextureUpdateSource::Bytes { data } => {
let old = self.texture_resolver.texture_cache_map.insert(allocation.id, texture);
assert_eq!(old.is_some(), is_realloc, "Renderer and RenderBackend disagree");
if let Some(old) = old {
self.device.blit_renderable_texture(
self.texture_resolver.texture_cache_map.get_mut(&allocation.id).unwrap(),
&old
);
self.device.delete_texture(old);
}
},
TextureCacheAllocationKind::Free => {
let texture = self.texture_resolver.texture_cache_map.remove(&allocation.id).unwrap();
self.device.delete_texture(texture);
},
}
}
for update in update_list.updates {
let TextureCacheUpdate { id, rect, stride, offset, layer_index, source } = update;
let texture = &self.texture_resolver.texture_cache_map[&id];
let mut uploader = self.device.upload_texture(
texture,
&self.texture_cache_upload_pbo,
0,
);
let bytes_uploaded = match source {
TextureUpdateSource::Bytes { data } => {
uploader.upload(
rect, layer_index, stride,
&data[offset as usize ..],
)
}
TextureUpdateSource::External { id, channel_index } => {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
// The filter is only relevant for NativeTexture external images.
let size = match handler.lock(id, channel_index, ImageRendering::Auto).source {
ExternalImageSource::RawData(data) => {
uploader.upload(
rect, layer_index, stride,
&data[offset as usize ..],
)
}
TextureUpdateSource::External { id, channel_index } => {
let handler = self.external_image_handler
.as_mut()
.expect("Found external image, but no handler set!");
// The filter is only relevant for NativeTexture external images.
let size = match handler.lock(id, channel_index, ImageRendering::Auto).source {
ExternalImageSource::RawData(data) => {
uploader.upload(
rect, layer_index, stride,
&data[offset as usize ..],
)
}
ExternalImageSource::Invalid => {
// Create a local buffer to fill the pbo.
let bpp = texture.get_format().bytes_per_pixel();
let width = stride.unwrap_or(rect.size.width * bpp);
let total_size = width * rect.size.height;
// WR haven't support RGBAF32 format in texture_cache, so
// we use u8 type here.
let dummy_data: Vec<u8> = vec![255; total_size as usize];
uploader.upload(rect, layer_index, stride, &dummy_data)
}
ExternalImageSource::NativeTexture(eid) => {
panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
}
};
handler.unlock(id, channel_index);
size
ExternalImageSource::Invalid => {
// Create a local buffer to fill the pbo.
let bpp = texture.get_format().bytes_per_pixel();
let width = stride.unwrap_or(rect.size.width * bpp);
let total_size = width * rect.size.height;
// WR haven't support RGBAF32 format in texture_cache, so
// we use u8 type here.
let dummy_data: Vec<u8> = vec![255; total_size as usize];
uploader.upload(rect, layer_index, stride, &dummy_data)
}
ExternalImageSource::NativeTexture(eid) => {
panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
}
};
handler.unlock(id, channel_index);
size
}
};
self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
}
TextureUpdateOp::Free => {
let texture = self.texture_resolver.texture_cache_map.remove(&update.id).unwrap();
self.device.delete_texture(texture);
}
}
self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
}
}

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

@ -10,7 +10,7 @@ use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::{ImageSource, UvRectKind};
use internal_types::{CacheTextureId, LayerIndex, TextureUpdateList, TextureUpdateSource};
use internal_types::{RenderTargetInfo, TextureSource, TextureUpdate, TextureUpdateOp};
use internal_types::{TextureSource, TextureCacheAllocInfo, TextureCacheUpdate};
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
use render_backend::FrameId;
use resource_cache::CacheItem;
@ -19,7 +19,7 @@ use std::cmp;
use std::mem;
use std::rc::Rc;
// The size of each region (page) in a texture layer.
/// The size of each region/layer in shared cache texture arrays.
const TEXTURE_REGION_DIMENSIONS: u32 = 512;
// Items in the texture cache can either be standalone textures,
@ -33,9 +33,7 @@ enum EntryKind {
// Origin within the texture layer where this item exists.
origin: DeviceUintPoint,
// The layer index of the texture array.
layer_index: u16,
// The region that this entry belongs to in the layer.
region_index: u16,
layer_index: usize,
},
}
@ -191,15 +189,99 @@ impl EvictionNotice {
}
}
/// A set of lazily allocated, fixed size, texture arrays for each format the
/// texture cache supports.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureCache {
// A lazily allocated, fixed size, texture array for
// each format the texture cache supports.
struct SharedTextures {
array_rgba8_nearest: TextureArray,
array_a8_linear: TextureArray,
array_a16_linear: TextureArray,
array_rgba8_linear: TextureArray,
}
impl SharedTextures {
/// Mints a new set of shared textures.
fn new() -> Self {
Self {
// Used primarily for cached shadow masks. There can be lots of
// these on some pages like francine, but most pages don't use it
// much.
array_a8_linear: TextureArray::new(
ImageFormat::R8,
TextureFilter::Linear,
4,
),
// Used for experimental hdr yuv texture support, but not used in
// production Firefox.
array_a16_linear: TextureArray::new(
ImageFormat::R16,
TextureFilter::Linear,
4,
),
// The primary cache for images, glyphs, etc.
array_rgba8_linear: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Linear,
16 * 4,
),
// Used for image-rendering: crisp. This is mostly favicons, which
// are small. Some other images use it too, but those tend to be
// larger than 512x512 and thus don't use the shared cache anyway.
//
// Even though most of the buckets will be sparsely-used, we still
// need a few to account for different favicon sizes. 4 seems enough
// in practice, though we might also be able to get away with 2 or 3.
array_rgba8_nearest: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Nearest,
4,
),
}
}
/// Clears each texture in the set, with the given set of pending updates.
fn clear(&mut self, updates: &mut TextureUpdateList) {
self.array_a8_linear.clear(updates);
self.array_a16_linear.clear(updates);
self.array_rgba8_linear.clear(updates);
self.array_rgba8_nearest.clear(updates);
}
/// Returns a mutable borrow for the shared texture array matching the parameters.
fn select(&mut self, format: ImageFormat, filter: TextureFilter) -> &mut TextureArray {
match (format, filter) {
(ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::R16, TextureFilter::Linear) => &mut self.array_a16_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(_, _) => unreachable!(),
}
}
}
/// General-purpose manager for images in GPU memory. This includes images,
/// rasterized glyphs, rasterized blobs, cached render tasks, etc.
///
/// The texture cache is owned and managed by the RenderBackend thread, and
/// produces a series of commands to manipulate the textures on the Renderer
/// thread. These commands are executed before any rendering is performed for
/// a given frame.
///
/// Entries in the texture cache are not guaranteed to live past the end of the
/// frame in which they are requested, and may be evicted. The API supports
/// querying whether an entry is still available.
///
/// The TextureCache is different from the GpuCache in that the former stores
/// images, whereas the latter stores data and parameters for use in the shaders.
/// This means that the texture cache can be visualized, which is a good way to
/// understand how it works. Enabling gfx.webrender.debug.texture-cache shows a
/// live view of its contents in Firefox.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureCache {
/// Set of texture arrays in different formats used for the shared cache.
shared_textures: SharedTextures,
// Maximum texture size supported by hardware.
max_texture_size: u32,
@ -207,8 +289,9 @@ pub struct TextureCache {
// The next unused virtual texture ID. Monotonically increasing.
next_id: CacheTextureId,
// A list of updates that need to be applied to the
// texture cache in the rendering thread this frame.
// A list of allocations and updates that need to be
// applied to the texture cache in the rendering thread
// this frame.
#[cfg_attr(all(feature = "serde", any(feature = "capture", feature = "replay")), serde(skip))]
pending_updates: TextureUpdateList,
@ -233,46 +316,8 @@ pub struct TextureCache {
impl TextureCache {
pub fn new(max_texture_size: u32) -> Self {
TextureCache {
shared_textures: SharedTextures::new(),
max_texture_size,
// Used primarily for cached shadow masks. There can be lots of
// these on some pages like francine, but most pages don't use it
// much.
array_a8_linear: TextureArray::new(
ImageFormat::R8,
TextureFilter::Linear,
1024,
1,
),
// Used for experimental hdr yuv texture support, but not used in
// production Firefox.
array_a16_linear: TextureArray::new(
ImageFormat::R16,
TextureFilter::Linear,
1024,
1,
),
// The primary cache for images, glyphs, etc.
array_rgba8_linear: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Linear,
2048,
4,
),
// Used for image-rendering: crisp. This is mostly favicons, which
// are small. Some other images use it too, but those tend to be
// larger than 512x512 and thus don't use the shared cache anyway.
//
// Ideally we'd use 512 as the dimensions here, since we don't really
// need more. But once a page gets something of a given size bucket
// assigned to it, all further allocations need to be of that size.
// So using 1024 gives us 4 buckets instead of 1, which in practice
// is probably enough.
array_rgba8_nearest: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Nearest,
1024,
1,
),
next_id: CacheTextureId(1),
pending_updates: TextureUpdateList::new(),
frame_id: FrameId::invalid(),
@ -307,33 +352,7 @@ impl TextureCache {
assert!(self.entries.len() == 0);
if let Some(texture_id) = self.array_a8_linear.clear() {
self.pending_updates.push(TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Free,
});
}
if let Some(texture_id) = self.array_a16_linear.clear() {
self.pending_updates.push(TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Free,
});
}
if let Some(texture_id) = self.array_rgba8_linear.clear() {
self.pending_updates.push(TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Free,
});
}
if let Some(texture_id) = self.array_rgba8_nearest.clear() {
self.pending_updates.push(TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Free,
});
}
self.shared_textures.clear(&mut self.pending_updates);
}
pub fn begin_frame(&mut self, frame_id: FrameId) {
@ -343,13 +362,13 @@ impl TextureCache {
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
self.expire_old_standalone_entries();
self.array_a8_linear
self.shared_textures.array_a8_linear
.update_profile(&mut texture_cache_profile.pages_a8_linear);
self.array_a16_linear
self.shared_textures.array_a16_linear
.update_profile(&mut texture_cache_profile.pages_a16_linear);
self.array_rgba8_linear
self.shared_textures.array_rgba8_linear
.update_profile(&mut texture_cache_profile.pages_rgba8_linear);
self.array_rgba8_nearest
self.shared_textures.array_rgba8_nearest
.update_profile(&mut texture_cache_profile.pages_rgba8_nearest);
}
@ -461,7 +480,7 @@ impl TextureCache {
} => (layer_index, origin),
};
let op = TextureUpdate::new_update(
let op = TextureCacheUpdate::new_update(
data,
&descriptor,
origin,
@ -470,7 +489,7 @@ impl TextureCache {
layer_index as i32,
dirty_rect,
);
self.pending_updates.push(op);
self.pending_updates.push_update(op);
}
}
@ -478,24 +497,10 @@ impl TextureCache {
fn get_region_mut(&mut self,
format: ImageFormat,
filter: TextureFilter,
region_index: u16
layer_index: usize,
) -> &mut TextureRegion {
let texture_array = match (format, filter) {
(ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::R16, TextureFilter::Linear) => &mut self.array_a16_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGBAF32, _) |
(ImageFormat::RG8, _) |
(ImageFormat::RGBAI32, _) |
(ImageFormat::R8, TextureFilter::Nearest) |
(ImageFormat::R8, TextureFilter::Trilinear) |
(ImageFormat::R16, TextureFilter::Nearest) |
(ImageFormat::R16, TextureFilter::Trilinear) |
(ImageFormat::BGRA8, TextureFilter::Trilinear) => unreachable!(),
};
&mut texture_array.regions[region_index as usize]
let texture_array = self.shared_textures.select(format, filter);
&mut texture_array.regions[layer_index]
}
// Check if a given texture handle has a valid allocation
@ -691,22 +696,18 @@ impl TextureCache {
match entry.kind {
EntryKind::Standalone { .. } => {
// This is a standalone texture allocation. Free it directly.
self.pending_updates.push(TextureUpdate {
id: entry.texture_id,
op: TextureUpdateOp::Free,
});
self.pending_updates.push_free(entry.texture_id);
None
}
EntryKind::Cache {
origin,
region_index,
..
layer_index,
} => {
// Free the block in the given region.
let region = self.get_region_mut(
entry.format,
entry.filter,
region_index
layer_index,
);
region.free(origin);
Some(region)
@ -722,43 +723,26 @@ impl TextureCache {
user_data: [f32; 3],
uv_rect_kind: UvRectKind,
) -> Option<CacheEntry> {
// Work out which cache it goes in, based on format.
let texture_array = match (descriptor.format, filter) {
(ImageFormat::R8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::R16, TextureFilter::Linear) => &mut self.array_a16_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGBAF32, _) |
(ImageFormat::RGBAI32, _) |
(ImageFormat::R8, TextureFilter::Nearest) |
(ImageFormat::R8, TextureFilter::Trilinear) |
(ImageFormat::R16, TextureFilter::Nearest) |
(ImageFormat::R16, TextureFilter::Trilinear) |
(ImageFormat::BGRA8, TextureFilter::Trilinear) |
(ImageFormat::RG8, _) => unreachable!(),
};
// Mutably borrow the correct texture.
let texture_array = self.shared_textures.select(descriptor.format, filter);
// Lazy initialize this texture array if required.
if texture_array.texture_id.is_none() {
assert!(texture_array.regions.is_empty());
let texture_id = self.next_id;
self.next_id.0 += 1;
let update_op = TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Create {
width: texture_array.dimensions,
height: texture_array.dimensions,
format: descriptor.format,
filter: texture_array.filter,
// This needs to be a render target because some render
// tasks get rendered into the texture cache.
render_target: Some(RenderTargetInfo { has_depth: false }),
layer_count: texture_array.layer_count as i32,
},
let info = TextureCacheAllocInfo {
width: TEXTURE_REGION_DIMENSIONS,
height: TEXTURE_REGION_DIMENSIONS,
format: descriptor.format,
filter: texture_array.filter,
layer_count: 1,
};
self.pending_updates.push(update_op);
self.pending_updates.push_alloc(texture_id, info);
texture_array.texture_id = Some(texture_id);
texture_array.regions.push(TextureRegion::new(0));
}
// Do the allocation. This can fail and return None
@ -824,6 +808,7 @@ impl TextureCache {
// If it's allowed in the cache, see if there is a spot for it.
if allowed_in_shared_cache {
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
filter,
@ -831,10 +816,36 @@ impl TextureCache {
uv_rect_kind,
);
// If we failed to allocate in the shared cache, run an
// eviction cycle, and then try to allocate again.
// If we failed to allocate in the shared cache, make some space
// and then try to allocate again. If we still have room to grow
// the cache, we do that. Otherwise, we evict.
//
// We should improve this logic to support some degree of eviction
// before the cache fills up eintirely.
if new_cache_entry.is_none() {
self.expire_old_shared_entries(&descriptor);
let reallocated = {
let texture_array = self.shared_textures.select(descriptor.format, filter);
let num_regions = texture_array.regions.len();
if num_regions < texture_array.max_layer_count {
// We have room to grow.
let info = TextureCacheAllocInfo {
width: TEXTURE_REGION_DIMENSIONS,
height: TEXTURE_REGION_DIMENSIONS,
format: descriptor.format,
filter: texture_array.filter,
layer_count: (num_regions + 1) as i32,
};
self.pending_updates.push_realloc(texture_array.texture_id.unwrap(), info);
texture_array.regions.push(TextureRegion::new(num_regions));
true
} else {
false
}
};
if !reallocated {
// Out of room. Evict.
self.expire_old_shared_entries(&descriptor);
}
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
@ -852,20 +863,15 @@ impl TextureCache {
let texture_id = self.next_id;
self.next_id.0 += 1;
// Create an update operation to allocate device storage
// of the right size / format.
let update_op = TextureUpdate {
id: texture_id,
op: TextureUpdateOp::Create {
width: descriptor.size.width,
height: descriptor.size.height,
format: descriptor.format,
filter,
render_target: Some(RenderTargetInfo { has_depth: false }),
layer_count: 1,
},
// Push a command to allocate device storage of the right size / format.
let info = TextureCacheAllocInfo {
width: descriptor.size.width,
height: descriptor.size.height,
format: descriptor.format,
filter,
layer_count: 1,
};
self.pending_updates.push(update_op);
self.pending_updates.push_alloc(texture_id, info);
new_cache_entry = Some(CacheEntry::new_standalone(
texture_id,
@ -976,28 +982,25 @@ impl TextureLocation {
}
}
// A region is a sub-rect of a texture array layer.
// All allocations within a region are of the same size.
/// A region corresponds to a layer in a shared cache texture.
///
/// All allocations within a region are of the same size.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct TextureRegion {
layer_index: i32,
region_size: u32,
layer_index: usize,
slab_size: SlabSize,
free_slots: Vec<TextureLocation>,
total_slot_count: usize,
origin: DeviceUintPoint,
}
impl TextureRegion {
fn new(region_size: u32, layer_index: i32, origin: DeviceUintPoint) -> Self {
fn new(layer_index: usize) -> Self {
TextureRegion {
layer_index,
region_size,
slab_size: SlabSize::invalid(),
free_slots: Vec::new(),
total_slot_count: 0,
origin,
}
}
@ -1007,8 +1010,8 @@ impl TextureRegion {
debug_assert!(self.free_slots.is_empty());
self.slab_size = slab_size;
let slots_per_x_axis = self.region_size / self.slab_size.width;
let slots_per_y_axis = self.region_size / self.slab_size.height;
let slots_per_x_axis = TEXTURE_REGION_DIMENSIONS / self.slab_size.width;
let slots_per_y_axis = TEXTURE_REGION_DIMENSIONS / self.slab_size.height;
// Add each block to a freelist.
for y in 0 .. slots_per_y_axis {
@ -1038,16 +1041,16 @@ impl TextureRegion {
self.free_slots.pop().map(|location| {
DeviceUintPoint::new(
self.origin.x + self.slab_size.width * location.0 as u32,
self.origin.y + self.slab_size.height * location.1 as u32,
self.slab_size.width * location.0 as u32,
self.slab_size.height * location.1 as u32,
)
})
}
// Free a block in this region.
fn free(&mut self, point: DeviceUintPoint) {
let x = (point.x - self.origin.x) / self.slab_size.width;
let y = (point.y - self.origin.y) / self.slab_size.height;
let x = point.x / self.slab_size.width;
let y = point.y / self.slab_size.height;
self.free_slots.push(TextureLocation::new(x, y));
// If this region is completely unused, deinit it
@ -1059,17 +1062,14 @@ impl TextureRegion {
}
}
// A texture array contains a number of texture layers, where
// each layer contains one or more regions that can act
// as slab allocators.
/// A texture array contains a number of texture layers, where each layer
/// contains a region that can act as a slab allocator.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct TextureArray {
filter: TextureFilter,
dimensions: u32,
layer_count: usize,
max_layer_count: usize,
format: ImageFormat,
is_allocated: bool,
regions: Vec<TextureRegion>,
texture_id: Option<CacheTextureId>,
}
@ -1078,31 +1078,30 @@ impl TextureArray {
fn new(
format: ImageFormat,
filter: TextureFilter,
dimensions: u32,
layer_count: usize,
max_layer_count: usize,
) -> Self {
TextureArray {
format,
filter,
dimensions,
layer_count,
is_allocated: false,
max_layer_count,
regions: Vec::new(),
texture_id: None,
}
}
fn clear(&mut self) -> Option<CacheTextureId> {
self.is_allocated = false;
fn clear(&mut self, updates: &mut TextureUpdateList) {
self.regions.clear();
self.texture_id.take()
if let Some(id) = self.texture_id.take() {
updates.push_free(id);
}
}
fn update_profile(&self, counter: &mut ResourceProfileCounter) {
if self.is_allocated {
let size = self.layer_count as u32 * self.dimensions *
self.dimensions * self.format.bytes_per_pixel();
counter.set(self.layer_count as usize, size as usize);
let layer_count = self.regions.len();
if layer_count != 0 {
let size = layer_count as u32 * TEXTURE_REGION_DIMENSIONS *
TEXTURE_REGION_DIMENSIONS * self.format.bytes_per_pixel();
counter.set(layer_count as usize, size as usize);
} else {
counter.set(0, 0);
}
@ -1116,31 +1115,6 @@ impl TextureArray {
frame_id: FrameId,
uv_rect_kind: UvRectKind,
) -> Option<CacheEntry> {
// Lazily allocate the regions if not already created.
// This means that very rarely used image formats can be
// added but won't allocate a cache if never used.
if !self.is_allocated {
debug_assert!(self.dimensions % TEXTURE_REGION_DIMENSIONS == 0);
let regions_per_axis = self.dimensions / TEXTURE_REGION_DIMENSIONS;
for layer_index in 0 .. self.layer_count {
for y in 0 .. regions_per_axis {
for x in 0 .. regions_per_axis {
let origin = DeviceUintPoint::new(
x * TEXTURE_REGION_DIMENSIONS,
y * TEXTURE_REGION_DIMENSIONS,
);
let region = TextureRegion::new(
TEXTURE_REGION_DIMENSIONS,
layer_index as i32,
origin
);
self.regions.push(region);
}
}
}
self.is_allocated = true;
}
// Quantize the size of the allocation to select a region to
// allocate from.
let slab_size = SlabSize::new(size);
@ -1164,8 +1138,7 @@ impl TextureArray {
} else if region.slab_size == slab_size {
if let Some(location) = region.alloc() {
entry_kind = Some(EntryKind::Cache {
layer_index: region.layer_index as u16,
region_index: i as u16,
layer_index: region.layer_index,
origin: location,
});
break;
@ -1180,8 +1153,7 @@ impl TextureArray {
region.init(slab_size);
entry_kind = region.alloc().map(|location| {
EntryKind::Cache {
layer_index: region.layer_index as u16,
region_index: empty_region_index as u16,
layer_index: region.layer_index,
origin: location,
}
});
@ -1206,8 +1178,8 @@ impl TextureArray {
}
}
impl TextureUpdate {
// Constructs a TextureUpdate operation to be passed to the
impl TextureCacheUpdate {
// Constructs a TextureCacheUpdate operation to be passed to the
// rendering thread in order to do an upload to the right
// location in the texture cache.
fn new_update(
@ -1218,7 +1190,7 @@ impl TextureUpdate {
texture_id: CacheTextureId,
layer_index: i32,
dirty_rect: Option<DeviceUintRect>,
) -> TextureUpdate {
) -> TextureCacheUpdate {
let source = match data {
ImageData::Blob(..) => {
panic!("The vector image should have been rasterized.");
@ -1248,7 +1220,8 @@ impl TextureUpdate {
let stride = descriptor.compute_stride();
let offset = descriptor.offset + dirty.origin.y * stride + dirty.origin.x * descriptor.format.bytes_per_pixel();
TextureUpdateOp::Update {
TextureCacheUpdate {
id: texture_id,
rect: DeviceUintRect::new(
DeviceUintPoint::new(origin.x + dirty.origin.x, origin.y + dirty.origin.y),
DeviceUintSize::new(
@ -1263,7 +1236,8 @@ impl TextureUpdate {
}
}
None => {
TextureUpdateOp::Update {
TextureCacheUpdate {
id: texture_id,
rect: DeviceUintRect::new(origin, size),
source,
stride: descriptor.stride,
@ -1273,10 +1247,7 @@ impl TextureUpdate {
}
};
TextureUpdate {
id: texture_id,
op: update_op,
}
update_op
}
}

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

@ -1 +1 @@
46ee0ffd00da268faf04e3263ad41733f58a6573
ab887f2ed4d5d378bb7536b1d721bff45c0ad0e6

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

@ -5506,7 +5506,10 @@ GlobalLexicals(JSContext* cx, unsigned argc, Value* vp)
if (!JS_GetPropertyById(cx, globalLexical, id, &val)) {
return false;
}
if (!JS_SetPropertyById(cx, res, id, val)) {
if (val.isMagic(JS_UNINITIALIZED_LEXICAL)) {
continue;
}
if (!JS_DefinePropertyById(cx, res, id, val, JSPROP_ENUMERATE)) {
return false;
}
}

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

@ -4,11 +4,15 @@ const y = 2;
var z = 3;
var obj = globalLexicals();
assertEq(Object.keys(obj).length >= 3, true);
assertEq(obj.Foo, Foo);
assertEq(obj.x, 1);
assertEq(obj.y, 2);
assertEq("z" in obj, false);
assertEq("uninit" in obj, false);
let uninit;
// It's just a copy.
obj.x = 2;
assertEq(x, 1);

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

@ -204,6 +204,7 @@ class CompileInfo
: script_(script), fun_(fun), osrPc_(osrPc),
analysisMode_(analysisMode), scriptNeedsArgsObj_(scriptNeedsArgsObj),
hadOverflowBailout_(script->hadOverflowBailout()),
hadFrequentBailouts_(script->hadFrequentBailouts()),
mayReadFrameArgsDirectly_(script->mayReadFrameArgsDirectly()),
inlineScriptTree_(inlineScriptTree)
{
@ -256,7 +257,7 @@ class CompileInfo
explicit CompileInfo(unsigned nlocals)
: script_(nullptr), fun_(nullptr), osrPc_(nullptr),
analysisMode_(Analysis_None), scriptNeedsArgsObj_(false), hadOverflowBailout_(false),
mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr),
hadFrequentBailouts_(false), mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr),
needsBodyEnvironmentObject_(false), funNeedsSomeEnvironmentObject_(false)
{
nimplicit_ = 0;
@ -561,6 +562,9 @@ class CompileInfo
bool hadOverflowBailout() const {
return hadOverflowBailout_;
}
bool hadFrequentBailouts() const {
return hadFrequentBailouts_;
}
bool mayReadFrameArgsDirectly() const {
return mayReadFrameArgsDirectly_;
}
@ -585,6 +589,7 @@ class CompileInfo
// Record the state of previous bailouts in order to prevent compiling the
// same function identically the next time.
bool hadOverflowBailout_;
bool hadFrequentBailouts_;
bool mayReadFrameArgsDirectly_;

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

@ -1503,8 +1503,7 @@ OptimizeMIR(MIRGenerator* mir)
// LICM can hoist instructions from conditional branches and trigger
// repeated bailouts. Disable it if this script is known to bailout
// frequently.
JSScript* script = mir->info().script();
if (!script || !script->hadFrequentBailouts()) {
if (!mir->info().hadFrequentBailouts()) {
if (!LICM(mir, graph)) {
return false;
}

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

@ -402,14 +402,6 @@ class JSFunction : public js::NativeObject
flags_ |= NEW_SCRIPT_CLEARED;
}
void setAsyncKind(js::FunctionAsyncKind asyncKind) {
if (isInterpretedLazy()) {
lazyScript()->setAsyncKind(asyncKind);
} else {
nonLazyScript()->setAsyncKind(asyncKind);
}
}
static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
js::MutableHandleValue v);

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

@ -213,7 +213,7 @@ JSScript::ensureHasAnalyzedArgsUsage(JSContext* cx)
inline bool
JSScript::isDebuggee() const
{
return realm_->debuggerObservesAllExecution() || bitFields_.hasDebugScript_;
return realm_->debuggerObservesAllExecution() || hasDebugScript();
}
inline bool

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

@ -335,6 +335,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
HandleScriptSourceObject sourceObjectArg, HandleFunction fun,
MutableHandleScript scriptp)
{
using ImmutableFlags = JSScript::ImmutableFlags;
/* NB: Keep this in sync with CopyScript. */
enum ScriptBits {
@ -610,19 +612,19 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
scriptp.set(script);
if (scriptBits & (1 << Strict)) {
script->bitFields_.strict_ = true;
script->setFlag(ImmutableFlags::Strict);
}
if (scriptBits & (1 << ExplicitUseStrict)) {
script->bitFields_.explicitUseStrict_ = true;
script->setFlag(ImmutableFlags::ExplicitUseStrict);
}
if (scriptBits & (1 << ContainsDynamicNameAccess)) {
script->bitFields_.bindingsAccessedDynamically_ = true;
script->setFlag(ImmutableFlags::BindingsAccessedDynamically);
}
if (scriptBits & (1 << FunHasExtensibleScope)) {
script->bitFields_.funHasExtensibleScope_ = true;
script->setFlag(ImmutableFlags::FunHasExtensibleScope);
}
if (scriptBits & (1 << FunHasAnyAliasedFormal)) {
script->bitFields_.funHasAnyAliasedFormal_ = true;
script->setFlag(ImmutableFlags::FunHasAnyAliasedFormal);
}
if (scriptBits & (1 << ArgumentsHasVarBinding)) {
script->setArgumentsHasVarBinding();
@ -631,43 +633,43 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
script->setNeedsArgsObj(true);
}
if (scriptBits & (1 << HasMappedArgsObj)) {
script->bitFields_.hasMappedArgsObj_ = true;
script->setFlag(ImmutableFlags::HasMappedArgsObj);
}
if (scriptBits & (1 << FunctionHasThisBinding)) {
script->bitFields_.functionHasThisBinding_ = true;
script->setFlag(ImmutableFlags::FunctionHasThisBinding);
}
if (scriptBits & (1 << FunctionHasExtraBodyVarScope)) {
script->bitFields_.functionHasExtraBodyVarScope_ = true;
script->setFlag(ImmutableFlags::FunctionHasExtraBodyVarScope);
}
if (scriptBits & (1 << HasSingleton)) {
script->bitFields_.hasSingletons_ = true;
script->setFlag(ImmutableFlags::HasSingletons);
}
if (scriptBits & (1 << TreatAsRunOnce)) {
script->bitFields_.treatAsRunOnce_ = true;
script->setFlag(ImmutableFlags::TreatAsRunOnce);
}
if (scriptBits & (1 << HasNonSyntacticScope)) {
script->bitFields_.hasNonSyntacticScope_ = true;
script->setFlag(ImmutableFlags::HasNonSyntacticScope);
}
if (scriptBits & (1 << HasInnerFunctions)) {
script->bitFields_.hasInnerFunctions_ = true;
script->setFlag(ImmutableFlags::HasInnerFunctions);
}
if (scriptBits & (1 << NeedsHomeObject)) {
script->bitFields_.needsHomeObject_ = true;
script->setFlag(ImmutableFlags::NeedsHomeObject);
}
if (scriptBits & (1 << IsDerivedClassConstructor)) {
script->bitFields_.isDerivedClassConstructor_ = true;
script->setFlag(ImmutableFlags::IsDerivedClassConstructor);
}
if (scriptBits & (1 << IsDefaultClassConstructor)) {
script->bitFields_.isDefaultClassConstructor_ = true;
script->setFlag(ImmutableFlags::IsDefaultClassConstructor);
}
if (scriptBits & (1 << IsGenerator)) {
script->setGeneratorKind(GeneratorKind::Generator);
script->setFlag(ImmutableFlags::IsGenerator);
}
if (scriptBits & (1 << IsAsync)) {
script->setAsyncKind(FunctionAsyncKind::AsyncFunction);
script->setFlag(ImmutableFlags::IsAsync);
}
if (scriptBits & (1 << HasRest)) {
script->setHasRest();
script->setFlag(ImmutableFlags::HasRest);
}
}
@ -1109,7 +1111,7 @@ JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start,
column_ = column;
// Since this script has been changed to point into the user's source, we
// can clear its self-hosted flag, allowing Debugger to see it.
bitFields_.selfHosted_ = false;
clearFlag(ImmutableFlags::SelfHosted);
}
js::ScriptSourceObject&
@ -1186,7 +1188,7 @@ JSScript::initScriptCounts(JSContext* cx)
}
// safe to set this; we can't fail after this point.
bitFields_.hasScriptCounts_ = true;
setFlag(MutableFlags::HasScriptCounts);
// Enable interrupts in any interpreter frames running on this script. This
// is used to let the interpreter increment the PCCounts, if present.
@ -1412,7 +1414,7 @@ JSScript::getIonCounts()
void
JSScript::clearHasScriptCounts()
{
bitFields_.hasScriptCounts_ = false;
clearFlag(MutableFlags::HasScriptCounts);
}
void
@ -1421,7 +1423,7 @@ JSScript::releaseScriptCounts(ScriptCounts* counts)
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
*counts = std::move(*p->value().get());
realm()->scriptCountsMap->remove(p);
bitFields_.hasScriptCounts_ = false;
clearHasScriptCounts();
}
void
@ -3300,10 +3302,10 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
}
// Record compile options that get checked at runtime.
script->bitFields_.noScriptRval_ = options.noScriptRval;
script->bitFields_.selfHosted_ = options.selfHostingMode;
script->bitFields_.treatAsRunOnce_ = options.isRunOnce;
script->bitFields_.hideScriptFromDebugger_ = options.hideScriptFromDebugger;
script->setFlag(ImmutableFlags::NoScriptRval, options.noScriptRval);
script->setFlag(ImmutableFlags::SelfHosted, options.selfHostingMode);
script->setFlag(ImmutableFlags::TreatAsRunOnce, options.isRunOnce);
script->setFlag(ImmutableFlags::HideScriptFromDebugger, options.hideScriptFromDebugger);
if (cx->runtime()->lcovOutput().isEnabled()) {
if (!script->initScriptName(cx)) {
@ -3449,9 +3451,9 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
fun->setScript(script);
}
script->bitFields_.funHasExtensibleScope_ = funbox->hasExtensibleScope();
script->bitFields_.needsHomeObject_ = funbox->needsHomeObject();
script->bitFields_.isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
script->setFlag(ImmutableFlags::FunHasExtensibleScope, funbox->hasExtensibleScope());
script->setFlag(ImmutableFlags::NeedsHomeObject, funbox->needsHomeObject());
script->setFlag(ImmutableFlags::IsDerivedClassConstructor, funbox->isDerivedClassConstructor());
if (funbox->argumentsHasLocalBinding()) {
script->setArgumentsHasVarBinding();
@ -3461,37 +3463,35 @@ JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox
} else {
MOZ_ASSERT(!funbox->definitelyNeedsArgsObj());
}
script->bitFields_.hasMappedArgsObj_ = funbox->hasMappedArgsObj();
script->setFlag(ImmutableFlags::HasMappedArgsObj, funbox->hasMappedArgsObj());
script->bitFields_.functionHasThisBinding_ = funbox->hasThisBinding();
script->bitFields_.functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
script->setFlag(ImmutableFlags::FunctionHasThisBinding, funbox->hasThisBinding());
script->setFlag(ImmutableFlags::FunctionHasExtraBodyVarScope, funbox->hasExtraBodyVarScope());
script->funLength_ = funbox->length;
script->setGeneratorKind(funbox->generatorKind());
script->setAsyncKind(funbox->asyncKind());
if (funbox->hasRest()) {
script->setHasRest();
}
script->setFlag(ImmutableFlags::IsGenerator, funbox->isGenerator());
script->setFlag(ImmutableFlags::IsAsync, funbox->isAsync());
script->setFlag(ImmutableFlags::HasRest, funbox->hasRest());
PositionalFormalParameterIter fi(script);
while (fi && !fi.closedOver()) {
fi++;
}
script->bitFields_.funHasAnyAliasedFormal_ = !!fi;
script->setFlag(ImmutableFlags::FunHasAnyAliasedFormal, !!fi);
script->setHasInnerFunctions(funbox->hasInnerFunctions());
script->setFlag(ImmutableFlags::HasInnerFunctions, funbox->hasInnerFunctions());
}
/* static */ void
JSScript::initFromModuleContext(HandleScript script)
{
script->bitFields_.funHasExtensibleScope_ = false;
script->bitFields_.needsHomeObject_ = false;
script->bitFields_.isDerivedClassConstructor_ = false;
script->clearFlag(ImmutableFlags::FunHasExtensibleScope);
script->clearFlag(ImmutableFlags::NeedsHomeObject);
script->clearFlag(ImmutableFlags::IsDerivedClassConstructor);
script->funLength_ = 0;
script->setGeneratorKind(GeneratorKind::NotGenerator);
script->clearFlag(ImmutableFlags::IsGenerator);
// Since modules are only run once, mark the script so that initializers
// created within it may be given more precise types.
@ -3571,16 +3571,17 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, frontend::Byt
bce->resumeOffsetList.finish(data->resumeOffsets(), prologueLength);
}
script->bitFields_.strict_ = bce->sc->strict();
script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
script->bitFields_.hasSingletons_ = bce->hasSingletons;
script->setFlag(ImmutableFlags::Strict, bce->sc->strict());
script->setFlag(ImmutableFlags::ExplicitUseStrict, bce->sc->hasExplicitUseStrict());
script->setFlag(ImmutableFlags::BindingsAccessedDynamically,
bce->sc->bindingsAccessedDynamically());
script->setFlag(ImmutableFlags::HasSingletons, bce->hasSingletons);
script->nfixed_ = bce->maxFixedSlots;
script->nslots_ = nslots;
script->bodyScopeIndex_ = bce->bodyScopeIndex;
script->bitFields_.hasNonSyntacticScope_ =
bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
script->setFlag(ImmutableFlags::HasNonSyntacticScope,
bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic));
// There shouldn't be any fallible operation after initFromFunctionBox,
// JSFunction::hasUncompletedScript relies on the fact that the existence
@ -4017,6 +4018,8 @@ bool
js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
MutableHandle<GCVector<Scope*>> scopes)
{
using ImmutableFlags = JSScript::ImmutableFlags;
if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
JS_ReportErrorASCII(cx, "No cloning toplevel run-once scripts");
return false;
@ -4129,25 +4132,25 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->setNeedsArgsObj(src->needsArgsObj());
}
}
dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj();
dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding();
dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
dst->bitFields_.strict_ = src->strict();
dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict();
dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
dst->bitFields_.bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
dst->bitFields_.funHasExtensibleScope_ = src->funHasExtensibleScope();
dst->bitFields_.funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
dst->bitFields_.hasSingletons_ = src->hasSingletons();
dst->bitFields_.treatAsRunOnce_ = src->treatAsRunOnce();
dst->bitFields_.hasInnerFunctions_ = src->hasInnerFunctions();
dst->setGeneratorKind(src->generatorKind());
dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor();
dst->bitFields_.needsHomeObject_ = src->needsHomeObject();
dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor();
dst->bitFields_.isAsync_ = src->bitFields_.isAsync_;
dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
dst->setFlag(ImmutableFlags::HasMappedArgsObj, src->hasMappedArgsObj());
dst->setFlag(ImmutableFlags::FunctionHasThisBinding, src->functionHasThisBinding());
dst->setFlag(ImmutableFlags::FunctionHasExtraBodyVarScope, src->functionHasExtraBodyVarScope());
dst->setFlag(ImmutableFlags::Strict, src->strict());
dst->setFlag(ImmutableFlags::ExplicitUseStrict, src->explicitUseStrict());
dst->setFlag(ImmutableFlags::HasNonSyntacticScope, scopes[0]->hasOnChain(ScopeKind::NonSyntactic));
dst->setFlag(ImmutableFlags::BindingsAccessedDynamically, src->bindingsAccessedDynamically());
dst->setFlag(ImmutableFlags::FunHasExtensibleScope, src->funHasExtensibleScope());
dst->setFlag(ImmutableFlags::FunHasAnyAliasedFormal, src->funHasAnyAliasedFormal());
dst->setFlag(ImmutableFlags::HasSingletons, src->hasSingletons());
dst->setFlag(ImmutableFlags::TreatAsRunOnce, src->treatAsRunOnce());
dst->setFlag(ImmutableFlags::HasInnerFunctions, src->hasInnerFunctions());
dst->setFlag(ImmutableFlags::IsGenerator, src->isGenerator());
dst->setFlag(ImmutableFlags::IsDerivedClassConstructor, src->isDerivedClassConstructor());
dst->setFlag(ImmutableFlags::NeedsHomeObject, src->needsHomeObject());
dst->setFlag(ImmutableFlags::IsDefaultClassConstructor, src->isDefaultClassConstructor());
dst->setFlag(ImmutableFlags::IsAsync, src->isAsync());
dst->setFlag(ImmutableFlags::HasRest, src->hasRest());
dst->setFlag(ImmutableFlags::HideScriptFromDebugger, src->hideScriptFromDebugger());
{
auto array = dst->data_->scopes();
@ -4294,7 +4297,7 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleScope enclosingScope, HandleFun
DebugScript*
JSScript::debugScript()
{
MOZ_ASSERT(bitFields_.hasDebugScript_);
MOZ_ASSERT(hasDebugScript());
DebugScriptMap* map = realm()->debugScriptMap.get();
MOZ_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(this);
@ -4305,21 +4308,21 @@ JSScript::debugScript()
DebugScript*
JSScript::releaseDebugScript()
{
MOZ_ASSERT(bitFields_.hasDebugScript_);
MOZ_ASSERT(hasDebugScript());
DebugScriptMap* map = realm()->debugScriptMap.get();
MOZ_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(this);
MOZ_ASSERT(p);
DebugScript* debug = p->value().release();
map->remove(p);
bitFields_.hasDebugScript_ = false;
clearFlag(MutableFlags::HasDebugScript);
return debug;
}
void
JSScript::destroyDebugScript(FreeOp* fop)
{
if (bitFields_.hasDebugScript_) {
if (hasDebugScript()) {
#ifdef DEBUG
for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
if (BreakpointSite* site = getBreakpointSite(pc)) {
@ -4336,7 +4339,7 @@ JSScript::destroyDebugScript(FreeOp* fop)
bool
JSScript::ensureHasDebugScript(JSContext* cx)
{
if (bitFields_.hasDebugScript_) {
if (hasDebugScript()) {
return true;
}
@ -4361,7 +4364,7 @@ JSScript::ensureHasDebugScript(JSContext* cx)
return false;
}
bitFields_.hasDebugScript_ = true; // safe to set this; we can't fail after this point
setFlag(MutableFlags::HasDebugScript); // safe to set this; we can't fail after this point
/*
* Ensure that any Interpret() instances running on this script have
@ -4642,16 +4645,16 @@ JSScript::innermostScope(jsbytecode* pc)
void
JSScript::setArgumentsHasVarBinding()
{
bitFields_.argsHasVarBinding_ = true;
bitFields_.needsArgsAnalysis_ = true;
setFlag(ImmutableFlags::ArgsHasVarBinding);
setFlag(MutableFlags::NeedsArgsAnalysis);
}
void
JSScript::setNeedsArgsObj(bool needsArgsObj)
{
MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
bitFields_.needsArgsAnalysis_ = false;
bitFields_.needsArgsObj_ = needsArgsObj;
clearFlag(MutableFlags::NeedsArgsAnalysis);
setFlag(MutableFlags::NeedsArgsObj, needsArgsObj);
}
void
@ -4720,7 +4723,7 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
MOZ_ASSERT(!script->isGenerator());
MOZ_ASSERT(!script->isAsync());
script->bitFields_.needsArgsObj_ = true;
script->setFlag(MutableFlags::NeedsArgsObj);
/*
* Since we can't invalidate baseline scripts, set a flag that's checked from
@ -5098,7 +5101,7 @@ JSScript::AutoDelazify::holdScript(JS::HandleFunction fun)
JSAutoRealm ar(cx_, fun);
script_ = JSFunction::getOrCreateScript(cx_, fun);
if (script_) {
oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_;
oldDoNotRelazify_ = script_->hasFlag(MutableFlags::DoNotRelazify);
script_->setDoNotRelazify(true);
}
}

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

@ -1634,6 +1634,143 @@ class JSScript : public js::gc::TenuredCell
mozilla::Atomic<uint32_t, mozilla::Relaxed,
mozilla::recordreplay::Behavior::DontPreserve> warmUpCount = {};
// Immutable flags should not be modified after this script has been
// initialized. These flags should likely be preserved when serializing
// (XDR) or copying (CopyScript) this script.
enum class ImmutableFlags : uint32_t {
// No need for result value of last expression statement.
NoScriptRval = 1 << 0,
// Code is in strict mode.
Strict = 1 << 1,
// Code has "use strict"; explicitly.
ExplicitUseStrict = 1 << 2,
// True if the script has a non-syntactic scope on its dynamic scope chain.
// That is, there are objects about which we know nothing between the
// outermost syntactic scope and the global.
HasNonSyntacticScope = 1 << 3,
// See Parser::selfHostingMode.
SelfHosted = 1 << 4,
// See FunctionBox.
BindingsAccessedDynamically = 1 << 5,
FunHasExtensibleScope = 1 << 6,
// True if any formalIsAliased(i).
FunHasAnyAliasedFormal = 1 << 7,
// Script has singleton objects.
HasSingletons = 1 << 8,
FunctionHasThisBinding = 1 << 9,
FunctionHasExtraBodyVarScope = 1 << 10,
// Whether the arguments object for this script, if it needs one, should be
// mapped (alias formal parameters).
HasMappedArgsObj = 1 << 11,
// Script contains inner functions. Used to check if we can relazify the
// script.
HasInnerFunctions = 1 << 12,
NeedsHomeObject = 1 << 13,
IsDerivedClassConstructor = 1 << 14,
IsDefaultClassConstructor = 1 << 15,
// Script is a lambda to treat as running once or a global or eval script
// that will only run once. Which one it is can be disambiguated by
// checking whether function() is null.
TreatAsRunOnce = 1 << 16,
// 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
IsLikelyConstructorWrapper = 1 << 17,
// Set if the debugger's onNewScript hook has not yet been called.
HideScriptFromDebugger = 1 << 18,
// Set if this function is a generator function or async generator.
IsGenerator = 1 << 19,
// Set if this function is an async function or async generator.
IsAsync = 1 << 20,
// Set if this function has a rest parameter.
HasRest = 1 << 21,
// See comments below.
ArgsHasVarBinding = 1 << 22,
};
uint32_t immutableFlags_ = 0;
// Mutable flags typically store information about runtime or deoptimization
// behavior of this script.
enum class MutableFlags : uint32_t {
// Have warned about uses of undefined properties in this script.
WarnedAboutUndefinedProp = 1 << 0,
// If treatAsRunOnce, whether script has executed.
HasRunOnce = 1 << 1,
// Script has been reused for a clone.
HasBeenCloned = 1 << 2,
// Script came from eval(), and is still active.
IsActiveEval = 1 << 3,
// Script came from eval(), and is in eval cache.
IsCachedEval = 1 << 4,
// Script has an entry in Realm::scriptCountsMap.
HasScriptCounts = 1 << 5,
// Script has an entry in Realm::debugScriptMap.
HasDebugScript = 1 << 6,
// Freeze constraints for stack type sets have been generated.
HasFreezeConstraints = 1 << 7,
// Generation for this script's TypeScript. If out of sync with the
// TypeZone's generation, the TypeScript needs to be swept.
TypesGeneration = 1 << 8,
// Do not relazify this script. This is used by the relazify() testing
// function for scripts that are on the stack and also by the AutoDelazify
// RAII class. Usually we don't relazify functions in compartments with
// scripts on the stack, but the relazify() testing function overrides that,
// and sometimes we're working with a cross-compartment function and need to
// keep it from relazifying.
DoNotRelazify = 1 << 9,
// IonMonkey compilation hints.
// Script has had hoisted bounds checks fail.
FailedBoundsCheck = 1 << 10,
// Script has had hoisted shape guard fail.
FailedShapeGuard = 1 << 11,
HadFrequentBailouts = 1 << 12,
HadOverflowBailout = 1 << 13,
// Explicitly marked as uninlineable.
Uninlineable = 1 << 14,
// Idempotent cache has triggered invalidation.
InvalidatedIdempotentCache = 1 << 15,
// Lexical check did fail and bail out.
FailedLexicalCheck = 1 << 16,
// See comments below.
NeedsArgsAnalysis = 1 << 17,
NeedsArgsObj = 1 << 18,
};
uint32_t mutableFlags_ = 0;
// 16-bit fields.
/**
@ -1648,144 +1785,6 @@ class JSScript : public js::gc::TenuredCell
/* Number of type sets used in this script for dynamic type monitoring. */
uint16_t nTypeSets_ = 0;
private:
struct BitFields
{
/*
* Bit-fields can't have member initializers til C++2a, i.e. probably
* C++20, so we can't initialize these to zero in place. Instead we
* braced-init this to all zeroes in the JSScript constructor, then
* custom-assign particular bit-fields in the constructor body.
*/
// No need for result value of last expression statement.
bool noScriptRval_ : 1;
// Code is in strict mode.
bool strict_ : 1;
// Code has "use strict"; explicitly.
bool explicitUseStrict_ : 1;
// True if the script has a non-syntactic scope on its dynamic scope chain.
// That is, there are objects about which we know nothing between the
// outermost syntactic scope and the global.
bool hasNonSyntacticScope_ : 1;
// see Parser::selfHostingMode.
bool selfHosted_ : 1;
// See FunctionBox.
bool bindingsAccessedDynamically_ : 1;
bool funHasExtensibleScope_ : 1;
// True if any formalIsAliased(i).
bool funHasAnyAliasedFormal_ : 1;
// Have warned about uses of undefined properties in this script.
bool warnedAboutUndefinedProp_ : 1;
// Script has singleton objects.
bool hasSingletons_ : 1;
// Script is a lambda to treat as running once or a global or eval script
// that will only run once. Which one it is can be disambiguated by
// checking whether function() is null.
bool treatAsRunOnce_ : 1;
// If treatAsRunOnce, whether script has executed.
bool hasRunOnce_ : 1;
// Script has been reused for a clone.
bool hasBeenCloned_ : 1;
// Script came from eval(), and is still active.
bool isActiveEval_ : 1;
// Script came from eval(), and is in eval cache.
bool isCachedEval_ : 1;
// 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
bool isLikelyConstructorWrapper_ : 1;
// IonMonkey compilation hints.
/* Script has had hoisted bounds checks fail. */
bool failedBoundsCheck_ : 1;
/* Script has had hoisted shape guard fail. */
bool failedShapeGuard_ : 1;
bool hadFrequentBailouts_ : 1;
bool hadOverflowBailout_ : 1;
/* Explicitly marked as uninlineable. */
bool uninlineable_ : 1;
// Idempotent cache has triggered invalidation.
bool invalidatedIdempotentCache_ : 1;
// Lexical check did fail and bail out.
bool failedLexicalCheck_ : 1;
// Script has an entry in Realm::scriptCountsMap.
bool hasScriptCounts_ : 1;
// Script has an entry in Realm::debugScriptMap.
bool hasDebugScript_ : 1;
// Freeze constraints for stack type sets have been generated.
bool hasFreezeConstraints_ : 1;
/* See comments below. */
bool argsHasVarBinding_ : 1;
bool needsArgsAnalysis_ : 1;
bool needsArgsObj_ : 1;
bool functionHasThisBinding_ : 1;
bool functionHasExtraBodyVarScope_ : 1;
// Whether the arguments object for this script, if it needs one, should be
// mapped (alias formal parameters).
bool hasMappedArgsObj_ : 1;
// Generation for this script's TypeScript. If out of sync with the
// TypeZone's generation, the TypeScript needs to be swept.
//
// This should be a uint32 but is instead a bool so that MSVC packs it
// correctly.
bool typesGeneration_ : 1;
// Do not relazify this script. This is used by the relazify() testing
// function for scripts that are on the stack and also by the AutoDelazify
// RAII class. Usually we don't relazify functions in compartments with
// scripts on the stack, but the relazify() testing function overrides that,
// and sometimes we're working with a cross-compartment function and need to
// keep it from relazifying.
bool doNotRelazify_ : 1;
// Script contains inner functions. Used to check if we can relazify the
// script.
bool hasInnerFunctions_ : 1;
bool needsHomeObject_ : 1;
bool isDerivedClassConstructor_ : 1;
bool isDefaultClassConstructor_ : 1;
// True if this function is a generator function or async generator.
bool isGenerator_ : 1;
// True if this function is an async function or async generator.
bool isAsync_ : 1;
bool hasRest_ : 1;
// True if the debugger's onNewScript hook has not yet been called.
bool hideScriptFromDebugger_ : 1;
};
BitFields bitFields_ = {}; // Zero-initialize bitfield flags.
//
// End of fields. Start methods.
//
@ -1844,6 +1843,44 @@ class JSScript : public js::gc::TenuredCell
void assertValidJumpTargets() const;
#endif
// MutableFlags accessors.
MOZ_MUST_USE bool hasFlag(MutableFlags flag) const {
return mutableFlags_ & uint32_t(flag);
}
void setFlag(MutableFlags flag) {
mutableFlags_ |= uint32_t(flag);
}
void setFlag(MutableFlags flag, bool b) {
if (b) {
setFlag(flag);
} else {
clearFlag(flag);
}
}
void clearFlag(MutableFlags flag) {
mutableFlags_ &= ~uint32_t(flag);
}
// ImmutableFlags accessors.
MOZ_MUST_USE bool hasFlag(ImmutableFlags flag) const {
return immutableFlags_ & uint32_t(flag);
}
void setFlag(ImmutableFlags flag) {
immutableFlags_ |= uint32_t(flag);
}
void setFlag(ImmutableFlags flag, bool b) {
if (b) {
setFlag(flag);
} else {
clearFlag(flag);
}
}
void clearFlag(ImmutableFlags flag) {
immutableFlags_ &= ~uint32_t(flag);
}
public:
inline JSPrincipals* principals();
@ -1998,113 +2035,117 @@ class JSScript : public js::gc::TenuredCell
}
bool noScriptRval() const {
return bitFields_.noScriptRval_;
return hasFlag(ImmutableFlags::NoScriptRval);
}
bool strict() const {
return bitFields_.strict_;
return hasFlag(ImmutableFlags::Strict);
}
bool explicitUseStrict() const { return bitFields_.explicitUseStrict_; }
bool explicitUseStrict() const { return hasFlag(ImmutableFlags::ExplicitUseStrict); }
bool hasNonSyntacticScope() const {
return bitFields_.hasNonSyntacticScope_;
return hasFlag(ImmutableFlags::HasNonSyntacticScope);
}
bool selfHosted() const { return bitFields_.selfHosted_; }
bool bindingsAccessedDynamically() const { return bitFields_.bindingsAccessedDynamically_; }
bool selfHosted() const { return hasFlag(ImmutableFlags::SelfHosted); }
bool bindingsAccessedDynamically() const {
return hasFlag(ImmutableFlags::BindingsAccessedDynamically);
}
bool funHasExtensibleScope() const {
return bitFields_.funHasExtensibleScope_;
return hasFlag(ImmutableFlags::FunHasExtensibleScope);
}
bool funHasAnyAliasedFormal() const {
return bitFields_.funHasAnyAliasedFormal_;
return hasFlag(ImmutableFlags::FunHasAnyAliasedFormal);
}
bool hasSingletons() const { return bitFields_.hasSingletons_; }
bool hasSingletons() const { return hasFlag(ImmutableFlags::HasSingletons); }
bool treatAsRunOnce() const {
return bitFields_.treatAsRunOnce_;
return hasFlag(ImmutableFlags::TreatAsRunOnce);
}
bool hasRunOnce() const { return bitFields_.hasRunOnce_; }
bool hasBeenCloned() const { return bitFields_.hasBeenCloned_; }
bool hasRunOnce() const { return hasFlag(MutableFlags::HasRunOnce); }
bool hasBeenCloned() const { return hasFlag(MutableFlags::HasBeenCloned); }
void setTreatAsRunOnce() { bitFields_.treatAsRunOnce_ = true; }
void setHasRunOnce() { bitFields_.hasRunOnce_ = true; }
void setHasBeenCloned() { bitFields_.hasBeenCloned_ = true; }
void setTreatAsRunOnce() { setFlag(ImmutableFlags::TreatAsRunOnce); }
void setHasRunOnce() { setFlag(MutableFlags::HasRunOnce); }
void setHasBeenCloned() { setFlag(MutableFlags::HasBeenCloned); }
bool isActiveEval() const { return bitFields_.isActiveEval_; }
bool isCachedEval() const { return bitFields_.isCachedEval_; }
bool isActiveEval() const { return hasFlag(MutableFlags::IsActiveEval); }
bool isCachedEval() const { return hasFlag(MutableFlags::IsCachedEval); }
void cacheForEval() {
MOZ_ASSERT(isActiveEval());
MOZ_ASSERT(!isCachedEval());
bitFields_.isActiveEval_ = false;
bitFields_.isCachedEval_ = true;
clearFlag(MutableFlags::IsActiveEval);
setFlag(MutableFlags::IsCachedEval);
// IsEvalCacheCandidate will make sure that there's nothing in this
// script that would prevent reexecution even if isRunOnce is
// true. So just pretend like we never ran this script.
bitFields_.hasRunOnce_ = false;
clearFlag(MutableFlags::HasRunOnce);
}
void uncacheForEval() {
MOZ_ASSERT(isCachedEval());
MOZ_ASSERT(!isActiveEval());
bitFields_.isCachedEval_ = false;
bitFields_.isActiveEval_ = true;
clearFlag(MutableFlags::IsCachedEval);
setFlag(MutableFlags::IsActiveEval);
}
void setActiveEval() { bitFields_.isActiveEval_ = true; }
void setActiveEval() { setFlag(MutableFlags::IsActiveEval); }
bool isLikelyConstructorWrapper() const {
return bitFields_.isLikelyConstructorWrapper_;
return hasFlag(ImmutableFlags::IsLikelyConstructorWrapper);
}
void setLikelyConstructorWrapper() {
setFlag(ImmutableFlags::IsLikelyConstructorWrapper);
}
void setLikelyConstructorWrapper() { bitFields_.isLikelyConstructorWrapper_ = true; }
bool failedBoundsCheck() const {
return bitFields_.failedBoundsCheck_;
return hasFlag(MutableFlags::FailedBoundsCheck);
}
bool failedShapeGuard() const {
return bitFields_.failedShapeGuard_;
return hasFlag(MutableFlags::FailedShapeGuard);
}
bool hadFrequentBailouts() const {
return bitFields_.hadFrequentBailouts_;
return hasFlag(MutableFlags::HadFrequentBailouts);
}
bool hadOverflowBailout() const {
return bitFields_.hadOverflowBailout_;
return hasFlag(MutableFlags::HadOverflowBailout);
}
bool uninlineable() const {
return bitFields_.uninlineable_;
return hasFlag(MutableFlags::Uninlineable);
}
bool invalidatedIdempotentCache() const {
return bitFields_.invalidatedIdempotentCache_;
return hasFlag(MutableFlags::InvalidatedIdempotentCache);
}
bool failedLexicalCheck() const {
return bitFields_.failedLexicalCheck_;
return hasFlag(MutableFlags::FailedLexicalCheck);
}
bool isDefaultClassConstructor() const {
return bitFields_.isDefaultClassConstructor_;
return hasFlag(ImmutableFlags::IsDefaultClassConstructor);
}
void setFailedBoundsCheck() { bitFields_.failedBoundsCheck_ = true; }
void setFailedShapeGuard() { bitFields_.failedShapeGuard_ = true; }
void setHadFrequentBailouts() { bitFields_.hadFrequentBailouts_ = true; }
void setHadOverflowBailout() { bitFields_.hadOverflowBailout_ = true; }
void setUninlineable() { bitFields_.uninlineable_ = true; }
void setInvalidatedIdempotentCache() { bitFields_.invalidatedIdempotentCache_ = true; }
void setFailedLexicalCheck() { bitFields_.failedLexicalCheck_ = true; }
void setIsDefaultClassConstructor() { bitFields_.isDefaultClassConstructor_ = true; }
void setFailedBoundsCheck() { setFlag(MutableFlags::FailedBoundsCheck); }
void setFailedShapeGuard() { setFlag(MutableFlags::FailedShapeGuard); }
void setHadFrequentBailouts() { setFlag(MutableFlags::HadFrequentBailouts); }
void setHadOverflowBailout() { setFlag(MutableFlags::HadOverflowBailout); }
void setUninlineable() { setFlag(MutableFlags::Uninlineable); }
void setInvalidatedIdempotentCache() { setFlag(MutableFlags::InvalidatedIdempotentCache); }
void setFailedLexicalCheck() { setFlag(MutableFlags::FailedLexicalCheck); }
void setIsDefaultClassConstructor() { setFlag(ImmutableFlags::IsDefaultClassConstructor); }
bool hasScriptCounts() const { return bitFields_.hasScriptCounts_; }
bool hasScriptCounts() const { return hasFlag(MutableFlags::HasScriptCounts); }
bool hasScriptName();
bool hasFreezeConstraints() const { return bitFields_.hasFreezeConstraints_; }
void setHasFreezeConstraints() { bitFields_.hasFreezeConstraints_ = true; }
bool hasFreezeConstraints() const { return hasFlag(MutableFlags::HasFreezeConstraints); }
void setHasFreezeConstraints() { setFlag(MutableFlags::HasFreezeConstraints); }
bool warnedAboutUndefinedProp() const { return bitFields_.warnedAboutUndefinedProp_; }
void setWarnedAboutUndefinedProp() { bitFields_.warnedAboutUndefinedProp_ = true; }
bool warnedAboutUndefinedProp() const { return hasFlag(MutableFlags::WarnedAboutUndefinedProp); }
void setWarnedAboutUndefinedProp() { setFlag(MutableFlags::WarnedAboutUndefinedProp); }
/* See ContextFlags::funArgumentsHasLocalBinding comment. */
bool argumentsHasVarBinding() const {
return bitFields_.argsHasVarBinding_;
return hasFlag(ImmutableFlags::ArgsHasVarBinding);
}
void setArgumentsHasVarBinding();
bool argumentsAliasesFormals() const {
@ -2112,52 +2153,36 @@ class JSScript : public js::gc::TenuredCell
}
js::GeneratorKind generatorKind() const {
return bitFields_.isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
}
bool isGenerator() const { return bitFields_.isGenerator_; }
void setGeneratorKind(js::GeneratorKind kind) {
// A script only gets its generator kind set as part of initialization,
// so it can only transition from not being a generator.
MOZ_ASSERT(!isGenerator());
bitFields_.isGenerator_ = kind == js::GeneratorKind::Generator;
return isGenerator() ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
}
bool isGenerator() const { return hasFlag(ImmutableFlags::IsGenerator); }
js::FunctionAsyncKind asyncKind() const {
return bitFields_.isAsync_
return isAsync()
? js::FunctionAsyncKind::AsyncFunction
: js::FunctionAsyncKind::SyncFunction;
}
bool isAsync() const {
return bitFields_.isAsync_;
}
void setAsyncKind(js::FunctionAsyncKind kind) {
bitFields_.isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
return hasFlag(ImmutableFlags::IsAsync);
}
bool hasRest() const {
return bitFields_.hasRest_;
}
void setHasRest() {
bitFields_.hasRest_ = true;
return hasFlag(ImmutableFlags::HasRest);
}
bool hideScriptFromDebugger() const {
return bitFields_.hideScriptFromDebugger_;
return hasFlag(ImmutableFlags::HideScriptFromDebugger);
}
void clearHideScriptFromDebugger() {
bitFields_.hideScriptFromDebugger_ = false;
clearFlag(ImmutableFlags::HideScriptFromDebugger);
}
void setNeedsHomeObject() {
bitFields_.needsHomeObject_ = true;
}
bool needsHomeObject() const {
return bitFields_.needsHomeObject_;
return hasFlag(ImmutableFlags::NeedsHomeObject);
}
bool isDerivedClassConstructor() const {
return bitFields_.isDerivedClassConstructor_;
return hasFlag(ImmutableFlags::IsDerivedClassConstructor);
}
/*
@ -2170,21 +2195,21 @@ class JSScript : public js::gc::TenuredCell
* maintain the invariant that needsArgsObj is only called after the script
* has been analyzed.
*/
bool analyzedArgsUsage() const { return !bitFields_.needsArgsAnalysis_; }
bool analyzedArgsUsage() const { return !hasFlag(MutableFlags::NeedsArgsAnalysis); }
inline bool ensureHasAnalyzedArgsUsage(JSContext* cx);
bool needsArgsObj() const {
MOZ_ASSERT(analyzedArgsUsage());
return bitFields_.needsArgsObj_;
return hasFlag(MutableFlags::NeedsArgsObj);
}
void setNeedsArgsObj(bool needsArgsObj);
static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script);
bool hasMappedArgsObj() const {
return bitFields_.hasMappedArgsObj_;
return hasFlag(ImmutableFlags::HasMappedArgsObj);
}
bool functionHasThisBinding() const {
return bitFields_.functionHasThisBinding_;
return hasFlag(ImmutableFlags::FunctionHasThisBinding);
}
/*
@ -2200,24 +2225,20 @@ class JSScript : public js::gc::TenuredCell
}
uint32_t typesGeneration() const {
return (uint32_t) bitFields_.typesGeneration_;
return uint32_t(hasFlag(MutableFlags::TypesGeneration));
}
void setTypesGeneration(uint32_t generation) {
MOZ_ASSERT(generation <= 1);
bitFields_.typesGeneration_ = (bool) generation;
setFlag(MutableFlags::TypesGeneration, bool(generation));
}
void setDoNotRelazify(bool b) {
bitFields_.doNotRelazify_ = b;
}
void setHasInnerFunctions(bool b) {
bitFields_.hasInnerFunctions_ = b;
setFlag(MutableFlags::DoNotRelazify, b);
}
bool hasInnerFunctions() const {
return bitFields_.hasInnerFunctions_;
return hasFlag(ImmutableFlags::HasInnerFunctions);
}
bool hasAnyIonScript() const {
@ -2282,11 +2303,11 @@ class JSScript : public js::gc::TenuredCell
}
bool isRelazifiable() const {
return (selfHosted() || lazyScript) && !bitFields_.hasInnerFunctions_ && !types_ &&
return (selfHosted() || lazyScript) && !hasInnerFunctions() && !types_ &&
!isGenerator() && !isAsync() &&
!isDefaultClassConstructor() &&
!hasBaselineScript() && !hasAnyIonScript() &&
!bitFields_.doNotRelazify_;
!hasFlag(MutableFlags::DoNotRelazify);
}
void setLazyScript(js::LazyScript* lazy) {
lazyScript = lazy;
@ -2416,8 +2437,9 @@ class JSScript : public js::gc::TenuredCell
}
bool functionHasExtraBodyVarScope() const {
MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs());
return bitFields_.functionHasExtraBodyVarScope_;
bool res = hasFlag(ImmutableFlags::FunctionHasExtraBodyVarScope);
MOZ_ASSERT_IF(res, functionHasParameterExprs());
return res;
}
js::VarScope* functionExtraBodyVarScope() const {
@ -2658,9 +2680,13 @@ class JSScript : public js::gc::TenuredCell
js::DebugScript* releaseDebugScript();
void destroyDebugScript(js::FreeOp* fop);
bool hasDebugScript() const {
return hasFlag(MutableFlags::HasDebugScript);
}
public:
bool hasBreakpointsAt(jsbytecode* pc);
bool hasAnyBreakpointsOrStepMode() { return bitFields_.hasDebugScript_; }
bool hasAnyBreakpointsOrStepMode() { return hasDebugScript(); }
// See comment above 'debugMode' in Realm.h for explanation of
// invariants of debuggee compartments, scripts, and frames.
@ -2668,7 +2694,7 @@ class JSScript : public js::gc::TenuredCell
js::BreakpointSite* getBreakpointSite(jsbytecode* pc)
{
return bitFields_.hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
return hasDebugScript() ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
}
js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc);
@ -2686,10 +2712,10 @@ class JSScript : public js::gc::TenuredCell
bool incrementStepModeCount(JSContext* cx);
void decrementStepModeCount(js::FreeOp* fop);
bool stepModeEnabled() { return bitFields_.hasDebugScript_ && !!debugScript()->stepMode; }
bool stepModeEnabled() { return hasDebugScript() && !!debugScript()->stepMode; }
#ifdef DEBUG
uint32_t stepModeCount() { return bitFields_.hasDebugScript_ ? debugScript()->stepMode : 0; }
uint32_t stepModeCount() { return hasDebugScript() ? debugScript()->stepMode : 0; }
#endif
void finalize(js::FreeOp* fop);

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

@ -4886,7 +4886,7 @@ JSScript::sweepTypes(const js::AutoSweepTypeScript& sweep)
// Freeze constraints on stack type sets need to be regenerated the
// next time the script is analyzed.
bitFields_.hasFreezeConstraints_ = false;
clearFlag(MutableFlags::HasFreezeConstraints);
return;
}
@ -4902,7 +4902,7 @@ JSScript::sweepTypes(const js::AutoSweepTypeScript& sweep)
if (zone()->types.hadOOMSweepingTypes()) {
// It's possible we OOM'd while copying freeze constraints, so they
// need to be regenerated.
bitFields_.hasFreezeConstraints_ = false;
clearFlag(MutableFlags::HasFreezeConstraints);
}
}

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

@ -826,7 +826,8 @@ PresShell::PresShell()
, mHasHandledUserInput(false)
#ifdef NIGHTLY_BUILD
, mForceDispatchKeyPressEventsForNonPrintableKeys(false)
, mInitializedForceDispatchKeyPressEventsForNonPrintableKeys(false)
, mForceUseLegacyKeyCodeAndCharCodeValues(false)
, mInitializedWithKeyPressEventDispatchingBlacklist(false)
#endif // #ifdef NIGHTLY_BUILD
{
MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p", this));
@ -7919,7 +7920,8 @@ GetDocumentURIToCompareWithBlacklist(PresShell& aPresShell)
}
static bool
DispatchKeyPressEventsEvenForNonPrintableKeys(nsIURI* aURI)
IsURIInBlacklistPref(nsIURI* aURI,
const char* aBlacklistPrefName)
{
if (!aURI) {
return false;
@ -7940,11 +7942,8 @@ DispatchKeyPressEventsEvenForNonPrintableKeys(nsIURI* aURI)
// The black list is comma separated domain list. Each item may start with
// "*.". If starts with "*.", it matches any sub-domains.
static const char* kPrefNameOfBlackList =
"dom.keyboardevent.keypress.hack.dispatch_non_printable_keys";
nsAutoCString blackList;
Preferences::GetCString(kPrefNameOfBlackList, blackList);
Preferences::GetCString(aBlacklistPrefName, blackList);
if (blackList.IsEmpty()) {
return false;
}
@ -8016,8 +8015,7 @@ PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
if (aEvent->IsBlockedForFingerprintingResistance()) {
aEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
#ifdef NIGHTLY_BUILD
} else if (aEvent->mMessage == eKeyPress &&
aEvent->mFlags.mOnlySystemGroupDispatchInContent) {
} else if (aEvent->mMessage == eKeyPress) {
// If eKeyPress event is marked as not dispatched in the default event
// group in web content, it's caused by non-printable key or key
// combination. In this case, UI Events declares that browsers
@ -8025,15 +8023,26 @@ PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
// broken with this strict behavior due to historical issue.
// Therefore, we need to keep dispatching keypress event for such keys
// even with breaking the standard.
if (!mInitializedForceDispatchKeyPressEventsForNonPrintableKeys) {
mInitializedForceDispatchKeyPressEventsForNonPrintableKeys = true;
// Similarly, the other browsers sets non-zero value of keyCode or
// charCode of keypress event to the other. Therefore, we should
// behave so, however, some web apps may be broken. On such web apps,
// we should keep using legacy our behavior.
if (!mInitializedWithKeyPressEventDispatchingBlacklist) {
mInitializedWithKeyPressEventDispatchingBlacklist = true;
nsCOMPtr<nsIURI> uri = GetDocumentURIToCompareWithBlacklist(*this);
mForceDispatchKeyPressEventsForNonPrintableKeys =
DispatchKeyPressEventsEvenForNonPrintableKeys(uri);
IsURIInBlacklistPref(uri,
"dom.keyboardevent.keypress.hack.dispatch_non_printable_keys");
mForceUseLegacyKeyCodeAndCharCodeValues =
IsURIInBlacklistPref(uri,
"dom.keyboardevent.keypress.hack.use_legacy_keycode_and_charcode");
}
if (mForceDispatchKeyPressEventsForNonPrintableKeys) {
aEvent->mFlags.mOnlySystemGroupDispatchInContent = false;
}
if (mForceUseLegacyKeyCodeAndCharCodeValues) {
aEvent->AsKeyboardEvent()->mUseLegacyKeyCodeAndCharCodeValues = true;
}
#endif // #ifdef NIGHTLY_BUILD
}

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

@ -871,8 +871,14 @@ private:
// Whether we should dispatch keypress events even for non-printable keys
// for keeping backward compatibility.
bool mForceDispatchKeyPressEventsForNonPrintableKeys : 1;
// Whether mForceDispatchKeyPressEventsForNonPrintableKeys is initialized.
bool mInitializedForceDispatchKeyPressEventsForNonPrintableKeys : 1;
// Whether we should set keyCode or charCode value of keypress events whose
// value is zero to the other value or not. When this is set to true, we
// should keep using legacy keyCode and charCode values (i.e., one of them
// is always 0).
bool mForceUseLegacyKeyCodeAndCharCodeValues : 1;
// Whether mForceDispatchKeyPressEventsForNonPrintableKeys and
// mForceUseLegacyKeyCodeAndCharCodeValues are initialized.
bool mInitializedWithKeyPressEventDispatchingBlacklist : 1;
#endif // #ifdef NIGHTLY_BUILD
static bool sDisableNonTestMouseEvents;

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

@ -2645,6 +2645,7 @@ CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
static bool
FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
MOZ_ASSERT(aAncestor != aDescendant);
MOZ_ASSERT(aAncestor->GetContent() != aDescendant->GetContent());
MOZ_ASSERT(aAncestor->Extend3DContext());
nsIFrame* ancestor = aAncestor->FirstContinuation();
@ -2666,14 +2667,13 @@ FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
static bool
ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
{
nsIFrame* transformFrame;
if (aItem->GetType() == DisplayItemType::TYPE_TRANSFORM ||
aItem->GetType() == DisplayItemType::TYPE_PERSPECTIVE) {
transformFrame = aItem->Frame();
} else {
auto type = aItem->GetType();
if (type != DisplayItemType::TYPE_TRANSFORM &&
type != DisplayItemType::TYPE_PERSPECTIVE) {
return false;
}
if (aAncestor == transformFrame) {
nsIFrame* transformFrame = aItem->Frame();
if (aAncestor->GetContent() == transformFrame->GetContent()) {
return true;
}
return FrameParticipatesIn3DContext(aAncestor, transformFrame);

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

@ -0,0 +1,13 @@
<style>
* { -webkit-transform-style: preserve-3d }
</style>
<script>
function go() {
a.append("x");
}
</script>
<body onload=go()>
<svg overflow="auto">
<use xlink:href="#b" style="-webkit-transform-style: flat"/>
<use id="b" xlink:href="#a">
<text id="a">

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

@ -15,3 +15,4 @@ load 1465305-1.html
load 1468124-1.html
load 1469472.html
load 1477831-1.html
load 1504033.html

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

@ -172,7 +172,7 @@ fuzzy(0-16,0-69) fuzzy-if(skiaContent,0-95,0-2206) == attachment-local-clipping-
fuzzy(0-80,0-500) fuzzy-if(skiaContent,0-109,0-908) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html
fuzzy-if(skiaContent,0-1,0-8) fuzzy-if(webrender,0-1,0-84) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
fuzzy-if(webrender,73-93,49600-49600) == background-repeat-large-area.html background-repeat-large-area-ref.html
fuzzy-if(webrender,10-93,49600-49600) == background-repeat-large-area.html background-repeat-large-area-ref.html
fuzzy(0-30,0-474) fuzzy-if(skiaContent,0-31,0-474) == background-tiling-zoom-1.html background-tiling-zoom-1-ref.html

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

@ -1391,7 +1391,7 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 495385-4.html 495385-4-r
== 501257-1a.html 501257-1-ref.html
== 501257-1b.html 501257-1-ref.html
== 501257-1.xhtml 501257-1-ref.xhtml
fuzzy-if(webrender,2-6,39042-97456) == 501627-1.html 501627-1-ref.html # Bug 1481664
fuzzy-if(webrender,0-6,0-97456) == 501627-1.html 501627-1-ref.html # Bug 1481664
== 502288-1.html 502288-1-ref.html
fuzzy-if(gtkWidget,0-1,0-2) == 502447-1.html 502447-1-ref.html #Bug 1315834
== 502795-1.html 502795-1-ref.html
@ -1772,7 +1772,7 @@ fuzzy-if(asyncPan,0-190,0-510) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-102,0-
== 827577-1b.html 827577-1-ref.html
== 827799-1.html about:blank
== 829958.html 829958-ref.html
fuzzy-if(webrender&&gtkWidget,1-2,44000-152400) == 836844-1.html 836844-1-ref.html
fuzzy-if(webrender&&gtkWidget,0-2,0-152400) == 836844-1.html 836844-1-ref.html
== 841192-1.html 841192-1-ref.html
== 844178.html 844178-ref.html
fuzzy-if(OSX,0-1,0-364) fuzzy-if(skiaContent,0-1,0-320) == 846144-1.html 846144-1-ref.html

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

@ -5,7 +5,7 @@ fuzzy-if(webrender,9-9,4780-5120) == blur.html blur-ref.html
== blur.svg blur-ref.svg
== blur-calc.html blur-calc-ref.html
== blur-calc-negative.html blur-calc-negative-ref.html
fuzzy-if(cocoaWidget&&webrender,1-1,1-1) skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html
fuzzy-if(cocoaWidget&&webrender,0-1,0-1) skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html
fuzzy-if(webrender,9-9,4780-5120) == blur-em-radius.html blur-em-radius-ref.html
== blur-invalid-radius.html blur-invalid-radius-ref.html
fuzzy-if(webrender,9-9,4780-5120) == blur-rem-radius.html blur-rem-radius-ref.html

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

@ -122,7 +122,7 @@ public final class GeckoRuntimeSettings implements Parcelable {
* @return This Builder instance.
*/
public @NonNull Builder webFontsEnabled(final boolean flag) {
mSettings.mWebFonts.set(flag);
mSettings.mWebFonts.set(flag ? 1 : 0);
return this;
}
@ -368,8 +368,8 @@ public final class GeckoRuntimeSettings implements Parcelable {
"javascript.enabled", true);
/* package */ Pref<Boolean> mRemoteDebugging = new Pref<Boolean>(
"devtools.debugger.remote-enabled", false);
/* package */ Pref<Boolean> mWebFonts = new Pref<Boolean>(
"browser.display.use_document_fonts", true);
/* package */ Pref<Integer> mWebFonts = new Pref<Integer>(
"browser.display.use_document_fonts", 1);
/* package */ Pref<Integer> mCookieBehavior = new Pref<Integer>(
"network.cookie.cookieBehavior", COOKIE_ACCEPT_ALL);
/* package */ Pref<Integer> mCookieLifetime = new Pref<Integer>(
@ -541,7 +541,7 @@ public final class GeckoRuntimeSettings implements Parcelable {
* @return Whether web fonts support is enabled.
*/
public boolean getWebFontsEnabled() {
return mWebFonts.get();
return mWebFonts.get() != 0 ? true : false;
}
/**
@ -551,7 +551,7 @@ public final class GeckoRuntimeSettings implements Parcelable {
* @return This GeckoRuntimeSettings instance.
*/
public @NonNull GeckoRuntimeSettings setWebFontsEnabled(final boolean flag) {
mWebFonts.set(flag);
mWebFonts.set(flag ? 1 : 0);
return this;
}

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

@ -197,11 +197,17 @@ VARCACHE_PREF(
// If this is true, "keypress" event's keyCode value and charCode value always
// become same if the event is not created/initialized by JS.
#ifdef NIGHTLY_BUILD
# define PREF_VALUE true
#else
# define PREF_VALUE false
#endif
VARCACHE_PREF(
"dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value",
dom_keyboardevent_keypress_set_keycode_and_charcode_to_same_value,
bool, false
bool, PREF_VALUE
)
#undef PREF_VALUE
// NOTE: This preference is used in unit tests. If it is removed or its default
// value changes, please update test_sharedMap_var_caches.js accordingly.

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

@ -231,6 +231,16 @@ pref("dom.keyboardevent.keypress.hack.dispatch_non_printable_keys",
pref("dom.keyboardevent.keypress.dispatch_non_printable_keys_only_system_group_in_content", false);
#endif
#ifdef NIGHTLY_BUILD
// Blacklist of domains of web apps which handle keyCode and charCode of
// keypress events with a path only for Firefox (i.e., broken if we set
// non-zero keyCode or charCode value to the other). The format is exactly
// same as "dom.keyboardevent.keypress.hack.dispatch_non_printable_keys". So,
// check its explanation for the detail.
pref("dom.keyboardevent.keypress.hack.use_legacy_keycode_and_charcode",
"docs.google.com,www.rememberthemilk.com");
#endif
// Whether the WebMIDI API is enabled
pref("dom.webmidi.enabled", false);

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

@ -0,0 +1,179 @@
# coding=utf8
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import absolute_import
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import transforms_from, MESSAGE_REFERENCE
from fluent.migrate import COPY
def migrate(ctx):
"""Bug 1491679 - Convert a subset of the strings in extensions.dtd to using Fluent for localization, part {index}."""
ctx.add_transforms(
"toolkit/toolkit/about/aboutAddons.ftl",
"toolkit/toolkit/about/aboutAddons.ftl",
transforms_from(
"""
extensions-warning-safe-mode-label =
.value = { COPY(from_path, "warning.safemode.label") }
extensions-warning-check-compatibility-label =
.value = { COPY(from_path, "warning.checkcompatibility.label") }
extensions-warning-check-compatibility-enable =
.label = { COPY(from_path, "warning.checkcompatibility.enable.label") }
.tooltiptext = { COPY(from_path, "warning.checkcompatibility.enable.tooltip") }
extensions-warning-update-security-label =
.value = { COPY(from_path, "warning.updatesecurity.label") }
extensions-warning-update-security-enable =
.label = { COPY(from_path, "warning.updatesecurity.enable.label") }
.tooltiptext = { COPY(from_path, "warning.updatesecurity.enable.tooltip") }
extensions-updates-check-for-updates =
.label = { COPY(from_path, "updates.checkForUpdates.label") }
.accesskey = { COPY(from_path, "updates.checkForUpdates.accesskey") }
extensions-updates-view-updates =
.label = { COPY(from_path, "updates.viewUpdates.label") }
.accesskey = { COPY(from_path, "updates.viewUpdates.accesskey") }
extensions-updates-update-addons-automatically =
.label = { COPY(from_path, "updates.updateAddonsAutomatically.label") }
.accesskey = { COPY(from_path, "updates.updateAddonsAutomatically.accesskey") }
extensions-updates-reset-updates-to-automatic =
.label = { COPY(from_path, "updates.resetUpdatesToAutomatic.label") }
.accesskey = { COPY(from_path, "updates.resetUpdatesToAutomatic.accesskey") }
extensions-updates-reset-updates-to-manual =
.label = { COPY(from_path, "updates.resetUpdatesToManual.label") }
.accesskey = { COPY(from_path, "updates.resetUpdatesToManual.accesskey") }
extensions-updates-updating =
.value = { COPY(from_path, "updates.updating.label") }
extensions-updates-installed =
.value = { COPY(from_path, "updates.installed.label") }
extensions-updates-downloaded =
.value = { COPY(from_path, "updates.downloaded.label") }
extensions-updates-restart =
.label = { COPY(from_path, "updates.restart.label") }
extensions-updates-none-found =
.value = { COPY(from_path, "updates.noneFound.label") }
extensions-updates-manual-updates-found =
.label = { COPY(from_path, "updates.manualUpdatesFound.label") }
extensions-updates-update-selected =
.label = { COPY(from_path, "updates.updateSelected.label") }
.tooltiptext = { COPY(from_path, "updates.updateSelected.tooltip") }
""", from_path="toolkit/chrome/mozapps/extensions/extensions.dtd"))
ctx.add_transforms(
"toolkit/toolkit/about/aboutAddons.ftl",
"toolkit/toolkit/about/aboutAddons.ftl",
[
FTL.Message(
id=FTL.Identifier("extensions-view-discover"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("name"),
value=COPY(
"toolkit/chrome/mozapps/extensions/extensions.dtd",
"view.discover.label"
)
),
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-view-discover.name")
)
]
)
)
]
),
FTL.Message(
id=FTL.Identifier("extensions-view-recent-updates"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("name"),
value=COPY(
"toolkit/chrome/mozapps/extensions/extensions.dtd",
"view.recentUpdates.label"
)
),
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-view-recent-updates.name")
)
]
)
)
]
),
FTL.Message(
id=FTL.Identifier("extensions-view-available-updates"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("name"),
value=COPY(
"toolkit/chrome/mozapps/extensions/extensions.dtd",
"view.availableUpdates.label"
)
),
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-view-available-updates.name")
)
]
)
)
]
),
FTL.Message(
id=FTL.Identifier("extensions-warning-safe-mode-container"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-warning-safe-mode-label.value")
)
]
)
)
]
),
FTL.Message(
id=FTL.Identifier("extensions-warning-check-compatibility-container"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-warning-check-compatibility-label.value")
)
]
)
)
]
),
FTL.Message(
id=FTL.Identifier("extensions-warning-update-security-container"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("tooltiptext"),
value=FTL.Pattern(
elements=[
FTL.Placeable(
expression=MESSAGE_REFERENCE("extensions-warning-update-security-label.value")
)
]
)
)
]
),
]
)

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

@ -7733,6 +7733,42 @@
"description": "a testing histogram; not meant to be touched",
"operating_systems": ["mac"]
},
"TELEMETRY_TEST_MAIN_ONLY": {
"record_in_processes": ["main"],
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"expires_in_version": "never",
"kind": "linear",
"low": 1,
"high": 2147483646,
"n_buckets": 10,
"bug_numbers": [1498164],
"description": "a testing histogram; not meant to be touched",
"record_into_store": ["main"]
},
"TELEMETRY_TEST_SYNC_ONLY": {
"record_in_processes": ["main"],
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"expires_in_version": "never",
"kind": "linear",
"low": 1,
"high": 2147483646,
"n_buckets": 10,
"bug_numbers": [1498164],
"description": "a testing histogram; not meant to be touched",
"record_into_store": ["sync"]
},
"TELEMETRY_TEST_MULTIPLE_STORES": {
"record_in_processes": ["main"],
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"expires_in_version": "never",
"kind": "linear",
"low": 1,
"high": 2147483646,
"n_buckets": 10,
"bug_numbers": [1498164],
"description": "a testing histogram; not meant to be touched",
"record_into_store": ["main", "sync"]
},
"STARTUP_CRASH_DETECTED": {
"record_in_processes": ["main", "content"],
"expires_in_version": "never",
@ -10847,10 +10883,12 @@
},
"SSL_CERT_VERIFICATION_ERRORS": {
"record_in_processes": ["main", "content"],
"alert_emails": ["seceng@mozilla.org"],
"expires_in_version": "default",
"alert_emails": ["jhofmann@mozilla.com", "rtestard@mozilla.com", "seceng@mozilla.org"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"bug_numbers": [1503572],
"releaseChannelCollection": "opt-out",
"description": "If certificate verification failed in a TLS handshake, what was the error? (see MapCertErrorToProbeValue in security/manager/ssl/SSLServerCertVerification.cpp and the values in security/pkix/include/pkix/Result.h)"
},
"SSL_CT_POLICY_COMPLIANCE_OF_EV_CERTS": {

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

@ -2472,6 +2472,49 @@ telemetry.test:
- fennec
- geckoview
main_only:
bug_numbers:
- 1498164
description: >
This is a test uint type with only the main store.
expires: never
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
record_in_processes:
- 'main'
record_into_store:
- 'main'
sync_only:
bug_numbers:
- 1498164
description: >
This is a test uint type with only the sync store.
expires: never
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
record_in_processes:
- 'main'
record_into_store:
- 'sync'
multiple_stores:
bug_numbers:
- 1498164
description: >
This is a test uint type with multiple stores.
expires: never
kind: uint
notification_emails:
- telemetry-client-dev@mozilla.com
record_in_processes:
- 'main'
record_into_store:
- 'main'
- 'sync'
# NOTE: Please don't add new definitions below this point. Consider adding
# them earlier in the file and leave the telemetry.test category as the last
# one for readability.

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

@ -20,10 +20,12 @@ banner = """/* This file is auto-generated, see gen_histogram_data.py. */
"""
def print_array_entry(output, histogram, name_index, exp_index, label_index,
label_count, key_index, key_count):
def print_array_entry(output, histogram, name_index, exp_index,
label_index, label_count,
key_index, key_count,
store_index, store_count):
if histogram.record_on_os(buildconfig.substs["OS_TARGET"]):
print(" { %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %s, %s },"
print(" { %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %s, %s, %s },"
% (histogram.low(),
histogram.high(),
histogram.n_buckets(),
@ -31,8 +33,10 @@ def print_array_entry(output, histogram, name_index, exp_index, label_index,
exp_index,
label_count,
key_count,
store_count,
label_index,
key_index,
store_index,
"true" if histogram.keyed() else "false",
histogram.nsITelemetry_kind(),
histogram.dataset(),
@ -42,10 +46,13 @@ def print_array_entry(output, histogram, name_index, exp_index, label_index,
def write_histogram_table(output, histograms):
string_table = StringTable()
label_table = []
label_count = 0
keys_table = []
keys_count = 0
store_table = []
total_store_count = 0
print("constexpr HistogramInfo gHistogramInfos[] = {", file=output)
for histogram in histograms:
@ -66,8 +73,19 @@ def write_histogram_table(output, histograms):
keys_table.append((histogram.name(), string_table.stringIndexes(keys)))
keys_count += len(keys)
stores = histogram.record_into_store()
store_index = 0
if stores == ["main"]:
# if count == 1 && offset == UINT16_MAX -> only main store
store_index = 'UINT16_MAX'
else:
store_index = total_store_count
store_table.append((histogram.name(), string_table.stringIndexes(stores)))
total_store_count += len(stores)
print_array_entry(output, histogram, name_index, exp_index,
label_index, len(labels), key_index, len(keys))
label_index, len(labels), key_index, len(keys),
store_index, len(stores))
print("};\n", file=output)
strtab_name = "gHistogramStringTable"
@ -95,6 +113,18 @@ def write_histogram_table(output, histograms):
print("};", file=output)
static_assert(output, "sizeof(gHistogramKeyTable) <= UINT16_MAX", "index overflow")
store_table_name = "gHistogramStoresTable"
print("\n#if defined(_MSC_VER) && !defined(__clang__)", file=output)
print("const uint32_t {}[] = {{".format(store_table_name), file=output)
print("#else", file=output)
print("constexpr uint32_t {}[] = {{".format(store_table_name), file=output)
print("#endif", file=output)
for name, indexes in store_table:
print("/* %s */ %s," % (name, ", ".join(map(str, indexes))), file=output)
print("};", file=output)
static_assert(output, "sizeof(%s) <= UINT16_MAX" % store_table_name,
"index overflow")
# Write out static asserts for histogram data. We'd prefer to perform
# these checks in this script itself, but since several histograms

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

@ -35,7 +35,7 @@ file_footer = """\
"""
def write_scalar_info(scalar, output, name_index, expiration_index):
def write_scalar_info(scalar, output, name_index, expiration_index, store_index, store_count):
"""Writes a scalar entry to the output file.
:param scalar: a ScalarType instance describing the scalar.
@ -47,14 +47,16 @@ def write_scalar_info(scalar, output, name_index, expiration_index):
if cpp_guard:
print("#if defined(%s)" % cpp_guard, file=output)
print(" {{ {}, {}, {}, {}, {}, {}, {} }},"
print(" {{ {}, {}, {}, {}, {}, {}, {}, {}, {} }},"
.format(scalar.nsITelemetry_kind,
name_index,
expiration_index,
scalar.dataset,
" | ".join(scalar.record_in_processes_enum),
"true" if scalar.keyed else "false",
" | ".join(scalar.products_enum)),
" | ".join(scalar.products_enum),
store_count,
store_index),
file=output)
if cpp_guard:
@ -69,14 +71,28 @@ def write_scalar_tables(scalars, output):
"""
string_table = StringTable()
store_table = []
total_store_count = 0
print("const ScalarInfo gScalars[] = {", file=output)
for s in scalars:
# We add both the scalar label and the expiration string to the strings
# table.
name_index = string_table.stringIndex(s.label)
exp_index = string_table.stringIndex(s.expires)
stores = s.record_into_store
store_index = 0
if stores == ["main"]:
# if count == 1 && offset == UINT16_MAX -> only main store
store_index = 'UINT16_MAX'
else:
store_index = total_store_count
store_table.append((s.label, string_table.stringIndexes(stores)))
total_store_count += len(stores)
# Write the scalar info entry.
write_scalar_info(s, output, name_index, exp_index)
write_scalar_info(s, output, name_index, exp_index, store_index, len(stores))
print("};", file=output)
string_table_name = "gScalarsStringTable"
@ -84,6 +100,18 @@ def write_scalar_tables(scalars, output):
static_assert(output, "sizeof(%s) <= UINT32_MAX" % string_table_name,
"index overflow")
store_table_name = "gScalarStoresTable"
print("\n#if defined(_MSC_VER) && !defined(__clang__)", file=output)
print("const uint32_t {}[] = {{".format(store_table_name), file=output)
print("#else", file=output)
print("constexpr uint32_t {}[] = {{".format(store_table_name), file=output)
print("#endif", file=output)
for name, indexes in store_table:
print("/* %s */ %s," % (name, ", ".join(map(str, indexes))), file=output)
print("};", file=output)
static_assert(output, "sizeof(%s) <= UINT16_MAX" % store_table_name,
"index overflow")
def parse_scalar_definitions(filenames):
if len(filenames) > 1:

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

@ -36,6 +36,7 @@ ALWAYS_ALLOWED_KEYS = [
'bug_numbers',
'keys',
'record_in_processes',
'record_into_store',
'products',
]
@ -141,6 +142,7 @@ definition is a dict-like object that must contain at least the keys:
self._expiration = definition.get('expires_in_version')
self._labels = definition.get('labels', [])
self._record_in_processes = definition.get('record_in_processes')
self._record_into_store = definition.get('record_into_store', ['main'])
self._products = definition.get('products', ["all"])
self._operating_systems = definition.get('operating_systems', ["all"])
@ -232,6 +234,10 @@ the histogram."""
return canonical_os in os
def record_into_store(self):
"""Get the non-empty list of stores to record into"""
return self._record_into_store
def ranges(self):
"""Return an array of lower bounds for each bucket in the histogram."""
bucket_fns = {
@ -303,6 +309,7 @@ the histogram."""
self.check_record_in_processes(name, definition)
self.check_products(name, definition)
self.check_operating_systems(name, definition)
self.check_record_into_store(name, definition)
def check_name(self, name):
if '#' in name:
@ -415,7 +422,7 @@ the histogram."""
field = 'operating_systems'
operating_systems = definition.get(field)
DOC_URL = HISTOGRAMS_DOC_URL + "#operating_systems"
DOC_URL = HISTOGRAMS_DOC_URL + "#operating-systems"
if not operating_systems:
# operating_systems is optional
@ -426,6 +433,23 @@ the histogram."""
ParserError('Histogram "%s" has unknown operating system "%s" in %s.\n%s' %
(name, operating_system, field, DOC_URL)).handle_later()
def check_record_into_store(self, name, definition):
if not self._strict_type_checks:
return
field = 'record_into_store'
DOC_URL = HISTOGRAMS_DOC_URL + "#record-into-store"
if field not in definition:
# record_into_store is optional
return
record_into_store = definition.get(field)
# record_into_store should not be empty
if not record_into_store:
ParserError('Histogram "%s" has empty list of stores, which is not allowed.\n%s' %
(name, DOC_URL)).handle_later()
def check_keys_field(self, name, definition):
keys = definition.get('keys')
if not self._strict_type_checks or keys is None:
@ -512,6 +536,7 @@ the histogram."""
"keys": basestring,
"products": basestring,
"operating_systems": basestring,
"record_into_store": basestring,
}
# For the server-side, where _strict_type_checks==False, we want to

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

@ -111,6 +111,7 @@ class ScalarType:
'release_channel_collection': basestring,
'keyed': bool,
'products': list,
'record_into_store': list,
}
# The types for the data within the fields that hold lists.
@ -119,6 +120,7 @@ class ScalarType:
'notification_emails': basestring,
'record_in_processes': basestring,
'products': basestring,
'record_into_store': basestring,
}
# Concatenate the required and optional field definitions.
@ -329,6 +331,11 @@ class ScalarType:
"""Get the cpp guard for this scalar"""
return self._definition.get('cpp_guard')
@property
def record_into_store(self):
"""Get the list of stores this probe should be recorded into"""
return self._definition.get('record_into_store', ['main'])
def load_scalars(filename, strict_type_checks=True):
"""Parses a YAML file containing the scalar definition.

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

@ -49,6 +49,8 @@ struct BaseScalarInfo {
struct ScalarInfo : BaseScalarInfo {
uint32_t name_offset;
uint32_t expiration_offset;
uint32_t store_count;
uint16_t store_offset;
// In order to cleanly support dynamic scalars in TelemetryScalar.cpp, we need
// to use virtual functions for |name| and |expiration|, as they won't be looked
@ -59,7 +61,8 @@ struct ScalarInfo : BaseScalarInfo {
ScalarInfo(uint32_t aKind, uint32_t aNameOffset, uint32_t aExpirationOffset,
uint32_t aDataset,
mozilla::Telemetry::Common::RecordedProcessType aRecordInProcess,
bool aKeyed, mozilla::Telemetry::Common::SupportedProduct aProducts)
bool aKeyed, mozilla::Telemetry::Common::SupportedProduct aProducts,
uint32_t aStoreCount, uint16_t aStoreOffset)
: BaseScalarInfo(aKind, aDataset, aRecordInProcess, aKeyed, aProducts)
, name_offset(aNameOffset)
, expiration_offset(aExpirationOffset)

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

@ -140,8 +140,10 @@ struct HistogramInfo {
uint32_t expiration_offset;
uint32_t label_count;
uint32_t key_count;
uint32_t store_count;
uint16_t label_index;
uint16_t key_index;
uint16_t store_index;
bool keyed;
uint8_t histogramType;
uint8_t dataset;

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

@ -235,6 +235,16 @@ Optional. This field is a list of products this histogram can be recorded on. Cu
If this field is left out it defaults to ``all``.
``record_into_store``
---------------------
.. note::
This field is not yet ready for use.
Optional. This field is a list of stores this histogram should be recorded into.
If this field is left out it defaults to ``[main]``.
Changing a histogram
====================
Changing histogram declarations after the histogram has been released is tricky. Many tools (like `the aggregator <https://github.com/mozilla/python_mozaggregator>`_) assume histograms don't change. The current recommended procedure is to change the name of the histogram.

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

@ -173,6 +173,8 @@ Optional Fields
- ``geckoview``
- ``all`` (record on all products)
- ``record_into_store``: A list of stores this scalar should be recorded into. It defaults to ``[main]`` (*Note: This field is not yet ready to use*).
String type restrictions
------------------------
To prevent abuses, the content of a string scalar is limited to 50 characters in length. Trying

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

@ -1033,7 +1033,6 @@
"SSL_AUTH_RSA_KEY_SIZE_FULL",
"SSL_BYTES_BEFORE_CERT_CALLBACK",
"SSL_CERT_ERROR_OVERRIDES",
"SSL_CERT_VERIFICATION_ERRORS",
"SSL_CIPHER_SUITE_FULL",
"SSL_CIPHER_SUITE_RESUMED",
"SSL_HANDSHAKE_TYPE",
@ -1363,7 +1362,6 @@
"TRANSLATED_PAGES_BY_LANGUAGE",
"MOZ_SQLITE_OTHER_WRITE_B",
"LOCALDOMSTORAGE_SHUTDOWN_DATABASE_MS",
"SSL_CERT_VERIFICATION_ERRORS",
"FX_SESSION_RESTORE_NUMBER_OF_WINDOWS_RESTORED",
"MOZ_SQLITE_PLACES_WRITE_MS",
"FX_THUMBNAILS_BG_CAPTURE_CANVAS_DRAW_TIME_MS",

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

@ -42,7 +42,7 @@ add_task(async function test_recording() {
"pre_content_spawn_expiration": {
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
keyed: false,
release_channel_collection: true,
record_on_release: true,
},
});
@ -65,17 +65,17 @@ add_task(async function test_recording() {
"post_content_spawn": {
kind: Ci.nsITelemetry.SCALAR_TYPE_BOOLEAN,
keyed: false,
release_channel_collection: false,
record_on_release: false,
},
"post_content_spawn_keyed": {
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
keyed: true,
release_channel_collection: true,
record_on_release: true,
},
"pre_content_spawn_expiration": {
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
keyed: false,
release_channel_collection: true,
record_on_release: true,
expired: true,
},
});

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

@ -40,6 +40,7 @@ class TestParser(unittest.TestCase):
self.assertTrue(hist.expiration(), "never")
self.assertTrue(hist.kind(), "boolean")
self.assertTrue(hist.record_in_processes, ["main", "content"])
self.assertTrue(hist.record_into_store, ["main"])
def test_missing_bug_numbers(self):
SAMPLE_HISTOGRAM = {
@ -325,6 +326,50 @@ class TestParser(unittest.TestCase):
parse_histograms.whitelists = None
def test_multistore(self):
SAMPLE_HISTOGRAM = {
"TEST_VALID_HISTOGRAM": {
"record_in_processes": ["main", "content"],
"alert_emails": ["team@mozilla.xyz"],
"bug_numbers": [1383793],
"expires_in_version": "never",
"kind": "boolean",
"description": "Test histogram",
"record_into_store": ["main", "sync"],
}
}
histograms = load_histogram(SAMPLE_HISTOGRAM)
parse_histograms.load_whitelist()
hist = parse_histograms.Histogram('TEST_VALID_HISTOGRAM',
histograms['TEST_VALID_HISTOGRAM'],
strict_type_checks=True)
ParserError.exit_func()
self.assertTrue(hist.expiration(), "never")
self.assertTrue(hist.kind(), "boolean")
self.assertTrue(hist.record_into_store, ["main", "sync"])
def test_multistore_empty(self):
SAMPLE_HISTOGRAM = {
"TEST_HISTOGRAM_EMPTY_MULTISTORE": {
"record_in_processes": ["main", "content"],
"alert_emails": ["team@mozilla.xyz"],
"bug_numbers": [1383793],
"expires_in_version": "never",
"kind": "boolean",
"description": "Test histogram",
"record_into_store": [],
}
}
histograms = load_histogram(SAMPLE_HISTOGRAM)
parse_histograms.load_whitelist()
parse_histograms.Histogram('TEST_HISTOGRAM_EMPTY_MULTISTORE',
histograms['TEST_HISTOGRAM_EMPTY_MULTISTORE'],
strict_type_checks=True)
self.assertRaises(SystemExit, ParserError.exit_func)
if __name__ == '__main__':
mozunit.main()

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

@ -53,6 +53,7 @@ bug_numbers:
SAMPLE_SCALAR_INVALID_ADDRESSES = """
description: A nice one-line description.
expires: never
record_in_processes:
- 'main'
kind: uint
notification_emails:
@ -68,6 +69,71 @@ bug_numbers:
self.assertRaises(SystemExit, ParserError.exit_func)
def test_multistore_default(self):
SAMPLE_SCALAR = """
description: A nice one-line description.
expires: never
record_in_processes:
- 'main'
kind: uint
notification_emails:
- test01@mozilla.com
bug_numbers:
- 12345
"""
scalar = load_scalar(SAMPLE_SCALAR)
sclr = parse_scalars.ScalarType("CATEGORY",
"PROVE",
scalar,
strict_type_checks=True)
ParserError.exit_func()
self.assertEqual(sclr.record_into_store, ["main"])
def test_multistore_extended(self):
SAMPLE_SCALAR = """
description: A nice one-line description.
expires: never
record_in_processes:
- 'main'
kind: uint
notification_emails:
- test01@mozilla.com
bug_numbers:
- 12345
record_into_store:
- main
- sync
"""
scalar = load_scalar(SAMPLE_SCALAR)
sclr = parse_scalars.ScalarType("CATEGORY",
"PROVE",
scalar,
strict_type_checks=True)
ParserError.exit_func()
self.assertEqual(sclr.record_into_store, ["main", "sync"])
def test_multistore_empty(self):
SAMPLE_SCALAR = """
description: A nice one-line description.
expires: never
record_in_processes:
- 'main'
kind: uint
notification_emails:
- test01@mozilla.com
bug_numbers:
- 12345
record_into_store: []
"""
scalar = load_scalar(SAMPLE_SCALAR)
parse_scalars.ScalarType("CATEGORY",
"PROVE",
scalar,
strict_type_checks=True)
self.assertRaises(SystemExit, ParserError.exit_func)
if __name__ == '__main__':
mozunit.main()

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

@ -2,49 +2,6 @@
- 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/. -->
<!-- global warnings -->
<!ENTITY warning.safemode.label "All add-ons have been disabled by safe mode.">
<!ENTITY warning.checkcompatibility.label "Add-on compatibility checking is disabled. You may have incompatible add-ons.">
<!ENTITY warning.checkcompatibility.enable.label "Enable">
<!ENTITY warning.checkcompatibility.enable.tooltip "Enable add-on compatibility checking">
<!ENTITY warning.updatesecurity.label "Add-on update security checking is disabled. You may be compromised by updates.">
<!ENTITY warning.updatesecurity.enable.label "Enable">
<!ENTITY warning.updatesecurity.enable.tooltip "Enable add-on update security checking">
<!-- categories / views -->
<!ENTITY view.discover.label "Get Add-ons">
<!ENTITY view.recentUpdates.label "Recent Updates">
<!ENTITY view.availableUpdates.label "Available Updates">
<!-- addon updates -->
<!ENTITY updates.checkForUpdates.label "Check for Updates">
<!ENTITY updates.checkForUpdates.accesskey "C">
<!ENTITY updates.viewUpdates.label "View Recent Updates">
<!ENTITY updates.viewUpdates.accesskey "V">
<!-- LOCALIZATION NOTE (updates.updateAddonsAutomatically.label): This menu item
is a checkbox that toggles the default global behavior for add-on update
checking. -->
<!ENTITY updates.updateAddonsAutomatically.label "Update Add-ons Automatically">
<!ENTITY updates.updateAddonsAutomatically.accesskey "A">
<!-- LOCALIZATION NOTE (updates.resetUpdatesToAutomatic.label, updates.resetUpdatesToManual.label):
Specific addons can have custom update checking behaviors ("Manually",
"Automatically", "Use default global behavior"). These menu items reset the
update checking behavior for all add-ons to the default global behavior
(which itself is either "Automatically" or "Manually", controlled by the
updates.updateAddonsAutomatically.label menu item). -->
<!ENTITY updates.resetUpdatesToAutomatic.label "Reset All Add-ons to Update Automatically">
<!ENTITY updates.resetUpdatesToAutomatic.accesskey "R">
<!ENTITY updates.resetUpdatesToManual.label "Reset All Add-ons to Update Manually">
<!ENTITY updates.resetUpdatesToManual.accesskey "R">
<!ENTITY updates.updating.label "Updating add-ons">
<!ENTITY updates.installed.label "Your add-ons have been updated.">
<!ENTITY updates.downloaded.label "Your add-on updates have been downloaded.">
<!ENTITY updates.restart.label "Restart now to complete installation">
<!ENTITY updates.noneFound.label "No updates found">
<!ENTITY updates.manualUpdatesFound.label "View Available Updates">
<!ENTITY updates.updateSelected.label "Install Updates">
<!ENTITY updates.updateSelected.tooltip "Install available updates in this list">
<!-- addon actions -->
<!ENTITY cmd.enableAddon.label "Enable">
<!ENTITY cmd.enableAddon.accesskey "E">

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

@ -189,3 +189,89 @@ legacy-extensions =
legacy-extensions-description =
These extensions do not meet current { -brand-short-name } standards so they have been deactivated. <label data-l10n-name="legacy-learn-more">Learn about the changes to add-ons</label>
extensions-view-discover =
.name = Get Add-ons
.tooltiptext = { extensions-view-discover.name }
extensions-view-recent-updates =
.name = Recent Updates
.tooltiptext = { extensions-view-recent-updates.name }
extensions-view-available-updates =
.name = Available Updates
.tooltiptext = { extensions-view-available-updates.name }
## These are global warnings
extensions-warning-safe-mode-label =
.value = All add-ons have been disabled by safe mode.
extensions-warning-safe-mode-container =
.tooltiptext = { extensions-warning-safe-mode-label.value }
extensions-warning-check-compatibility-label =
.value = Add-on compatibility checking is disabled. You may have incompatible add-ons.
extensions-warning-check-compatibility-container =
.tooltiptext = { extensions-warning-check-compatibility-label.value }
extensions-warning-check-compatibility-enable =
.label = Enable
.tooltiptext = Enable add-on compatibility checking
extensions-warning-update-security-label =
.value = Add-on update security checking is disabled. You may be compromised by updates.
extensions-warning-update-security-container =
.tooltiptext = { extensions-warning-update-security-label.value }
extensions-warning-update-security-enable =
.label = Enable
.tooltiptext = Enable add-on update security checking
## Strings connected to add-on updates
extensions-updates-check-for-updates =
.label = Check for Updates
.accesskey = C
extensions-updates-view-updates =
.label = View Recent Updates
.accesskey = V
# This menu item is a checkbox that toggles the default global behavior for
# add-on update checking.
extensions-updates-update-addons-automatically =
.label = Update Add-ons Automatically
.accesskey = A
## Specific add-ons can have custom update checking behaviors ("Manually",
## "Automatically", "Use default global behavior"). These menu items reset the
## update checking behavior for all add-ons to the default global behavior
## (which itself is either "Automatically" or "Manually", controlled by the
## extensions-updates-update-addons-automatically.label menu item).
extensions-updates-reset-updates-to-automatic =
.label = Reset All Add-ons to Update Automatically
.accesskey = R
extensions-updates-reset-updates-to-manual =
.label = Reset All Add-ons to Update Manually
.accesskey = R
## Status messages displayed when updating add-ons
extensions-updates-updating =
.value = Updating add-ons
extensions-updates-installed =
.value = Your add-ons have been updated.
extensions-updates-downloaded =
.value = Your add-on updates have been downloaded.
extensions-updates-restart =
.label = Restart now to complete installation
extensions-updates-none-found =
.value = No updates found
extensions-updates-manual-updates-found =
.label = View Available Updates
extensions-updates-update-selected =
.label = Install Updates
.tooltiptext = Install available updates in this list

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

@ -128,20 +128,23 @@
<richlistbox id="categories" flex="1">
<richlistitem id="category-discover" value="addons://discover/"
class="category"
name="&view.discover.label;" priority="1000"
tooltiptext="&view.discover.label;"/>
data-l10n-id="extensions-view-discover"
data-l10n-attrs="name"
priority="1000"/>
<richlistitem id="category-legacy" value="addons://legacy/"
class="category" priority="20000"
disabled="true"/>
<richlistitem id="category-availableUpdates" value="addons://updates/available"
class="category"
name="&view.availableUpdates.label;" priority="100000"
tooltiptext="&view.availableUpdates.label;"
data-l10n-id="extensions-view-available-updates"
data-l10n-attrs="name"
disabled="true"/>
<richlistitem id="category-recentUpdates" value="addons://updates/recent"
class="category"
name="&view.recentUpdates.label;" priority="101000"
tooltiptext="&view.recentUpdates.label;" disabled="true"/>
data-l10n-id="extensions-view-recent-updates"
data-l10n-attrs="name"
priority="101000"
disabled="true"/>
</richlistbox>
<spacer flex="1"/>
@ -225,18 +228,19 @@
<hbox id="updates-container" align="center">
<image class="spinner"/>
<label id="updates-noneFound" hidden="true"
value="&updates.noneFound.label;"/>
data-l10n-id="extensions-updates-none-found"/>
<button id="updates-manualUpdatesFound-btn" class="button-link"
hidden="true" label="&updates.manualUpdatesFound.label;"
hidden="true"
data-l10n-id="extensions-updates-manual-updates-found"
command="cmd_goToAvailableUpdates"/>
<label id="updates-progress" hidden="true"
value="&updates.updating.label;"/>
data-l10n-id="extensions-updates-updating"/>
<label id="updates-installed" hidden="true"
value="&updates.installed.label;"/>
data-l10n-id="extensions-updates-installed"/>
<label id="updates-downloaded" hidden="true"
value="&updates.downloaded.label;"/>
data-l10n-id="extensions-updates-downloaded"/>
<button id="updates-restart-btn" class="button-link" hidden="true"
label="&updates.restart.label;"
data-l10n-id="extensions-updates-restart"
command="cmd_restartApp"/>
</hbox>
@ -244,12 +248,10 @@
data-l10n-id="tools-menu">
<menupopup id="utils-menu">
<menuitem id="utils-updateNow"
label="&updates.checkForUpdates.label;"
accesskey="&updates.checkForUpdates.accesskey;"
data-l10n-id="extensions-updates-check-for-updates"
command="cmd_findAllUpdates"/>
<menuitem id="utils-viewUpdates"
label="&updates.viewUpdates.label;"
accesskey="&updates.viewUpdates.accesskey;"
data-l10n-id="extensions-updates-view-updates"
command="cmd_goToRecentUpdates"/>
<menuseparator id="utils-installFromFile-separator"/>
<menuitem id="utils-installFromFile"
@ -260,17 +262,14 @@
command="cmd_debugAddons"/>
<menuseparator/>
<menuitem id="utils-autoUpdateDefault"
label="&updates.updateAddonsAutomatically.label;"
accesskey="&updates.updateAddonsAutomatically.accesskey;"
data-l10n-id="extensions-updates-update-addons-automatically"
type="checkbox" autocheck="false"
command="cmd_toggleAutoUpdateDefault"/>
<menuitem id="utils-resetAddonUpdatesToAutomatic"
label="&updates.resetUpdatesToAutomatic.label;"
accesskey="&updates.resetUpdatesToAutomatic.accesskey;"
data-l10n-id="extensions-updates-reset-updates-to-automatic"
command="cmd_resetAddonAutoUpdate"/>
<menuitem id="utils-resetAddonUpdatesToManual"
label="&updates.resetUpdatesToManual.label;"
accesskey="&updates.resetUpdatesToManual.accesskey;"
data-l10n-id="extensions-updates-reset-updates-to-manual"
command="cmd_resetAddonAutoUpdate"/>
</menupopup>
</toolbarbutton>
@ -310,30 +309,28 @@
<!-- global warnings -->
<hbox class="global-warning" flex="1">
<hbox class="global-warning-safemode" flex="1" align="center"
tooltiptext="&warning.safemode.label;">
data-l10n-id="extensions-warning-safe-mode-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.safemode.label;"/>
data-l10n-id="extensions-warning-safe-mode-label"/>
</hbox>
<hbox class="global-warning-checkcompatibility" flex="1" align="center"
tooltiptext="&warning.checkcompatibility.label;">
data-l10n-id="extensions-warning-check-compatibility-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.checkcompatibility.label;"/>
data-l10n-id="extensions-warning-check-compatibility-label"/>
</hbox>
<button class="button-link global-warning-checkcompatibility"
label="&warning.checkcompatibility.enable.label;"
tooltiptext="&warning.checkcompatibility.enable.tooltip;"
data-l10n-id="extensions-warning-check-compatibility-enable"
command="cmd_enableCheckCompatibility"/>
<hbox class="global-warning-updatesecurity" flex="1" align="center"
tooltiptext="&warning.updatesecurity.label;">
data-l10n-id="extensions-warning-update-security-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.updatesecurity.label;"/>
data-l10n-id="extensions-warning-update-security-label"/>
</hbox>
<button class="button-link global-warning-updatesecurity"
label="&warning.updatesecurity.enable.label;"
tooltiptext="&warning.updatesecurity.enable.tooltip;"
data-l10n-id="extensions-warning-update-security-enable"
command="cmd_enableUpdateSecurity"/>
<spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
</hbox>
@ -370,30 +367,28 @@
<!-- global warnings -->
<hbox class="global-warning" flex="1">
<hbox class="global-warning-safemode" flex="1" align="center"
tooltiptext="&warning.safemode.label;">
data-l10n-id="extensions-warning-safe-mode-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.safemode.label;"/>
data-l10n-id="extensions-warning-safe-mode-label"/>
</hbox>
<hbox class="global-warning-checkcompatibility" flex="1" align="center"
tooltiptext="&warning.checkcompatibility.label;">
data-l10n-id="extensions-warning-check-compatibility-label">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.checkcompatibility.label;"/>
data-l10n-id="extensions-warning-check-compatibility-label"/>
</hbox>
<button class="button-link global-warning-checkcompatibility"
label="&warning.checkcompatibility.enable.label;"
tooltiptext="&warning.checkcompatibility.enable.tooltip;"
data-l10n-id="extensions-warning-check-compatibility-enable"
command="cmd_enableCheckCompatibility"/>
<hbox class="global-warning-updatesecurity" flex="1" align="center"
tooltiptext="&warning.updatesecurity.label;">
data-l10n-id="extensions-warning-update-security-label">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.updatesecurity.label;"/>
data-l10n-id="extensions-warning-update-security-label"/>
</hbox>
<button class="button-link global-warning-updatesecurity"
label="&warning.updatesecurity.enable.label;"
tooltiptext="&warning.updatesecurity.enable.tooltip;"
data-l10n-id="extensions-warning-update-security-enable"
command="cmd_enableUpdateSecurity"/>
<spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
</hbox>
@ -411,8 +406,7 @@
</vbox>
<hbox id="update-actions" pack="center">
<button id="update-selected-btn" hidden="true"
label="&updates.updateSelected.label;"
tooltiptext="&updates.updateSelected.tooltip;"/>
data-l10n-id="extensions-updates-update-selected"/>
</hbox>
<richlistbox id="updates-list" class="list" flex="1"/>
</vbox>
@ -423,30 +417,28 @@
<!-- global warnings -->
<hbox class="global-warning-container global-warning">
<hbox class="global-warning-safemode" flex="1" align="center"
tooltiptext="&warning.safemode.label;">
data-l10n-id="extensions-warning-safe-mode-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.safemode.label;"/>
data-l10n-id="extensions-warning-safe-mode-label"/>
</hbox>
<hbox class="global-warning-checkcompatibility" flex="1" align="center"
tooltiptext="&warning.checkcompatibility.label;">
data-l10n-id="extensions-warning-check-compatibility-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.checkcompatibility.label;"/>
data-l10n-id="extensions-warning-check-compatibility-label"/>
</hbox>
<button class="button-link global-warning-checkcompatibility"
label="&warning.checkcompatibility.enable.label;"
tooltiptext="&warning.checkcompatibility.enable.tooltip;"
data-l10n-id="extensions-warning-check-compatibility-enable"
command="cmd_enableCheckCompatibility"/>
<hbox class="global-warning-updatesecurity" flex="1" align="center"
tooltiptext="&warning.updatesecurity.label;">
data-l10n-id="extensions-warning-update-security-container">
<image class="warning-icon"/>
<label class="global-warning-text" flex="1" crop="end"
value="&warning.updatesecurity.label;"/>
data-l10n-id="extensions-warning-update-security-label"/>
</hbox>
<button class="button-link global-warning-updatesecurity"
label="&warning.updatesecurity.enable.label;"
tooltiptext="&warning.updatesecurity.enable.tooltip;"
data-l10n-id="extensions-warning-update-security-label"
command="cmd_enableUpdateSecurity"/>
<spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
</hbox>

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

@ -86,7 +86,7 @@ getId(const char *bin_name)
using namespace google_breakpad;
PageAllocator allocator;
auto_wasteful_vector<uint8_t, sizeof(MDGUID)> identifier(&allocator);
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier(&allocator);
#if defined(GP_OS_android)
if (nsDependentCString(bin_name).Find("!/") != kNotFound) {

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

@ -166,6 +166,7 @@ protected:
, mIsComposing(false)
, mIsSynthesizedByTIP(false)
, mMaybeSkippableInRemoteProcess(true)
, mUseLegacyKeyCodeAndCharCodeValues(false)
, mEditCommandsForSingleLineEditorInitialized(false)
, mEditCommandsForMultiLineEditorInitialized(false)
, mEditCommandsForRichTextEditorInitialized(false)
@ -195,6 +196,7 @@ public:
, mIsComposing(false)
, mIsSynthesizedByTIP(false)
, mMaybeSkippableInRemoteProcess(true)
, mUseLegacyKeyCodeAndCharCodeValues(false)
, mEditCommandsForSingleLineEditorInitialized(false)
, mEditCommandsForMultiLineEditorInitialized(false)
, mEditCommandsForRichTextEditorInitialized(false)
@ -400,6 +402,10 @@ public:
// Don't refer this member directly when you need to check this.
// Use CanSkipInRemoteProcess() instead.
bool mMaybeSkippableInRemoteProcess;
// Indicates whether the event should return legacy keyCode value and
// charCode value to web apps (one of them is always 0) or not, when it's
// an eKeyPress event.
bool mUseLegacyKeyCodeAndCharCodeValues;
bool CanSkipInRemoteProcess() const
{
@ -681,6 +687,8 @@ public:
#endif
mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP;
mMaybeSkippableInRemoteProcess = aEvent.mMaybeSkippableInRemoteProcess;
mUseLegacyKeyCodeAndCharCodeValues =
aEvent.mUseLegacyKeyCodeAndCharCodeValues;
// Don't copy mEditCommandsFor*Editor because it may require a lot of
// memory space. For example, if the event is dispatched but grabbed by