merge inbound to central. r=merge a=merge

This commit is contained in:
Sebastian Hengst
2018-01-06 00:27:10 +02:00
142 changed files with 3655 additions and 2289 deletions

View File

@@ -15,3 +15,4 @@ skip-if = buildapp == 'mulet'
[test_canvas.html]
[test_shadowroot.html]
skip-if = stylo # bug 1293844
support-files = test_shadowroot_subframe.html

View File

@@ -8,31 +8,6 @@
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript">
function doTest() {
testElm("component", {
role: ROLE_GROUPING,
children: [
{
role: ROLE_PUSHBUTTON,
},
{
role: ROLE_LINK,
},
]
});
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
@@ -46,13 +21,19 @@
<pre id="test">
</pre>
<div role="group" id="component"></div>
<script>
var component = document.getElementById("component");
var shadow = component.createShadowRoot();
shadow.innerHTML = "<button>Hello</button>" +
'<a href="#"> World</a>';
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, function() {
// This test loads in an iframe, to ensure that the element instance is
// loaded with the correct value of the preference.
var iframe = document.createElement("iframe");
iframe.src = "test_shadowroot_subframe.html";
document.body.appendChild(iframe);
});
</script>
</body>

View File

@@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<head>
<title>ShadowRoot tests</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript" src="../common.js"></script>
<script type="application/javascript" src="../role.js"></script>
<script type="application/javascript">
let SimpleTest = window.parent.SimpleTest;
let ok = window.parent.ok;
let is = window.parent.is;
function doTest() {
testElm("component", {
role: ROLE_GROUPING,
children: [
{
role: ROLE_PUSHBUTTON,
},
{
role: ROLE_LINK,
},
]
});
SimpleTest.finish();
}
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<div role="group" id="component"></div>
<script>
var component = document.getElementById("component");
var shadow = component.attachShadow({mode: "open"});
shadow.innerHTML = "<button>Hello</button>" +
'<a href="#"> World</a>';
</script>
</body>

View File

@@ -9,6 +9,7 @@ skip-if = (os == "android" || appname == "b2g")
[test_general.html]
[test_menu.xul]
[test_shadowroot.html]
support-files = test_shadowroot_subframe.html
[test_zoom.html]
[test_zoom_text.html]
[test_zoom_tree.xul]

View File

@@ -8,26 +8,6 @@
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../layout.js"></script>
<script type="application/javascript">
function doTest() {
var componentAcc = getAccessible("component1");
testChildAtPoint(componentAcc, 1, 1, componentAcc.firstChild,
componentAcc.firstChild);
componentAcc = getAccessible("component2");
testChildAtPoint(componentAcc, 1, 1, componentAcc.firstChild,
componentAcc.firstChild);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
@@ -41,31 +21,19 @@
<pre id="test">
</pre>
<div role="group" class="components" id="component1" style="display: inline-block;">
<!--
<div role="button" id="component-child"
style="width: 100px; height: 100px; background-color: pink;">
</div>
-->
</div>
<div role="group" class="components" id="component2" style="display: inline-block;">
<!--
<button>Hello world</button>
-->
</div>
<script>
// This routine adds the comment children of each 'component' to its
// shadow root.
var components = document.querySelectorAll(".components");
for (var i = 0; i < components.length; i++) {
var component = components[i];
var shadow = component.createShadowRoot();
for (var child = component.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 8)
// eslint-disable-next-line no-unsanitized/property
shadow.innerHTML = child.data;
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, function() {
// This test loads in an iframe, to ensure that the element instance is
// loaded with the correct value of the preference.
var iframe = document.createElement("iframe");
iframe.src = "test_shadowroot_subframe.html";
document.body.appendChild(iframe);
});
</script>
</body>

View File

@@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<title>ShadowRoot hit tests</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript" src="../common.js"></script>
<script type="application/javascript" src="../layout.js"></script>
<script type="application/javascript">
let SimpleTest = window.parent.SimpleTest;
let ok = window.parent.ok;
let is = window.parent.is;
function doTest() {
var componentAcc = getAccessible("component1");
testChildAtPoint(componentAcc, 1, 1, componentAcc.firstChild,
componentAcc.firstChild);
componentAcc = getAccessible("component2");
testChildAtPoint(componentAcc, 1, 1, componentAcc.firstChild,
componentAcc.firstChild);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<div role="group" class="components" id="component1" style="display: inline-block;">
<!--
<div role="button" id="component-child"
style="width: 100px; height: 100px; background-color: pink;">
</div>
-->
</div>
<div role="group" class="components" id="component2" style="display: inline-block;">
<!--
<button>Hello world</button>
-->
</div>
<script>
// This routine adds the comment children of each 'component' to its
// shadow root.
var components = document.querySelectorAll(".components");
for (var i = 0; i < components.length; i++) {
var component = components[i];
var shadow = component.attachShadow({mode: "open"});
for (var child = component.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 8)
// eslint-disable-next-line no-unsanitized/property
shadow.innerHTML = child.data;
}
}
</script>
</body>
</html>

View File

@@ -15,6 +15,7 @@ support-files =
[test_bug1175913.html]
[test_bug1189277.html]
[test_bug1276857.html]
support-files = test_bug1276857_subframe.html
[test_canvas.html]
[test_colorpicker.xul]
[test_contextmenu.xul]

View File

@@ -18,9 +18,14 @@
<script type="application/javascript">
function runTest() {
let iframe = document.getElementById("iframe");
// children change will recreate the table
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("c1"))
new invokerChecker(EVENT_REORDER, () => {
let doc = getNode("iframe").contentDocument;
return doc && doc.getElementById("c1");
})
];
this.invoke = function runTest_invoke() {
@@ -33,9 +38,9 @@
{ TEXT_LEAF: [] } // More text
]
};
testAccessibleTree("c1", tree);
testAccessibleTree(iframe.contentDocument.getElementById("c1"), tree);
getNode("c1_t").querySelector("span").remove();
iframe.contentDocument.getElementById("c1_t").querySelector("span").remove();
};
this.finalCheck = function runTest_finalCheck() {
@@ -45,7 +50,7 @@
{ TEXT_LEAF: [] } // More text
]
};
testAccessibleTree("c1", tree);
testAccessibleTree(iframe.contentDocument.getElementById("c1"), tree);
};
this.getID = function runTest_getID() {
@@ -56,7 +61,10 @@
function runShadowTest() {
// children change will recreate the table
this.eventSeq = [
new invokerChecker(EVENT_REORDER, "c2")
new invokerChecker(EVENT_REORDER, () => {
let doc = getNode("iframe").contentDocument;
return doc && doc.getElementById("c2");
})
];
this.invoke = function runShadowTest_invoke() {
@@ -69,9 +77,10 @@
{ TEXT_LEAF: [] } // More text
]
};
testAccessibleTree("c2", tree);
testAccessibleTree(iframe.contentDocument.getElementById("c2"), tree);
gShadowRoot.firstElementChild.querySelector("span").remove();
var shadowRoot = iframe.contentDocument.getElementById("c2_c").shadowRoot;
shadowRoot.firstElementChild.querySelector("span").remove();
};
this.finalCheck = function runShadowTest_finalCheck() {
@@ -81,7 +90,7 @@
{ TEXT_LEAF: [] } // More text
]
};
testAccessibleTree("c2", tree);
testAccessibleTree(iframe.contentDocument.getElementById("c2"), tree);
};
this.getID = function runShadowTest_getID() {
@@ -101,39 +110,22 @@
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, function() {
// This test loads in an iframe, to ensure that the element instance is
// loaded with the correct value of the preference.
let iframe = document.createElement("iframe");
iframe.id = "iframe";
iframe.src = "test_bug1276857_subframe.html";
addA11yLoadEvent(doTest, iframe.contentWindow);
document.body.appendChild(iframe);
});
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="c1">
<div id="c1_t" style="display: table" role="presentation">
Some text
<span style="display: table-cell">something with accessibles goes here</span>
More text
</div>
</div>
<template id="tmpl">
<div style="display: table" role="presentation">
Some text
<span style="display: table-cell">something with accessibles goes here</span>
More text
</div>
</template>
<div id="c2"><div id="c2_c" role="presentation"></div></div>
<script>
var gShadowRoot = document.getElementById("c2_c").createShadowRoot();
var tmpl = document.getElementById("tmpl");
gShadowRoot.appendChild(document.importNode(tmpl.content, true));
</script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<title>DOM mutations test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript" src="../role.js"></script>
</head>
<body>
<div id="c1">
<div id="c1_t" style="display: table" role="presentation">
Some text
<span style="display: table-cell">something with accessibles goes here</span>
More text
</div>
</div>
<template id="tmpl">
<div style="display: table" role="presentation">
Some text
<span style="display: table-cell">something with accessibles goes here</span>
More text
</div>
</template>
<div id="c2"><div id="c2_c" role="presentation"></div></div>
<script>
var gShadowRoot = document.getElementById("c2_c").attachShadow({mode: "open"});
var tmpl = document.getElementById("tmpl");
gShadowRoot.appendChild(document.importNode(tmpl.content, true));
</script>
</body>
</html>

View File

@@ -523,8 +523,6 @@ pref("general.warnOnAboutConfig", false);
// applications, but without it there isn't a really good way to prevent chrome
// spoofing, see bug 337344
pref("dom.disable_window_open_feature.location", true);
// prevent JS from setting status messages
pref("dom.disable_window_status_change", true);
// allow JS to move and resize existing windows
pref("dom.disable_window_move_resize", false);
// prevent JS from monkeying with window focus, etc

View File

@@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 2.0.244
Current extension version is: 2.0.250
Taken from upstream commit: 5bf4fb97
Taken from upstream commit: 6b2ed504

View File

@@ -29,7 +29,7 @@
exports["pdfjs-dist/build/pdf"] = factory();
else
root["pdfjs-dist/build/pdf"] = root.pdfjsDistBuildPdf = factory();
})(this, function() {
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
@@ -1936,7 +1936,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
if (worker.destroyed) {
return Promise.reject(new Error('Worker was destroyed'));
}
let apiVersion = '2.0.244';
let apiVersion = '2.0.250';
source.disableRange = (0, _dom_utils.getDefaultSetting)('disableRange');
source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
@@ -3233,8 +3233,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() {
}();
var version, build;
{
exports.version = version = '2.0.244';
exports.build = build = '5bf4fb97';
exports.version = version = '2.0.250';
exports.build = build = '6b2ed504';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@@ -4621,8 +4621,8 @@ exports.SVGGraphics = SVGGraphics;
"use strict";
var pdfjsVersion = '2.0.244';
var pdfjsBuild = '5bf4fb97';
var pdfjsVersion = '2.0.250';
var pdfjsBuild = '6b2ed504';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(12);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
@@ -7744,8 +7744,8 @@ if (!_global_scope2.default.PDFJS) {
}
var PDFJS = _global_scope2.default.PDFJS;
{
PDFJS.version = '2.0.244';
PDFJS.build = '5bf4fb97';
PDFJS.version = '2.0.250';
PDFJS.build = '6b2ed504';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {

View File

@@ -29,7 +29,7 @@
exports["pdfjs-dist/build/pdf.worker"] = factory();
else
root["pdfjs-dist/build/pdf.worker"] = root.pdfjsDistBuildPdfWorker = factory();
})(this, function() {
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
@@ -12230,8 +12230,9 @@ var JpxImage = function JpxImageClosure() {
precision: (data[j] & 0x7F) + 1,
isSigned: !!(data[j] & 0x80),
XRsiz: data[j + 1],
YRsiz: data[j + 1]
YRsiz: data[j + 2]
};
j += 3;
calculateComponentDimensions(component, siz);
components.push(component);
}
@@ -20783,8 +20784,8 @@ exports.PostScriptCompiler = PostScriptCompiler;
"use strict";
var pdfjsVersion = '2.0.244';
var pdfjsBuild = '5bf4fb97';
var pdfjsVersion = '2.0.250';
var pdfjsBuild = '6b2ed504';
var pdfjsCoreWorker = __w_pdfjs_require__(19);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
@@ -20979,7 +20980,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '2.0.244';
let workerVersion = '2.0.250';
if (apiVersion !== null && apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}

View File

@@ -22,16 +22,6 @@
padding: 0px;
}
.dialog-button-box {
padding-bottom: 8px;
padding-inline-start: 8px;
padding-inline-end: 8px;
}
.prefwindow[type="child"] .dialog-button-box {
padding: 0px;
}
/* General Pane */
#useFirefoxSync,
#getStarted {

View File

@@ -24,11 +24,6 @@
padding-inline-end: 20px;
}
.dialog-button-box {
margin: 0 12px 12px;
padding-top: 0 !important;
}
description {
margin-bottom: 4px !important;
}

View File

@@ -68,3 +68,7 @@ groupbox description {
menulist label {
font-weight: unset;
}
.dialog-button-box {
padding: 0;
}

View File

@@ -28,16 +28,6 @@
padding: 0px;
}
.dialog-button-box {
padding-bottom: 10px;
padding-inline-start: 8px;
padding-inline-end: 10px;
}
.prefwindow[type="child"] .dialog-button-box {
padding: 0px;
}
/* General Pane */
#useFirefoxSync,

View File

@@ -1,7 +1,7 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Taken from upstream commit: f98e56ff661460044382df55bd33cea601e093f0
Taken from upstream commit: 0bcf3e687305960077e1255510e424d0437a3b69
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.0

File diff suppressed because it is too large Load Diff

View File

@@ -96,6 +96,8 @@ skip-if = os == "linux" # bug 1351952
[browser_dbg-layout-changes.js]
[browser_dbg-outline.js]
[browser_dbg-pause-exceptions.js]
[browser_dbg-pause-ux.js]
skip-if = os == "win"
[browser_dbg-navigation.js]
[browser_dbg-minified.js]
[browser_dbg-pretty-print.js]
@@ -103,6 +105,7 @@ skip-if = os == "linux" # bug 1351952
[browser_dbg-pretty-print-paused.js]
[browser_dbg-preview.js]
skip-if = true # regular failures during release in Bug 1415300
[browser_dbg-preview-source-maps.js]
[browser_dbg-returnvalues.js]
[browser_dbg-scopes-mutations.js]
[browser_dbg-search-file.js]

View File

@@ -11,9 +11,11 @@ add_task(async function() {
// reload.
await addBreakpoint(dbg, "scripts.html", 18);
reload(dbg);
await waitForDispatch(dbg, "NAVIGATE");
await waitForSelectedSource(dbg, "doc-scripts.html");
await waitForPaused(dbg);
await waitForLoadedSource(dbg, "doc-scripts.html");
assertPausedLocation(dbg);
await resume(dbg);

View File

@@ -17,24 +17,25 @@ add_task(async function() {
// Wait for the source text to load and make sure we're in the right
// place.
await waitForLoadedSource(dbg, sourceUrl);
await waitForSelectedSource(dbg, sourceUrl);
log(`loaded source`);
// TODO: revisit highlighting lines when the debugger opens
// assertHighlightLocation(dbg, "long.js", 66);
// Jump to line 16 and make sure the editor scrolled.
log(`Select line 16 and make sure the editor scrolled.`);
await selectSource(dbg, "long.js", 16);
await waitForElement(dbg, ".CodeMirror-code > .highlight-line");
assertHighlightLocation(dbg, "long.js", 16);
// Make sure only one line is ever highlighted and the flash
// animation is cancelled on old lines.
log(`Select several locations and check that we have one highlight`);
await selectSource(dbg, "long.js", 17);
await selectSource(dbg, "long.js", 18);
assertHighlightLocation(dbg, "long.js", 18);
// Test jumping to a line in a source that exists but hasn't been
// loaded yet.
log(`Select an unloaded source`);
selectSource(dbg, "simple1.js", 6);
// Make sure the source is in the loading state, wait for it to be
@@ -42,7 +43,7 @@ add_task(async function() {
const simple1 = findSource(dbg, "simple1.js");
is(getSource(getState(), simple1.id).get("loadedState"), "loading");
await waitForLoadedSource(dbg, "simple1.js");
await waitForSelectedSource(dbg, "simple1.js");
ok(getSource(getState(), simple1.id).get("text"));
assertHighlightLocation(dbg, "simple1.js", 6);
});

View File

@@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function getScrollTop(dbg) {
return getCM(dbg).doc.scrollTop;
}
async function waitForMatch(dbg, { matchIndex, count }) {
await waitForState(
dbg,
state => {
const result = dbg.selectors.getFileSearchResults(state);
return result.matchIndex == matchIndex && result.count == count;
},
"wait for match"
);
}
add_task(async function() {
const dbg = await initDebugger("doc-scripts.html");
// Make sure that we can set a breakpoint on a line out of the
// viewport, and that pausing there scrolls the editor to it.
let longSrc = findSource(dbg, "long.js");
await addBreakpoint(dbg, longSrc, 66);
invokeInTab("testModel");
await waitForPaused(dbg);
const pauseScrollTop = getScrollTop(dbg);
log("1. adding a breakpoint should not scroll the editor");
getCM(dbg).scrollTo(0, 0);
await addBreakpoint(dbg, longSrc, 11);
is(getScrollTop(dbg), 0, "scroll position");
log("2. searching should jump to the match");
pressKey(dbg, "fileSearch");
type(dbg, "check");
await waitForMatch(dbg, { matchIndex: 0, count: 2 });
const matchScrollTop = getScrollTop(dbg);
ok(pauseScrollTop != matchScrollTop, "did not jump to debug line");
});

View File

@@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function getCoordsFromPosition(cm, { line, ch }) {
return cm.charCoords({ line: ~~line, ch: ~~ch });
}
function hoverAtPos(dbg, { line, ch }) {
const cm = getCM(dbg);
const coords = getCoordsFromPosition(cm, { line: line - 1, ch });
const tokenEl = dbg.win.document.elementFromPoint(coords.left, coords.top);
tokenEl.dispatchEvent(
new MouseEvent("mouseover", {
bubbles: true,
cancelable: true,
view: dbg.win
})
);
}
function assertTooltip(dbg, { result, expression }) {
const previewEl = findElement(dbg, "tooltip");
is(previewEl.innerText, result, "Preview text shown to user");
const preview = dbg.selectors.getPreview(dbg.getState());
is(`${preview.result}`, result, "Preview.result");
is(preview.updating, false, "Preview.updating");
is(preview.expression, expression, "Preview.expression");
}
function assertPopup(dbg, { field, value, expression }) {
const previewEl = findElement(dbg, "popup");
is(previewEl.innerText, "", "Preview text shown to user");
const preview = dbg.selectors.getPreview(dbg.getState());
is(
`${preview.result.preview.ownProperties[field].value}`,
value,
"Preview.result"
);
is(preview.updating, false, "Preview.updating");
is(preview.expression, expression, "Preview.expression");
}
add_task(async function() {
const dbg = await initDebugger("doc-sourcemaps.html");
const { selectors: { getSelectedSource }, getState } = dbg;
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
await selectSource(dbg, "times2");
await addBreakpoint(dbg, "times2", 2);
invokeInTab("keepMeAlive");
await waitForPaused(dbg);
await waitForSelectedSource(dbg, "times2");
const tooltipPreviewed = waitForDispatch(dbg, "SET_PREVIEW");
hoverAtPos(dbg, { line: 2, ch: 9 });
await tooltipPreviewed;
assertTooltip(dbg, { result: 4, expression: "x" });
});

View File

@@ -208,7 +208,7 @@ function waitForSources(dbg, ...sources) {
}
if (!sourceExists(store.getState())) {
return waitForState(dbg, sourceExists);
return waitForState(dbg, sourceExists, `source ${url}`);
}
})
);
@@ -313,8 +313,14 @@ function assertDebugLine(dbg, line) {
);
const debugLine =
findElementWithSelector(dbg, ".new-debug-line") ||
findElementWithSelector(dbg, ".new-debug-line-error");
findElement(dbg, "debugLine") || findElement(dbg, "debugErrorLine");
is(
findAllElements(dbg, "debugLine").length +
findAllElements(dbg, "debugErrorLine").length,
1,
"There is only one line"
);
ok(isVisibleInEditor(dbg, debugLine), "debug line is visible");
@@ -935,6 +941,8 @@ const selectors = {
pauseOnExceptions: ".pause-exceptions",
breakpoint: ".CodeMirror-code > .new-breakpoint",
highlightLine: ".CodeMirror-code > .highlight-line",
debugLine: ".new-debug-line",
debugErrorLine: ".new-debug-line-error",
codeMirror: ".CodeMirror",
resume: ".resume.active",
sourceTabs: ".source-tabs",

View File

@@ -34,6 +34,7 @@ class GridItem extends PureComponent {
this.setGridColor = this.setGridColor.bind(this);
this.translateNodeFrontToGrip = this.translateNodeFrontToGrip.bind(this);
this.onGridCheckboxClick = this.onGridCheckboxClick.bind(this);
this.onGridInspectIconClick = this.onGridInspectIconClick.bind(this);
}
componentDidMount() {
@@ -114,10 +115,15 @@ class GridItem extends PureComponent {
onToggleGridHighlighter(grid.nodeFront);
}
onGridInspectIconClick(nodeFront) {
let { setSelectedNode } = this.props;
setSelectedNode(nodeFront, "layout-panel").catch(e => console.error(e));
nodeFront.scrollIntoView().catch(e => console.error(e));
}
render() {
let {
grid,
setSelectedNode,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
} = this.props;
@@ -142,7 +148,7 @@ class GridItem extends PureComponent {
object: this.translateNodeFrontToGrip(nodeFront),
onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
onInspectIconClick: () => setSelectedNode(nodeFront, "layout-panel"),
onInspectIconClick: () => this.onGridInspectIconClick(nodeFront),
}
)
),

View File

@@ -1,13 +1,13 @@
# wasmparser version
Current vesion is: 0.4.11
Current vesion is: 0.5.2
# Upgrade process
1. Pull latest release from npm and extract WasmDis.js and WasmParser.js, e.g.
```
curl https://registry.npmjs.org/wasmparser/-/wasmparser-0.4.11.tgz | tar -x --strip-components 2 package/dist/{WasmDis,WasmParser}.js
curl https://registry.npmjs.org/wasmparser/-/wasmparser-0.5.2.tgz | tar -x --strip-components 2 package/dist/{WasmDis,WasmParser}.js
```
2. Remove reference to source maps (last line)

View File

@@ -69,6 +69,16 @@ function memoryAddressToString(address, code) {
case 55 /* i64_store */:
case 43 /* f64_load */:
case 57 /* f64_store */:
case 65026 /* i64_atomic_wait */:
case 65041 /* i64_atomic_load */:
case 65048 /* i64_atomic_store */:
case 65055 /* i64_atomic_rmw_add */:
case 65062 /* i64_atomic_rmw_sub */:
case 65069 /* i64_atomic_rmw_and */:
case 65076 /* i64_atomic_rmw_or */:
case 65083 /* i64_atomic_rmw_xor */:
case 65090 /* i64_atomic_rmw_xchg */:
case 65097 /* i64_atomic_rmw_cmpxchg */:
defaultAlignFlags = 3;
break;
case 40 /* i32_load */:
@@ -78,6 +88,26 @@ function memoryAddressToString(address, code) {
case 62 /* i64_store32 */:
case 42 /* f32_load */:
case 56 /* f32_store */:
case 65024 /* atomic_wake */:
case 65025 /* i32_atomic_wait */:
case 65040 /* i32_atomic_load */:
case 65046 /* i64_atomic_load32_u */:
case 65047 /* i32_atomic_store */:
case 65053 /* i64_atomic_store32 */:
case 65054 /* i32_atomic_rmw_add */:
case 65060 /* i64_atomic_rmw32_u_add */:
case 65061 /* i32_atomic_rmw_sub */:
case 65067 /* i64_atomic_rmw32_u_sub */:
case 65068 /* i32_atomic_rmw_and */:
case 65074 /* i64_atomic_rmw32_u_and */:
case 65075 /* i32_atomic_rmw_or */:
case 65081 /* i64_atomic_rmw32_u_or */:
case 65082 /* i32_atomic_rmw_xor */:
case 65088 /* i64_atomic_rmw32_u_xor */:
case 65089 /* i32_atomic_rmw_xchg */:
case 65095 /* i64_atomic_rmw32_u_xchg */:
case 65096 /* i32_atomic_rmw_cmpxchg */:
case 65102 /* i64_atomic_rmw32_u_cmpxchg */:
defaultAlignFlags = 2;
break;
case 46 /* i32_load16_s */:
@@ -86,6 +116,24 @@ function memoryAddressToString(address, code) {
case 51 /* i64_load16_u */:
case 59 /* i32_store16 */:
case 61 /* i64_store16 */:
case 65043 /* i32_atomic_load16_u */:
case 65045 /* i64_atomic_load16_u */:
case 65050 /* i32_atomic_store16 */:
case 65052 /* i64_atomic_store16 */:
case 65057 /* i32_atomic_rmw16_u_add */:
case 65059 /* i64_atomic_rmw16_u_add */:
case 65064 /* i32_atomic_rmw16_u_sub */:
case 65066 /* i64_atomic_rmw16_u_sub */:
case 65071 /* i32_atomic_rmw16_u_and */:
case 65073 /* i64_atomic_rmw16_u_and */:
case 65078 /* i32_atomic_rmw16_u_or */:
case 65080 /* i64_atomic_rmw16_u_or */:
case 65085 /* i32_atomic_rmw16_u_xor */:
case 65087 /* i64_atomic_rmw16_u_xor */:
case 65092 /* i32_atomic_rmw16_u_xchg */:
case 65094 /* i64_atomic_rmw16_u_xchg */:
case 65099 /* i32_atomic_rmw16_u_cmpxchg */:
case 65101 /* i64_atomic_rmw16_u_cmpxchg */:
defaultAlignFlags = 1;
break;
case 44 /* i32_load8_s */:
@@ -94,6 +142,24 @@ function memoryAddressToString(address, code) {
case 49 /* i64_load8_u */:
case 58 /* i32_store8 */:
case 60 /* i64_store8 */:
case 65042 /* i32_atomic_load8_u */:
case 65044 /* i64_atomic_load8_u */:
case 65049 /* i32_atomic_store8 */:
case 65051 /* i64_atomic_store8 */:
case 65056 /* i32_atomic_rmw8_u_add */:
case 65058 /* i64_atomic_rmw8_u_add */:
case 65063 /* i32_atomic_rmw8_u_sub */:
case 65065 /* i64_atomic_rmw8_u_sub */:
case 65070 /* i32_atomic_rmw8_u_and */:
case 65072 /* i64_atomic_rmw8_u_and */:
case 65077 /* i32_atomic_rmw8_u_or */:
case 65079 /* i64_atomic_rmw8_u_or */:
case 65084 /* i32_atomic_rmw8_u_xor */:
case 65086 /* i64_atomic_rmw8_u_xor */:
case 65091 /* i32_atomic_rmw8_u_xchg */:
case 65093 /* i64_atomic_rmw8_u_xchg */:
case 65098 /* i32_atomic_rmw8_u_cmpxchg */:
case 65100 /* i64_atomic_rmw8_u_cmpxchg */:
defaultAlignFlags = 0;
break;
}
@@ -384,7 +450,7 @@ var WasmDisassembler = (function () {
return backrefLabel.label || '' + depth;
};
WasmDisassembler.prototype.printOperator = function (operator) {
var code = operator.code;
var code = operator.code | 0;
this.appendBuffer(getOperatorName(code));
switch (code) {
case 2 /* block */:
@@ -476,6 +542,72 @@ var WasmDisassembler = (function () {
case 60 /* i64_store8 */:
case 61 /* i64_store16 */:
case 62 /* i64_store32 */:
case 65024 /* atomic_wake */:
case 65025 /* i32_atomic_wait */:
case 65026 /* i64_atomic_wait */:
case 65040 /* i32_atomic_load */:
case 65041 /* i64_atomic_load */:
case 65042 /* i32_atomic_load8_u */:
case 65043 /* i32_atomic_load16_u */:
case 65044 /* i64_atomic_load8_u */:
case 65045 /* i64_atomic_load16_u */:
case 65046 /* i64_atomic_load32_u */:
case 65047 /* i32_atomic_store */:
case 65048 /* i64_atomic_store */:
case 65049 /* i32_atomic_store8 */:
case 65050 /* i32_atomic_store16 */:
case 65051 /* i64_atomic_store8 */:
case 65052 /* i64_atomic_store16 */:
case 65053 /* i64_atomic_store32 */:
case 65054 /* i32_atomic_rmw_add */:
case 65055 /* i64_atomic_rmw_add */:
case 65056 /* i32_atomic_rmw8_u_add */:
case 65057 /* i32_atomic_rmw16_u_add */:
case 65058 /* i64_atomic_rmw8_u_add */:
case 65059 /* i64_atomic_rmw16_u_add */:
case 65060 /* i64_atomic_rmw32_u_add */:
case 65061 /* i32_atomic_rmw_sub */:
case 65062 /* i64_atomic_rmw_sub */:
case 65063 /* i32_atomic_rmw8_u_sub */:
case 65064 /* i32_atomic_rmw16_u_sub */:
case 65065 /* i64_atomic_rmw8_u_sub */:
case 65066 /* i64_atomic_rmw16_u_sub */:
case 65067 /* i64_atomic_rmw32_u_sub */:
case 65068 /* i32_atomic_rmw_and */:
case 65069 /* i64_atomic_rmw_and */:
case 65070 /* i32_atomic_rmw8_u_and */:
case 65071 /* i32_atomic_rmw16_u_and */:
case 65072 /* i64_atomic_rmw8_u_and */:
case 65073 /* i64_atomic_rmw16_u_and */:
case 65074 /* i64_atomic_rmw32_u_and */:
case 65075 /* i32_atomic_rmw_or */:
case 65076 /* i64_atomic_rmw_or */:
case 65077 /* i32_atomic_rmw8_u_or */:
case 65078 /* i32_atomic_rmw16_u_or */:
case 65079 /* i64_atomic_rmw8_u_or */:
case 65080 /* i64_atomic_rmw16_u_or */:
case 65081 /* i64_atomic_rmw32_u_or */:
case 65082 /* i32_atomic_rmw_xor */:
case 65083 /* i64_atomic_rmw_xor */:
case 65084 /* i32_atomic_rmw8_u_xor */:
case 65085 /* i32_atomic_rmw16_u_xor */:
case 65086 /* i64_atomic_rmw8_u_xor */:
case 65087 /* i64_atomic_rmw16_u_xor */:
case 65088 /* i64_atomic_rmw32_u_xor */:
case 65089 /* i32_atomic_rmw_xchg */:
case 65090 /* i64_atomic_rmw_xchg */:
case 65091 /* i32_atomic_rmw8_u_xchg */:
case 65092 /* i32_atomic_rmw16_u_xchg */:
case 65093 /* i64_atomic_rmw8_u_xchg */:
case 65094 /* i64_atomic_rmw16_u_xchg */:
case 65095 /* i64_atomic_rmw32_u_xchg */:
case 65096 /* i32_atomic_rmw_cmpxchg */:
case 65097 /* i64_atomic_rmw_cmpxchg */:
case 65098 /* i32_atomic_rmw8_u_cmpxchg */:
case 65099 /* i32_atomic_rmw16_u_cmpxchg */:
case 65100 /* i64_atomic_rmw8_u_cmpxchg */:
case 65101 /* i64_atomic_rmw16_u_cmpxchg */:
case 65102 /* i64_atomic_rmw32_u_cmpxchg */:
var memoryAddress = memoryAddressToString(operator.memoryAddress, operator.code);
if (memoryAddress !== null) {
this.appendBuffer(' ');
@@ -620,9 +752,12 @@ var WasmDisassembler = (function () {
case 15 /* MEMORY_SECTION_ENTRY */:
var memoryInfo = reader.result;
var memoryName = this._nameResolver.getMemoryName(this._memoryCount++, false);
this.appendBuffer(" (memory " + memoryName + " " + memoryInfo.limits.initial);
if (memoryInfo.limits.maximum !== undefined) {
this.appendBuffer(" " + memoryInfo.limits.maximum);
this.appendBuffer(" (memory " + memoryName + " ");
if (memoryInfo.shared) {
this.appendBuffer("(shared " + limitsToString(memoryInfo.limits) + ")");
}
else {
this.appendBuffer(limitsToString(memoryInfo.limits));
}
this.appendBuffer(')');
this.newLine();
@@ -681,7 +816,14 @@ var WasmDisassembler = (function () {
case 2 /* Memory */:
var memoryImportInfo = importInfo.type;
var memoryName = this._nameResolver.getMemoryName(this._memoryCount++, false);
this.appendBuffer(" (memory " + memoryName + " " + limitsToString(memoryImportInfo.limits) + ")");
this.appendBuffer(" (memory " + memoryName + " ");
if (memoryImportInfo.shared) {
this.appendBuffer("(shared " + limitsToString(memoryImportInfo.limits) + ")");
}
else {
this.appendBuffer(limitsToString(memoryImportInfo.limits));
}
this.appendBuffer(')');
break;
case 3 /* Global */:
var globalImportInfo = importInfo.type;

View File

@@ -208,11 +208,98 @@ var OperatorCode;
OperatorCode[OperatorCode["i64_reinterpret_f64"] = 189] = "i64_reinterpret_f64";
OperatorCode[OperatorCode["f32_reinterpret_i32"] = 190] = "f32_reinterpret_i32";
OperatorCode[OperatorCode["f64_reinterpret_i64"] = 191] = "f64_reinterpret_i64";
OperatorCode[OperatorCode["i32_extend8_s"] = 192] = "i32_extend8_s";
OperatorCode[OperatorCode["i32_extend16_s"] = 193] = "i32_extend16_s";
OperatorCode[OperatorCode["i64_extend8_s"] = 194] = "i64_extend8_s";
OperatorCode[OperatorCode["i64_extend16_s"] = 195] = "i64_extend16_s";
OperatorCode[OperatorCode["i64_extend32_s"] = 196] = "i64_extend32_s";
OperatorCode[OperatorCode["prefix_0xfc"] = 252] = "prefix_0xfc";
OperatorCode[OperatorCode["prefix_0xfe"] = 254] = "prefix_0xfe";
OperatorCode[OperatorCode["i32_trunc_s_sat_f32"] = 64512] = "i32_trunc_s_sat_f32";
OperatorCode[OperatorCode["i32_trunc_u_sat_f32"] = 64513] = "i32_trunc_u_sat_f32";
OperatorCode[OperatorCode["i32_trunc_s_sat_f64"] = 64514] = "i32_trunc_s_sat_f64";
OperatorCode[OperatorCode["i32_trunc_u_sat_f64"] = 64515] = "i32_trunc_u_sat_f64";
OperatorCode[OperatorCode["i64_trunc_s_sat_f32"] = 64516] = "i64_trunc_s_sat_f32";
OperatorCode[OperatorCode["i64_trunc_u_sat_f32"] = 64517] = "i64_trunc_u_sat_f32";
OperatorCode[OperatorCode["i64_trunc_s_sat_f64"] = 64518] = "i64_trunc_s_sat_f64";
OperatorCode[OperatorCode["i64_trunc_u_sat_f64"] = 64519] = "i64_trunc_u_sat_f64";
OperatorCode[OperatorCode["atomic_wake"] = 65024] = "atomic_wake";
OperatorCode[OperatorCode["i32_atomic_wait"] = 65025] = "i32_atomic_wait";
OperatorCode[OperatorCode["i64_atomic_wait"] = 65026] = "i64_atomic_wait";
OperatorCode[OperatorCode["i32_atomic_load"] = 65040] = "i32_atomic_load";
OperatorCode[OperatorCode["i64_atomic_load"] = 65041] = "i64_atomic_load";
OperatorCode[OperatorCode["i32_atomic_load8_u"] = 65042] = "i32_atomic_load8_u";
OperatorCode[OperatorCode["i32_atomic_load16_u"] = 65043] = "i32_atomic_load16_u";
OperatorCode[OperatorCode["i64_atomic_load8_u"] = 65044] = "i64_atomic_load8_u";
OperatorCode[OperatorCode["i64_atomic_load16_u"] = 65045] = "i64_atomic_load16_u";
OperatorCode[OperatorCode["i64_atomic_load32_u"] = 65046] = "i64_atomic_load32_u";
OperatorCode[OperatorCode["i32_atomic_store"] = 65047] = "i32_atomic_store";
OperatorCode[OperatorCode["i64_atomic_store"] = 65048] = "i64_atomic_store";
OperatorCode[OperatorCode["i32_atomic_store8"] = 65049] = "i32_atomic_store8";
OperatorCode[OperatorCode["i32_atomic_store16"] = 65050] = "i32_atomic_store16";
OperatorCode[OperatorCode["i64_atomic_store8"] = 65051] = "i64_atomic_store8";
OperatorCode[OperatorCode["i64_atomic_store16"] = 65052] = "i64_atomic_store16";
OperatorCode[OperatorCode["i64_atomic_store32"] = 65053] = "i64_atomic_store32";
OperatorCode[OperatorCode["i32_atomic_rmw_add"] = 65054] = "i32_atomic_rmw_add";
OperatorCode[OperatorCode["i64_atomic_rmw_add"] = 65055] = "i64_atomic_rmw_add";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_add"] = 65056] = "i32_atomic_rmw8_u_add";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_add"] = 65057] = "i32_atomic_rmw16_u_add";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_add"] = 65058] = "i64_atomic_rmw8_u_add";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_add"] = 65059] = "i64_atomic_rmw16_u_add";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_add"] = 65060] = "i64_atomic_rmw32_u_add";
OperatorCode[OperatorCode["i32_atomic_rmw_sub"] = 65061] = "i32_atomic_rmw_sub";
OperatorCode[OperatorCode["i64_atomic_rmw_sub"] = 65062] = "i64_atomic_rmw_sub";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_sub"] = 65063] = "i32_atomic_rmw8_u_sub";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_sub"] = 65064] = "i32_atomic_rmw16_u_sub";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_sub"] = 65065] = "i64_atomic_rmw8_u_sub";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_sub"] = 65066] = "i64_atomic_rmw16_u_sub";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_sub"] = 65067] = "i64_atomic_rmw32_u_sub";
OperatorCode[OperatorCode["i32_atomic_rmw_and"] = 65068] = "i32_atomic_rmw_and";
OperatorCode[OperatorCode["i64_atomic_rmw_and"] = 65069] = "i64_atomic_rmw_and";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_and"] = 65070] = "i32_atomic_rmw8_u_and";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_and"] = 65071] = "i32_atomic_rmw16_u_and";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_and"] = 65072] = "i64_atomic_rmw8_u_and";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_and"] = 65073] = "i64_atomic_rmw16_u_and";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_and"] = 65074] = "i64_atomic_rmw32_u_and";
OperatorCode[OperatorCode["i32_atomic_rmw_or"] = 65075] = "i32_atomic_rmw_or";
OperatorCode[OperatorCode["i64_atomic_rmw_or"] = 65076] = "i64_atomic_rmw_or";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_or"] = 65077] = "i32_atomic_rmw8_u_or";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_or"] = 65078] = "i32_atomic_rmw16_u_or";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_or"] = 65079] = "i64_atomic_rmw8_u_or";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_or"] = 65080] = "i64_atomic_rmw16_u_or";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_or"] = 65081] = "i64_atomic_rmw32_u_or";
OperatorCode[OperatorCode["i32_atomic_rmw_xor"] = 65082] = "i32_atomic_rmw_xor";
OperatorCode[OperatorCode["i64_atomic_rmw_xor"] = 65083] = "i64_atomic_rmw_xor";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_xor"] = 65084] = "i32_atomic_rmw8_u_xor";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_xor"] = 65085] = "i32_atomic_rmw16_u_xor";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_xor"] = 65086] = "i64_atomic_rmw8_u_xor";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_xor"] = 65087] = "i64_atomic_rmw16_u_xor";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_xor"] = 65088] = "i64_atomic_rmw32_u_xor";
OperatorCode[OperatorCode["i32_atomic_rmw_xchg"] = 65089] = "i32_atomic_rmw_xchg";
OperatorCode[OperatorCode["i64_atomic_rmw_xchg"] = 65090] = "i64_atomic_rmw_xchg";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_xchg"] = 65091] = "i32_atomic_rmw8_u_xchg";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_xchg"] = 65092] = "i32_atomic_rmw16_u_xchg";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_xchg"] = 65093] = "i64_atomic_rmw8_u_xchg";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_xchg"] = 65094] = "i64_atomic_rmw16_u_xchg";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_xchg"] = 65095] = "i64_atomic_rmw32_u_xchg";
OperatorCode[OperatorCode["i32_atomic_rmw_cmpxchg"] = 65096] = "i32_atomic_rmw_cmpxchg";
OperatorCode[OperatorCode["i64_atomic_rmw_cmpxchg"] = 65097] = "i64_atomic_rmw_cmpxchg";
OperatorCode[OperatorCode["i32_atomic_rmw8_u_cmpxchg"] = 65098] = "i32_atomic_rmw8_u_cmpxchg";
OperatorCode[OperatorCode["i32_atomic_rmw16_u_cmpxchg"] = 65099] = "i32_atomic_rmw16_u_cmpxchg";
OperatorCode[OperatorCode["i64_atomic_rmw8_u_cmpxchg"] = 65100] = "i64_atomic_rmw8_u_cmpxchg";
OperatorCode[OperatorCode["i64_atomic_rmw16_u_cmpxchg"] = 65101] = "i64_atomic_rmw16_u_cmpxchg";
OperatorCode[OperatorCode["i64_atomic_rmw32_u_cmpxchg"] = 65102] = "i64_atomic_rmw32_u_cmpxchg";
})(OperatorCode = exports.OperatorCode || (exports.OperatorCode = {}));
;
exports.OperatorCodeNames = [
"unreachable", "nop", "block", "loop", "if", "else", undefined, undefined, undefined, undefined, undefined, "end", "br", "br_if", "br_table", "return", "call", "call_indirect", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "drop", "select", undefined, undefined, undefined, undefined, "get_local", "set_local", "tee_local", "get_global", "set_global", undefined, undefined, undefined, "i32.load", "i64.load", "f32.load", "f64.load", "i32.load8_s", "i32.load8_u", "i32.load16_s", "i32.load16_u", "i64.load8_s", "i64.load8_u", "i64.load16_s", "i64.load16_u", "i64.load32_s", "i64.load32_u", "i32.store", "i64.store", "f32.store", "f64.store", "i32.store8", "i32.store16", "i64.store8", "i64.store16", "i64.store32", "current_memory", "grow_memory", "i32.const", "i64.const", "f32.const", "f64.const", "i32.eqz", "i32.eq", "i32.ne", "i32.lt_s", "i32.lt_u", "i32.gt_s", "i32.gt_u", "i32.le_s", "i32.le_u", "i32.ge_s", "i32.ge_u", "i64.eqz", "i64.eq", "i64.ne", "i64.lt_s", "i64.lt_u", "i64.gt_s", "i64.gt_u", "i64.le_s", "i64.le_u", "i64.ge_s", "i64.ge_u", "f32.eq", "f32.ne", "f32.lt", "f32.gt", "f32.le", "f32.ge", "f64.eq", "f64.ne", "f64.lt", "f64.gt", "f64.le", "f64.ge", "i32.clz", "i32.ctz", "i32.popcnt", "i32.add", "i32.sub", "i32.mul", "i32.div_s", "i32.div_u", "i32.rem_s", "i32.rem_u", "i32.and", "i32.or", "i32.xor", "i32.shl", "i32.shr_s", "i32.shr_u", "i32.rotl", "i32.rotr", "i64.clz", "i64.ctz", "i64.popcnt", "i64.add", "i64.sub", "i64.mul", "i64.div_s", "i64.div_u", "i64.rem_s", "i64.rem_u", "i64.and", "i64.or", "i64.xor", "i64.shl", "i64.shr_s", "i64.shr_u", "i64.rotl", "i64.rotr", "f32.abs", "f32.neg", "f32.ceil", "f32.floor", "f32.trunc", "f32.nearest", "f32.sqrt", "f32.add", "f32.sub", "f32.mul", "f32.div", "f32.min", "f32.max", "f32.copysign", "f64.abs", "f64.neg", "f64.ceil", "f64.floor", "f64.trunc", "f64.nearest", "f64.sqrt", "f64.add", "f64.sub", "f64.mul", "f64.div", "f64.min", "f64.max", "f64.copysign", "i32.wrap/i64", "i32.trunc_s/f32", "i32.trunc_u/f32", "i32.trunc_s/f64", "i32.trunc_u/f64", "i64.extend_s/i32", "i64.extend_u/i32", "i64.trunc_s/f32", "i64.trunc_u/f32", "i64.trunc_s/f64", "i64.trunc_u/f64", "f32.convert_s/i32", "f32.convert_u/i32", "f32.convert_s/i64", "f32.convert_u/i64", "f32.demote/f64", "f64.convert_s/i32", "f64.convert_u/i32", "f64.convert_s/i64", "f64.convert_u/i64", "f64.promote/f32", "i32.reinterpret/f32", "i64.reinterpret/f64", "f32.reinterpret/i32", "f64.reinterpret/i64", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined
"unreachable", "nop", "block", "loop", "if", "else", undefined, undefined, undefined, undefined, undefined, "end", "br", "br_if", "br_table", "return", "call", "call_indirect", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "drop", "select", undefined, undefined, undefined, undefined, "get_local", "set_local", "tee_local", "get_global", "set_global", undefined, undefined, undefined, "i32.load", "i64.load", "f32.load", "f64.load", "i32.load8_s", "i32.load8_u", "i32.load16_s", "i32.load16_u", "i64.load8_s", "i64.load8_u", "i64.load16_s", "i64.load16_u", "i64.load32_s", "i64.load32_u", "i32.store", "i64.store", "f32.store", "f64.store", "i32.store8", "i32.store16", "i64.store8", "i64.store16", "i64.store32", "current_memory", "grow_memory", "i32.const", "i64.const", "f32.const", "f64.const", "i32.eqz", "i32.eq", "i32.ne", "i32.lt_s", "i32.lt_u", "i32.gt_s", "i32.gt_u", "i32.le_s", "i32.le_u", "i32.ge_s", "i32.ge_u", "i64.eqz", "i64.eq", "i64.ne", "i64.lt_s", "i64.lt_u", "i64.gt_s", "i64.gt_u", "i64.le_s", "i64.le_u", "i64.ge_s", "i64.ge_u", "f32.eq", "f32.ne", "f32.lt", "f32.gt", "f32.le", "f32.ge", "f64.eq", "f64.ne", "f64.lt", "f64.gt", "f64.le", "f64.ge", "i32.clz", "i32.ctz", "i32.popcnt", "i32.add", "i32.sub", "i32.mul", "i32.div_s", "i32.div_u", "i32.rem_s", "i32.rem_u", "i32.and", "i32.or", "i32.xor", "i32.shl", "i32.shr_s", "i32.shr_u", "i32.rotl", "i32.rotr", "i64.clz", "i64.ctz", "i64.popcnt", "i64.add", "i64.sub", "i64.mul", "i64.div_s", "i64.div_u", "i64.rem_s", "i64.rem_u", "i64.and", "i64.or", "i64.xor", "i64.shl", "i64.shr_s", "i64.shr_u", "i64.rotl", "i64.rotr", "f32.abs", "f32.neg", "f32.ceil", "f32.floor", "f32.trunc", "f32.nearest", "f32.sqrt", "f32.add", "f32.sub", "f32.mul", "f32.div", "f32.min", "f32.max", "f32.copysign", "f64.abs", "f64.neg", "f64.ceil", "f64.floor", "f64.trunc", "f64.nearest", "f64.sqrt", "f64.add", "f64.sub", "f64.mul", "f64.div", "f64.min", "f64.max", "f64.copysign", "i32.wrap/i64", "i32.trunc_s/f32", "i32.trunc_u/f32", "i32.trunc_s/f64", "i32.trunc_u/f64", "i64.extend_s/i32", "i64.extend_u/i32", "i64.trunc_s/f32", "i64.trunc_u/f32", "i64.trunc_s/f64", "i64.trunc_u/f64", "f32.convert_s/i32", "f32.convert_u/i32", "f32.convert_s/i64", "f32.convert_u/i64", "f32.demote/f64", "f64.convert_s/i32", "f64.convert_u/i32", "f64.convert_s/i64", "f64.convert_u/i64", "f64.promote/f32", "i32.reinterpret/f32", "i64.reinterpret/f64", "f32.reinterpret/i32", "f64.reinterpret/i64", "i32.extend8_s", "i32.extend16_s", "i64.extend8_s", "i64.extend16_s", "i64.extend32_s", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined
];
["i32.trunc_s:sat/f32", "i32.trunc_u:sat/f32", "i32.trunc_s:sat/f64", "i32.trunc_u:sat/f64", "i64.trunc_s:sat/f32", "i64.trunc_u:sat/f32", "i64.trunc_s:sat/f64", "i64.trunc_u:sat/f64"].forEach(function (s, i) {
exports.OperatorCodeNames[0xfc00 | i] = s;
});
["atomic.wake", "i32.atomic.wait", "i64.atomic.wait", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "i32.atomic.load", "i64.atomic.load", "i32.atomic.load8_u", "i32.atomic.load16_u", "i64.atomic.load8_u", "i64.atomic.load16_u", "i64.atomic.load32_u", "i32.atomic.store", "i64.atomic.store", "i32.atomic.store8", "i32.atomic.store16", "i64.atomic.store8", "i64.atomic.store16", "i64.atomic.store32", "i32.atomic.rmw.add", "i64.atomic.rmw.add", "i32.atomic.rmw8_u.add", "i32.atomic.rmw16_u.add", "i64.atomic.rmw8_u.add", "i64.atomic.rmw16_u.add", "i64.atomic.rmw32_u.add", "i32.atomic.rmw.sub", "i64.atomic.rmw.sub", "i32.atomic.rmw8_u.sub", "i32.atomic.rmw16_u.sub", "i64.atomic.rmw8_u.sub", "i64.atomic.rmw16_u.sub", "i64.atomic.rmw32_u.sub", "i32.atomic.rmw.and", "i64.atomic.rmw.and", "i32.atomic.rmw8_u.and", "i32.atomic.rmw16_u.and", "i64.atomic.rmw8_u.and", "i64.atomic.rmw16_u.and", "i64.atomic.rmw32_u.and", "i32.atomic.rmw.or", "i64.atomic.rmw.or", "i32.atomic.rmw8_u.or", "i32.atomic.rmw16_u.or", "i64.atomic.rmw8_u.or", "i64.atomic.rmw16_u.or", "i64.atomic.rmw32_u.or", "i32.atomic.rmw.xor", "i64.atomic.rmw.xor", "i32.atomic.rmw8_u.xor", "i32.atomic.rmw16_u.xor", "i64.atomic.rmw8_u.xor", "i64.atomic.rmw16_u.xor", "i64.atomic.rmw32_u.xor", "i32.atomic.rmw.xchg", "i64.atomic.rmw.xchg", "i32.atomic.rmw8_u.xchg", "i32.atomic.rmw16_u.xchg", "i64.atomic.rmw8_u.xchg", "i64.atomic.rmw16_u.xchg", "i64.atomic.rmw32_u.xchg", "i32.atomic.rmw.cmpxchg", "i64.atomic.rmw.cmpxchg", "i32.atomic.rmw8_u.cmpxchg", "i32.atomic.rmw16_u.cmpxchg", "i64.atomic.rmw8_u.cmpxchg", "i64.atomic.rmw16_u.cmpxchg", "i64.atomic.rmw32_u.cmpxchg"].forEach(function (s, i) {
exports.OperatorCodeNames[0xfe00 | i] = s;
});
var ExternalKind;
(function (ExternalKind) {
ExternalKind[ExternalKind["Function"] = 0] = "Function";
@@ -537,22 +624,24 @@ var BinaryReader = (function () {
returns: returnTypes
};
};
BinaryReader.prototype.readResizableLimits = function () {
var flags = this.readVarUint32() >>> 0;
BinaryReader.prototype.readResizableLimits = function (maxPresent) {
var initial = this.readVarUint32() >>> 0;
var maximum;
if (flags & 0x1) {
if (maxPresent) {
maximum = this.readVarUint32() >>> 0;
}
return { flags: flags, initial: initial, maximum: maximum };
return { initial: initial, maximum: maximum };
};
BinaryReader.prototype.readTableType = function () {
var elementType = this.readVarInt7();
var limits = this.readResizableLimits();
var flags = this.readVarUint32() >>> 0;
var limits = this.readResizableLimits(!!(flags & 0x01));
return { elementType: elementType, limits: limits };
};
BinaryReader.prototype.readMemoryType = function () {
return { limits: this.readResizableLimits() };
var flags = this.readVarUint32() >>> 0;
var shared = !!(flags & 0x02);
return { limits: this.readResizableLimits(!!(flags & 0x01)), shared: shared };
};
BinaryReader.prototype.readGlobalType = function () {
if (!this.hasVarIntBytes()) {
@@ -920,6 +1009,117 @@ var BinaryReader = (function () {
this._sectionEntriesLeft--;
return true;
};
BinaryReader.prototype.readCodeOperator_0xfc = function () {
var code = this._data[this._pos++] | 0xfc00;
switch (code) {
case 64512 /* i32_trunc_s_sat_f32 */:
case 64513 /* i32_trunc_u_sat_f32 */:
case 64514 /* i32_trunc_s_sat_f64 */:
case 64515 /* i32_trunc_u_sat_f64 */:
case 64516 /* i64_trunc_s_sat_f32 */:
case 64517 /* i64_trunc_u_sat_f32 */:
case 64518 /* i64_trunc_s_sat_f64 */:
case 64519 /* i64_trunc_u_sat_f64 */:
break;
default:
this.error = new Error("Unknown operator: " + code);
this.state = -1 /* ERROR */;
return true;
}
this.result = { code: code,
blockType: undefined, brDepth: undefined, brTable: undefined,
funcIndex: undefined, typeIndex: undefined, localIndex: undefined,
globalIndex: undefined, memoryAddress: undefined, literal: undefined };
return true;
};
BinaryReader.prototype.readCodeOperator_0xfe = function () {
var MAX_CODE_OPERATOR_0XFE_SIZE = 11;
var pos = this._pos;
if (!this._eof && pos + MAX_CODE_OPERATOR_0XFE_SIZE > this._length) {
return false;
}
var code = this._data[this._pos++] | 0xfe00;
var memoryAddress;
switch (code) {
case 65024 /* atomic_wake */:
case 65025 /* i32_atomic_wait */:
case 65026 /* i64_atomic_wait */:
case 65040 /* i32_atomic_load */:
case 65041 /* i64_atomic_load */:
case 65042 /* i32_atomic_load8_u */:
case 65043 /* i32_atomic_load16_u */:
case 65044 /* i64_atomic_load8_u */:
case 65045 /* i64_atomic_load16_u */:
case 65046 /* i64_atomic_load32_u */:
case 65047 /* i32_atomic_store */:
case 65048 /* i64_atomic_store */:
case 65049 /* i32_atomic_store8 */:
case 65050 /* i32_atomic_store16 */:
case 65051 /* i64_atomic_store8 */:
case 65052 /* i64_atomic_store16 */:
case 65053 /* i64_atomic_store32 */:
case 65054 /* i32_atomic_rmw_add */:
case 65055 /* i64_atomic_rmw_add */:
case 65056 /* i32_atomic_rmw8_u_add */:
case 65057 /* i32_atomic_rmw16_u_add */:
case 65058 /* i64_atomic_rmw8_u_add */:
case 65059 /* i64_atomic_rmw16_u_add */:
case 65060 /* i64_atomic_rmw32_u_add */:
case 65061 /* i32_atomic_rmw_sub */:
case 65062 /* i64_atomic_rmw_sub */:
case 65063 /* i32_atomic_rmw8_u_sub */:
case 65064 /* i32_atomic_rmw16_u_sub */:
case 65065 /* i64_atomic_rmw8_u_sub */:
case 65066 /* i64_atomic_rmw16_u_sub */:
case 65067 /* i64_atomic_rmw32_u_sub */:
case 65068 /* i32_atomic_rmw_and */:
case 65069 /* i64_atomic_rmw_and */:
case 65070 /* i32_atomic_rmw8_u_and */:
case 65071 /* i32_atomic_rmw16_u_and */:
case 65072 /* i64_atomic_rmw8_u_and */:
case 65073 /* i64_atomic_rmw16_u_and */:
case 65074 /* i64_atomic_rmw32_u_and */:
case 65075 /* i32_atomic_rmw_or */:
case 65076 /* i64_atomic_rmw_or */:
case 65077 /* i32_atomic_rmw8_u_or */:
case 65078 /* i32_atomic_rmw16_u_or */:
case 65079 /* i64_atomic_rmw8_u_or */:
case 65080 /* i64_atomic_rmw16_u_or */:
case 65081 /* i64_atomic_rmw32_u_or */:
case 65082 /* i32_atomic_rmw_xor */:
case 65083 /* i64_atomic_rmw_xor */:
case 65084 /* i32_atomic_rmw8_u_xor */:
case 65085 /* i32_atomic_rmw16_u_xor */:
case 65086 /* i64_atomic_rmw8_u_xor */:
case 65087 /* i64_atomic_rmw16_u_xor */:
case 65088 /* i64_atomic_rmw32_u_xor */:
case 65089 /* i32_atomic_rmw_xchg */:
case 65090 /* i64_atomic_rmw_xchg */:
case 65091 /* i32_atomic_rmw8_u_xchg */:
case 65092 /* i32_atomic_rmw16_u_xchg */:
case 65093 /* i64_atomic_rmw8_u_xchg */:
case 65094 /* i64_atomic_rmw16_u_xchg */:
case 65095 /* i64_atomic_rmw32_u_xchg */:
case 65096 /* i32_atomic_rmw_cmpxchg */:
case 65097 /* i64_atomic_rmw_cmpxchg */:
case 65098 /* i32_atomic_rmw8_u_cmpxchg */:
case 65099 /* i32_atomic_rmw16_u_cmpxchg */:
case 65100 /* i64_atomic_rmw8_u_cmpxchg */:
case 65101 /* i64_atomic_rmw16_u_cmpxchg */:
case 65102 /* i64_atomic_rmw32_u_cmpxchg */:
memoryAddress = this.readMemoryImmediate();
break;
default:
this.error = new Error("Unknown operator: " + code);
this.state = -1 /* ERROR */;
return true;
}
this.result = { code: code,
blockType: undefined, brDepth: undefined, brTable: undefined,
funcIndex: undefined, typeIndex: undefined, localIndex: undefined,
globalIndex: undefined, memoryAddress: memoryAddress, literal: undefined };
return true;
};
BinaryReader.prototype.readCodeOperator = function () {
if (this.state === 30 /* CODE_OPERATOR */ &&
this._pos >= this._functionRange.end) {
@@ -938,7 +1138,7 @@ var BinaryReader = (function () {
if (!this._eof && pos + MAX_CODE_OPERATOR_SIZE > this._length) {
return false;
}
var code = this._data[this._pos++];
var code = this._data[this._pos++] | 0;
var blockType, brDepth, brTable, funcIndex, typeIndex, localIndex, globalIndex, memoryAddress, literal, reserved;
switch (code) {
case 2 /* block */:
@@ -1025,6 +1225,158 @@ var BinaryReader = (function () {
literal = new DataView(this._data.buffer, this._data.byteOffset).getFloat64(this._pos, true);
this._pos += 8;
break;
case 252 /* prefix_0xfc */:
if (this.readCodeOperator_0xfc()) {
return true;
}
this._pos = pos;
return false;
case 254 /* prefix_0xfe */:
if (this.readCodeOperator_0xfe()) {
return true;
}
this._pos = pos;
return false;
case 0 /* unreachable */:
case 1 /* nop */:
case 5 /* else */:
case 11 /* end */:
case 15 /* return */:
case 26 /* drop */:
case 27 /* select */:
case 69 /* i32_eqz */:
case 70 /* i32_eq */:
case 71 /* i32_ne */:
case 72 /* i32_lt_s */:
case 73 /* i32_lt_u */:
case 74 /* i32_gt_s */:
case 75 /* i32_gt_u */:
case 76 /* i32_le_s */:
case 77 /* i32_le_u */:
case 78 /* i32_ge_s */:
case 79 /* i32_ge_u */:
case 80 /* i64_eqz */:
case 81 /* i64_eq */:
case 82 /* i64_ne */:
case 83 /* i64_lt_s */:
case 84 /* i64_lt_u */:
case 85 /* i64_gt_s */:
case 86 /* i64_gt_u */:
case 87 /* i64_le_s */:
case 88 /* i64_le_u */:
case 89 /* i64_ge_s */:
case 90 /* i64_ge_u */:
case 91 /* f32_eq */:
case 92 /* f32_ne */:
case 93 /* f32_lt */:
case 94 /* f32_gt */:
case 95 /* f32_le */:
case 96 /* f32_ge */:
case 97 /* f64_eq */:
case 98 /* f64_ne */:
case 99 /* f64_lt */:
case 100 /* f64_gt */:
case 101 /* f64_le */:
case 102 /* f64_ge */:
case 103 /* i32_clz */:
case 104 /* i32_ctz */:
case 105 /* i32_popcnt */:
case 106 /* i32_add */:
case 107 /* i32_sub */:
case 108 /* i32_mul */:
case 109 /* i32_div_s */:
case 110 /* i32_div_u */:
case 111 /* i32_rem_s */:
case 112 /* i32_rem_u */:
case 113 /* i32_and */:
case 114 /* i32_or */:
case 115 /* i32_xor */:
case 116 /* i32_shl */:
case 117 /* i32_shr_s */:
case 118 /* i32_shr_u */:
case 119 /* i32_rotl */:
case 120 /* i32_rotr */:
case 121 /* i64_clz */:
case 122 /* i64_ctz */:
case 123 /* i64_popcnt */:
case 124 /* i64_add */:
case 125 /* i64_sub */:
case 126 /* i64_mul */:
case 127 /* i64_div_s */:
case 128 /* i64_div_u */:
case 129 /* i64_rem_s */:
case 130 /* i64_rem_u */:
case 131 /* i64_and */:
case 132 /* i64_or */:
case 133 /* i64_xor */:
case 134 /* i64_shl */:
case 135 /* i64_shr_s */:
case 136 /* i64_shr_u */:
case 137 /* i64_rotl */:
case 138 /* i64_rotr */:
case 139 /* f32_abs */:
case 140 /* f32_neg */:
case 141 /* f32_ceil */:
case 142 /* f32_floor */:
case 143 /* f32_trunc */:
case 144 /* f32_nearest */:
case 145 /* f32_sqrt */:
case 146 /* f32_add */:
case 147 /* f32_sub */:
case 148 /* f32_mul */:
case 149 /* f32_div */:
case 150 /* f32_min */:
case 151 /* f32_max */:
case 152 /* f32_copysign */:
case 153 /* f64_abs */:
case 154 /* f64_neg */:
case 155 /* f64_ceil */:
case 156 /* f64_floor */:
case 157 /* f64_trunc */:
case 158 /* f64_nearest */:
case 159 /* f64_sqrt */:
case 160 /* f64_add */:
case 161 /* f64_sub */:
case 162 /* f64_mul */:
case 163 /* f64_div */:
case 164 /* f64_min */:
case 165 /* f64_max */:
case 166 /* f64_copysign */:
case 167 /* i32_wrap_i64 */:
case 168 /* i32_trunc_s_f32 */:
case 169 /* i32_trunc_u_f32 */:
case 170 /* i32_trunc_s_f64 */:
case 171 /* i32_trunc_u_f64 */:
case 172 /* i64_extend_s_i32 */:
case 173 /* i64_extend_u_i32 */:
case 174 /* i64_trunc_s_f32 */:
case 175 /* i64_trunc_u_f32 */:
case 176 /* i64_trunc_s_f64 */:
case 177 /* i64_trunc_u_f64 */:
case 178 /* f32_convert_s_i32 */:
case 179 /* f32_convert_u_i32 */:
case 180 /* f32_convert_s_i64 */:
case 181 /* f32_convert_u_i64 */:
case 182 /* f32_demote_f64 */:
case 183 /* f64_convert_s_i32 */:
case 184 /* f64_convert_u_i32 */:
case 185 /* f64_convert_s_i64 */:
case 186 /* f64_convert_u_i64 */:
case 187 /* f64_promote_f32 */:
case 188 /* i32_reinterpret_f32 */:
case 189 /* i64_reinterpret_f64 */:
case 190 /* f32_reinterpret_i32 */:
case 191 /* f64_reinterpret_i64 */:
case 192 /* i32_extend8_s */:
case 193 /* i32_extend16_s */:
case 194 /* i64_extend8_s */:
case 195 /* i64_extend16_s */:
case 196 /* i64_extend32_s */:
break;
default:
this.error = new Error("Unknown operator: " + code);
this.state = -1 /* ERROR */;
return true;
}
this.result = { code: code,
blockType: blockType, brDepth: brDepth, brTable: brTable,

View File

@@ -191,6 +191,7 @@
#include "nsRect.h"
#include "nsRefreshTimer.h"
#include "nsSandboxFlags.h"
#include "nsIServiceWorkerManager.h"
#include "nsSHistory.h"
#include "nsStructuredCloneContainer.h"
#include "nsSubDocumentFrame.h"
@@ -2792,7 +2793,7 @@ nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal)
// Don't pre-allocate the client when we are sandboxed. The inherited
// principal does not take sandboxing into account.
// TODO: Refactor sandboxing principal code out so we can use it here.
if (!aPrincipal && (mSandboxFlags & SANDBOXED_ORIGIN)) {
if (!aPrincipal && mSandboxFlags) {
return;
}
@@ -2834,18 +2835,34 @@ nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal)
return;
}
// We're done if there is no parent controller or if this docshell
// is not permitted to control for some reason.
Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
if (controller.isNothing()) {
if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(nullptr)) {
return;
}
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
return;
}
// If the parent is controlled then propagate that controller to the
// initial about:blank client as well. This will set the controller
// in the ClientManagerService in the parent.
RefPtr<ClientHandle> handle =
ClientManager::CreateHandle(mInitialClientSource->Info(),
parentInner->EventTargetFor(TaskCategory::Other));
handle->Control(controller.ref());
//
// Note: If the registration is missing from the SWM we avoid setting
// the controller on the client. We can do this synchronously
// for now since SWM is in the child process. In the future
// when SWM is in the parent process we will probably have to
// always set the initial client source and then somehow clear
// it if we find the registration is acutally gone. Its also
// possible this race only occurs in cases where the resulting
// window is no longer exposed. For example, in theory the SW
// should not go away if our parent window is controlled.
if (!swm->StartControlling(mInitialClientSource->Info(), controller.ref())) {
return;
}
// Also mark the ClientSource as controlled directly in case script
// immediately accesses navigator.serviceWorker.controller.
@@ -14085,6 +14102,54 @@ nsDocShell::CanSetOriginAttributes()
return true;
}
bool
nsDocShell::ServiceWorkerAllowedToControlWindow(nsIURI* aURI)
{
// NOTE: Ideally this method would call one of the
// nsContentUtils::StorageAllowed*() methods to determine if the
// interception is allowed. Unfortunately we cannot safely do this
// before the first window loads in the child process because the
// permission manager might not have all its data yet. Therefore,
// we use this somewhat lame alternate implementation here. Once
// interception is moved to the parent process we should switch
// to calling nsContentUtils::StorageAllowed*(). See bug 1428130.
if (UsePrivateBrowsing() || mSandboxFlags) {
return false;
}
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
uint32_t lifetimePolicy = nsContentUtils::CookiesLifetimePolicy();
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
lifetimePolicy == nsICookieService::ACCEPT_SESSION) {
return false;
}
if (!aURI || cookieBehavior == nsICookieService::BEHAVIOR_ACCEPT) {
return true;
}
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
: nullptr;
if (parentWindow) {
nsresult rv = NS_OK;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
if (thirdPartyUtil) {
bool isThirdPartyURI = true;
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI,
&isThirdPartyURI);
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
return false;
}
}
}
return true;
}
nsresult
nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs)
{
@@ -14289,27 +14354,11 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
bool* aShouldIntercept)
{
*aShouldIntercept = false;
// No in private browsing
if (UsePrivateBrowsing()) {
return NS_OK;
}
if (mSandboxFlags) {
// If we're sandboxed, don't intercept.
return NS_OK;
}
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
// If cookies are disabled, don't intercept.
return NS_OK;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_OK;
}
// For subresource requests we base our decision solely on the client's
// controller value. Any settings that would have blocked service worker
// access should have been set before the initial navigation created the
// window.
if (!aIsNonSubresourceRequest) {
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
@@ -14325,27 +14374,19 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
return NS_OK;
}
// If the user has set a cookie policy that restricts cookies, then
// avoid intercepting 3rd party iframes.
if (cookieBehavior != nsICookieService::BEHAVIOR_ACCEPT) {
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
: nullptr;
if (parentWindow) {
nsresult rv = NS_OK;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
bool isThirdPartyURI = true;
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI, &isThirdPartyURI);
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
return NS_OK;
}
}
// For navigations, first check to see if we are allowed to control a
// window with the given URL.
if (!ServiceWorkerAllowedToControlWindow(aURI)) {
return NS_OK;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_OK;
}
// We're allowed to control a window, so check with the ServiceWorkerManager
// for a matching service worker.
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
*aShouldIntercept = swm->IsAvailable(principal, aURI);

View File

@@ -352,6 +352,19 @@ public:
mAncestorOuterWindowIDs = mozilla::Move(aAncestorOuterWindowIDs);
}
bool CanSetOriginAttributes();
// Determine if a service worker is allowed to control a window in this
// docshell with the given URL. If there are any reasons it should not,
// this will return false. If true is returned then the window *may* be
// controlled. The caller must still consult either the parent controller
// or the ServiceWorkerManager to determine if a service worker should
// actually control the window.
//
// A nullptr URL is considered to be an about:blank window and will not
// trigger 3rd party iframe checks.
bool ServiceWorkerAllowedToControlWindow(nsIURI* aURI);
const mozilla::OriginAttributes& GetOriginAttributes()
{
return mOriginAttributes;

View File

@@ -2937,6 +2937,11 @@ public:
return sCookiesBehavior;
}
static uint32_t CookiesLifetimePolicy()
{
return sCookiesLifetimePolicy;
}
// The order of these entries matters, as we use std::min for total ordering
// of permissions. Private Browsing is considered to be more limiting
// then session scoping

View File

@@ -5599,7 +5599,10 @@ nsDocument::DispatchContentLoadedEvents()
using mozilla::dom::workers::ServiceWorkerManager;
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
swm->MaybeCheckNavigationUpdate(this);
Maybe<ClientInfo> clientInfo = GetClientInfo();
if (clientInfo.isSome()) {
swm->MaybeCheckNavigationUpdate(clientInfo.ref());
}
}
}

View File

@@ -1786,11 +1786,34 @@ nsGlobalWindowInner::EnsureClientSource()
}
}
// Verify the final ClientSource principal matches the final document
// principal. The ClientChannelHelper handles things like network
// redirects, but there are other ways the document principal can change.
// For example, if something sets the nsIChannel.owner property, then
// the final channel principal can be anything. Unfortunately there is
// no good way to detect this until after the channel completes loading.
//
// For now we handle this just by reseting the ClientSource. This will
// result in a new ClientSource with the correct principal being created.
// To APIs like ServiceWorker and Clients API it will look like there was
// an initial content page created that was then immediately replaced.
// This is pretty close to what we are actually doing.
if (mClientSource) {
nsCOMPtr<nsIPrincipal> clientPrincipal(mClientSource->Info().GetPrincipal());
if (!clientPrincipal || !clientPrincipal->Equals(mDoc->NodePrincipal())) {
mClientSource.reset();
}
}
// If we don't have a reserved client or an initial client, then create
// one now. This can happen in certain cases where we avoid preallocating
// the client in the docshell. This mainly occurs in situations where
// the principal is not clearly inherited from the parent; e.g. sandboxed
// iframes, window.open(), etc.
//
// We also do this late ClientSource creation if the final document ended
// up with a different principal.
//
// TODO: We may not be marking initial about:blank documents created
// this way as controlled by a service worker properly. The
// controller should be coming from the same place as the inheritted
@@ -1804,13 +1827,23 @@ nsGlobalWindowInner::EnsureClientSource()
mDoc->NodePrincipal());
MOZ_DIAGNOSTIC_ASSERT(mClientSource);
newClientSource = true;
// Note, we don't apply the loadinfo controller below if we create
// the ClientSource here.
}
// The load may have started controlling the Client as well. If
// so, mark it as controlled immediately here. The actor may
// or may not have been notified by the parent side about being
// controlled yet.
if (loadInfo) {
//
// Note: We should be careful not to control a client that was created late.
// These clients were not seen by the ServiceWorkerManager when it
// marked the LoadInfo controlled and it won't know about them. Its
// also possible we are creating the client late due to the final
// principal changing and these clients should definitely not be
// controlled by a service worker with a different principal.
else if (loadInfo) {
const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController();
if (controller.isSome()) {
mClientSource->SetController(controller.ref());

View File

@@ -3117,11 +3117,10 @@ nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus)
mStatus = aStatus;
/*
* If caller is not chrome and dom.disable_window_status_change is true,
* prevent propagating window.status to the UI by exiting early
* If caller is not chrome, prevent propagating window.status to the UI by
* exiting early.
*/
if (!CanSetProperty("dom.disable_window_status_change")) {
if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
return;
}

View File

@@ -579,6 +579,7 @@ skip-if = toolkit == 'android' #bug 687032
skip-if = stylo # bug 1293844
[test_bug1037687.html]
skip-if = stylo # bug 1293844
support-files = test_bug1037687_subframe.html
[test_bug1043106.html]
[test_bug1057176.html]
[test_bug1060938.html]

View File

@@ -15,12 +15,25 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1025933
SimpleTest.waitForExplicitFinish();
function test() {
var s = document.getElementById("host").createShadowRoot();
s.innerHTML = '<div style="width:100px;height:100px;background:red"></div>';
var el = s.firstElementChild;
is(el.clientWidth, 100);
is(el.clientHeight, 100);
SimpleTest.finish();
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, function() {
var iframe = document.createElement('iframe');
iframe.srcdoc = '<div id="content"> <div id="host"></div </div>';
iframe.onload = function() {
var s = iframe.contentDocument.getElementById("host").attachShadow({mode: 'open'});
s.innerHTML = '<div style="width:100px;height:100px;background:red"></div>';
var el = s.firstElementChild;
is(el.clientWidth, 100);
is(el.clientHeight, 100);
SimpleTest.finish();
}
document.body.appendChild(iframe);
});
}
</script>
@@ -28,9 +41,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1025933
<body onload="test()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1025933">Mozilla Bug 1025933</a>
<p id="display"></p>
<div id="content">
<div id="host"></div>
</div>
<pre id="test">
</pre>
</body>

View File

@@ -8,49 +8,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1037687
<title>Test for Bug 1037687</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1037687 **/
SimpleTest.waitForExplicitFinish();
var host;
var sr;
var embed;
var object;
var iframe;
var resourceLoadCount = 0;
function resourceLoaded(event) {
++resourceLoadCount;
ok(true, event.target + " got " + event.load);
if (resourceLoadCount == 3) {
SimpleTest.finish();
}
}
function createResource(sr, type) {
var el = document.createElement(type);
var attrName = type == "object" ? "data" : "src";
el.setAttribute(attrName, "file_mozfiledataurl_img.jpg");
el.onload = resourceLoaded;
var info = document.createElement("div");
info.textContent = type;
sr.appendChild(info);
sr.appendChild(el);
}
function test() {
host = document.getElementById("host");
sr = host.createShadowRoot();
embed = createResource(sr, "embed");
object = createResource(sr, "object");
iframe = createResource(sr, "iframe");
}
</script>
</head>
<body onload="test()">
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1037687">Mozilla Bug 1037687</a>
<p id="display"></p>
<div id="content" style="display: none">
@@ -58,6 +17,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1037687
</div>
<pre id="test">
</pre>
<div id="host"></div>
<script type="application/javascript">
/** Test for Bug 1037687 **/
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, function() {
// This test loads in an iframe, to ensure that the element instance is
// loaded with the correct value of the preference.
let iframe = document.createElement("iframe");
iframe.src = "test_bug1037687_subframe.html";
document.body.appendChild(iframe);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
var SimpleTest = window.parent.SimpleTest;
var ok = window.parent.ok;
var is = window.parent.is;
var host;
var sr;
var embed;
var object;
var iframe;
var resourceLoadCount = 0;
function resourceLoaded(event) {
++resourceLoadCount;
ok(true, event.target + " got " + event.load);
if (resourceLoadCount == 3) {
SimpleTest.finish();
}
}
function createResource(sr, type) {
var el = document.createElement(type);
var attrName = type == "object" ? "data" : "src";
el.setAttribute(attrName, "file_mozfiledataurl_img.jpg");
el.onload = resourceLoaded;
var info = document.createElement("div");
info.textContent = type;
sr.appendChild(info);
sr.appendChild(el);
}
function test() {
host = document.getElementById("host");
sr = host.attachShadow({mode: 'open'});
embed = createResource(sr, "embed");
object = createResource(sr, "object");
iframe = createResource(sr, "iframe");
}
</script>
</head>
<body onload="test()">
<div id="host"></div>
</body>
</html>

View File

@@ -65,6 +65,16 @@ ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs)
return ref.forget();
}
void
ClientHandle::OnShutdownThing()
{
NS_ASSERT_OWNINGTHREAD(ClientHandle);
if (!mDetachPromise) {
return;
}
mDetachPromise->Resolve(true, __func__);
}
ClientHandle::ClientHandle(ClientManager* aManager,
nsISerialEventTarget* aSerialEventTarget,
const ClientInfo& aClientInfo)
@@ -182,5 +192,21 @@ ClientHandle::PostMessage(StructuredCloneData& aData,
return ref.forget();
}
RefPtr<GenericPromise>
ClientHandle::OnDetach()
{
NS_ASSERT_OWNINGTHREAD(ClientSource);
if (!mDetachPromise) {
mDetachPromise = new GenericPromise::Private(__func__);
if (IsShutdown()) {
mDetachPromise->Resolve(true, __func__);
}
}
RefPtr<GenericPromise> ref(mDetachPromise);
return Move(ref);
}
} // namespace dom
} // namespace mozilla

View File

@@ -42,6 +42,7 @@ class ClientHandle final : public ClientThing<ClientHandleChild>
RefPtr<ClientManager> mManager;
nsCOMPtr<nsISerialEventTarget> mSerialEventTarget;
RefPtr<GenericPromise::Private> mDetachPromise;
ClientInfo mClientInfo;
~ClientHandle();
@@ -52,6 +53,10 @@ class ClientHandle final : public ClientThing<ClientHandleChild>
already_AddRefed<ClientOpPromise>
StartOp(const ClientOpConstructorArgs& aArgs);
// ClientThing interface
void
OnShutdownThing() override;
// Private methods called by ClientHandleChild
void
ExecutionReady(const ClientInfo& aClientInfo);
@@ -90,6 +95,17 @@ public:
PostMessage(ipc::StructuredCloneData& aData,
const ServiceWorkerDescriptor& aSource);
// Return a Promise that resolves when the ClientHandle object is detached
// from its remote actors. This will happen if the ClientSource is destroyed
// and triggers the cleanup of the handle actors. It will also naturally
// happen when the ClientHandle is de-referenced and tears down its own
// actors.
//
// Note: This method can only be called on the ClientHandle owning thread,
// but the MozPromise lets you Then() to another thread.
RefPtr<GenericPromise>
OnDetach();
NS_INLINE_DECL_REFCOUNTING(ClientHandle);
};

View File

@@ -7,11 +7,13 @@
#include "ClientInfo.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/ipc/BackgroundUtils.h"
namespace mozilla {
namespace dom {
using mozilla::ipc::PrincipalInfo;
using mozilla::ipc::PrincipalInfoToPrincipal;
ClientInfo::ClientInfo(const nsID& aId,
ClientType aType,
@@ -138,5 +140,13 @@ ClientInfo::IsPrivateBrowsing() const
}
}
nsCOMPtr<nsIPrincipal>
ClientInfo::GetPrincipal() const
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrincipal> ref = PrincipalInfoToPrincipal(PrincipalInfo());
return Move(ref);
}
} // namespace dom
} // namespace mozilla

View File

@@ -95,6 +95,11 @@ public:
// Determine if the client is in private browsing mode.
bool
IsPrivateBrowsing() const;
// Get a main-thread nsIPrincipal for the client. This may return nullptr
// if the PrincipalInfo() fails to deserialize for some reason.
nsCOMPtr<nsIPrincipal>
GetPrincipal() const;
};
} // namespace dom

View File

@@ -206,6 +206,14 @@ ClientSource::WorkerExecutionReady(WorkerPrivate* aWorkerPrivate)
return;
}
// A client without access to storage should never be controlled by
// a service worker. Check this here in case we were controlled before
// execution ready. We can't reliably determine what our storage policy
// is before execution ready, unfortunately.
if (mController.isSome()) {
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate->IsStorageAllowed());
}
// Its safe to store the WorkerPrivate* here because the ClientSource
// is explicitly destroyed by WorkerPrivate before exiting its run loop.
MOZ_DIAGNOSTIC_ASSERT(mOwner.is<Nothing>());
@@ -235,6 +243,15 @@ ClientSource::WindowExecutionReady(nsPIDOMWindowInner* aInnerWindow)
return NS_ERROR_UNEXPECTED;
}
// A client without access to storage should never be controlled by
// a service worker. Check this here in case we were controlled before
// execution ready. We can't reliably determine what our storage policy
// is before execution ready, unfortunately.
if (mController.isSome()) {
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(aInnerWindow) ==
nsContentUtils::StorageAccess::eAllow);
}
// Don't use nsAutoCString here since IPC requires a full nsCString anyway.
nsCString spec;
@@ -290,6 +307,10 @@ ClientSource::DocShellExecutionReady(nsIDocShell* aDocShell)
return NS_ERROR_UNEXPECTED;
}
// Note: We don't assert storage access for a controlled client. If
// the about:blank actually gets used then WindowExecutionReady() will
// get called which asserts storage access.
// TODO: dedupe this with WindowExecutionReady
FrameType frameType = FrameType::Top_level;
if (!outer->IsTopLevelWindow()) {
@@ -360,6 +381,16 @@ ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
// this invariant.
MOZ_DIAGNOSTIC_ASSERT(!mClientInfo.IsPrivateBrowsing());
// A client without access to storage should never be controlled a
// a service worker. If we are already execution ready with a real
// window or worker, then verify assert the storage policy is correct.
if (GetInnerWindow()) {
MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::StorageAllowedForWindow(GetInnerWindow()) ==
nsContentUtils::StorageAccess::eAllow);
} else if (GetWorkerPrivate()) {
MOZ_DIAGNOSTIC_ASSERT(GetWorkerPrivate()->IsStorageAllowed());
}
if (mController.isSome() && mController.ref() == aServiceWorker) {
return;
}

View File

@@ -90,6 +90,15 @@ protected:
mActor->MaybeStartTeardown();
mActor = nullptr;
}
OnShutdownThing();
}
// Allow extending classes to take action when shutdown.
virtual void
OnShutdownThing()
{
// by default do nothing
}
public:
@@ -106,6 +115,8 @@ public:
// instead of calling ShutdownThing() to avoid calling MaybeStartTeardown()
// on the destroyed actor.
mShutdown = true;
OnShutdownThing();
}
};

View File

@@ -1263,23 +1263,6 @@ IMEContentObserver::ClearAddedNodesDuringDocumentChange()
", finished storing consecutive nodes", this));
}
// static
nsIContent*
IMEContentObserver::GetChildNode(nsINode* aParent, int32_t aOffset)
{
if (!aParent->HasChildren() || aOffset < 0 ||
aOffset >= static_cast<int32_t>(aParent->Length())) {
return nullptr;
}
if (!aOffset) {
return aParent->GetFirstChild();
}
if (aOffset == static_cast<int32_t>(aParent->Length() - 1)) {
return aParent->GetLastChild();
}
return aParent->GetChildAt_Deprecated(aOffset);
}
bool
IMEContentObserver::IsNextNodeOfLastAddedNode(nsINode* aParent,
nsIContent* aChild) const

View File

@@ -188,12 +188,6 @@ private:
bool IsSafeToNotifyIME() const;
bool IsEditorComposing() const;
/**
* nsINode::GetChildAt() is slow. So, this avoids to use it if it's
* first child or last child of aParent.
*/
static nsIContent* GetChildNode(nsINode* aParent, int32_t aOffset);
// Following methods are called by DocumentObserver when
// beginning to update the contents and ending updating the contents.
void BeginDocumentUpdate();

View File

@@ -13,38 +13,48 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1079236
/** Test for Bug 1079236 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
function runTests() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentDocument.body.innerHTML = '<div id="content"></div>';
function runTests() {
var c = document.getElementById("content");
var sr = c.createShadowRoot();
sr.innerHTML = "<input type='file'" + ">";
var file = sr.firstChild;
is(file.type, "file");
file.offsetLeft; // Flush layout because dispatching mouse events.
document.body.onmousemove = function(e) {
is(e.target, c, "Event target should be the element in non-Shadow DOM");
if (e.originalTarget == file) {
is(e.originalTarget, file,
"type='file' implementation doesn't seem to have native anonymous content");
} else {
var wrapped = SpecialPowers.wrap(e.originalTarget);
isnot(wrapped, file, "Shouldn't have the same event.target and event.originalTarget");
var c = iframe.contentDocument.getElementById("content");
var sr = c.attachShadow({mode: 'open'});
sr.innerHTML = "<input type='file'" + ">";
var file = sr.firstChild;
is(file.type, "file");
file.offsetLeft; // Flush layout because dispatching mouse events.
iframe.contentDocument.body.onmousemove = function(e) {
is(e.target, c, "Event target should be the element in non-Shadow DOM");
if (e.originalTarget == file) {
is(e.originalTarget, file,
"type='file' implementation doesn't seem to have native anonymous content");
} else {
var wrapped = SpecialPowers.wrap(e.originalTarget);
isnot(wrapped, file, "Shouldn't have the same event.target and event.originalTarget");
}
ok(!("composedTarget" in e), "Events shouldn't have composedTarget in non-chrome context!");
e = SpecialPowers.wrap(e);
var composedTarget = SpecialPowers.unwrap(e.composedTarget);
ok(composedTarget, file, "composedTarget should be the file object.");
SimpleTest.finish();
}
ok(!("composedTarget" in e), "Events shouldn't have composedTarget in non-chrome context!");
e = SpecialPowers.wrap(e);
var composedTarget = SpecialPowers.unwrap(e.composedTarget);
ok(composedTarget, file, "composedTarget should be the file object.");
SimpleTest.finish();
var r = file.getBoundingClientRect();
synthesizeMouse(file, r.width / 6, r.height / 2, { type: "mousemove"}, iframe.contentWindow);
iframe.contentDocument.body.onmousemove = null;
}
var r = file.getBoundingClientRect();
synthesizeMouse(file, r.width / 6, r.height / 2, { type: "mousemove"} );
document.body.onmousemove = null;
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, runTests);
});
</script>
</head>

View File

@@ -10,37 +10,47 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1145910
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<style>
div:active {
color: rgb(0, 255, 0);
}
</style>
<div id="host">Foo</div>
<script type="application/javascript">
/** Test for Bug 1145910 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
var host = document.getElementById("host");
var shadow = host.createShadowRoot();
function runTests() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentDocument.body.innerHTML =
'<style> div:active { color: rgb(0, 255, 0); } </style> <div id="host">Foo</div>';
var host = iframe.contentDocument.getElementById("host");
var shadow = host.attachShadow({mode: 'open'});
shadow.innerHTML = '<style>div:active { color: rgb(0, 255, 0); }</style><div id="inner">Bar</div>';
var inner = shadow.getElementById("inner");
var iframeWin = iframe.contentWindow;
is(window.getComputedStyle(host).color, "rgb(0, 0, 0)", "The host should not be active");
is(window.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
is(iframeWin.getComputedStyle(host).color, "rgb(0, 0, 0)", "The host should not be active");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
synthesizeMouseAtCenter(host, { type: "mousedown" });
synthesizeMouseAtCenter(host, { type: "mousedown" }, iframeWin);
is(window.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
is(window.getComputedStyle(host).color, "rgb(0, 255, 0)", "Host should be active when the inner div is made active.");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
is(iframeWin.getComputedStyle(host).color, "rgb(0, 255, 0)", "Host should be active when the inner div is made active.");
synthesizeMouseAtCenter(host, { type: "mouseup" });
synthesizeMouseAtCenter(host, { type: "mouseup" }, iframeWin);
is(window.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
is(window.getComputedStyle(host).color, "rgb(0, 0, 0)", "Host should no longer be active.");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
is(iframeWin.getComputedStyle(host).color, "rgb(0, 0, 0)", "Host should no longer be active.");
SimpleTest.finish();
};
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, runTests);
});
</script>

View File

@@ -10,32 +10,44 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1150308
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="host"><span id="distributeme">Foo</span></div>
<script type="application/javascript">
/** Test for Bug 1150308 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
var host = document.getElementById("host");
var shadow = host.createShadowRoot();
shadow.innerHTML = '<style>.bar:active { color: rgb(0, 255, 0); }</style><div class="bar" id="inner"><content></content></div>';
function runTests() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentDocument.body.innerHTML =
'<div id="host"><span id="distributeme">Foo</span></div>';
var host = iframe.contentDocument.getElementById("host");
var shadow = host.attachShadow({mode: 'open'});
shadow.innerHTML = '<style>.bar:active { color: rgb(0, 255, 0); }</style><div class="bar" id="inner"><slot></slot></div>';
var inner = shadow.getElementById("inner");
var distributed = document.getElementById("distributeme");
var distributed = iframe.contentDocument.getElementById("distributeme");
var iframeWin = iframe.contentWindow;
is(window.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
synthesizeMouseAtCenter(distributed, { type: "mousedown" });
synthesizeMouseAtCenter(distributed, { type: "mousedown" }, iframeWin);
is(window.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
synthesizeMouseAtCenter(distributed, { type: "mouseup" });
synthesizeMouseAtCenter(distributed, { type: "mouseup" }, iframeWin);
is(window.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
SimpleTest.finish();
});
};
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, runTests);
});
</script>
</body>
</html>

View File

@@ -6,20 +6,21 @@
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script>
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.webcomponents.enabled", true]
]});
function runTests()
{
let dragService = SpecialPowers.Cc["@mozilla.org/widget/dragservice;1"].
getService(SpecialPowers.Ci.nsIDragService);
let shadow = document.querySelector('#outter').createShadowRoot();
let target = document.createElement('a');
let linkText = document.createTextNode("Drag me if you can!");
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentDocument.body.innerHTML = '<div id="outter"/>';
let iframeDoc = iframe.contentDocument;
let iframeWin = iframe.contentWindow;
let shadow = iframeDoc.querySelector('#outter').attachShadow({mode: 'open'});
let target = iframeDoc.createElement('a');
let linkText = iframeDoc.createTextNode("Drag me if you can!");
target.appendChild(linkText);
target.href = "http://www.mozilla.org/";
shadow.appendChild(target);
@@ -35,20 +36,29 @@ function runTests()
}
ok(!dragService.getCurrentSession(), "There shouldn't be a drag session!");
window.addEventListener("dragstart", trapDrag, true);
synthesizeMouse(target, 2, 2, { type: "mousedown" });
synthesizeMouse(target, 11, 11, { type: "mousemove" });
synthesizeMouse(target, 20, 20, { type: "mousemove" });
window.removeEventListener("dragstart", trapDrag, true);
iframeWin.addEventListener("dragstart", trapDrag, true);
synthesizeMouse(target, 2, 2, { type: "mousedown" }, iframeWin);
synthesizeMouse(target, 11, 11, { type: "mousemove" }, iframeWin);
synthesizeMouse(target, 20, 20, { type: "mousemove" }, iframeWin);
iframeWin.removeEventListener("dragstart", trapDrag, true);
ok(dragService.getCurrentSession(), "Drag session is available.");
dragService.endDragSession(false);
ok(!dragService.getCurrentSession(), "There shouldn't be a drag session anymore!");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, runTests);
});
</script>
<body onload="window.setTimeout(runTests, 0);">
<div id="outter"/>
<body>
</body>
</html>

View File

@@ -37,7 +37,7 @@ BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
nsresult
BlobSet::AppendString(const nsAString& aString, bool nativeEOL)
{
nsAutoCString utf8Str;
nsCString utf8Str;
if (NS_WARN_IF(!AppendUTF16toUTF8(aString, utf8Str, mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@@ -15,6 +15,17 @@ interface nsIInterceptedChannel;
interface nsIPrincipal;
interface nsIRunnable;
interface nsIURI;
%{C++
namespace mozilla {
namespace dom {
class ClientInfo;
class ServiceWorkerDescriptor;
} // namespace dom
} // namespace mozilla
%}
[ref] native const_ClientInfoRef(const mozilla::dom::ClientInfo);
[ref] native const_ServiceWorkerDescriptorRef(const mozilla::dom::ServiceWorkerDescriptor);
[scriptable, uuid(52ee2c9d-ee87-4caf-9588-23ae77ff8798)]
interface nsIServiceWorkerUnregisterCallback : nsISupports
@@ -150,6 +161,9 @@ interface nsIServiceWorkerManager : nsISupports
*/
[notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
[notxpcom, nostdcall] bool StartControlling(in const_ClientInfoRef aClientInfo,
in const_ServiceWorkerDescriptorRef aServiceWorker);
/**
* Documents that have called MaybeStartControlling() should call this when
* they are destroyed. This function may be called multiple times, and is

View File

@@ -507,7 +507,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLSelectElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLSlotElement",
{name: "HTMLSlotElement", disabled: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLSourceElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
@@ -843,7 +843,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ScopedCredentialInfo", disabled: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"ShadowRoot", // Bogus, but the test harness forces it on. See bug 1159768.
{name: "ShadowRoot", disabled: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"SharedWorker",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Set dom.webcomponents.enabled pref to true and loads an iframe, to ensure
* that the Element instance is loaded with the correct value of the
* preference.
*
* @return {Promise} promise that resolves when iframe is loaded.
*/
function setWebComponentsPrefAndCreateIframe(aSrcDoc) {
return new Promise(function (aResolve, aReject) {
SpecialPowers.pushPrefEnv({
set: [
["dom.webcomponents.enabled", true]
]
}, () => {
let iframe = document.createElement("iframe");
iframe.onload = function () { aResolve(iframe.contentDocument); }
iframe.onerror = function () { aReject('Failed to load iframe'); }
if (aSrcDoc) {
iframe.srcdoc = aSrcDoc;
}
document.body.appendChild(iframe);
});
});
}

View File

@@ -2,13 +2,12 @@
support-files =
inert_style.css
dummy_page.html
head.js
[test_bug900724.html]
[test_bug1017896.html]
[test_bug1176757.html]
[test_bug1276240.html]
[test_content_element.html]
skip-if = true # Triggers assertions about flattened tree inconsistencies and it's going away in bug 1418002.
[test_custom_element_callback_innerhtml.html]
[test_custom_element_htmlconstructor.html]
skip-if = os == 'android' # bug 1323645

View File

@@ -5,13 +5,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1176757
-->
<head>
<title>Test for Bug 1176757</title>
<script type="text/javascript" src="head.js"></script>
<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>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1176757">Mozilla Bug 1176757</a>
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1176757">Mozilla Bug 1176757</a>
<p id="display"></p>
<div id="content" style="display: none">
@@ -20,19 +21,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1176757
<script class="testbody" type="text/javascript">
/** Test for Bug 1176757 **/
var element = document.createElement("a");
var shadowRoot = element.createShadowRoot();
var thrownException = false;
SimpleTest.waitForExplicitFinish();
setWebComponentsPrefAndCreateIframe()
.then((aDocument) => {
var element = aDocument.createElement("div");
var shadowRoot = element.attachShadow({mode: "open"});
var thrownException = false;
try {
shadowRoot.cloneNode();
} catch(err) {
thrownException = err;
}
try {
shadowRoot.cloneNode();
} catch(err) {
thrownException = err;
}
ok(thrownException !== false, "An exception should've been thrown");
is(thrownException.name, "DataCloneError", "A DataCloneError exception should've been thrown");
ok(thrownException !== false, "An exception should've been thrown");
is(thrownException.name, "DataCloneError", "A DataCloneError exception should've been thrown");
SimpleTest.finish();
});
</script>
</pre>
</body>

View File

@@ -5,83 +5,89 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1269155
-->
<head>
<title>Test for Bug 1269155</title>
<script type="text/javascript" src="head.js"></script>
<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>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1269155">Mozilla Bug 1269155</a>
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1269155">Mozilla Bug 1269155</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 1269155 **/
var host = document.querySelector('#content');
var root = host.createShadowRoot();
SimpleTest.waitForExplicitFinish();
var header1 = document.createElement('h1');
header1.textContent = 'Shadow Header1';
var content = '<div id="content" style="display: none"> </div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
var host = aDocument.querySelector('#content');
var root = host.attachShadow({mode: "open"});
var paragraph1 = document.createElement('p');
paragraph1.textContent = 'shadow text paragraph1';
var header1 = aDocument.createElement('h1');
header1.textContent = 'Shadow Header1';
root.appendChild(header1);
root.appendChild(paragraph1);
var paragraph1 = aDocument.createElement('p');
paragraph1.textContent = 'shadow text paragraph1';
var root2 = paragraph1.createShadowRoot();
var header2 = document.createElement('h2');
header2.textContent = 'Shadow Header2';
root.appendChild(header1);
root.appendChild(paragraph1);
var paragraph2 = document.createElement('p');
paragraph2.textContent = 'shadow text paragraph2';
root2.appendChild(header2);
root2.appendChild(paragraph2);
var root2 = paragraph1.attachShadow({mode: "open"});
var header2 = aDocument.createElement('h2');
header2.textContent = 'Shadow Header2';
var paragraph2 = aDocument.createElement('p');
paragraph2.textContent = 'shadow text paragraph2';
root2.appendChild(header2);
root2.appendChild(paragraph2);
var frag = document.createDocumentFragment();
var paragraph3 = document.createElement('p');
paragraph3.textContent = 'fragment paragraph3';
frag.appendChild(paragraph3);
var frag = aDocument.createDocumentFragment();
var paragraph3 = aDocument.createElement('p');
paragraph3.textContent = 'fragment paragraph3';
frag.appendChild(paragraph3);
var root3 = paragraph3.createShadowRoot();
var header4 = document.createElement('h2');
header4.textContent = 'Shadow Header3';
var root3 = paragraph3.attachShadow({mode: "open"});
var header4 = aDocument.createElement('h2');
header4.textContent = 'Shadow Header3';
var paragraph4 = document.createElement('p');
paragraph4.textContent = 'shadow text paragraph4';
var paragraph4 = aDocument.createElement('p');
paragraph4.textContent = 'shadow text paragraph4';
root3.appendChild(header4);
root3.appendChild(paragraph4);
root3.appendChild(header4);
root3.appendChild(paragraph4);
//shadow dom without compose
is(root.getRootNode(), root, "root.getRootNode() should be root.");
is(root2.getRootNode(), root2, "root2.getRootNode() should be root.");
is(root3.getRootNode(), root3, "root3.getRootNode() should be root.");
is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
is(header2.getRootNode(), root2, "header1.getRootNode() should be root2.");
is(header4.getRootNode(), root3, "header1.getRootNode() should be root3.");
//shadow dom with compose
is(root.getRootNode({ composed: true }), document, "root.getRootNode() with composed flag should be document.");
is(root2.getRootNode({ composed: true }), document, "root2.getRootNode() with composed flag should be document.");
is(root3.getRootNode({ composed: true }), frag, "root3.getRootNode() with composed flag should be frag.");
is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
is(header2.getRootNode({ composed: true }) , document, "header2.getRootNode() with composed flag should be document.");
is(header4.getRootNode({ composed: true }) , frag, "head4.getRootNode() with composed flag should be frag.");
//dom without compose
is(host.getRootNode(), document, "host.getRootNode() should be document.");
is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
is(paragraph1.getRootNode(), root, "paragraph1.getRootNode() should be root.");
is(frag.getRootNode(), frag, "frag.getRootNode() should be frag.");
//dom with compose
is(host.getRootNode({ composed: true }) , document, "host.getRootNode() with composed flag should be document.");
is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
is(paragraph1.getRootNode({ composed: true }) , document, "paragraph1.getRootNode() with composed flag should be document.");
is(frag.getRootNode({ composed: true }) , frag, "frag.getRootNode() with composed flag should be frag.");
//shadow dom without compose
is(root.getRootNode(), root, "root.getRootNode() should be root.");
is(root2.getRootNode(), root2, "root2.getRootNode() should be root.");
is(root3.getRootNode(), root3, "root3.getRootNode() should be root.");
is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
is(header2.getRootNode(), root2, "header1.getRootNode() should be root2.");
is(header4.getRootNode(), root3, "header1.getRootNode() should be root3.");
//shadow dom with compose
is(root.getRootNode({ composed: true }), aDocument, "root.getRootNode() with composed flag should be document.");
is(root2.getRootNode({ composed: true }), aDocument, "root2.getRootNode() with composed flag should be document.");
is(root3.getRootNode({ composed: true }), frag, "root3.getRootNode() with composed flag should be frag.");
is(header1.getRootNode({ composed: true }) , aDocument, "header1.getRootNode() with composed flag should be document.");
is(header2.getRootNode({ composed: true }) , aDocument, "header2.getRootNode() with composed flag should be document.");
is(header4.getRootNode({ composed: true }) , frag, "head4.getRootNode() with composed flag should be frag.");
//dom without compose
is(host.getRootNode(), aDocument, "host.getRootNode() should be document.");
is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
is(paragraph1.getRootNode(), root, "paragraph1.getRootNode() should be root.");
is(frag.getRootNode(), frag, "frag.getRootNode() should be frag.");
//dom with compose
is(host.getRootNode({ composed: true }) , aDocument, "host.getRootNode() with composed flag should be document.");
is(header1.getRootNode({ composed: true }) , aDocument, "header1.getRootNode() with composed flag should be document.");
is(paragraph1.getRootNode({ composed: true }) , aDocument, "paragraph1.getRootNode() with composed flag should be document.");
is(frag.getRootNode({ composed: true }) , frag, "frag.getRootNode() with composed flag should be frag.");
SimpleTest.finish();
});
</script>
</pre>
</body>

View File

@@ -1,131 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for HTMLContent element</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="grabme"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
// Create a ShadowRoot and append some nodes, containing an insertion point with a universal selector.
var shadow = $("grabme").createShadowRoot();
shadow.innerHTML = '<span><content id="point"></content></span>';
// Get the insertion point from the ShadowRoot and check that child of host is distributed.
// Insertion point should match everything because the selector set is empty.
var insertionPoint = shadow.getElementById("point");
$("grabme").innerHTML = '<div id="distme"></div>';
var distNodes = insertionPoint.getDistributedNodes();
is(distNodes[0], $("distme"), "Child of bound content should be distributed into insertion point with universal selector.");
is(distNodes.length, 1, "Should only have one child distributed into insertion point.");
// Add another node to bound content and make sure that the node list is static and does not change.
var someSpan = document.createElement("span");
$("grabme").appendChild(someSpan);
is(distNodes.length, 1, "NodeList from getDistributedNodes should be static.");
// Test content select.
$("grabme").innerHTML = '<div id="first" class="tall"></div><div id="second" class="skinny"></div>';
shadow.innerHTML = '<span><content select=".tall" id="point"></content></span>';
var insertionPoint = shadow.getElementById("point");
distNodes = insertionPoint.getDistributedNodes();
is(distNodes.length, 1, "Insertion point should only match element with the 'tall' class.");
is(distNodes[0], $("first"), "Insertion point should only match element with the 'tall' class.");
// Get rid of the select attribute and check that the insertion point matches everything.
insertionPoint.removeAttribute("select");
is(insertionPoint.getDistributedNodes().length, 2, "After removing the 'select' attribute, the insertion point should match everything.");
// Set an invalid selector and make sure that nothing is matched.
insertionPoint.setAttribute("select", "div:first-child");
is(insertionPoint.getDistributedNodes().length, 0, "Invalid selectors should match nothing.");
// all compound selectors must only be permitted simple selectors.
insertionPoint.setAttribute("select", "div:first-child, span");
is(insertionPoint.getDistributedNodes().length, 0, "Invalid selectors should match nothing.");
// Test multiple compound selectors.
$("grabme").innerHTML = '<div id="first"></div><span id="second"></span><span data-match-me="pickme" id="third"></span>';
insertionPoint.setAttribute("select", "span[data-match-me=pickme], div");
distNodes = insertionPoint.getDistributedNodes();
is(distNodes.length, 2, "Insertion point selector should only match two nodes.");
is(distNodes[0], $("first"), "First child node should match selector.");
is(distNodes[1], $("third"), "Third child node should match selector.");
// Test select property
insertionPoint.select = "#second, #third";
distNodes = insertionPoint.getDistributedNodes();
is(distNodes.length, 2, "Insertion point selector (set using property) should only match two nodes.");
is(distNodes[0], $("second"), "First child node should match selector.");
is(distNodes[1], $("third"), "Third child node should match selector.");
is(insertionPoint.select, "#second, #third", "select property should be transparent.");
// Empty set of selectors should match everything.
insertionPoint.select = "";
is(insertionPoint.getDistributedNodes().length, 3, "Empty set of selectors (set using property) should match everything.");
// Remove insertion point and make sure that the point does not have any nodes distributed.
$("grabme").innerHTML = '<div></div><span></span>';
insertionPoint.removeAttribute("select");
is(insertionPoint.getDistributedNodes().length, 2, "Insertion point with univeral selector should match two nodes.");
var insertionParent = insertionPoint.parentNode;
insertionParent.removeChild(insertionPoint);
is(insertionPoint.getDistributedNodes().length, 0, "Insertion point should match no nodes after removal.");
insertionParent.appendChild(insertionPoint);
is(insertionPoint.getDistributedNodes().length, 2, "Insertion point should match two nodes after appending.");
// Test multiple insertion points and check tree order distribution of points.
// Append two divs and three spans into host.
$("grabme").innerHTML = '<div></div><span></span><div></div><span></span><span></span>';
shadow.innerHTML = '<content select="div" id="divpoint"></content><content select="div, span" id="allpoint"></content>';
// Insertion point matching div
var divPoint = shadow.getElementById("divpoint");
// Insertion point matching span and div
var allPoint = shadow.getElementById("allpoint");
is(divPoint.getDistributedNodes().length, 2, "Two div nodes should be distributed into divPoint.");
is(allPoint.getDistributedNodes().length, 3, "Remaining nodes should be distributed into allPoint.");
shadow.removeChild(allPoint);
is(divPoint.getDistributedNodes().length, 2, "Number of div distributed into insertion point should not change.");
is(allPoint.getDistributedNodes().length, 0, "Removed insertion point should not have any nodes.");
shadow.insertBefore(allPoint, divPoint);
is(allPoint.getDistributedNodes().length, 5, "allPoint should have nodes distributed before divPoint.");
is(divPoint.getDistributedNodes().length, 0, "divPoint should have no distributed nodes because they are all distributed to allPoint.");
// Make sure that fallback content are in the distributed nodes.
$("grabme").innerHTML = '<div id="one"></div><div id="two"></div>';
shadow.innerHTML = '<content select="#nothing" id="point"><span id="fallback"></span></content>';
insertionPoint = shadow.getElementById("point");
is(insertionPoint.getDistributedNodes().length, 1, "There should be one distributed node from fallback content.");
is(insertionPoint.getDistributedNodes()[0].id, "fallback", "Distributed node should be fallback content.");
$("grabme").innerHTML = '';
shadow.innerHTML = '<content select="div" id="point"><span id="one"></span><span id="two"></span></content>';
insertionPoint = shadow.getElementById("point");
// Make sure that two fallback nodes are distributed into the insertion point.
is(insertionPoint.getDistributedNodes().length, 2, "There should be two distributed nodes from fallback content.");
is(insertionPoint.getDistributedNodes()[0].id, "one", "First distributed node should have an ID of one.");
is(insertionPoint.getDistributedNodes()[1].id, "two", "Second distributed node should have an ID of two.");
// Append a node that gets matched by the insertion point, thus causing the fallback content to be removed.
var matchingDiv = document.createElement("div");
matchingDiv.id = "three";
$("grabme").appendChild(matchingDiv);
is(insertionPoint.getDistributedNodes().length, 1, "There should be one node distributed from the host.");
is(insertionPoint.getDistributedNodes()[0].id, "three", "Node distriubted from host should have id of three.");
// Remove the matching node from the host and make sure that the fallback content gets distributed.
$("grabme").removeChild(matchingDiv);
is(insertionPoint.getDistributedNodes().length, 2, "There should be two distributed nodes from fallback content.");
is(insertionPoint.getDistributedNodes()[0].id, "one", "First distributed node should have an ID of one.");
is(insertionPoint.getDistributedNodes()[1].id, "two", "Second distributed node should have an ID of two.");
</script>
</body>
</html>

View File

@@ -5,115 +5,124 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1087460
-->
<head>
<title>Test for custom element callbacks in shadow DOM.</title>
<script type="text/javascript" src="head.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>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1087460">Bug 1087460</a>
<div id="container"></div>
<script>
// Test callback for custom element when used after registration.
SimpleTest.waitForExplicitFinish();
var connectedCallbackCount = 0;
var disconnectedCallbackCount = 0;
var attributeChangedCallbackCount = 0;
var content = '<div id="container"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
class Foo extends HTMLElement
{
connectedCallback() {
connectedCallbackCount++;
}
// Test callback for custom element when used after registration.
disconnectedCallback() {
disconnectedCallbackCount++;
}
var iframeWin = aDocument.defaultView;
var connectedCallbackCount = 0;
var disconnectedCallbackCount = 0;
var attributeChangedCallbackCount = 0;
attributeChangedCallback(aName, aOldValue, aNewValue) {
attributeChangedCallbackCount++;
}
class Foo extends iframeWin.HTMLElement
{
connectedCallback() {
connectedCallbackCount++;
}
static get observedAttributes() {
return ["data-foo"];
}
}
disconnectedCallback() {
disconnectedCallbackCount++;
}
customElements.define("x-foo", Foo);
attributeChangedCallback(aName, aOldValue, aNewValue) {
attributeChangedCallbackCount++;
}
var container = document.getElementById("container");
var shadow = container.createShadowRoot();
var customElem = document.createElement("x-foo");
static get observedAttributes() {
return ["data-foo"];
}
}
is(attributeChangedCallbackCount, 0, "attributeChangedCallback should not be called after just creating an element.");
customElem.setAttribute("data-foo", "bar");
is(attributeChangedCallbackCount, 1, "attributeChangedCallback should be called after setting an attribute.");
iframeWin.customElements.define("x-foo", Foo);
is(connectedCallbackCount, 0, "connectedCallback should not be called on an element that is not in a document/composed document.");
shadow.appendChild(customElem);
is(connectedCallbackCount, 1, "connectedCallback should be called after attaching custom element to the composed document.");
var container = aDocument.getElementById("container");
var shadow = container.attachShadow({mode: "open"});
var customElem = aDocument.createElement("x-foo");
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called without detaching custom element.");
shadow.removeChild(customElem);
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
is(attributeChangedCallbackCount, 0, "attributeChangedCallback should not be called after just creating an element.");
customElem.setAttribute("data-foo", "bar");
is(attributeChangedCallbackCount, 1, "attributeChangedCallback should be called after setting an attribute.");
// Test callback for custom element already in the composed doc when created.
is(connectedCallbackCount, 0, "connectedCallback should not be called on an element that is not in a document/composed document.");
shadow.appendChild(customElem);
is(connectedCallbackCount, 1, "connectedCallback should be called after attaching custom element to the composed document.");
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called without detaching custom element.");
shadow.removeChild(customElem);
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
shadow.innerHTML = "<x-foo></x-foo>";
is(connectedCallbackCount, 1, "connectedCallback should be called after creating an element in the composed document.");
// Test callback for custom element already in the composed doc when created.
shadow.innerHTML = "";
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
// Test callback for custom element in shadow DOM when host attached/detached to/from document.
shadow.innerHTML = "<x-foo></x-foo>";
is(connectedCallbackCount, 1, "connectedCallback should be called after creating an element in the composed document.");
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
shadow.innerHTML = "";
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after detaching custom element from the composed document.");
var host = document.createElement("div");
shadow = host.createShadowRoot();
customElem = document.createElement("x-foo");
// Test callback for custom element in shadow DOM when host attached/detached to/from document.
is(connectedCallbackCount, 0, "connectedCallback should not be called on newly created element.");
shadow.appendChild(customElem);
is(connectedCallbackCount, 0, "connectedCallback should not be called on attaching to a tree that is not in the composed document.");
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called.");
shadow.removeChild(customElem);
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called when detaching from a tree that is not in the composed document.");
var host = aDocument.createElement("div");
shadow = host.attachShadow({mode: "open"});
customElem = aDocument.createElement("x-foo");
shadow.appendChild(customElem);
is(connectedCallbackCount, 0, "connectedCallback should still not be called after reattaching to a shadow tree that is not in the composed document.");
is(connectedCallbackCount, 0, "connectedCallback should not be called on newly created element.");
shadow.appendChild(customElem);
is(connectedCallbackCount, 0, "connectedCallback should not be called on attaching to a tree that is not in the composed document.");
container.appendChild(host);
is(connectedCallbackCount, 1, "connectedCallback should be called after host is inserted into document.");
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called.");
shadow.removeChild(customElem);
is(disconnectedCallbackCount, 0, "disconnectedCallback should not be called when detaching from a tree that is not in the composed document.");
container.removeChild(host);
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after host is removed from document.");
shadow.appendChild(customElem);
is(connectedCallbackCount, 0, "connectedCallback should still not be called after reattaching to a shadow tree that is not in the composed document.");
// Test callback for custom element for upgraded element.
container.appendChild(host);
is(connectedCallbackCount, 1, "connectedCallback should be called after host is inserted into document.");
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
container.removeChild(host);
is(disconnectedCallbackCount, 1, "disconnectedCallback should be called after host is removed from document.");
shadow = container.shadowRoot;
shadow.innerHTML = "<x-bar></x-bar>";
// Test callback for custom element for upgraded element.
class Bar extends HTMLElement {
connectedCallback() {
connectedCallbackCount++;
}
};
connectedCallbackCount = 0;
disconnectedCallbackCount = 0;
attributeChangedCallbackCount = 0;
customElements.define("x-bar", Bar);
is(connectedCallbackCount, 1, "connectedCallback should be called after upgrading element in composed document.");
shadow = container.shadowRoot;
shadow.innerHTML = "<x-bar></x-bar>";
class Bar extends iframeWin.HTMLElement {
connectedCallback() {
connectedCallbackCount++;
}
};
iframeWin.customElements.define("x-bar", Bar);
is(connectedCallbackCount, 1, "connectedCallback should be called after upgrading element in composed document.");
SimpleTest.finish();
});
</script>
</body>

View File

@@ -5,21 +5,31 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1062578
-->
<head>
<title>Test for creating style in shadow root of host not in document.</title>
<script type="text/javascript" src="head.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>
<div id="grabme"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1062578">Bug 1062578</a>
<script>
var host = document.createElement("div");
var shadow = host.createShadowRoot();
shadow.innerHTML = '<style> #inner { height: 200px; } </style><div id="inner">Hello</div>';
grabme.appendChild(host);
SimpleTest.waitForExplicitFinish();
var inner = shadow.getElementById("inner");
is(getComputedStyle(inner, null).getPropertyValue("height"), "200px", "Style in shadow root should take effect.");
var content = '<div id="grabme"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
var host = aDocument.createElement("div");
var shadow = host.attachShadow({mode: "open"});
shadow.innerHTML = '<style> #inner { height: 200px; } </style><div id="inner">Hello</div>';
var iframeWin = aDocument.defaultView;
iframeWin.grabme.appendChild(host);
var inner = shadow.getElementById("inner");
is(iframeWin.getComputedStyle(inner, null).getPropertyValue("height"), "200px", "Style in shadow root should take effect.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1177991
-->
<head>
<title>Test for Bug 1177991</title>
<script type="text/javascript" src="head.js"></script>
<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" />
@@ -18,18 +19,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1177991
<pre id="test">
<script class="testbody" type="text/javascript">
var thrownException = false;
var shadowRoot = document.createElement('a').createShadowRoot();
SimpleTest.waitForExplicitFinish();
setWebComponentsPrefAndCreateIframe()
.then((aDocument) => {
var thrownException = false;
var shadowRoot = aDocument.createElement('div').attachShadow({mode: "open"});
try {
document.adoptNode(shadowRoot);
} catch(err) {
thrownException = err;
}
try {
aDocument.adoptNode(shadowRoot);
} catch(err) {
thrownException = err;
}
ok(thrownException !== false, "A HierarchyRequestError");
is(thrownException.name, "HierarchyRequestError", "A HierarchyRequestError should've been thrown");
ok(thrownException !== false, "A HierarchyRequestError");
is(thrownException.name, "HierarchyRequestError", "A HierarchyRequestError should've been thrown");
SimpleTest.finish();
});
</script>
</pre>
</body>

View File

@@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1177914
-->
<head>
<title>Test for Bug 1177914</title>
<script type="text/javascript" src="head.js"></script>
<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" />
@@ -18,19 +19,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1177914
<pre id="test">
<script class="testbody" type="text/javascript">
var thrownException = false;
var shadowRoot = document.createElement('a').createShadowRoot();
SimpleTest.waitForExplicitFinish();
setWebComponentsPrefAndCreateIframe()
.then((aDocument) => {
var thrownException = false;
var shadowRoot = aDocument.createElement('div').attachShadow({mode: "open"});
try {
document.importNode(shadowRoot);
} catch(err) {
thrownException = err;
}
try {
aDocument.importNode(shadowRoot);
} catch(err) {
thrownException = err;
}
ok(thrownException !== false, "A HierarchyRequestError");
is(thrownException.name, "NotSupportedError", "A NotSupportedError exception should've been thrown");
ok(thrownException !== false, "An exception should've been thrown");
is(thrownException.name, "NotSupportedError", "A NotSupportedError exception should've been thrown");
SimpleTest.finish();
});
</script>
</pre>
</body>

View File

@@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887541
-->
<head>
<title>Test for event retargeting in web components</title>
<script type="text/javascript" src="head.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@@ -12,136 +13,141 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887541
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
<script>
/*
* Creates an event listener with an expected event target.
*/
function createEventListener(expectedTarget, msg) {
return function(e) {
is(e.target, expectedTarget, msg);
};
}
SimpleTest.waitForExplicitFinish();
setWebComponentsPrefAndCreateIframe()
.then((aDocument) => {
/*
* Creates an event listener with an expected event target.
*/
function createEventListener(expectedTarget, msg) {
return function(e) {
is(e.target, expectedTarget, msg);
};
}
/*
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
*
* <div elemThree> ---- <shadow-root shadowOne>
* | |
* <div elemOne> <content elemTwo>
*
* Dispatch event on elemOne
*/
/*
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
*
* <div elemThree> ---- <shadow-root shadowOne>
* | |
* <div elemOne> <content elemTwo>
*
* Dispatch event on elemOne
*/
var elemOne = document.createElement("div");
var elemTwo = document.createElement("content");
var elemThree = document.createElement("div");
var shadowOne = elemThree.createShadowRoot();
var elemOne = aDocument.createElement("div");
var elemTwo = aDocument.createElement("content");
var elemThree = aDocument.createElement("div");
var shadowOne = elemThree.attachShadow({mode: "open"});
elemThree.appendChild(elemOne);
shadowOne.appendChild(elemTwo);
elemThree.appendChild(elemOne);
shadowOne.appendChild(elemTwo);
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
var customEvent = new CustomEvent("custom", { "bubbles" : true });
elemOne.dispatchEvent(customEvent);
var customEvent = new CustomEvent("custom", { "bubbles" : true });
elemOne.dispatchEvent(customEvent);
/*
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
*
* <div elemThree> ---- <shadow-root shadowOne>
* | |
* <div elemOne> <content elemTwo>
*
* Dispatch event on elemTwo
*/
/*
* Test of event retargeting through a basic ShadowRoot with a content insertion point.
*
* <div elemThree> ---- <shadow-root shadowOne>
* | |
* <div elemOne> <content elemTwo>
*
* Dispatch event on elemTwo
*/
elemOne = document.createElement("div");
elemTwo = document.createElement("content");
elemThree = document.createElement("div");
shadowOne = elemThree.createShadowRoot();
elemOne = aDocument.createElement("div");
elemTwo = aDocument.createElement("content");
elemThree = aDocument.createElement("div");
shadowOne = elemThree.attachShadow({mode: "open"});
elemThree.appendChild(elemOne);
shadowOne.appendChild(elemTwo);
elemThree.appendChild(elemOne);
shadowOne.appendChild(elemTwo);
elemTwo.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
shadowOne.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of shadowOne."));
elemTwo.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
shadowOne.addEventListener("custom", createEventListener(elemTwo, "elemTwo is in common ancestor tree of shadowOne."));
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemTwo.dispatchEvent(customEvent);
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemTwo.dispatchEvent(customEvent);
/*
* Test of event retargeting through a nested ShadowRoots with content insertion points.
*
* <div elemFive> --- <shadow-root shadowTwo>
* | |
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
* | |
* <content elemTwo> <content elemThree>
*
* Dispatch custom event on elemOne.
*/
/*
* Test of event retargeting through a nested ShadowRoots with content insertion points.
*
* <div elemFive> --- <shadow-root shadowTwo>
* | |
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
* | |
* <content elemTwo> <content elemThree>
*
* Dispatch custom event on elemOne.
*/
elemOne = document.createElement("div");
elemTwo = document.createElement("content");
elemThree = document.createElement("content");
var elemFour = document.createElement("div");
var elemFive = document.createElement("div");
var shadowTwo = elemFive.createShadowRoot();
shadowOne = elemFour.createShadowRoot();
elemOne = aDocument.createElement("div");
elemTwo = aDocument.createElement("content");
elemThree = aDocument.createElement("content");
var elemFour = aDocument.createElement("div");
var elemFive = aDocument.createElement("div");
var shadowTwo = elemFive.attachShadow({mode: "open"});
shadowOne = elemFour.attachShadow({mode: "open"});
elemFive.appendChild(elemOne);
shadowTwo.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowOne.appendChild(elemThree);
elemFive.appendChild(elemOne);
shadowTwo.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowOne.appendChild(elemThree);
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
elemFour.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFour."));
elemFive.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFive."));
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
shadowTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowTwo."));
elemOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemOne."));
elemTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemTwo."));
elemThree.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemThree."));
elemFour.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFour."));
elemFive.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of elemFive."));
shadowOne.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowOne."));
shadowTwo.addEventListener("custom", createEventListener(elemOne, "elemOne is in common ancestor tree of shadowTwo."));
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemOne.dispatchEvent(customEvent);
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemOne.dispatchEvent(customEvent);
/*
* Test of event retargeting through a nested ShadowRoots with content insertion points.
*
* <div elemFive> --- <shadow-root shadowTwo>
* | |
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
* | |
* <content elemTwo> <content elemThree>
*
* Dispatch custom event on elemThree.
*/
/*
* Test of event retargeting through a nested ShadowRoots with content insertion points.
*
* <div elemFive> --- <shadow-root shadowTwo>
* | |
* <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
* | |
* <content elemTwo> <content elemThree>
*
* Dispatch custom event on elemThree.
*/
elemOne = document.createElement("div");
elemTwo = document.createElement("content");
elemThree = document.createElement("content");
elemFour = document.createElement("div");
elemFive = document.createElement("div");
shadowTwo = elemFive.createShadowRoot();
shadowOne = elemFour.createShadowRoot();
elemOne = aDocument.createElement("div");
elemTwo = aDocument.createElement("content");
elemThree = aDocument.createElement("content");
elemFour = aDocument.createElement("div");
elemFive = aDocument.createElement("div");
shadowTwo = elemFive.attachShadow({mode: "open"});
shadowOne = elemFour.attachShadow({mode: "open"});
elemFive.appendChild(elemOne);
shadowTwo.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowOne.appendChild(elemThree);
elemFive.appendChild(elemOne);
shadowTwo.appendChild(elemFour);
elemFour.appendChild(elemTwo);
shadowOne.appendChild(elemThree);
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
elemFour.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of elemFour."));
elemFive.addEventListener("custom", createEventListener(elemFive, "elemFive is in common ancestor tree of elemFive."));
shadowOne.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of shadowOne."));
shadowTwo.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of shadowTwo."));
elemThree.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of elemThree."));
elemFour.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of elemFour."));
elemFive.addEventListener("custom", createEventListener(elemFive, "elemFive is in common ancestor tree of elemFive."));
shadowOne.addEventListener("custom", createEventListener(elemThree, "elemThree is in common ancestor tree of shadowOne."));
shadowTwo.addEventListener("custom", createEventListener(elemFour, "elemFour is in common ancestor tree of shadowTwo."));
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
customEvent = new CustomEvent("custom", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887541
-->
<head>
<title>Test for event model in web components</title>
<script type="text/javascript" src="head.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@@ -15,154 +16,159 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887541
var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
.getService(SpecialPowers.Ci.nsIEventListenerService);
function eventListener(e) {
eventChain.push(this);
}
SimpleTest.waitForExplicitFinish();
setWebComponentsPrefAndCreateIframe()
.then((aDocument) => {
function eventListener(e) {
eventChain.push(this);
}
function isEventChain(actual, expected, msg) {
is(actual.length, expected.length, msg);
for (var i = 0; i < expected.length; i++) {
is(actual[i], expected[i], msg + " at " + i);
}
function isEventChain(actual, expected, msg) {
is(actual.length, expected.length, msg);
for (var i = 0; i < expected.length; i++) {
is(actual[i], expected[i], msg + " at " + i);
}
if (0 < actual.length) {
var chain = els.getEventTargetChainFor(actual[0], false); // Events should be dispatched on actual[0].
ok(expected.length < chain.length, "There should be additional chrome event targets.");
}
}
if (0 < actual.length) {
var chain = els.getEventTargetChainFor(actual[0], false); // Events should be dispatched on actual[0].
ok(expected.length < chain.length, "There should be additional chrome event targets.");
}
}
/*
* <div elemOne> ------ <shadow-root shadowOne>
* |
* <span elemTwo>
* |
* <span elemThree>
*/
/*
* <div elemOne> ------ <shadow-root shadowOne>
* |
* <span elemTwo>
* |
* <span elemThree>
*/
var elemOne = document.createElement("div");
var elemTwo = document.createElement("span");
var elemThree = document.createElement("span");
var shadowOne = elemOne.createShadowRoot();
var elemOne = aDocument.createElement("div");
var elemTwo = aDocument.createElement("span");
var elemThree = aDocument.createElement("span");
var shadowOne = elemOne.attachShadow({mode: "open"});
shadowOne.appendChild(elemTwo);
elemTwo.appendChild(elemThree);
shadowOne.appendChild(elemTwo);
elemTwo.appendChild(elemThree);
// Test stopping "abort" event.
// Test stopping "abort" event.
elemOne.addEventListener("abort", eventListener);
elemTwo.addEventListener("abort", eventListener);
elemThree.addEventListener("abort", eventListener);
shadowOne.addEventListener("abort", eventListener);
elemOne.addEventListener("abort", eventListener);
elemTwo.addEventListener("abort", eventListener);
elemThree.addEventListener("abort", eventListener);
shadowOne.addEventListener("abort", eventListener);
var eventChain = [];
var eventChain = [];
var customEvent = new CustomEvent("abort", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that abort event is stopped at shadow root.");
var customEvent = new CustomEvent("abort", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that abort event is stopped at shadow root.");
// Test stopping "error" event.
// Test stopping "error" event.
elemOne.addEventListener("error", eventListener);
elemTwo.addEventListener("error", eventListener);
elemThree.addEventListener("error", eventListener);
shadowOne.addEventListener("error", eventListener);
elemOne.addEventListener("error", eventListener);
elemTwo.addEventListener("error", eventListener);
elemThree.addEventListener("error", eventListener);
shadowOne.addEventListener("error", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("error", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that error event is stopped at shadow root.");
customEvent = new CustomEvent("error", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that error event is stopped at shadow root.");
// Test stopping "select" event.
// Test stopping "select" event.
elemOne.addEventListener("select", eventListener);
elemTwo.addEventListener("select", eventListener);
elemThree.addEventListener("select", eventListener);
shadowOne.addEventListener("select", eventListener);
elemOne.addEventListener("select", eventListener);
elemTwo.addEventListener("select", eventListener);
elemThree.addEventListener("select", eventListener);
shadowOne.addEventListener("select", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("select", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that select event is stopped at shadow root.");
customEvent = new CustomEvent("select", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that select event is stopped at shadow root.");
// Test stopping "change" event.
// Test stopping "change" event.
elemOne.addEventListener("change", eventListener);
elemTwo.addEventListener("change", eventListener);
elemThree.addEventListener("change", eventListener);
shadowOne.addEventListener("change", eventListener);
elemOne.addEventListener("change", eventListener);
elemTwo.addEventListener("change", eventListener);
elemThree.addEventListener("change", eventListener);
shadowOne.addEventListener("change", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("change", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
customEvent = new CustomEvent("change", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
// Test stopping "reset" event.
// Test stopping "reset" event.
elemOne.addEventListener("reset", eventListener);
elemTwo.addEventListener("reset", eventListener);
elemThree.addEventListener("reset", eventListener);
shadowOne.addEventListener("reset", eventListener);
elemOne.addEventListener("reset", eventListener);
elemTwo.addEventListener("reset", eventListener);
elemThree.addEventListener("reset", eventListener);
shadowOne.addEventListener("reset", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("reset", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that reset event is stopped at shadow root.");
customEvent = new CustomEvent("reset", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that reset event is stopped at shadow root.");
// Test stopping "load" event.
// Test stopping "load" event.
elemOne.addEventListener("load", eventListener);
elemTwo.addEventListener("load", eventListener);
elemThree.addEventListener("load", eventListener);
shadowOne.addEventListener("load", eventListener);
elemOne.addEventListener("load", eventListener);
elemTwo.addEventListener("load", eventListener);
elemThree.addEventListener("load", eventListener);
shadowOne.addEventListener("load", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("load", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that load event is stopped at shadow root.");
customEvent = new CustomEvent("load", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that load event is stopped at shadow root.");
// Test stopping "resize" event.
// Test stopping "resize" event.
elemOne.addEventListener("resize", eventListener);
elemTwo.addEventListener("resize", eventListener);
elemThree.addEventListener("resize", eventListener);
shadowOne.addEventListener("resize", eventListener);
elemOne.addEventListener("resize", eventListener);
elemTwo.addEventListener("resize", eventListener);
elemThree.addEventListener("resize", eventListener);
shadowOne.addEventListener("resize", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("resize", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that resize event is stopped at shadow root.");
customEvent = new CustomEvent("resize", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that resize event is stopped at shadow root.");
// Test stopping "scroll" event.
// Test stopping "scroll" event.
elemOne.addEventListener("scroll", eventListener);
elemTwo.addEventListener("scroll", eventListener);
elemThree.addEventListener("scroll", eventListener);
shadowOne.addEventListener("scroll", eventListener);
elemOne.addEventListener("scroll", eventListener);
elemTwo.addEventListener("scroll", eventListener);
elemThree.addEventListener("scroll", eventListener);
shadowOne.addEventListener("scroll", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("scroll", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that scroll event is stopped at shadow root.");
customEvent = new CustomEvent("scroll", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that scroll event is stopped at shadow root.");
// Test stopping "selectstart" event.
// Test stopping "selectstart" event.
elemOne.addEventListener("selectstart", eventListener);
elemTwo.addEventListener("selectstart", eventListener);
elemThree.addEventListener("selectstart", eventListener);
shadowOne.addEventListener("selectstart", eventListener);
elemOne.addEventListener("selectstart", eventListener);
elemTwo.addEventListener("selectstart", eventListener);
elemThree.addEventListener("selectstart", eventListener);
shadowOne.addEventListener("selectstart", eventListener);
eventChain = [];
eventChain = [];
customEvent = new CustomEvent("selectstart", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that selectstart event is stopped at shadow root.");
customEvent = new CustomEvent("selectstart", { "bubbles" : true });
elemThree.dispatchEvent(customEvent);
isEventChain(eventChain, [elemThree, elemTwo, shadowOne], "Test that selectstart event is stopped at shadow root.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,79 +5,87 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for ShadowRoot</title>
<script type="text/javascript" src="head.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>
<div id="movedtoshadow" class="testclass"></div>
<svg id="svgmovedtoshadow"></svg>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
// Create ShadowRoot.
var element = document.createElement("div");
ok(!element.shadowRoot, "div element should not have a shadow root.");
var shadow = element.createShadowRoot();
is(element.shadowRoot, shadow, "shadowRoot property should return the same shadow root that was just created.");
// Move an element from the document to the ShadowRoot.
var inShadowEl = document.getElementById("movedtoshadow");
var inShadowSVGEl = document.getElementById("svgmovedtoshadow");
SimpleTest.waitForExplicitFinish();
// Test getElementById
ok(!shadow.getElementById("movedtoshadow"), "Element not in ShadowRoot should not be accessible from ShadowRoot API.");
ok(!shadow.getElementById("svgmovedtoshadow"), "SVG element not in ShadowRoot should not be accessible from ShadowRoot API.");
shadow.appendChild(inShadowEl);
shadow.appendChild(inShadowSVGEl);
is(shadow.getElementById("movedtoshadow"), inShadowEl, "Element appended to a ShadowRoot should be accessible from ShadowRoot API.");
ok(!document.getElementById("movedtoshadow"), "Element appended to a ShadowRoot should not be accessible from document.");
is(shadow.getElementById("svgmovedtoshadow"), inShadowSVGEl, "SVG element appended to a ShadowRoot should be accessible from ShadowRoot API.");
ok(!document.getElementById("svgmovedtoshadow"), "SVG element appended to a ShadowRoot should not be accessible from document.");
var content = '<div id="movedtoshadow" class="testclass"></div>' +
'<svg id="svgmovedtoshadow"></svg>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
// Create ShadowRoot.
var element = aDocument.createElement("div");
ok(!element.shadowRoot, "div element should not have a shadow root.");
var shadow = element.attachShadow({mode: "open"});
is(element.shadowRoot, shadow, "shadowRoot property should return the same shadow root that was just created.");
// Test getElementsByClassName
is(document.getElementsByClassName("testclass").length, 0, "Element removed from DOM should not be accessible by DOM accessors.");
is(shadow.getElementsByClassName("testclass").length, 1, "Element added to ShadowRoot should be accessible by ShadowRoot API.");
// Move an element from the document to the ShadowRoot.
var inShadowEl = aDocument.getElementById("movedtoshadow");
var inShadowSVGEl = aDocument.getElementById("svgmovedtoshadow");
// Test getElementsByTagName{NS}
is(document.getElementsByTagName("div").length, 0, "Element removed from DOM should not be accessible from DOM accessors.");
is(shadow.getElementsByTagName("div").length, 1, "Elements in the ShadowRoot should be accessible from the ShadowRoot API.");
is(document.getElementsByTagName("svg").length, 0, "SVG elements removed from DOM should not be accessible from DOM accessors.");
is(shadow.getElementsByTagName("svg").length, 1, "SVG element in the ShadowRoot should be accessible from the ShadowRoot API.");
is(shadow.getElementsByTagNameNS("http://www.w3.org/2000/svg", "svg").length, 1, "SVG element in the ShadowRoot should be accessible from the ShadowRoot API.");
// Test getElementById
ok(!shadow.getElementById("movedtoshadow"), "Element not in ShadowRoot should not be accessible from ShadowRoot API.");
ok(!shadow.getElementById("svgmovedtoshadow"), "SVG element not in ShadowRoot should not be accessible from ShadowRoot API.");
shadow.appendChild(inShadowEl);
shadow.appendChild(inShadowSVGEl);
is(shadow.getElementById("movedtoshadow"), inShadowEl, "Element appended to a ShadowRoot should be accessible from ShadowRoot API.");
ok(!aDocument.getElementById("movedtoshadow"), "Element appended to a ShadowRoot should not be accessible from document.");
is(shadow.getElementById("svgmovedtoshadow"), inShadowSVGEl, "SVG element appended to a ShadowRoot should be accessible from ShadowRoot API.");
ok(!aDocument.getElementById("svgmovedtoshadow"), "SVG element appended to a ShadowRoot should not be accessible from document.");
// Remove elements from ShadowRoot and make sure that they are no longer accessible via the ShadowRoot API.
shadow.removeChild(inShadowEl);
shadow.removeChild(inShadowSVGEl);
ok(!shadow.getElementById("movedtoshadow"), "ShadowRoot API should not be able to access elements removed from ShadowRoot.");
ok(!shadow.getElementById("svgmovedtoshadow"), "ShadowRoot API should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByClassName("testclass").length, 0, "ShadowRoot getElementsByClassName should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByTagName("svg").length, 0, "ShadowRoot getElementsByTagName should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByTagNameNS("http://www.w3.org/2000/svg", "svg").length, 0, "ShadowRoot getElementsByTagNameNS should not be able to access elements removed from ShadowRoot.");
// Test getElementsByClassName
is(aDocument.getElementsByClassName("testclass").length, 0, "Element removed from DOM should not be accessible by DOM accessors.");
is(shadow.getElementsByClassName("testclass").length, 1, "Element added to ShadowRoot should be accessible by ShadowRoot API.");
// Test querySelector on element in a ShadowRoot.
element = document.createElement("div");
shadow = element.createShadowRoot();
var parentDiv = document.createElement("div");
var childSpan = document.createElement("span");
childSpan.id = "innerdiv";
parentDiv.appendChild(childSpan);
is(parentDiv.querySelector("#innerdiv"), childSpan, "ID query selector should work on element in ShadowRoot.");
is(parentDiv.querySelector("span"), childSpan, "Tag query selector should work on element in ShadowRoot.");
// Test getElementsByTagName{NS}
is(aDocument.getElementsByTagName("div").length, 0, "Element removed from DOM should not be accessible from DOM accessors.");
is(shadow.getElementsByTagName("div").length, 1, "Elements in the ShadowRoot should be accessible from the ShadowRoot API.");
is(aDocument.getElementsByTagName("svg").length, 0, "SVG elements removed from DOM should not be accessible from DOM accessors.");
is(shadow.getElementsByTagName("svg").length, 1, "SVG element in the ShadowRoot should be accessible from the ShadowRoot API.");
is(shadow.getElementsByTagNameNS("http://www.w3.org/2000/svg", "svg").length, 1, "SVG element in the ShadowRoot should be accessible from the ShadowRoot API.");
// Test that exception is thrown when trying to create a cycle with host node.
element = document.createElement("div");
shadow = element.createShadowRoot();
try {
shadow.appendChild(element);
ok(false, "Excpetion should be thrown when creating a cycle with host content.");
} catch (ex) {
ok(true, "Excpetion should be thrown when creating a cycle with host content.");
}
// Remove elements from ShadowRoot and make sure that they are no longer accessible via the ShadowRoot API.
shadow.removeChild(inShadowEl);
shadow.removeChild(inShadowSVGEl);
ok(!shadow.getElementById("movedtoshadow"), "ShadowRoot API should not be able to access elements removed from ShadowRoot.");
ok(!shadow.getElementById("svgmovedtoshadow"), "ShadowRoot API should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByClassName("testclass").length, 0, "ShadowRoot getElementsByClassName should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByTagName("svg").length, 0, "ShadowRoot getElementsByTagName should not be able to access elements removed from ShadowRoot.");
is(shadow.getElementsByTagNameNS("http://www.w3.org/2000/svg", "svg").length, 0, "ShadowRoot getElementsByTagNameNS should not be able to access elements removed from ShadowRoot.");
// Basic innerHTML tests.
shadow.innerHTML = '<span id="first"></span><div id="second"></div>';
is(shadow.childNodes.length, 2, "There should be two children in the ShadowRoot.");
is(shadow.getElementById("second").tagName, "DIV", "Elements created by innerHTML should be accessible by ShadowRoot API.");
// Test querySelector on element in a ShadowRoot.
element = aDocument.createElement("div");
shadow = element.attachShadow({mode: "open"});
var parentDiv = aDocument.createElement("div");
var childSpan = aDocument.createElement("span");
childSpan.id = "innerdiv";
parentDiv.appendChild(childSpan);
is(parentDiv.querySelector("#innerdiv"), childSpan, "ID query selector should work on element in ShadowRoot.");
is(parentDiv.querySelector("span"), childSpan, "Tag query selector should work on element in ShadowRoot.");
// Test that exception is thrown when trying to create a cycle with host node.
element = aDocument.createElement("div");
shadow = element.attachShadow({mode: "open"});
try {
shadow.appendChild(element);
ok(false, "Excpetion should be thrown when creating a cycle with host content.");
} catch (ex) {
ok(true, "Excpetion should be thrown when creating a cycle with host content.");
}
// Basic innerHTML tests.
shadow.innerHTML = '<span id="first"></span><div id="second"></div>';
is(shadow.childNodes.length, 2, "There should be two children in the ShadowRoot.");
is(shadow.getElementById("second").tagName, "DIV", "Elements created by innerHTML should be accessible by ShadowRoot API.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,40 +5,45 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for inert elements in ShadowRoot</title>
<script type="text/javascript" src="head.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 onload="runChecks();">
<div id="grabme"></div>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
var element = document.getElementById("grabme");
var shadow = element.createShadowRoot();
// Check that <base> is inert.
shadow.innerHTML = '<base href="http://www.example.org/" />';
isnot(document.baseURI, "http://www.example.org/", "Base element should be inert in ShadowRoot.");
SimpleTest.waitForExplicitFinish();
// Check that <link> is inert.
var numStyleBeforeLoad = document.styleSheets.length;
var content = '<div id="grabme"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
function runChecks() {
isnot(aDocument.defaultView.getComputedStyle(shadowSpan, null).getPropertyValue("padding-top"), "10px", "Link element should be inert.");
is(aDocument.styleSheets.length, numStyleBeforeLoad, "Document style count should remain the same because the style should not be in the doucment.");
is(shadow.styleSheets.length, 0, "Inert link should not add style to ShadowRoot.");
// Remove link to make sure we don't get assertions.
shadow.removeChild(shadowStyle);
SimpleTest.finish();
};
shadow.innerHTML = '<link id="shadowlink" rel="stylesheet" type="text/css" href="inert_style.css" /><span id="shadowspan"></span>';
shadow.applyAuthorStyles = true;
var shadowSpan = shadow.getElementById("shadowspan");
var shadowStyle = shadow.getElementById("shadowlink");
var element = aDocument.getElementById("grabme");
var shadow = element.attachShadow({mode: "open"});
function runChecks() {
isnot(getComputedStyle(shadowSpan, null).getPropertyValue("padding-top"), "10px", "Link element should be inert.");
is(document.styleSheets.length, numStyleBeforeLoad, "Document style count should remain the same because the style should not be in the doucment.");
is(shadow.styleSheets.length, 0, "Inert link should not add style to ShadowRoot.");
// Remove link to make sure we don't get assertions.
shadow.removeChild(shadowStyle);
SimpleTest.finish();
};
// Check that <base> is inert.
shadow.innerHTML = '<base href="http://www.example.org/" />';
isnot(aDocument.baseURI, "http://www.example.org/", "Base element should be inert in ShadowRoot.");
// Check that <link> is inert.
var numStyleBeforeLoad = aDocument.styleSheets.length;
shadow.innerHTML = '<link id="shadowlink" rel="stylesheet" type="text/css" href="inert_style.css" /><span id="shadowspan"></span>';
shadow.applyAuthorStyles = true;
var shadowSpan = shadow.getElementById("shadowspan");
var shadowStyle = shadow.getElementById("shadowlink");
runChecks();
});
</script>
</body>
</html>

View File

@@ -5,12 +5,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for ShadowRoot styling</title>
<script type="text/javascript" src="head.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>
<div class="tall" id="bodydiv"></div>
<div id="container"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
@@ -18,70 +17,80 @@ if (!SpecialPowers.DOMWindowUtils.isStyledByServo) {
SimpleTest.expectAssertions(3, 3); // GeckoRestyleManager stuff.
}
// Create ShadowRoot.
var container = document.getElementById("container");
var elem = document.createElement("div");
container.appendChild(elem); // Put ShadowRoot host in document.
var root = elem.createShadowRoot();
SimpleTest.waitForExplicitFinish();
// A style element that will be appended into the ShadowRoot.
var shadowStyle = document.createElement("style");
shadowStyle.innerHTML = ".tall { height: 100px; } .fat { padding-left: inherit; }";
var content = '<div class="tall" id="bodydiv"></div>' +
'<div id="container"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
var iframeWin = aDocument.defaultView;
root.innerHTML = '<div id="divtostyle" class="tall fat"></div>';
var divToStyle = root.getElementById("divtostyle");
// Create ShadowRoot.
var container = aDocument.getElementById("container");
var elem = aDocument.createElement("div");
container.appendChild(elem); // Put ShadowRoot host in document.
var root = elem.attachShadow({mode: "open"});
// Make sure styleSheet counts are correct after appending a style to the ShadowRoot.
is(document.styleSheets.length, 1, "There should only be one style sheet on the document from the test style sheet.");
is(root.styleSheets.length, 0, "The ShadowRoot should have no style sheets.");
root.appendChild(shadowStyle);
is(document.styleSheets.length, 1, "Styles in the ShadowRoot element should not be accessible from the document.");
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet from the appened style.");
is(root.styleSheets[0].ownerNode, shadowStyle, "First style in ShadowRoot should match the style that was just appended.");
// A style element that will be appended into the ShadowRoot.
var shadowStyle = aDocument.createElement("style");
shadowStyle.innerHTML = ".tall { height: 100px; } .fat { padding-left: inherit; }";
var dummyStyle = document.createElement("style");
root.appendChild(dummyStyle);
is(root.styleSheets.length, 2, "ShadowRoot should have an additional style from appending dummyStyle.");
is(root.styleSheets[1].ownerNode, dummyStyle, "Second style in ShadowRoot should be the dummyStyle.");
root.removeChild(dummyStyle);
is(root.styleSheets.length, 1, "Removing dummyStyle should remove it from the ShadowRoot style sheets.");
is(root.styleSheets[0].ownerNode, shadowStyle, "The style sheet remaining in the ShadowRoot should be shadowStyle.");
root.innerHTML = '<div id="divtostyle" class="tall fat"></div>';
var divToStyle = root.getElementById("divtostyle");
// Make sure that elements outside of the ShadowRoot are not affected by the ShadowRoot style.
isnot(getComputedStyle(document.getElementById("bodydiv"), null).getPropertyValue("height"), "100px", "Style sheets in ShadowRoot should not apply to elements no in the ShadowRoot.");
// Make sure styleSheet counts are correct after appending a style to the ShadowRoot.
is(aDocument.styleSheets.length, 0, "There shouldn't be any style sheet in the test frame document.");
is(root.styleSheets.length, 0, "The ShadowRoot should have no style sheets.");
root.appendChild(shadowStyle);
is(aDocument.styleSheets.length, 0, "Styles in the ShadowRoot element should not be accessible from the document.");
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet from the appened style.");
is(root.styleSheets[0].ownerNode, shadowStyle, "First style in ShadowRoot should match the style that was just appended.");
// Make sure that elements in the ShadowRoot are styled according to the ShadowRoot style.
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "100px", "ShadowRoot style sheets should apply to elements in ShadowRoot.");
var dummyStyle = aDocument.createElement("style");
root.appendChild(dummyStyle);
is(root.styleSheets.length, 2, "ShadowRoot should have an additional style from appending dummyStyle.");
is(root.styleSheets[1].ownerNode, dummyStyle, "Second style in ShadowRoot should be the dummyStyle.");
root.removeChild(dummyStyle);
is(root.styleSheets.length, 1, "Removing dummyStyle should remove it from the ShadowRoot style sheets.");
is(root.styleSheets[0].ownerNode, shadowStyle, "The style sheet remaining in the ShadowRoot should be shadowStyle.");
// Tests for applyAuthorStyles.
var authorStyle = document.createElement("style");
authorStyle.innerHTML = ".fat { padding-right: 20px; padding-left: 30px; }";
document.body.appendChild(authorStyle);
// Make sure that elements outside of the ShadowRoot are not affected by the ShadowRoot style.
isnot(iframeWin.getComputedStyle(aDocument.getElementById("bodydiv"), null).getPropertyValue("height"), "100px", "Style sheets in ShadowRoot should not apply to elements no in the ShadowRoot.");
is(root.applyAuthorStyles, false, "applyAuthorStyles defaults to false.");
isnot(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
root.applyAuthorStyles = true;
is(root.applyAuthorStyles, true, "applyAuthorStyles was set to true.");
is(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should apply to ShadowRoot when ShadowRoot.applyAuthorStyles is true.");
root.applyAuthorStyles = false;
is(root.applyAuthorStyles, false, "applyAuthorStyles was set to false.");
isnot(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
// Make sure that elements in the ShadowRoot are styled according to the ShadowRoot style.
is(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("height"), "100px", "ShadowRoot style sheets should apply to elements in ShadowRoot.");
// Test dynamic changes to style in ShadowRoot.
root.innerHTML = '<div id="divtostyle" class="dummy"></div>';
divToStyle = root.getElementById("divtostyle");
var dummyShadowStyle = document.createElement("style");
dummyShadowStyle.innerHTML = ".dummy { height: 300px; }";
root.appendChild(dummyShadowStyle);
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "300px", "Dummy element in ShadowRoot should be styled by style in ShadowRoot.");
dummyShadowStyle.innerHTML = ".dummy { height: 200px; }";
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "200px", "Dynamic changes to styles in ShadowRoot should change style of affected elements.");
// Tests for applyAuthorStyles.
var authorStyle = aDocument.createElement("style");
authorStyle.innerHTML = ".fat { padding-right: 20px; padding-left: 30px; }";
aDocument.body.appendChild(authorStyle);
// Test id selector in ShadowRoot style.
root.innerHTML = '<style>#divtostyle { padding-top: 10px; }</style><div id="divtostyle"></div>';
divToStyle = root.getElementById("divtostyle");
is(getComputedStyle(divToStyle, null).getPropertyValue("padding-top"), "10px", "ID selector in style selector should match element.");
is(root.applyAuthorStyles, false, "applyAuthorStyles defaults to false.");
isnot(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
root.applyAuthorStyles = true;
is(root.applyAuthorStyles, true, "applyAuthorStyles was set to true.");
is(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should apply to ShadowRoot when ShadowRoot.applyAuthorStyles is true.");
root.applyAuthorStyles = false;
is(root.applyAuthorStyles, false, "applyAuthorStyles was set to false.");
isnot(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
// Test dynamic changes to style in ShadowRoot.
root.innerHTML = '<div id="divtostyle" class="dummy"></div>';
divToStyle = root.getElementById("divtostyle");
var dummyShadowStyle = aDocument.createElement("style");
dummyShadowStyle.innerHTML = ".dummy { height: 300px; }";
root.appendChild(dummyShadowStyle);
is(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("height"), "300px", "Dummy element in ShadowRoot should be styled by style in ShadowRoot.");
dummyShadowStyle.innerHTML = ".dummy { height: 200px; }";
is(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("height"), "200px", "Dynamic changes to styles in ShadowRoot should change style of affected elements.");
// Test id selector in ShadowRoot style.
root.innerHTML = '<style>#divtostyle { padding-top: 10px; }</style><div id="divtostyle"></div>';
divToStyle = root.getElementById("divtostyle");
is(iframeWin.getComputedStyle(divToStyle, null).getPropertyValue("padding-top"), "10px", "ID selector in style selector should match element.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,38 +5,48 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for ShadowRoot style order</title>
<script type="text/javascript" src="head.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>
<div id="container"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
// Create ShadowRoot.
var container = document.getElementById("container");
var elem = document.createElement("div");
container.appendChild(elem); // Put ShadowRoot host in document.
var root = elem.createShadowRoot();
// Style elements that will be appended into the ShadowRoot.
var tallShadowStyle = document.createElement("style");
tallShadowStyle.innerHTML = ".tall { height: 100px; }";
SimpleTest.waitForExplicitFinish();
var veryTallShadowStyle = document.createElement("style");
veryTallShadowStyle.innerHTML = ".tall { height: 200px; }";
var content = '<div id="container"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
var iframeWin = aDocument.defaultView;
var divToStyle = document.createElement("div");
divToStyle.setAttribute("class", "tall");
root.appendChild(divToStyle);
// Create ShadowRoot.
var container = aDocument.getElementById("container");
var elem = aDocument.createElement("div");
container.appendChild(elem); // Put ShadowRoot host in document.
var root = elem.attachShadow({mode: "open"});
// Make sure the styles are applied in tree order.
root.appendChild(tallShadowStyle);
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet.");
is(window.getComputedStyle(divToStyle).getPropertyValue("height"), "100px", "Style in ShadowRoot should apply to elements in ShadowRoot.");
root.appendChild(veryTallShadowStyle);
is(root.styleSheets.length, 2, "ShadowRoot should have two style sheets.");
is(window.getComputedStyle(divToStyle).getPropertyValue("height"), "200px", "Style in ShadowRoot should apply to elements in ShadowRoot in tree order.");
// Style elements that will be appended into the ShadowRoot.
var tallShadowStyle = aDocument.createElement("style");
tallShadowStyle.innerHTML = ".tall { height: 100px; }";
var veryTallShadowStyle = aDocument.createElement("style");
veryTallShadowStyle.innerHTML = ".tall { height: 200px; }";
var divToStyle = aDocument.createElement("div");
divToStyle.setAttribute("class", "tall");
root.appendChild(divToStyle);
// Make sure the styles are applied in tree order.
root.appendChild(tallShadowStyle);
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet.");
is(iframeWin.getComputedStyle(divToStyle).getPropertyValue("height"), "100px", "Style in ShadowRoot should apply to elements in ShadowRoot.");
root.appendChild(veryTallShadowStyle);
is(root.styleSheets.length, 2, "ShadowRoot should have two style sheets.");
is(iframeWin.getComputedStyle(divToStyle).getPropertyValue("height"), "200px", "Style in ShadowRoot should apply to elements in ShadowRoot in tree order.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -5,24 +5,35 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806506
-->
<head>
<title>Test for styling fallback content</title>
<script type="text/javascript" src="head.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>
<div id="grabme"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
<script>
var host = document.getElementById("grabme");
var shadow = host.createShadowRoot();
shadow.innerHTML = '<style id="innerstyle"></style><span id="container"><content><span id="innerspan">Hello</span></content></span>';
var innerStyle = shadow.getElementById("innerstyle");
innerStyle.innerHTML = '#innerspan { margin-top: 10px; }';
var innerSpan = shadow.getElementById("innerspan");
is(getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "10px", "Default content should be style by id selector.");
SimpleTest.waitForExplicitFinish();
innerStyle.innerHTML = '#container > content > #innerspan { margin-top: 30px; }';
is(getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "30px", "Default content should be style by child combinators.");
var content = '<div id="grabme"></div>';
setWebComponentsPrefAndCreateIframe(content)
.then((aDocument) => {
var iframeWin = aDocument.defaultView;
var host = aDocument.getElementById("grabme");
var shadow = host.attachShadow({mode: "open"});
shadow.innerHTML = '<style id="innerstyle"></style><span id="container"><slot><span id="innerspan">Hello</span></slot></span>';
var innerStyle = shadow.getElementById("innerstyle");
innerStyle.innerHTML = '#innerspan { margin-top: 10px; }';
var innerSpan = shadow.getElementById("innerspan");
is(iframeWin.getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "10px", "Default content should be style by id selector.");
innerStyle.innerHTML = '#container > slot > #innerspan { margin-top: 30px; }';
is(iframeWin.getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "30px", "Default content should be style by child combinators.");
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@@ -313,6 +313,75 @@ ServiceWorkerManager::Init(ServiceWorkerRegistrar* aRegistrar)
mActor = static_cast<ServiceWorkerManagerChild*>(actor);
}
RefPtr<GenericPromise>
ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
ServiceWorkerRegistrationInfo* aRegistrationInfo)
{
MOZ_DIAGNOSTIC_ASSERT(aRegistrationInfo->GetActive());
RefPtr<GenericPromise> ref;
const ServiceWorkerDescriptor& active =
aRegistrationInfo->GetActive()->Descriptor();
auto entry = mControlledClients.LookupForAdd(aClientInfo.Id());
if (entry) {
RefPtr<ServiceWorkerRegistrationInfo> old =
entry.Data()->mRegistrationInfo.forget();
ref = Move(entry.Data()->mClientHandle->Control(active));
entry.Data()->mRegistrationInfo = aRegistrationInfo;
if (old != aRegistrationInfo) {
StopControllingRegistration(old);
aRegistrationInfo->StartControllingClient();
}
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
return Move(ref);
}
RefPtr<ClientHandle> clientHandle =
ClientManager::CreateHandle(aClientInfo,
SystemGroup::EventTargetFor(TaskCategory::Other));
ref = Move(clientHandle->Control(active));
aRegistrationInfo->StartControllingClient();
entry.OrInsert([&] {
return new ControlledClientData(clientHandle, aRegistrationInfo);
});
RefPtr<ServiceWorkerManager> self(this);
clientHandle->OnDetach()->Then(
SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
[self = Move(self), aClientInfo] {
self->StopControllingClient(aClientInfo);
});
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
return Move(ref);
}
void
ServiceWorkerManager::StopControllingClient(const ClientInfo& aClientInfo)
{
auto entry = mControlledClients.Lookup(aClientInfo.Id());
if (!entry) {
return;
}
RefPtr<ServiceWorkerRegistrationInfo> reg =
entry.Data()->mRegistrationInfo.forget();
entry.Remove();
StopControllingRegistration(reg);
}
void
ServiceWorkerManager::MaybeStartShutdown()
{
@@ -1432,8 +1501,13 @@ ServiceWorkerManager::GetActiveWorkerInfoForDocument(nsIDocument* aDocument)
{
AssertIsOnMainThread();
Maybe<ClientInfo> clientInfo(aDocument->GetClientInfo());
if (clientInfo.isNothing()) {
return nullptr;
}
RefPtr<ServiceWorkerRegistrationInfo> registration;
GetDocumentRegistration(aDocument, getter_AddRefs(registration));
GetClientRegistration(clientInfo.ref(), getter_AddRefs(registration));
if (!registration) {
return nullptr;
@@ -1578,7 +1652,7 @@ ServiceWorkerManager::WorkerIsIdle(ServiceWorkerInfo* aWorker)
return;
}
if (!reg->IsControllingDocuments() && reg->mPendingUninstall) {
if (!reg->IsControllingClients() && reg->mPendingUninstall) {
RemoveRegistration(reg);
return;
}
@@ -2269,15 +2343,25 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
entry.Remove();
}
// The registration should generally only be removed if there are no controlled
// documents, but mControlledDocuments can contain references to potentially
// controlled docs. This happens when the service worker is not active yet.
// We must purge these references since we are evicting the registration.
// Verify there are no controlled clients for the purged registration.
for (auto iter = swm->mControlledClients.Iter(); !iter.Done(); iter.Next()) {
auto& reg = iter.UserData()->mRegistrationInfo;
if (reg->mScope.Equals(aRegistration->mScope)) {
MOZ_DIAGNOSTIC_ASSERT(false,
"controlled client when removing registration");
iter.Remove();
break;
}
}
// Registration lifecycle is managed via mControlledClients now. Do not
// assert on on mControlledDocuments as races may cause this to still be
// set when the registration is destroyed.
for (auto iter = swm->mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerRegistrationInfo* reg = iter.UserData();
MOZ_ASSERT(reg);
if (reg->mScope.Equals(aRegistration->mScope)) {
iter.Remove();
break;
}
}
@@ -2308,32 +2392,49 @@ ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
MOZ_ASSERT(aDoc);
RefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(aDoc);
if (registration) {
if (registration && registration->GetActive() &&
aDoc->GetSandboxFlags() == 0) {
MOZ_ASSERT(!mControlledDocuments.Contains(aDoc));
StartControllingADocument(registration, aDoc);
}
}
bool
ServiceWorkerManager::StartControlling(const ClientInfo& aClientInfo,
const ServiceWorkerDescriptor& aServiceWorker)
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aServiceWorker.PrincipalInfo());
NS_ENSURE_TRUE(principal, false);
nsCOMPtr<nsIURI> scope;
nsresult rv =
NS_NewURI(getter_AddRefs(scope), aServiceWorker.Scope(), nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, false);
RefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(principal, scope);
NS_ENSURE_TRUE(registration, false);
StartControllingClient(aClientInfo, registration);
return true;
}
void
ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDoc);
RefPtr<ServiceWorkerRegistrationInfo> registration;
mControlledDocuments.Remove(aDoc, getter_AddRefs(registration));
// A document which was uncontrolled does not maintain that state itself, so
// it will always call MaybeStopControlling() even if there isn't an
// associated registration. So this check is required.
if (registration) {
StopControllingADocument(registration);
}
mControlledDocuments.Remove(aDoc);
}
void
ServiceWorkerManager::MaybeCheckNavigationUpdate(nsIDocument* aDoc)
ServiceWorkerManager::MaybeCheckNavigationUpdate(const ClientInfo& aClientInfo)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDoc);
// We perform these success path navigation update steps when the
// document tells us its more or less done loading. This avoids
// slowing down page load and also lets pages consistently get
@@ -2343,52 +2444,27 @@ ServiceWorkerManager::MaybeCheckNavigationUpdate(nsIDocument* aDoc)
// 9.8.22 Else: (respondWith was entered and succeeded)
// If request is a non-subresource request, then: Invoke Soft Update
// algorithm.
RefPtr<ServiceWorkerRegistrationInfo> registration;
mControlledDocuments.Get(aDoc, getter_AddRefs(registration));
if (registration) {
registration->MaybeScheduleUpdate();
ControlledClientData* data = mControlledClients.Get(aClientInfo.Id());
if (data && data->mRegistrationInfo) {
data->mRegistrationInfo->MaybeScheduleUpdate();
}
}
RefPtr<GenericPromise>
void
ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
nsIDocument* aDoc)
{
MOZ_ASSERT(aRegistration);
MOZ_ASSERT(aDoc);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
RefPtr<GenericPromise> ref = GenericPromise::CreateAndResolve(true, __func__);
aRegistration->StartControllingADocument();
mControlledDocuments.Put(aDoc, aRegistration);
// Mark the document's ClientSource as controlled using the ClientHandle
// interface. While we could get at the ClientSource directly from the
// document here, our goal is to move ServiceWorkerManager to a separate
// process. Using the ClientHandle supports this remote operation.
ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
Maybe<ClientInfo> clientInfo = aDoc->GetClientInfo();
if (activeWorker && clientInfo.isSome()) {
RefPtr<ClientHandle> clientHandle =
ClientManager::CreateHandle(clientInfo.ref(),
SystemGroup::EventTargetFor(TaskCategory::Other));
ref = Move(clientHandle->Control(activeWorker->Descriptor()));
}
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
return Move(ref);
}
void
ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration)
ServiceWorkerManager::StopControllingRegistration(ServiceWorkerRegistrationInfo* aRegistration)
{
aRegistration->StopControllingADocument();
if (aRegistration->IsControllingDocuments() || !aRegistration->IsIdle()) {
aRegistration->StopControllingClient();
if (aRegistration->IsControllingClients() || !aRegistration->IsIdle()) {
return;
}
@@ -2718,10 +2794,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
// First, attempt to mark the reserved client controlled directly. This
// will update the controlled status in the ClientManagerService in the
// parent. It will also eventually propagate back to the ClientSource.
RefPtr<ClientHandle> clientHandle =
ClientManager::CreateHandle(clientInfo.ref(),
SystemGroup::EventTargetFor(TaskCategory::Other));
clientHandle->Control(serviceWorker->Descriptor());
StartControllingClient(clientInfo.ref(), registration);
}
// But we also note the reserved state on the LoadInfo. This allows the
@@ -2785,20 +2858,21 @@ ServiceWorkerManager::IsAvailable(nsIPrincipal* aPrincipal,
}
nsresult
ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
ServiceWorkerRegistrationInfo** aRegistrationInfo)
ServiceWorkerManager::GetClientRegistration(const ClientInfo& aClientInfo,
ServiceWorkerRegistrationInfo** aRegistrationInfo)
{
RefPtr<ServiceWorkerRegistrationInfo> registration;
if (!mControlledDocuments.Get(aDoc, getter_AddRefs(registration))) {
ControlledClientData* data = mControlledClients.Get(aClientInfo.Id());
if (!data || !data->mRegistrationInfo) {
return NS_ERROR_NOT_AVAILABLE;
}
// If the document is controlled, the current worker MUST be non-null.
if (!registration->GetActive()) {
if (!data->mRegistrationInfo->GetActive()) {
return NS_ERROR_NOT_AVAILABLE;
}
registration.forget(aRegistrationInfo);
RefPtr<ServiceWorkerRegistrationInfo> ref = data->mRegistrationInfo;
ref.forget(aRegistrationInfo);
return NS_OK;
}
@@ -3169,13 +3243,21 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
return ref.forget();
}
Maybe<ClientInfo> clientInfo(aDocument->GetClientInfo());
if (NS_WARN_IF(clientInfo.isNothing())) {
ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
// The registration that should be controlling the client
RefPtr<ServiceWorkerRegistrationInfo> matchingRegistration =
GetServiceWorkerRegistrationInfo(aDocument);
// The registration currently controlling the client
RefPtr<ServiceWorkerRegistrationInfo> controllingRegistration;
GetDocumentRegistration(aDocument, getter_AddRefs(controllingRegistration));
GetClientRegistration(clientInfo.ref(),
getter_AddRefs(controllingRegistration));
if (aWorkerRegistration != matchingRegistration ||
aWorkerRegistration == controllingRegistration) {
@@ -3183,11 +3265,8 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
return ref.forget();
}
if (controllingRegistration) {
StopControllingADocument(controllingRegistration);
}
ref = StartControllingADocument(aWorkerRegistration, aDocument);
StartControllingADocument(aWorkerRegistration, aDocument);
ref = StartControllingClient(clientInfo.ref(), aWorkerRegistration);
return ref.forget();
}
@@ -3248,31 +3327,19 @@ ServiceWorkerManager::UpdateClientControllers(ServiceWorkerRegistrationInfo* aRe
RefPtr<ServiceWorkerInfo> activeWorker = aRegistration->GetActive();
MOZ_DIAGNOSTIC_ASSERT(activeWorker);
AutoTArray<nsCOMPtr<nsIDocument>, 16> docList;
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
if (iter.UserData() != aRegistration) {
AutoTArray<RefPtr<ClientHandle>, 16> handleList;
for (auto iter = mControlledClients.Iter(); !iter.Done(); iter.Next()) {
if (iter.UserData()->mRegistrationInfo != aRegistration) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
if (NS_WARN_IF(!doc)) {
continue;
}
docList.AppendElement(doc.forget());
handleList.AppendElement(iter.UserData()->mClientHandle);
}
// Fire event after iterating mControlledDocuments is done to prevent
// Fire event after iterating mControlledClients is done to prevent
// modification by reentering from the event handlers during iteration.
for (auto& doc : docList) {
Maybe<ClientInfo> clientInfo = doc->GetClientInfo();
if (clientInfo.isNothing()) {
continue;
}
RefPtr<ClientHandle> clientHandle =
ClientManager::CreateHandle(clientInfo.ref(),
SystemGroup::EventTargetFor(TaskCategory::Other));
clientHandle->Control(activeWorker->Descriptor());
for (auto& handle : handleList) {
handle->Control(activeWorker->Descriptor());
}
}

View File

@@ -21,6 +21,7 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ClientHandle.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerCommon.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h"
@@ -105,6 +106,21 @@ public:
nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments;
struct ControlledClientData
{
RefPtr<ClientHandle> mClientHandle;
RefPtr<ServiceWorkerRegistrationInfo> mRegistrationInfo;
ControlledClientData(ClientHandle* aClientHandle,
ServiceWorkerRegistrationInfo* aRegistrationInfo)
: mClientHandle(aClientHandle)
, mRegistrationInfo(aRegistrationInfo)
{
}
};
nsClassHashtable<nsIDHashKey, ControlledClientData> mControlledClients;
// Track all documents that have attempted to register a service worker for a
// given scope.
typedef nsTArray<nsCOMPtr<nsIWeakReference>> WeakDocumentList;
@@ -304,7 +320,7 @@ public:
ServiceWorkerRegistrationListener* aListener);
void
MaybeCheckNavigationUpdate(nsIDocument* aDoc);
MaybeCheckNavigationUpdate(const ClientInfo& aClientInfo);
nsresult
SendPushEvent(const nsACString& aOriginAttributes,
@@ -328,6 +344,13 @@ private:
void
Init(ServiceWorkerRegistrar* aRegistrar);
RefPtr<GenericPromise>
StartControllingClient(const ClientInfo& aClientInfo,
ServiceWorkerRegistrationInfo* aRegistrationInfo);
void
StopControllingClient(const ClientInfo& aClientInfo);
void
MaybeStartShutdown();
@@ -349,8 +372,8 @@ private:
Update(ServiceWorkerRegistrationInfo* aRegistration);
nsresult
GetDocumentRegistration(nsIDocument* aDoc,
ServiceWorkerRegistrationInfo** aRegistrationInfo);
GetClientRegistration(const ClientInfo& aClientInfo,
ServiceWorkerRegistrationInfo** aRegistrationInfo);
nsresult
GetServiceWorkerForScope(nsPIDOMWindowInner* aWindow,
@@ -375,12 +398,12 @@ private:
void
NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration);
RefPtr<GenericPromise>
void
StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
nsIDocument* aDoc);
void
StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration);
StopControllingRegistration(ServiceWorkerRegistrationInfo* aRegistration);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetServiceWorkerRegistrationInfo(nsPIDOMWindowInner* aWindow);

View File

@@ -81,7 +81,7 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
const nsACString& aScope,
nsIPrincipal* aPrincipal,
ServiceWorkerUpdateViaCache aUpdateViaCache)
: mControlledDocumentsCounter(0)
: mControlledClientsCounter(0)
, mUpdateState(NoUpdate)
, mCreationTime(PR_Now())
, mCreationTimeStamp(TimeStamp::Now())
@@ -94,9 +94,7 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
{
if (IsControllingDocuments()) {
NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
}
MOZ_DIAGNOSTIC_ASSERT(!IsControllingClients());
}
NS_IMPL_ISUPPORTS(ServiceWorkerRegistrationInfo, nsIServiceWorkerRegistrationInfo)
@@ -248,7 +246,7 @@ void
ServiceWorkerRegistrationInfo::TryToActivate()
{
AssertIsOnMainThread();
bool controlling = IsControllingDocuments();
bool controlling = IsControllingClients();
bool skipWaiting = mWaitingWorker && mWaitingWorker->SkipWaitingFlag();
bool idle = IsIdle();
if (idle && (!controlling || skipWaiting)) {

View File

@@ -17,7 +17,7 @@ namespace workers {
class ServiceWorkerRegistrationInfo final
: public nsIServiceWorkerRegistrationInfo
{
uint32_t mControlledDocumentsCounter;
uint32_t mControlledClientsCounter;
enum
{
@@ -79,22 +79,22 @@ public:
GetServiceWorkerInfoById(uint64_t aId);
void
StartControllingADocument()
StartControllingClient()
{
++mControlledDocumentsCounter;
++mControlledClientsCounter;
}
void
StopControllingADocument()
StopControllingClient()
{
MOZ_ASSERT(mControlledDocumentsCounter);
--mControlledDocumentsCounter;
MOZ_ASSERT(mControlledClientsCounter);
--mControlledClientsCounter;
}
bool
IsControllingDocuments() const
IsControllingClients() const
{
return mActiveWorker && mControlledDocumentsCounter;
return mActiveWorker && mControlledClientsCounter;
}
void

View File

@@ -138,7 +138,7 @@ ServiceWorkerUnregisterJob::Unregister()
InvokeResultCallbacks(NS_OK);
// "If no service worker client is using registration..."
if (!registration->IsControllingDocuments() && registration->IsIdle()) {
if (!registration->IsControllingClients() && registration->IsIdle()) {
// "Invoke [[Clear Registration]]..."
swm->RemoveRegistration(registration);
}

View File

@@ -19,10 +19,6 @@
info("skip_waiting_scope/index.html shouldn't be launched directly!");
}
navigator.serviceWorker.ready.then(function() {
parent.postMessage("READY", "*");
});
navigator.serviceWorker.oncontrollerchange = function() {
parent.postMessage({
event: "controllerchange",

View File

@@ -13,6 +13,7 @@
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script src="utils.js"></script>
<script class="testbody" type="text/javascript">
var registration, iframe, content;
@@ -21,19 +22,9 @@
{scope: "./skip_waiting_scope/"});
}
function waitForActivated(swr) {
async function waitForActivated(swr) {
registration = swr;
var promise = new Promise(function(resolve, reject) {
window.onmessage = function(e) {
if (e.data === "READY") {
ok(true, "Active worker is activated now");
resolve();
} else {
ok(false, "Wrong value. Somenting went wrong");
resolve();
}
}
});
await waitForState(registration.installing, "activated")
iframe = document.createElement("iframe");
iframe.setAttribute("src", "skip_waiting_scope/index.html");
@@ -41,7 +32,7 @@
content = document.getElementById("content");
content.appendChild(iframe);
return promise;
await new Promise(resolve => iframe.onload = resolve);
}
function checkWhetherItSkippedWaiting() {

View File

@@ -82,9 +82,10 @@ function runTest(aExpectedResponses) {
// Verify that we can register and intercept a 3rd party iframe with
// the given cookie policy.
function testShouldIntercept(policy, done) {
function testShouldIntercept(behavior, lifetime, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy]
["network.cookie.cookieBehavior", behavior],
["network.cookie.lifetimePolicy", lifetime],
]}, function() {
runTest([{
status: "ok"
@@ -121,9 +122,10 @@ function testShouldIntercept(policy, done) {
// Verify that we cannot register a service worker in a 3rd party
// iframe with the given cookie policy.
function testShouldNotRegister(policy, done) {
function testShouldNotRegister(behavior, lifetime, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy]
["network.cookie.cookieBehavior", behavior],
["network.cookie.lifetimePolicy", lifetime],
]}, function() {
runTest([{
status: "registrationfailed",
@@ -152,9 +154,10 @@ function testShouldNotRegister(policy, done) {
// Verify that if a service worker is already registered a 3rd
// party iframe will still not be intercepted with the given cookie
// policy.
function testShouldNotIntercept(policy, done) {
function testShouldNotIntercept(behavior, lifetime, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
["network.cookie.cookieBehavior", BEHAVIOR_ACCEPT],
["network.cookie.lifetimePolicy", LIFETIME_EXPIRE],
]}, function() {
runTest([{
status: "ok"
@@ -163,7 +166,8 @@ function testShouldNotIntercept(policy, done) {
next: function() {
iframe.addEventListener("load", testIframeLoaded);
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy],
["network.cookie.cookieBehavior", behavior],
["network.cookie.lifetimePolicy", lifetime],
]}, function() {
iframe.src = origin + basePath + "iframe1.html";
});
@@ -186,7 +190,8 @@ function testShouldNotIntercept(policy, done) {
status: "getregistrationfailed",
next: function() {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT],
["network.cookie.cookieBehavior", BEHAVIOR_ACCEPT],
["network.cookie.lifetimePolicy", LIFETIME_EXPIRE],
]}, function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
});
@@ -204,10 +209,13 @@ function testShouldNotIntercept(policy, done) {
});
}
const COOKIE_BEHAVIOR_ACCEPT = 0;
const COOKIE_BEHAVIOR_REJECTFOREIGN = 1;
const COOKIE_BEHAVIOR_REJECT = 2;
const COOKIE_BEHAVIOR_LIMITFOREIGN = 3;
const BEHAVIOR_ACCEPT = 0;
const BEHAVIOR_REJECTFOREIGN = 1;
const BEHAVIOR_REJECT = 2;
const BEHAVIOR_LIMITFOREIGN = 3;
const LIFETIME_EXPIRE = 0;
const LIFETIME_SESSION = 2;
let steps = [() => {
SpecialPowers.pushPrefEnv({"set": [
@@ -215,22 +223,37 @@ let steps = [() => {
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["browser.dom.window.dump.enabled", true],
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
["network.cookie.cookieBehavior", BEHAVIOR_ACCEPT],
["network.cookie.lifetimePolicy", LIFETIME_EXPIRE],
]}, next);
}, () => {
testShouldIntercept(COOKIE_BEHAVIOR_ACCEPT, next);
testShouldIntercept(BEHAVIOR_ACCEPT, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotRegister(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
testShouldNotRegister(BEHAVIOR_REJECTFOREIGN, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotIntercept(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
testShouldNotIntercept(BEHAVIOR_REJECTFOREIGN, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotRegister(COOKIE_BEHAVIOR_REJECT, next);
testShouldNotRegister(BEHAVIOR_REJECT, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotIntercept(COOKIE_BEHAVIOR_REJECT, next);
testShouldNotIntercept(BEHAVIOR_REJECT, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotRegister(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
testShouldNotRegister(BEHAVIOR_LIMITFOREIGN, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotIntercept(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
testShouldNotIntercept(BEHAVIOR_LIMITFOREIGN, LIFETIME_EXPIRE, next);
}, () => {
testShouldNotIntercept(BEHAVIOR_ACCEPT, LIFETIME_SESSION, next);
}, () => {
testShouldNotRegister(BEHAVIOR_REJECTFOREIGN, LIFETIME_SESSION, next);
}, () => {
testShouldNotIntercept(BEHAVIOR_REJECTFOREIGN, LIFETIME_SESSION, next);
}, () => {
testShouldNotRegister(BEHAVIOR_REJECT, LIFETIME_SESSION, next);
}, () => {
testShouldNotIntercept(BEHAVIOR_REJECT, LIFETIME_SESSION, next);
}, () => {
testShouldNotRegister(BEHAVIOR_LIMITFOREIGN, LIFETIME_SESSION, next);
}, () => {
testShouldNotIntercept(BEHAVIOR_LIMITFOREIGN, LIFETIME_SESSION, next);
}];
</script>

View File

@@ -13,14 +13,15 @@
<p id="display"></p>
<div id="content"></div>
<pre id="test"></pre>
<script src="utils.js"></script>
<script class="testbody" type="text/javascript">
var registration;
var promise;
function start() {
return navigator.serviceWorker.register("worker_updatefoundevent.js",
{ scope: "./updatefoundevent.html" })
.then((swr) => registration = swr);
async function start() {
registration = await navigator.serviceWorker.register("worker_updatefoundevent.js",
{ scope: "./updatefoundevent.html" })
await waitForState(registration.installing, 'activated');
}
function startWaitForUpdateFound() {

View File

@@ -3,21 +3,16 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
onactivate = function(e) {
e.waitUntil(new Promise(function(resolve, reject) {
registration.onupdatefound = function(e) {
clients.matchAll().then(function(clients) {
if (!clients.length) {
reject("No clients found");
}
if (registration.scope.match(/updatefoundevent\.html$/)) {
clients[0].postMessage("finish");
resolve();
} else {
dump("Scope did not match");
}
}, reject);
registration.onupdatefound = function(e) {
clients.matchAll().then(function(clients) {
if (!clients.length) {
reject("No clients found");
}
}));
if (registration.scope.match(/updatefoundevent\.html$/)) {
clients[0].postMessage("finish");
} else {
dump("Scope did not match");
}
});
}

View File

@@ -21,19 +21,6 @@
namespace mozilla {
namespace wr {
struct ColorF;
struct TypedSize2D_f32__LayerPixel;
typedef TypedSize2D_f32__LayerPixel LayerSize;
typedef LayerSize LayoutSize;
struct TypedRect_f32__LayerPixel;
typedef TypedRect_f32__LayerPixel LayerRect;
typedef LayerRect LayoutRect;
} // namespace wr
namespace gfx {
template <class units, class F> struct RectTyped;
} // namespace gfx

View File

@@ -366,6 +366,23 @@ typedef GenericFlingAnimation FlingAnimation;
* the main thread doesn't actually need to do a repaint. This pref allows the
* main thread to skip doing those repaints in cases where it doesn't need to.
*
* \li\b apz.pinch_lock.mode
* The preferred pinch locking style. See PinchLockMode for possible values.
*
* \li\b apz.pinch_lock.scroll_lock_threshold
* Pinch locking is triggered if the user scrolls more than this distance
* and pinches less than apz.pinch_lock.span_lock_threshold.\n
* Units: (real-world, i.e. screen) inches
*
* \li\b apz.pinch_lock.span_breakout_threshold
* Distance in inches the user must pinch before lock can be broken.\n
* Units: (real-world, i.e. screen) inches measured between two touch points
*
* \li\b apz.pinch_lock.span_lock_threshold
* Pinch locking is triggered if the user pinches less than this distance
* and scrolls more than apz.pinch_lock.scroll_lock_threshold.\n
* Units: (real-world, i.e. screen) inches measured between two touch points
*
* \li\b apz.popups.enabled
* Determines whether APZ is used for XUL popup widgets with remote content.
* Ideally, this should always be true, but it is currently not well tested, and
@@ -759,6 +776,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mX(this),
mY(this),
mPanDirRestricted(false),
mPinchLocked(false),
mZoomConstraints(false, false,
mFrameMetrics.GetDevPixelsPerCSSPixel() * kViewportMinScale / ParentLayerToScreenScale(1),
mFrameMetrics.GetDevPixelsPerCSSPixel() * kViewportMaxScale / ParentLayerToScreenScale(1)),
@@ -864,6 +882,11 @@ AsyncPanZoomController::GetSecondTapTolerance()
return static_cast<AxisLockMode>(gfxPrefs::APZAxisLockMode());
}
/* static */AsyncPanZoomController::PinchLockMode AsyncPanZoomController::GetPinchLockMode()
{
return static_cast<PinchLockMode>(gfxPrefs::APZPinchLockMode());
}
bool
AsyncPanZoomController::ArePointerEventsConsumable(TouchBlockState* aBlock, uint32_t aTouchPoints) {
if (aTouchPoints == 0) {
@@ -1328,6 +1351,7 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
mPinchLocked = false;
mPinchPaintTimerSet = false;
// Note that there may not be a touch block at this point, if we received the
// PinchGestureEvent directly from widget code without any touch events.
@@ -1369,9 +1393,26 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
return nsEventStatus_eConsumeNoDefault;
}
ParentLayerCoord spanDistance = fabsf(aEvent.mPreviousSpan - aEvent.mCurrentSpan);
ParentLayerPoint focusPoint, focusChange;
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
focusPoint = aEvent.mLocalFocusPoint - mFrameMetrics.GetCompositionBounds().TopLeft();
focusChange = mLastZoomFocus - focusPoint;
mLastZoomFocus = focusPoint;
}
HandlePinchLocking(
ToScreenCoordinates(ParentLayerPoint(0, spanDistance), focusPoint).Length(),
ToScreenCoordinates(focusChange, focusPoint));
bool allowZoom = mZoomConstraints.mAllowZoom && !mPinchLocked;
// If zooming is not allowed, this is a two-finger pan.
// Tracking panning distance and velocity.
if (!mZoomConstraints.mAllowZoom) {
// UpdateWithTouchAtDevicePoint() acquires the tree lock, so
// it cannot be called while the mRecursiveMutex lock is held.
if (!allowZoom) {
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, 0, aEvent.mTime);
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, 0, aEvent.mTime);
}
@@ -1397,11 +1438,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
RecursiveMutexAutoLock lock(mRecursiveMutex);
CSSToParentLayerScale userZoom = mFrameMetrics.GetZoom().ToScaleFactor();
ParentLayerPoint focusPoint = aEvent.mLocalFocusPoint - mFrameMetrics.GetCompositionBounds().TopLeft();
CSSPoint cssFocusPoint = focusPoint / mFrameMetrics.GetZoom();
ParentLayerPoint focusChange = mLastZoomFocus - focusPoint;
mLastZoomFocus = focusPoint;
// If displacing by the change in focus point will take us off page bounds,
// then reduce the displacement such that it doesn't.
focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
@@ -1439,12 +1477,9 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
realMaxZoom = realMinZoom;
}
bool doScale = (spanRatio > 1.0 && userZoom < realMaxZoom) ||
(spanRatio < 1.0 && userZoom > realMinZoom);
if (!mZoomConstraints.mAllowZoom) {
doScale = false;
}
bool doScale = allowZoom && (
(spanRatio > 1.0 && userZoom < realMaxZoom) ||
(spanRatio < 1.0 && userZoom > realMinZoom));
if (doScale) {
spanRatio = clamped(spanRatio,
@@ -2601,6 +2636,24 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
}
}
void AsyncPanZoomController::HandlePinchLocking(ScreenCoord spanDistance, ScreenPoint focusChange) {
if (mPinchLocked) {
if (GetPinchLockMode() == PINCH_STICKY) {
ScreenCoord spanBreakoutThreshold = gfxPrefs::APZPinchLockSpanBreakoutThreshold() * APZCTreeManager::GetDPI();
mPinchLocked = !(spanDistance > spanBreakoutThreshold);
}
} else {
if (GetPinchLockMode() != PINCH_FREE) {
ScreenCoord spanLockThreshold = gfxPrefs::APZPinchLockSpanLockThreshold() * APZCTreeManager::GetDPI();
ScreenCoord scrollLockThreshold = gfxPrefs::APZPinchLockScrollLockThreshold() * APZCTreeManager::GetDPI();
if (spanDistance < spanLockThreshold && focusChange.Length() > scrollLockThreshold) {
mPinchLocked = true;
}
}
}
}
nsEventStatus
AsyncPanZoomController::StartPanning(const ParentLayerPoint& aStartPoint) {
RecursiveMutexAutoLock lock(mRecursiveMutex);

View File

@@ -655,6 +655,11 @@ protected:
*/
void HandlePanningUpdate(const ScreenPoint& aDelta);
/**
* Set and update the pinch lock
*/
void HandlePinchLocking(ScreenCoord spanDistance, ScreenPoint focusChange);
/**
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
* state and starts actually panning us.
@@ -724,6 +729,14 @@ protected:
static AxisLockMode GetAxisLockMode();
enum PinchLockMode {
PINCH_FREE, /* No locking at all */
PINCH_STANDARD, /* Default pinch locking mode that remains locked until pinch gesture ends*/
PINCH_STICKY, /* Allow lock to be broken, with hysteresis */
};
static PinchLockMode GetPinchLockMode();
// Helper function for OnSingleTapUp(), OnSingleTapConfirmed(), and
// OnLongPressUp().
nsEventStatus GenerateSingleTap(GeckoContentController::TapType aType,
@@ -800,6 +813,10 @@ private:
// the touch-action CSS property.
bool mPanDirRestricted;
// This flag is set to true when we are in a pinch-locked state. ie: user
// is performing a two-finger pan rather than a pinch gesture
bool mPinchLocked;
// Most up-to-date constraints on zooming. These should always be reasonable
// values; for example, allowing a min zoom of 0.0 can cause very bad things
// to happen.

View File

@@ -137,14 +137,24 @@ public:
if (entry.mManager->IsDestroyed()) {
mKeys.RemoveElementAt(i);
} else if (entry.mManager == aManager) {
found = true;
if (entry.mInvalidations != aInvalidations) {
aManager->AddImageKeyForDiscard(entry.mImageKey);
WebRenderBridgeChild* wrBridge = aManager->WrBridge();
MOZ_ASSERT(wrBridge);
// Even if the manager is the same, its underlying WebRenderBridgeChild
// can change state. If our namespace differs, then our old key has
// already been discarded.
bool ownsKey = wrBridge->GetNamespace() == entry.mImageKey.mNamespace;
if (!ownsKey || entry.mInvalidations != aInvalidations) {
if (ownsKey) {
aManager->AddImageKeyForDiscard(entry.mImageKey);
}
entry.mInvalidations = aInvalidations;
entry.mImageKey = aManager->WrBridge()->GetNextImageKey();
entry.mImageKey = wrBridge->GetNextImageKey();
aResources.AddExternalImage(mId, entry.mImageKey);
}
key = entry.mImageKey;
found = true;
}
}

View File

@@ -252,7 +252,7 @@ AsyncImagePipelineManager::UpdateWithoutExternalImage(wr::ResourceUpdateQueue& a
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
// Costly copy right here...
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
bytes.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
if (aOp == TextureHost::UPDATE_IMAGE) {

View File

@@ -173,7 +173,7 @@ ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
}
bool
ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto)
{
// source = zero is for small allocs.
MOZ_RELEASE_ASSERT(aRange.source() != 0);
@@ -193,7 +193,7 @@ ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInt
}
bool
ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto)
{
if (aRange.length() == 0) {
return true;

View File

@@ -51,10 +51,10 @@ public:
ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems);
bool Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
bool Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
protected:
bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);
const nsTArray<ipc::Shmem>& mSmallAllocs;
const nsTArray<ipc::Shmem>& mLargeAllocs;

View File

@@ -289,7 +289,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
switch (cmd.type()) {
case OpUpdateResource::TOpAddImage: {
const auto& op = cmd.get_OpAddImage();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -298,7 +298,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpUpdateImage: {
const auto& op = cmd.get_OpUpdateImage();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -307,7 +307,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpAddBlobImage: {
const auto& op = cmd.get_OpAddBlobImage();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -316,7 +316,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpUpdateBlobImage: {
const auto& op = cmd.get_OpUpdateBlobImage();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -332,7 +332,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpAddRawFont: {
const auto& op = cmd.get_OpAddRawFont();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -341,7 +341,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpAddFontDescriptor: {
const auto& op = cmd.get_OpAddFontDescriptor();
wr::Vec_u8 bytes;
wr::Vec<uint8_t> bytes;
if (!reader.Read(op.bytes(), bytes)) {
return false;
}
@@ -350,7 +350,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpAddFontInstance: {
const auto& op = cmd.get_OpAddFontInstance();
wr::Vec_u8 variations;
wr::Vec<uint8_t> variations;
if (!reader.Read(op.variations(), variations)) {
return false;
}
@@ -440,7 +440,7 @@ WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
wr::Vec_u8 data;
wr::Vec<uint8_t> data;
data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
aResources.AddImage(keys[0], descriptor, data);
dSurf->Unmap();
@@ -611,7 +611,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
}
wr::Vec_u8 dlData(Move(dl));
wr::Vec<uint8_t> dlData(Move(dl));
// If id namespaces do not match, it means the command is obsolete, probably
// because the tab just moved to a new window.

View File

@@ -333,6 +333,10 @@ private:
DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
DECL_GFX_PREF(Live, "apz.paint_skipping.enabled", APZPaintSkipping, bool, true);
DECL_GFX_PREF(Live, "apz.peek_messages.enabled", APZPeekMessages, bool, true);
DECL_GFX_PREF(Live, "apz.pinch_lock.mode", APZPinchLockMode, int32_t, 1);
DECL_GFX_PREF(Live, "apz.pinch_lock.scroll_lock_threshold", APZPinchLockScrollLockThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.pinch_lock.span_breakout_threshold", APZPinchLockSpanBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.pinch_lock.span_lock_threshold", APZPinchLockSpanLockThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.popups.enabled", APZPopupsEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
DECL_GFX_PREF(Live, "apz.record_checkerboarding", APZRecordCheckerboarding, bool, false);

View File

@@ -265,7 +265,7 @@ WebRenderAPI::SetDisplayList(gfx::Color aBgColor,
wr::WrPipelineId pipeline_id,
const LayoutSize& content_size,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec_u8& dl_data,
wr::Vec<uint8_t>& dl_data,
ResourceUpdateQueue& aResources)
{
wr_api_set_display_list(mDocHandle,
@@ -505,7 +505,7 @@ ResourceUpdateQueue::Clear()
void
ResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes)
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_add_image(mUpdates,
key,
@@ -515,7 +515,7 @@ ResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
void
ResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes)
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_add_blob_image(mUpdates,
key,
@@ -552,7 +552,7 @@ ResourceUpdateQueue::AddExternalImageBuffer(ImageKey aKey,
void
ResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes)
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_update_image(mUpdates,
aKey,
@@ -563,7 +563,7 @@ ResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
void
ResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes,
wr::Vec<uint8_t>& aBytes,
const wr::DeviceUintRect& aDirtyRect)
{
wr_resource_updates_update_blob_image(mUpdates,
@@ -595,13 +595,13 @@ ResourceUpdateQueue::DeleteImage(ImageKey aKey)
}
void
ResourceUpdateQueue::AddRawFont(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex)
ResourceUpdateQueue::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
{
wr_resource_updates_add_raw_font(mUpdates, aKey, &aBytes.inner, aIndex);
}
void
ResourceUpdateQueue::AddFontDescriptor(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex)
ResourceUpdateQueue::AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
{
wr_resource_updates_add_font_descriptor(mUpdates, aKey, &aBytes.inner, aIndex);
}
@@ -618,7 +618,7 @@ ResourceUpdateQueue::AddFontInstance(wr::FontInstanceKey aKey,
float aGlyphSize,
const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
wr::Vec_u8& aVariations)
wr::Vec<uint8_t>& aVariations)
{
wr_resource_updates_add_font_instance(mUpdates, aKey, aFontKey, aGlyphSize,
aOptions, aPlatformOptions,
@@ -1131,7 +1131,7 @@ DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds,
const wr::BorderWidths& aWidths,
wr::ImageKey aImage,
const wr::NinePatchDescriptor& aPatch,
const wr::SideOffsets2D_f32& aOutset,
const wr::SideOffsets2D<float>& aOutset,
const wr::RepeatMode& aRepeatHorizontal,
const wr::RepeatMode& aRepeatVertical)
{
@@ -1149,7 +1149,7 @@ DisplayListBuilder::PushBorderGradient(const wr::LayoutRect& aBounds,
const wr::LayoutPoint& aEndPoint,
const nsTArray<wr::GradientStop>& aStops,
wr::ExtendMode aExtendMode,
const wr::SideOffsets2D_f32& aOutset)
const wr::SideOffsets2D<float>& aOutset)
{
wr_dp_push_border_gradient(mWrState, aBounds, aClip, aIsBackfaceVisible,
aWidths, aStartPoint, aEndPoint,
@@ -1166,7 +1166,7 @@ DisplayListBuilder::PushBorderRadialGradient(const wr::LayoutRect& aBounds,
const wr::LayoutSize& aRadius,
const nsTArray<wr::GradientStop>& aStops,
wr::ExtendMode aExtendMode,
const wr::SideOffsets2D_f32& aOutset)
const wr::SideOffsets2D<float>& aOutset)
{
wr_dp_push_border_radial_gradient(
mWrState, aBounds, aClip, aIsBackfaceVisible, aWidths, aCenter,

View File

@@ -63,11 +63,11 @@ public:
void AddImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes);
wr::Vec<uint8_t>& aBytes);
void AddBlobImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes);
wr::Vec<uint8_t>& aBytes);
void AddExternalImageBuffer(ImageKey key,
const ImageDescriptor& aDescriptor,
@@ -81,11 +81,11 @@ public:
void UpdateImageBuffer(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes);
wr::Vec<uint8_t>& aBytes);
void UpdateBlobImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec_u8& aBytes,
wr::Vec<uint8_t>& aBytes,
const wr::DeviceUintRect& aDirtyRect);
void UpdateExternalImage(ImageKey aKey,
@@ -96,9 +96,9 @@ public:
void DeleteImage(wr::ImageKey aKey);
void AddRawFont(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex);
void AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex);
void AddFontDescriptor(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex);
void AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex);
void DeleteFont(wr::FontKey aKey);
@@ -107,7 +107,7 @@ public:
float aGlyphSize,
const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
wr::Vec_u8& aVariations);
wr::Vec<uint8_t>& aVariations);
void DeleteFontInstance(wr::FontInstanceKey aKey);
@@ -161,7 +161,7 @@ public:
wr::WrPipelineId pipeline_id,
const wr::LayoutSize& content_size,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec_u8& dl_data,
wr::Vec<uint8_t>& dl_data,
ResourceUpdateQueue& aResources);
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId pipeline_id);
@@ -361,7 +361,7 @@ public:
const wr::BorderWidths& aWidths,
wr::ImageKey aImage,
const wr::NinePatchDescriptor& aPatch,
const wr::SideOffsets2D_f32& aOutset,
const wr::SideOffsets2D<float>& aOutset,
const wr::RepeatMode& aRepeatHorizontal,
const wr::RepeatMode& aRepeatVertical);
@@ -373,7 +373,7 @@ public:
const wr::LayoutPoint& aEndPoint,
const nsTArray<wr::GradientStop>& aStops,
wr::ExtendMode aExtendMode,
const wr::SideOffsets2D_f32& aOutset);
const wr::SideOffsets2D<float>& aOutset);
void PushBorderRadialGradient(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
@@ -383,7 +383,7 @@ public:
const wr::LayoutSize& aRadius,
const nsTArray<wr::GradientStop>& aStops,
wr::ExtendMode aExtendMode,
const wr::SideOffsets2D_f32& aOutset);
const wr::SideOffsets2D<float>& aOutset);
void PushText(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,

View File

@@ -11,13 +11,15 @@
namespace mozilla {
namespace wr {
Vec_u8::Vec_u8(mozilla::ipc::ByteBuf&& aSrc) {
inner.data = aSrc.mData;
inner.length = aSrc.mLen;
inner.capacity = aSrc.mCapacity;
aSrc.mData = nullptr;
aSrc.mLen = 0;
aSrc.mCapacity = 0;
void
Assign_WrVecU8(wr::WrVecU8& aVec, mozilla::ipc::ByteBuf&& aOther)
{
aVec.data = aOther.mData;
aVec.length = aOther.mLen;
aVec.capacity = aOther.mCapacity;
aOther.mData = nullptr;
aOther.mLen = 0;
aOther.mCapacity = 0;
}
} // namespace wr

View File

@@ -461,7 +461,7 @@ static inline wr::BorderWidths ToBorderWidths(float top, float right, float bott
}
static inline wr::NinePatchDescriptor ToNinePatchDescriptor(uint32_t width, uint32_t height,
const wr::SideOffsets2D_u32& slice)
const wr::SideOffsets2D<uint32_t>& slice)
{
NinePatchDescriptor patch;
patch.width = width;
@@ -470,9 +470,9 @@ static inline wr::NinePatchDescriptor ToNinePatchDescriptor(uint32_t width, uint
return patch;
}
static inline wr::SideOffsets2D_u32 ToSideOffsets2D_u32(uint32_t top, uint32_t right, uint32_t bottom, uint32_t left)
static inline wr::SideOffsets2D<uint32_t> ToSideOffsets2D_u32(uint32_t top, uint32_t right, uint32_t bottom, uint32_t left)
{
SideOffsets2D_u32 offset;
SideOffsets2D<uint32_t> offset;
offset.top = top;
offset.right = right;
offset.bottom = bottom;
@@ -480,9 +480,9 @@ static inline wr::SideOffsets2D_u32 ToSideOffsets2D_u32(uint32_t top, uint32_t r
return offset;
}
static inline wr::SideOffsets2D_f32 ToSideOffsets2D_f32(float top, float right, float bottom, float left)
static inline wr::SideOffsets2D<float> ToSideOffsets2D_f32(float top, float right, float bottom, float left)
{
SideOffsets2D_f32 offset;
SideOffsets2D<float> offset;
offset.top = top;
offset.right = right;
offset.bottom = bottom;
@@ -571,21 +571,29 @@ inline mozilla::Range<uint8_t> MutByteSliceToRange(wr::MutByteSlice aWrSlice) {
return mozilla::Range<uint8_t>(aWrSlice.buffer, aWrSlice.len);
}
struct Vec_u8 {
void Assign_WrVecU8(wr::WrVecU8& aVec, mozilla::ipc::ByteBuf&& aOther);
template<typename T>
struct Vec;
template<>
struct Vec<uint8_t> {
wr::WrVecU8 inner;
Vec_u8() {
Vec() {
SetEmpty();
}
Vec_u8(Vec_u8&) = delete;
Vec_u8(Vec_u8&& src) {
Vec(Vec&) = delete;
Vec(Vec&& src) {
inner = src.inner;
src.SetEmpty();
}
explicit Vec_u8(mozilla::ipc::ByteBuf&& aSrc);
explicit Vec(mozilla::ipc::ByteBuf&& aSrc) {
Assign_WrVecU8(inner, std::move(aSrc));
}
Vec_u8&
operator=(Vec_u8&& src) {
Vec&
operator=(Vec&& src) {
inner = src.inner;
src.SetEmpty();
return *this;
@@ -612,7 +620,7 @@ struct Vec_u8 {
wr_vec_u8_push_bytes(&inner, RangeToByteSlice(aBytes));
}
~Vec_u8() {
~Vec() {
if (inner.data) {
wr_vec_u8_free(inner);
}

View File

@@ -27,7 +27,6 @@ rename_args = "GeckoCase"
[struct]
derive_eq = true
generic_template_specialization = false
[enum]
add_sentinel = true

View File

@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Generated with cbindgen:0.2.2 */
/* Generated with cbindgen:0.3.3 */
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
@@ -14,8 +14,6 @@
#include <cstdint>
#include <cstdlib>
extern "C" {
namespace mozilla {
namespace wr {
@@ -237,10 +235,18 @@ enum class YuvColorSpace : uint32_t {
Sentinel /* this must be last for serialization purposes. */
};
struct Arc_VecU8;
template<typename T>
struct Arc;
// Geometry in the coordinate system of the render target (screen or intermediate
// surface) in physical pixels.
struct DevicePixel;
struct DocumentHandle;
// Geometry in a layer's local coordinate space (logical pixels).
struct LayerPixel;
// The renderer is responsible for submitting to the GPU the work prepared by the
// RenderBackend.
struct Renderer;
@@ -248,7 +254,17 @@ struct Renderer;
// The resource updates for a given transaction (they must be applied in the same frame).
struct ResourceUpdates;
struct Vec_u8;
// Offset in number of tiles.
struct Tiles;
// The default unit.
struct UnknownUnit;
template<typename T>
struct Vec;
// Geometry in the document's coordinate space (logical pixels).
struct WorldPixel;
struct WrProgramCache;
@@ -285,11 +301,11 @@ struct FontKey {
}
};
typedef FontKey WrFontKey;
using WrFontKey = FontKey;
typedef Arc_VecU8 ArcVecU8;
using VecU8 = Vec<uint8_t>;
typedef Vec_u8 VecU8;
using ArcVecU8 = Arc<VecU8>;
struct Epoch {
uint32_t mHandle;
@@ -305,13 +321,13 @@ struct Epoch {
}
};
typedef Epoch WrEpoch;
using WrEpoch = Epoch;
// This type carries no valuable semantics for WR. However, it reflects the fact that
// clients (Servo) may generate pipelines by different semi-independent sources.
// These pipelines still belong to the same `IdNamespace` and the same `DocumentId`.
// Having this extra Id field enables them to generate `PipelineId` without collision.
typedef uint32_t PipelineSourceId;
using PipelineSourceId = uint32_t;
// From the point of view of WR, `PipelineId` is completely opaque and generic as long as
// it's clonable, serializable, comparable, and hashable.
@@ -325,21 +341,22 @@ struct PipelineId {
}
};
typedef PipelineId WrPipelineId;
using WrPipelineId = PipelineId;
struct TypedSize2D_f32__LayerPixel {
float width;
float height;
template<typename T, typename U>
struct TypedSize2D {
T width;
T height;
bool operator==(const TypedSize2D_f32__LayerPixel& aOther) const {
bool operator==(const TypedSize2D& aOther) const {
return width == aOther.width &&
height == aOther.height;
}
};
typedef TypedSize2D_f32__LayerPixel LayerSize;
using LayerSize = TypedSize2D<float, LayerPixel>;
typedef LayerSize LayoutSize;
using LayoutSize = LayerSize;
// Describes the memory layout of a display list.
//
@@ -382,6 +399,11 @@ struct WrOpacityProperty {
}
};
// Geometry in a stacking context's local coordinate space (logical pixels).
//
// For now layout pixels are equivalent to layer pixels, but it may change.
using LayoutPixel = LayerPixel;
// A 3d transform stored as a 4 by 4 matrix in row-major order in memory.
//
// Transforms can be parametrized over the source and destination units, to describe a
@@ -393,25 +415,26 @@ struct WrOpacityProperty {
// A pre-transformation corresponds to adding an operation that is applied before
// the rest of the transformation, while a post-transformation adds an operation
// that is applied after.
struct TypedTransform3D_f32__LayoutPixel__LayoutPixel {
float m11;
float m12;
float m13;
float m14;
float m21;
float m22;
float m23;
float m24;
float m31;
float m32;
float m33;
float m34;
float m41;
float m42;
float m43;
float m44;
template<typename T, typename Src, typename Dst>
struct TypedTransform3D {
T m11;
T m12;
T m13;
T m14;
T m21;
T m22;
T m23;
T m24;
T m31;
T m32;
T m33;
T m34;
T m41;
T m42;
T m43;
T m44;
bool operator==(const TypedTransform3D_f32__LayoutPixel__LayoutPixel& aOther) const {
bool operator==(const TypedTransform3D& aOther) const {
return m11 == aOther.m11 &&
m12 == aOther.m12 &&
m13 == aOther.m13 &&
@@ -431,27 +454,28 @@ struct TypedTransform3D_f32__LayoutPixel__LayoutPixel {
}
};
typedef TypedTransform3D_f32__LayoutPixel__LayoutPixel LayoutTransform;
using LayoutTransform = TypedTransform3D<float, LayoutPixel, LayoutPixel>;
struct WrTransformProperty {
uint64_t id;
LayoutTransform transform;
};
typedef IdNamespace WrIdNamespace;
using WrIdNamespace = IdNamespace;
// A 2d Point tagged with a unit.
struct TypedPoint2D_f32__WorldPixel {
float x;
float y;
template<typename T, typename U>
struct TypedPoint2D {
T x;
T y;
bool operator==(const TypedPoint2D_f32__WorldPixel& aOther) const {
bool operator==(const TypedPoint2D& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
typedef TypedPoint2D_f32__WorldPixel WorldPoint;
using WorldPoint = TypedPoint2D<float, WorldPixel>;
// Represents RGBA screen colors with floating point numbers.
//
@@ -471,31 +495,21 @@ struct ColorF {
}
};
// A 2d Point tagged with a unit.
struct TypedPoint2D_f32__LayerPixel {
float x;
float y;
bool operator==(const TypedPoint2D_f32__LayerPixel& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
// A 2d Rectangle optionally tagged with a unit.
struct TypedRect_f32__LayerPixel {
TypedPoint2D_f32__LayerPixel origin;
TypedSize2D_f32__LayerPixel size;
template<typename T, typename U>
struct TypedRect {
TypedPoint2D<T, U> origin;
TypedSize2D<T, U> size;
bool operator==(const TypedRect_f32__LayerPixel& aOther) const {
bool operator==(const TypedRect& aOther) const {
return origin == aOther.origin &&
size == aOther.size;
}
};
typedef TypedRect_f32__LayerPixel LayerRect;
using LayerRect = TypedRect<float, LayerPixel>;
typedef LayerRect LayoutRect;
using LayoutRect = LayerRect;
struct BorderRadius {
LayoutSize top_left;
@@ -541,7 +555,7 @@ struct ImageKey {
}
};
typedef ImageKey WrImageKey;
using WrImageKey = ImageKey;
struct WrImageMask {
WrImageKey image;
@@ -573,19 +587,20 @@ struct StickyOffsetBounds {
};
// A 2d Vector tagged with a unit.
struct TypedVector2D_f32__LayerPixel {
float x;
float y;
template<typename T, typename U>
struct TypedVector2D {
T x;
T y;
bool operator==(const TypedVector2D_f32__LayerPixel& aOther) const {
bool operator==(const TypedVector2D& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
typedef TypedVector2D_f32__LayerPixel LayerVector2D;
using LayerVector2D = TypedVector2D<float, LayerPixel>;
typedef LayerVector2D LayoutVector2D;
using LayoutVector2D = LayerVector2D;
struct BorderWidths {
float left;
@@ -611,9 +626,9 @@ struct BorderSide {
}
};
typedef TypedPoint2D_f32__LayerPixel LayerPoint;
using LayerPoint = TypedPoint2D<float, LayerPixel>;
typedef LayerPoint LayoutPoint;
using LayoutPoint = LayerPoint;
struct GradientStop {
float offset;
@@ -625,14 +640,14 @@ struct GradientStop {
}
};
// The default side offset type with no unit.
struct SideOffsets2D_f32 {
float top;
float right;
float bottom;
float left;
template<typename T, typename U>
struct TypedSideOffsets2D {
T top;
T right;
T bottom;
T left;
bool operator==(const SideOffsets2D_f32& aOther) const {
bool operator==(const TypedSideOffsets2D& aOther) const {
return top == aOther.top &&
right == aOther.right &&
bottom == aOther.bottom &&
@@ -641,24 +656,13 @@ struct SideOffsets2D_f32 {
};
// The default side offset type with no unit.
struct SideOffsets2D_u32 {
uint32_t top;
uint32_t right;
uint32_t bottom;
uint32_t left;
bool operator==(const SideOffsets2D_u32& aOther) const {
return top == aOther.top &&
right == aOther.right &&
bottom == aOther.bottom &&
left == aOther.left;
}
};
template<typename T>
using SideOffsets2D = TypedSideOffsets2D<T, UnknownUnit>;
struct NinePatchDescriptor {
uint32_t width;
uint32_t height;
SideOffsets2D_u32 slice;
SideOffsets2D<uint32_t> slice;
bool operator==(const NinePatchDescriptor& aOther) const {
return width == aOther.width &&
@@ -713,9 +717,9 @@ struct FontInstanceKey {
}
};
typedef FontInstanceKey WrFontInstanceKey;
using WrFontInstanceKey = FontInstanceKey;
typedef uint32_t GlyphIndex;
using GlyphIndex = uint32_t;
struct GlyphInstance {
GlyphIndex index;
@@ -735,9 +739,9 @@ struct GlyphOptions {
}
};
typedef YuvColorSpace WrYuvColorSpace;
using WrYuvColorSpace = YuvColorSpace;
typedef LogLevelFilter WrLogLevelFilter;
using WrLogLevelFilter = LogLevelFilter;
struct ByteSlice {
const uint8_t *buffer;
@@ -749,18 +753,7 @@ struct ByteSlice {
}
};
// A 2d Point tagged with a unit.
struct TypedPoint2D_u16__Tiles {
uint16_t x;
uint16_t y;
bool operator==(const TypedPoint2D_u16__Tiles& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
typedef TypedPoint2D_u16__Tiles TileOffset;
using TileOffset = TypedPoint2D<uint16_t, Tiles>;
struct MutByteSlice {
uint8_t *buffer;
@@ -824,9 +817,9 @@ struct WrExternalImageId {
}
};
typedef WrExternalImage (*LockExternalImageCallback)(void*, WrExternalImageId, uint8_t);
using LockExternalImageCallback = WrExternalImage(*)(void*, WrExternalImageId, uint8_t);
typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageId, uint8_t);
using UnlockExternalImageCallback = void(*)(void*, WrExternalImageId, uint8_t);
struct WrExternalImageHandler {
void *external_image_obj;
@@ -856,7 +849,7 @@ struct WrImageDescriptor {
}
};
typedef ExternalImageType WrExternalImageBufferType;
using WrExternalImageBufferType = ExternalImageType;
// Represents RGBA screen colors with one byte per channel.
//
@@ -924,39 +917,9 @@ struct FontInstancePlatformOptions {
};
#endif
// A 2d Point tagged with a unit.
struct TypedPoint2D_u32__DevicePixel {
uint32_t x;
uint32_t y;
using DeviceUintRect = TypedRect<uint32_t, DevicePixel>;
bool operator==(const TypedPoint2D_u32__DevicePixel& aOther) const {
return x == aOther.x &&
y == aOther.y;
}
};
struct TypedSize2D_u32__DevicePixel {
uint32_t width;
uint32_t height;
bool operator==(const TypedSize2D_u32__DevicePixel& aOther) const {
return width == aOther.width &&
height == aOther.height;
}
};
// A 2d Rectangle optionally tagged with a unit.
struct TypedRect_u32__DevicePixel {
TypedPoint2D_u32__DevicePixel origin;
TypedSize2D_u32__DevicePixel size;
bool operator==(const TypedRect_u32__DevicePixel& aOther) const {
return origin == aOther.origin &&
size == aOther.size;
}
};
typedef TypedRect_u32__DevicePixel DeviceUintRect;
extern "C" {
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
@@ -1184,7 +1147,7 @@ void wr_dp_push_border_gradient(WrState *aState,
const GradientStop *aStops,
size_t aStopsCount,
ExtendMode aExtendMode,
SideOffsets2D_f32 aOutset)
SideOffsets2D<float> aOutset)
WR_FUNC;
WR_INLINE
@@ -1195,7 +1158,7 @@ void wr_dp_push_border_image(WrState *aState,
BorderWidths aWidths,
WrImageKey aImage,
NinePatchDescriptor aPatch,
SideOffsets2D_f32 aOutset,
SideOffsets2D<float> aOutset,
RepeatMode aRepeatHorizontal,
RepeatMode aRepeatVertical)
WR_FUNC;
@@ -1211,7 +1174,7 @@ void wr_dp_push_border_radial_gradient(WrState *aState,
const GradientStop *aStops,
size_t aStopsCount,
ExtendMode aExtendMode,
SideOffsets2D_f32 aOutset)
SideOffsets2D<float> aOutset)
WR_FUNC;
WR_INLINE
@@ -1638,11 +1601,11 @@ bool wr_window_new(WrWindowId aWindowId,
uint32_t *aOutMaxTextureSize)
WR_FUNC;
} // extern "C"
} // namespace wr
} // namespace mozilla
} // extern "C"
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
* 1. Get the latest cbindgen using `cargo install --force cbindgen`

View File

@@ -0,0 +1,6 @@
x = new Uint32Array(4);
try {
Math.max(Uint32Array.prototype)();
} catch (e) {}
x[3] = -1;
assertEq(x.toString(), "0,0,0,4294967295");

View File

@@ -7,6 +7,7 @@
#include "jit/arm/CodeGenerator-arm.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Maybe.h"
#include "jscntxt.h"
#include "jscompartment.h"
@@ -1429,11 +1430,22 @@ CodeGeneratorARM::visitUnbox(LUnbox* unbox)
MUnbox* mir = unbox->mir();
Register type = ToRegister(unbox->type());
ScratchRegisterScope scratch(masm);
mozilla::Maybe<ScratchRegisterScope> scratch;
scratch.emplace(masm);
JSValueTag tag = MIRTypeToTag(mir->type());
if (mir->fallible()) {
masm.ma_cmp(type, Imm32(MIRTypeToTag(mir->type())), scratch);
masm.ma_cmp(type, Imm32(tag), *scratch);
bailoutIf(Assembler::NotEqual, unbox->snapshot());
} else {
#ifdef DEBUG
Label ok;
masm.ma_cmp(type, Imm32(tag), *scratch);
masm.ma_b(&ok, Assembler::Equal);
scratch.reset();
masm.assumeUnreachable("Infallible unbox type mismatch");
masm.bind(&ok);
#endif
}
}

View File

@@ -115,6 +115,16 @@ CodeGeneratorX64::visitUnbox(LUnbox* unbox)
MOZ_CRASH("Given MIRType cannot be unboxed.");
}
bailoutIf(cond, unbox->snapshot());
} else {
#ifdef DEBUG
Operand input = ToOperand(unbox->getOperand(LUnbox::Input));
JSValueTag tag = MIRTypeToTag(mir->type());
Label ok;
masm.splitTag(input, ScratchReg);
masm.branch32(Assembler::Equal, ScratchReg, Imm32(tag), &ok);
masm.assumeUnreachable("Infallible unbox type mismatch");
masm.bind(&ok);
#endif
}
Operand input = ToOperand(unbox->getOperand(LUnbox::Input));

View File

@@ -123,9 +123,17 @@ CodeGeneratorX86::visitUnbox(LUnbox* unbox)
// inputs.
MUnbox* mir = unbox->mir();
JSValueTag tag = MIRTypeToTag(mir->type());
if (mir->fallible()) {
masm.cmp32(ToOperand(unbox->type()), Imm32(MIRTypeToTag(mir->type())));
masm.cmp32(ToOperand(unbox->type()), Imm32(tag));
bailoutIf(Assembler::NotEqual, unbox->snapshot());
} else {
#ifdef DEBUG
Label ok;
masm.branch32(Assembler::Equal, ToOperand(unbox->type()), Imm32(tag), &ok);
masm.assumeUnreachable("Infallible unbox type mismatch");
masm.bind(&ok);
#endif
}
}

View File

@@ -86,20 +86,6 @@ BEGIN_TEST(testSavedStacks_RangeBasedForLoops)
CHECK(obj->is<js::SavedFrame>());
JS::Rooted<js::SavedFrame*> savedFrame(cx, &obj->as<js::SavedFrame>());
js::SavedFrame* f = savedFrame.get();
for (auto& frame : *savedFrame.get()) {
CHECK(&frame == f);
f = f->getParent();
}
CHECK(f == nullptr);
const js::SavedFrame* cf = savedFrame.get();
for (const auto& frame : *savedFrame.get()) {
CHECK(&frame == cf);
cf = cf->getParent();
}
CHECK(cf == nullptr);
JS::Rooted<js::SavedFrame*> rf(cx, savedFrame);
for (JS::Handle<js::SavedFrame*> frame : js::SavedFrame::RootedRange(cx, rf)) {
JS_GC(cx);

Some files were not shown because too many files have changed in this diff Show More