Merge inbound to mozilla-central. a=merge

This commit is contained in:
Brindusan Cristian 2018-08-23 01:00:10 +03:00
Родитель 312fdae0eb a67fd14d8f
Коммит d21b936680
143 изменённых файлов: 2518 добавлений и 1427 удалений

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

@ -418,13 +418,11 @@ var ContentBlocking = {
}
// Check whether the user has added an exception for this site.
let hasException = false;
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
hasException = PrivateBrowsingUtils.existsInTrackingAllowlist(baseURI);
} else {
hasException = Services.perms.testExactPermission(baseURI,
"trackingprotection") == Services.perms.ALLOW_ACTION;
}
let type = PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser) ?
"trackingprotection-pb" :
"trackingprotection";
let hasException = Services.perms.testExactPermission(baseURI, type) ==
Services.perms.ALLOW_ACTION;
this.content.toggleAttribute("detected", detected);
this.content.toggleAttribute("hasException", hasException);

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

@ -553,7 +553,8 @@
for (let i = numPinned - 1; i >= 0; i--) {
let tab = this.children[i];
width += layoutData.pinnedTabWidth;
tab.style.marginInlineStart = -(width + layoutData.scrollButtonWidth) + "px";
tab.style.setProperty("margin-inline-start",
-(width + layoutData.scrollButtonWidth) + "px", "important");
tab._pinnedUnscrollable = true;
}
this.style.paddingInlineStart = width + "px";

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

@ -286,3 +286,4 @@ skip-if = !crashreporter || !e10s # Tabs can't crash without e10s
[browser_speculative_connect.js]
[browser_1446343-windowsize.js]
[browser_restore_reversed_z_order.js]
skip-if = true #Bug 1455602

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

@ -388,10 +388,6 @@
@RESPATH@/components/nsUrlClassifierListManager.js
@RESPATH@/components/nsUrlClassifierLib.js
; Private Browsing
@RESPATH@/components/PrivateBrowsing.manifest
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
; Security Reports
@RESPATH@/components/SecurityReporter.manifest
@RESPATH@/components/SecurityReporter.js

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

@ -70,8 +70,8 @@
background-color: transparent;
border-radius: 0;
border-width: 0;
margin: 0;
padding: 0;
margin: 0 !important /* override tabbox.css */;
padding: 0 !important /* override tabbox.css */;
-moz-box-align: stretch;
}

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

@ -13,7 +13,7 @@ const {
module.exports = {
/**
* Update the geometry editor's enabled state.
* Updates the geometry editor's enabled state.
*
* @param {Boolean} enabled
* Whether or not the geometry editor is enabled or not.
@ -26,7 +26,7 @@ module.exports = {
},
/**
* Update the layout state with the new layout properties.
* Updates the layout state with the new layout properties.
*/
updateLayout(layout) {
return {
@ -36,7 +36,7 @@ module.exports = {
},
/**
* Update the offset parent state with the new DOM node.
* Updates the offset parent state with the new DOM node.
*/
updateOffsetParent(offsetParent) {
return {

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

@ -8,13 +8,13 @@ const { createEnum } = require("devtools/client/shared/enum");
createEnum([
// Update the geometry editor's enabled state.
// Updates the geometry editor's enabled state.
"UPDATE_GEOMETRY_EDITOR_ENABLED",
// Update the layout state with the latest layout properties.
// Updates the layout state with the latest layout properties.
"UPDATE_LAYOUT",
// Update the offset parent state with the new DOM node.
// Updates the offset parent state with the new DOM node.
"UPDATE_OFFSET_PARENT",
], module.exports);

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

@ -18,13 +18,13 @@ class BoxModel extends PureComponent {
static get propTypes() {
return {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
setSelectedNode: PropTypes.func.isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
onShowBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
onToggleGeometryEditor: PropTypes.func.isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -44,16 +44,17 @@ class BoxModel extends PureComponent {
render() {
const {
boxModel,
setSelectedNode,
showBoxModelProperties,
onHideBoxModelHighlighter,
onShowBoxModelEditor,
onShowBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
onToggleGeometryEditor,
setSelectedNode,
showBoxModelProperties,
} = this.props;
return dom.div(
return (
dom.div(
{
className: "boxmodel-container",
tabIndex: 0,
@ -85,6 +86,7 @@ class BoxModel extends PureComponent {
})
:
null
)
);
}
}

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

@ -18,9 +18,9 @@ class BoxModelEditable extends PureComponent {
direction: PropTypes.string,
focusable: PropTypes.bool.isRequired,
level: PropTypes.string,
onShowBoxModelEditor: PropTypes.func.isRequired,
property: PropTypes.string.isRequired,
textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
};
}
@ -49,7 +49,8 @@ class BoxModelEditable extends PureComponent {
box !== "position" &&
textContent.toString().length > LONG_TEXT_ROTATE_LIMIT;
return dom.p(
return (
dom.p(
{
className: `boxmodel-${box}
${direction ? " boxmodel-" + direction : "boxmodel-" + property}
@ -67,6 +68,7 @@ class BoxModelEditable extends PureComponent {
},
textContent
)
)
);
}
}

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

@ -49,20 +49,12 @@ class BoxModelInfo extends PureComponent {
buttonClass += " checked";
}
return dom.div(
{
className: "boxmodel-info",
},
dom.span(
{
className: "boxmodel-element-size",
},
return (
dom.div({ className: "boxmodel-info" },
dom.span({ className: "boxmodel-element-size" },
SHARED_L10N.getFormatStr("dimensions", width, height)
),
dom.section(
{
className: "boxmodel-position-group",
},
dom.section({ className: "boxmodel-position-group" },
isPositionEditable ?
dom.button({
className: buttonClass,
@ -71,11 +63,7 @@ class BoxModelInfo extends PureComponent {
})
:
null,
dom.span(
{
className: "boxmodel-element-position",
},
position
dom.span({ className: "boxmodel-element-position" }, position)
)
)
);

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

@ -46,10 +46,10 @@ class BoxModelMain extends PureComponent {
this.getPositionValue = this.getPositionValue.bind(this);
this.getWidthValue = this.getWidthValue.bind(this);
this.moveFocus = this.moveFocus.bind(this);
this.setAriaActive = this.setAriaActive.bind(this);
this.onHighlightMouseOver = this.onHighlightMouseOver.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.onLevelClick = this.onLevelClick.bind(this);
this.setAriaActive = this.setAriaActive.bind(this);
}
componentDidUpdate() {
@ -414,10 +414,7 @@ class BoxModelMain extends PureComponent {
width = this.getWidthValue(width);
const contentBox = layout["box-sizing"] == "content-box" ?
dom.div(
{
className: "boxmodel-size",
},
dom.div({ className: "boxmodel-size" },
BoxModelEditable({
box: "content",
focusable,
@ -429,10 +426,7 @@ class BoxModelMain extends PureComponent {
textContent: width,
onShowBoxModelEditor
}),
dom.span(
{},
"\u00D7"
),
dom.span({}, "\u00D7"),
BoxModelEditable({
box: "content",
focusable,
@ -443,19 +437,14 @@ class BoxModelMain extends PureComponent {
})
)
:
dom.p(
{
className: "boxmodel-size",
},
dom.span(
{
title: "content",
},
dom.p({ className: "boxmodel-size" },
dom.span({ title: "content" },
SHARED_L10N.getFormatStr("dimensions", width, height)
)
);
return dom.div(
return (
dom.div(
{
className: "boxmodel-main devtools-monospace",
"data-box": "position",
@ -478,10 +467,7 @@ class BoxModelMain extends PureComponent {
)
:
null,
dom.div(
{
className: "boxmodel-box"
},
dom.div({ className: "boxmodel-box" },
dom.span(
{
className: "boxmodel-legend",
@ -714,6 +700,7 @@ class BoxModelMain extends PureComponent {
onShowBoxModelEditor,
}),
contentBox
)
);
}
}

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

@ -20,9 +20,9 @@ class BoxModelProperties extends PureComponent {
static get propTypes() {
return {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
setSelectedNode: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -73,9 +73,9 @@ class BoxModelProperties extends PureComponent {
render() {
const {
boxModel,
setSelectedNode,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
} = this.props;
const { layout } = boxModel;
@ -88,19 +88,16 @@ class BoxModelProperties extends PureComponent {
return ComputedProperty({
name: info,
key: info,
value: layout[info],
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
referenceElement,
referenceElementType,
setSelectedNode,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
value: layout[info],
});
});
return dom.div(
{
className: "boxmodel-properties",
},
return dom.div({ className: "boxmodel-properties" },
dom.div(
{
className: "boxmodel-properties-header",

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

@ -13,7 +13,7 @@ const {
module.exports = {
/**
* Update the color used for the grid's highlighter.
* Updates the color used for the grid's highlighter.
*
* @param {NodeFront} nodeFront
* The NodeFront of the DOM node to toggle the grid highlighter.
@ -29,7 +29,7 @@ module.exports = {
},
/**
* Update the grid highlighted state.
* Updates the grid highlighted state.
*
* @param {NodeFront} nodeFront
* The NodeFront of the DOM node to toggle the grid highlighter.
@ -45,7 +45,7 @@ module.exports = {
},
/**
* Update the grid state with the new list of grids.
* Updates the grid state with the new list of grids.
*/
updateGrids(grids) {
return {

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

@ -13,7 +13,7 @@ const {
module.exports = {
/**
* Update the grid highlighter's show grid areas preference.
* Updates the grid highlighter's show grid areas preference.
*
* @param {Boolean} enabled
* Whether or not the grid highlighter should show the grid areas.
@ -26,7 +26,7 @@ module.exports = {
},
/**
* Update the grid highlighter's show grid line numbers preference.
* Updates the grid highlighter's show grid line numbers preference.
*
* @param {Boolean} enabled
* Whether or not the grid highlighter should show the grid line numbers.
@ -39,7 +39,7 @@ module.exports = {
},
/**
* Update the grid highlighter's show infinite lines preference.
* Updates the grid highlighter's show infinite lines preference.
*
* @param {Boolean} enabled
* Whether or not the grid highlighter should extend grid lines infinitely.

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

@ -8,22 +8,22 @@ const { createEnum } = require("devtools/client/shared/enum");
createEnum([
// Update the color used for the overlay of a grid.
// Updates the color used for the overlay of a grid.
"UPDATE_GRID_COLOR",
// Update the grid highlighted state.
// Updates the grid highlighted state.
"UPDATE_GRID_HIGHLIGHTED",
// Update the entire grids state with the new list of grids.
// Updates the entire grids state with the new list of grids.
"UPDATE_GRIDS",
// Update the grid highlighter's show grid areas state.
// Updates the grid highlighter's show grid areas state.
"UPDATE_SHOW_GRID_AREAS",
// Update the grid highlighter's show grid line numbers state.
// Updates the grid highlighter's show grid line numbers state.
"UPDATE_SHOW_GRID_LINE_NUMBERS",
// Update the grid highlighter's show infinite lines state.
// Updates the grid highlighter's show infinite lines state.
"UPDATE_SHOW_INFINITE_LINES",
], module.exports);

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

@ -21,7 +21,6 @@ class Grid extends PureComponent {
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
setSelectedNode: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
@ -30,6 +29,7 @@ class Grid extends PureComponent {
onToggleShowGridAreas: PropTypes.func.isRequired,
onToggleShowGridLineNumbers: PropTypes.func.isRequired,
onToggleShowInfiniteLines: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -38,7 +38,6 @@ class Grid extends PureComponent {
getSwatchColorPickerTooltip,
grids,
highlighterSettings,
setSelectedNode,
onHideBoxModelHighlighter,
onSetGridOverlayColor,
onShowBoxModelHighlighterForNode,
@ -47,25 +46,28 @@ class Grid extends PureComponent {
onToggleGridHighlighter,
onToggleShowGridLineNumbers,
onToggleShowInfiniteLines,
setSelectedNode,
} = this.props;
return grids.length ?
dom.div(
{
id: "layout-grid-container",
},
dom.div(
{
className: "grid-content",
},
if (!grids.length) {
return (
dom.div({ className: "devtools-sidepanel-no-result" },
getStr("layout.noGridsOnThisPage")
)
);
}
return (
dom.div({ id: "layout-grid-container" },
dom.div({ className: "grid-content" },
GridList({
getSwatchColorPickerTooltip,
grids,
setSelectedNode,
onHideBoxModelHighlighter,
onSetGridOverlayColor,
onShowBoxModelHighlighterForNode,
onToggleGridHighlighter,
setSelectedNode,
}),
GridDisplaySettings({
highlighterSettings,
@ -79,12 +81,6 @@ class Grid extends PureComponent {
onShowGridOutlineHighlight,
})
)
:
dom.div(
{
className: "devtools-sidepanel-no-result",
},
getStr("layout.noGridsOnThisPage")
);
}
}

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

@ -23,6 +23,7 @@ class GridDisplaySettings extends PureComponent {
constructor(props) {
super(props);
this.onShowGridAreasCheckboxClick = this.onShowGridAreasCheckboxClick.bind(this);
this.onShowGridLineNumbersCheckboxClick =
this.onShowGridLineNumbersCheckboxClick.bind(this);
@ -62,22 +63,12 @@ class GridDisplaySettings extends PureComponent {
highlighterSettings,
} = this.props;
return dom.div(
{
className: "grid-container",
},
dom.span(
{},
getStr("layout.gridDisplaySettings")
),
dom.ul(
{},
dom.li(
{
className: "grid-settings-item",
},
dom.label(
{},
return (
dom.div({ className: "grid-container" },
dom.span({}, getStr("layout.gridDisplaySettings")),
dom.ul({},
dom.li({ className: "grid-settings-item" },
dom.label({},
dom.input(
{
id: "grid-setting-show-grid-line-numbers",
@ -89,12 +80,8 @@ class GridDisplaySettings extends PureComponent {
getStr("layout.displayLineNumbers")
)
),
dom.li(
{
className: "grid-settings-item",
},
dom.label(
{},
dom.li({ className: "grid-settings-item" },
dom.label({},
dom.input(
{
id: "grid-setting-show-grid-areas",
@ -106,12 +93,8 @@ class GridDisplaySettings extends PureComponent {
getStr("layout.displayAreaNames")
)
),
dom.li(
{
className: "grid-settings-item",
},
dom.label(
{},
dom.li({ className: "grid-settings-item" },
dom.label({},
dom.input(
{
id: "grid-setting-extend-grid-lines",
@ -124,6 +107,7 @@ class GridDisplaySettings extends PureComponent {
)
)
)
)
);
}
}

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

@ -22,19 +22,20 @@ class GridItem extends PureComponent {
return {
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grid: PropTypes.shape(Types.grid).isRequired,
setSelectedNode: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.setGridColor = this.setGridColor.bind(this);
this.onGridCheckboxClick = this.onGridCheckboxClick.bind(this);
this.onGridInspectIconClick = this.onGridInspectIconClick.bind(this);
this.setGridColor = this.setGridColor.bind(this);
}
componentDidMount() {
@ -97,10 +98,9 @@ class GridItem extends PureComponent {
} = this.props;
const { nodeFront } = grid;
return dom.li(
{},
dom.label(
{},
return (
dom.li({},
dom.label({},
dom.input(
{
checked: grid.highlighted,
@ -131,13 +131,9 @@ class GridItem extends PureComponent {
),
// The SwatchColorPicker relies on the nextSibling of the swatch element to apply
// the selected color. This is why we use a span in display: none for now.
// Ideally we should modify the SwatchColorPickerTooltip to bypass this requirement.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
dom.span(
{
className: "grid-color-value"
},
grid.color
// Ideally we should modify the SwatchColorPickerTooltip to bypass this
// requirement. See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
dom.span({ className: "grid-color-value" }, grid.color)
)
);
}

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

@ -18,11 +18,11 @@ class GridList extends PureComponent {
return {
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
setSelectedNode: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -30,21 +30,16 @@ class GridList extends PureComponent {
const {
getSwatchColorPickerTooltip,
grids,
setSelectedNode,
onHideBoxModelHighlighter,
onSetGridOverlayColor,
onShowBoxModelHighlighterForNode,
onToggleGridHighlighter,
setSelectedNode,
} = this.props;
return dom.div(
{
className: "grid-container",
},
dom.span(
{},
getStr("layout.overlayGrid")
),
return (
dom.div({ className: "grid-container" },
dom.span({}, getStr("layout.overlayGrid")),
dom.ul(
{
id: "grid-list",
@ -54,13 +49,14 @@ class GridList extends PureComponent {
key: grid.id,
getSwatchColorPickerTooltip,
grid,
setSelectedNode,
onHideBoxModelHighlighter,
onSetGridOverlayColor,
onShowBoxModelHighlighterForNode,
onToggleGridHighlighter,
setSelectedNode,
}))
)
)
);
}
}

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

@ -58,13 +58,13 @@ class GridOutline extends PureComponent {
this.getGridAreaName = this.getGridAreaName.bind(this);
this.getHeight = this.getHeight.bind(this);
this.getTotalWidthAndHeight = this.getTotalWidthAndHeight.bind(this);
this.onHighlightCell = this.onHighlightCell.bind(this);
this.renderCannotShowOutlineText = this.renderCannotShowOutlineText.bind(this);
this.renderGrid = this.renderGrid.bind(this);
this.renderGridCell = this.renderGridCell.bind(this);
this.renderGridOutline = this.renderGridOutline.bind(this);
this.renderGridOutlineBorder = this.renderGridOutlineBorder.bind(this);
this.renderOutline = this.renderOutline.bind(this);
this.onHighlightCell = this.onHighlightCell.bind(this);
}
componentWillReceiveProps({ grids }) {

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

@ -56,8 +56,6 @@ class GridInspector {
this.telemetry = inspector.telemetry;
this.walker = this.inspector.walker;
this.updateGridPanel = this.updateGridPanel.bind(this);
this.onHighlighterShown = this.onHighlighterShown.bind(this);
this.onHighlighterHidden = this.onHighlighterHidden.bind(this);
this.onNavigate = this.onNavigate.bind(this);
@ -69,6 +67,7 @@ class GridInspector {
this.onToggleShowGridAreas = this.onToggleShowGridAreas.bind(this);
this.onToggleShowGridLineNumbers = this.onToggleShowGridLineNumbers.bind(this);
this.onToggleShowInfiniteLines = this.onToggleShowInfiniteLines.bind(this);
this.updateGridPanel = this.updateGridPanel.bind(this);
this.init();
}

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

@ -27,7 +27,6 @@ const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
const FLEXBOX_ENABLED_PREF = "devtools.flexboxinspector.enabled";
const BOXMODEL_OPENED_PREF = "devtools.layout.boxmodel.opened";
const FLEXBOX_OPENED_PREF = "devtools.layout.flexbox.opened";
const GRID_OPENED_PREF = "devtools.layout.grid.opened";
@ -39,8 +38,6 @@ class LayoutApp extends PureComponent {
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(GridTypes.grid)).isRequired,
highlighterSettings: PropTypes.shape(GridTypes.highlighterSettings).isRequired,
setSelectedNode: PropTypes.func.isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetFlexboxOverlayColor: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
@ -50,6 +47,8 @@ class LayoutApp extends PureComponent {
onToggleGridHighlighter: PropTypes.func.isRequired,
onToggleShowGridLineNumbers: PropTypes.func.isRequired,
onToggleShowInfiniteLines: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
};
}
@ -93,9 +92,10 @@ class LayoutApp extends PureComponent {
];
}
return dom.div(
{ id: "layout-container" },
return (
dom.div({ id: "layout-container" },
Accordion({ items })
)
);
}
}

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

@ -34,8 +34,8 @@ class LayoutView {
}
const {
setSelectedNode,
onShowBoxModelHighlighterForNode,
setSelectedNode,
} = this.inspector.getCommonComponentProps();
const {
@ -63,12 +63,6 @@ class LayoutView {
const layoutApp = LayoutApp({
getSwatchColorPickerTooltip: this.getSwatchColorPickerTooltip,
setSelectedNode,
/**
* Shows the box model properties under the box model if true, otherwise, hidden by
* default.
*/
showBoxModelProperties: true,
onHideBoxModelHighlighter,
onSetFlexboxOverlayColor,
onSetGridOverlayColor,
@ -82,6 +76,12 @@ class LayoutView {
onToggleShowGridAreas,
onToggleShowGridLineNumbers,
onToggleShowInfiniteLines,
setSelectedNode,
/**
* Shows the box model properties under the box model if true, otherwise, hidden by
* default.
*/
showBoxModelProperties: true,
});
const provider = createElement(Provider, {

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

@ -17,6 +17,7 @@ const Viewports = createFactory(require("./Viewports"));
loader.lazyGetter(this, "DeviceModal",
() => createFactory(require("./DeviceModal")));
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
const {
addCustomDevice,
removeCustomDevice,
@ -24,7 +25,6 @@ const {
updateDeviceModal,
updatePreferredDevices,
} = require("../actions/devices");
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
const { changeReloadCondition } = require("../actions/reload-conditions");
const { takeScreenshot } = require("../actions/screenshot");
const { changeTouchSimulation } = require("../actions/touch-simulation");
@ -222,10 +222,8 @@ class App extends Component {
deviceAdderViewportTemplate = viewports[devices.modalOpenedFromViewport];
}
return dom.div(
{
id: "app",
},
return (
dom.div({ id: "app" },
Toolbar({
devices,
displayPixelRatio,
@ -269,6 +267,7 @@ class App extends Component {
})
:
null
)
);
}
}

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

@ -26,10 +26,10 @@ class Browser extends PureComponent {
*/
static get propTypes() {
return {
swapAfterMount: PropTypes.bool.isRequired,
userContextId: PropTypes.number.isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
swapAfterMount: PropTypes.bool.isRequired,
userContextId: PropTypes.number.isRequired,
};
}
@ -149,7 +149,8 @@ class Browser extends PureComponent {
// @noisolation and @allowfullscreen are needed so that these frames have the same
// access to browser features as regular browser tabs. The `swapFrameLoaders` platform
// API we use compares such features before allowing the swap to proceed.
return dom.iframe(
return (
dom.iframe(
{
allowFullScreen: "true",
className: "browser",
@ -165,6 +166,7 @@ class Browser extends PureComponent {
this.browser = browser;
},
}
)
);
}
}

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

@ -10,7 +10,7 @@ const { createFactory, PureComponent } = require("devtools/client/shared/vendor/
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ViewportDimension = createFactory(require("./ViewportDimension.js"));
const ViewportDimension = createFactory(require("./ViewportDimension"));
const { getFormatStr, getStr } = require("../utils/l10n");
const Types = require("../types");
@ -19,8 +19,8 @@ class DeviceAdder extends PureComponent {
static get propTypes() {
return {
devices: PropTypes.shape(Types.devices).isRequired,
viewportTemplate: PropTypes.shape(Types.viewport).isRequired,
onAddCustomDevice: PropTypes.func.isRequired,
viewportTemplate: PropTypes.shape(Types.viewport).isRequired,
};
}
@ -136,26 +136,12 @@ class DeviceAdder extends PureComponent {
});
}
return dom.div(
{
id: "device-adder"
},
dom.div(
{
id: "device-adder-content",
},
dom.div(
{
id: "device-adder-column-1",
},
dom.label(
{
id: "device-adder-name",
},
dom.span(
{
className: "device-adder-label",
},
return (
dom.div({ id: "device-adder" },
dom.div({ id: "device-adder-content" },
dom.div({ id: "device-adder-column-1" },
dom.label({ id: "device-adder-name" },
dom.span({ className: "device-adder-label" },
getStr("responsive.deviceAdderName")
),
dom.input({
@ -165,14 +151,8 @@ class DeviceAdder extends PureComponent {
},
})
),
dom.label(
{
id: "device-adder-size",
},
dom.span(
{
className: "device-adder-label"
},
dom.label({ id: "device-adder-size" },
dom.span({ className: "device-adder-label" },
getStr("responsive.deviceAdderSize")
),
ViewportDimension({
@ -184,14 +164,8 @@ class DeviceAdder extends PureComponent {
onRemoveDeviceAssociation: () => {},
})
),
dom.label(
{
id: "device-adder-pixel-ratio",
},
dom.span(
{
className: "device-adder-label"
},
dom.label({ id: "device-adder-pixel-ratio" },
dom.span({ className: "device-adder-label" },
getStr("responsive.deviceAdderPixelRatio")
),
dom.input({
@ -204,18 +178,9 @@ class DeviceAdder extends PureComponent {
})
)
),
dom.div(
{
id: "device-adder-column-2",
},
dom.label(
{
id: "device-adder-user-agent",
},
dom.span(
{
className: "device-adder-label"
},
dom.div({ id: "device-adder-column-2" },
dom.label({ id: "device-adder-user-agent" },
dom.span({ className: "device-adder-label" },
getStr("responsive.deviceAdderUserAgent")
),
dom.input({
@ -225,14 +190,8 @@ class DeviceAdder extends PureComponent {
},
})
),
dom.label(
{
id: "device-adder-touch",
},
dom.span(
{
className: "device-adder-label"
},
dom.label({ id: "device-adder-touch" },
dom.span({ className: "device-adder-label" },
getStr("responsive.deviceAdderTouch")
),
dom.input({
@ -252,6 +211,7 @@ class DeviceAdder extends PureComponent {
},
getStr("responsive.deviceAdderSave")
)
)
);
}
}

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

@ -133,34 +133,26 @@ class DeviceModal extends PureComponent {
.sort((a, b) => a.name.localeCompare(b.name));
}
return dom.div(
return (
dom.div(
{
id: "device-modal-wrapper",
className: this.props.devices.isModalOpen ? "opened" : "closed",
},
dom.div(
{
className: "device-modal",
},
dom.div({ className: "device-modal" },
dom.button({
id: "device-close-button",
className: "devtools-button",
onClick: () => onUpdateDeviceModal(false),
}),
dom.div(
{
className: "device-modal-content",
},
dom.div({ className: "device-modal-content" },
devices.types.map(type => {
return dom.div(
{
className: `device-type device-type-${type}`,
key: type,
},
dom.header(
{
className: "device-header",
},
dom.header({ className: "device-header" },
type
),
sortedDevices[type].map(device => {
@ -221,6 +213,7 @@ class DeviceModal extends PureComponent {
onClick: () => onUpdateDeviceModal(false),
}
)
)
);
}
}

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

@ -22,9 +22,9 @@ class DevicePixelRatioMenu extends PureComponent {
return {
devices: PropTypes.shape(Types.devices).isRequired,
displayPixelRatio: Types.pixelRatio.value.isRequired,
onChangePixelRatio: PropTypes.func.isRequired,
selectedDevice: PropTypes.string.isRequired,
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
onChangePixelRatio: PropTypes.func.isRequired,
};
}

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

@ -17,11 +17,11 @@ class DeviceSelector extends PureComponent {
static get propTypes() {
return {
devices: PropTypes.shape(Types.devices).isRequired,
selectedDevice: PropTypes.string.isRequired,
viewportId: PropTypes.number.isRequired,
onChangeDevice: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onUpdateDeviceModal: PropTypes.func.isRequired,
selectedDevice: PropTypes.string.isRequired,
viewportId: PropTypes.number.isRequired,
};
}
@ -33,11 +33,11 @@ class DeviceSelector extends PureComponent {
onShowDeviceMenu(event) {
const {
devices,
selectedDevice,
viewportId,
onChangeDevice,
onResizeViewport,
onUpdateDeviceModal,
selectedDevice,
viewportId,
} = this.props;
const menuItems = [];

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

@ -22,13 +22,13 @@ class ResizableViewport extends Component {
static get propTypes() {
return {
leftAlignmentEnabled: PropTypes.bool.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
swapAfterMount: PropTypes.bool.isRequired,
viewport: PropTypes.shape(Types.viewport).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
onRemoveDeviceAssociation: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
swapAfterMount: PropTypes.bool.isRequired,
viewport: PropTypes.shape(Types.viewport).isRequired,
};
}

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

@ -18,9 +18,9 @@ class SettingsMenu extends PureComponent {
static get propTypes() {
return {
leftAlignmentEnabled: PropTypes.bool.isRequired,
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
onChangeReloadCondition: PropTypes.func.isRequired,
onToggleLeftAlignment: PropTypes.func.isRequired,
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
};
}
@ -32,9 +32,9 @@ class SettingsMenu extends PureComponent {
onToggleSettingMenu(event) {
const {
leftAlignmentEnabled,
reloadConditions,
onChangeReloadCondition,
onToggleLeftAlignment,
reloadConditions,
} = this.props;
const menuItems = [

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

@ -15,9 +15,9 @@ const Types = require("../types");
class ViewportDimension extends Component {
static get propTypes() {
return {
viewport: PropTypes.shape(Types.viewport).isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRemoveDeviceAssociation: PropTypes.func.isRequired,
viewport: PropTypes.shape(Types.viewport).isRequired,
};
}

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

@ -17,24 +17,24 @@ class Viewports extends Component {
static get propTypes() {
return {
leftAlignmentEnabled: PropTypes.bool.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
onRemoveDeviceAssociation: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
};
}
render() {
const {
leftAlignmentEnabled,
screenshot,
viewports,
onBrowserMounted,
onContentResize,
onRemoveDeviceAssociation,
onResizeViewport,
screenshot,
viewports,
} = this.props;
const viewportSize = window.getViewportSize();
@ -68,13 +68,13 @@ class Viewports extends Component {
return ResizableViewport({
key: viewport.id,
leftAlignmentEnabled,
screenshot,
swapAfterMount: i == 0,
viewport,
onBrowserMounted,
onContentResize,
onRemoveDeviceAssociation,
onResizeViewport,
screenshot,
swapAfterMount: i == 0,
viewport,
});
})
)

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

@ -42,6 +42,7 @@ var dragLinkText = [[
function dumpTransfer(dataTransfer,expect) {
dataTransfer = SpecialPowers.wrap(dataTransfer);
dtData = dataTransfer.mozItemCount + "items:\n";
for (var i = 0; i < dataTransfer.mozItemCount; i++) {
var dtTypes = dataTransfer.mozTypesAt(i);

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

@ -40,6 +40,8 @@
#include "mozilla/dom/Promise.h"
#include "nsNetUtil.h"
#define MOZ_CALLS_ENABLED_PREF "dom.datatransfer.mozAtAPIs"
namespace mozilla {
namespace dom {
@ -1523,5 +1525,22 @@ DataTransfer::SetMode(DataTransfer::Mode aMode)
}
}
/* static */
bool
DataTransfer::MozAtAPIsEnabled(JSContext* aCx, JSObject* aObj /*unused*/)
{
// Read the pref
static bool sPrefCached = false;
static bool sPrefCacheValue = false;
if (!sPrefCached) {
sPrefCached = true;
Preferences::AddBoolVarCache(&sPrefCacheValue, MOZ_CALLS_ENABLED_PREF);
}
// We can expose moz* APIs if we are chrome code or if pref is enabled
return nsContentUtils::IsSystemCaller(aCx) || sPrefCacheValue;
}
} // namespace dom
} // namespace mozilla

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

@ -428,6 +428,11 @@ public:
const bool& aPlainTextOnly,
nsTArray<nsCString>* aResult);
// Returns true if moz* APIs should be exposed (true for chrome code or if
// dom.datatransfer.moz pref is enabled).
// The affected moz* APIs are mozItemCount, mozTypesAt, mozClearDataAt, mozSetDataAt, mozGetDataAt
static bool MozAtAPIsEnabled(JSContext* cx, JSObject* obj);
protected:
// caches text and uri-list data formats that exist in the drag service or

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

@ -1,6 +1,6 @@
<html>
<head>
<title>Tests for the DatTransferItemList object</title>
<title>Tests for the DataTransferItemList object</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/AddTask.js"></script>
@ -10,7 +10,7 @@
<body style="height: 300px; overflow: auto;">
<p id="display"> </p>
<img id="image" draggable="true" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82">
<div id="over" "style="width: 100px; height: 100px; border: 2px black dashed;">
<div id="over" style="width: 100px; height: 100px; border: 2px black dashed;">
drag over here
</div>

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

@ -30,7 +30,7 @@ function runTests()
ok(true, "Got dragstart event");
dataTransfer = event.dataTransfer;
ok(dataTransfer, "DataTransfer object is available.");
is(dataTransfer.mozItemCount, 1, "initial link item count");
is(SpecialPowers.wrap(dataTransfer).mozItemCount, 1, "initial link item count");
is(dataTransfer.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list");
is(dataTransfer.getData("text/plain"), "http://www.mozilla.org/", "link text/plain");
}

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

@ -41,10 +41,6 @@ function afterDragTests()
"NoModificationAllowedError", "setData when read only");
expectError(() => gDataTransfer.clearData("text/plain"),
"NoModificationAllowedError", "clearData when read only");
expectError(() => gDataTransfer.mozSetDataAt("text/plain", "Some Text", 0),
"NoModificationAllowedError", "setDataAt when read only");
expectError(() => gDataTransfer.mozClearDataAt("text/plain", 0),
"NoModificationAllowedError", "clearDataAt when read only");
expectError(() => gDataTransfer.addElement(draggable),
"NoModificationAllowedError", "addElement when read only");
@ -130,7 +126,7 @@ function doDragStartSelection(event)
is(dt.getData("TEXT"), "This is a draggable bit of text.", "initial selection TEXT");
is(dt.getData("text/UNICODE"), "This is a draggable bit of text.", "initial selection text/UNICODE");
is(dt.mozItemCount, 1, "initial selection item count");
is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial selection item count");
dt.clearData("text/plain");
dt.clearData("text/html");
@ -143,10 +139,14 @@ function doDragStartSelection(event)
function test_DataTransfer(dt)
{
is(dt.mozItemCount, 0, "empty itemCount");
is(SpecialPowers.wrap(dt).mozItemCount, 0, "empty itemCount");
var types = dt.types;
ok(Array.isArray(types), "empty types is an Array");
// The above test fails if we have SpecialPowers.wrap(dt).types instead of dt.types
// because chrome consumers get the 'ReturnValueNeedsContainsHack'.
// So wrap with special powers after the test
dt = SpecialPowers.wrap(dt);
checkTypes(dt, [], 0, "empty");
is(dt.getData("text/plain"), "", "empty data is empty");
@ -316,11 +316,9 @@ function test_DataTransfer(dt)
checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2");
// Try to add and then remove a non-string type to the DataTransfer and ensure
// that the type appears in DataTransfer.types. These calls need to be called
// with SpecialPowers.wrap(), as adding and removing non-string/file types to
// DataTransfer is chrome-only.
// that the type appears in DataTransfer.types.
{
SpecialPowers.wrap(dt).mozSetDataAt("application/-x-body", document.body, 0);
dt.mozSetDataAt("application/-x-body", document.body, 0);
let found = false;
for (let i = 0; i < dt.types.length; ++i) {
if (dt.types[i] == "application/-x-body") {
@ -329,7 +327,7 @@ function test_DataTransfer(dt)
}
}
ok(found, "Data should appear in datatransfer.types despite having a non-string type");
SpecialPowers.wrap(dt).mozClearDataAt("application/-x-body", 0);
dt.mozClearDataAt("application/-x-body", 0);
}
dt.mozClearDataAt("text/html", 1);
@ -419,7 +417,7 @@ function doDragStartLink(event)
checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
"text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial link");
is(dt.mozItemCount, 1, "initial link item count");
is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial link item count");
is(dt.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list");
is(dt.getData("text/plain"), "http://www.mozilla.org/", "link text/plain");
@ -436,7 +434,7 @@ function doDragStartImage(event)
checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
"text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial image");
is(dt.mozItemCount, 1, "initial image item count");
is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial image item count");
is(dt.getData("text/uri-list"), dataurl, "image text/uri-list");
is(dt.getData("text/plain"), dataurl, "image text/plain");
@ -450,7 +448,7 @@ function doDragStartInput(event)
var dt = event.dataTransfer;
checkTypes(dt, ["text/plain"], 0, "initial input");
is(dt.mozItemCount, 1, "initial input item count");
is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial input item count");
// is(dt.getData("text/plain"), "Text", "input text/plain");
// event.preventDefault();
@ -511,11 +509,12 @@ function doDragOverSynthetic(event)
function onDragStartDraggable(event)
{
var dt = event.dataTransfer;
ok(dt.mozItemCount == 0 && dt.types.length == 0 && event.originalTarget == gDragInfo.target, gDragInfo.testid);
ok(SpecialPowers.wrap(dt).mozItemCount == 0 && dt.types.length == 0 && event.originalTarget == gDragInfo.target, gDragInfo.testid);
gExtraDragTests++;
}
// Expects dt wrapped in SpecialPowers
function checkOneDataItem(dt, expectedtypes, expecteddata, index, testid)
{
checkTypes(dt, expectedtypes, index, testid);
@ -537,13 +536,14 @@ function checkTypes(dt, expectedtypes, index, testid)
}
}
types = dt.mozTypesAt(index);
types = SpecialPowers.wrap(dt).mozTypesAt(index);
is(types.length, expectedtypes.length, testid + " typesAt length");
for (var f = 0; f < expectedtypes.length; f++) {
is(types[f], expectedtypes[f], testid + " " + types[f] + " at " + index + " check");
}
}
// Expects dt wrapped in SpecialPowers
function checkURL(dt, url, fullurllist, index, testid)
{
is(dt.getData("text/uri-list"), fullurllist, testid + " text/uri-list");

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

@ -47,6 +47,7 @@ VideoSink::VideoSink(AbstractThread* aThread,
, mContainer(aContainer)
, mProducerID(ImageContainer::AllocateProducerID())
, mFrameStats(aFrameStats)
, mOldDroppedCount(0)
, mHasVideo(false)
, mUpdateScheduler(aThread)
, mVideoQueueSendToCompositorSize(aVQueueSentToCompositerSize)
@ -464,6 +465,13 @@ VideoSink::RenderVideoFrames(int32_t aMaxFrames,
if (images.Length() > 0) {
mContainer->SetCurrentFrames(frames[0]->mDisplay, images);
uint32_t droppedCount = mContainer->GetDroppedImageCount();
uint32_t dropped = droppedCount - mOldDroppedCount;
if (dropped > 0) {
mFrameStats.NotifyDecodedFrames({0, 0, dropped});
mOldDroppedCount = droppedCount;
VSINK_LOG_V("%u video frame discarded by compositor", dropped);
}
}
}

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

@ -108,7 +108,8 @@ private:
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
}
MediaQueue<VideoData>& VideoQueue() const {
MediaQueue<VideoData>& VideoQueue() const
{
return mVideoQueue;
}
@ -131,6 +132,8 @@ private:
// The presentation end time of the last video frame which has been displayed.
TimeUnit mVideoFrameEndTime;
uint32_t mOldDroppedCount;
// Event listeners for VideoQueue
MediaEventListener mPushListener;
MediaEventListener mFinishListener;

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

@ -13,7 +13,7 @@
var statsExpectedByType = {
"inbound-rtp": {
expected: ["id", "timestamp", "type", "ssrc", "isRemote", "mediaType",
"packetsReceived", "packetsLost", "bytesReceived", "jitter",],
"kind", "packetsReceived", "packetsLost", "bytesReceived", "jitter",],
optional: ["roundTripTime", "remoteId", "nackCount",],
localVideoOnly: ["discardedPackets", "framerateStdDev", "framerateMean",
"bitrateMean", "bitrateStdDev", "firCount", "pliCount", "framesDecoded",],
@ -26,7 +26,7 @@ var statsExpectedByType = {
},
"outbound-rtp": {
expected: ["id", "timestamp", "type", "ssrc", "isRemote", "mediaType",
"packetsSent", "bytesSent", "remoteId",],
"kind", "packetsSent", "bytesSent", "remoteId",],
optional: ["remoteId", "nackCount",],
localVideoOnly: ["droppedFrames", "bitrateMean", "bitrateStdDev",
"framerateMean", "framerateStdDev", "framesEncoded", "firCount",
@ -148,10 +148,16 @@ var pedanticChecks = report => {
// isRemote
ok(stat.isRemote !== undefined, stat.type + ".isRemote exists.");
// mediaType
// kind
ok(["audio", "video"].includes(stat.kind),
stat.type + ".kind is 'audio' or 'video'");
// mediaType, renamed to kind but remains for backward compability.
ok(["audio", "video"].includes(stat.mediaType),
stat.type + ".mediaType is 'audio' or 'video'");
ok(stat.kind == stat.mediaType, "kind equals legacy mediaType");
// remote id
if (stat.remoteId) {
ok(report.has(stat.remoteId), "remoteId exists in report.");
@ -169,7 +175,7 @@ var pedanticChecks = report => {
+ ".nackCount is only set when isRemote is false");
}
if (!stat.inner.isRemote && stat.inner.mediaType == "video") {
if (!stat.inner.isRemote && stat.inner.kind == "video") {
// firCount
ok(stat.firCount >= 0 && stat.firCount < 100,
stat.type + ".firCount is a sane number for a short test. value="
@ -205,7 +211,7 @@ var pedanticChecks = report => {
+ stat.packetsLost);
// This should be much lower for audio, TODO: Bug 1330575
let expectedJitter = stat.mediaType == "video" ? 0.5 : 1;
let expectedJitter = stat.kind == "video" ? 0.5 : 1;
// jitter
ok(stat.jitter < expectedJitter,
stat.type + ".jitter is sane number for a local only test. value="
@ -240,20 +246,20 @@ var pedanticChecks = report => {
//
// Local video only stats
//
if (stat.inner.isRemote || stat.inner.mediaType != "video") {
if (stat.inner.isRemote || stat.inner.kind != "video") {
expectations.localVideoOnly.forEach(field => {
if (stat.inner.isRemote) {
ok(stat[field] === undefined, stat.type + " does not have field "
+ field + " when isRemote is true");
} else { // mediaType != video
} else { // kind != video
ok(stat[field] === undefined, stat.type + " does not have field "
+ field + " when mediaType is not 'video'");
+ field + " when kind is not 'video'");
}
});
} else {
expectations.localVideoOnly.forEach(field => {
ok(stat.inner[field] !== undefined, stat.type + " has field " + field
+ " when mediaType is video");
+ " when kind is video");
});
// discardedPackets
ok(stat.discardedPackets < 100, stat.type
@ -321,20 +327,20 @@ var pedanticChecks = report => {
//
// Local video only stats
//
if (stat.inner.isRemote || stat.inner.mediaType != "video") {
if (stat.inner.isRemote || stat.inner.kind != "video") {
expectations.localVideoOnly.forEach(field => {
if (stat.inner.isRemote) {
ok(stat[field] === undefined, stat.type + " does not have field "
+ field + " when isRemote is true");
} else { // mediaType != video
} else { // kind != video
ok(stat[field] === undefined, stat.type + " does not have field "
+ field + " when mediaType is not 'video'");
+ field + " when kind is not 'video'");
}
});
} else {
expectations.localVideoOnly.forEach(field => {
ok(stat.inner[field] !== undefined, stat.type + " has field " + field
+ " when mediaType is video and isRemote is false");
+ " when kind is video and isRemote is false");
});
// bitrateMean

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

@ -292,6 +292,7 @@ static void WriteRTCRtpStreamStats(
WriteParam(aMsg, aParam.mIsRemote);
WriteParam(aMsg, aParam.mMediaTrackId);
WriteParam(aMsg, aParam.mMediaType);
WriteParam(aMsg, aParam.mKind);
WriteParam(aMsg, aParam.mRemoteId);
WriteParam(aMsg, aParam.mSsrc);
WriteParam(aMsg, aParam.mTransportId);
@ -309,6 +310,7 @@ static bool ReadRTCRtpStreamStats(
!ReadParam(aMsg, aIter, &(aResult->mIsRemote)) ||
!ReadParam(aMsg, aIter, &(aResult->mMediaTrackId)) ||
!ReadParam(aMsg, aIter, &(aResult->mMediaType)) ||
!ReadParam(aMsg, aIter, &(aResult->mKind)) ||
!ReadParam(aMsg, aIter, &(aResult->mRemoteId)) ||
!ReadParam(aMsg, aIter, &(aResult->mSsrc)) ||
!ReadParam(aMsg, aIter, &(aResult->mTransportId))) {

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

@ -88,6 +88,3 @@ if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
# 'reinterpret_cast': conversion from 'DWORD' to 'HANDLE' of greater size
]
DEFINES['__PRETTY_FUNCTION__'] = '__FUNCSIG__'
if CONFIG['MOZ_ASAN'] and CONFIG['CC_TYPE'] == 'clang-cl':
AllowCompilerWarnings() # workaround for bug 1306642

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

@ -1941,7 +1941,7 @@ ServiceWorkerPrivate::TerminateWorker()
}
Unused << NS_WARN_IF(!mWorkerPrivate->Cancel());
mWorkerPrivate = nullptr;
RefPtr<WorkerPrivate> workerPrivate(mWorkerPrivate.forget());
mSupportsArray.Clear();
// Any pending events are never going to fire on this worker. Cancel

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

@ -90,6 +90,7 @@ subsuite = clipboard
[test_consoleAPI.html]
[test_contentViewer_overrideDPPX.html]
[test_CCW_optimization.html]
[test_datatransfer_disallowed.html]
[test_devicePixelRatio_with_zoom.html]
[test_DOMMatrix.html]
[test_domWindowUtils.html]

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

@ -24,15 +24,7 @@ function checkAllowed(event)
let exception;
try {
clipboardData.mozSetDataAt("text/customdata", document.getElementById("input"), 0);
} catch(ex) {
exception = ex;
}
is(String(exception).indexOf("SecurityError"), 0, "Cannot set non-string");
exception = null;
try {
clipboardData.mozSetDataAt("application/x-moz-file", "Test", 0);
clipboardData.setData("application/x-moz-file", "Test");
} catch(ex) {
exception = ex;
}
@ -40,7 +32,7 @@ function checkAllowed(event)
exception = null;
try {
clipboardData.mozSetDataAt("application/x-moz-file-promise", "Test", 0);
clipboardData.setData("application/x-moz-file-promise", "Test");
} catch(ex) {
exception = ex;
}
@ -48,7 +40,7 @@ function checkAllowed(event)
exception = null;
try {
clipboardData.mozSetDataAt("application/something", "This is data", 0);
clipboardData.setData("application/something", "This is data");
} catch(ex) {
exception = ex;
}

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

@ -302,7 +302,7 @@ add_task(async function test_input_cut_dataTransfer() {
ok(event instanceof ClipboardEvent, "cut event is a ClipboardEvent");
ok(event.clipboardData instanceof DataTransfer, "cut event dataTransfer is a DataTransfer");
is(event.target, contentInput, "cut event target");
is(event.clipboardData.mozItemCount, 0, "cut event mozItemCount");
is(SpecialPowers.wrap(event.clipboardData).mozItemCount, 0, "cut event mozItemCount");
is(event.clipboardData.getData("text/plain"), "", "cut event getData");
event.clipboardData.setData("text/plain", "This is some dataTransfer text");
cachedCutData = event.clipboardData;
@ -349,7 +349,7 @@ add_task(async function test_input_copy_dataTransfer() {
ok(event instanceof ClipboardEvent, "copy event is a ClipboardEvent");
ok(event.clipboardData instanceof DataTransfer, "copy event dataTransfer is a DataTransfer");
is(event.target, contentInput, "copy event target");
is(event.clipboardData.mozItemCount, 0, "copy event mozItemCount");
is(SpecialPowers.wrap(event.clipboardData).mozItemCount, 0, "copy event mozItemCount");
is(event.clipboardData.getData("text/plain"), "", "copy event getData");
event.clipboardData.setData("text/plain", "Copied dataTransfer text");
cachedCopyData = event.clipboardData;
@ -394,7 +394,7 @@ add_task(async function test_input_paste_dataTransfer() {
ok(event instanceof ClipboardEvent, "paste event is an ClipboardEvent");
ok(event.clipboardData instanceof DataTransfer, "paste event dataTransfer is a DataTransfer");
is(event.target, contentInput, "paste event target");
is(event.clipboardData.mozItemCount, 1, "paste event mozItemCount");
is(SpecialPowers.wrap(event.clipboardData).mozItemCount, 1, "paste event mozItemCount");
is(event.clipboardData.getData("text/plain"), clipboardInitialValue, "paste event getData");
cachedPasteData = event.clipboardData;
};
@ -440,21 +440,21 @@ add_task(async function test_input_copypaste_dataTransfer_multiple() {
cd.setData("text/plain", "would be a phrase");
var exh = false;
try { cd.mozSetDataAt("text/plain", "Text", 1); } catch (ex) { exh = true; }
try { SpecialPowers.wrap(cd).mozSetDataAt("text/plain", "Text", 1); } catch (ex) { exh = true; }
ok(exh, "exception occured mozSetDataAt 1");
exh = false;
try { cd.mozTypesAt(1); } catch (ex) { exh = true; }
try { SpecialPowers.wrap(cd).mozTypesAt(1); } catch (ex) { exh = true; }
ok(exh, "exception occured mozTypesAt 1");
exh = false;
try { cd.mozGetDataAt("text/plain", 1); } catch (ex) { exh = true; }
try { SpecialPowers.wrap(cd).mozGetDataAt("text/plain", 1); } catch (ex) { exh = true; }
ok(exh, "exception occured mozGetDataAt 1");
exh = false;
try { cd.mozClearDataAt("text/plain", 1); } catch (ex) { exh = true; }
ok(exh, "exception occured mozClearDataAt 1");
cd.setData("text/x-moz-url", "http://www.mozilla.org");
cd.mozSetDataAt("text/x-custom", "Custom Text with \u0000 null", 0);
is(cd.mozItemCount, 1, "mozItemCount after set multiple types");
SpecialPowers.wrap(cd).mozSetDataAt("text/x-custom", "Custom Text with \u0000 null", 0);
is(SpecialPowers.wrap(cd).mozItemCount, 1, "mozItemCount after set multiple types");
return false;
};
@ -473,7 +473,7 @@ add_task(async function test_input_copypaste_dataTransfer_multiple() {
contentInput.onpaste = function(event) {
var cd = event.clipboardData;
is(cd.mozItemCount, 1, "paste after copy multiple types mozItemCount");
is(SpecialPowers.wrap(cd).mozItemCount, 1, "paste after copy multiple types mozItemCount");
is(cd.getData("text/plain"), "would be a phrase", "paste text/plain multiple types");
// Firefox for Android's clipboard code doesn't handle x-moz-url. Therefore
@ -640,10 +640,10 @@ function compareSynthetic(event, eventtype) {
is(event.type, expectedData.type, "synthetic " + eventtype + " event type");
if (expectedData.data === null) {
is(event.clipboardData.mozItemCount, 0, "synthetic " + eventtype + " empty data");
is(SpecialPowers.wrap(event.clipboardData).mozItemCount, 0, "synthetic " + eventtype + " empty data");
}
else {
is(event.clipboardData.mozItemCount, 1, "synthetic " + eventtype + " item count");
is(SpecialPowers.wrap(event.clipboardData).mozItemCount, 1, "synthetic " + eventtype + " item count");
is(event.clipboardData.types.length, 1, "synthetic " + eventtype + " types length");
is(event.clipboardData.getData(expectedData.dataType), expectedData.data,
"synthetic " + eventtype + " data");
@ -666,7 +666,7 @@ async function checkCachedDataTransfer(cd, eventtype) {
ok(!oldtext, "clipboard get using " + testprefix);
try {
cd.mozSetDataAt("text/plain", "Test Cache Data", 0);
SpecialPowers.wrap(cd).mozSetDataAt("text/plain", "Test Cache Data", 0);
} catch (ex) {}
ok(!cd.getData("text/plain"), "clipboard set using " + testprefix);

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

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for DataTransfer moz* APIs</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script>
function run_test()
{
SpecialPowers.pushPrefEnv({"set": [
["dom.datatransfer.moz", false],
]}, function() {
let hiddenMethods = ["mozTypesAt", "mozClearDataAt", "mozGetDataAt", "mozSetDataAt", "mozItemCount"];
let exposedMethods = Object.getOwnPropertyNames(DataTransfer.prototype);
for (var idx in hiddenMethods) {
if (exposedMethods.includes(hiddenMethods[idx])) {
ok(false, hiddenMethods[idx] + " should not be exposed");
} else {
ok(true, hiddenMethods[idx] + " was not exposed");
}
}
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(run_test);
</script>

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

@ -54,7 +54,7 @@ partial interface DataTransfer {
/**
* The number of items being dragged.
*/
[UseCounter]
[Func="DataTransfer::MozAtAPIsEnabled"]
readonly attribute unsigned long mozItemCount;
/**
@ -77,7 +77,7 @@ partial interface DataTransfer {
* at the specified index. If the index is not in the range from 0 to
* itemCount - 1, an empty string list is returned.
*/
[Throws, NeedsCallerType, UseCounter]
[Throws, NeedsCallerType, Func="DataTransfer::MozAtAPIsEnabled"]
DOMStringList mozTypesAt(unsigned long index);
/**
@ -94,7 +94,7 @@ partial interface DataTransfer {
* @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
* @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
*/
[Throws, NeedsSubjectPrincipal, UseCounter]
[Throws, NeedsSubjectPrincipal, Func="DataTransfer::MozAtAPIsEnabled"]
void mozClearDataAt(DOMString format, unsigned long index);
/*
@ -118,7 +118,7 @@ partial interface DataTransfer {
* @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater than itemCount
* @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified
*/
[Throws, NeedsSubjectPrincipal, UseCounter]
[Throws, NeedsSubjectPrincipal, Func="DataTransfer::MozAtAPIsEnabled"]
void mozSetDataAt(DOMString format, any data, unsigned long index);
/**
@ -130,7 +130,7 @@ partial interface DataTransfer {
* @returns the data of the given format, or null if it doesn't exist.
* @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount
*/
[Throws, NeedsSubjectPrincipal, UseCounter]
[Throws, NeedsSubjectPrincipal, Func="DataTransfer::MozAtAPIsEnabled"]
any mozGetDataAt(DOMString format, unsigned long index);
/**

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

@ -29,6 +29,7 @@ dictionary RTCStats {
dictionary RTCRtpStreamStats : RTCStats {
unsigned long ssrc;
DOMString mediaType;
DOMString kind;
DOMString remoteId;
boolean isRemote = false;
DOMString mediaTrackId;

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

@ -121,6 +121,15 @@ ImageContainerListener::NotifyComposite(const ImageCompositeNotification& aNotif
}
}
void
ImageContainerListener::NotifyDropped(uint32_t aDropped)
{
MutexAutoLock lock(mLock);
if (mImageContainer) {
mImageContainer->NotifyDropped(aDropped);
}
}
void
ImageContainerListener::ClearImageContainer()
{
@ -258,29 +267,7 @@ ImageContainer::SetCurrentImageInternal(const nsTArray<NonOwningImage>& aImages)
mCurrentImages[0].mFrameID <= aImages[0].mFrameID,
"frame IDs shouldn't go backwards");
if (aImages[0].mProducerID != mCurrentProducerID) {
mFrameIDsNotYetComposited.Clear();
mCurrentProducerID = aImages[0].mProducerID;
} else if (!aImages[0].mTimeStamp.IsNull()) {
// Check for expired frames
for (auto& img : mCurrentImages) {
if (img.mProducerID != aImages[0].mProducerID ||
img.mTimeStamp.IsNull() ||
img.mTimeStamp >= aImages[0].mTimeStamp) {
break;
}
if (!img.mComposited && !img.mTimeStamp.IsNull() &&
img.mFrameID != aImages[0].mFrameID) {
mFrameIDsNotYetComposited.AppendElement(img.mFrameID);
}
}
// Remove really old frames, assuming they'll never be composited.
const uint32_t maxFrames = 100;
if (mFrameIDsNotYetComposited.Length() > maxFrames) {
uint32_t dropFrames = mFrameIDsNotYetComposited.Length() - maxFrames;
mDroppedImageCount += dropFrames;
mFrameIDsNotYetComposited.RemoveElementsAt(0, dropFrames);
}
}
}
@ -303,7 +290,7 @@ ImageContainer::SetCurrentImageInternal(const nsTArray<NonOwningImage>& aImages)
img->mTimeStamp = aImages[i].mTimeStamp;
img->mFrameID = aImages[i].mFrameID;
img->mProducerID = aImages[i].mProducerID;
for (auto& oldImg : mCurrentImages) {
for (const auto& oldImg : mCurrentImages) {
if (oldImg.mFrameID == img->mFrameID &&
oldImg.mProducerID == img->mProducerID) {
img->mComposited = oldImg.mComposited;
@ -439,17 +426,6 @@ ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification)
++mPaintCount;
if (aNotification.producerID() == mCurrentProducerID) {
uint32_t i;
for (i = 0; i < mFrameIDsNotYetComposited.Length(); ++i) {
if (mFrameIDsNotYetComposited[i] <= aNotification.frameID()) {
if (mFrameIDsNotYetComposited[i] < aNotification.frameID()) {
++mDroppedImageCount;
}
} else {
break;
}
}
mFrameIDsNotYetComposited.RemoveElementsAt(0, i);
for (auto& img : mCurrentImages) {
if (img.mFrameID == aNotification.frameID()) {
img.mComposited = true;
@ -458,11 +434,17 @@ ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification)
}
if (!aNotification.imageTimeStamp().IsNull()) {
mPaintDelay = aNotification.firstCompositeTimeStamp() -
aNotification.imageTimeStamp();
mPaintDelay =
aNotification.firstCompositeTimeStamp() - aNotification.imageTimeStamp();
}
}
void
ImageContainer::NotifyDropped(uint32_t aDropped)
{
mDroppedImageCount += aDropped;
}
#ifdef XP_WIN
D3D11YCbCrRecycleAllocator*
ImageContainer::GetD3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator)

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

@ -356,6 +356,7 @@ public:
explicit ImageContainerListener(ImageContainer* aImageContainer);
void NotifyComposite(const ImageCompositeNotification& aNotification);
void NotifyDropped(uint32_t aDropped);
void ClearImageContainer();
void DropImageClient();
private:
@ -613,11 +614,11 @@ public:
*/
uint32_t GetDroppedImageCount()
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
return mDroppedImageCount;
}
void NotifyComposite(const ImageCompositeNotification& aNotification);
void NotifyDropped(uint32_t aDropped);
ImageContainerListener* GetImageContainerListener()
{
@ -675,8 +676,8 @@ private:
// See GetPaintDelay. Accessed only with mRecursiveMutex held.
TimeDuration mPaintDelay;
// See GetDroppedImageCount. Accessed only with mRecursiveMutex held.
uint32_t mDroppedImageCount;
// See GetDroppedImageCount.
mozilla::Atomic<uint32_t> mDroppedImageCount;
// This is the image factory used by this container, layer managers using
// this container can set an alternative image factory that will be used to
@ -701,9 +702,7 @@ private:
bool mIsAsync;
CompositableHandle mAsyncContainerHandle;
nsTArray<FrameID> mFrameIDsNotYetComposited;
// ProducerID for last current image(s), including the frames in
// mFrameIDsNotYetComposited
// ProducerID for last current image(s)
ProducerID mCurrentProducerID;
RefPtr<ImageContainerListener> mNotifyCompositeListener;

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

@ -127,11 +127,12 @@ public:
* *aPictureRect (if non-null, and the returned TextureHost is non-null)
* is set to the picture rect.
*/
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) {
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr)
{
return nullptr;
}
virtual gfx::IntSize GetImageSize() const
virtual gfx::IntSize GetImageSize()
{
MOZ_ASSERT(false, "Should have been overridden");
return gfx::IntSize();
@ -244,6 +245,8 @@ public:
virtual void BindTextureSource() {}
virtual uint32_t GetDroppedFrames() { return 0; }
protected:
HostLayerManager* GetLayerManager() const;

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

@ -18,16 +18,19 @@ ImageComposite::ImageComposite()
: mLastFrameID(-1)
, mLastProducerID(-1)
, mBias(BIAS_NONE)
{}
, mDroppedFrames(0)
, mLastChosenImageIndex(0)
{
}
ImageComposite::~ImageComposite()
{
}
/* static */ TimeStamp
ImageComposite::GetBiasedTime(const TimeStamp& aInput, ImageComposite::Bias aBias)
TimeStamp
ImageComposite::GetBiasedTime(const TimeStamp& aInput) const
{
switch (aBias) {
switch (mBias) {
case ImageComposite::BIAS_NEGATIVE:
return aInput - TimeDuration::FromMilliseconds(BIAS_TIME_MS);
case ImageComposite::BIAS_POSITIVE:
@ -37,18 +40,24 @@ ImageComposite::GetBiasedTime(const TimeStamp& aInput, ImageComposite::Bias aBia
}
}
/* static */ ImageComposite::Bias
ImageComposite::UpdateBias(const TimeStamp& aCompositionTime,
const TimeStamp& aCompositedImageTime,
const TimeStamp& aNextImageTime, // may be null
ImageComposite::Bias aBias)
void
ImageComposite::UpdateBias(size_t aImageIndex)
{
if (aCompositedImageTime.IsNull()) {
return ImageComposite::BIAS_NONE;
MOZ_ASSERT(aImageIndex < ImagesCount());
TimeStamp compositionTime = GetCompositionTime();
TimeStamp compositedImageTime = mImages[aImageIndex].mTimeStamp;
TimeStamp nextImageTime = aImageIndex + 1 < ImagesCount()
? mImages[aImageIndex + 1].mTimeStamp
: TimeStamp();
if (compositedImageTime.IsNull()) {
mBias = ImageComposite::BIAS_NONE;
return;
}
TimeDuration threshold = TimeDuration::FromMilliseconds(1.0);
if (aCompositionTime - aCompositedImageTime < threshold &&
aCompositionTime - aCompositedImageTime > -threshold) {
if (compositionTime - compositedImageTime < threshold &&
compositionTime - compositedImageTime > -threshold) {
// The chosen frame's time is very close to the composition time (probably
// just before the current composition time, but due to previously set
// negative bias, it could be just after the current composition time too).
@ -59,11 +68,12 @@ ImageComposite::UpdateBias(const TimeStamp& aCompositionTime,
// Try to prevent that by adding a negative bias to the frame times during
// the next composite; that should ensure the next frame's time is treated
// as falling just before a composite time.
return ImageComposite::BIAS_NEGATIVE;
mBias = ImageComposite::BIAS_NEGATIVE;
return;
}
if (!aNextImageTime.IsNull() &&
aNextImageTime - aCompositionTime < threshold &&
aNextImageTime - aCompositionTime > -threshold) {
if (!nextImageTime.IsNull() &&
nextImageTime - compositionTime < threshold &&
nextImageTime - compositionTime > -threshold) {
// The next frame's time is very close to our composition time (probably
// just after the current composition time, but due to previously set
// positive bias, it could be just before the current composition time too).
@ -73,14 +83,19 @@ ImageComposite::UpdateBias(const TimeStamp& aCompositionTime,
// Try to prevent that by adding a negative bias to the frame times during
// the next composite; that should ensure the next frame's time is treated
// as falling just before a composite time.
return ImageComposite::BIAS_POSITIVE;
mBias = ImageComposite::BIAS_POSITIVE;
return;
}
return ImageComposite::BIAS_NONE;
mBias = ImageComposite::BIAS_NONE;
}
int
ImageComposite::ChooseImageIndex() const
ImageComposite::ChooseImageIndex()
{
// ChooseImageIndex is called for all images in the layer when it is visible.
// Change to this behaviour would break dropped frames counting calculation:
// We rely on this assumption to determine if during successive runs an
// image is returned that isn't the one following immediately the previous one
if (mImages.IsEmpty()) {
return -1;
}
@ -98,24 +113,115 @@ ImageComposite::ChooseImageIndex() const
return -1;
}
uint32_t result = 0;
uint32_t result = mLastChosenImageIndex;
while (result + 1 < mImages.Length() &&
GetBiasedTime(mImages[result + 1].mTimeStamp, mBias) <= now) {
GetBiasedTime(mImages[result + 1].mTimeStamp) <= now) {
++result;
}
if (result - mLastChosenImageIndex > 1) {
// We're not returning the same image as the last call to ChooseImageIndex
// or the immediately next one. We can assume that the frames not returned
// have been dropped as they were too late to be displayed
mDroppedFrames += result - mLastChosenImageIndex - 1;
}
mLastChosenImageIndex = result;
return result;
}
const ImageComposite::TimedImage* ImageComposite::ChooseImage() const
const ImageComposite::TimedImage* ImageComposite::ChooseImage()
{
int index = ChooseImageIndex();
return index >= 0 ? &mImages[index] : nullptr;
}
ImageComposite::TimedImage* ImageComposite::ChooseImage()
void
ImageComposite::RemoveImagesWithTextureHost(TextureHost* aTexture)
{
int index = ChooseImageIndex();
return index >= 0 ? &mImages[index] : nullptr;
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (mImages[i].mTextureHost == aTexture) {
aTexture->UnbindTextureSource();
mImages.RemoveElementAt(i);
}
}
}
void
ImageComposite::ClearImages()
{
mImages.Clear();
mLastChosenImageIndex = 0;
}
uint32_t
ImageComposite::ScanForLastFrameIndex(const nsTArray<TimedImage>& aNewImages)
{
if (mImages.IsEmpty()) {
return 0;
}
uint32_t i = mLastChosenImageIndex;
uint32_t newIndex = 0;
uint32_t dropped = 0;
// See if the new array of images have any images in common with the
// previous list that we haven't played yet.
uint32_t j = 0;
while (i < mImages.Length() && j < aNewImages.Length()) {
if (mImages[i].mProducerID != aNewImages[j].mProducerID) {
// This is new content, can stop.
newIndex = j;
break;
}
int32_t oldFrameID = mImages[i].mFrameID;
int32_t newFrameID = aNewImages[j].mFrameID;
if (oldFrameID > newFrameID) {
// This is an image we have already returned, we don't need to present
// it again and can start from this index next time.
newIndex = ++j;
continue;
}
if (oldFrameID < mLastFrameID) {
// we have already returned that frame previously, ignore.
i++;
continue;
}
if (oldFrameID < newFrameID) {
// This is a new image, all images prior the new one and not yet
// rendered can be considered as dropped. Those images have a FrameID
// inferior to the new image.
for (++i; i < mImages.Length() && mImages[i].mFrameID < newFrameID &&
mImages[i].mProducerID == aNewImages[j].mProducerID;
i++) {
dropped++;
}
break;
}
i++;
j++;
}
if (dropped > 0) {
mDroppedFrames += dropped;
}
if (newIndex >= aNewImages.Length()) {
// Somehow none of those images should be rendered (can this happen?)
// We will always return the last one for now.
newIndex = aNewImages.Length() - 1;
}
return newIndex;
}
void
ImageComposite::SetImages(nsTArray<TimedImage>&& aNewImages)
{
mLastChosenImageIndex = ScanForLastFrameIndex(aNewImages);
mImages = std::move(aNewImages);
}
const ImageComposite::TimedImage*
ImageComposite::GetImage(size_t aIndex) const
{
if (aIndex >= mImages.Length()) {
return nullptr;
}
return &mImages[aIndex];
}
} // namespace layers

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

@ -40,6 +40,12 @@ public:
int32_t GetLastFrameID() const { return mLastFrameID; }
int32_t GetLastProducerID() const { return mLastProducerID; }
uint32_t GetDroppedFramesAndReset()
{
uint32_t dropped = mDroppedFrames;
mDroppedFrames = 0;
return dropped;
}
enum Bias {
// Don't apply bias to frame times
@ -50,13 +56,8 @@ public:
BIAS_POSITIVE,
};
static TimeStamp GetBiasedTime(const TimeStamp& aInput, ImageComposite::Bias aBias);
protected:
static Bias UpdateBias(const TimeStamp& aCompositionTime,
const TimeStamp& aCompositedImageTime,
const TimeStamp& aNextImageTime, // may be null
ImageComposite::Bias aBias);
void UpdateBias(size_t aImageIndex);
virtual TimeStamp GetCompositionTime() const = 0;
@ -74,17 +75,34 @@ protected:
* it depends only on mImages, mCompositor->GetCompositionTime(), and mBias.
* mBias is updated at the end of Composite().
*/
const TimedImage* ChooseImage() const;
TimedImage* ChooseImage();
int ChooseImageIndex() const;
const TimedImage* ChooseImage();
int ChooseImageIndex();
const TimedImage* GetImage(size_t aIndex) const;
size_t ImagesCount() const { return mImages.Length(); }
const nsTArray<TimedImage>& Images() const { return mImages; }
void RemoveImagesWithTextureHost(TextureHost* aTexture);
void ClearImages();
void SetImages(nsTArray<TimedImage>&& aNewImages);
nsTArray<TimedImage> mImages;
int32_t mLastFrameID;
int32_t mLastProducerID;
private:
nsTArray<TimedImage> mImages;
TimeStamp GetBiasedTime(const TimeStamp& aInput) const;
// Scan new images and look for common ones in the existing mImages array.
// Will determine if an image has been dropped through gaps between images and
// adjust mDroppedFrames accordingly.
// Return the index of what the last returned image would have been.
uint32_t ScanForLastFrameIndex(const nsTArray<TimedImage>& aNewImages);
/**
* Bias to apply to the next frame.
*/
Bias mBias;
uint32_t mDroppedFrames;
uint32_t mLastChosenImageIndex;
};
} // namespace layers

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

@ -9,6 +9,7 @@
#include "LayersLogging.h" // for AppendToString
#include "composite/CompositableHost.h" // for CompositableHost, etc
#include "ipc/IPCMessageUtils.h" // for null_t
#include "mozilla/Move.h"
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
@ -66,13 +67,12 @@ ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
img.mTextureHost->Updated();
}
mImages.SwapElements(newImages);
newImages.Clear();
SetImages(std::move(newImages));
// If we only have one image we can upload it right away, otherwise we'll upload
// on-demand during composition after we have picked the proper timestamp.
if (mImages.Length() == 1) {
SetCurrentTextureHost(mImages[0].mTextureHost);
if (ImagesCount() == 1) {
SetCurrentTextureHost(GetImage(0)->mTextureHost);
}
HostLayerManager* lm = GetLayerManager();
@ -82,11 +82,11 @@ ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
// means that any CompositeUntil() call we made in Composite() may no longer
// guarantee that we'll composite until the next frame is ready. Fix that here.
if (lm && mLastFrameID >= 0) {
for (size_t i = 0; i < mImages.Length(); ++i) {
bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
mImages[i].mProducerID != mLastProducerID;
if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
lm->CompositeUntil(mImages[i].mTimeStamp +
for (const auto& img : Images()) {
bool frameComesAfter =
img.mFrameID > mLastFrameID || img.mProducerID != mLastProducerID;
if (frameComesAfter && !img.mTimeStamp.IsNull()) {
lm->CompositeUntil(img.mTimeStamp +
TimeDuration::FromMilliseconds(BIAS_TIME_MS));
break;
}
@ -142,13 +142,7 @@ ImageHost::RemoveTextureHost(TextureHost* aTexture)
MOZ_ASSERT(!mLocked);
CompositableHost::RemoveTextureHost(aTexture);
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (mImages[i].mTextureHost == aTexture) {
aTexture->UnbindTextureSource();
mImages.RemoveElementAt(i);
}
}
RemoveImagesWithTextureHost(aTexture);
}
TimeStamp
@ -164,14 +158,15 @@ ImageHost::GetCompositionTime() const
TextureHost*
ImageHost::GetAsTextureHost(IntRect* aPictureRect)
{
TimedImage* img = ChooseImage();
if (img) {
SetCurrentTextureHost(img->mTextureHost);
const TimedImage* img = ChooseImage();
if (!img) {
return nullptr;
}
if (aPictureRect && img) {
SetCurrentTextureHost(img->mTextureHost);
if (aPictureRect) {
*aPictureRect = img->mPictureRect;
}
return img ? img->mTextureHost.get() : nullptr;
return img->mTextureHost;
}
void ImageHost::Attach(Layer* aLayer,
@ -179,7 +174,7 @@ void ImageHost::Attach(Layer* aLayer,
AttachFlags aFlags)
{
CompositableHost::Attach(aLayer, aProvider, aFlags);
for (auto& img : mImages) {
for (const auto& img : Images()) {
img.mTextureHost->SetTextureSourceProvider(aProvider);
img.mTextureHost->Updated();
}
@ -201,7 +196,7 @@ ImageHost::Composite(Compositor* aCompositor,
return;
}
TimedImage* img = info.img;
const TimedImage* img = info.img;
{
AutoLockCompositableHost autoLock(this);
@ -319,11 +314,12 @@ ImageHost::PrepareToRender(TextureSourceProvider* aProvider, RenderInfo* aOutInf
return false;
}
if (uint32_t(imageIndex) + 1 < mImages.Length()) {
lm->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
if (uint32_t(imageIndex) + 1 < ImagesCount()) {
lm->CompositeUntil(GetImage(imageIndex + 1)->mTimeStamp +
TimeDuration::FromMilliseconds(BIAS_TIME_MS));
}
TimedImage* img = &mImages[imageIndex];
const TimedImage* img = GetImage(imageIndex);
img->mTextureHost->SetTextureSourceProvider(aProvider);
SetCurrentTextureHost(img->mTextureHost);
@ -347,7 +343,7 @@ void
ImageHost::FinishRendering(const RenderInfo& aInfo)
{
HostLayerManager* lm = GetLayerManager();
TimedImage* img = aInfo.img;
const TimedImage* img = aInfo.img;
int imageIndex = aInfo.imageIndex;
if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
@ -369,18 +365,14 @@ ImageHost::FinishRendering(const RenderInfo& aInfo)
// since callers of ChooseImage(Index) assume the same image will be chosen
// during a given composition. This must happen after autoLock's
// destructor!
mBias = UpdateBias(
lm->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
uint32_t(imageIndex + 1) < mImages.Length() ?
mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
mBias);
UpdateBias(imageIndex);
}
void
ImageHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mTextureSourceProvider != aProvider) {
for (auto& img : mImages) {
for (const auto& img : Images()) {
img.mTextureHost->SetTextureSourceProvider(aProvider);
}
}
@ -395,7 +387,7 @@ ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
nsAutoCString pfx(aPrefix);
pfx += " ";
for (auto& img : mImages) {
for (const auto& img : Images()) {
aStream << "\n";
img.mTextureHost->PrintInfo(aStream, pfx.get());
AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
@ -407,7 +399,7 @@ ImageHost::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml)
{
for (auto& img : mImages) {
for (const auto& img : Images()) {
aStream << aPrefix;
aStream << (aDumpHtml ? "<ul><li>TextureHost: "
: "TextureHost: ");
@ -419,7 +411,7 @@ ImageHost::Dump(std::stringstream& aStream,
already_AddRefed<gfx::DataSourceSurface>
ImageHost::GetAsSurface()
{
TimedImage* img = ChooseImage();
const TimedImage* img = ChooseImage();
if (img) {
return img->mTextureHost->GetAsSurface();
}
@ -430,7 +422,7 @@ bool
ImageHost::Lock()
{
MOZ_ASSERT(!mLocked);
TimedImage* img = ChooseImage();
const TimedImage* img = ChooseImage();
if (!img) {
return false;
}
@ -456,7 +448,7 @@ ImageHost::Unlock()
}
IntSize
ImageHost::GetImageSize() const
ImageHost::GetImageSize()
{
const TimedImage* img = ChooseImage();
if (img) {
@ -489,7 +481,7 @@ ImageHost::IsOpaque()
already_AddRefed<TexturedEffect>
ImageHost::GenEffect(const gfx::SamplingFilter aSamplingFilter)
{
TimedImage* img = ChooseImage();
const TimedImage* img = ChooseImage();
if (!img) {
return nullptr;
}

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

@ -69,7 +69,7 @@ public:
virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
gfx::IntSize GetImageSize() const override;
gfx::IntSize GetImageSize() override;
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
@ -91,9 +91,14 @@ public:
bool IsOpaque();
uint32_t GetDroppedFrames() override
{
return GetDroppedFramesAndReset();
}
struct RenderInfo {
int imageIndex;
TimedImage* img;
const TimedImage* img;
RefPtr<TextureHost> host;
RenderInfo() : imageIndex(-1), img(nullptr)

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

@ -68,18 +68,26 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
if (!compositable) {
return false;
}
if (TextureSourceProvider* provider = compositable->GetTextureSourceProvider()) {
return ReceiveCompositableUpdate(aEdit.detail(), WrapNotNull(compositable));
}
bool
CompositableParentManager::ReceiveCompositableUpdate(
const CompositableOperationDetail& aDetail,
NotNull<CompositableHost*> aCompositable)
{
if (TextureSourceProvider* provider = aCompositable->GetTextureSourceProvider()) {
if (!provider->IsValid()) {
return false;
}
}
switch (aEdit.detail().type()) {
switch (aDetail.type()) {
case CompositableOperationDetail::TOpPaintTextureRegion: {
MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
const OpPaintTextureRegion& op = aEdit.detail().get_OpPaintTextureRegion();
Layer* layer = compositable->GetLayer();
const OpPaintTextureRegion& op = aDetail.get_OpPaintTextureRegion();
Layer* layer = aCompositable->GetLayer();
if (!layer || layer->GetType() != Layer::TYPE_PAINTED) {
return false;
}
@ -89,10 +97,9 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
RenderTraceInvalidateStart(thebes, "FF00FF", op.updatedRegion().GetBounds());
if (!compositable->UpdateThebes(bufferData,
if (!aCompositable->UpdateThebes(bufferData,
op.updatedRegion(),
thebes->GetValidRegion()))
{
thebes->GetValidRegion())) {
return false;
}
@ -101,8 +108,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
case CompositableOperationDetail::TOpUseTiledLayerBuffer: {
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
const OpUseTiledLayerBuffer& op = aEdit.detail().get_OpUseTiledLayerBuffer();
TiledContentHost* tiledHost = compositable->AsTiledContentHost();
const OpUseTiledLayerBuffer& op = aDetail.get_OpUseTiledLayerBuffer();
TiledContentHost* tiledHost = aCompositable->AsTiledContentHost();
NS_ASSERTION(tiledHost, "The compositable is not tiled");
@ -140,16 +147,16 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
break;
}
case CompositableOperationDetail::TOpRemoveTexture: {
const OpRemoveTexture& op = aEdit.detail().get_OpRemoveTexture();
const OpRemoveTexture& op = aDetail.get_OpRemoveTexture();
RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
MOZ_ASSERT(tex.get());
compositable->RemoveTextureHost(tex);
aCompositable->RemoveTextureHost(tex);
break;
}
case CompositableOperationDetail::TOpUseTexture: {
const OpUseTexture& op = aEdit.detail().get_OpUseTexture();
const OpUseTexture& op = aDetail.get_OpUseTexture();
AutoTArray<CompositableHost::TimedTexture,4> textures;
for (auto& timedTexture : op.textures()) {
@ -166,7 +173,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
}
if (textures.Length() > 0) {
compositable->UseTextureHost(textures);
aCompositable->UseTextureHost(textures);
for (auto& timedTexture : op.textures()) {
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(timedTexture.textureParent());
@ -179,13 +186,13 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
}
if (UsesImageBridge() && compositable->GetLayer()) {
ScheduleComposition(compositable);
if (UsesImageBridge() && aCompositable->GetLayer()) {
ScheduleComposition(aCompositable);
}
break;
}
case CompositableOperationDetail::TOpUseComponentAlphaTextures: {
const OpUseComponentAlphaTextures& op = aEdit.detail().get_OpUseComponentAlphaTextures();
const OpUseComponentAlphaTextures& op = aDetail.get_OpUseComponentAlphaTextures();
RefPtr<TextureHost> texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent());
RefPtr<TextureHost> texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent());
if (op.readLockedBlack()) {
@ -196,7 +203,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
MOZ_ASSERT(texOnBlack && texOnWhite);
compositable->UseComponentAlphaTextures(texOnBlack, texOnWhite);
aCompositable->UseComponentAlphaTextures(texOnBlack, texOnWhite);
if (texOnBlack) {
texOnBlack->SetLastFwdTransactionId(mFwdTransactionId);
@ -213,7 +220,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
if (UsesImageBridge()) {
ScheduleComposition(compositable);
ScheduleComposition(aCompositable);
}
break;
}

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

@ -9,6 +9,7 @@
#include <vector> // for vector
#include "mozilla/Attributes.h" // for override
#include "mozilla/NotNull.h"
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
#include "mozilla/layers/TextureClient.h"
@ -48,6 +49,8 @@ protected:
* Handle the IPDL messages that affect PCompositable actors.
*/
bool ReceiveCompositableUpdate(const CompositableOperation& aEdit);
bool ReceiveCompositableUpdate(const CompositableOperationDetail& aDetail,
NotNull<CompositableHost*> aCompositable);
void ReleaseCompositable(const CompositableHandle& aHandle);

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

@ -997,18 +997,23 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageDat
return IPC_OK();
}
RefPtr<ImageContainerListener>
ImageBridgeChild::FindListener(const CompositableHandle& aHandle)
{
RefPtr<ImageContainerListener> listener;
MutexAutoLock lock(mContainerMapLock);
auto it = mImageContainerListeners.find(aHandle.Value());
if (it != mImageContainerListeners.end()) {
listener = it->second;
}
return listener;
}
mozilla::ipc::IPCResult
ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
{
for (auto& n : aNotifications) {
RefPtr<ImageContainerListener> listener;
{
MutexAutoLock lock(mContainerMapLock);
auto it = mImageContainerListeners.find(n.compositable().Value());
if (it != mImageContainerListeners.end()) {
listener = it->second;
}
}
RefPtr<ImageContainerListener> listener = FindListener(n.compositable());
if (listener) {
listener->NotifyComposite(n);
}
@ -1016,6 +1021,17 @@ ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&
return IPC_OK();
}
mozilla::ipc::IPCResult
ImageBridgeChild::RecvReportFramesDropped(const CompositableHandle& aHandle, const uint32_t& aFrames)
{
RefPtr<ImageContainerListener> listener = FindListener(aHandle);
if (listener) {
listener->NotifyDropped(aFrames);
}
return IPC_OK();
}
PTextureChild*
ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
const ReadLockDescriptor& aReadLock,

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

@ -194,6 +194,9 @@ public:
virtual mozilla::ipc::IPCResult
RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications) override;
virtual mozilla::ipc::IPCResult
RecvReportFramesDropped(const CompositableHandle& aHandle, const uint32_t& aFrames) override;
// Create an ImageClient from any thread.
RefPtr<ImageClient> CreateImageClient(
CompositableType aType,
@ -403,6 +406,7 @@ private:
*/
Mutex mContainerMapLock;
std::unordered_map<uint64_t, RefPtr<ImageContainerListener>> mImageContainerListeners;
RefPtr<ImageContainerListener> FindListener(const CompositableHandle& aHandle);
#if defined(XP_WIN)
/**

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

@ -198,10 +198,17 @@ ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
UpdateFwdTransactionId(aFwdTransactionId);
for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
if (!ReceiveCompositableUpdate(aEdits[i])) {
for (const auto& edit : aEdits) {
RefPtr<CompositableHost> compositable =
FindCompositable(edit.compositable());
if (!compositable ||
!ReceiveCompositableUpdate(edit.detail(), WrapNotNull(compositable))) {
return IPC_FAIL_NO_REASON(this);
}
uint32_t dropped = compositable->GetDroppedFrames();
if (dropped) {
Unused << SendReportFramesDropped(edit.compositable(), dropped);
}
}
if (!IsSameProcess()) {

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

@ -36,6 +36,9 @@ child:
async DidComposite(ImageCompositeNotification[] aNotifications);
// Report the number of frames dropped for the given CompositableHost.
async ReportFramesDropped(CompositableHandle aHandle, uint32_t aFrames);
parent:
async Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);

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

@ -7,6 +7,7 @@
#include "WebRenderImageHost.h"
#include "LayersLogging.h"
#include "mozilla/Move.h"
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorVsyncScheduler.h" // for CompositorVsyncScheduler
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
@ -68,8 +69,7 @@ WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
img.mTextureHost->Updated();
}
mImages.SwapElements(newImages);
newImages.Clear();
SetImages(std::move(newImages));
if (mWrBridge && mWrBridge->CompositorScheduler() && GetAsyncRef()) {
// Will check if we will generate frame.
@ -82,12 +82,12 @@ WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
// guarantee that we'll composite until the next frame is ready. Fix that here.
if (mWrBridge && mLastFrameID >= 0) {
MOZ_ASSERT(mWrBridge->AsyncImageManager());
for (size_t i = 0; i < mImages.Length(); ++i) {
bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
mImages[i].mProducerID != mLastProducerID;
if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
mWrBridge->AsyncImageManager()->CompositeUntil(mImages[i].mTimeStamp +
TimeDuration::FromMilliseconds(BIAS_TIME_MS));
for (const auto& img : Images()) {
bool frameComesAfter =
img.mFrameID > mLastFrameID || img.mProducerID != mLastProducerID;
if (frameComesAfter && !img.mTimeStamp.IsNull()) {
mWrBridge->AsyncImageManager()->CompositeUntil(
img.mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
break;
}
}
@ -104,9 +104,7 @@ WebRenderImageHost::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
void
WebRenderImageHost::CleanupResources()
{
nsTArray<TimedImage> newImages;
mImages.SwapElements(newImages);
newImages.Clear();
ClearImages();
SetCurrentTextureHost(nullptr);
}
@ -114,13 +112,7 @@ void
WebRenderImageHost::RemoveTextureHost(TextureHost* aTexture)
{
CompositableHost::RemoveTextureHost(aTexture);
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
if (mImages[i].mTextureHost == aTexture) {
aTexture->UnbindTextureSource();
mImages.RemoveElementAt(i);
}
}
RemoveImagesWithTextureHost(aTexture);
}
TimeStamp
@ -137,7 +129,7 @@ WebRenderImageHost::GetCompositionTime() const
TextureHost*
WebRenderImageHost::GetAsTextureHost(IntRect* aPictureRect)
{
TimedImage* img = ChooseImage();
const TimedImage* img = ChooseImage();
if (img) {
return img->mTextureHost;
}
@ -157,12 +149,14 @@ WebRenderImageHost::GetAsTextureHostForComposite()
return nullptr;
}
if (uint32_t(imageIndex) + 1 < mImages.Length()) {
if (uint32_t(imageIndex) + 1 < ImagesCount()) {
MOZ_ASSERT(mWrBridge->AsyncImageManager());
mWrBridge->AsyncImageManager()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
mWrBridge->AsyncImageManager()->CompositeUntil(
GetImage(imageIndex + 1)->mTimeStamp +
TimeDuration::FromMilliseconds(BIAS_TIME_MS));
}
TimedImage* img = &mImages[imageIndex];
const TimedImage* img = GetImage(imageIndex);
if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
if (mAsyncRef) {
@ -179,12 +173,7 @@ WebRenderImageHost::GetAsTextureHostForComposite()
}
SetCurrentTextureHost(img->mTextureHost);
mBias = UpdateBias(
mWrBridge->AsyncImageManager()->GetCompositionTime(),
mImages[imageIndex].mTimeStamp,
uint32_t(imageIndex + 1) < mImages.Length() ?
mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
mBias);
UpdateBias(imageIndex);
return mCurrentTextureHost;
}
@ -223,7 +212,7 @@ void
WebRenderImageHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mTextureSourceProvider != aProvider) {
for (auto& img : mImages) {
for (const auto& img : Images()) {
img.mTextureHost->SetTextureSourceProvider(aProvider);
}
}
@ -238,7 +227,7 @@ WebRenderImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
nsAutoCString pfx(aPrefix);
pfx += " ";
for (auto& img : mImages) {
for (const auto& img : Images()) {
aStream << "\n";
img.mTextureHost->PrintInfo(aStream, pfx.get());
AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
@ -250,7 +239,7 @@ WebRenderImageHost::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml)
{
for (auto& img : mImages) {
for (const auto& img : Images()) {
aStream << aPrefix;
aStream << (aDumpHtml ? "<ul><li>TextureHost: "
: "TextureHost: ");
@ -262,7 +251,7 @@ WebRenderImageHost::Dump(std::stringstream& aStream,
already_AddRefed<gfx::DataSourceSurface>
WebRenderImageHost::GetAsSurface()
{
TimedImage* img = ChooseImage();
const TimedImage* img = ChooseImage();
if (img) {
return img->mTextureHost->GetAsSurface();
}
@ -283,7 +272,7 @@ WebRenderImageHost::Unlock()
}
IntSize
WebRenderImageHost::GetImageSize() const
WebRenderImageHost::GetImageSize()
{
const TimedImage* img = ChooseImage();
if (img) {

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

@ -50,7 +50,7 @@ public:
virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
gfx::IntSize GetImageSize() const override;
gfx::IntSize GetImageSize() override;
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
@ -66,6 +66,11 @@ public:
virtual void CleanupResources() override;
uint32_t GetDroppedFrames() override
{
return GetDroppedFramesAndReset();
}
virtual WebRenderImageHost* AsWebRenderImageHost() override { return this; }
TextureHost* GetAsTextureHostForComposite();

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

@ -375,12 +375,13 @@ bool SkDashPath::InternalFilter(SkPath* dst, const SkPath& src, SkStrokeRec* rec
SkScalar pathLength = SkPathMeasure(src, false, rec->getResScale()).getLength();
SkScalar endPhase = SkScalarMod(pathLength + initialDashLength, intervalLength);
int index = 0;
while (endPhase > intervals[index]) {
endPhase -= intervals[index++];
SkScalar sum = 0;
while (endPhase > sum + intervals[index]) {
sum += intervals[index++];
SkASSERT(index <= count);
}
// if dash ends inside "on", or ends at beginning of "off"
if (is_even(index) == (endPhase > 0)) {
if (is_even(index) == (endPhase > sum)) {
SkPoint midPoint = src.getPoint(0);
// get vector at end of rect
int last = src.countPoints() - 1;

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

@ -1,7 +1,7 @@
[DEFAULT]
[test_acceleration.html]
skip-if = (os == 'win' && os_version == '10.0' && !debug) # Bug 1430530
skip-if = (os == 'win') # Bug 1430530
subsuite = gpu
[test_bug509244.html]
[test_bug513439.html]

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

@ -157,7 +157,6 @@ public:
void
Remove()
{
remove();
mManager->RemoveUserData(&sWRUserDataKey);
}
@ -232,8 +231,11 @@ PurgeWRGlyphAtlas()
}
}
}
// Remove the layer manager's destroy notification.
user->Remove();
}
// Remove the layer managers' destroy notifications only after processing
// so as not to mess up gWRUsers iteration.
while (!gWRUsers.isEmpty()) {
gWRUsers.popFirst()->Remove();
}
// Finally, clear out the atlases.
for (size_t i = 0; i < 8; i++) {

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

@ -420,6 +420,7 @@ BackgroundChildImpl::DeallocPCamerasChild(camera::PCamerasChild *aActor)
RefPtr<camera::CamerasChild> child =
dont_AddRef(static_cast<camera::CamerasChild*>(aActor));
MOZ_ASSERT(aActor);
camera::Shutdown();
#endif
return true;
}

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

@ -35,6 +35,7 @@ using mozilla::AssertedCast;
using mozilla::IsFinite;
using mozilla::IsNaN;
using mozilla::IsNegative;
using mozilla::SpecificNaN;
using js::intl::CallICU;
using js::intl::DateTimeFormatOptions;
@ -376,11 +377,17 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
}
static JSString*
PartitionNumberPattern(JSContext* cx, UNumberFormat* nf, double x,
PartitionNumberPattern(JSContext* cx, UNumberFormat* nf, double* x,
UFieldPositionIterator* fpositer)
{
return CallICU(cx, [nf, x, fpositer](UChar* chars, int32_t size, UErrorCode* status) {
return unum_formatDoubleForFields(nf, x, chars, size, fpositer, status);
// ICU incorrectly formats NaN values with the sign bit set, as if they
// were negative. Replace all NaNs with a single pattern with sign bit
// unset ("positive", that is) until ICU is fixed.
if (MOZ_UNLIKELY(IsNaN(*x)))
*x = SpecificNaN<double>(0, 1);
return CallICU(cx, [nf, d = *x, fpositer](UChar* chars, int32_t size, UErrorCode* status) {
return unum_formatDoubleForFields(nf, d, chars, size, fpositer, status);
});
}
@ -389,7 +396,7 @@ intl_FormatNumber(JSContext* cx, UNumberFormat* nf, double x, MutableHandleValue
{
// Passing null for |fpositer| will just not compute partition information,
// letting us common up all ICU number-formatting code.
JSString* str = PartitionNumberPattern(cx, nf, x, nullptr);
JSString* str = PartitionNumberPattern(cx, nf, &x, nullptr);
if (!str)
return false;
@ -428,6 +435,11 @@ GetFieldTypeForNumberField(UNumberFormatFields fieldName, double d)
// Manual trawling through the ICU call graph appears to indicate that
// the basic formatting we request will never include a positive sign.
// But this analysis may be mistaken, so don't absolutely trust it.
MOZ_ASSERT(!IsNaN(d),
"ICU appearing not to produce positive-sign among fields, "
"plus our coercing all NaNs to one with sign bit unset "
"(i.e. \"positive\"), means we shouldn't reach here with a "
"NaN value");
return IsNegative(d) ? &JSAtomState::minusSign : &JSAtomState::plusSign;
}
@ -478,7 +490,7 @@ intl_FormatNumberToParts(JSContext* cx, UNumberFormat* nf, double x, MutableHand
MOZ_ASSERT(fpositer);
ScopedICUObject<UFieldPositionIterator, ufieldpositer_close> toClose(fpositer);
RootedString overallResult(cx, PartitionNumberPattern(cx, nf, x, fpositer));
RootedString overallResult(cx, PartitionNumberPattern(cx, nf, &x, fpositer));
if (!overallResult)
return false;

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

@ -151,8 +151,9 @@ GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind)
if (allowGC && !cx->suppressGC) {
cx->runtime()->gc.minorGC(JS::gcreason::OUT_OF_NURSERY);
// Exceeding gcMaxBytes while tenuring can disable the Nursery.
if (cx->nursery().isEnabled())
// Exceeding gcMaxBytes while tenuring can disable the Nursery, and
// other heuristics can disable nursery strings for this zone.
if (cx->nursery().isEnabled() && cx->zone()->allocNurseryStrings)
return static_cast<JSString*>(cx->nursery().allocateString(cx->zone(), thingSize, kind));
}
return nullptr;

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

@ -25,8 +25,8 @@ static T* extractUnbarriered(T* v)
return v;
}
template <class K, class V, class HP>
WeakMap<K, V, HP>::WeakMap(JSContext* cx, JSObject* memOf)
template <class K, class V>
WeakMap<K, V>::WeakMap(JSContext* cx, JSObject* memOf)
: Base(cx->zone()), WeakMapBase(memOf, cx->zone())
{
zone()->gcWeakMapList().insertFront(this);
@ -40,9 +40,9 @@ WeakMap<K, V, HP>::WeakMap(JSContext* cx, JSObject* memOf)
// This implementation does not use 'markedCell'; it looks up origKey and checks
// the mark bits on everything it cares about, one of which will be
// markedCell. But a subclass might use it to optimize the liveness check.
template <class K, class V, class HP>
template <class K, class V>
void
WeakMap<K, V, HP>::markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr origKey)
WeakMap<K, V>::markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr origKey)
{
MOZ_ASSERT(marked);
@ -64,9 +64,9 @@ WeakMap<K, V, HP>::markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellP
key.unsafeSet(nullptr); // Prevent destructor from running barriers.
}
template <class K, class V, class HP>
template <class K, class V>
void
WeakMap<K, V, HP>::trace(JSTracer* trc)
WeakMap<K, V>::trace(JSTracer* trc)
{
MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), isInList());
@ -94,9 +94,9 @@ WeakMap<K, V, HP>::trace(JSTracer* trc)
TraceEdge(trc, &r.front().value(), "WeakMap entry value");
}
template <class K, class V, class HP>
template <class K, class V>
/* static */ void
WeakMap<K, V, HP>::addWeakEntry(GCMarker* marker, JS::GCCellPtr key,
WeakMap<K, V>::addWeakEntry(GCMarker* marker, JS::GCCellPtr key,
const gc::WeakMarkable& markable)
{
Zone* zone = key.asCell()->asTenured().zone();
@ -114,9 +114,9 @@ WeakMap<K, V, HP>::addWeakEntry(GCMarker* marker, JS::GCCellPtr key,
}
}
template <class K, class V, class HP>
template <class K, class V>
bool
WeakMap<K, V, HP>::markIteratively(GCMarker* marker)
WeakMap<K, V>::markIteratively(GCMarker* marker)
{
MOZ_ASSERT(marked);
@ -152,10 +152,12 @@ WeakMap<K, V, HP>::markIteratively(GCMarker* marker)
return markedAny;
}
template <class K, class V, class HP>
template <class K, class V>
inline JSObject*
WeakMap<K, V, HP>::getDelegate(JSObject* key) const
WeakMap<K, V>::getDelegate(JSObject* key) const
{
JS::AutoSuppressGCAnalysis nogc;
JSWeakmapKeyDelegateOp op = key->getClass()->extWeakmapKeyDelegateOp();
if (!op)
return nullptr;
@ -168,23 +170,23 @@ WeakMap<K, V, HP>::getDelegate(JSObject* key) const
return obj;
}
template <class K, class V, class HP>
template <class K, class V>
inline JSObject*
WeakMap<K, V, HP>::getDelegate(JSScript* script) const
WeakMap<K, V>::getDelegate(JSScript* script) const
{
return nullptr;
}
template <class K, class V, class HP>
template <class K, class V>
inline JSObject*
WeakMap<K, V, HP>::getDelegate(LazyScript* script) const
WeakMap<K, V>::getDelegate(LazyScript* script) const
{
return nullptr;
}
template <class K, class V, class HP>
template <class K, class V>
inline bool
WeakMap<K, V, HP>::keyNeedsMark(JSObject* key) const
WeakMap<K, V>::keyNeedsMark(JSObject* key) const
{
JSObject* delegate = getDelegate(key);
/*
@ -194,24 +196,24 @@ WeakMap<K, V, HP>::keyNeedsMark(JSObject* key) const
return delegate && gc::IsMarkedUnbarriered(zone()->runtimeFromMainThread(), &delegate);
}
template <class K, class V, class HP>
template <class K, class V>
inline bool
WeakMap<K, V, HP>::keyNeedsMark(JSScript* script) const
WeakMap<K, V>::keyNeedsMark(JSScript* script) const
{
return false;
}
template <class K, class V, class HP>
template <class K, class V>
inline bool
WeakMap<K, V, HP>::keyNeedsMark(LazyScript* script) const
WeakMap<K, V>::keyNeedsMark(LazyScript* script) const
{
return false;
}
template <class K, class V, class HP>
template <class K, class V>
void
WeakMap<K, V, HP>::sweep()
WeakMap<K, V>::sweep()
{
/* Remove all entries whose keys remain unmarked. */
for (Enum e(*this); !e.empty(); e.popFront()) {
@ -227,9 +229,9 @@ WeakMap<K, V, HP>::sweep()
}
/* memberOf can be nullptr, which means that the map is not part of a JSObject. */
template <class K, class V, class HP>
template <class K, class V>
void
WeakMap<K, V, HP>::traceMappings(WeakMapTracer* tracer)
WeakMap<K, V>::traceMappings(WeakMapTracer* tracer)
{
for (Range r = Base::all(); !r.empty(); r.popFront()) {
gc::Cell* key = gc::ToMarkable(r.front().key());
@ -243,9 +245,9 @@ WeakMap<K, V, HP>::traceMappings(WeakMapTracer* tracer)
}
#if DEBUG
template <class K, class V, class HP>
template <class K, class V>
void
WeakMap<K, V, HP>::assertEntriesNotAboutToBeFinalized()
WeakMap<K, V>::assertEntriesNotAboutToBeFinalized()
{
for (Range r = Base::all(); !r.empty(); r.popFront()) {
K k(r.front().key());

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

@ -111,13 +111,12 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase>
bool marked;
};
template <class Key, class Value,
class HashPolicy = DefaultHasher<Key> >
class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
template <class Key, class Value>
class WeakMap : public HashMap<Key, Value, MovableCellHasher<Key>, ZoneAllocPolicy>,
public WeakMapBase
{
public:
typedef HashMap<Key, Value, HashPolicy, ZoneAllocPolicy> Base;
typedef HashMap<Key, Value, MovableCellHasher<Key>, ZoneAllocPolicy> Base;
typedef typename Base::Enum Enum;
typedef typename Base::Lookup Lookup;
typedef typename Base::Entry Entry;
@ -191,13 +190,11 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
};
class ObjectValueMap : public WeakMap<HeapPtr<JSObject*>, HeapPtr<Value>,
MovableCellHasher<HeapPtr<JSObject*>>>
class ObjectValueMap : public WeakMap<HeapPtr<JSObject*>, HeapPtr<Value>>
{
public:
ObjectValueMap(JSContext* cx, JSObject* obj)
: WeakMap<HeapPtr<JSObject*>, HeapPtr<Value>,
MovableCellHasher<HeapPtr<JSObject*>>>(cx, obj)
: WeakMap(cx, obj)
{}
bool findZoneEdges() override;

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

@ -41,9 +41,8 @@ template <typename K, typename V>
struct Utils
{
typedef typename DataType<K>::BarrieredType KeyType;
typedef typename DataType<K>::HasherType HasherType;
typedef typename DataType<V>::BarrieredType ValueType;
typedef WeakMap<KeyType, ValueType, HasherType> Type;
typedef WeakMap<KeyType, ValueType> Type;
typedef Type* PtrType;
static PtrType cast(void* ptr) { return static_cast<PtrType>(ptr); }
};

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

@ -1,4 +1,4 @@
// If debugger.onEnterFrame returns {return:val}, the frame returns immediately.
// If debugger.onEnterFrame returns null, the debuggee is terminated immediately.
load(libdir + "asserts.js");

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

@ -0,0 +1,26 @@
// frame.live is false for generator frames after they return.
let g = newGlobal();
g.eval("function* f() { debugger; }");
let dbg = Debugger(g);
let savedFrame;
dbg.onDebuggerStatement = frame => {
savedFrame = frame;
assertEq(frame.callee.name, "f");
assertEq(frame.live, true);
frame.onPop = function() {
assertEq(frame.live, true);
};
};
g.f().next();
assertEq(savedFrame.live, false);
try {
savedFrame.older;
throw new Error("expected exception, none thrown");
} catch (exc) {
assertEq(exc.message, "Debugger.Frame is not live");
}

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

@ -0,0 +1,53 @@
// frame.live is false for generator frames popped due to exception or termination.
load(libdir + "/asserts.js");
function test(when, what) {
let g = newGlobal();
g.eval("function* f(x) { yield x; }");
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let fw = gw.getOwnPropertyDescriptor("f").value;
let t = 0;
let poppedFrame;
function tick(frame) {
if (frame.callee == fw) {
if (t == when) {
poppedFrame = frame;
dbg.onEnterFrame = undefined;
frame.onPop = undefined;
return what;
}
t++;
}
return undefined;
}
dbg.onDebuggerStatement = frame => {
dbg.onEnterFrame = frame => {
frame.onPop = function() {
return tick(this);
};
return tick(frame);
};
let result = frame.eval("for (let _ of f(0)) {}");
assertDeepEq(result, what);
};
g.eval("debugger;");
assertEq(t, when);
assertEq(poppedFrame.live, false);
assertErrorMessage(() => poppedFrame.older,
Error,
"Debugger.Frame is not live");
}
for (let when = 0; when < 6; when++) {
for (let what of [null, {throw: "fit"}]) {
test(when, what);
}
}

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

@ -0,0 +1,26 @@
// Terminating a generator from the onPop callback for its initial yield
// leaves the Frame in a sane but inactive state.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval("function* f(x) { yield x; }");
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let genFrame = null;
dbg.onDebuggerStatement = frame => {
dbg.onEnterFrame = frame => {
if (frame.callee == gw.getOwnPropertyDescriptor("f").value) {
genFrame = frame;
frame.onPop = completion => null;
}
};
assertEq(frame.eval("f(0);"), null);
};
g.eval("debugger;");
assertEq(genFrame instanceof Debugger.Frame, true);
assertEq(genFrame.live, false);
assertThrowsInstanceOf(() => genFrame.callee, Error);

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

@ -1,20 +0,0 @@
// Returning {throw:} from an onPop handler when yielding works and
// closes the generator-iterator.
load(libdir + "iteration.js");
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
dbg.onDebuggerStatement = function handleDebugger(frame) {
frame.onPop = function (c) {
return {throw: "fit"};
};
};
g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
g.eval("var it = g();");
var rv = gw.executeInGlobal("it.next();");
assertEq(rv.throw, "fit");
dbg.enabled = false;
assertIteratorDone(g.it);

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

@ -1,21 +0,0 @@
// |jit-test| error: fit
// Throwing an exception from an onPop handler when yielding terminates the debuggee
// but does not close the generator-iterator.
load(libdir + 'iteration.js')
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
dbg.onDebuggerStatement = function handleDebugger(frame) {
frame.onPop = function (c) {
throw "fit";
};
};
g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
g.eval("var it = g();");
assertEq(gw.executeInGlobal("it.next();"), null);
dbg.enabled = false;
assertIteratorNext(g.it, 1);

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

@ -0,0 +1,31 @@
// Stepping into the `.next()` method of a generator works as expected.
let g = newGlobal();
g.eval(`\
function* nums() { // line 1
yield 1; // 2
yield 2; // 3
} // 4
function f() { // 5
let gen = nums(); // 6
gen.next(); // 7
gen.next(); // 8
gen.next(); // 9
} // 10
`);
let log = [];
let previousLine = -1;
let dbg = new Debugger(g);
dbg.onEnterFrame = frame => {
frame.onStep = () => {
let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
if (previousLine != line) { // We stepped to a new line.
log.push(line);
previousLine = line;
}
};
};
g.f();
assertEq(log.join(" "), "5 6 1 6 7 1 2 7 8 2 3 8 9 3 9 10");

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

@ -0,0 +1,44 @@
// Stepping into the `.throw()` method of a generator with no relevant catch block.
//
// The debugger fires onEnterFrame and then frame.onPop for the generator frame when
// `gen.throw()` is called.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`\
function* z() { // line 1
yield 1; // 2
yield 2; // 3
} // 4
function f() { // 5
let gen = z(); // 6
gen.next(); // 7
gen.throw("fit"); // 8
} // 9
`);
let log = "";
let previousLine = -1;
let dbg = new Debugger(g);
dbg.onEnterFrame = frame => {
log += frame.callee.name + "{";
frame.onStep = () => {
let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
if (previousLine != line) { // We stepped to a new line.
log += line;
previousLine = line;
}
};
frame.onPop = completion => {
if ("throw" in completion)
log += "!";
log += "}";
}
};
assertThrowsValue(() => g.f(), "fit");
// z{1} is the initial generator setup.
// z{12} is the first .next() call, running to `yield 1` on line 2
// The final `z{!}` is for the .throw() call.
assertEq(log, "f{56z{1}67z{12}78z{!}!}");

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

@ -0,0 +1,45 @@
// Stepping into the `.throw()` method of a generator with a relevant catch block.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`\
function* z() { // line 1
try { // 2
yield 1; // 3
} catch (exc) { // 4
yield 2; // 5
} // 6
} // 7
function f() { // 8
let gen = z(); // 9
gen.next(); // 10
gen.throw("fit"); // 11
} // 12
`);
let log = [];
let previousLine = -1;
let dbg = new Debugger(g);
dbg.onEnterFrame = frame => {
log.push(frame.callee.name + " in");
frame.onStep = () => {
let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
if (previousLine != line) { // We stepped to a new line.
log.push(line);
previousLine = line;
}
};
frame.onPop = completion => {
log.push(frame.callee.name + " out");
};
};
g.f();
assertEq(
log.join(", "),
"f in, 8, 9, z in, 1, z out, " +
"9, 10, z in, 1, 2, 3, z out, " +
"10, 11, z in, 2, 4, 5, z out, " + // not sure why we hit line 2 here, source notes bug maybe
"11, 12, f out"
);

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

@ -0,0 +1,33 @@
// onStep works during the evaluation of default parameter values in generators.
//
// (They're evaluated at a weird time in the generator life cycle, before the
// generator object is created.)
let g = newGlobal();
g.eval(`\
function f1() {} // line 1
function f2() {} // 2
function f3() {} // 3
// 4
function* gen( // 5
name, // 6
schema = f1(), // 7
timeToLive = f2(), // 8
lucidity = f3() // 9
) { // 10
} // 11
`);
let dbg = Debugger(g);
let log = [];
dbg.onEnterFrame = frame => {
frame.onStep = () => {
let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
if (log.length == 0 || line != log[log.length - 1]) {
log.push(line);
}
};
};
g.gen(0);
assertEq(log.toSource(), [5, 7, 1, 8, 2, 9, 3, 10].toSource());

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

@ -0,0 +1,42 @@
// Test for OOM hitting a breakpoint in a generator.
//
// (The purpose is to test OOM-handling in the code that creates the
// Debugger.Frame object and associates it with the generator object.)
if (!('oomTest' in this))
quit();
let g = newGlobal();
g.eval(`\
function* gen(x) { // line 1
x++; // 2
yield x; // 3
} // 4
`);
let dbg = new Debugger;
// On OOM in the debugger, propagate it to the debuggee.
dbg.uncaughtExceptionHook = exc => exc === "out of memory" ? {throw: exc} : null;
let gw = dbg.addDebuggee(g);
let script = gw.makeDebuggeeValue(g.gen).script;
let hits = 0;
let handler = {
hit(frame) {
hits++;
print("x=", frame.environment.getVariable("x"));
}
};
for (let offset of script.getLineOffsets(2))
script.setBreakpoint(offset, handler);
let result;
oomTest(() => {
hits = 0;
result = g.gen(1).next();
}, false);
assertEq(hits, 1);
assertEq(result.done, false);
assertEq(result.value, 2);

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

@ -0,0 +1,15 @@
// Bug 1479429 - Methods throw on out-of-range bytecode offsets.
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function(frame) {
assertThrowsInstanceOf(
() => frame.script.getPredecessorOffsets(0x400000),
TypeError);
assertThrowsInstanceOf(
() => frame.script.getSuccessorOffsets(-1),
TypeError);
}
g.eval("debugger;");

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

@ -0,0 +1,60 @@
// A Debugger can {return:} from onDebuggerStatement in an async generator.
// A resolved promise for a {value: _, done: true} object is returned.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`
async function* f(x) {
debugger; // when==0 to force return here
await x;
yield 1;
debugger; // when==1 to force return here
}
`);
let exc = null;
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
function test(when) {
let hits = 0;
let outcome = "FAIL";
dbg.onDebuggerStatement = frame => {
if (hits++ == when)
return {return: "ponies"};
};
let iter = g.f(0);
// At the initial suspend.
assertEq(hits, 0);
iter.next().then(result => {
// At the yield point, unless we already force-returned from the first
// debugger statement.
assertEq(hits, 1);
if (when == 0)
return result;
assertEq(result.value, 1);
assertEq(result.done, false);
return iter.next();
}).then(result => {
// After forced return.
assertEq(hits, when + 1);
assertEq(result.value, "ponies");
assertEq(result.done, true);
outcome = "pass";
}).catch(e => {
// An assertion failed.
exc = e;
});
assertEq(hits, 1);
drainJobQueue();
if (exc !== null)
throw exc;
assertEq(outcome, "pass");
}
for (let i = 0; i < 2; i++) {
test(i);
}

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

@ -0,0 +1,34 @@
// A Debugger can {return:} from onDebuggerStatement in an async function.
// The async function's promise is resolved with the returned value.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`
async function f(x) {
debugger; // when==0 to force return here
await x;
debugger; // when==1 to force return here
}
`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
function test(when, what, expected) {
let hits = 0;
let result = "FAIL";
dbg.onDebuggerStatement = frame => {
if (hits++ == when)
return {return: gw.makeDebuggeeValue(what)};
};
g.f(0).then(x => { result = x; });
assertEq(hits, 1);
drainJobQueue();
assertEq(hits, when + 1);
assertEq(result, expected);
}
for (let i = 0; i < 2; i++) {
test(i, "ok", "ok");
test(i, g.Promise.resolve(37), 37);
}

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

@ -0,0 +1,33 @@
// A Debugger can {return:} from the first onEnterFrame for an async function.
// (The exact behavior is undocumented; we're testing that it doesn't crash.)
let g = newGlobal();
g.hit2 = false;
g.eval(`async function f(x) { await x; return "ponies"; }`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let hits = 0;
let resumption = undefined;
dbg.onEnterFrame = frame => {
if (frame.type == "call" && frame.callee.name === "f") {
frame.onPop = completion => {
assertEq(completion.return, resumption.return);
hits++;
};
// Don't tell anyone, but if we force-return a generator object here,
// the robots accept it as one of their own and plug it right into the
// async function machinery. This may be handy against Skynet someday.
resumption = frame.eval(`(function* f2() { hit2 = true; throw "fit"; })()`);
assertEq(resumption.return.class, "Generator");
return resumption;
}
};
let p = g.f(0);
assertEq(hits, 1);
let pw = gw.makeDebuggeeValue(p);
assertEq(pw.isPromise, true);
assertEq(pw.promiseState, "rejected");
assertEq(pw.promiseReason, "fit");

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

@ -0,0 +1,36 @@
// A Debugger can {throw:} from onEnterFrame in an async function.
// The resulting promise (if any) is rejected with the thrown error value.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`
async function f() { await 1; }
var err = new TypeError("object too hairy");
`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let errw = gw.makeDebuggeeValue(g.err);
// Repeat the test for each onEnterFrame event.
// It fires up to three times:
// - when the async function g.f is called;
// - when we enter it to run to `await 1`;
// - when we resume after the await to run to the end.
for (let when = 0; when < 3; when++) {
let hits = 0;
dbg.onEnterFrame = frame => {
return hits++ < when ? undefined : {throw: errw};
};
let result = undefined;
g.f()
.then(value => { result = {returned: value}; })
.catch(err => { result = {threw: err}; });
drainJobQueue();
assertEq(hits, when + 1);
assertDeepEq(result, {threw: g.err});
}

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

@ -0,0 +1,30 @@
// A Debugger can {return:} from onEnterFrame at any resume point in an async function.
// The async function's promise is resolved with the returned value.
let g = newGlobal();
g.eval(`async function f(x) { await x; }`);
let dbg = new Debugger(g);
function test(when) {
let hits = 0;
dbg.onEnterFrame = frame => {
if (frame.type == "call" && frame.callee.name === "f") {
if (hits++ == when) {
return {return: "exit"};
}
}
};
let result = undefined;
let finished = false;
g.f("hello").then(value => { result = value; finished = true; });
drainJobQueue();
assertEq(finished, true);
assertEq(hits, when + 1);
assertEq(result, "exit");
}
// onEnterFrame with hits==0 is not a resume point; {return:} behaves differently there
// (see onEnterFrame-async-resumption-02.js).
test(1); // force return from first resume point, immediately after the initial suspend
test(2); // force return from second resume point, immediately after the await instruction

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

@ -0,0 +1,81 @@
// Frame properties and methods work in generator-resuming onEnterFrame events.
// Also tests onPop events, for good measure.
let g = newGlobal();
g.eval(`\
function* gen(lo, hi) {
var a = 1/2;
yield a;
yield a * a;
}
`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let hits = 0;
let savedScript = null;
let savedEnv = null;
let savedOffsets = new Set;
function check(frame) {
assertEq(frame.type, "call");
assertEq(frame.constructing, false);
assertEq(frame.callee, gw.makeDebuggeeValue(g.gen));
// `arguments` elements don't work in resumed generator frames,
// because generators don't keep the arguments around.
// The first onEnterFrame and onPop events can see them.
assertEq(frame.arguments.length, hits < 2 ? args.length : 0);
for (var i = 0; i < frame.arguments.length; i++) {
assertEq(frame.arguments.hasOwnProperty(i), true);
if (hits < 2)
assertEq(frame.arguments[i], gw.makeDebuggeeValue(args[i]), `arguments[${i}]`);
else
assertEq(frame.arguments[i], undefined);
}
if (savedEnv === null) {
savedEnv = frame.environment;
assertEq(savedScript, null);
savedScript = frame.script;
} else {
assertEq(frame.environment, savedEnv);
assertEq(frame.script, savedScript);
}
let a_expected = hits < 3 ? undefined : 1/2;
assertEq(savedEnv.getVariable("a"), a_expected);
assertEq(frame.generator, true);
assertEq(frame.live, true);
let pc = frame.offset;
assertEq(savedOffsets.has(pc), false);
savedOffsets.add(pc);
assertEq(frame.older, null);
assertEq(frame.this, gw);
assertEq(typeof frame.implementation, "string");
// And the moment of truth:
assertEq(frame.eval("2 + 2").return, 4);
assertEq(frame.eval("a").return, a_expected);
assertEq(frame.eval("if (a !== undefined) { assertEq(a < (lo + hi) / 2, true); } 7;").return, 7);
}
dbg.onEnterFrame = frame => {
if (frame.type === "eval")
return;
check(frame);
hits++;
frame.onPop = completion => {
check(frame);
hits++;
};
};
// g.gen ignores the arguments passed to it, but we use them to test
// frame.arguments.
let args = [0, 10, g, dbg];
for (let v of g.gen(...args)) {}
assertEq(hits, 8);

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

@ -0,0 +1,27 @@
// onEnterFrame fires after the [[GeneratorState]] is set to "executing".
//
// This test checks that Debugger doesn't accidentally make it possible to
// reenter a generator frame that's already on the stack. (Also tests a fun
// corner case in baseline debug-mode OSR.)
load(libdir + "asserts.js");
let g = newGlobal();
g.eval('function* f() { yield 1; yield 2; }');
let dbg = Debugger(g);
let genObj = null;
let hits = 0;
dbg.onEnterFrame = frame => {
// The first time onEnterFrame fires, there is no generator object, so
// there's nothing to test. The generator object doesn't exist until
// JSOP_GENERATOR is reached, right before the initial yield.
if (genObj !== null) {
dbg.removeDebuggee(g); // avoid the DebuggeeWouldRun exception
assertThrowsInstanceOf(() => genObj.next(), g.TypeError);
dbg.addDebuggee(g);
hits++;
}
};
genObj = g.f();
for (let x of genObj) {}
assertEq(hits, 3);

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

@ -0,0 +1,25 @@
// If onEnterFrame terminates a generator, the Frame is left in a sane but inactive state.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval("function* f(x) { yield x; }");
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
let genFrame = null;
dbg.onDebuggerStatement = frame => {
dbg.onEnterFrame = frame => {
if (frame.callee == gw.getOwnPropertyDescriptor("f").value) {
genFrame = frame;
return null;
}
};
assertEq(frame.eval("f(0);"), null);
};
g.eval("debugger;");
assertEq(genFrame instanceof Debugger.Frame, true);
assertEq(genFrame.live, false);
assertThrowsInstanceOf(() => genFrame.callee, Error);

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

@ -0,0 +1,36 @@
// A debugger can {throw:} from onEnterFrame at any resume point in a generator.
// It closes the generator.
load(libdir + "asserts.js");
let g = newGlobal();
g.eval(`
function* f() { yield 1; }
var exn = new TypeError("object too hairy");
`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);
// Repeat the test for each onEnterFrame event.
// It fires up to three times:
// - when the generator g.f is called;
// - when we enter it to run to `yield 1`;
// - when we resume after the yield to run to the end.
for (let i = 0; i < 3; i++) {
let hits = 0;
dbg.onEnterFrame = frame => {
return hits++ < i ? undefined : {throw: gw.makeDebuggeeValue(g.exn)};
};
let genObj;
assertThrowsValue(
() => {
genObj = g.f();
for (let x of genObj) {}
},
g.exn
);
assertEq(hits, i + 1);
if (hits > 1)
assertEq(genObj.next().done, true);
}

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

@ -0,0 +1,39 @@
// A Debugger can {return:} from onEnterFrame at any resume point in a generator.
// Force-returning closes the generator.
load(libdir + "asserts.js");
let g = newGlobal();
g.values = [1, 2, 3];
g.eval(`function* f() { yield* values; }`);
let dbg = Debugger(g);
// onEnterFrame will fire up to 5 times.
// - once for the initial call to g.f();
// - four times at resume points:
// - initial resume at the top of the generator body
// - resume after yielding 1
// - resume after yielding 2
// - resume after yielding 3 (this resumption will run to the end).
// This test ignores the initial call and focuses on resume points.
for (let i = 1; i < 5; i++) {
let hits = 0;
dbg.onEnterFrame = frame => {
return hits++ < i ? undefined : {return: "we're done here"};
};
let genObj = g.f();
let actual = [];
while (true) {
let r = genObj.next();
if (r.done) {
assertDeepEq(r, {value: "we're done here", done: true});
break;
}
actual.push(r.value);
}
assertEq(hits, i + 1);
assertDeepEq(actual, g.values.slice(0, i - 1));
assertDeepEq(genObj.next(), {value: undefined, done: true});
}

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

@ -0,0 +1,35 @@
// Returning {throw:} from onEnterFrame when resuming inside a try block in a
// generator causes control to jump to the catch block.
let g = newGlobal();
g.eval(`
function* gen() {
try {
yield 0;
return "fail";
} catch (exc) {
assertEq(exc, "fit");
return "ok";
}
}
`)
let dbg = new Debugger(g);
let hits = 0;
dbg.onEnterFrame = frame => {
assertEq(frame.callee.name, "gen");
if (++hits == 3) {
// First hit is when calling gen();
// second hit is resuming at the implicit initial yield;
// third hit is resuming inside the try block.
return {throw: "fit"};
}
};
let it = g.gen();
let result = it.next();
assertEq(result.done, false);
assertEq(result.value, 0);
result = it.next();
assertEq(result.done, true);
assertEq(result.value, "ok");

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

@ -4647,7 +4647,7 @@ BaselineCompiler::emit_JSOP_AWAIT()
return emit_JSOP_YIELD();
}
typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
static const VMFunction DebugAfterYieldInfo =
FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
@ -4660,8 +4660,21 @@ BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD()
frame.assertSyncedStack();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
prepareVMCall();
pushArg(ImmPtr(pc));
pushArg(R0.scratchReg());
return callVM(DebugAfterYieldInfo);
if (!callVM(DebugAfterYieldInfo))
return false;
icEntries_.back().setFakeKind(ICEntry::Kind_DebugAfterYield);
Label done;
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
{
masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
masm.jump(&return_);
}
masm.bind(&done);
return true;
}
typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, jsbytecode*);
@ -4693,7 +4706,7 @@ static const VMFunction InterpretResumeInfo =
typedef bool (*GeneratorThrowFn)(JSContext*, BaselineFrame*, Handle<GeneratorObject*>,
HandleValue, uint32_t);
static const VMFunction GeneratorThrowInfo =
static const VMFunction GeneratorThrowOrReturnInfo =
FunctionInfo<GeneratorThrowFn>(jit::GeneratorThrowOrReturn, "GeneratorThrowOrReturn", TailCall);
bool
@ -4878,7 +4891,7 @@ BaselineCompiler::emit_JSOP_RESUME()
pushArg(genObj);
pushArg(scratch2);
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowInfo);
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowOrReturnInfo);
// Create the frame descriptor.
masm.subStackPtrFrom(scratch1);

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

@ -103,6 +103,7 @@ struct DebugModeOSREntry
frameKind == ICEntry::Kind_EarlyStackCheck ||
frameKind == ICEntry::Kind_DebugTrap ||
frameKind == ICEntry::Kind_DebugPrologue ||
frameKind == ICEntry::Kind_DebugAfterYield ||
frameKind == ICEntry::Kind_DebugEpilogue;
}
@ -307,6 +308,8 @@ ICEntryKindToString(ICEntry::Kind kind)
return "debug trap";
case ICEntry::Kind_DebugPrologue:
return "debug prologue";
case ICEntry::Kind_DebugAfterYield:
return "debug after yield";
case ICEntry::Kind_DebugEpilogue:
return "debug epilogue";
default:
@ -367,6 +370,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
// - All the ways above.
// C. From the debug trap handler.
// D. From the debug prologue.
// K. From a JSOP_DEBUGAFTERYIELD instruction.
// E. From the debug epilogue.
//
// Cycles (On to Off to On)+ or (Off to On to Off)+:
@ -470,6 +474,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
kind == ICEntry::Kind_EarlyStackCheck ||
kind == ICEntry::Kind_DebugTrap ||
kind == ICEntry::Kind_DebugPrologue ||
kind == ICEntry::Kind_DebugAfterYield ||
kind == ICEntry::Kind_DebugEpilogue);
// We will have allocated a new recompile info, so delete the
@ -546,6 +551,17 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
popFrameReg = true;
break;
case ICEntry::Kind_DebugAfterYield:
// Case K above.
//
// Resume at the next instruction.
MOZ_ASSERT(*pc == JSOP_DEBUGAFTERYIELD);
recompInfo->resumeAddr = bl->nativeCodeForPC(script,
pc + JSOP_DEBUGAFTERYIELD_LENGTH,
&recompInfo->slotInfo);
popFrameReg = true;
break;
default:
// Case E above.
//
@ -945,9 +961,9 @@ HasForcedReturn(BaselineDebugModeOSRInfo* info, bool rv)
if (kind == ICEntry::Kind_DebugEpilogue)
return true;
// |rv| is the value in ReturnReg. If true, in the case of the prologue,
// it means a forced return.
if (kind == ICEntry::Kind_DebugPrologue)
// |rv| is the value in ReturnReg. If true, in the case of the prologue or
// after yield, it means a forced return.
if (kind == ICEntry::Kind_DebugPrologue || kind == ICEntry::Kind_DebugAfterYield)
return rv;
// N.B. The debug trap handler handles its own forced return, so no

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