зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
d21b936680
|
@ -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,47 +44,49 @@ class BoxModel extends PureComponent {
|
|||
render() {
|
||||
const {
|
||||
boxModel,
|
||||
setSelectedNode,
|
||||
showBoxModelProperties,
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelEditor,
|
||||
onShowBoxModelHighlighter,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
onToggleGeometryEditor,
|
||||
setSelectedNode,
|
||||
showBoxModelProperties,
|
||||
} = this.props;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "boxmodel-container",
|
||||
tabIndex: 0,
|
||||
ref: div => {
|
||||
this.boxModelContainer = div;
|
||||
return (
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-container",
|
||||
tabIndex: 0,
|
||||
ref: div => {
|
||||
this.boxModelContainer = div;
|
||||
},
|
||||
onKeyDown: this.onKeyDown,
|
||||
},
|
||||
onKeyDown: this.onKeyDown,
|
||||
},
|
||||
BoxModelMain({
|
||||
boxModel,
|
||||
boxModelContainer: this.boxModelContainer,
|
||||
ref: boxModelMain => {
|
||||
this.boxModelMain = boxModelMain;
|
||||
},
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelEditor,
|
||||
onShowBoxModelHighlighter,
|
||||
}),
|
||||
BoxModelInfo({
|
||||
boxModel,
|
||||
onToggleGeometryEditor,
|
||||
}),
|
||||
showBoxModelProperties ?
|
||||
BoxModelProperties({
|
||||
BoxModelMain({
|
||||
boxModel,
|
||||
setSelectedNode,
|
||||
boxModelContainer: this.boxModelContainer,
|
||||
ref: boxModelMain => {
|
||||
this.boxModelMain = boxModelMain;
|
||||
},
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
})
|
||||
:
|
||||
null
|
||||
onShowBoxModelEditor,
|
||||
onShowBoxModelHighlighter,
|
||||
}),
|
||||
BoxModelInfo({
|
||||
boxModel,
|
||||
onToggleGeometryEditor,
|
||||
}),
|
||||
showBoxModelProperties ?
|
||||
BoxModelProperties({
|
||||
boxModel,
|
||||
setSelectedNode,
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
})
|
||||
:
|
||||
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,23 +49,25 @@ class BoxModelEditable extends PureComponent {
|
|||
box !== "position" &&
|
||||
textContent.toString().length > LONG_TEXT_ROTATE_LIMIT;
|
||||
|
||||
return dom.p(
|
||||
{
|
||||
className: `boxmodel-${box}
|
||||
${direction ? " boxmodel-" + direction : "boxmodel-" + property}
|
||||
${rotate ? " boxmodel-rotate" : ""}`,
|
||||
},
|
||||
dom.span(
|
||||
return (
|
||||
dom.p(
|
||||
{
|
||||
className: "boxmodel-editable",
|
||||
"data-box": box,
|
||||
tabIndex: box === level && focusable ? 0 : -1,
|
||||
title: property,
|
||||
ref: span => {
|
||||
this.boxModelEditable = span;
|
||||
},
|
||||
className: `boxmodel-${box}
|
||||
${direction ? " boxmodel-" + direction : "boxmodel-" + property}
|
||||
${rotate ? " boxmodel-rotate" : ""}`,
|
||||
},
|
||||
textContent
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-editable",
|
||||
"data-box": box,
|
||||
tabIndex: box === level && focusable ? 0 : -1,
|
||||
title: property,
|
||||
ref: span => {
|
||||
this.boxModelEditable = span;
|
||||
},
|
||||
},
|
||||
textContent
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,33 +49,21 @@ class BoxModelInfo extends PureComponent {
|
|||
buttonClass += " checked";
|
||||
}
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "boxmodel-info",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-element-size",
|
||||
},
|
||||
SHARED_L10N.getFormatStr("dimensions", width, height)
|
||||
),
|
||||
dom.section(
|
||||
{
|
||||
className: "boxmodel-position-group",
|
||||
},
|
||||
isPositionEditable ?
|
||||
dom.button({
|
||||
className: buttonClass,
|
||||
title: BOXMODEL_L10N.getStr("boxmodel.geometryButton.tooltip"),
|
||||
onClick: this.onToggleGeometryEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-element-position",
|
||||
},
|
||||
position
|
||||
return (
|
||||
dom.div({ className: "boxmodel-info" },
|
||||
dom.span({ className: "boxmodel-element-size" },
|
||||
SHARED_L10N.getFormatStr("dimensions", width, height)
|
||||
),
|
||||
dom.section({ className: "boxmodel-position-group" },
|
||||
isPositionEditable ?
|
||||
dom.button({
|
||||
className: buttonClass,
|
||||
title: BOXMODEL_L10N.getStr("boxmodel.geometryButton.tooltip"),
|
||||
onClick: this.onToggleGeometryEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
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,277 +437,270 @@ 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(
|
||||
{
|
||||
className: "boxmodel-main devtools-monospace",
|
||||
"data-box": "position",
|
||||
ref: div => {
|
||||
this.positionLayout = div;
|
||||
},
|
||||
onClick: this.onLevelClick,
|
||||
onKeyDown: this.onKeyDown,
|
||||
onMouseOver: this.onHighlightMouseOver,
|
||||
onMouseOut: this.props.onHideBoxModelHighlighter,
|
||||
},
|
||||
displayPosition ?
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "position",
|
||||
title: "position",
|
||||
},
|
||||
"position"
|
||||
)
|
||||
:
|
||||
null,
|
||||
return (
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-box"
|
||||
className: "boxmodel-main devtools-monospace",
|
||||
"data-box": "position",
|
||||
ref: div => {
|
||||
this.positionLayout = div;
|
||||
},
|
||||
onClick: this.onLevelClick,
|
||||
onKeyDown: this.onKeyDown,
|
||||
onMouseOver: this.onHighlightMouseOver,
|
||||
onMouseOut: this.props.onHideBoxModelHighlighter,
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "margin",
|
||||
title: "margin",
|
||||
},
|
||||
"margin"
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-margins",
|
||||
"data-box": "margin",
|
||||
title: "margin",
|
||||
ref: div => {
|
||||
this.marginLayout = div;
|
||||
},
|
||||
},
|
||||
displayPosition ?
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "border",
|
||||
title: "border",
|
||||
"data-box": "position",
|
||||
title: "position",
|
||||
},
|
||||
"border"
|
||||
"position"
|
||||
)
|
||||
:
|
||||
null,
|
||||
dom.div({ className: "boxmodel-box" },
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "margin",
|
||||
title: "margin",
|
||||
},
|
||||
"margin"
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-borders",
|
||||
"data-box": "border",
|
||||
title: "border",
|
||||
className: "boxmodel-margins",
|
||||
"data-box": "margin",
|
||||
title: "margin",
|
||||
ref: div => {
|
||||
this.borderLayout = div;
|
||||
this.marginLayout = div;
|
||||
},
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "padding",
|
||||
title: "padding",
|
||||
"data-box": "border",
|
||||
title: "border",
|
||||
},
|
||||
"padding"
|
||||
"border"
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-paddings",
|
||||
"data-box": "padding",
|
||||
title: "padding",
|
||||
className: "boxmodel-borders",
|
||||
"data-box": "border",
|
||||
title: "border",
|
||||
ref: div => {
|
||||
this.paddingLayout = div;
|
||||
this.borderLayout = div;
|
||||
},
|
||||
},
|
||||
dom.div({
|
||||
className: "boxmodel-contents",
|
||||
"data-box": "content",
|
||||
title: "content",
|
||||
ref: div => {
|
||||
this.contentLayout = div;
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-legend",
|
||||
"data-box": "padding",
|
||||
title: "padding",
|
||||
},
|
||||
})
|
||||
"padding"
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "boxmodel-paddings",
|
||||
"data-box": "padding",
|
||||
title: "padding",
|
||||
ref: div => {
|
||||
this.paddingLayout = div;
|
||||
},
|
||||
},
|
||||
dom.div({
|
||||
className: "boxmodel-contents",
|
||||
"data-box": "content",
|
||||
title: "content",
|
||||
ref: div => {
|
||||
this.contentLayout = div;
|
||||
},
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
displayPosition ?
|
||||
),
|
||||
displayPosition ?
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-top",
|
||||
ref: editable => {
|
||||
this.positionEditable = editable;
|
||||
},
|
||||
textContent: positionTop,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-right",
|
||||
textContent: positionRight,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-bottom",
|
||||
textContent: positionBottom,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-left",
|
||||
textContent: positionLeft,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
box: "margin",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-top",
|
||||
property: "margin-top",
|
||||
ref: editable => {
|
||||
this.positionEditable = editable;
|
||||
this.marginEditable = editable;
|
||||
},
|
||||
textContent: positionTop,
|
||||
textContent: marginTop,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
box: "margin",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-right",
|
||||
textContent: positionRight,
|
||||
property: "margin-right",
|
||||
textContent: marginRight,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
box: "margin",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-bottom",
|
||||
textContent: positionBottom,
|
||||
property: "margin-bottom",
|
||||
textContent: marginBottom,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
displayPosition ?
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "position",
|
||||
box: "margin",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "position-left",
|
||||
textContent: positionLeft,
|
||||
property: "margin-left",
|
||||
textContent: marginLeft,
|
||||
onShowBoxModelEditor,
|
||||
})
|
||||
:
|
||||
null,
|
||||
BoxModelEditable({
|
||||
box: "margin",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "margin-top",
|
||||
ref: editable => {
|
||||
this.marginEditable = editable;
|
||||
},
|
||||
textContent: marginTop,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "margin",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "margin-right",
|
||||
textContent: marginRight,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "margin",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "margin-bottom",
|
||||
textContent: marginBottom,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "margin",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "margin-left",
|
||||
textContent: marginLeft,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-top-width",
|
||||
ref: editable => {
|
||||
this.borderEditable = editable;
|
||||
},
|
||||
textContent: borderTop,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-right-width",
|
||||
textContent: borderRight,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-bottom-width",
|
||||
textContent: borderBottom,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-left-width",
|
||||
textContent: borderLeft,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-top",
|
||||
ref: editable => {
|
||||
this.paddingEditable = editable;
|
||||
},
|
||||
textContent: paddingTop,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-right",
|
||||
textContent: paddingRight,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-bottom",
|
||||
textContent: paddingBottom,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-left",
|
||||
textContent: paddingLeft,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
contentBox
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-top-width",
|
||||
ref: editable => {
|
||||
this.borderEditable = editable;
|
||||
},
|
||||
textContent: borderTop,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-right-width",
|
||||
textContent: borderRight,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-bottom-width",
|
||||
textContent: borderBottom,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "border",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "border-left-width",
|
||||
textContent: borderLeft,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "top",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-top",
|
||||
ref: editable => {
|
||||
this.paddingEditable = editable;
|
||||
},
|
||||
textContent: paddingTop,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "right",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-right",
|
||||
textContent: paddingRight,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "bottom",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-bottom",
|
||||
textContent: paddingBottom,
|
||||
onShowBoxModelEditor,
|
||||
}),
|
||||
BoxModelEditable({
|
||||
box: "padding",
|
||||
direction: "left",
|
||||
focusable,
|
||||
level,
|
||||
property: "padding-left",
|
||||
textContent: paddingLeft,
|
||||
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,13 +81,7 @@ 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,65 +63,48 @@ 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(
|
||||
{},
|
||||
dom.input(
|
||||
{
|
||||
id: "grid-setting-show-grid-line-numbers",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showGridLineNumbers,
|
||||
onChange: this.onShowGridLineNumbersCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.displayLineNumbers")
|
||||
)
|
||||
),
|
||||
dom.li(
|
||||
{
|
||||
className: "grid-settings-item",
|
||||
},
|
||||
dom.label(
|
||||
{},
|
||||
dom.input(
|
||||
{
|
||||
id: "grid-setting-show-grid-areas",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showGridAreasOverlay,
|
||||
onChange: this.onShowGridAreasCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.displayAreaNames")
|
||||
)
|
||||
),
|
||||
dom.li(
|
||||
{
|
||||
className: "grid-settings-item",
|
||||
},
|
||||
dom.label(
|
||||
{},
|
||||
dom.input(
|
||||
{
|
||||
id: "grid-setting-extend-grid-lines",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showInfiniteLines,
|
||||
onChange: this.onShowInfiniteLinesCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.extendLinesInfinitely")
|
||||
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",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showGridLineNumbers,
|
||||
onChange: this.onShowGridLineNumbersCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.displayLineNumbers")
|
||||
)
|
||||
),
|
||||
dom.li({ className: "grid-settings-item" },
|
||||
dom.label({},
|
||||
dom.input(
|
||||
{
|
||||
id: "grid-setting-show-grid-areas",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showGridAreasOverlay,
|
||||
onChange: this.onShowGridAreasCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.displayAreaNames")
|
||||
)
|
||||
),
|
||||
dom.li({ className: "grid-settings-item" },
|
||||
dom.label({},
|
||||
dom.input(
|
||||
{
|
||||
id: "grid-setting-extend-grid-lines",
|
||||
type: "checkbox",
|
||||
checked: highlighterSettings.showInfiniteLines,
|
||||
onChange: this.onShowInfiniteLinesCheckboxClick,
|
||||
}
|
||||
),
|
||||
getStr("layout.extendLinesInfinitely")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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,47 +98,42 @@ class GridItem extends PureComponent {
|
|||
} = this.props;
|
||||
const { nodeFront } = grid;
|
||||
|
||||
return dom.li(
|
||||
{},
|
||||
dom.label(
|
||||
{},
|
||||
dom.input(
|
||||
return (
|
||||
dom.li({},
|
||||
dom.label({},
|
||||
dom.input(
|
||||
{
|
||||
checked: grid.highlighted,
|
||||
type: "checkbox",
|
||||
value: grid.id,
|
||||
onChange: this.onGridCheckboxClick,
|
||||
}
|
||||
),
|
||||
Rep(
|
||||
{
|
||||
defaultRep: ElementNode,
|
||||
mode: MODE.TINY,
|
||||
object: translateNodeFrontToGrip(nodeFront),
|
||||
onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
|
||||
onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
|
||||
onInspectIconClick: () => this.onGridInspectIconClick(nodeFront),
|
||||
}
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
checked: grid.highlighted,
|
||||
type: "checkbox",
|
||||
value: grid.id,
|
||||
onChange: this.onGridCheckboxClick,
|
||||
className: "grid-color-swatch",
|
||||
style: {
|
||||
backgroundColor: grid.color,
|
||||
},
|
||||
title: grid.color,
|
||||
}
|
||||
),
|
||||
Rep(
|
||||
{
|
||||
defaultRep: ElementNode,
|
||||
mode: MODE.TINY,
|
||||
object: translateNodeFrontToGrip(nodeFront),
|
||||
onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
|
||||
onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
|
||||
onInspectIconClick: () => this.onGridInspectIconClick(nodeFront),
|
||||
}
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "grid-color-swatch",
|
||||
style: {
|
||||
backgroundColor: grid.color,
|
||||
},
|
||||
title: grid.color,
|
||||
}
|
||||
),
|
||||
// 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
|
||||
// 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)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,36 +30,32 @@ 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")
|
||||
),
|
||||
dom.ul(
|
||||
{
|
||||
id: "grid-list",
|
||||
className: "devtools-monospace",
|
||||
},
|
||||
grids.map(grid => GridItem({
|
||||
key: grid.id,
|
||||
getSwatchColorPickerTooltip,
|
||||
grid,
|
||||
setSelectedNode,
|
||||
onHideBoxModelHighlighter,
|
||||
onSetGridOverlayColor,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
onToggleGridHighlighter,
|
||||
}))
|
||||
return (
|
||||
dom.div({ className: "grid-container" },
|
||||
dom.span({}, getStr("layout.overlayGrid")),
|
||||
dom.ul(
|
||||
{
|
||||
id: "grid-list",
|
||||
className: "devtools-monospace",
|
||||
},
|
||||
grids.map(grid => GridItem({
|
||||
key: grid.id,
|
||||
getSwatchColorPickerTooltip,
|
||||
grid,
|
||||
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" },
|
||||
Accordion({ items })
|
||||
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,53 +222,52 @@ class App extends Component {
|
|||
deviceAdderViewportTemplate = viewports[devices.modalOpenedFromViewport];
|
||||
}
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
id: "app",
|
||||
},
|
||||
Toolbar({
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
viewport: viewports[0],
|
||||
onChangeDevice,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onScreenshot,
|
||||
onToggleLeftAlignment,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
Viewports({
|
||||
screenshot,
|
||||
viewports,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
}),
|
||||
devices.isModalOpen ?
|
||||
DeviceModal({
|
||||
deviceAdderViewportTemplate,
|
||||
return (
|
||||
dom.div({ id: "app" },
|
||||
Toolbar({
|
||||
devices,
|
||||
onAddCustomDevice,
|
||||
onDeviceListUpdate,
|
||||
onRemoveCustomDevice,
|
||||
onUpdateDeviceDisplayed,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
viewport: viewports[0],
|
||||
onChangeDevice,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onScreenshot,
|
||||
onToggleLeftAlignment,
|
||||
onUpdateDeviceModal,
|
||||
})
|
||||
:
|
||||
null
|
||||
}),
|
||||
Viewports({
|
||||
screenshot,
|
||||
viewports,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
}),
|
||||
devices.isModalOpen ?
|
||||
DeviceModal({
|
||||
deviceAdderViewportTemplate,
|
||||
devices,
|
||||
onAddCustomDevice,
|
||||
onDeviceListUpdate,
|
||||
onRemoveCustomDevice,
|
||||
onUpdateDeviceDisplayed,
|
||||
onUpdateDeviceModal,
|
||||
})
|
||||
:
|
||||
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,22 +149,24 @@ 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(
|
||||
{
|
||||
allowFullScreen: "true",
|
||||
className: "browser",
|
||||
height: "100%",
|
||||
mozbrowser: "true",
|
||||
noisolation: "true",
|
||||
remote: "true",
|
||||
remotetype: "web",
|
||||
src: "about:blank",
|
||||
usercontextid: userContextId,
|
||||
width: "100%",
|
||||
ref: browser => {
|
||||
this.browser = browser;
|
||||
},
|
||||
}
|
||||
return (
|
||||
dom.iframe(
|
||||
{
|
||||
allowFullScreen: "true",
|
||||
className: "browser",
|
||||
height: "100%",
|
||||
mozbrowser: "true",
|
||||
noisolation: "true",
|
||||
remote: "true",
|
||||
remotetype: "web",
|
||||
src: "about:blank",
|
||||
usercontextid: userContextId,
|
||||
width: "100%",
|
||||
ref: browser => {
|
||||
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,121 +136,81 @@ 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",
|
||||
},
|
||||
getStr("responsive.deviceAdderName")
|
||||
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({
|
||||
defaultValue: deviceName,
|
||||
ref: input => {
|
||||
this.nameInput = input;
|
||||
},
|
||||
})
|
||||
),
|
||||
dom.input({
|
||||
defaultValue: deviceName,
|
||||
ref: input => {
|
||||
this.nameInput = input;
|
||||
},
|
||||
})
|
||||
dom.label({ id: "device-adder-size" },
|
||||
dom.span({ className: "device-adder-label" },
|
||||
getStr("responsive.deviceAdderSize")
|
||||
),
|
||||
ViewportDimension({
|
||||
viewport: {
|
||||
width,
|
||||
height,
|
||||
},
|
||||
onResizeViewport: this.onChangeSize,
|
||||
onRemoveDeviceAssociation: () => {},
|
||||
})
|
||||
),
|
||||
dom.label({ id: "device-adder-pixel-ratio" },
|
||||
dom.span({ className: "device-adder-label" },
|
||||
getStr("responsive.deviceAdderPixelRatio")
|
||||
),
|
||||
dom.input({
|
||||
type: "number",
|
||||
step: "any",
|
||||
defaultValue: normalizedViewport.pixelRatio,
|
||||
ref: input => {
|
||||
this.pixelRatioInput = input;
|
||||
},
|
||||
})
|
||||
)
|
||||
),
|
||||
dom.label(
|
||||
{
|
||||
id: "device-adder-size",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "device-adder-label"
|
||||
},
|
||||
getStr("responsive.deviceAdderSize")
|
||||
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({
|
||||
defaultValue: normalizedViewport.userAgent,
|
||||
ref: input => {
|
||||
this.userAgentInput = input;
|
||||
},
|
||||
})
|
||||
),
|
||||
ViewportDimension({
|
||||
viewport: {
|
||||
width,
|
||||
height,
|
||||
},
|
||||
onResizeViewport: this.onChangeSize,
|
||||
onRemoveDeviceAssociation: () => {},
|
||||
})
|
||||
dom.label({ id: "device-adder-touch" },
|
||||
dom.span({ className: "device-adder-label" },
|
||||
getStr("responsive.deviceAdderTouch")
|
||||
),
|
||||
dom.input({
|
||||
defaultChecked: normalizedViewport.touch,
|
||||
type: "checkbox",
|
||||
ref: input => {
|
||||
this.touchInput = input;
|
||||
},
|
||||
})
|
||||
)
|
||||
),
|
||||
dom.label(
|
||||
{
|
||||
id: "device-adder-pixel-ratio",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "device-adder-label"
|
||||
},
|
||||
getStr("responsive.deviceAdderPixelRatio")
|
||||
),
|
||||
dom.input({
|
||||
type: "number",
|
||||
step: "any",
|
||||
defaultValue: normalizedViewport.pixelRatio,
|
||||
ref: input => {
|
||||
this.pixelRatioInput = input;
|
||||
},
|
||||
})
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
dom.button(
|
||||
{
|
||||
id: "device-adder-column-2",
|
||||
id: "device-adder-save",
|
||||
onClick: this.onDeviceAdderSave,
|
||||
},
|
||||
dom.label(
|
||||
{
|
||||
id: "device-adder-user-agent",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "device-adder-label"
|
||||
},
|
||||
getStr("responsive.deviceAdderUserAgent")
|
||||
),
|
||||
dom.input({
|
||||
defaultValue: normalizedViewport.userAgent,
|
||||
ref: input => {
|
||||
this.userAgentInput = input;
|
||||
},
|
||||
})
|
||||
),
|
||||
dom.label(
|
||||
{
|
||||
id: "device-adder-touch",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "device-adder-label"
|
||||
},
|
||||
getStr("responsive.deviceAdderTouch")
|
||||
),
|
||||
dom.input({
|
||||
defaultChecked: normalizedViewport.touch,
|
||||
type: "checkbox",
|
||||
ref: input => {
|
||||
this.touchInput = input;
|
||||
},
|
||||
})
|
||||
)
|
||||
),
|
||||
),
|
||||
dom.button(
|
||||
{
|
||||
id: "device-adder-save",
|
||||
onClick: this.onDeviceAdderSave,
|
||||
},
|
||||
getStr("responsive.deviceAdderSave")
|
||||
getStr("responsive.deviceAdderSave")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -133,93 +133,86 @@ class DeviceModal extends PureComponent {
|
|||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
id: "device-modal-wrapper",
|
||||
className: this.props.devices.isModalOpen ? "opened" : "closed",
|
||||
},
|
||||
return (
|
||||
dom.div(
|
||||
{
|
||||
className: "device-modal",
|
||||
id: "device-modal-wrapper",
|
||||
className: this.props.devices.isModalOpen ? "opened" : "closed",
|
||||
},
|
||||
dom.button({
|
||||
id: "device-close-button",
|
||||
className: "devtools-button",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
}),
|
||||
dom.div({ className: "device-modal" },
|
||||
dom.button({
|
||||
id: "device-close-button",
|
||||
className: "devtools-button",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
}),
|
||||
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" },
|
||||
type
|
||||
),
|
||||
sortedDevices[type].map(device => {
|
||||
const details = getFormatStr(
|
||||
"responsive.deviceDetails", device.width, device.height,
|
||||
device.pixelRatio, device.userAgent, device.touch
|
||||
);
|
||||
|
||||
let removeDeviceButton;
|
||||
if (type == "custom") {
|
||||
removeDeviceButton = dom.button({
|
||||
className: "device-remove-button devtools-button",
|
||||
onClick: () => onRemoveCustomDevice(device),
|
||||
});
|
||||
}
|
||||
|
||||
return dom.label(
|
||||
{
|
||||
className: "device-label",
|
||||
key: device.name,
|
||||
title: details,
|
||||
},
|
||||
dom.input({
|
||||
className: "device-input-checkbox",
|
||||
type: "checkbox",
|
||||
value: device.name,
|
||||
checked: this.state[device.name],
|
||||
onChange: this.onDeviceCheckboxChange,
|
||||
}),
|
||||
dom.span(
|
||||
{
|
||||
className: "device-name",
|
||||
},
|
||||
device.name
|
||||
),
|
||||
removeDeviceButton
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
),
|
||||
DeviceAdder({
|
||||
devices,
|
||||
viewportTemplate: deviceAdderViewportTemplate,
|
||||
onAddCustomDevice,
|
||||
}),
|
||||
dom.button(
|
||||
{
|
||||
id: "device-submit-button",
|
||||
onClick: this.onDeviceModalSubmit,
|
||||
},
|
||||
getStr("responsive.done")
|
||||
)
|
||||
),
|
||||
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",
|
||||
},
|
||||
type
|
||||
),
|
||||
sortedDevices[type].map(device => {
|
||||
const details = getFormatStr(
|
||||
"responsive.deviceDetails", device.width, device.height,
|
||||
device.pixelRatio, device.userAgent, device.touch
|
||||
);
|
||||
|
||||
let removeDeviceButton;
|
||||
if (type == "custom") {
|
||||
removeDeviceButton = dom.button({
|
||||
className: "device-remove-button devtools-button",
|
||||
onClick: () => onRemoveCustomDevice(device),
|
||||
});
|
||||
}
|
||||
|
||||
return dom.label(
|
||||
{
|
||||
className: "device-label",
|
||||
key: device.name,
|
||||
title: details,
|
||||
},
|
||||
dom.input({
|
||||
className: "device-input-checkbox",
|
||||
type: "checkbox",
|
||||
value: device.name,
|
||||
checked: this.state[device.name],
|
||||
onChange: this.onDeviceCheckboxChange,
|
||||
}),
|
||||
dom.span(
|
||||
{
|
||||
className: "device-name",
|
||||
},
|
||||
device.name
|
||||
),
|
||||
removeDeviceButton
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
),
|
||||
DeviceAdder({
|
||||
devices,
|
||||
viewportTemplate: deviceAdderViewportTemplate,
|
||||
onAddCustomDevice,
|
||||
}),
|
||||
dom.button(
|
||||
{
|
||||
id: "device-submit-button",
|
||||
onClick: this.onDeviceModalSubmit,
|
||||
},
|
||||
getStr("responsive.done")
|
||||
className: "modal-overlay",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
}
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "modal-overlay",
|
||||
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,
|
||||
op.updatedRegion(),
|
||||
thebes->GetValidRegion()))
|
||||
{
|
||||
if (!aCompositable->UpdateThebes(bufferData,
|
||||
op.updatedRegion(),
|
||||
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=", "]");
|
||||
|
@ -247,10 +236,10 @@ WebRenderImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
|
||||
void
|
||||
WebRenderImageHost::Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml)
|
||||
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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче