Merge pull request #9397 from faceless2/bfo-css-fonts-3-fontfeature
Added new testcases to test font-variant precedence rules
diff --git a/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html b/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
index 5f1c7fa..1621c03 100644
--- a/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
+++ b/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
@@ -8,34 +8,29 @@
<body class="show_output">
<h1>2d.drawImage.zerocanvas</h1>
-<p class="desc"></p>
+<p class="desc">drawImage with zero-sized canvas as the source shoud throw exception</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+
<ul id="d"></ul>
<script>
-var t = async_test("");
+var t = async_test("drawImage with zero-sized canvas as the source shoud throw exception");
_addTest(function(canvas, ctx) {
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
-
var canvas2 = document.createElement('canvas');
canvas2.width = 0;
-canvas2.height = 10;
-ctx.drawImage(canvas2, 0, 0);
+canvas2.height = 50;
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
-canvas2.width = 10;
+canvas2.width = 50;
canvas2.height = 0;
-ctx.drawImage(canvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
canvas2.width = 0;
canvas2.height = 0;
-ctx.drawImage(canvas2, 0, 0);
-
-_assertPixelApprox(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
});
diff --git a/2dcontext/tools/spec.yaml b/2dcontext/tools/spec.yaml
index 278dc95..e57bbc8 100644
--- a/2dcontext/tools/spec.yaml
+++ b/2dcontext/tools/spec.yaml
@@ -586,7 +586,7 @@
text: "If the image argument is <...> an HTMLVideoElement object whose readyState attribute is either HAVE_NOTHING or HAVE_METADATA<^>, then the implementation *must* return without drawing anything."
- id: 2d.drawImage.zerocanvas
previously: [ 10, "dw and dh" ]
- text: "If the image argument is an HTMLCanvasElement object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* return without drawing anything<^>."
+ text: "If the image argument is an HTMLCanvasElement or an OffscreenCanvas object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* throw an INVALID_STATE_ERR exception<^>."
- id: 2d.drawImage.zerosource
text: "If one of the sw or sh arguments is zero<^>, the implementation *must* return without drawing anything."
- id: 2d.drawImage.paint
diff --git a/2dcontext/tools/tests2d.yaml b/2dcontext/tools/tests2d.yaml
index 7da08f9..f7b858a 100644
--- a/2dcontext/tools/tests2d.yaml
+++ b/2dcontext/tools/tests2d.yaml
@@ -9002,27 +9002,22 @@
expected: green
- name: 2d.drawImage.zerocanvas
+ desc: drawImage with zero-sized canvas as the source shoud throw exception
testing:
- 2d.drawImage.zerocanvas
code: |
- ctx.fillStyle = '#0f0';
- ctx.fillRect(0, 0, 100, 50);
-
var canvas2 = document.createElement('canvas');
canvas2.width = 0;
- canvas2.height = 10;
- ctx.drawImage(canvas2, 0, 0);
+ canvas2.height = 50;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
- canvas2.width = 10;
+ canvas2.width = 50;
canvas2.height = 0;
- ctx.drawImage(canvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
canvas2.width = 0;
canvas2.height = 0;
- ctx.drawImage(canvas2, 0, 0);
-
- @assert pixel 50,25 ==~ 0,255,0,255;
- expected: green
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
- name: 2d.drawImage.svg
desc: drawImage() of an SVG image
diff --git a/IndexedDB/interleaved-cursors.html b/IndexedDB/interleaved-cursors-common.js
similarity index 93%
rename from IndexedDB/interleaved-cursors.html
rename to IndexedDB/interleaved-cursors-common.js
index 3112690..a76ec52 100644
--- a/IndexedDB/interleaved-cursors.html
+++ b/IndexedDB/interleaved-cursors-common.js
@@ -1,12 +1,5 @@
-<!doctype html>
-<meta charset="utf-8">
-<meta name="timeout" content="long">
-<title>IndexedDB: Interleaved iteration of multiple cursors</title>
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support-promises.js"></script>
-<script>
+// Infrastructure shared by interleaved-cursors-{small,large}.html
+
// Number of objects that each iterator goes over.
const itemCount = 10;
@@ -169,7 +162,7 @@
});
}
-for (let cursorCount of [1, 10, 100, 500]) {
+function cursorTest(cursorCount) {
promise_test(testCase => {
return createDatabase(testCase, (database, transaction) => {
const store = database.createObjectStore('cache',
@@ -193,4 +186,3 @@
});
}, `${cursorCount} cursors`);
}
-</script>
diff --git a/IndexedDB/interleaved-cursors-large.html b/IndexedDB/interleaved-cursors-large.html
new file mode 100644
index 0000000..6f4e440
--- /dev/null
+++ b/IndexedDB/interleaved-cursors-large.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>IndexedDB: Interleaved iteration of multiple cursors</title>
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="interleaved-cursors-common.js"></script>
+<script>
+cursorTest(250);
+</script>
diff --git a/IndexedDB/interleaved-cursors-small.html b/IndexedDB/interleaved-cursors-small.html
new file mode 100644
index 0000000..a4c4777
--- /dev/null
+++ b/IndexedDB/interleaved-cursors-small.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>IndexedDB: Interleaved iteration of multiple cursors</title>
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="interleaved-cursors-common.js"></script>
+<script>
+cursorTest(1);
+cursorTest(10);
+cursorTest(100);
+</script>
diff --git a/README.md b/README.md
index 0247e8c..90f1f47 100644
--- a/README.md
+++ b/README.md
@@ -32,17 +32,22 @@
and read the [Windows Notes](#windows-notes) section below.
To get the tests running, you need to set up the test domains in your
-[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system). The
-following entries are required:
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system).
+The necessary content can be generated with `./wpt make-hosts-file`; on
+Windows, you will need to preceed the prior command with `python` or
+the path to the Python binary (`python wpt make-hosts-file`).
+
+For example, on most UNIX-like systems, you can setup the hosts file with:
+
+```bash
+./wpt make-hosts-file | sudo tee -a /etc/hosts
```
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
+
+And on Windows (note this requires an Administrator privileged shell):
+
+```bash
+python wpt make-hosts-file >> %SystemRoot%\System32\drivers\etc\hosts
```
If you are behind a proxy, you also need to make sure the domains above are
diff --git a/common/css-paint-tests.js b/common/worklet-reftest.js
similarity index 71%
rename from common/css-paint-tests.js
rename to common/worklet-reftest.js
index cd57332..e060835 100644
--- a/common/css-paint-tests.js
+++ b/common/worklet-reftest.js
@@ -1,12 +1,12 @@
// To make sure that we take the snapshot at the right time, we do double
// requestAnimationFrame. In the second frame, we take a screenshot, that makes
// sure that we already have a full frame.
-function importPaintWorkletAndTerminateTestAfterAsyncPaint(code) {
- if (typeof CSS.paintWorklet == "undefined") {
+function importWorkletAndTerminateTestAfterAsyncPaint(worklet, code) {
+ if (typeof worklet == "undefined") {
takeScreenshot();
} else {
var blob = new Blob([code], {type: 'text/javascript'});
- CSS.paintWorklet.addModule(URL.createObjectURL(blob)).then(function() {
+ worklet.addModule(URL.createObjectURL(blob)).then(function() {
requestAnimationFrame(function() {
requestAnimationFrame(function() {
takeScreenshot();
diff --git a/compat/webkit-appearance.tentative.html b/compat/webkit-appearance.tentative.html
new file mode 100644
index 0000000..8c0273d
--- /dev/null
+++ b/compat/webkit-appearance.tentative.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>-webkit-appearance support</title>
+<!-- There is no spec for -webkit-appearance. It is supported in Opera, Safari,
+ Chrome, and Edge. Firefox has expressed intent to support it. -->
+<link rel="help" href="https://github.com/whatwg/compat/issues/6">
+<meta name="assert" content="This test checks for support of the -webkit-appearance CSS attribute." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="tester"></div>
+
+<script>
+const WEBKIT_APPEARANCE_VALUES = [
+ 'none',
+ 'checkbox',
+ 'radio',
+ 'push-button',
+ 'square-button',
+ 'button',
+ 'button-bevel',
+ 'inner-spin-button',
+ 'listbox',
+ 'listitem',
+ 'media-enter-fullscreen-button',
+ 'media-exit-fullscreen-button',
+ 'media-mute-button',
+ 'media-play-button',
+ 'media-overlay-play-button',
+ 'media-toggle-closed-captions-button',
+ 'media-slider',
+ 'media-sliderthumb',
+ 'media-volume-slider-container',
+ 'media-volume-slider',
+ 'media-volume-sliderthumb',
+ 'media-controls-background',
+ 'media-controls-fullscreen-background',
+ 'media-current-time-display',
+ 'media-time-remaining-display',
+ 'menulist',
+ 'menulist-button',
+ 'menulist-text',
+ 'menulist-textfield',
+ 'meter',
+ 'progress-bar',
+ 'progress-bar-value',
+ 'slider-horizontal',
+ 'slider-vertical',
+ 'sliderthumb-horizontal',
+ 'sliderthumb-vertical',
+ 'caret',
+ 'searchfield',
+ 'searchfield-cancel-button',
+ 'textfield',
+ 'textarea',
+];
+
+for (const appearance_value of WEBKIT_APPEARANCE_VALUES) {
+ test(() => {
+ const div = document.getElementById('tester');
+ div.style = `-webkit-appearance: ${appearance_value}`;
+ assert_equals(getComputedStyle(div).webkitAppearance, appearance_value);
+ });
+}
+</script>
diff --git a/console/console-format-specifier-symbol-manual.html b/console/console-format-specifier-symbol-manual.html
new file mode 100644
index 0000000..47a981f
--- /dev/null
+++ b/console/console-format-specifier-symbol-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Console Format Specifiers on Symbols</title>
+<meta name="author" title="Dominic Farolino" href="mailto:domfarolino@gmail.com">
+<meta name="assert" content="Console format specifiers on Symbols">
+<link rel="help" href="https://console.spec.whatwg.org/#formatter">
+</head>
+<body>
+<p>Open the console inside the developer tools. It should contain five lines, each of which are:</p>
+<p><code>Symbol(description)</code></p>
+
+<script>
+console.log("%s", Symbol.for("description"));
+console.dirxml("%s", Symbol.for("description"));
+console.trace("%s", Symbol.for("description"));
+console.group("%s", Symbol.for("description"));
+console.groupCollapsed("%s", Symbol.for("description"));
+</script>
+</body>
+</html>
diff --git a/cookie-store/cookie-store.idl b/cookie-store/cookie-store.idl
new file mode 100644
index 0000000..d4f6459
--- /dev/null
+++ b/cookie-store/cookie-store.idl
@@ -0,0 +1,56 @@
+// https://github.com/WICG/cookie-store/blob/gh-pages/explainer.md
+
+dictionary CookieListItem {
+ USVString name;
+ USVString value;
+};
+
+typedef sequence<CookieListItem> CookieList;
+
+[
+ Exposed=(ServiceWorker,Window)
+] interface CookieStore {
+ Promise<CookieList?> getAll(USVString name, optional CookieStoreGetOptions options);
+ Promise<CookieList?> getAll(optional CookieStoreGetOptions options);
+
+ Promise<CookieListItem?> get(USVString name, optional CookieStoreGetOptions options);
+ Promise<CookieListItem?> get(optional CookieStoreGetOptions options);
+
+ Promise<boolean> has(USVString name, optional CookieStoreGetOptions options);
+ Promise<boolean> has(optional CookieStoreGetOptions options);
+
+ Promise<void> set(USVString name, USVString value, optional CookieStoreSetOptions options);
+ Promise<void> set(CookieStoreSetOptions options);
+
+ Promise<void> delete(USVString name, optional CookieStoreSetOptions options);
+ Promise<void> delete(CookieStoreSetOptions options);
+};
+
+enum CookieMatchType {
+ "equals",
+ "startsWith"
+};
+
+dictionary CookieStoreGetOptions {
+ USVString name;
+ USVString url;
+ CookieMatchType matchType = "equals";
+};
+
+dictionary CookieStoreSetOptions {
+ USVString name;
+ USVString value;
+ DOMTimeStamp? expires = null;
+ USVString domain;
+ USVString path = "/";
+ boolean? secure;
+ boolean httpOnly = false;
+};
+
+partial interface Window {
+ [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
+};
+
+partial interface ServiceWorkerGlobalScope {
+ [Replaceable, SameObject] readonly attribute CookieStore cookieStore;
+};
diff --git a/cookie-store/idlharness.tentative.html b/cookie-store/idlharness.tentative.html
new file mode 100644
index 0000000..cf80246
--- /dev/null
+++ b/cookie-store/idlharness.tentative.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Async Cookies: IDL tests</title>
+<link rel="help" href="https://github.com/WICG/cookie-store"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const urls = ['/interfaces/html.idl', 'cookie-store.idl'];
+ const [html, cookie_store] = await Promise.all(
+ urls.map(url => fetch(url).then(response => response.text())));
+
+ const idl_array = new IdlArray();
+
+ // Dependencies of HTML
+ idl_array.add_untested_idls('interface Document {};');
+ idl_array.add_untested_idls('interface LinkStyle {};');
+ idl_array.add_untested_idls(html);
+
+ idl_array.add_untested_idls(
+ `[Global=ServiceWorker, Exposed=ServiceWorker]
+ interface ServiceWorkerGlobalScope {};`);
+
+ idl_array.add_idls(cookie_store);
+
+ idl_array.add_objects({
+ CookieStore: [self.cookieStore],
+ });
+ idl_array.test();
+}, 'Interface test');
+</script>
diff --git a/cookie-store/idlharness_serviceworker.js b/cookie-store/idlharness_serviceworker.js
new file mode 100644
index 0000000..35eccfd
--- /dev/null
+++ b/cookie-store/idlharness_serviceworker.js
@@ -0,0 +1,31 @@
+self.GLOBAL = {
+ isWindow: function() { return false; },
+ isWorker: function() { return true; },
+};
+importScripts('/resources/testharness.js',
+ '/resources/WebIDLParser.js',
+ '/resources/idlharness.js');
+
+promise_test(async t => {
+ const urls = ['cookie-store.idl'];
+ const [cookie_store] = await Promise.all(
+ urls.map(url => fetch(url).then(response => response.text())));
+
+ const idl_array = new IdlArray();
+
+ idl_array.add_untested_idls(
+ `[Global=ServiceWorker, Exposed=ServiceWorker]
+ interface ServiceWorkerGlobalScope {};`);
+ idl_array.add_untested_idls(
+ `[Global=Window, Exposed=Window]
+ interface Window {};`);
+
+ idl_array.add_idls(cookie_store);
+
+ idl_array.add_objects({
+ CookieStore: [self.cookieStore],
+ });
+ idl_array.test();
+}, 'Interface test');
+
+done();
diff --git a/cookie-store/idlharness_serviceworker.tentative.https.html b/cookie-store/idlharness_serviceworker.tentative.https.html
new file mode 100644
index 0000000..845a9fd
--- /dev/null
+++ b/cookie-store/idlharness_serviceworker.tentative.https.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Async Cookies: ServiceWorker IDL tests</title>
+<link rel="help" href="https://github.com/WICG/cookie-store">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+(async () => {
+ const scope = 'does/not/exist';
+
+ let registration = await navigator.serviceWorker.getRegistration(scope);
+ if (registration)
+ await registration.unregister();
+ registration = await navigator.serviceWorker.register(
+ 'idlharness_serviceworker.js', {scope});
+
+ fetch_tests_from_worker(registration.installing);
+})();
+</script>
diff --git a/css/CSS2/floats/intrinsic-size-float-and-line.html b/css/CSS2/floats/intrinsic-size-float-and-line.html
new file mode 100644
index 0000000..0603124
--- /dev/null
+++ b/css/CSS2/floats/intrinsic-size-float-and-line.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>Put float next to line in shrink-to-fit container</title>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#float-width" title="10.3.5 Floating, non-replaced elements">
+<link rel="match" href="../../reference/ref-filled-green-200px-square.html">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="float:left; min-width:150px; background:red;">
+ <div style="float:right; width:100px; height:200px; background:green;"></div>
+ <div style="vertical-align:top; display:inline-block; width:100px; height:200px; background:green;"></div>
+</div>
diff --git a/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html b/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html
new file mode 100644
index 0000000..471a4c7
--- /dev/null
+++ b/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>Collapse bottom margin from previous sibling through zero height block to next sibling</title>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins" title="8.3.1 Collapsing margins">
+<link rel="match" href="../../reference/ref-filled-green-200px-square.html">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="overflow:hidden; width:200px; height:400px; background:green;">
+ <div style="margin-bottom:200px;"></div>
+ <div style="height:0;"></div>
+ <div style="height:200px; margin-top:100px; background:white;"></div>
+ <div style="height:200px; background:red;"></div>
+</div>
diff --git a/css/CSS2/visudet/reference/content-height-005-ref.html b/css/CSS2/visudet/reference/content-height-005-ref.html
index 70a3ee0..b68f8a9 100644
--- a/css/CSS2/visudet/reference/content-height-005-ref.html
+++ b/css/CSS2/visudet/reference/content-height-005-ref.html
@@ -2,6 +2,7 @@
<meta charset="utf-8">
<title>CSS Test Reference file</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
div {
font-size: 50px;
diff --git a/css/css-align/content-distribution/place-content-shorthand-004.html b/css/css-align/content-distribution/place-content-shorthand-004.html
index 30f45b6..3f9bd88 100644
--- a/css/css-align/content-distribution/place-content-shorthand-004.html
+++ b/css/css-align/content-distribution/place-content-shorthand-004.html
@@ -48,6 +48,12 @@
}, "Verify 'auto' values are invalid");
test(function() {
+ checkInvalidValues("self-start")
+ checkInvalidValues("center self-end")
+ checkInvalidValues("self-end start")
+ }, "Verify self-position values are invalid");
+
+ test(function() {
checkInvalidValues("")
}, "Verify empty declaration is invalid");
</script>
diff --git a/css/css-align/default-alignment/parse-justify-items-002.html b/css/css-align/default-alignment/parse-justify-items-002.html
index 6ba2c7c..1806fa2 100644
--- a/css/css-align/default-alignment/parse-justify-items-002.html
+++ b/css/css-align/default-alignment/parse-justify-items-002.html
@@ -19,39 +19,39 @@
test(function() {
element = document.createElement("div");
document.body.appendChild(element);
- checkValues(element, "justifyItems", "justify-items", "", "legacy");
+ checkValues(element, "justifyItems", "justify-items", "", "normal");
}, "Test 'initial' value when nothing is specified");
test(function() {
container.style.display = "";
- checkInitialValues(element, "justifyItems", "justify-items", "center", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "center", "normal");
}, "Test justify-items: 'initial'");
test(function() {
container.style.display = "grid";
- checkInitialValues(element, "justifyItems", "justify-items", "safe start", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "safe start", "normal");
}, "Test grid items justify-items: 'initial'");
test(function() {
container.style.display = "flex";
- checkInitialValues(element, "justifyItems", "justify-items", "unsafe end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "unsafe end", "normal");
}, "Test flex items justify-items: 'initial'");
test(function() {
container.style.display = "";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "start", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "start", "normal");
}, "Test absolute positioned elements justify-items: 'initial'");
test(function() {
container.style.display = "grid";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "end", "normal");
}, "Test absolute positioned grid items justify-items: 'initial'");
test(function() {
container.style.display = "flex";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "end", "normal");
}, "Test absolute positioned flex items justify-items: 'initial'");
</script>
diff --git a/css/css-align/default-alignment/place-items-shorthand-004.html b/css/css-align/default-alignment/place-items-shorthand-004.html
index c5d9472..aa3ff30 100644
--- a/css/css-align/default-alignment/place-items-shorthand-004.html
+++ b/css/css-align/default-alignment/place-items-shorthand-004.html
@@ -37,7 +37,18 @@
checkInvalidValues("auto")
checkInvalidValues("auto right")
checkInvalidValues("auto auto")
- }, "Verify 'auto' value is invalid as first longhand value.");
+ checkInvalidValues("center auto")
+ }, "Verify 'auto' value is invalid.");
+
+ test(function() {
+ checkInvalidValues("legacy")
+ checkInvalidValues("legacy start")
+ checkInvalidValues("end legacy")
+ checkInvalidValues("legacy left")
+ checkInvalidValues("center legacy")
+ checkInvalidValues("start legacy center")
+ }, "Verify 'legacy' value is invalid.");
+
test(function() {
checkInvalidValues("")
diff --git a/css/css-backgrounds/background-331.html b/css/css-backgrounds/background-331.html
index 3d72ad4..1216234 100644
--- a/css/css-backgrounds/background-331.html
+++ b/css/css-backgrounds/background-331.html
@@ -57,7 +57,7 @@
test(function() {
assert_equals(cs.getPropertyValue("background-color"),
- "transparent", "background initial value for background-color");
+ "rgba(0, 0, 0, 0)", "background initial value for background-color");
}, "background_initial_color");
</script>
</body>
diff --git a/css/css-backgrounds/background-332.html b/css/css-backgrounds/background-332.html
index da11dc8..2621cb6 100644
--- a/css/css-backgrounds/background-332.html
+++ b/css/css-backgrounds/background-332.html
@@ -57,7 +57,7 @@
test(function() {
assert_equals(cs.getPropertyValue("background-color"),
- "gray", "background specified value for background-color");
+ "rgb(128, 128, 128)", "background specified value for background-color");
}, "background_specified_color");
</script>
</body>
diff --git a/css/css-backgrounds/background-333.html b/css/css-backgrounds/background-333.html
index 8331527..53dd150 100644
--- a/css/css-backgrounds/background-333.html
+++ b/css/css-backgrounds/background-333.html
@@ -57,7 +57,7 @@
test(function() {
assert_equals(cs.getPropertyValue("background-color"),
- "red", "background specified value for background-color");
+ "rgb(255, 0, 0)", "background specified value for background-color");
}, "background_specified_color_color");
</script>
</body>
diff --git a/css/css-backgrounds/box-shadow-syntax-001.xht b/css/css-backgrounds/box-shadow-syntax-001.xht
index 4e32c9f..4df5907 100644
--- a/css/css-backgrounds/box-shadow-syntax-001.xht
+++ b/css/css-backgrounds/box-shadow-syntax-001.xht
@@ -21,7 +21,7 @@
}
.inset {
color: green;
- height: 13px;
+ height: 12px;
margin: -1px 0 -4px -4px;
}
diff --git a/css/css-backgrounds/reference/box-shadow-syntax-001.xht b/css/css-backgrounds/reference/box-shadow-syntax-001.xht
index 697c21a..34be7bc 100644
--- a/css/css-backgrounds/reference/box-shadow-syntax-001.xht
+++ b/css/css-backgrounds/reference/box-shadow-syntax-001.xht
@@ -10,6 +10,7 @@
border: solid green 4px;
padding-top: 1px;
border-style: none none solid solid;
+ height: 7px;
}
</style>
</head>
diff --git a/css/css-color/color-function-parsing.html b/css/css-color/color-function-parsing.html
new file mode 100644
index 0000000..7f483bb
--- /dev/null
+++ b/css/css-color/color-function-parsing.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: color() parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#color-function">
+<meta name="assert" content="Tests basic parsing of the color function">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="test"></div>
+<script>
+ const div = document.querySelector("#test");
+ function testColorFunction(description, rule, expectedValue) {
+ test(function() {
+ div.style.color = "black";
+ div.style.color = rule;
+ assert_equals(getComputedStyle(div).color, expectedValue);
+ }, description);
+ }
+
+ testColorFunction("Basic sRGB white", "color(srgb 1 1 1)", "color(srgb 1 1 1)");
+ testColorFunction("White with lots of space", "color( srgb 1 1 1 )", "color(srgb 1 1 1)");
+ testColorFunction("sRGB color", "color(srgb 0.25 0.5 0.75)", "color(srgb 0.25 0.5 0.75)");
+ testColorFunction("Different case for sRGB", "color(SrGb 0.25 0.5 0.75)", "color(srgb 0.25 0.5 0.75)");
+ testColorFunction("sRGB color with unnecessary decimals", "color(srgb 1.00000 0.500000 0.20)", "color(srgb 1 0.5 0.2)");
+ testColorFunction("sRGB white with 0.5 alpha", "color(srgb 1 1 1 / 0.5)", "color(srgb 1 1 1 / 0.5)");
+ testColorFunction("sRGB white with 0 alpha", "color(srgb 1 1 1 / 0)", "color(srgb 1 1 1 / 0)");
+ testColorFunction("sRGB white with 50% alpha", "color(srgb 1 1 1 / 50%)", "color(srgb 1 1 1 / 0.5)");
+ testColorFunction("sRGB white with 0% alpha", "color(srgb 1 1 1 / 0%)", "color(srgb 1 1 1 / 0)");
+ testColorFunction("One missing component is 0", "color(srgb 1 1)", "color(srgb 1 1 0)");
+ testColorFunction("Two missing components are 0", "color(srgb 1)", "color(srgb 1 0 0)");
+ testColorFunction("All components missing", "color(srgb)", "color(srgb 0 0 0)");
+ testColorFunction("Display P3 color", "color(display-p3 0.6 0.7 0.8)", "color(display-p3 0.6 0.7 0.8)");
+ testColorFunction("Different case for Display P3", "color(dIspLaY-P3 0.6 0.7 0.8)", "color(display-p3 0.6 0.7 0.8)");
+
+ testColorFunction("Unknown color space should fallback", "color(unknown 1 2 3, red)", "color(unknown 1 2 3, red)");
+
+ testColorFunction("sRGB color with negative component should clamp to 0", "color(srgb -0.25 0.5 0.75)", "color(srgb 0 0.5 0.75)");
+ testColorFunction("sRGB color with component > 1 should clamp", "color(srgb 0.25 1.5 0.75)", "color(srgb 0.25 1 0.75)");
+ testColorFunction("Display P3 color with negative component should clamp to 0", "color(display-p3 0.5 -199 0.75)", "color(display-p3 0.5 0 0.75)");
+ testColorFunction("Display P3 color with component > 1 should clamp", "color(display-p3 184 1.00001 2347329746587)", "color(display-p3 1 1 1)");
+ testColorFunction("Alpha > 1 should clamp", "color(srgb 0.1 0.2 0.3 / 1.9)", "color(srgb 0.1 0.2 0.3)");
+ testColorFunction("Negative alpha should clamp", "color(srgb 1 1 1 / -0.2)", "color(srgb 1 1 1 / 0)");
+
+ // Invalid properties
+ testColorFunction("Empty", "color()", "rgb(0, 0, 0)");
+ testColorFunction("Bad color space", "color(banana 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad Display P3 color space", "color(displayp3 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("No color space", "color(1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Too many parameters", "color(srgb 1 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Way too many parameters", "color(srgb 1 1 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad parameters", "color(srgb 1 eggs 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad alpha", "color(srgb 1 1 1 / bacon)", "rgb(0, 0, 0)");
+ testColorFunction("Junk after alpha", "color(srgb 1 1 1 / 1 cucumber)", "rgb(0, 0, 0)");
+</script>
diff --git a/css/css-fonts/font-variation-settings-serialization-001.html b/css/css-fonts/font-variation-settings-serialization-001.html
new file mode 100644
index 0000000..65178c9
--- /dev/null
+++ b/css/css-fonts/font-variation-settings-serialization-001.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Test: font-feature-settings serialization</title>
+ <link rel="author" title="Greg Whitworth" href="mailto:gwhit@microsoft.com">
+ <link rel="help" href="http://www.w3.org/TR/css-fonts-4/#propdef-font-variation-settings">
+ <link rel="issue" href="https://github.com/w3c/csswg-drafts/issues/1959#issuecomment-360864254">
+ <meta name="desctiption" content="It was decided in issue 1959 that font-variation-settings is a map, therefor duplicates should be removed">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <div id="test1" style='font-variation-settings: "bldA" 1, "bldA" 2'></div>
+
+ <script>
+ const test1_canEqual = ['"bldA" 2', "'bldA' 2"];
+ test(function() {
+ assert_in_array(getComputedStyle(document.getElementById('test1')).fontVariationSettings, test1_canEqual);
+ }, "font-feature-settings should be serialized to not include duplicates");
+ </script>
+ </body>
+</html>
+
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
index 66417a4..127ea8d 100644
--- a/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
@@ -135,3 +135,217 @@
<div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
<div data-expected-width="25"></div>
</div>
+
+<h3>grid content writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-columns: auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 25px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 25px;">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="15" style="margin: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="padding: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="border: solid 5px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-columns: auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 25px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 25px;">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="15" style="margin: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="padding: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="border: solid 5px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
index d821e5c..636a40f 100644
--- a/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
@@ -32,7 +32,7 @@
<div id="log"></div>
-<h3>writing-mode: vertical-lr;</h3>
+<h3>item writing-mode: vertical-lr;</h3>
<pre>grid-template-rows: auto;</pre>
@@ -139,7 +139,7 @@
<div data-expected-height="25"></div>
</div>
-<h3>writing-mode: vertical-rl;</h3>
+<h3>item writing-mode: vertical-rl;</h3>
<pre>grid-template-rows: auto;</pre>
@@ -246,3 +246,216 @@
<div data-expected-height="25"></div>
</div>
+<h3>grid container writing-mode: vertical-lr; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 25px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 25px;">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="15" style="margin: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="padding: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="border: solid 5px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-rl; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 25px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 25px;">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="15" style="margin: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="padding: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="border: solid 5px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html
new file mode 100644
index 0000000..fb706bf
--- /dev/null
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html
@@ -0,0 +1,355 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Minimum size of grid items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#min-size-auto" title="6.5. Implied Minimum Size of Grid Items">
+<meta name="assert" content="Checks that automatic minimum size is clamped with different column sizes and spaning items.">
+<link rel="stylesheet" href="../support/grid.css">
+<style>
+.grid {
+ border: solid thick;
+ font: 10px/1 Ahem;
+ width: 50px;
+ height: 50px;
+ grid-template-rows: 25px 25px;
+}
+
+.grid > div {
+ grid-column: span 2;
+}
+
+.grid > div:nth-child(1) {
+ color: blue;
+ background: cyan;
+}
+
+.grid > div:nth-child(2) {
+ background: magenta;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid" style="grid-template-columns: auto auto;">
+ <div data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-columns: 0px 0px;">
+ <div data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-columns: 20px 20px;">
+ <div data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: auto auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 0px 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 20px 20px;">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: auto auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 0px 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 20px 20px;">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html
new file mode 100644
index 0000000..722426e
--- /dev/null
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html
@@ -0,0 +1,465 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Minimum size of grid items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#min-size-auto" title="6.5. Implied Minimum Size of Grid Items">
+<meta name="assert" content="Checks that automatic minimum size is clamped with different row sizes and spaning items.">
+<link rel="stylesheet" href="../support/grid.css">
+<style>
+.grid {
+ border: solid thick;
+ font: 10px/1 Ahem;
+ width: 50px;
+ height: 50px;
+ grid-template-columns: 25px 25px;
+ margin: 50px 0px;
+}
+
+.grid > div {
+ grid-row: span 2;
+}
+
+.grid > div:nth-child(1) {
+ color: blue;
+ background: cyan;
+}
+
+.grid > div:nth-child(2) {
+ background: magenta;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<h3>item writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid" style="grid-template-rows: auto auto;">
+ <div class="verticalLR" data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-rows: 0px 0px;">
+ <div class="verticalLR" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-rows: 20px 20px;">
+ <div class="verticalLR" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>item writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid" style="grid-template-rows: auto auto;">
+ <div class="verticalRL" data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-rows: 0px 0px;">
+ <div class="verticalRL" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-rows: 20px 20px;">
+ <div class="verticalRL" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-lr; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: auto auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 0px 0px;">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 20px 20px;">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-rl; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: auto auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 0px 0px;">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 20px 20px;">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
diff --git a/css/css-layout-api/box-tree-registered-ref.html b/css/css-layout-api/box-tree-registered-ref.html
new file mode 100644
index 0000000..0ba9862
--- /dev/null
+++ b/css/css-layout-api/box-tree-registered-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+.container {
+ margin: 20px 0;
+ border: solid 2px;
+ width: 100px;
+}
+
+.pink {
+ background: hotpink;
+}
+</style>
+
+<div class="container">
+ <div class="pink" style="width: 50px; height: 100px;"></div>
+</div>
+
+<div class="container">
+ <div class="pink" style="width: 100px; height: 100px;"></div>
+</div>
diff --git a/css/css-layout-api/box-tree-registered.https.html b/css/css-layout-api/box-tree-registered.https.html
new file mode 100644
index 0000000..eb3fb67
--- /dev/null
+++ b/css/css-layout-api/box-tree-registered.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-api-box-tree">
+<link rel="match" href="box-tree-registered-ref.html">
+<meta name="assert" content="This test checks that a registered layout() has children which are blockified and new formatting contexts." />
+<style>
+@supports (display: layout(registered)) {
+ .test {
+ display: layout(registered);
+ }
+}
+
+.container {
+ margin: 20px 0;
+ border: solid 2px;
+ width: 100px;
+}
+
+.float {
+ float: left;
+ width: 50%;
+ height: 50px;
+}
+
+.pink {
+ background: hotpink;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/worklet-reftest.js"></script>
+
+<div class="container">
+ <!-- This tests that the "layout()" grandchildren floats within the don't interact with each other. -->
+ <div class="test">
+ <div class="inflow">
+ <div class="float pink"></div>
+ </div>
+ <div class="inflow">
+ <div class="float pink"></div>
+ </div>
+ </div>
+</div>
+
+<div class="container">
+ <!-- This tests that the "layout()" children margins interact as if they are new formatting contexts. -->
+ <div class="test">
+ <div class="inflow pink">
+ <div style="margin-bottom: 50px;"></div>
+ </div>
+ <div class="inflow pink">
+ <div style="margin-top: 50px;"></div>
+ </div>
+ </div>
+</div>
+
+<script id="code" type="text/worklet">
+registerLayout('registered', class {
+ *intrinsicSizes() {}
+ *layout() {}
+});
+</script>
+
+<script>
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, document.getElementById('code').textContent);
+</script>
+</html>
diff --git a/css/css-layout-api/box-tree-unregistered-ref.html b/css/css-layout-api/box-tree-unregistered-ref.html
new file mode 100644
index 0000000..fc43ad2
--- /dev/null
+++ b/css/css-layout-api/box-tree-unregistered-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<style>
+.container {
+ margin: 20px 0;
+ border: solid 2px;
+ width: 100px;
+}
+
+.inflow {
+ height: 40px;
+}
+</style>
+
+<div class="container">
+ <div class="inflow"></div>
+ <div class="inflow" style="background: hotpink"></div>
+ <div class="inflow"></div>
+</div>
+
+<div class="container">
+ <div class="inflow"></div>
+ <div class="inflow" style="background: hotpink"></div>
+ <div class="inflow"></div>
+</div>
+
+<div class="container">
+ <div class="inflow" style="background: hotpink"></div>
+ <div class="inflow" style="background: green"></div>
+</div>
diff --git a/css/css-layout-api/box-tree-unregistered.https.html b/css/css-layout-api/box-tree-unregistered.https.html
new file mode 100644
index 0000000..48d7aa7
--- /dev/null
+++ b/css/css-layout-api/box-tree-unregistered.https.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-api-box-tree">
+<link rel="match" href="box-tree-unregistered-ref.html">
+<meta name="assert" content="This test checks that an unregistered layout() works the same as a normal flow-root." />
+<style>
+@supports (display: layout(unregistered)) {
+ .test {
+ display: layout(unregistered);
+ }
+}
+
+.container {
+ margin: 20px 0;
+ border: solid 2px;
+ width: 100px;
+}
+
+.float {
+ float: left;
+ width: 100%;
+ height: 40px;
+ background: hotpink;
+}
+
+.inflow {
+ height: 40px;
+ background: hotpink;
+}
+</style>
+
+<div class="container">
+ <!-- This tests that the "layout()" margins don't collapse with its children. -->
+ <div class="test" style="margin: 20px 0">
+ <div class="inflow" style="margin: 20px 0"></div>
+ </div>
+</div>
+
+<div class="container">
+ <!-- This tests that the "layout()" grows to fit child floats. -->
+ <div class="test">
+ <div class="float" style="margin: 40px 0"></div>
+ </div>
+</div>
+
+<div class="container">
+ <!-- This tests that a float does not intrude into "layout()" box. -->
+ <div class="float"></div>
+ <div class="test" style="width: 100%; height: 40px; background: green;"></div>
+</div>
diff --git a/css/css-paint-api/background-image-alpha.https.html b/css/css-paint-api/background-image-alpha.https.html
index de8a0d7..53d869d 100644
--- a/css/css-paint-api/background-image-alpha.https.html
+++ b/css/css-paint-api/background-image-alpha.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
<div id="canvas-opaque" class="container"></div>
@@ -49,7 +49,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/background-image-multiple.https.html b/css/css-paint-api/background-image-multiple.https.html
index 7fb5751..79ff883 100644
--- a/css/css-paint-api/background-image-multiple.https.html
+++ b/css/css-paint-api/background-image-multiple.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -27,7 +27,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/background-image-tiled.https.html b/css/css-paint-api/background-image-tiled.https.html
index 0497acf..8498c82 100644
--- a/css/css-paint-api/background-image-tiled.https.html
+++ b/css/css-paint-api/background-image-tiled.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="one"></div>
<div id="two"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-001.https.html b/css/css-paint-api/geometry-background-image-001.https.html
index d1207e0..601d418 100644
--- a/css/css-paint-api/geometry-background-image-001.https.html
+++ b/css/css-paint-api/geometry-background-image-001.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -28,7 +28,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-002.https.html b/css/css-paint-api/geometry-background-image-002.https.html
index 47455ba..1d57073 100644
--- a/css/css-paint-api/geometry-background-image-002.https.html
+++ b/css/css-paint-api/geometry-background-image-002.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -28,7 +28,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-001.https.html b/css/css-paint-api/geometry-background-image-tiled-001.https.html
index 5cf8eb7..8e28b54 100644
--- a/css/css-paint-api/geometry-background-image-tiled-001.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-001.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-002.https.html b/css/css-paint-api/geometry-background-image-tiled-002.https.html
index 491abd1..9248e38 100644
--- a/css/css-paint-api/geometry-background-image-tiled-002.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-002.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-003.https.html b/css/css-paint-api/geometry-background-image-tiled-003.https.html
index 9a29c30..5b6b6c7 100644
--- a/css/css-paint-api/geometry-background-image-tiled-003.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-003.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-001.https.html b/css/css-paint-api/geometry-border-image-001.https.html
index 54249d3..3fb4643 100644
--- a/css/css-paint-api/geometry-border-image-001.https.html
+++ b/css/css-paint-api/geometry-border-image-001.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderWidth = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-002.https.html b/css/css-paint-api/geometry-border-image-002.https.html
index 4759886..26e24bb 100644
--- a/css/css-paint-api/geometry-border-image-002.https.html
+++ b/css/css-paint-api/geometry-border-image-002.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderImageOutset = '20px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-003.https.html b/css/css-paint-api/geometry-border-image-003.https.html
index 1ce6ac9..a26f2b7 100644
--- a/css/css-paint-api/geometry-border-image-003.https.html
+++ b/css/css-paint-api/geometry-border-image-003.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderImageOutset = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-004.https.html b/css/css-paint-api/geometry-border-image-004.https.html
index b15b66d..60db7ff 100644
--- a/css/css-paint-api/geometry-border-image-004.https.html
+++ b/css/css-paint-api/geometry-border-image-004.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -35,7 +35,7 @@
<script>
document.getElementById('canvas-geometry').style.borderWidth = '10px';
document.getElementById('canvas-geometry').style.borderImageOutset = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-with-float-size.https.html b/css/css-paint-api/geometry-with-float-size.https.html
index 6cd3eca..65477e4 100644
--- a/css/css-paint-api/geometry-with-float-size.https.html
+++ b/css/css-paint-api/geometry-with-float-size.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/hidpi/device-pixel-ratio.https.html b/css/css-paint-api/hidpi/device-pixel-ratio.https.html
index fb62c23..46a9aa2 100644
--- a/css/css-paint-api/hidpi/device-pixel-ratio.https.html
+++ b/css/css-paint-api/hidpi/device-pixel-ratio.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<p>This test ensures that the PaintWorkletGlobalScope.devicePixelRatio returns
the correct value, which should be identical as window.devicePixelRatio. To
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/invalid-image-constructor-error.https.html b/css/css-paint-api/invalid-image-constructor-error.https.html
index 022b915..439ff8b 100644
--- a/css/css-paint-api/invalid-image-constructor-error.https.html
+++ b/css/css-paint-api/invalid-image-constructor-error.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
diff --git a/css/css-paint-api/invalid-image-paint-error.https.html b/css/css-paint-api/invalid-image-paint-error.https.html
index c185d89..2806ad9 100644
--- a/css/css-paint-api/invalid-image-paint-error.https.html
+++ b/css/css-paint-api/invalid-image-paint-error.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/invalid-image-pending-script.https.html b/css/css-paint-api/invalid-image-pending-script.https.html
index e19fa41..4347a00 100644
--- a/css/css-paint-api/invalid-image-pending-script.https.html
+++ b/css/css-paint-api/invalid-image-pending-script.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -26,7 +26,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/overdraw.https.html b/css/css-paint-api/overdraw.https.html
index f95eeb5..5be26f7 100644
--- a/css/css-paint-api/overdraw.https.html
+++ b/css/css-paint-api/overdraw.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -24,7 +24,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint-arguments.https.html b/css/css-paint-api/paint-arguments.https.html
index f4ae452..abfb2a6 100644
--- a/css/css-paint-api/paint-arguments.https.html
+++ b/css/css-paint-api/paint-arguments.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint-function-arguments.https.html b/css/css-paint-api/paint-function-arguments.https.html
index d49f3f2..d87b0b8 100644
--- a/css/css-paint-api/paint-function-arguments.https.html
+++ b/css/css-paint-api/paint-function-arguments.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-composite.https.html b/css/css-paint-api/paint2d-composite.https.html
index ba88f92..80e94e4 100644
--- a/css/css-paint-api/paint2d-composite.https.html
+++ b/css/css-paint-api/paint2d-composite.https.html
@@ -19,7 +19,7 @@
#xor { background-image: paint(xor); }
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="source-over"></div>
<div id="source-in"></div>
@@ -67,7 +67,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-filter.https.html b/css/css-paint-api/paint2d-filter.https.html
index 560b1b2..d0c4539 100644
--- a/css/css-paint-api/paint2d-filter.https.html
+++ b/css/css-paint-api/paint2d-filter.https.html
@@ -24,7 +24,7 @@
#filter-url { background-image: paint(filter-url); }
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="filter-none"></div>
<div id="filter-blur-10px"></div>
@@ -100,7 +100,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-gradient.https.html b/css/css-paint-api/paint2d-gradient.https.html
index b936430..892a791 100644
--- a/css/css-paint-api/paint2d-gradient.https.html
+++ b/css/css-paint-api/paint2d-gradient.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -34,7 +34,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-image.https.html b/css/css-paint-api/paint2d-image.https.html
index ba89430..6fce4b6 100644
--- a/css/css-paint-api/paint2d-image.https.html
+++ b/css/css-paint-api/paint2d-image.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<div id="output"></div>
<script id="code" type="text/worklet">
@@ -25,6 +25,6 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</html>
diff --git a/css/css-paint-api/paint2d-paths.https.html b/css/css-paint-api/paint2d-paths.https.html
index 55a01b4..091f548 100644
--- a/css/css-paint-api/paint2d-paths.https.html
+++ b/css/css-paint-api/paint2d-paths.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-rects.https.html b/css/css-paint-api/paint2d-rects.https.html
index 24247da..2494272 100644
--- a/css/css-paint-api/paint2d-rects.https.html
+++ b/css/css-paint-api/paint2d-rects.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-shadows.https.html b/css/css-paint-api/paint2d-shadows.https.html
index ad0a1aa..98dcfbc 100644
--- a/css/css-paint-api/paint2d-shadows.https.html
+++ b/css/css-paint-api/paint2d-shadows.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-transform.https.html b/css/css-paint-api/paint2d-transform.https.html
index f5b6aa8..c91b500 100644
--- a/css/css-paint-api/paint2d-transform.https.html
+++ b/css/css-paint-api/paint2d-transform.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -32,7 +32,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-001.https.html b/css/css-paint-api/parse-input-arguments-001.https.html
index 931a55a..4356ce6 100644
--- a/css/css-paint-api/parse-input-arguments-001.https.html
+++ b/css/css-paint-api/parse-input-arguments-001.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-002.https.html b/css/css-paint-api/parse-input-arguments-002.https.html
index c07c0c0..6fc16c7 100644
--- a/css/css-paint-api/parse-input-arguments-002.https.html
+++ b/css/css-paint-api/parse-input-arguments-002.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-003.https.html b/css/css-paint-api/parse-input-arguments-003.https.html
index ff388de..44fd850 100644
--- a/css/css-paint-api/parse-input-arguments-003.https.html
+++ b/css/css-paint-api/parse-input-arguments-003.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-004.https.html b/css/css-paint-api/parse-input-arguments-004.https.html
index 8d5b8d7..138a790 100644
--- a/css/css-paint-api/parse-input-arguments-004.https.html
+++ b/css/css-paint-api/parse-input-arguments-004.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-005.https.html b/css/css-paint-api/parse-input-arguments-005.https.html
index b726c22..c12e00c 100644
--- a/css/css-paint-api/parse-input-arguments-005.https.html
+++ b/css/css-paint-api/parse-input-arguments-005.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -39,7 +39,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-006.https.html b/css/css-paint-api/parse-input-arguments-006.https.html
index 7d8504c..664b7a8 100644
--- a/css/css-paint-api/parse-input-arguments-006.https.html
+++ b/css/css-paint-api/parse-input-arguments-006.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-007.https.html b/css/css-paint-api/parse-input-arguments-007.https.html
index a59ac93..53f245b 100644
--- a/css/css-paint-api/parse-input-arguments-007.https.html
+++ b/css/css-paint-api/parse-input-arguments-007.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-008.https.html b/css/css-paint-api/parse-input-arguments-008.https.html
index 2d6df23..1914e3c 100644
--- a/css/css-paint-api/parse-input-arguments-008.https.html
+++ b/css/css-paint-api/parse-input-arguments-008.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-009.https.html b/css/css-paint-api/parse-input-arguments-009.https.html
index 03c7c69..21d004d 100644
--- a/css/css-paint-api/parse-input-arguments-009.https.html
+++ b/css/css-paint-api/parse-input-arguments-009.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-010.https.html b/css/css-paint-api/parse-input-arguments-010.https.html
index 0bd6768..d923479 100644
--- a/css/css-paint-api/parse-input-arguments-010.https.html
+++ b/css/css-paint-api/parse-input-arguments-010.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-011.https.html b/css/css-paint-api/parse-input-arguments-011.https.html
index e772a50..6cea438 100644
--- a/css/css-paint-api/parse-input-arguments-011.https.html
+++ b/css/css-paint-api/parse-input-arguments-011.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-012.https.html b/css/css-paint-api/parse-input-arguments-012.https.html
index 422b45f..938150a 100644
--- a/css/css-paint-api/parse-input-arguments-012.https.html
+++ b/css/css-paint-api/parse-input-arguments-012.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-013.https.html b/css/css-paint-api/parse-input-arguments-013.https.html
index cd62879..37e3eb435 100644
--- a/css/css-paint-api/parse-input-arguments-013.https.html
+++ b/css/css-paint-api/parse-input-arguments-013.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-014.https.html b/css/css-paint-api/parse-input-arguments-014.https.html
index 39aee6a..690e488 100644
--- a/css/css-paint-api/parse-input-arguments-014.https.html
+++ b/css/css-paint-api/parse-input-arguments-014.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-015.https.html b/css/css-paint-api/parse-input-arguments-015.https.html
index c2e1844..fba7671 100644
--- a/css/css-paint-api/parse-input-arguments-015.https.html
+++ b/css/css-paint-api/parse-input-arguments-015.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-016.https.html b/css/css-paint-api/parse-input-arguments-016.https.html
index 4bea1b4..8c9d05d 100644
--- a/css/css-paint-api/parse-input-arguments-016.https.html
+++ b/css/css-paint-api/parse-input-arguments-016.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-017.https.html b/css/css-paint-api/parse-input-arguments-017.https.html
index 38f9f43..0d14fe74 100644
--- a/css/css-paint-api/parse-input-arguments-017.https.html
+++ b/css/css-paint-api/parse-input-arguments-017.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-018.https.html b/css/css-paint-api/parse-input-arguments-018.https.html
index 9d03a8d..541332a 100644
--- a/css/css-paint-api/parse-input-arguments-018.https.html
+++ b/css/css-paint-api/parse-input-arguments-018.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<p>This test result should show a rect with black border, where the rect is
filled with green on the lower right corner. The registerPaint('failureIndicator')
@@ -63,7 +63,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-019.https.html b/css/css-paint-api/parse-input-arguments-019.https.html
index 76627fb..707a0c6 100644
--- a/css/css-paint-api/parse-input-arguments-019.https.html
+++ b/css/css-paint-api/parse-input-arguments-019.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-020.https.html b/css/css-paint-api/parse-input-arguments-020.https.html
index b582555..fe8dbad 100644
--- a/css/css-paint-api/parse-input-arguments-020.https.html
+++ b/css/css-paint-api/parse-input-arguments-020.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-021.https.html b/css/css-paint-api/parse-input-arguments-021.https.html
index 666d4c4..0c3a596 100644
--- a/css/css-paint-api/parse-input-arguments-021.https.html
+++ b/css/css-paint-api/parse-input-arguments-021.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-022.https.html b/css/css-paint-api/parse-input-arguments-022.https.html
index 3c5d9f9..50aaa6b 100644
--- a/css/css-paint-api/parse-input-arguments-022.https.html
+++ b/css/css-paint-api/parse-input-arguments-022.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/registered-properties-in-custom-paint.https.html b/css/css-paint-api/registered-properties-in-custom-paint.https.html
index c446347..00b0368 100644
--- a/css/css-paint-api/registered-properties-in-custom-paint.https.html
+++ b/css/css-paint-api/registered-properties-in-custom-paint.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -56,7 +56,7 @@
CSS.registerProperty({name: '--length', syntax: '<length>', initialValue: '0px'});
CSS.registerProperty({name: '--length-initial', syntax: '<length>', initialValue: '20px'});
CSS.registerProperty({name: '--number', syntax: '<number>', initialValue: '0'});
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-background-image.https.html b/css/css-paint-api/style-background-image.https.html
index 7853607..6eeaf3c 100644
--- a/css/css-paint-api/style-background-image.https.html
+++ b/css/css-paint-api/style-background-image.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -56,7 +56,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-before-pseudo.https.html b/css/css-paint-api/style-before-pseudo.https.html
index 5249f58..bf3f69f 100644
--- a/css/css-paint-api/style-before-pseudo.https.html
+++ b/css/css-paint-api/style-before-pseudo.https.html
@@ -18,7 +18,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body style="font: 10px/1 Ahem;">
<div></div>
@@ -57,7 +57,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-first-letter-pseudo.https.html b/css/css-paint-api/style-first-letter-pseudo.https.html
index 3cdffb4..b8a22ce 100644
--- a/css/css-paint-api/style-first-letter-pseudo.https.html
+++ b/css/css-paint-api/style-first-letter-pseudo.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body style="font: 10px/1 Ahem;">
<div>ppp</div>
@@ -51,7 +51,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/valid-image-after-load.https.html b/css/css-paint-api/valid-image-after-load.https.html
index 73557d2..44612f9 100644
--- a/css/css-paint-api/valid-image-after-load.https.html
+++ b/css/css-paint-api/valid-image-after-load.https.html
@@ -9,7 +9,6 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
<body>
<div id="output"></div>
diff --git a/css/css-paint-api/valid-image-before-load.https.html b/css/css-paint-api/valid-image-before-load.https.html
index 483d16c..7738d9d 100644
--- a/css/css-paint-api/valid-image-before-load.https.html
+++ b/css/css-paint-api/valid-image-before-load.https.html
@@ -9,7 +9,6 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
<body>
<div id="output"></div>
diff --git a/css/css-pseudo/first-letter-property-whitelist.html b/css/css-pseudo/first-letter-property-whitelist.html
new file mode 100644
index 0000000..073e554
--- /dev/null
+++ b/css/css-pseudo/first-letter-property-whitelist.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<title>CSS Test: Properties allowed on ::first-letter pseudo elements</title>
+<link rel="author" title="Chris Nardi" href="mailto:cnardi@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-styling">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#target::first-letter {}
+#target { visibility: hidden; }
+</style>
+<div id="target">text</div>
+<script>
+'use strict';
+var style;
+const target = document.querySelector("#target");
+var defaultComputedStyle = getComputedStyle(target);
+
+test(function() {
+ var styleRule = document.styleSheets[0].cssRules[0];
+ assert_equals(styleRule.selectorText, '#target::first-letter', 'make sure we have the correct style rule');
+ style = styleRule.style;
+}, 'pre test setup');
+
+var validProperties = {
+ backgroundAttachment: 'fixed',
+ backgroundBlendMode: 'hue',
+ backgroundClip: 'padding-box',
+ backgroundColor: 'rgb(10, 20, 30)',
+ backgroundImage: 'linear-gradient(black, white)',
+ backgroundOrigin: 'border-box',
+ backgroundPosition: 'left 10px top 20px',
+ backgroundRepeat: 'no-repeat',
+ backgroundSize: '10px 20px',
+ border: '40px dotted rgb(10, 20, 30)',
+ borderImage: 'linear-gradient(black, white) 10% / 20 / 30px repeat',
+ borderRadius: '10px 20px',
+ boxShadow: 'rgb(10, 20, 30) 10px 20px 30px 40px inset',
+ color: 'rgba(10, 20, 30, 0.4)',
+ float: 'right',
+ font: 'italic small-caps 900 normal 10px / 20px sans-serif',
+ fontFeatureSettings: '"vert" 2',
+ fontSizeAdjust: '0.5',
+ fontKerning: 'none',
+ fontVariationSettings: '"XHGT" 0.7',
+ letterSpacing: '12px',
+ margin: '10px 20px 30px 40px',
+ padding: '10px 20px 30px 40px',
+ opacity: '0.5',
+ textDecoration: 'overline wavy rgb(10, 20, 30)',
+ textJustify: 'inter-word',
+ textShadow: 'rgb(10, 20, 30) 10px 20px 30px',
+ textTransform: 'capitalize',
+ textUnderlinePosition: 'under',
+ verticalAlign: '12%',
+ wordSpacing: '12px'
+};
+
+var invalidProperties = {
+ transition: 'transform 1s',
+ transform: 'rotate(45deg)',
+ wordBreak: 'break-all'
+};
+
+function testFirstLetterProperty(property, rule, expected, reason) {
+ test(function() {
+ style[property] = "";
+ style[property] = rule;
+ assert_equals(getComputedStyle(target, '::first-letter')[property], expected);
+ style[property] = "";
+ }, reason);
+}
+
+for (var property in validProperties) {
+ testFirstLetterProperty(property, validProperties[property], validProperties[property],
+ "Whitelisted property " + property + " should be applied to first-letter pseudo elements.");
+}
+
+for (var property in invalidProperties) {
+ testFirstLetterProperty(property, invalidProperties[property], defaultComputedStyle[property],
+ "Non-whitelisted property " + property + " should not be applied to first-letter pseudo elements.");
+}
+</script>
diff --git a/css/css-scoping/slotted-link.html b/css/css-scoping/slotted-link.html
new file mode 100644
index 0000000..c06c961
--- /dev/null
+++ b/css/css-scoping/slotted-link.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Scoping: ::slotted :link</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#slotted-pseudo">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="host"><a id="a" href="#notvisited">This link should be green.</a></div>
+<script>
+ let root = host.attachShadow({mode:"open"});
+ root.innerHTML = `
+ <style>
+ ::slotted(:link) { color:green }
+ ::slotted(:visited) { color:red }
+ </style>
+ <slot></slot>`;
+
+ test(() => {
+ assert_equals(getComputedStyle(a).color, "rgb(0, 128, 0)", "Unvisited link should be green.");
+ }, "Check that we match :link and not :visited for slotted anchor.");
+</script>
diff --git a/css/css-tables/internal-containing-block-001.html b/css/css-tables/internal-containing-block-001.html
new file mode 100644
index 0000000..a874548
--- /dev/null
+++ b/css/css-tables/internal-containing-block-001.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Grogan" href="dgrogan@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-tables-3/#abspos-boxes-in-table-internal">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#valdef-position-absolute">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="bookmark" href="https://bugs.chromium.org/p/chromium/issues/detail?id=798164" />
+<meta name="flags" content="" />
+<meta name="assert" content="A table-row with position:relative establishes a
+containing block for a position:absolute descendent of a table-cell, and the
+descendent is positioned correctly." />
+<title>
+relpos table-row establishes containing block for abspos
+</title>
+
+<style>
+tr {
+ position: relative;
+}
+
+div.abspos {
+ position: absolute;
+ height: 50px;
+ width: 100px;
+ background: green;
+}
+
+div.static {
+ height: 50px;
+ width: 100px;
+ background:red;
+}
+
+td, tr {
+ margin:0px;
+ padding:0px;
+}
+
+table {
+ border-collapse:collapse;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.
+</p>
+
+<table>
+ <tr>
+ <td>
+ <div class="abspos"></div>
+ <div class="static"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div class="abspos"></div>
+ <div class="static"></div>
+ </td>
+ </tr>
+</table>
diff --git a/css/css-transforms/animation/scale-interpolation.html b/css/css-transforms/animation/scale-interpolation.html
index da25d3a..942b80a 100644
--- a/css/css-transforms/animation/scale-interpolation.html
+++ b/css/css-transforms/animation/scale-interpolation.html
@@ -28,13 +28,13 @@
test_interpolation({
property: 'scale',
from: '26 17 9',
- to: '2',
+ to: '2 1',
}, [
{at: -1, expect: '50 33 17'},
{at: 0, expect: '26 17 9'},
{at: 0.125, expect: '23 15 8'},
{at: 0.875, expect: '5 3 2'},
- {at: 1, expect: '2'},
+ {at: 1, expect: '2 1'},
{at: 2, expect: '-22 -15 -7'}
]);
diff --git a/css/css-transforms/css-transform-property-existence.html b/css/css-transforms/css-transform-property-existence.html
index 75e1a1b..5885db2 100644
--- a/css/css-transforms/css-transform-property-existence.html
+++ b/css/css-transforms/css-transform-property-existence.html
@@ -14,7 +14,7 @@
<div id="log"></div>
<script>
test(function() {
- assert_not_equals(document.getElementById("test").style.transfor, undefined, "expect transform is not undefined");
+ assert_not_equals(document.getElementById("test").style.transform, undefined, "expect transform is not undefined");
}, "Check the existence of transform.");
test(function() {
diff --git a/css/css-transforms/individual-transform/individual-transform-1-ref.html b/css/css-transforms/individual-transform/individual-transform-1-ref.html
index 8a568d2..9271c77 100644
--- a/css/css-transforms/individual-transform/individual-transform-1-ref.html
+++ b/css/css-transforms/individual-transform/individual-transform-1-ref.html
@@ -24,7 +24,7 @@
left: 100px;
width: 50px;
height: 100px;
- transform: scaleX(2);
+ transform: scale(2, 2);
}
.translate_1 {
left: 150px;
diff --git a/css/css-transforms/parsing/rotate-parsing-invalid.html b/css/css-transforms/parsing/rotate-parsing-invalid.html
index 2597a42..8326db3 100644
--- a/css/css-transforms/parsing/rotate-parsing-invalid.html
+++ b/css/css-transforms/parsing/rotate-parsing-invalid.html
@@ -17,6 +17,12 @@
test_invalid_value("rotate", "100 400deg");
test_invalid_value("rotate", "100 200 400deg");
test_invalid_value("rotate", "100 200 300 500 400deg");
+
+test_invalid_value("rotate", "x y 45deg");
+test_invalid_value("rotate", "45deg x y");
+test_invalid_value("rotate", "z");
+test_invalid_value("rotate", "1 2");
+test_invalid_value("rotate", "1 2 3");
</script>
</body>
</html>
diff --git a/css/css-transforms/parsing/rotate-parsing-valid.html b/css/css-transforms/parsing/rotate-parsing-valid.html
index a33f0fd..b2e5749 100644
--- a/css/css-transforms/parsing/rotate-parsing-valid.html
+++ b/css/css-transforms/parsing/rotate-parsing-valid.html
@@ -17,6 +17,16 @@
test_valid_value("rotate", "0deg");
test_valid_value("rotate", "100 200 300 400grad");
+test_valid_value("rotate", "400grad 100 200 300", "100 200 300 400grad");
+
+test_valid_value("rotate", "x 400grad", "1 0 0 400grad");
+test_valid_value("rotate", "400grad x", "1 0 0 400grad");
+
+test_valid_value("rotate", "y 400grad", "0 1 0 400grad");
+test_valid_value("rotate", "400grad y", "0 1 0 400grad");
+
+test_valid_value("rotate", "z 400grad", "0 0 1 400grad");
+test_valid_value("rotate", "400grad z", "0 0 1 400grad");
</script>
</body>
</html>
diff --git a/css/css-transforms/transforms-support-calc.html b/css/css-transforms/transforms-support-calc.html
index 19bacd9..71a046f 100644
--- a/css/css-transforms/transforms-support-calc.html
+++ b/css/css-transforms/transforms-support-calc.html
@@ -31,7 +31,7 @@
test(function(){
target.style = 'translate: calc(30px + 20%) calc(-200px + 100%);';
- assert_equals(getComputedStyle(target).translate, '90px 0px');
+ assert_equals(getComputedStyle(target).translate, 'calc(30px + 20%) calc(-200px + 100%)');
}, 'translate supports calc');
test(function(){
diff --git a/css/css-transforms/translate-getComputedStyle.html b/css/css-transforms/translate-getComputedStyle.html
new file mode 100644
index 0000000..1e6759d
--- /dev/null
+++ b/css/css-transforms/translate-getComputedStyle.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Transform Module Level 2: translate getComputedStyle</title>
+ <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+ <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-translate">
+ <meta name="assert" content="translate computed style does not resolve percentages.">
+ <style type="text/css">
+ #container {
+ transform-style: preserve-3d;;
+ }
+ #first {
+ font-size: 10px;
+ translate: 10px 2em;
+ }
+ #second {
+ translate: 30% 40% 50px;
+ }
+ #third {
+ font-size: 10px;
+ width: 98px;
+ height: 76px;
+ translate: calc(7em + 80%) -9em;
+ }
+ </style>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="container">
+ <div id="first"></div>
+ <div id="second"></div>
+ <div id="third"></div>
+ </div>
+ <script>
+ 'use strict';
+ function getTranslateFor(id) {
+ return window.getComputedStyle(document.getElementById(id)).getPropertyValue("translate");
+ }
+
+ test(function() {
+ assert_equals(getTranslateFor("first"), "10px 20px");
+ assert_equals(getTranslateFor("second"), "30% 40% 50px");
+ assert_equals(getTranslateFor("third"), "calc(70px + 80%) -90px");
+ }, "computed style for translate");
+ </script>
+</body>
+</html>
diff --git a/css/css-typed-om/resources/testhelper.js b/css/css-typed-om/resources/testhelper.js
index f7c7e03..91af64c 100644
--- a/css/css-typed-om/resources/testhelper.js
+++ b/css/css-typed-om/resources/testhelper.js
@@ -54,6 +54,12 @@
assert_style_value_equals(a.ax, b.ax);
assert_style_value_equals(a.ay, b.ay);
break;
+ case 'CSSSkewX':
+ assert_style_value_equals(a.ax, b.ax);
+ break;
+ case 'CSSSkewY':
+ assert_style_value_equals(a.ay, b.ay);
+ break;
case 'CSSPerspective':
assert_style_value_equals(a.length, b.length);
break;
diff --git a/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html b/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
index 3311380..5e58bea 100644
--- a/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
+++ b/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
@@ -29,22 +29,22 @@
{
value: 'var(--A, 1em)',
expectedResult: [
- new CSSVariableReferenceValue('--A', new CSSUnparsedValue(' 1em')),
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' 1em'])),
]
},
{
value: 'var(--A, var(--B))',
expectedResult: [
- new CSSVariableReferenceValue('--A', new CSSUnparsedValue(' ', new CSSVariableReferenceValue('--B'))),
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--B')])),
]
},
{
value: 'calc(42px + var(--foo, 15em) + var(--bar, var(--far) + 15px))',
expectedResult: [
'calc(42px + ',
- new CSSVariableReferenceValue('--foo', new CSSUnparsedValue(' 15em')),
+ new CSSVariableReferenceValue('--foo', new CSSUnparsedValue([' 15em'])),
' + ',
- new CSSVariableReferenceValue('--bar', new CSSUnparsedValue(' ', new CSSVariableReferenceValue('--far'), ' + 15px')),
+ new CSSVariableReferenceValue('--bar', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--far'), ' + 15px'])),
')',
]
},
@@ -52,11 +52,11 @@
for (const {value, expectedResult} of gTestCases) {
test(t => {
- assert_string_normalizes_to(t, 'color', value, new CSSUnparsedValue(...expectedResult));
+ assert_string_normalizes_to(t, 'color', value, new CSSUnparsedValue(expectedResult));
}, 'Normalizing "' + value + '" on a CSS property returns correct CSSUnparsedValue');
test(t => {
- assert_string_normalizes_to(t, '--X', value, new CSSUnparsedValue(...expectedResult));
+ assert_string_normalizes_to(t, '--X', value, new CSSUnparsedValue(expectedResult));
}, 'Normalizing "' + value + '" on a custom property returns correct CSSUnparsedValue');
}
diff --git a/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html b/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
index 25b980b..9157ae8 100644
--- a/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
+++ b/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
@@ -124,18 +124,23 @@
desc: 'skew() with only X'
},
{
+ cssText: 'skew(90deg, 0deg)',
+ expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ desc: 'skew() with X and Y which is 0 value'
+ },
+ {
cssText: 'skew(90deg, 45deg)',
expected: new CSSSkew(CSS.deg(90), CSS.deg(45)),
desc: 'skew() with X and Y'
},
{
cssText: 'skewX(90deg)',
- expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ expected: new CSSSkewX(CSS.deg(90)),
desc: 'skewX()'
},
{
cssText: 'skewY(90deg)',
- expected: new CSSSkew(CSS.deg(0), CSS.deg(90)),
+ expected: new CSSSkewY(CSS.deg(90)),
desc: 'skewY()'
},
{
@@ -153,12 +158,14 @@
test(t => {
test_transform_normalization(t,
- 'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) scale3d(1, 2, 3)',
+ 'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) skewX(20deg) skewY(30deg) scale3d(1, 2, 3)',
new CSSTransformValue([
new CSSTranslate(CSS.px(1), CSS.px(0)),
new CSSRotate(CSS.number(1), CSS.number(0), CSS.number(0), CSS.deg(90)),
new CSSPerspective(CSS.px(1)),
new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ new CSSSkewX(CSS.deg(20)),
+ new CSSSkewY(CSS.deg(30)),
new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
]));
}, 'Normalizing a <transform-list> returns a CSSTransformValue containing all the transforms');
diff --git a/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html b/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
index 00d723f..dc87e81 100644
--- a/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
+++ b/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
@@ -50,6 +50,16 @@
desc: 'CSSSkew with Y which is 0 value'
},
{
+ value: new CSSSkewX(CSS.deg(90)),
+ cssText: 'skewX(90deg)',
+ desc: 'CSSSkewX'
+ },
+ {
+ value: new CSSSkewY(CSS.deg(90)),
+ cssText: 'skewY(90deg)',
+ desc: 'CSSSkewY'
+ },
+ {
value: new CSSPerspective(CSS.px(1)),
cssText: 'perspective(1px)',
desc: 'CSSPerspective'
diff --git a/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html b/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
index 8b7a868..6fc2e02 100644
--- a/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
+++ b/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
@@ -11,25 +11,25 @@
'use strict';
test(() => {
- assert_equals(new CSSUnparsedValue('lem', 'on', 'ade').toString(), 'lemonade');
+ assert_equals(new CSSUnparsedValue(['lem', 'on', 'ade']).toString(), 'lemonade');
}, 'CSSUnparsedValue containing strings serializes to its concatenated contents');
test(() => {
- assert_equals(new CSSUnparsedValue(
+ assert_equals(new CSSUnparsedValue([
new CSSVariableReferenceValue('--A',
- new CSSUnparsedValue(new CSSVariableReferenceValue('--B'))),
- new CSSVariableReferenceValue('--C')).toString(),
+ new CSSUnparsedValue([new CSSVariableReferenceValue('--B')])),
+ new CSSVariableReferenceValue('--C')]).toString(),
'var(--A,var(--B))var(--C)');
}, 'CSSUnparsedValue containing variable references serializes its ' +
'concatenated contents');
test(() => {
- assert_equals(new CSSUnparsedValue('foo', 'bar ',
+ assert_equals(new CSSUnparsedValue(['foo', 'bar ',
new CSSVariableReferenceValue('--A',
- new CSSUnparsedValue('baz ',
- new CSSVariableReferenceValue('--B'), 'lemon')),
+ new CSSUnparsedValue(['baz ',
+ new CSSVariableReferenceValue('--B'), 'lemon'])),
new CSSVariableReferenceValue('--C',
- new CSSUnparsedValue('ade'))).toString(),
+ new CSSUnparsedValue(['ade']))]).toString(),
'foobar var(--A,baz var(--B)lemon)var(--C,ade)');
}, 'CSSUnparsedValue containing mix of strings and variable references ' +
'serializes to its concatenated contents');
diff --git a/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html b/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html
new file mode 100644
index 0000000..1e61414
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkewX tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewx">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws(new TypeError(), () => new CSSSkewX(value));
+ }, 'Constructing a CSSSkewX with ' + desc + ' throws a TypeError');
+}
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ assert_throws(new TypeError(), () => skewX.ax = value);
+ assert_style_value_equals(skewX.ax, CSS.deg(0));
+ }, 'Updating CSSSkewX.ax with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ax, desc: axDesc} of gValidTestCases) {
+ test(() => {
+ const skewX = new CSSSkewX(ax);
+ assert_equals(skewX.ax, ax);
+ assert_true(skewX.is2D);
+ }, 'CSSSkewX can be constructed from ' + axDesc);
+}
+
+for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ skewX.ax = value;
+ assert_style_value_equals(skewX.ax, value);
+ }, 'CSSSkew.ax can be updated to ' + desc);
+}
+
+test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ skewX.is2D = false;
+ assert_true(skewX.is2D);
+}, 'Modifying skewX.is2D is a no-op');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html b/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
new file mode 100644
index 0000000..643d2f6
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkewY tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewy">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws(new TypeError(), () => new CSSSkewY(value));
+ }, 'Constructing a CSSSkewY with ' + desc + ' throws a TypeError');
+}
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ assert_throws(new TypeError(), () => skewY.ay = value);
+ assert_style_value_equals(skewY.ay, CSS.deg(0));
+ }, 'Updating CSSSkewY.ay with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ay, desc: ayDesc} of gValidTestCases) {
+ test(() => {
+ const skewY = new CSSSkewY(ay);
+ assert_equals(skewY.ay, ay);
+ assert_true(skewY.is2D);
+ }, 'CSSSkewY can be constructed from ' + ayDesc);
+}
+
+for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.ay = value;
+ assert_style_value_equals(skewY.ay, value);
+ }, 'CSSSkewY.ay can be updated to ' + desc);
+}
+
+test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.is2D = false;
+ assert_true(skewY.is2D);
+}, 'Modifying skewY.is2D is a no-op');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html b/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html
new file mode 100644
index 0000000..67b63a6
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformComponent.toMatrix with Relative Units</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformComponent.toMatrix throws when given relative units" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws(new TypeError(), () => {
+ return new CSSTranslate(
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(1, 'em')
+ ).toMatrix();
+ });
+}, 'CSSTranslate.toMatrix() containing relative units throws TypeError');
+
+test(() => {
+ assert_throws(new TypeError(), () => {
+ return new CSSPerspective(new CSSUnitValue(1, 'em')).toMatrix();
+ });
+}, 'CSSPerspective.toMatrix() containing relative units throws TypeError');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html b/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html
new file mode 100644
index 0000000..14d819b
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformComponent.toMatrix tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformComponent.toMatrix for each type of component" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gEpsilon = 1e-6;
+
+test(() => {
+ const component = new CSSTranslate(
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(2, 'px'),
+ new CSSUnitValue(3, 'px')
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).translate(1, 2, 3);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, 1e-8);
+}, 'CSSTranslate.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSRotate(
+ new CSSUnitValue(1, 'number'),
+ new CSSUnitValue(2, 'number'),
+ new CSSUnitValue(3, 'number'),
+ new CSSUnitValue(90, 'deg')
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).rotateAxisAngle(1, 2, 3, 90);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSRotate.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSScale(1, 2, 3);
+ const expectedMatrix = (new DOMMatrixReadOnly()).scale(1, 2, 3);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSScale.toMatrix() returns correct matrix');
+
+test(() => {
+ const alpha = 10, beta = 20;
+ const component = new CSSSkew(
+ new CSSUnitValue(alpha, 'rad'),
+ new CSSUnitValue(beta, 'rad')
+ );
+ const expectedMatrix = new DOMMatrixReadOnly(
+ [1, Math.tan(beta), 0, 0, Math.tan(alpha), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkew.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSSkewX(
+ new CSSUnitValue(10, 'rad'),
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).skewX(10);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkewX.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSSkewY(
+ new CSSUnitValue(10, 'rad'),
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).skewY(10);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkewY.toMatrix() returns correct matrix');
+
+test(() => {
+ const length = 10;
+ const component = new CSSPerspective(new CSSUnitValue(length, 'px'));
+ const expectedMatrix = new DOMMatrixReadOnly(
+ [1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, -1/length,
+ 0, 0, 0, 1]);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSPerspective.toMatrix() returns correct matrix');
+
+test(() => {
+ const matrix = new DOMMatrixReadOnly(
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ const component = new CSSMatrixComponent(matrix);
+ assert_matrix_approx_equals(component.toMatrix(), matrix, gEpsilon);
+}, 'CSSMatrixComponent.toMatrix() returns correct matrix');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html b/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html
new file mode 100644
index 0000000..c0e0bbc
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformValue.toMatrix</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformValue.toMatrix multiplies component matrices" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gEpsilon = 1e-6;
+
+test(() => {
+ const transformMatrix = new DOMMatrixReadOnly([1, 1, 1, 1, 1, 1]);
+ const transformArray = [
+ new CSSScale(2, 2),
+ new CSSMatrixComponent(transformMatrix),
+ new CSSScale(5, 6)
+ ];
+
+ let expectedMatrix = new DOMMatrix();
+ expectedMatrix.scaleSelf(2, 2);
+ expectedMatrix.multiplySelf(transformMatrix);
+ expectedMatrix.scaleSelf(5, 6);
+
+ const transform = new CSSTransformValue(transformArray);
+ assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSTransformValue.toMatrix() multiplies its component matrices');
+
+test(() => {
+ const transformMatrix = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ let transformArray = [
+ new CSSTranslate(CSS.px(1), CSS.px(1), CSS.px(1)),
+ new CSSRotate(1, 2, 3, CSS.deg(90)),
+ new CSSScale(2, 3, 2),
+ new CSSMatrixComponent(transformMatrix),
+ ];
+
+ transformArray.forEach(transform => transform.is2D = true);
+
+ let expectedMatrix = new DOMMatrix();
+ expectedMatrix.translateSelf(1, 1);
+ expectedMatrix.rotateSelf(90);
+ expectedMatrix.scaleSelf(2, 3);
+ expectedMatrix.multiplySelf(new DOMMatrixReadOnly([1, 2, 5, 6, 13, 14]));
+
+ const transform = new CSSTransformValue(transformArray);
+ assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSTransformValue.toMatrix() respects is2D changes in its components');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html b/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html
index b16d736..bc1ace6 100644
--- a/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html
+++ b/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html
@@ -9,8 +9,6 @@
<script>
'use strict';
-const EPSILON = 1e-6;
-
test(() => {
assert_throws(new TypeError(), () => new CSSTransformValue());
assert_throws(new TypeError(), () => new CSSTransformValue([]));
@@ -52,106 +50,6 @@
}, 'CSSTransformValue.is2D is readonly');
test(() => {
- assert_throws(new TypeError(), () => new CSSTransformValue([new CSSTranslate(CSS.px(1), CSS.em(1))]).toMatrix());
- assert_throws(new TypeError(), () => new CSSTransformValue([new CSSPerspective(CSS.em(1))]).toMatrix());
-}, 'Calling CSSTransformValue.toMatrix containing relative units throws TypeError');
-
-test(() => {
- const transform = new CSSTransformValue([
- new CSSTranslate(CSS.px(1), CSS.px(2), CSS.px(3))
- ]);
- const expectedMatrix = (new DOMMatrixReadOnly()).translate(1, 2, 3);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, 1e-8);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSTranslate');
-
-test(() => {
- const transform = new CSSTransformValue([
- new CSSRotate(CSS.number(1), CSS.number(2), CSS.number(3), CSS.deg(90))
- ]);
- const expectedMatrix = (new DOMMatrixReadOnly()).rotateAxisAngle(1, 2, 3, 90);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSRotate');
-
-test(() => {
- const transform = new CSSTransformValue([
- new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3))
- ]);
- const expectedMatrix = (new DOMMatrixReadOnly()).scale(1, 2, 3);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSScale');
-
-test(() => {
- const alpha = 10;
- const beta = 20;
- const transform = new CSSTransformValue([
- new CSSSkew(CSS.rad(alpha), CSS.rad(beta))
- ]);
- const expectedMatrix = new DOMMatrixReadOnly(
- [1, Math.tan(beta), 0, 0, Math.tan(alpha), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSSkew');
-
-test(() => {
- const length = 10;
- const transform = new CSSTransformValue([
- new CSSPerspective(CSS.px(length))
- ]);
- const expectedMatrix = new DOMMatrixReadOnly(
- [1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, -1/length,
- 0, 0, 0, 1]);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSPerspective');
-
-test(() => {
- const matrix = new DOMMatrixReadOnly(
- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
- const transform = new CSSTransformValue([
- new CSSMatrixComponent(matrix)
- ]);
- assert_matrix_approx_equals(transform.toMatrix(), matrix, EPSILON);
-}, 'CSSTransformValue.toMatrix returns correct matrix for CSSMatrixComponent');
-
-test(() => {
- const transformMatrix = new DOMMatrixReadOnly([1, 1, 1, 1, 1, 1]);
- const transformArray = [
- new CSSScale(2, 2),
- new CSSMatrixComponent(transformMatrix),
- new CSSScale(5, 6)
- ];
-
- let expectedMatrix = new DOMMatrix();
- expectedMatrix.scaleSelf(2, 2);
- expectedMatrix.multiplySelf(transformMatrix);
- expectedMatrix.scaleSelf(5, 6);
-
- const transform = new CSSTransformValue(transformArray);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix multiplies its component matrices');
-
-test(() => {
- const transformMatrix = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
- let transformArray = [
- new CSSTranslate(CSS.px(1), CSS.px(1), CSS.px(1)),
- new CSSRotate(1, 2, 3, CSS.deg(90)),
- new CSSScale(2, 3, 2),
- new CSSMatrixComponent(transformMatrix),
- ];
-
- transformArray.forEach(transform => transform.is2D = true);
-
- let expectedMatrix = new DOMMatrix();
- expectedMatrix.translateSelf(1, 1);
- expectedMatrix.rotateSelf(90);
- expectedMatrix.scaleSelf(2, 3);
- expectedMatrix.multiplySelf(new DOMMatrixReadOnly([1, 2, 5, 6, 13, 14]));
-
- const transform = new CSSTransformValue(transformArray);
- assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, EPSILON);
-}, 'CSSTransformValue.toMatrix respects is2D changes in its components');
-
-test(() => {
const transformArray = [
new CSSScale(2, 2),
new CSSMatrixComponent(new DOMMatrixReadOnly([1, 1, 1, 1, 1, 1])),
diff --git a/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html b/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
index 3a994dd..8af27e1 100644
--- a/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
+++ b/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
@@ -37,7 +37,7 @@
for (const {args, description} of gTestArguments) {
test(() => {
- const result = new CSSUnparsedValue(...args);
+ const result = new CSSUnparsedValue(args);
assert_not_equals(result, null,
'A CSSUnparsedValue should be created');
diff --git a/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html b/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
index 24082eb..e729acf 100644
--- a/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
+++ b/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
@@ -22,7 +22,7 @@
test(() => {
const result = new CSSVariableReferenceValue('--foo',
- new CSSUnparsedValue('lemon'));
+ new CSSUnparsedValue(['lemon']));
assert_not_equals(result, null,
'A CSSVariableReferenceValue should be created');
@@ -30,7 +30,7 @@
'Variable member should be same as passed in the constructor');
assert_not_equals(result.fallback, null,
'Fallback member should not be null');
- assert_style_value_equals(result.fallback, new CSSUnparsedValue('lemon'),
+ assert_style_value_equals(result.fallback, new CSSUnparsedValue(['lemon']),
'Fallback member should be as same as passed in the constructor');
}, 'CSSVariableReferenceValue can be constructed with fallback');
diff --git a/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
index d2a68e7..edadefa 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
@@ -38,7 +38,7 @@
test(() => {
const result = styleMap.get('--foo');
- assert_style_value_equals(result, new CSSUnparsedValue(' auto'));
+ assert_style_value_equals(result, new CSSUnparsedValue([' auto']));
}, 'Computed StylePropertyMap contains custom property declarations in style rules');
test(() => {
@@ -48,7 +48,7 @@
test(() => {
const result = styleMap.get('--bar');
- assert_style_value_equals(result, new CSSUnparsedValue(' 5'));
+ assert_style_value_equals(result, new CSSUnparsedValue([' 5']));
}, 'Computed StylePropertyMap contains custom property declarations in inline rules');
test(() => {
diff --git a/css/css-typed-om/the-stylepropertymap/computed/get.html b/css/css-typed-om/the-stylepropertymap/computed/get.html
index c11ca73..3e061e1 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/get.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/get.html
@@ -24,7 +24,7 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from computed style returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
index cd8dcd0..ca7d3b6 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
@@ -31,7 +31,7 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
index 07d59d8..4006b20 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
@@ -34,9 +34,9 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--A: A; --C: C; color: red; --B: B;');
- assert_style_value_equals(findInStyleMap(styleMap, '--A'), new CSSUnparsedValue(' A'));
- assert_style_value_equals(findInStyleMap(styleMap, '--B'), new CSSUnparsedValue(' B'));
- assert_style_value_equals(findInStyleMap(styleMap, '--C'), new CSSUnparsedValue(' C'));
+ assert_style_value_equals(findInStyleMap(styleMap, '--A'), new CSSUnparsedValue([' A']));
+ assert_style_value_equals(findInStyleMap(styleMap, '--B'), new CSSUnparsedValue([' B']));
+ assert_style_value_equals(findInStyleMap(styleMap, '--C'), new CSSUnparsedValue([' C']));
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
</script>
diff --git a/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
index 355a509..b1d7ce6 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
@@ -45,7 +45,7 @@
}, 'Declared StylePropertyMap does not contain inline styles');
test(() => {
- assert_style_value_equals(styleMap.get('--foo'), new CSSUnparsedValue(' auto'));
+ assert_style_value_equals(styleMap.get('--foo'), new CSSUnparsedValue([' auto']));
}, 'Declared StylePropertyMap contains custom property declarations');
test(() => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/get.html b/css/css-typed-om/the-stylepropertymap/declared/get.html
index aa649df..c4215cb 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/get.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/get.html
@@ -29,7 +29,7 @@
test(t => {
const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from CSS rule returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
index 5fe635c..dd4e90b 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
@@ -36,7 +36,7 @@
test(t => {
const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
index be61e25..0609010 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
@@ -42,9 +42,9 @@
assert_array_equals(keys, ['--A', '--B', '--C']);
assert_style_value_array_equals(values, [
- new CSSUnparsedValue(' A'),
- new CSSUnparsedValue(' B'),
- new CSSUnparsedValue(' C'),
+ new CSSUnparsedValue([' A']),
+ new CSSUnparsedValue([' B']),
+ new CSSUnparsedValue([' C']),
])
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
diff --git a/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
index fe4cced..232c7d3 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
@@ -63,11 +63,11 @@
test(t => {
let styleMap = createDeclaredStyleMap(t, '');
- styleMap.set('--foo', new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
styleMap.set('--foo', '20px');
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Setting a custom property with CSSStyleValue or String updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
index a5ee95e..8602e2c 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
@@ -46,11 +46,11 @@
test(t => {
let styleMap = createDeclaredStyleMap(t, '');
- styleMap.update('--foo', () => new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
- styleMap.update('--foo', () => new CSSUnparsedValue('20px'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['20px']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Updating a custom property with CSSStyleValue updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/get.html b/css/css-typed-om/the-stylepropertymap/inline/get.html
index ac7c6e4..8588e6e 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/get.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/get.html
@@ -29,7 +29,7 @@
test(t => {
const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from inline style returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
index 62cbec3..c7e3700 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
@@ -36,7 +36,7 @@
test(t => {
const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
index cbf76d8..ebd1df7 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
@@ -42,9 +42,9 @@
assert_array_equals(keys, ['--A', '--B', '--C']);
assert_style_value_array_equals(values, [
- new CSSUnparsedValue(' A'),
- new CSSUnparsedValue(' B'),
- new CSSUnparsedValue(' C'),
+ new CSSUnparsedValue([' A']),
+ new CSSUnparsedValue([' B']),
+ new CSSUnparsedValue([' C']),
])
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
diff --git a/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
index dc8ccc5..67d2426d 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
@@ -63,11 +63,11 @@
test(t => {
let styleMap = createInlineStyleMap(t, '');
- styleMap.set('--foo', new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
styleMap.set('--foo', '20px');
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Setting a custom property with CSSStyleValue or String updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
index ac2d834..77f2c10 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
@@ -46,11 +46,11 @@
test(t => {
let styleMap = createInlineStyleMap(t, '');
- styleMap.update('--foo', () => new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
- styleMap.update('--foo', () => new CSSUnparsedValue('20px'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['20px']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Updating a custom property with CSSStyleValue updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html b/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
new file mode 100644
index 0000000..8ab0363
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-direction' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+// FIXME: animation-direction is list-valued. Run list-valued tests here too.
+runPropertyTests('animation-direction', [
+ { syntax: 'normal' },
+ { syntax: 'reverse' },
+ { syntax: 'alternate-reverse' },
+ { syntax: 'alternate' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/background-image.html b/css/css-typed-om/the-stylepropertymap/properties/background-image.html
new file mode 100644
index 0000000..d584a0f
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/background-image.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-image' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+// FIXME: background-image is list-valued. Run list-valued tests here too.
+runPropertyTests('background-image', [
+ { syntax: 'none' },
+ { syntax: '<image>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/border-style.html b/css/css-typed-om/the-stylepropertymap/properties/border-style.html
new file mode 100644
index 0000000..1328ab1
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/border-style.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>border style properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('border-' + suffix + '-style', [
+ { syntax: 'none' },
+ { syntax: 'solid' },
+ // and other keywords
+ ]);
+}
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/border-width.html b/css/css-typed-om/the-stylepropertymap/properties/border-width.html
new file mode 100644
index 0000000..d1fe0b0
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/border-width.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>border width properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_zero_px(result) {
+ assert_style_value_equals(result, new CSSUnitValue(0, 'px'));
+}
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('border-' + suffix + '-width', [
+ // Computed value is 0 when border-style is 'none'.
+ // FIXME: Add separate test where border-style is not 'none' or 'hidden'.
+ { syntax: 'thin', computed: assert_is_zero_px },
+ { syntax: 'medium', computed: assert_is_zero_px },
+ { syntax: 'thick', computed: assert_is_zero_px },
+ { syntax: '<length>' },
+ ]);
+}
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/bottom.html b/css/css-typed-om/the-stylepropertymap/properties/bottom.html
new file mode 100644
index 0000000..36fe514
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/bottom.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'bottom' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('bottom', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/display.html b/css/css-typed-om/the-stylepropertymap/properties/display.html
new file mode 100644
index 0000000..51f3532
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/display.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'display' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('display', [
+ { syntax: 'none' },
+ { syntax: 'block' },
+ // and other keywords
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/height.html b/css/css-typed-om/the-stylepropertymap/properties/height.html
new file mode 100644
index 0000000..7d126ec
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/height.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'height' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('height', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/left.html b/css/css-typed-om/the-stylepropertymap/properties/left.html
new file mode 100644
index 0000000..6e82d2e
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/left.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'left' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('left', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/margin.html b/css/css-typed-om/the-stylepropertymap/properties/margin.html
new file mode 100644
index 0000000..679fb4a
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/margin.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>margin properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('margin-' + suffix, [
+ {
+ syntax: 'auto',
+ // Depending on which CSS spec is implemented, the computed value
+ // can be 'auto' or a browser specific value.
+ // FIXME: Figure out how to test this.
+ computed: () => {}
+ },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+ ]);
+}
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/object-position.html b/css/css-typed-om/the-stylepropertymap/properties/object-position.html
new file mode 100644
index 0000000..0dd30e9
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/object-position.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'object-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('object-position', [
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/padding.html b/css/css-typed-om/the-stylepropertymap/properties/padding.html
new file mode 100644
index 0000000..c740ae7
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/padding.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>padding properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('padding-' + suffix, [
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+ ]);
+}
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/position.html b/css/css-typed-om/the-stylepropertymap/properties/position.html
new file mode 100644
index 0000000..4b36ec7
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/position.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('position', [
+ { syntax: 'relative' },
+ { syntax: 'absolute' },
+ // and other keywords
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js b/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
new file mode 100644
index 0000000..f7f3bd8
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
@@ -0,0 +1,208 @@
+const gTestSyntaxExamples = {
+ '<length>': {
+ description: 'a length',
+ examples: [
+ {
+ description: "zero px",
+ input: new CSSUnitValue(0, 'px')
+ },
+ {
+ description: "a negative em",
+ input: new CSSUnitValue(-3.14, 'em'),
+ defaultComputed: value => {
+ // 'ems' are relative units, so just check that it computes to px
+ assert_class_string(value, 'CSSUnitValue',
+ '"em" lengths must compute to a CSSUnitValue');
+ assert_equals(value.unit, 'px', 'unit');
+ }
+ },
+ {
+ description: "a positive cm",
+ input: new CSSUnitValue(3.14, 'cm'),
+ defaultComputed: value => {
+ // 'cms' are relative units, so just check that it computes to px
+ assert_class_string(value, 'CSSUnitValue',
+ '"cm" lengths must compute to a CSSUnitValue');
+ assert_equals(value.unit, 'px', 'unit');
+ }
+ },
+ ],
+ },
+ '<percentage>': {
+ description: 'a percent',
+ examples: [
+ {
+ description: "zero percent",
+ input: new CSSUnitValue(0, 'percent')
+ },
+ {
+ description: "a negative percent",
+ input: new CSSUnitValue(-3.14, 'percent')
+ },
+ {
+ description: "a positive percent",
+ input: new CSSUnitValue(3.14, 'percent')
+ },
+ ],
+ },
+ '<time>': {
+ description: 'a time',
+ examples: [
+ {
+ description: "zero seconds",
+ input: new CSSUnitValue(0, 's')
+ },
+ {
+ description: "negative milliseconds",
+ input: new CSSUnitValue(-3.14, 'ms')
+ },
+ {
+ description: "positive seconds",
+ input: new CSSUnitValue(3.14, 's')
+ },
+ ],
+ },
+ '<position>': {
+ description: 'a position',
+ examples: [
+ {
+ decription: "origin position",
+ input: new CSSPositionValue(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'px'))
+ }
+ ],
+ },
+ '<image>': {
+ description: 'an image',
+ examples: [
+ {
+ description: "a PNG image",
+ input: new CSSURLImageValue('/media/1x1.png'),
+ defaultComputed: result => {
+ // URLs compute to absolute URLs
+ assert_true(result instanceof CSSURLImageValue,
+ 'Computed value should be a CSSURLImageValue');
+ assert_true(result.url.endsWith('/media/1x1.png'),
+ 'Computed value should be an absolute URL');
+ }
+ }
+ ],
+ },
+ '<transform>': {
+ description: 'a transform',
+ examples: [
+ {
+ description: 'a transform containing only a translate',
+ input: new CSSTransformValue([
+ new CSSTranslate(
+ new CSSUnitValue(0, 'px'),
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(2, 'px'),
+ )
+ ]),
+ }
+ ],
+ },
+};
+
+// Test setting a value in a style map and then getting it from the inline and
+// computed styles.
+function testPropertyValid(propertyName, examples, specified, computed, description) {
+ test(t => {
+ let element = createDivWithStyle(t);
+
+ for (const example of examples) {
+ element.attributeStyleMap.set(propertyName, example.input);
+
+ // specified style
+ const specifiedResult = element.attributeStyleMap.get(propertyName);
+ if (specified || example.defaultSpecified) {
+ (specified || example.defaultSpecified)(specifiedResult);
+ } else {
+ assert_not_equals(specifiedResult, null,
+ 'Specified value must not be null');
+ assert_true(specifiedResult instanceof CSSStyleValue,
+ 'Specified value must be a CSSStyleValue');
+ assert_style_value_equals(specifiedResult, example.input,
+ `Setting ${example.description} and getting its specified value`);
+ }
+
+ // computed style
+ const computedResult = element.computedStyleMap().get(propertyName);
+ if (computed || example.defaultComputed) {
+ (computed || example.defaultComputed)(computedResult);
+ } else {
+ assert_not_equals(computedResult, null,
+ 'Computed value must not be null');
+ assert_true(computedResult instanceof CSSStyleValue,
+ 'Computed value must be a CSSStyleValue');
+ assert_style_value_equals(computedResult, example.input,
+ `Setting ${example.description} and getting its computed value`);
+ }
+ }
+ }, `Can set '${propertyName}' to ${description}`);
+}
+
+// Test that styleMap.set throws for invalid values
+function testPropertyInvalid(propertyName, examples, description) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t);
+ for (const example of examples) {
+ assert_throws(new TypeError(), () => styleMap.set(propertyName, example.input));
+ }
+ }, `Setting '${propertyName}' to ${description} throws TypeError`);
+}
+
+function createKeywordExample(keyword) {
+ return {
+ description: `the '${keyword}' keyword`,
+ examples: [ { input: new CSSKeywordValue(keyword) } ]
+ };
+}
+
+// Run a battery of StylePropertyMap tests on |propertyName|.
+// Second argument is a list of test cases. A test case has the form:
+//
+// {
+// syntax: "<length>",
+// specified: /* a callback */ (optional)
+// computed: /* a callback */ (optional)
+// }
+//
+// If a callback is passed to |specified|, then the callback will be passed
+// the result of calling get() on the inline style map (specified values).
+// The callback should check if the result is expected using assert_* functions.
+// If no callback is passed, then we assert that the result is the same as
+// the input.
+//
+// Same goes for |computed|, but with the computed style map (computed values).
+function runPropertyTests(propertyName, testCases) {
+ let syntaxTested = new Set();
+
+ for (const testCase of testCases) {
+ // Retrieve test examples for this test case's syntax. If the syntax
+ // looks like a keyword, then create an example on the fly.
+ const syntaxExamples = testCase.syntax.match(/^[a-z\-]+$/) ?
+ createKeywordExample(testCase.syntax) :
+ gTestSyntaxExamples[testCase.syntax];
+
+ if (!syntaxExamples)
+ throw new Error(`'${testCase.syntax}' is not a valid CSS component`);
+
+ testPropertyValid(propertyName,
+ syntaxExamples.examples,
+ testCase.specified,
+ testCase.computed,
+ syntaxExamples.description);
+
+ syntaxTested.add(testCase.syntax);
+ }
+
+ // Also test that styleMap.set rejects invalid CSSStyleValues.
+ for (const [syntax, syntaxExamples] of Object.entries(gTestSyntaxExamples)) {
+ if (!syntaxTested.has(syntax)) {
+ testPropertyInvalid(propertyName,
+ syntaxExamples.examples,
+ syntaxExamples.description);
+ }
+ }
+}
diff --git a/css/css-typed-om/the-stylepropertymap/properties/right.html b/css/css-typed-om/the-stylepropertymap/properties/right.html
new file mode 100644
index 0000000..17488dfb
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/right.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'right' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('right', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/text-align.html b/css/css-typed-om/the-stylepropertymap/properties/text-align.html
new file mode 100644
index 0000000..c3d7f2e
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/text-align.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-align' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-align', [
+ { syntax: 'center' },
+ { syntax: 'justify' },
+ // and other keywords
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html b/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html
new file mode 100644
index 0000000..6bed8b6
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-style', [
+ { syntax: 'solid' },
+ { syntax: 'double' },
+ // and other keywords
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/top.html b/css/css-typed-om/the-stylepropertymap/properties/top.html
new file mode 100644
index 0000000..f12a76b
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/top.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'top' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('top', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/transform.html b/css/css-typed-om/the-stylepropertymap/properties/transform.html
new file mode 100644
index 0000000..7a85254
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/transform.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transform' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('transform', [
+ { syntax: 'none' },
+ { syntax: '<transform>' },
+]);
+
+</script>
diff --git a/css/css-typed-om/the-stylepropertymap/properties/width.html b/css/css-typed-om/the-stylepropertymap/properties/width.html
new file mode 100644
index 0000000..021a87f
--- /dev/null
+++ b/css/css-typed-om/the-stylepropertymap/properties/width.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('width', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/css/css-ui/reference/text-overflow-027-ref.html b/css/css-ui/reference/text-overflow-027-ref.html
new file mode 100644
index 0000000..8fc664b
--- /dev/null
+++ b/css/css-ui/reference/text-overflow-027-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test Reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<style>
+div { font-family: monospace; }
+</style>
+
+<p>The test passes if the following text is visible below: 123456 FE…</p>
+<div>123456 FE…</bdo></div>
diff --git a/css/css-ui/reference/text-overflow-028-ref.html b/css/css-ui/reference/text-overflow-028-ref.html
new file mode 100644
index 0000000..b25ab26
--- /dev/null
+++ b/css/css-ui/reference/text-overflow-028-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test Reference</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<style>
+div { font-family: monospace; }
+</style>
+
+<p>The test passes if the following text is visible below: …56 FEDCBA</p>
+<div>…56 FEDCBA</div>
diff --git a/css/css-ui/reference/text-overflow-029-ref.html b/css/css-ui/reference/text-overflow-029-ref.html
new file mode 100644
index 0000000..9cdd741
--- /dev/null
+++ b/css/css-ui/reference/text-overflow-029-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>CSS Basic User Interface Reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<style>
+div { font: 20px monospace; }
+</style>
+
+<div>Test passed…</div>
diff --git a/css/css-ui/text-overflow-027.html b/css/css-ui/text-overflow-027.html
new file mode 100644
index 0000000..fcb0104
--- /dev/null
+++ b/css/css-ui/text-overflow-027.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test: text-overflow applies visually to bidi</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
+<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
+<link rel="match" href="reference/text-overflow-027-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="text-overflow is a visual operation that occurs after layout, and therfore ellides text from the visual end of the line, even in bidi situations">
+<style>
+div {
+ font-family: monospace;
+ width: 10ch;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: pre;
+}
+</style>
+
+<p>The test passes if the following text is visible below: 123456 FE…</p>
+<div>123456 <bdo dir=rtl>ABCDEF</bdo></div>
diff --git a/css/css-ui/text-overflow-028.html b/css/css-ui/text-overflow-028.html
new file mode 100644
index 0000000..af906e1
--- /dev/null
+++ b/css/css-ui/text-overflow-028.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test: text-overflow applies visually to bidi</title>
+<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
+<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
+<link rel="match" href="reference/text-overflow-028-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="text-overflow is a visual operation that occurs after layout, and therfore ellides text from the visual end of the line, even in bidi situations">
+<style>
+div {
+ font-family: monospace;
+ width: 10ch;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: pre;
+}
+</style>
+
+<p>The test passes if the following text is visible below: …56 FEDCBA</p>
+<div dir=rtl><bdo dir=rtl>ABCDEF</bdo> 123456</div>
diff --git a/css/css-ui/text-overflow-029.html b/css/css-ui/text-overflow-029.html
new file mode 100644
index 0000000..f178011
--- /dev/null
+++ b/css/css-ui/text-overflow-029.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test: text-overflow and bidi interaction</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
+<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
+<link rel="match" href="reference/text-overflow-029-ref.html">
+<meta name="assert" content="When there's content of mixed directionality, text-overflow ellides the characters at the physical end of the line.">
+<meta name="flags" content="">
+<style>
+div {
+ font: 20px monospace;
+ width: 12.3ch; /* slightly more than 12ch because in some browsers (safari) the ellipsis is slightly large than other characters, even in monospace fonts. */
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+</style>
+
+<div>Test ‮deliafdessap‬</div>
diff --git a/css/css-writing-modes/available-size-011.html b/css/css-writing-modes/available-size-011.html
new file mode 100644
index 0000000..38aa583
--- /dev/null
+++ b/css/css-writing-modes/available-size-011.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>orthogonal flow parent with max-height</title>
+<meta charset=utf-8>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<meta name="assert" content="If an orthogonal flow's parent doesn't have a definite block size but does have a max block size, use that as the available size">
+<link rel="match" href="reference/available-size-011-ref.html">
+<meta name="flags" content="">
+<style>
+main {
+ max-height: 1em;
+ line-height: 1em;
+}
+div {
+ writing-mode: vertical-rl;
+}
+</style>
+
+<p>This test passes if the word “PASS” (without the quotation marks) appears below, written horizontally from left to right.
+<main><div>S S A P</div></main>
diff --git a/css/css-writing-modes/available-size-012.html b/css/css-writing-modes/available-size-012.html
new file mode 100644
index 0000000..937129e
--- /dev/null
+++ b/css/css-writing-modes/available-size-012.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / max-height + min-height / content height</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does not have a fixed height but does have a fixed max-height, use that, increased by min-height if it exists and is larger. (same as -001, with min-height)">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ max-height: 4ch; /* **max**-height does not give the element a definite block size */
+ min-height: 8ch;
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+ padding: 1ch 0;
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0; top: 1ch;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div take its height from
+ the min-height of its parent, it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-013.html b/css/css-writing-modes/available-size-013.html
new file mode 100644
index 0000000..1ffd656
--- /dev/null
+++ b/css/css-writing-modes/available-size-013.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height/ content height</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does have a fixed height, use that, increased by the min-height if it is set and is larger (same as -003, with min-height).">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ width: 300px; /* Shrinkwrapping this div is not what we're interested in testing here, so give it a width. See nested-orthogonal-001.html for that. */
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+ writing-mode: vertical-lr;
+ padding: 1ch 0;
+}
+
+div > div { padding-bottom: 2ch; } /* so that the content height of the parent and of the fixed size scrolling ancestor are different */
+div > div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0; top: 1ch;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div><div>0 0 0 0 <span>0</span> 0 0 0</div></div> <!-- If this div take its height from
+ the height of its scrollable ancestor, it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-014.html b/css/css-writing-modes/available-size-014.html
new file mode 100644
index 0000000..e0e41fb
--- /dev/null
+++ b/css/css-writing-modes/available-size-014.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height / not remaining size</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does a have fixed height, use that whole height increased by min-height if that's larger, even if some other content already consumes some of it (same as -005, with min-height).">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ width: 300px; /* Shrinkwrapping this div is not what we're interested in testing here, so give it a width. See nested-orthogonal-001.html for that. */
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+}
+
+div > div { padding-bottom: 2ch; } /* so that the content height of the parent and of the fixed size scrolling ancestor are different */
+div > div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ top: 1ch;
+}
+#spacer { /* shrinks the remaining space of the parent div. */
+ height: 1ch;
+ width: 100%;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div><aside id="spacer"></aside><div>0 0 0 0 <span>0</span> 0 0 0</div></div>
+ <!-- If the inner div take its height from the height of its scrollable
+ ancestor, it should wrap just right for the green 0 to overlap with the red
+ one. If instead it takes it size from the remaining height after having
+ removed #spacer, or does some other calculation that takes #spacer into
+ account, it won't line up with #red.-->
+</div>
diff --git a/css/css-writing-modes/available-size-015.html b/css/css-writing-modes/available-size-015.html
new file mode 100644
index 0000000..f7cb13b
--- /dev/null
+++ b/css/css-writing-modes/available-size-015.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / ICB / tall max-height + min-height scroller</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size, and there's a scroller with max-height and min-height, and max-height is smaller than the ICB but min-height is larger than the ICB, use the ICB as the available space (same as -008, with min-height).">
+<meta name="flags" content="">
+<style>
+body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
+div {
+ writing-mode: vertical-rl;
+ font-family: monospace;
+ font-size: 20px;
+ position: relative; /* to be a container for #red*/
+}
+.spacer { /* using 5 spacers of 20vh each instead of a single large one, so
+ that the line would wrap between spacers if it ends up being
+ shorter thatn 100vh*/
+ display: inline-block;
+ height: calc(20vh - 0.1px); /*Using this instead of 20vh, to account for accumulation of rounding errors, that might make 5*20vh taller than 100vh in some browsers*/
+}
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+ color: transparent;
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ font-family: monospace;
+ font-size: 20px;
+ left: 0; top: 0;
+}
+
+section {
+ overflow: hidden;
+ max-height: 40vh;
+ min-height: 120vh;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<section>
+<div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</section>
diff --git a/css/css-writing-modes/available-size-016.html b/css/css-writing-modes/available-size-016.html
new file mode 100644
index 0000000..c3c388e
--- /dev/null
+++ b/css/css-writing-modes/available-size-016.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / ICB / tall height + min-height scroller</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size, and there's a scroller with height and min-height, and height is smaller than the ICB but min-height is larger than the ICB, use the ICB as the available space (same as -009, with min-height).">
+<meta name="flags" content="">
+<style>
+body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
+div {
+ writing-mode: vertical-rl;
+ font-family: monospace;
+ font-size: 20px;
+ position: relative; /* to be a container for #red*/
+}
+.spacer { /* using 5 spacers of 20vh each instead of a single large one, so
+ that the line would wrap between spacers if it ends up being
+ shorter thatn 100vh*/
+ display: inline-block;
+ height: calc(20vh - 0.1px); /*Using this instead of 20vh, to account for accumulation of rounding errors, that might make 5*20vh taller than 100vh in some browsers*/
+}
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+ color: transparent;
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ font-family: monospace;
+ font-size: 20px;
+ left: 0; top: 0;
+}
+
+section {
+ overflow: hidden;
+ writing-mode: vertical-rl;
+ height: 40vh;
+ min-height: 120vh;
+}
+section > section {
+ writing-mode: horizontal-tb;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<section>
+<div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</section>
diff --git a/css/css-writing-modes/available-size-017.html b/css/css-writing-modes/available-size-017.html
new file mode 100644
index 0000000..79f1b85
--- /dev/null
+++ b/css/css-writing-modes/available-size-017.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height parent</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent has a height and a min-height larger than the height, use min-height as the available size.">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ color: transparent;
+ position: relative; /* to act as a container of #green */
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red {
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div takes its height from
+ the min-height of its parent (which it should)
+ it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-018.html b/css/css-writing-modes/available-size-018.html
new file mode 100644
index 0000000..4e86db7
--- /dev/null
+++ b/css/css-writing-modes/available-size-018.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / max-height + min-height parent</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent has a max-height and a min-height larger than the height, use min-height as the available size.">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ max-height: 4ch;
+ min-height: 8ch;
+ color: transparent;
+ position: relative; /* to act as a container of #green */
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red {
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div takes its height from
+ the min-height of its parent (which it should)
+ it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/float-lft-orthog-htb-in-vlr-002.xht b/css/css-writing-modes/float-lft-orthog-htb-in-vlr-002.xht
index 690dc78..6cef03a 100644
--- a/css/css-writing-modes/float-lft-orthog-htb-in-vlr-002.xht
+++ b/css/css-writing-modes/float-lft-orthog-htb-in-vlr-002.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-lft-orthog-htb-in-vlr-002-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht b/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht
index d11a2f9..977c653 100644
--- a/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht
+++ b/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-lft-orthog-htb-in-vrl-002-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-lft-orthog-vlr-in-htb-002.xht b/css/css-writing-modes/float-lft-orthog-vlr-in-htb-002.xht
index d760b49..e6229f1 100644
--- a/css/css-writing-modes/float-lft-orthog-vlr-in-htb-002.xht
+++ b/css/css-writing-modes/float-lft-orthog-vlr-in-htb-002.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-lft-orthog-vlr-in-htb-002-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-lft-orthog-vrl-in-htb-002.xht b/css/css-writing-modes/float-lft-orthog-vrl-in-htb-002.xht
index ac4462c..63f4359 100644
--- a/css/css-writing-modes/float-lft-orthog-vrl-in-htb-002.xht
+++ b/css/css-writing-modes/float-lft-orthog-vrl-in-htb-002.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-lft-orthog-vrl-in-htb-002-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-rgt-orthog-htb-in-vlr-003.xht b/css/css-writing-modes/float-rgt-orthog-htb-in-vlr-003.xht
index e11aad4..29937cd 100644
--- a/css/css-writing-modes/float-rgt-orthog-htb-in-vlr-003.xht
+++ b/css/css-writing-modes/float-rgt-orthog-htb-in-vlr-003.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-rgt-orthog-htb-in-vlr-003-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-rgt-orthog-htb-in-vrl-003.xht b/css/css-writing-modes/float-rgt-orthog-htb-in-vrl-003.xht
index 89cde7b..518b1f4 100644
--- a/css/css-writing-modes/float-rgt-orthog-htb-in-vrl-003.xht
+++ b/css/css-writing-modes/float-rgt-orthog-htb-in-vrl-003.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-rgt-orthog-htb-in-vrl-003-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-rgt-orthog-vlr-in-htb-003.xht b/css/css-writing-modes/float-rgt-orthog-vlr-in-htb-003.xht
index 09e5979..26589d7 100644
--- a/css/css-writing-modes/float-rgt-orthog-vlr-in-htb-003.xht
+++ b/css/css-writing-modes/float-rgt-orthog-vlr-in-htb-003.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-rgt-orthog-vlr-in-htb-003-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/float-rgt-orthog-vrl-in-htb-003.xht b/css/css-writing-modes/float-rgt-orthog-vrl-in-htb-003.xht
index 203c16e..9ded7b3 100644
--- a/css/css-writing-modes/float-rgt-orthog-vrl-in-htb-003.xht
+++ b/css/css-writing-modes/float-rgt-orthog-vrl-in-htb-003.xht
@@ -15,7 +15,7 @@
-->
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#auto-multicol" title="7.3.2 Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="float-rgt-orthog-vrl-in-htb-003-ref.xht" />
<meta content="" name="flags" />
diff --git a/css/css-writing-modes/reference/available-size-011-ref.html b/css/css-writing-modes/reference/available-size-011-ref.html
new file mode 100644
index 0000000..ef66b4e
--- /dev/null
+++ b/css/css-writing-modes/reference/available-size-011-ref.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>CSS writing mode test reference</title>
+<meta charset=utf-8>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<style>
+div {
+ line-height: 1em;
+ height: 1em;
+ writing-mode: vertical-rl;
+}
+</style>
+
+<p>This test passes if the word “PASS” (without the quotation marks) appears below, written horizontally from left to right.
+<div>S S A P</div>
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-001.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-001.xht
index 1f2d1f1..4a651f8 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-001.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-001.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-001-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-003.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-003.xht
index 7e5b672..f8fe8bf 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-003.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-003.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-003-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-004.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-004.xht
index 859d704..2111a8b 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-004.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-004.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-004-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-006.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-006.xht
index dde973c..52bdd50 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-006.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-006.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-006-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-007.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-007.xht
index d76033e..57d3975 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-007.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-007.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-007-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-008.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-008.xht
index 1a0d496..e340adb 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-008.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-008.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-008-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-009.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-009.xht
index 1749520..c156228 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-009.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-009.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-003-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-010.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-010.xht
index 716a81a..6d5eb25 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-010.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-010.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-010-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-011.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-011.xht
index a7d0cef..31ada5d 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-011.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-011.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-011-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-012.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-012.xht
index d838466..ce597bd 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-012.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-012.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-006-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-013.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-013.xht
index 645746c..8a8a4f3 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-013.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-013.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-013-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-015.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-015.xht
index cab989a..9a92dcb 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-015.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-015.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-015-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-016.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-016.xht
index 57059d2..fae31d7 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-016.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-016.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-016-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-018.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-018.xht
index 8502cf0..25a2626 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-018.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-018.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-018-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-019.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-019.xht
index 5490888..05a6479 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-019.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-019.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-019-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-020.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-020.xht
index 1667163..f950c77 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-020.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-020.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-020-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-021.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-021.xht
index ef18ccb..94e52c4 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-021.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-021.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-015-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-022.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-022.xht
index c945168..39bc330 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-022.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-022.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-022-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-023.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-023.xht
index 21e84bd..4d51832 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-023.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-023.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-023-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vlr-024.xht b/css/css-writing-modes/sizing-orthog-htb-in-vlr-024.xht
index 125ce02..a0e1071 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vlr-024.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vlr-024.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-lr' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-018-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-001.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-001.xht
index 94f5128..2e9fe94 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-001.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-001.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-001-ref.xht" />
<meta name="DC.date.created" content="2016-12-13T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-003.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-003.xht
index a59172d..828c1e5 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-003.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-003.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-003-ref.xht" />
<meta name="DC.date.created" content="2016-12-19T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-004.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-004.xht
index 9ac176a..4a20cd0 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-004.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-004.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-004-ref.xht" />
<meta name="DC.date.created" content="2016-12-19T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-006.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-006.xht
index c1e3f57..4328830 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-006.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-006.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-006-ref.xht" />
<meta name="DC.date.created" content="2016-12-19T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-007.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-007.xht
index 7bda42b..203883d 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-007.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-007.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-007-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-008.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-008.xht
index 9b214c9..f9a3a15 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-008.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-008.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-008-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-009.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-009.xht
index d262bb6..36d7d01 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-009.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-009.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-003-ref.xht" />
<meta name="DC.date.created" content="2016-12-19T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-010.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-010.xht
index 842ab97..2defea2 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-010.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-010.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-010-ref.xht" />
<meta name="DC.date.created" content="2016-12-19T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-011.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-011.xht
index c843969..3d03d10 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-011.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-011.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-011-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-012.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-012.xht
index a218bdf..8e43062 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-012.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-012.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-006-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-013.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-013.xht
index 1fb1eac..74ce5be 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-013.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-013.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-013-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-015.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-015.xht
index 8c4193c..b616855 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-015.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-015.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-015-ref.xht" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-016.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-016.xht
index 20ec773..a9e5dbc 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-016.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-016.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vlr-016-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-018.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-018.xht
index c0a77d8..5d28446 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-018.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-018.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside auto-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-018-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-019.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-019.xht
index 6b168bf..38ea05e 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-019.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-019.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-019-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht
index c3a6fa9..0bb3847 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-020-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht
index 5e8acd5..23555fb 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-015-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-022.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-022.xht
index 6c30cf7..1d14778 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-022.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-022.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-022-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht
index 47ed5af..c2b6176 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-023-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht b/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht
index 7b06bd8..811110e 100644
--- a/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht
+++ b/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'horizontal-tb' block with 'auto' inline size inside definite-sized 'vertical-rl' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-htb-in-vrl-018-ref.xht" />
<meta name="DC.date.created" content="2016-12-20T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-001.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-001.xht
index 49cfa83..1136196 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-001.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-001.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-001-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-003.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-003.xht
index 357c517..4f26ccf 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-003.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-003.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-003-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-004.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-004.xht
index 318c97c..0454836 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-004.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-004.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-004-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-006.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-006.xht
index 366749f..c58868f 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-006.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-006.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-006-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-007.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-007.xht
index b52ae55..54e3828 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-007.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-007.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-007-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht
index 187a48d..6f01a71 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-008-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-009.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-009.xht
index 8f81bce..47c4c1e 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-009.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-009.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-009-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-010.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-010.xht
index db786b2..de7495f 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-010.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-010.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-010-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-011.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-011.xht
index e973ee3..397781c 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-011.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-011.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-011-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-012.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-012.xht
index e1eb5f8..58149a1 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-012.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-012.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-012-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-013.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-013.xht
index cd42dd6..844b28c 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-013.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-013.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-013-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-015.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-015.xht
index 9d9de14..71b6fa6 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-015.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-015.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-015-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-016.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-016.xht
index e26e14d..341d4b6 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-016.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-016.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-016-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-018.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-018.xht
index 51c0bdd..c4d6f12 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-018.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-018.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-018-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-019.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-019.xht
index 86760b0..09c5923 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-019.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-019.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-019-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht
index 1b8d5ab..afa9a73 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-020-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-021.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-021.xht
index 1b37060..8bbf256 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-021.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-021.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-015-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-022.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-022.xht
index bb1a9af..9e15c25 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-022.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-022.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-022-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-023.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-023.xht
index 9cfb956..566da43 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-023.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-023.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-023-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vlr-in-htb-024.xht b/css/css-writing-modes/sizing-orthog-vlr-in-htb-024.xht
index 156d9e6..5ca1c96 100644
--- a/css/css-writing-modes/sizing-orthog-vlr-in-htb-024.xht
+++ b/css/css-writing-modes/sizing-orthog-vlr-in-htb-024.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-lr' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vlr-in-htb-018-ref.xht" />
<meta name="DC.date.created" content="2016-10-04T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht
index c19ab6c..0d41350 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-001-ref.xht" />
<meta name="DC.date.created" content="2016-09-02T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-003.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-003.xht
index a610020..22209ba 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-003.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-003.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-003-ref.xht" />
<meta name="DC.date.created" content="2016-09-08T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht
index 478a6a4..ee1d59d 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-004-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-006.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-006.xht
index 80955af..d3576e9 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-006.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-006.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-006-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-007.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-007.xht
index fb3c91d..505d046 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-007.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-007.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-007-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht
index 7df2838..1d71744 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-008-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-009.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-009.xht
index 399ce8f..0073da6 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-009.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-009.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-009-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-010.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-010.xht
index 5b0f4fa..71bbd3e 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-010.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-010.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-010-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-011.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-011.xht
index fa2ee6b..77bcedc 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-011.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-011.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-011-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-012.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-012.xht
index 1504ed9..5ba8fb9 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-012.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-012.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-012-ref.xht" />
<meta name="DC.date.created" content="2016-09-15T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht
index 4ccc0d0..997174e 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-013-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-015.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-015.xht
index 4b88733..a61c675 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-015.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-015.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-015-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-016.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-016.xht
index bbe2cdb..1e6382c 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-016.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-016.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-016-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-018.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-018.xht
index ab34193..35e9b19 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-018.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-018.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside auto-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-018-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-019.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-019.xht
index e4cebf2..0b29bc9 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-019.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-019.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-019-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht
index fc88acb..41c4ba9 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-020-ref.xht" />
<meta name="DC.date.created" content="2016-09-285T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-021.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-021.xht
index 44e085a..9e2e626 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-021.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-021.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-015-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-022.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-022.xht
index a47986d..1feb2c7 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-022.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-022.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-022-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-023.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-023.xht
index fbc6dea..d0c40ba 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-023.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-023.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-023-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/css-writing-modes/sizing-orthog-vrl-in-htb-024.xht b/css/css-writing-modes/sizing-orthog-vrl-in-htb-024.xht
index c4c0b03..d691383 100644
--- a/css/css-writing-modes/sizing-orthog-vrl-in-htb-024.xht
+++ b/css/css-writing-modes/sizing-orthog-vrl-in-htb-024.xht
@@ -7,7 +7,7 @@
<title>CSS Writing Modes Test: sizing of orthogonal 'vertical-rl' block with 'auto' inline size inside definite-sized 'horizontal-tb' containing block</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
- <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#auto-multicol" title="7.3.2. Auto-sizing Block Containers in Orthogonal Flows" />
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto" />
<link rel="match" href="sizing-orthog-vrl-in-htb-018-ref.xht" />
<meta name="DC.date.created" content="2016-09-28T09:54:03+11:00" scheme="W3CDTF" />
diff --git a/css/cssom/MediaList.html b/css/cssom/MediaList.html
index 17d4319..bddb5c9 100644
--- a/css/cssom/MediaList.html
+++ b/css/cssom/MediaList.html
@@ -44,6 +44,10 @@
media.mediaText = null;
assert_equals(media.mediaText, "", "MediaList mediaText attribute should be empty string in case of null");
assert_equals(media.toString(), "", "MediaList toString method should be empty string in case of null");
+
+ var rule = document.styleSheets[0].cssRules[0];
+ rule.media = "speech";
+ assert_equals(rule.media.mediaText, "speech", "MediaList mediaText attribute should be updated");
});
</script>
</head>
diff --git a/css/cssom/css-style-attr-decl-block.html b/css/cssom/css-style-attr-decl-block.html
new file mode 100644
index 0000000..9b45d66
--- /dev/null
+++ b/css/cssom/css-style-attr-decl-block.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="author" title="Xidorn Quan" href="mailto:me@upsuper.org">
+<link rel="help" href="https://drafts.csswg.org/cssom-1/#css-declaration-blocks">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+function createTestElement(style) {
+ let wrapper = document.createElement("div");
+ wrapper.innerHTML = `<div id="test" style="${style}"></div>`;
+ return wrapper.querySelector("#test");
+}
+
+test(function() {
+ let elem = createTestElement("z-index: 10;");
+ assert_equals(elem.style.cssText, "z-index: 10;");
+}, "Style attribute should create CSS declaration block based on its content");
+
+test(function() {
+ let elem = createTestElement("z-index: 20;");
+ let style = elem.style;
+ assert_equals(style.cssText, "z-index: 20;");
+ function assert_css_text(value, action) {
+ assert_equals(style.cssText, value, "CSS declaration block after " + action);
+ }
+ elem.setAttribute("style", "z-index: 21;");
+ assert_css_text("z-index: 21;", "changing the style attribute");
+ elem.removeAttribute("style");
+ assert_css_text("", "removing the style attribute");
+ elem.setAttribute("style", "position: absolute;");
+ assert_css_text("position: absolute;", "adding style attribute again");
+}, "Changes to style attribute should reflect on CSS declaration block");
+
+test(function() {
+ let elem = createTestElement("z-index: 30;");
+ let style = elem.style;
+ assert_equals(style.cssText, "z-index: 30;");
+ function assert_attr(value, action) {
+ assert_equals(elem.getAttribute("style"), value, "style attribute after " + action);
+ }
+ style.setProperty("z-index", "31");
+ assert_attr("z-index: 31;", "changing property in CSS declaration block");
+ style.removeProperty("z-index");
+ assert_attr("", "removing property from CSS declaration block");
+ style.setProperty("position", "absolute");
+ assert_attr("position: absolute;", "adding property to CSS declaration block");
+ style.cssText = "z-index: 32;";
+ assert_attr("z-index: 32;", "changing cssText");
+ style.cssText = "z-index: 33; invalid";
+ assert_attr("z-index: 33;", "changing cssText to a partial invalid value");
+}, "Changes to CSS declaration block should reflect on style attribute");
+
+test(function() {
+ let elem = createTestElement("z-index: 40;");
+ let style = elem.style;
+ assert_equals(style.cssText, "z-index: 40;");
+ // Create an observer for the element.
+ let observer = new MutationObserver(function() {});
+ observer.observe(elem, {attributes: true, attributeOldValue: true});
+ function assert_record_with_old_value(oldValue, action) {
+ let records = observer.takeRecords();
+ assert_equals(records.length, 1, "number of mutation records after " + action);
+ let record = records[0];
+ assert_equals(record.type, "attributes", "mutation type after " + action);
+ assert_equals(record.attributeName, "style", "mutated attribute after " + action);
+ assert_equals(record.oldValue, oldValue, "old value after " + action);
+ }
+ style.setProperty("z-index", "41");
+ assert_record_with_old_value("z-index: 40;", "changing property in CSS declaration block");
+ style.cssText = "z-index: 42;";
+ assert_record_with_old_value("z-index: 41;", "changing cssText");
+ style.cssText = "z-index: 42;";
+ assert_record_with_old_value("z-index: 42;", "changing cssText with the same content");
+ style.removeProperty("z-index");
+ assert_record_with_old_value("z-index: 42;", "removing property from CSS declaration block");
+ // Mutation to shorthand properties should also trigger only one mutation record.
+ style.setProperty("margin", "1px");
+ assert_record_with_old_value("", "adding shorthand property to CSS declaration block");
+ style.removeProperty("margin");
+ assert_record_with_old_value("margin: 1px;", "removing shorthand property from CSS declaration block");
+ // Final sanity check.
+ assert_equals(elem.getAttribute("style"), "");
+}, "Changes to CSS declaration block should queue mutation record for style attribute");
+
+test(function() {
+ let elem = createTestElement("z-index: 50; invalid");
+ let style = elem.style;
+ assert_equals(style.cssText, "z-index: 50;");
+ // Create an observer for the element.
+ let observer = new MutationObserver(function() {});
+ observer.observe(elem, {attributes: true});
+ function assert_no_record(action) {
+ let records = observer.takeRecords();
+ assert_true(records.length == 0, "expect no record after " + action);
+ }
+ style.setProperty("z-index", "invalid");
+ assert_no_record("setting invalid value to property");
+ // Longhand property.
+ style.removeProperty("position");
+ assert_no_record("removing non-existing longhand property");
+ style.setProperty("position", "");
+ assert_no_record("setting empty string to non-existing longhand property");
+ // Shorthand property.
+ style.removeProperty("margin");
+ assert_no_record("removing non-existing shorthand property");
+ style.setProperty("margin", "");
+ assert_no_record("setting empty string to non-existing shorthand property");
+ // Check that the value really isn't changed.
+ assert_equals(elem.getAttribute("style"), "z-index: 50; invalid",
+ "style attribute after removing non-existing properties");
+}, "Removing non-existing property or setting invalid value on CSS declaration block shouldn't queue mutation record");
+
+test(function() {
+ let elem = createTestElement("background-image: url(./);");
+ let style = elem.style;
+ let base = document.createElement("base");
+ base.href = "/";
+ document.body.appendChild(elem);
+ let originalComputedValue = getComputedStyle(elem).backgroundImage;
+ document.head.appendChild(base);
+ this.add_cleanup(() => {
+ document.head.removeChild(base);
+ document.body.removeChild(elem);
+ });
+ style.setProperty("background-color", "green");
+ assert_equals(getComputedStyle(elem).backgroundImage, originalComputedValue,
+ "getComputedStyle(elem).backgroundImage after setting background-color");
+ style.setProperty("background-image", "url(./)");
+ assert_not_equals(getComputedStyle(elem).backgroundImage, originalComputedValue,
+ "getComputedStyle(elem).backgroundImage after setting background-image");
+}, "Changes to CSS declaration block after a base URL change");
+</script>
diff --git a/css/cssom/cssimportrule.html b/css/cssom/cssimportrule.html
index d4a3250..691f886 100644
--- a/css/cssom/cssimportrule.html
+++ b/css/cssom/cssimportrule.html
@@ -14,16 +14,17 @@
<style id="styleElement" type="text/css">
@import url("support/a-green.css");
@import url("support/a-green.css") screen;
+ @page { background-color: red; }
</style>
</head>
<body>
<div id="log"></div>
<script type="text/javascript">
- var rule, ruleWithMedia;
+ var styleSheet, ruleList, rule, ruleWithMedia;
setup(function() {
- var styleSheet = document.getElementById("styleElement").sheet;
- var ruleList = styleSheet.cssRules;
+ styleSheet = document.getElementById("styleElement").sheet;
+ ruleList = styleSheet.cssRules;
rule = ruleList[0];
ruleWithMedia = ruleList[1];
});
@@ -83,6 +84,22 @@
assert_true(ruleWithMedia.media.length > 0);
assert_equals(ruleWithMedia.media.mediaText, "screen");
}, "Values of CSSImportRule attributes");
+
+ test(function() {
+ ruleWithMedia.media = "print";
+ assert_equals(ruleWithMedia.media.mediaText, "print");
+ }, "CSSImportRule : MediaList mediaText attribute should be updated due to [PutForwards]");
+
+ test(function() {
+ var ruleWithPage = ruleList[2];
+ ruleWithPage.style = "background-color: green;"
+ assert_equals(ruleWithPage.style.cssText, "background-color: green;");
+ }, "CSSStyleDeclaration cssText attribute should be updated due to [PutForwards]");
+
+ test(function() {
+ styleSheet.media = "screen";
+ assert_equals(styleSheet.media.mediaText, "screen");
+ }, "StyleSheet : MediaList mediaText attribute should be updated due to [PutForwards]");
</script>
</body>
</html>
diff --git a/css/cssom/cssom-fontfacerule.html b/css/cssom/cssom-fontfacerule.html
index 0620910..e44c3dc 100644
--- a/css/cssom/cssom-fontfacerule.html
+++ b/css/cssom/cssom-fontfacerule.html
@@ -3,7 +3,7 @@
<head>
<title>CSSOM Parsing Test: @font-face rules parsed into CSSOM CSSFontFaceRules</title>
<link rel="author" title="Paul Irish" href="mailto:paul.irish@gmail.com">
- <link rel="help" href="http://www.w3.org/TR/cssom-1/#css-font-face-rule">
+ <link rel="help" href="https://drafts.csswg.org/cssom/#css-rules">
<meta name="flags" content="dom">
@@ -44,7 +44,7 @@
test(function(){
- assert_equals(validRules[0].style.src, 'url(http://foo/bar/font.ttf)');
+ assert_equals(validRules[0].style.src, 'url("http://foo/bar/font.ttf")');
assert_equals(validRules[1].style.fontFamily, 'STIXGeneral');
/* unimplemented @font-face properties are not represented in CSSOM */
diff --git a/css/cssom/selectorText-modification-restyle-002.html b/css/cssom/selectorText-modification-restyle-002.html
new file mode 100644
index 0000000..a6b37c2
--- /dev/null
+++ b/css/cssom/selectorText-modification-restyle-002.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>CSSOM: Modify selectorText in a shadow tree stylesheet</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-cssstylerule-selectortext">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#selectors">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #container { color: red }
+ .subtree * { color: pink }
+</style>
+<div id="container">
+ <div id="host"></div>
+</div>
+<script>
+ const root = host.attachShadow({mode:"open"});
+ root.innerHTML = "<style>nomatch { color: green }</style><div>Green</div>";
+ const div = root.querySelector("div");
+
+ test(() => {
+ assert_equals(getComputedStyle(div).color, "rgb(255, 0, 0)", "Color should initial be red.");
+ }, "Check initial color.");
+
+ test(() => {
+ // The combination of the .subtree and CSSOM selector style invalidations
+ // caused the Blink implementation to fail an assertion.
+ container.className = "subtree";
+ root.styleSheets[0].cssRules[0].selectorText = "div";
+ assert_equals(getComputedStyle(div).color, "rgb(0, 128, 0)", "Color should be green after stylesheet change.");
+ }, "Check that color changes correctly after shadow stylesheet selector and #container class is changed.");
+</script>
diff --git a/css/mediaqueries/viewport-script-dynamic-ref.html b/css/mediaqueries/viewport-script-dynamic-ref.html
new file mode 100644
index 0000000..e3f1c95
--- /dev/null
+++ b/css/mediaqueries/viewport-script-dynamic-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io">
+<meta name="viewport" content="width=300">
+<style>
+p { color: green; }
+</style>
+<p>Should be green</p>
diff --git a/css/mediaqueries/viewport-script-dynamic.html b/css/mediaqueries/viewport-script-dynamic.html
new file mode 100644
index 0000000..7433877
--- /dev/null
+++ b/css/mediaqueries/viewport-script-dynamic.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test: Meta viewport after a script and stylesheets</title>
+<link rel="author" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1424878">
+<link rel="help" href="https://drafts.csswg.org/mediaqueries/#mf-dimensions">
+<link rel="match" href="viewport-script-dynamic-ref.html">
+<style>
+p { color: green; }
+/* Ensure that we initially match it, and stop matching it afterwards */
+@media (min-width: 310px) {
+ p {
+ color: red;
+ }
+}
+</style>
+<!-- The broken script below is the point of the test, see the bugzilla bug. -->
+<script src="intentionally-broken-url.js"></script>
+<meta name="viewport" content="width=300">
+<p>Should be green</p>
diff --git a/css/selectors/matches-nested.html b/css/selectors/matches-nested.html
new file mode 100644
index 0000000..b82d43d
--- /dev/null
+++ b/css/selectors/matches-nested.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Selectors: :matches()</title>
+ <link rel="author" title="Victoria Su" href="mailto:victoriaytsu@google.com">
+ <link rel="help" href="https://drafts.csswg.org/selectors-4/#matches">
+ <meta name="assert" content="This tests that the :matches() selector is effective when nested">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ /* Testing that highest specificity is chosen for class outside of :matches() */
+ .a+.b+.c>.e+.d {
+ color: black;
+ font-size: 10px;
+ width: 10px;
+ }
+ .a+:matches(.b+.f, .b+:matches(*, .c>.e, .g, *))+.d {
+ color: red;
+ font-size: 20px;
+ }
+ .a+.b+.c>.e+.d {
+ color: yellow;
+ }
+ /* Testing specificty of a class within :matches() */
+ .a+.c>.e {
+ color: black;
+ }
+ .a+:matches(.b+.f, :matches(.c>.e, .g)) {
+ color: red;
+ }
+ .c>.e {
+ color: black;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="a">
+ </div>
+ <div class="b" id="b2">
+ </div>
+ <div class="c" id="c2">
+ <div class="e">
+ </div>
+ <div class="d" id="d1">
+ Yellow
+ </div>
+ </div>
+ <div class="a">
+ </div>
+ <div class="c" id="c2">
+ <div class="e" id="e1">
+ Red
+ </div>
+ </div>
+ <script>
+
+ var red = "rgb(255, 0, 0)";
+ var yellow = "rgb(255, 255, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(d1).color, yellow);
+ assert_equals(getComputedStyle(d1).fontSize, "20px");
+ assert_equals(getComputedStyle(d1).width, "10px");
+ }, "Test nested :matches() chooses highest specificity for class outside :matches().");
+
+ test(() => {
+ assert_equals(getComputedStyle(e1).color, red);
+ }, "Test nested :matches() specificity for class within arguments.");
+
+ </script>
+ </body>
+</html>
\ No newline at end of file
diff --git a/css/selectors/matches-specificity.html b/css/selectors/matches-specificity.html
new file mode 100644
index 0000000..41d7251
--- /dev/null
+++ b/css/selectors/matches-specificity.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Selectors: :matches()</title>
+ <link rel="author" title="Victoria Su" href="mailto:victoriaytsu@google.com">
+ <link rel="help" href="https://drafts.csswg.org/selectors-4/#matches">
+ <meta name="assert" content="This tests that the :matches() selector chooses the correct specificity">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ .b.c + .d + .q.r + .s + #target {
+ font-size: 10px;
+ height: 10px;
+ width: 10px;
+ }
+ :matches(.a, .b.c + .d, .e) + :matches(* + .p, .q.r + .s, * + .t) + #target {
+ height: 20px;
+ width: 20px;
+ }
+ .b.c + .d + .q.r + .s + #target {
+ width: 30px;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="b c"></div>
+ <div class="a d e"></div>
+ <div class="q r"></div>
+ <div class="p s t"></div>
+ <div id="target"></div>
+ <script>
+
+ test(() => {
+ assert_equals(getComputedStyle(target).width, "30px");
+ assert_equals(getComputedStyle(target).height, "20px");
+ assert_equals(getComputedStyle(target).fontSize, "10px");
+ }, "Test :matches() uses highest possible specificity");
+
+ </script>
+ </body>
+</html>
\ No newline at end of file
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-horiz-001v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-horiz-001v.xhtml
new file mode 100644
index 0000000..f1dfdfd
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-horiz-001v.xhtml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Testcase with blocks as flex items in a horizontal flex container, with
+ various "flex" values and various combinations of the items
+ and with various writing-modes on the items. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing flexbox layout algorithm property on block flex items in a horizontal flex container
+ (with various writing-modes on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-basic-block-horiz-001-ref.xhtml"/>
+ <style>
+ div { height: 100px; }
+ div.flexbox {
+ border: 1px dashed blue;
+ width: 200px;
+ font-size: 10px;
+ display: flex;
+ }
+ div.a {
+ flex: 1 0 30px;
+ background: lightgreen;
+ writing-mode: vertical-lr;
+ }
+ div.b {
+ flex: 2 0 20px;
+ background: yellow;
+ writing-mode: vertical-rl;
+ }
+ div.c {
+ flex: 3 0 40px;
+ background: orange;
+ writing-mode: sideways-lr;
+ }
+ div.flexNone {
+ flex: none;
+ background: pink;
+ writing-mode: vertical-lr;
+ }
+ div.flexBasis {
+ flex: 0 0 20px;
+ background: gray;
+ writing-mode: sideways-rl;
+ }
+ div.spacer {
+ width: 15px;
+ height: 15px;
+ background: purple;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="flexbox"><div class="a"></div><div class="b"/></div>
+ <div class="flexbox"><div class="a"/><div class="c"/></div>
+ <div class="flexbox"><div class="a"/>
+ <div class="flexNone"><div class="spacer"/></div>
+ </div>
+ <div class="flexbox"><div class="b"/><div class="c"/></div>
+ <div class="flexbox"><div class="b"/>
+ <div class="flexNone"><div class="spacer"/><div class="spacer"/></div>
+ </div>
+
+ <div class="flexbox">
+ <div class="a"/><div class="b"/><div class="flexBasis"/><div class="c"/>
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-vert-001v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-vert-001v.xhtml
new file mode 100644
index 0000000..da943df
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-block-vert-001v.xhtml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Testcase with blocks as flex items in a vertical flex container, with
+ various "flex" values and various combinations of the items. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing flexbox layout algorithm property on block flex items in a vertical flex container
+ (with various writing-modes on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-basic-block-vert-001-ref.xhtml"/>
+ <style>
+ div { width: 50px; }
+ div.flexbox {
+ float: left;
+ border: 1px dashed blue;
+ height: 200px;
+ font-size: 10px;
+ display: flex;
+ flex-direction: column;
+ }
+ div.a {
+ flex: 1 0 30px;
+ background: lightgreen;
+ writing-mode: vertical-lr;
+ }
+ div.b {
+ flex: 2 0 20px;
+ background: yellow;
+ writing-mode: vertical-rl;
+ }
+ div.c {
+ flex: 3 0 40px;
+ background: orange;
+ writing-mode: sideways-lr;
+ }
+ div.flexNone {
+ flex: none;
+ background: pink;
+ writing-mode: vertical-lr;
+ }
+ div.flexBasis {
+ flex: 0 0 20px;
+ background: gray;
+ writing-mode: sideways-rl;
+ }
+ div.spacer {
+ display: inline-block;
+ width: 15px;
+ height: 15px;
+ background: purple;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="flexbox"><div class="a"></div><div class="b"/></div>
+ <div class="flexbox"><div class="a"/><div class="c"/></div>
+ <div class="flexbox"><div class="a"/>
+ <div class="flexNone"><div class="spacer"/></div>
+ </div>
+ <div class="flexbox"><div class="b"/><div class="c"/></div>
+ <div class="flexbox"><div class="b"/>
+ <div class="flexNone"><div class="spacer"/><div class="spacer"/></div>
+ </div>
+
+ <div class="flexbox">
+ <div class="a"/><div class="b"/><div class="flexBasis"/><div class="c"/>
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-horiz-001v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-horiz-001v.xhtml
new file mode 100644
index 0000000..ad623d7
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-horiz-001v.xhtml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+ This test checks that canvas elements behave correctly as flex items.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing flexbox layout algorithm property on canvas flex items in a horizontal flex container
+ (with a vertical writing-mode on the canvas flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-basic-canvas-horiz-001-ref.xhtml"/>
+ <style>
+ div.flexbox {
+ width: 200px;
+ background: lightgreen;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 5px;
+ line-height: 8px;
+ }
+ canvas {
+ min-width: 0;
+ width: 10px;
+ height: 20px;
+ border: 1px dotted green;
+ writing-mode: vertical-lr;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- A) One flex item -->
+ <div class="flexbox">
+ <canvas/>
+ </div>
+
+ <!-- B) Text and a canvas (ensure they aren't merged into one flex item) -->
+ <div class="flexbox">
+ some words <canvas/>
+ </div>
+
+ <!-- C) Two canvas elements, getting stretched by different ratios, from 0.
+
+ Space-to-be-distributed = 200px - borders = 200 - (1 + 1) - (1 + 1)
+ = 196px
+
+ 1st element gets 5/8 of space: 5/8 * 196px = 122.5px
+ 1st element gets 3/8 of space: 3/8 * 196px = 73.5px
+ -->
+ <div class="flexbox">
+ <canvas style="flex: 5"/>
+ <canvas style="flex: 3"/>
+ </div>
+
+ <!-- D) Two canvas elements, getting stretched by different ratios, from
+ different flex bases.
+
+ Space-to-be-distributed = 200px - (33 + 1 + 1) - (13 + 1 + 1) = 150px
+ 1st element gets 2/5 of space: 33px + 2/5 * 150px = 93px
+ 1st element gets 3/5 of space: 13px + 3/5 * 150px = 103px
+ -->
+ <div class="flexbox">
+ <canvas style="width: 33px; flex: 2 auto"/>
+ <canvas style="width: 13px; flex: 3 auto"/>
+ </div>
+
+ <!-- E) Two flex items, getting shrunk by different amounts.
+
+ Space-to-be-distributed = 200px - (150 + 1 + 1) - (100 + 1 + 1) = -54px
+ First element scaled flex ratio = 4 * 150 = 600
+ Second element scaled flex ratio = 3 * 100 = 300
+ * So, total flexibility is 600 + 300 = 900
+
+ 1st element gets 600/900 of space: 150 + 600/900 * -54 = 114px
+ 2nd element gets 300/900 of space: 100 + 300/900 * -54 = 82px
+ -->
+ <div class="flexbox">
+ <canvas style="width: 150px; flex: 1 4 auto"/>
+ <canvas style="width: 100px; flex: 1 3 auto"/>
+ </div>
+
+ <!-- F) Making sure we don't grow past max-width -->
+ <!-- Same as (D), except we've added a max-width on the second element.
+ -->
+ <div class="flexbox">
+ <canvas style="width: 33px; flex: 2 auto"/>
+ <canvas style="width: 13px; max-width: 90px; flex: 3 auto"/>
+ </div>
+
+ <!-- G) Making sure we grow at least as large as min-width -->
+ <!-- Same as (C), except we've added a min-width on the second element.
+ -->
+ <div class="flexbox">
+ <canvas style="width: 33px; flex: 2 auto"/>
+ <canvas style="width: 13px; min-width: 150px; flex: 3 auto"/>
+ </div>
+
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-vert-001v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-vert-001v.xhtml
new file mode 100644
index 0000000..057f63a
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-vert-001v.xhtml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+ This test checks that canvas elements behave correctly as flex items.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing flexbox layout algorithm property on canvas flex items in a vertical flex container
+ (with a vertical writing-mode on the canvas flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-basic-canvas-vert-001-ref.xhtml"/>
+ <style>
+ div.flexbox {
+ height: 200px;
+ background: lightgreen;
+ display: flex;
+ justify-content: space-between;
+ flex-direction: column;
+ float: left;
+ margin-right: 10px;
+ font: 8px monospace;
+ }
+ canvas {
+ width: 20px;
+ height: 10px;
+ min-height: 0;
+ border: 1px dotted green;
+ writing-mode: vertical-lr;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- A) One flex item -->
+ <div class="flexbox">
+ <canvas/>
+ </div>
+
+ <!-- B) Text and a canvas (ensure they aren't merged into one flex item) -->
+ <div class="flexbox">
+ a b <canvas/>
+ </div>
+
+ <!-- C) Two canvas elements, getting stretched by different ratios, from 0.
+
+ Space-to-be-distributed = 200px - borders = 200 - (1 + 1) - (1 + 1)
+ = 196px
+
+ 1st element gets 5/8 of space: 5/8 * 196px = 122.5px
+ 1st element gets 3/8 of space: 3/8 * 196px = 73.5px
+ -->
+ <div class="flexbox">
+ <canvas style="flex: 5"/>
+ <canvas style="flex: 3"/>
+ </div>
+
+ <!-- D) Two canvas elements, getting stretched by different ratios, from
+ different flex bases.
+
+ Space-to-be-distributed = 200px - (33 + 1 + 1) - (13 + 1 + 1) = 150px
+ 1st element gets 2/5 of space: 33px + 2/5 * 150px = 93px
+ 1st element gets 3/5 of space: 13px + 3/5 * 150px = 103px
+ -->
+ <div class="flexbox">
+ <canvas style="height: 33px; flex: 2 auto"/>
+ <canvas style="height: 13px; flex: 3 auto"/>
+ </div>
+
+ <!-- E) Two flex items, getting shrunk by different amounts.
+
+ Space-to-be-distributed = 200px - (150 + 1 + 1) - (100 + 1 + 1) = -54px
+ First element scaled flex ratio = 4 * 150 = 600
+ Second element scaled flex ratio = 3 * 100 = 300
+ * So, total flexibility is 600 + 300 = 900
+
+ 1st element gets 600/900 of space: 150 + 600/900 * -54 = 114px
+ 2nd element gets 300/900 of space: 100 + 300/900 * -54 = 82px
+ -->
+ <div class="flexbox">
+ <canvas style="height: 150px; flex: 1 4 auto"/>
+ <canvas style="height: 100px; flex: 1 3 auto"/>
+ </div>
+
+ <!-- F) Making sure we don't grow past max-height -->
+ <!-- Same as (D), except we've added a max-height on the second element.
+ -->
+ <div class="flexbox">
+ <canvas style="height: 33px; flex: 2 auto"/>
+ <canvas style="height: 13px; max-height: 90px; flex: 3 auto"/>
+ </div>
+
+ <!-- G) Making sure we grow at least as large as min-height -->
+ <!-- Same as (C), except we've added a min-height on the second element.
+ -->
+ <div class="flexbox">
+ <canvas style="height: 33px; flex: 2 auto"/>
+ <canvas style="height: 13px; min-height: 150px; flex: 3 auto"/>
+ </div>
+
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001v.html
new file mode 100644
index 0000000..4cc910b
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001v.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on non-stretched flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-001-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ writing-mode: vertical-lr;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 0 0 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-002v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-002v.html
new file mode 100644
index 0000000..0df92f9
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-002v.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on non-stretched flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-001-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ writing-mode: vertical-lr;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 0 0 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html
new file mode 100644
index 0000000..cb9275f
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on stretched flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-003-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: stretch;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ writing-mode: vertical-rl;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 0 0 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-004v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-004v.html
new file mode 100644
index 0000000..01c5271
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-004v.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on stretched flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-004-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: stretch;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ writing-mode: vertical-rl;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 0 0 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005v.html
new file mode 100644
index 0000000..ed1dcac
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005v.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on non-stretched flexible flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-005-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ flex: 1;
+ writing-mode: vertical-lr;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 1 1 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html
new file mode 100644
index 0000000..8c12fad
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>
+ CSS Test: Testing how explicit main-size & cross-size constraints
+ influence sizing on non-stretched flexible flex item w/ intrinsic ratio
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-main-size">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#hypothetical-cross-size">
+ <link rel="match" href="flexbox-intrinsic-ratio-006-ref.html">
+ <style>
+ .flexbox {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid black;
+ margin: 0 2px 2px 0; /* (Just for spacing things out, visually) */
+ width: 40px;
+ height: 40px;
+
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ float: left; /* For testing in "rows" */
+ }
+ br { clear: both; }
+
+ .flexbox > * {
+ flex: 1;
+ writing-mode: vertical-lr;
+
+ /* Disable "min-width:auto"/"min-height:auto" to focus purely on
+ later channels of influence. */
+ min-width: 0;
+ min-height: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- NOTE: solidblue.png has an intrinsic size of 16px by 16px. -->
+
+ <!-- Row 1: no special sizing: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png">
+ </div>
+ <br>
+
+ <!-- Row 2: Specified main-size, cross-size, or flex-basis: -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="flex: 1 1 30px">
+ </div>
+ <br>
+
+ <!-- Row 3: min main-size OR min cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ min-height: 34px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 34px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 4: max main-size OR max cross-size, or both -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ max-height: 6px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 6px;
+ max-height: 10px">
+ </div>
+ <br>
+
+ <!-- Row 5: min main-size vs. max cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ min-height: 30px">
+ </div>
+ <br>
+
+ <!-- Row 6: min|max main-size vs. explicit cross-size, & vice versa -->
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="min-width: 30px;
+ height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 30px;
+ max-height: 10px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="max-width: 10px;
+ height: 30px">
+ </div>
+ <div class="flexbox">
+ <img src="support/solidblue.png" style="width: 10px;
+ min-height: 30px">
+ </div>
+ </body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-002v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-002v.xhtml
new file mode 100644
index 0000000..a02e340
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-002v.xhtml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Testcase with margin/border/padding on flex items
+ and with various writing-modes on the items. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing margins, borders, and padding on flex items in a horizontal flex container
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-mbp-horiz-002-ref.xhtml"/>
+ <style>
+ div { height: 100px; border: 0; }
+ div.flexbox {
+ width: 200px;
+ font-size: 10px;
+ display: flex;
+ }
+ div.a {
+ flex: 1 0 9px;
+ background: lightgreen;
+ margin-left: 1px;
+ margin-right: 3px;
+ border-style: dotted;
+ border-left-width: 2px;
+ border-right-width: 4px;
+ padding-left: 5px;
+ padding-right: 6px;
+ writing-mode: vertical-lr;
+ }
+ div.b {
+ flex: 2 0 1px;
+ background: yellow;
+ margin-left: 2px;
+ margin-right: 4px;
+ border-style: dashed;
+ border-left-width: 7px;
+ border-right-width: 3px;
+ padding-left: 1px;
+ padding-right: 2px;
+ writing-mode: vertical-rl;
+ }
+ div.c {
+ flex: 3 0 40px;
+ background: orange;
+ writing-mode: sideways-lr;
+ }
+ div.flexNone {
+ flex: none;
+ background: pink;
+ writing-mode: vertical-lr;
+ }
+ div.flexBasis {
+ flex: 0 0 20px;
+ background: gray;
+ writing-mode: sideways-rl;
+ }
+ div.spacer {
+ width: 15px;
+ height: 15px;
+ background: purple;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="flexbox"><div class="a"></div><div class="b"/></div>
+ <div class="flexbox"><div class="a"/><div class="c"/></div>
+ <div class="flexbox"><div class="a"/>
+ <div class="flexNone"><div class="spacer"/></div>
+ </div>
+ <div class="flexbox"><div class="b"/><div class="c"/></div>
+ <div class="flexbox"><div class="b"/>
+ <div class="flexNone"><div class="spacer"/><div class="spacer"/></div>
+ </div>
+
+ <div class="flexbox">
+ <div class="a"/><div class="b"/><div class="flexBasis"/><div class="c"/>
+ </div>
+ </body>
+</html>
+
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-003v.xhtml b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-003v.xhtml
new file mode 100644
index 0000000..8baef30
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-003v.xhtml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Testcase with border/padding on a flex container and on its children -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ CSS Test: Testing borders and padding on a horizontal flex container and its flex items
+ (with a vertical writing-mode on the flex items).
+ </title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#layout-algorithm"/>
+ <link rel="match" href="flexbox-mbp-horiz-003-ref.xhtml"/>
+ <style>
+ div { height: 20px; border: 0; }
+ div.flexbox {
+ width: 200px;
+ display: flex;
+ margin-bottom: 2px;
+ }
+
+ <!-- customizations for flex container border/padding -->
+ .borderA {
+ border-style: dashed;
+ border-color: purple;
+ border-top-width: 6px;
+ border-right-width: 4px;
+ border-bottom-width: 2px;
+ border-left-width: 8px;
+ }
+
+ .borderB {
+ border-style: dashed;
+ border-color: purple;
+ border-top-width: 4px;
+ border-right-width: 5px;
+ border-bottom-width: 6px;
+ border-left-width: 7px;
+ }
+
+ .paddingA {
+ padding: 4px 3px 2px 1px;
+ }
+
+ .paddingB {
+ padding: 8px 11px 14px 17px;
+ }
+
+ div.child1 {
+ flex: 1 0 24px;
+ background: lightgreen;
+ border-style: dotted;
+ border-left-width: 2px;
+ border-right-width: 4px;
+ writing-mode: vertical-rl;
+ }
+ div.child2 {
+ flex: 2 0 10px;
+ background: yellow;
+ border-style: dashed;
+ border-left-width: 7px;
+ border-right-width: 3px;
+ writing-mode: vertical-lr;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="flexbox borderA"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox borderA paddingA"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox borderA paddingB"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox borderB"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox borderB paddingA"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox borderB paddingB"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox paddingA"
+ ><div class="child1"/><div class="child2"/></div>
+ <div class="flexbox paddingB"
+ ><div class="child1"/><div class="child2"/></div>
+ </body>
+</html>
+
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010-ref.html
new file mode 100644
index 0000000..e488416
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010-ref.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+ .container > .hl, .container > .hr {
+ /* In the testcase, these items are stretched vertically
+ via the default "align-self:stretch" behavior, and because
+ they have a height of "auto".
+ (The rest of the items have a non-auto height from "inline-size"
+ and their vertical writing-mode, so those ones do not stretch.) */
+ height: 118px;
+ }
+
+ .container.hl > * { float: left; }
+ .container.hr > * { float: right; }
+
+ </style>
+</head>
+<body>
+
+<div class="container hl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010.html
new file mode 100644
index 0000000..55c50e8
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-010.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a horizontal row-oriented flex container.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-010-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: row;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container hl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011-ref.html
new file mode 100644
index 0000000..8b92649
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011-ref.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+
+ /* This really floats to top ('logical left'), since all the containers
+ have a vertical writing mode. */
+ float: left;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+
+ .container > .vl, .container > .vr,
+ .container > .vl_rtl, .container > .vr_rtl {
+ /* In the testcase, these items are stretched horizontally
+ via the default "align-self:stretch" behavior, and because
+ they have a width of "auto".
+ (The rest of the items have a non-auto width from "inline-size"
+ and their horizontal writing-mode, so those ones do not stretch.) */
+ width: 126px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="container vl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html
new file mode 100644
index 0000000..6114e19
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a vertical row-oriented flex container.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-011-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: row;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container vl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012-ref.html
new file mode 100644
index 0000000..c03358b
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012-ref.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+
+ /* This really floats to top ('logical left'), since all the containers
+ have a vertical writing mode. */
+ float: right;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+
+ .container > .vl, .container > .vr,
+ .container > .vl_rtl, .container > .vr_rtl {
+ /* In the testcase, these items are stretched horizontally
+ via the default "align-self:stretch" behavior, and because
+ they have a width of "auto".
+ (The rest of the items have a non-auto width from "inline-size"
+ and their horizontal writing-mode, so those ones do not stretch.) */
+ width: 126px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="container vl_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html
new file mode 100644
index 0000000..a7b05f1
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a vertical row-oriented flex container
+ with 'direction' flipped.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-012-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: row;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container vl_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013-ref.html
new file mode 100644
index 0000000..2a27003
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013-ref.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ nocollapse {
+ /* special element to disable margin-collapsing */
+ display: block;
+ overflow: hidden;
+ height: 0;
+ }
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+ .container > .vl, .container > .vr,
+ .container > .vl_rtl, .container > .vr_rtl {
+ /* In the testcase, these items are stretched horizontally
+ via the default "align-self:stretch" behavior, and because
+ they have a width of "auto".
+ (The rest of the items have a non-auto width from "inline-size"
+ and their horizontal writing-mode, so those ones do not stretch.) */
+ width: 126px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="container hl">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container hl">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container hr">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container hr">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013.html
new file mode 100644
index 0000000..a5d483c
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-013.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a horizontal column-oriented flex container.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-013-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: column;
+ float: left;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 500px;
+ width: 150px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container hl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container hr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014-ref.html
new file mode 100644
index 0000000..4e4f590
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014-ref.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ nocollapse {
+ /* special element to disable margin-collapsing */
+ display: block;
+ overflow: hidden;
+ height: 0;
+ }
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+ .container > .hl, .container > .hr {
+ /* In the testcase, these items are stretched vertically
+ via the default "align-self:stretch" behavior, and because
+ they have a height of "auto".
+ (The rest of the items have a non-auto height from "inline-size"
+ and their vertical writing-mode, so those ones do not stretch.) */
+ height: 118px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="container vl">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vl">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vr">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vr">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html
new file mode 100644
index 0000000..1a54432
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a vertical column-oriented flex container.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-014-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: column;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container vl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015-ref.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015-ref.html
new file mode 100644
index 0000000..a236ca1
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015-ref.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: block;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ nocollapse {
+ /* special element to disable margin-collapsing */
+ display: block;
+ overflow: hidden;
+ height: 0;
+ }
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+
+ .container > .hl, .container > .hr {
+ /* In the testcase, these items are stretched vertically
+ via the default "align-self:stretch" behavior, and because
+ they have a height of "auto".
+ (The rest of the items have a non-auto height from "inline-size"
+ and their vertical writing-mode, so those ones do not stretch.) */
+ height: 118px;
+ }
+ </style>
+</head>
+<body>
+
+<div class="container vl_rtl">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vl_rtl">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vr_rtl">
+ <span class="hl small">a b c</span> <nocollapse></nocollapse>
+ <span class="hl big">d e</span> <nocollapse></nocollapse>
+ <span class="hr small">a b c</span> <nocollapse></nocollapse>
+ <span class="hr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl small">a b c</span> <nocollapse></nocollapse>
+ <span class="vl big">d e</span> <nocollapse></nocollapse>
+</div>
+<div class="container vr_rtl">
+ <span class="vr small">a b c</span> <nocollapse></nocollapse>
+ <span class="vr big">d e</span> <nocollapse></nocollapse>
+ <span class="vl_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vl_rtl big">d e</span> <nocollapse></nocollapse>
+ <span class="vr_rtl small">a b c</span><nocollapse></nocollapse>
+ <span class="vr_rtl big">d e</span> <nocollapse></nocollapse>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015.html b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015.html
new file mode 100644
index 0000000..af1f9b8
--- /dev/null
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>
+ CSS Test: Testing a mix of flex items with various values for
+ 'writing-mode' / 'direction' in a vertical column-oriented flex container
+ with 'direction' flipped.
+ </title>
+ <meta charset="utf-8">
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+ <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+ <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+ <link rel="match" href="flexbox-writing-mode-015-ref.html">
+ <link rel="stylesheet" type="text/css" href="support/ahem.css">
+ <style>
+ .container {
+ display: flex;
+ flex-direction: column;
+ border: 2px solid purple;
+ padding: 2px;
+ margin-bottom: 2em;
+ height: 150px;
+ width: 500px;
+ }
+
+ span {
+ display: block;
+ background: lightgrey;
+ border: 2px solid black;
+ /* If browser supports it, signal the inline direction with border color: */
+ border-block-start-color: orange;
+ border-inline-start-color: lime;
+
+ margin: 11px 13px 17px 7px;
+ inline-size: 6px;
+ }
+
+ .small { font: 12px Ahem; }
+ .big { font: 20px Ahem; }
+
+ .hl { writing-mode: horizontal-tb; direction: ltr; }
+ .hr { writing-mode: horizontal-tb; direction: rtl; }
+ .vl { writing-mode: vertical-lr; direction: ltr; }
+ .vr { writing-mode: vertical-rl; direction: ltr; }
+ .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+ .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+ </style>
+</head>
+<body>
+
+<div class="container vl_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vl_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="hl small">a b c</span>
+ <span class="hl big">d e</span>
+ <span class="hr small">a b c</span>
+ <span class="hr big">d e</span>
+ <span class="vl small">a b c</span>
+ <span class="vl big">d e</span>
+</div>
+<div class="container vr_rtl">
+ <span class="vr small">a b c</span>
+ <span class="vr big">d e</span>
+ <span class="vl_rtl small">a b c</span>
+ <span class="vl_rtl big">d e</span>
+ <span class="vr_rtl small">a b c</span>
+ <span class="vr_rtl big">d e</span>
+</div>
+
+</body>
+</html>
diff --git a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/reftest.list b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/reftest.list
index cb4c09e..d9252b2 100644
--- a/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/reftest.list
+++ b/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/reftest.list
@@ -61,11 +61,15 @@
# Basic tests with with blocks as flex items
== flexbox-basic-block-horiz-001.xhtml flexbox-basic-block-horiz-001-ref.xhtml
+== flexbox-basic-block-horiz-001v.xhtml flexbox-basic-block-horiz-001-ref.xhtml
== flexbox-basic-block-vert-001.xhtml flexbox-basic-block-vert-001-ref.xhtml
+== flexbox-basic-block-vert-001v.xhtml flexbox-basic-block-vert-001-ref.xhtml
# Tests for basic handling of <canvas>/<img>/etc as a flex item
== flexbox-basic-canvas-horiz-001.xhtml flexbox-basic-canvas-horiz-001-ref.xhtml
+== flexbox-basic-canvas-horiz-001v.xhtml flexbox-basic-canvas-horiz-001-ref.xhtml
== flexbox-basic-canvas-vert-001.xhtml flexbox-basic-canvas-vert-001-ref.xhtml
+== flexbox-basic-canvas-vert-001v.xhtml flexbox-basic-canvas-vert-001-ref.xhtml
== flexbox-basic-fieldset-horiz-001.xhtml flexbox-basic-fieldset-horiz-001-ref.xhtml
== flexbox-basic-fieldset-vert-001.xhtml flexbox-basic-fieldset-vert-001-ref.xhtml
== flexbox-basic-iframe-horiz-001.xhtml flexbox-basic-iframe-horiz-001-ref.xhtml
@@ -107,11 +111,17 @@
# (Note that tests 001 and 002 share a reference case; they render the same,
# because they don't do any direction-specific stretching/flexing.)
== flexbox-intrinsic-ratio-001.html flexbox-intrinsic-ratio-001-ref.html
+== flexbox-intrinsic-ratio-001v.html flexbox-intrinsic-ratio-001-ref.html
== flexbox-intrinsic-ratio-002.html flexbox-intrinsic-ratio-001-ref.html
+== flexbox-intrinsic-ratio-002v.html flexbox-intrinsic-ratio-001-ref.html
== flexbox-intrinsic-ratio-003.html flexbox-intrinsic-ratio-003-ref.html
+== flexbox-intrinsic-ratio-003v.html flexbox-intrinsic-ratio-003-ref.html
== flexbox-intrinsic-ratio-004.html flexbox-intrinsic-ratio-004-ref.html
+== flexbox-intrinsic-ratio-004v.html flexbox-intrinsic-ratio-004-ref.html
== flexbox-intrinsic-ratio-005.html flexbox-intrinsic-ratio-005-ref.html
+== flexbox-intrinsic-ratio-005v.html flexbox-intrinsic-ratio-005-ref.html
== flexbox-intrinsic-ratio-006.html flexbox-intrinsic-ratio-006-ref.html
+== flexbox-intrinsic-ratio-006v.html flexbox-intrinsic-ratio-006-ref.html
# Tests for flex items as (pseudo) stacking contexts
== flexbox-items-as-stacking-contexts-001.xhtml flexbox-items-as-stacking-contexts-001-ref.xhtml
@@ -141,7 +151,9 @@
== flexbox-mbp-horiz-001-rtl-reverse.xhtml flexbox-mbp-horiz-001-ref.xhtml
== flexbox-mbp-horiz-002a.xhtml flexbox-mbp-horiz-002-ref.xhtml
== flexbox-mbp-horiz-002b.xhtml flexbox-mbp-horiz-002-ref.xhtml
+== flexbox-mbp-horiz-002v.xhtml flexbox-mbp-horiz-002-ref.xhtml
== flexbox-mbp-horiz-003.xhtml flexbox-mbp-horiz-003-ref.xhtml
+== flexbox-mbp-horiz-003v.xhtml flexbox-mbp-horiz-003-ref.xhtml
== flexbox-mbp-horiz-003-reverse.xhtml flexbox-mbp-horiz-003-reverse-ref.xhtml
== flexbox-mbp-horiz-004.xhtml flexbox-mbp-horiz-004-ref.xhtml
@@ -199,7 +211,8 @@
== flexbox-with-pseudo-elements-002.html flexbox-with-pseudo-elements-002-ref.html
== flexbox-with-pseudo-elements-003.html flexbox-with-pseudo-elements-003-ref.html
-# Tests for combined influence of 'writing-mode' & 'direction' on flex axes
+# Tests for combined influence of 'writing-mode' & 'direction'
+# on flex container axes & flex item placement
== flexbox-writing-mode-001.html flexbox-writing-mode-001-ref.html
== flexbox-writing-mode-002.html flexbox-writing-mode-002-ref.html
== flexbox-writing-mode-003.html flexbox-writing-mode-003-ref.html
@@ -209,6 +222,12 @@
== flexbox-writing-mode-007.html flexbox-writing-mode-007-ref.html
== flexbox-writing-mode-008.html flexbox-writing-mode-008-ref.html
== flexbox-writing-mode-009.html flexbox-writing-mode-009-ref.html
+== flexbox-writing-mode-010.html flexbox-writing-mode-010-ref.html
+== flexbox-writing-mode-011.html flexbox-writing-mode-011-ref.html
+== flexbox-writing-mode-012.html flexbox-writing-mode-012-ref.html
+== flexbox-writing-mode-013.html flexbox-writing-mode-013-ref.html
+== flexbox-writing-mode-014.html flexbox-writing-mode-014-ref.html
+== flexbox-writing-mode-015.html flexbox-writing-mode-015-ref.html
# Single-line size clamping
== flexbox-single-line-clamp-1.html flexbox-single-line-clamp-1-ref.html
diff --git a/custom-elements/Document-createElement.html b/custom-elements/Document-createElement.html
index 97a5659..21f024c 100644
--- a/custom-elements/Document-createElement.html
+++ b/custom-elements/Document-createElement.html
@@ -36,12 +36,18 @@
customElements.define('autonomous-custom-element', AutonomousCustomElement);
customElements.define('is-custom-element', IsCustomElement);
- var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"});
+ var instance = document.createElement('autonomous-custom-element', { is: 'is-custom-element'});
assert_true(instance instanceof AutonomousCustomElement);
assert_equals(instance.localName, 'autonomous-custom-element');
assert_equals(instance.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace');
+ var instance2 = document.createElement('undefined-element', { is: 'is-custom-element'});
+ assert_false(instance2.matches(':defined'));
+ class DefinedLater extends HTMLElement {}
+ customElements.define('undefined-element', DefinedLater);
+ document.body.appendChild(instance2);
+ assert_true(instance2 instanceof DefinedLater);
}, 'document.createElement must create an instance of autonomous custom elements when it has is attribute');
function assert_reports(expected, testFunction, message) {
@@ -349,6 +355,7 @@
// https://github.com/w3c/webcomponents/issues/608
let div = document.createElement('div', { is: 'my-div' });
assert_false(div instanceof MyElement);
+ assert_false(div.hasAttribute('is'));
customElements.define('my-div', MyElement, { extends: 'div' });
document.body.appendChild(div);
diff --git a/custom-elements/Document-createElementNS.html b/custom-elements/Document-createElementNS.html
index 5711a46..4cc4561 100644
--- a/custom-elements/Document-createElementNS.html
+++ b/custom-elements/Document-createElementNS.html
@@ -24,12 +24,21 @@
}, 'autonomous: document.createElementNS should check namespaces.');
test(() => {
+ const xhtmlNS = 'http://www.w3.org/1999/xhtml';
+ assert_false(document.createElementNS(xhtmlNS, 'x-foo') instanceof HTMLUnknownElement);
+ assert_false(document.createElementNS(xhtmlNS, 'x-foo', {}) instanceof HTMLUnknownElement);
+ assert_false((new Document()).createElementNS(xhtmlNS, 'x-foo') instanceof HTMLUnknownElement);
+ assert_false((new Document()).createElementNS(xhtmlNS, 'x-foo', {}) instanceof HTMLUnknownElement);
+}, 'autonomous: document.createElementNS should not create HTMLUnknownElement for a valid custom element name');
+
+test(() => {
class MyBuiltinElement extends HTMLElement {};
customElements.define('my-builtin', MyBuiltinElement, { extends: 'address' });
let element = document.createElementNS('http://www.w3.org/1999/xhtml', 'p:address', { is: 'my-builtin'});
assert_true(element instanceof MyBuiltinElement);
assert_equals(element.prefix, 'p');
+ assert_false(element.hasAttribute('is'));
}, 'builtin: document.createElementNS should create custom elements with prefixes.');
test(() => {
@@ -38,6 +47,7 @@
customElements.define('my-builtin2', MyBuiltinElement2, { extends: 'address'});
let element = document.createElementNS('urn:example', 'address', { is: 'my-builtin2' });
assert_false(element instanceof MyBuiltinElement2);
+ assert_false(element.hasAttribute('is'));
}, 'builtin: document.createElementNS should check namespaces.');
</script>
</body>
diff --git a/custom-elements/builtin-coverage.html b/custom-elements/builtin-coverage.html
index 2778a68..bd084e9 100644
--- a/custom-elements/builtin-coverage.html
+++ b/custom-elements/builtin-coverage.html
@@ -1,9 +1,12 @@
<!DOCTYPE html>
+<html is="my-html">
+<head>
<meta charset="utf-8">
<meta name="help" content="https://html.spec.whatwg.org/multipage/custom-elements.html#element-definition">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<body>
+</head>
+<body is="my-body">
<div id="container"></div>
<script>
class MyA extends HTMLAnchorElement {
@@ -667,15 +670,15 @@
{tag: 'bdi', klass: MyBdi},
{tag: 'bdo', klass: MyBdo},
{tag: 'blockquote', klass: MyBlockquote},
- {tag: 'body', klass: MyBody, innerHTML: 'skip'},
+ {tag: 'body', klass: MyBody, parsing: 'document'},
{tag: 'br', klass: MyBr},
{tag: 'button', klass: MyButton},
{tag: 'canvas', klass: MyCanvas},
- {tag: 'caption', klass: MyCaption, innerHTML: 'table'},
+ {tag: 'caption', klass: MyCaption, parsing: 'table'},
{tag: 'cite', klass: MyCite},
{tag: 'code', klass: MyCode},
- {tag: 'col', klass: MyCol, innerHTML: 'table'},
- {tag: 'colgroup', klass: MyColgroup, innerHTML: 'table'},
+ {tag: 'col', klass: MyCol, parsing: 'table'},
+ {tag: 'colgroup', klass: MyColgroup, parsing: 'table'},
{tag: 'data', klass: MyData},
{tag: 'dd', klass: MyDd},
{tag: 'del', klass: MyDel},
@@ -700,7 +703,7 @@
{tag: 'header', klass: MyHeader},
{tag: 'hgroup', klass: MyHgroup},
{tag: 'hr', klass: MyHr},
- {tag: 'html', klass: MyHtml, innerHTML: 'skip'},
+ {tag: 'html', klass: MyHtml, parsing: 'document'},
{tag: 'i', klass: MyI},
{tag: 'iframe', klass: MyIframe},
{tag: 'img', klass: MyImg},
@@ -747,16 +750,16 @@
{tag: 'summary', klass: MySummary},
{tag: 'sup', klass: MySup},
{tag: 'table', klass: MyTable},
- {tag: 'tbody', klass: MyTbody, innerHTML: 'table'},
- {tag: 'td', klass: MyTd, innerHTML: 'table'},
+ {tag: 'tbody', klass: MyTbody, parsing: 'table'},
+ {tag: 'td', klass: MyTd, parsing: 'table'},
{tag: 'template', klass: MyTemplate},
{tag: 'textarea', klass: MyTextarea},
- {tag: 'tfoot', klass: MyTfoot, innerHTML: 'table'},
- {tag: 'th', klass: MyTh, innerHTML: 'table'},
- {tag: 'thead', klass: MyThead, innerHTML: 'table'},
+ {tag: 'tfoot', klass: MyTfoot, parsing: 'table'},
+ {tag: 'th', klass: MyTh, parsing: 'table'},
+ {tag: 'thead', klass: MyThead, parsing: 'table'},
{tag: 'time', klass: MyTime},
{tag: 'title', klass: MyTitle},
- {tag: 'tr', klass: MyTr, innerHTML: 'table'},
+ {tag: 'tr', klass: MyTr, parsing: 'table'},
{tag: 'track', klass: MyTrack},
{tag: 'u', klass: MyU},
{tag: 'ul', klass: MyUl},
@@ -789,7 +792,7 @@
}});
}
-for (t of testData) {
+for (const t of testData) {
test(() => {
let name = 'my-' + t.tag;
customElements.define(name, t.klass, { extends: t.tag });
@@ -797,27 +800,42 @@
test(() => {
let customized = new t.klass();
assert_equals(customized.constructor, t.klass);
+ assert_equals(customized.cloneNode().constructor, t.klass,
+ 'Cloning a customized built-in element should succeed.');
}, `${t.tag}: Operator 'new' should instantiate a customized built-in element`);
test(() => {
let customized = document.createElement(t.tag, { is: name });
assert_equals(customized.constructor, t.klass);
+ assert_equals(customized.cloneNode().constructor, t.klass,
+ 'Cloning a customized built-in element should succeed.');
}, `${t.tag}: document.createElement() should instantiate a customized built-in element`);
- if (t.innerHTML == 'skip')
+ if (t.parsing == 'document') {
+ let test = async_test(`${t.tag}: document parser should instantiate a customized built-in element`);
+ window.addEventListener('load', test.step_func_done(() => {
+ let customized = document.querySelector(t.tag);
+ assert_equals(customized.constructor, t.klass);
+ assert_equals(customized.cloneNode().constructor, t.klass,
+ 'Cloning a customized built-in element should succeed.');
+ }));
return;
+ }
test(() => {
let container = document.getElementById('container');
- if (t.innerHTML == 'table') {
+ if (t.parsing == 'table') {
container.innerHTML = `<table><${t.tag} is="${name}" id="${name}">`;
} else {
container.innerHTML = `<${t.tag} is="${name}" id="${name}">`;
}
let customized = document.getElementById(name);
assert_equals(customized.constructor, t.klass);
+ assert_equals(customized.cloneNode().constructor, t.klass,
+ 'Cloning a customized built-in element should succeed.');
}, `${t.tag}: innerHTML should instantiate a customized built-in element`);
}, `${t.tag}: Define a customized built-in element`);
}
</script>
</body>
+</html>
diff --git a/custom-elements/parser/serializing-html-fragments.html b/custom-elements/parser/serializing-html-fragments.html
new file mode 100644
index 0000000..6992dd6
--- /dev/null
+++ b/custom-elements/parser/serializing-html-fragments.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="container"></div>
+<script>
+test(() => {
+ class MyParagraph extends HTMLParagraphElement {}
+ customElements.define('my-p', MyParagraph, { extends: 'p' });
+
+ let p = new MyParagraph();
+ p.setAttribute('class', 'foo');
+ assert_equals(p.outerHTML, '<p is="my-p" class="foo"></p>');
+
+ let container = document.querySelector('#container');
+ container.appendChild(p);
+ container.innerHTML = container.innerHTML;
+ assert_not_equals(container.firstChild, p);
+ assert_true(container.firstChild instanceof MyParagraph);
+}, '"is" value should be serialized if the custom element has no "is" content attribute');
+
+test(() => {
+ let p = document.createElement('p', { is: 'your-p' });
+ assert_equals(p.outerHTML, '<p is="your-p"></p>');
+}, '"is" value should be serialized even for an undefined element');
+
+test(() => {
+ class MyDiv extends HTMLDivElement {}
+ customElements.define('my-div', MyDiv, { extends: 'div' });
+
+ let div = document.createElement('div', { is: 'my-div' });
+ div.setAttribute('is', 'foo"bar\n');
+ assert_equals(div.outerHTML, '<div is="foo"bar\n"></div>');
+}, '"is" content attribute should be serialized even if the element is a customized built-in element');
+</script>
+</body>
diff --git a/custom-elements/pseudo-class-defined.html b/custom-elements/pseudo-class-defined.html
new file mode 100644
index 0000000..30d5ac9
--- /dev/null
+++ b/custom-elements/pseudo-class-defined.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/semantics-other.html#selector-defined">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe"></iframe>
+<script>
+const testList = [
+ { tag_name: 'div', defined: true },
+ { tag_name: 'a-a', defined: false },
+ { tag_name: 'font-face', defined: true },
+ { tag_name: 'abbr', is: 'my-abbr', defined: false },
+];
+
+// Setup iframe to test the parser.
+const neither = 'rgb(255, 0, 0)';
+const defined = 'rgb(255, 165, 0)';
+const not_defined = 'rgb(0, 0, 255)';
+iframe.srcdoc = `<style>
+ * { color:${neither}; }
+ :defined { color:${defined}; }
+ :not(:defined) { color:${not_defined}; }
+</style>`
+ + testList.map(d => `<${d.tag_name}${d.is ? ' is=' + d.is : ''}></${d.tag_name}>`).join('');
+setup({ explicit_done: true });
+iframe.onload = () => {
+ const doc = iframe.contentDocument;
+ const doc_without_browsing_context = doc.implementation.createHTMLDocument();
+ for (const data of testList) {
+ // Test elements inserted by parser.
+ test_defined(data.defined, doc.getElementsByTagName(data.tag_name)[0],
+ `<${data.tag_name}${data.is ? ' is=' + data.is : ''}>`);
+
+ // Test DOM createElement() methods.
+ test_defined_for_createElement(data.defined, !data.defined, doc, data.tag_name, data.is);
+
+ // Documents without browsing context should behave the same.
+ test_defined_for_createElement(data.defined, false, doc_without_browsing_context, data.tag_name, data.is, 'Without browsing context: ');
+ }
+
+ done();
+};
+
+function test_defined_for_createElement(defined, should_test_change, doc, tag_name, is, description = '') {
+ let is_desc = is ? `, { is: "${is}" }` : '';
+ // Test document.createElement().
+ let element = is ? doc.createElement(tag_name, { is: is }) : doc.createElement(tag_name);
+ doc.body.appendChild(element);
+ test_defined(defined, element, `${description}createElement("${tag_name}"${is_desc})`);
+
+ // Test document.createElementNS().
+ let html_element = is ? doc.createElementNS('http://www.w3.org/1999/xhtml', tag_name, { is: is })
+ : doc.createElementNS('http://www.w3.org/1999/xhtml', tag_name);
+ doc.body.appendChild(html_element);
+ test_defined(defined, html_element, `${description}createElementNS("http://www.w3.org/1999/xhtml", "${tag_name}"${is_desc})`);
+
+ // If the element namespace is not HTML, it should be "uncustomized"; i.e., "defined".
+ let svg_element = is ? doc.createElementNS('http://www.w3.org/2000/svg', tag_name, { is: is })
+ : doc.createElementNS('http://www.w3.org/2000/svg', tag_name);
+ doc.body.appendChild(svg_element);
+ test_defined(true, svg_element, `${description}createElementNS("http://www.w3.org/2000/svg", "${tag_name}"${is_desc})`);
+
+ // Test ":defined" changes when the custom element was defined.
+ if (should_test_change) {
+ let w = doc.defaultView;
+ assert_false(!w, 'defaultView required to test change');
+ if (is) {
+ w.customElements.define(is, class extends w.HTMLElement {}, { extends: tag_name });
+ } else {
+ w.customElements.define(tag_name, class extends w.HTMLElement {
+ constructor() { super(); }
+ });
+ }
+
+ test_defined(true, element, `Upgraded ${description}createElement("${tag_name}"${is_desc})`);
+ test_defined(true, html_element, `Upgraded ${description}createElementNS("http://www.w3.org/1999/xhtml", "${tag_name}"${is_desc})`);
+ }
+}
+
+function test_defined(expected, element, description) {
+ test(() => {
+ assert_equals(element.matches(':defined'), expected, 'matches(":defined")');
+ assert_equals(element.matches(':not(:defined)'), !expected, 'matches(":not(:defined")');
+ const view = element.ownerDocument.defaultView;
+ if (!view)
+ return;
+ const style = view.getComputedStyle(element);
+ assert_equals(style.color, expected ? defined : not_defined, 'getComputedStyle');
+ }, `${description} should ${expected ? 'be' : 'not be'} :defined`);
+}
+</script>
diff --git a/custom-elements/upgrading/Document-importNode.html b/custom-elements/upgrading/Document-importNode.html
new file mode 100644
index 0000000..b80f906
--- /dev/null
+++ b/custom-elements/upgrading/Document-importNode.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-importnode">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/custom-elements-helpers.js"></script>
+<body>
+<script>
+test_with_window((w, doc) => {
+ class MyElement extends HTMLElement {}
+ class MyElement2 extends w.HTMLElement {}
+ customElements.define('my-element', MyElement);
+ w.customElements.define('my-element', MyElement2);
+
+ let original = document.createElement('my-element');
+ assert_true(original instanceof MyElement);
+
+ let imported = doc.importNode(original);
+ assert_true(imported instanceof MyElement2);
+}, 'autonomous: document.importNode() should import custom elements successfully');
+
+test_with_window((w, doc) => {
+ class MyElement3 extends w.HTMLElement {}
+ w.customElements.define('my-element3', MyElement3);
+
+ let original = document.createElement('my-element3');
+ assert_equals(original.constructor, HTMLElement);
+
+ let imported = doc.importNode(original);
+ assert_true(imported instanceof MyElement3);
+}, 'autonomous: document.importNode() should import "undefined" custom elements successfully');
+
+test_with_window((w, doc) => {
+ class MyDiv extends HTMLDivElement {}
+ class MyDiv2 extends w.HTMLDivElement {}
+ customElements.define('my-div', MyDiv, { extends: 'div' });
+ w.customElements.define('my-div', MyDiv2, { extends: 'div' });
+
+ let original = document.createElement('div', { is: 'my-div' });
+ assert_true(original instanceof MyDiv);
+
+ let imported = doc.importNode(original);
+ assert_true(imported instanceof MyDiv2);
+}, 'built-in: document.importNode() should import custom elements successfully');
+
+test_with_window((w, doc) => {
+ class MyDiv2 extends w.HTMLDivElement {}
+ w.customElements.define('my-div2', MyDiv2, { extends: 'div' });
+
+ let original = document.createElement('div', { is: 'my-div2' });
+ assert_equals(original.constructor, HTMLDivElement);
+
+ let imported = doc.importNode(original);
+ assert_true(imported instanceof MyDiv2);
+}, 'built-in: document.importNode() should import "undefined" custom elements successfully');
+</script>
+</body>
diff --git a/custom-elements/upgrading/Node-cloneNode.html b/custom-elements/upgrading/Node-cloneNode.html
index 0492e1f..1a8786e 100644
--- a/custom-elements/upgrading/Node-cloneNode.html
+++ b/custom-elements/upgrading/Node-cloneNode.html
@@ -49,6 +49,35 @@
'A cloned custom element must be an instance of the custom element');
}, 'Node.prototype.cloneNode(false) must be able to clone as a autonomous custom element when it contains is attribute');
+test(function () {
+ class MyDiv1 extends HTMLDivElement {};
+ class MyDiv2 extends HTMLDivElement {};
+ class MyDiv3 extends HTMLDivElement {};
+ customElements.define('my-div1', MyDiv1, { extends: 'div' });
+ customElements.define('my-div2', MyDiv2, { extends: 'div' });
+
+ let instance = document.createElement('div', { is: 'my-div1'});
+ assert_true(instance instanceof MyDiv1);
+ instance.setAttribute('is', 'my-div2');
+ let clone = instance.cloneNode(false);
+ assert_not_equals(instance, clone);
+ assert_true(clone instanceof MyDiv1,
+ 'A cloned custom element must be an instance of the custom element even with an inconsistent "is" attribute');
+
+ let instance3 = document.createElement('div', { is: 'my-div3'});
+ assert_false(instance3 instanceof MyDiv3);
+ instance3.setAttribute('is', 'my-div2');
+ let clone3 = instance3.cloneNode(false);
+ assert_not_equals(instance3, clone);
+ customElements.define('my-div3', MyDiv3, { extends: 'div' });
+ document.body.appendChild(instance3);
+ document.body.appendChild(clone3);
+ assert_true(instance3 instanceof MyDiv3,
+ 'An undefined element must be upgraded even with an inconsistent "is" attribute');
+ assert_true(clone3 instanceof MyDiv3,
+ 'A cloned undefined element must be upgraded even with an inconsistent "is" attribute');
+}, 'Node.prototype.cloneNode(false) must be able to clone as a customized built-in element when it has an inconsistent "is" attribute');
+
test_with_window(function (contentWindow) {
var contentDocument = contentWindow.document;
class MyCustomElement extends contentWindow.HTMLElement {}
diff --git a/docs/introduction.md b/docs/introduction.md
index c718efd..8833d86 100644
--- a/docs/introduction.md
+++ b/docs/introduction.md
@@ -102,17 +102,22 @@
and read the [Windows Notes](#windows-notes) section below.
To get the tests running, you need to set up the test domains in your
-[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system). The
-following entries are required:
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system).
+The necessary content can be generated with `./wpt make-hosts-file`; on
+Windows, you will need to preceed the prior command with `python` or
+the path to the Python binary (`python wpt make-hosts-file`).
+
+For example, on most UNIX-like systems, you can setup the hosts file with:
+
+```bash
+./wpt make-hosts-file | sudo tee -a /etc/hosts
```
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
+
+And on Windows (note this requires an Administrator privileged shell):
+
+```bash
+python wpt make-hosts-file >> %SystemRoot%\System32\drivers\etc\hosts
```
If you are behind a proxy, you also need to make sure the domains above are
diff --git a/domparsing/XMLSerializer-serializeToString.html b/domparsing/XMLSerializer-serializeToString.html
index 23323b9..92cdb10 100644
--- a/domparsing/XMLSerializer-serializeToString.html
+++ b/domparsing/XMLSerializer-serializeToString.html
@@ -39,6 +39,15 @@
var xmlString = (new XMLSerializer()).serializeToString(root);
assert_equals(xmlString, '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>');
}, 'Check if there is no redundant empty namespace declaration.');
+
+test(function() {
+ var serializer = new XMLSerializer();
+ var root = createXmlDoc().documentElement;
+ root.firstChild.setAttribute('attr1', 'value1\tvalue2\r\n');
+ var xmlString = serializer.serializeToString(root);
+ assert_equals(xmlString, '<root><child1 attr1="value1	value2
">value1</child1></root>');
+}, 'check XMLSerializer.serializeToString escapes attribute values for roundtripping');
+
</script>
</body>
</html>
diff --git a/fetch/api/abort/general.any.js b/fetch/api/abort/general.any.js
index e2c6e8d..eb59797 100644
--- a/fetch/api/abort/general.any.js
+++ b/fetch/api/abort/general.any.js
@@ -78,6 +78,7 @@
assert_true(Boolean(request.signal), "Signal member is present & truthy");
assert_equals(request.signal.constructor, AbortSignal);
assert_not_equals(request.signal, signal, 'Request has a new signal, not a reference');
+ assert_true(request.signal.aborted, `Request's signal has aborted`);
const fetchPromise = fetch(request);
diff --git a/fetch/api/redirect/redirect-empty-location-worker.html b/fetch/api/redirect/redirect-empty-location-worker.html
new file mode 100644
index 0000000..7dce98c
--- /dev/null
+++ b/fetch/api/redirect/redirect-empty-location-worker.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fetch in worker: handling empty Location header during redirection</title>
+ <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ fetch_tests_from_worker(new Worker("redirect-empty-location.js"));
+ </script>
+ </body>
+</html>
diff --git a/fetch/api/redirect/redirect-empty-location.html b/fetch/api/redirect/redirect-empty-location.html
new file mode 100644
index 0000000..afb033b
--- /dev/null
+++ b/fetch/api/redirect/redirect-empty-location.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fetch: handling empty Location header during redirection</title>
+ <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script src="../resources/utils.js"></script>
+ <script src="redirect-empty-location.js"></script>
+ </body>
+</html>
diff --git a/fetch/api/redirect/redirect-empty-location.js b/fetch/api/redirect/redirect-empty-location.js
new file mode 100644
index 0000000..a9d03c5
--- /dev/null
+++ b/fetch/api/redirect/redirect-empty-location.js
@@ -0,0 +1,23 @@
+// Tests receiving a redirect response with a Location header with an empty
+// value.
+
+if (this.document === undefined) {
+ importScripts("/resources/testharness.js");
+ importScripts("../resources/utils.js");
+}
+
+const url = RESOURCES_DIR + 'redirect-empty-location.py';
+
+promise_test(t => {
+ return promise_rejects(t, new TypeError(), fetch(url, {redirect:'follow'}));
+}, 'redirect response with empty Location, follow mode');
+
+promise_test(t => {
+ return fetch(url, {redirect:'manual'})
+ .then(resp => {
+ assert_equals(resp.type, 'opaqueredirect');
+ assert_equals(resp.status, 0);
+ });
+}, 'redirect response with empty Location, manual mode');
+
+done();
diff --git a/fetch/api/resources/redirect-empty-location.py b/fetch/api/resources/redirect-empty-location.py
new file mode 100644
index 0000000..2baabae
--- /dev/null
+++ b/fetch/api/resources/redirect-empty-location.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ headers = [("Location", "")]
+ return 302, headers, ""
diff --git a/fetch/corb/README.md b/fetch/corb/README.md
new file mode 100644
index 0000000..00e8c16
--- /dev/null
+++ b/fetch/corb/README.md
@@ -0,0 +1,21 @@
+# Tests related to Cross-Origin Resource Blocking (CORB).
+
+This directory contains tests related to the
+[Cross-Origin Resource Blocking (CORB)](https://chromium.googlesource.com/chromium/src/+/master/content/browser/loader/cross_origin_read_blocking_explainer.md) algorithm.
+
+Note that CORB is currently in very early stages of standardization path. At
+the same time, some tests in this directory (e.g.
+`css-with-json-parser-breaker`) cover behavior spec-ed outside of CORB (making
+sure that CORB doesn't change the existing web behavior) and therefore are
+valuable independently from CORB's standardization efforts.
+
+Tests that cover behavior that is changed by CORB have to be marked as
+[tentative](http://web-platform-tests.org/writing-tests/file-names.html)
+(using `.tentative` substring in their filename) until CORB
+is included in the official
+[Fetch spec](https://fetch.spec.whatwg.org/).
+
+The tests in this directory interact with various, random features,
+but the tests have been grouped together into the `fetch/corb` directory,
+because all of these tests verify behavior that is important to the CORB
+algorithm.
diff --git a/fetch/corb/css-with-json-parser-breaker.sub.html b/fetch/corb/css-with-json-parser-breaker.sub.html
new file mode 100644
index 0000000..9d930f9
--- /dev/null
+++ b/fetch/corb/css-with-json-parser-breaker.sub.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CORB should not block text/css with a JSON parser breaker</title>
+<link rel="stylesheet" type="text/css"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-with-json-parser-breaker.css">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<body>
+ <h1 id="header">Header example</h1>
+ <p>Paragraph body</p>
+</body>
+<script>
+test(function() {
+ var style = getComputedStyle(document.getElementById('header'));
+ assert_equals(style.getPropertyValue('color'), 'rgb(255, 0, 0)');
+}, "CORB should not block text/css with a JSON parser breaker");
+</script>
diff --git a/fetch/corb/resources/css-with-json-parser-breaker.css b/fetch/corb/resources/css-with-json-parser-breaker.css
new file mode 100644
index 0000000..3ba3365
--- /dev/null
+++ b/fetch/corb/resources/css-with-json-parser-breaker.css
@@ -0,0 +1,3 @@
+)]}'
+{}
+h1 { color: red; }
diff --git a/html/browsers/origin/cross-origin-objects/cross-origin-objects.html b/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
index 2820b75..e0b4b0c 100644
--- a/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
+++ b/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
@@ -11,6 +11,7 @@
<div id=log></div>
<iframe id="B"></iframe>
<iframe id="C"></iframe>
+<iframe id="D"></iframe>
<script>
/*
@@ -21,10 +22,13 @@
setup({explicit_done: true});
path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/frame.html';
+pathWithThen = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/frame-with-then.html';
var B = document.getElementById('B').contentWindow;
var C = document.getElementById('C').contentWindow;
+var D = document.getElementById('D').contentWindow;
B.frameElement.uriToLoad = path;
C.frameElement.uriToLoad = get_host_info().HTTP_REMOTE_ORIGIN + path;
+D.frameElement.uriToLoad = get_host_info().HTTP_REMOTE_ORIGIN + pathWithThen;
function reloadSubframes(cb) {
var iframes = document.getElementsByTagName('iframe');
@@ -45,8 +49,8 @@
*/
var testList = [];
-function addTest(fun, desc) { testList.push([fun, desc]); }
-
+function addTest(func, desc) { testList.push({func, desc, promiseTest: false}); }
+function addPromiseTest(func, desc) { testList.push({func, desc, promiseTest: true}); }
/*
* Basic sanity testing.
@@ -72,10 +76,10 @@
var whitelistedWindowIndices = ['0', '1'];
var whitelistedWindowPropNames = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent',
- 'opener', 'closed', 'close', 'blur', 'focus', 'length'];
+ 'opener', 'closed', 'close', 'blur', 'focus', 'length', 'then'];
whitelistedWindowPropNames = whitelistedWindowPropNames.concat(whitelistedWindowIndices);
whitelistedWindowPropNames.sort();
-var whitelistedLocationPropNames = ['href', 'replace'];
+var whitelistedLocationPropNames = ['href', 'replace', 'then'];
whitelistedLocationPropNames.sort();
var whitelistedSymbols = [Symbol.toStringTag, Symbol.hasInstance,
Symbol.isConcatSpreadable];
@@ -191,7 +195,7 @@
assert_equals(desc.configurable, true, "property descriptor for " + propName + " should be configurable");
if (!isArrayIndexPropertyName) {
assert_equals(desc.enumerable, false, "property descriptor for " + propName + " should not be enumerable");
- if(isSymbol) {
+ if (isSymbol || propName == "then") {
assert_true("value" in desc,
"property descriptor for " + propName + " should be a value descriptor");
assert_equals(desc.value, undefined,
@@ -222,6 +226,10 @@
});
}, "[[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly");
+addTest(function() {
+ assert_equals(typeof D.then, "object");
+}, "[[GetOwnProperty]] - Subframe named 'then' should shadow the default 'then' value");
+
/*
* [[Delete]]
*/
@@ -309,6 +317,10 @@
indexedWindowProps = allWindowProps.slice(0, whitelistedWindowIndices.length);
stringWindowProps = allWindowProps.slice(0, -1 * whitelistedSymbols.length);
symbolWindowProps = allWindowProps.slice(-1 * whitelistedSymbols.length);
+ // stringWindowProps should have "then" last in this case. Do this
+ // check before we call stringWindowProps.sort() below.
+ assert_equals(stringWindowProps[stringWindowProps.length - 1], "then",
+ "'then' property should be added to the end of the string list if not there");
assert_array_equals(indexedWindowProps, whitelistedWindowIndices,
"Reflect.ownKeys should start with the indices exposed on the cross-origin window.");
assert_array_equals(stringWindowProps.sort(), whitelistedWindowPropNames,
@@ -326,6 +338,17 @@
}, "[[OwnPropertyKeys]] should place the symbols after the property names after the subframe indices");
addTest(function() {
+ var stringProps = Object.getOwnPropertyNames(D);
+ // Named frames are not exposed via [[OwnPropertyKeys]].
+ assert_equals(stringProps.indexOf("a"), -1);
+ assert_equals(stringProps.indexOf("b"), -1);
+ assert_equals(typeof D.a, "object");
+ assert_equals(typeof D.b, "object");
+ assert_equals(stringProps[stringProps.length - 1], "then");
+ assert_equals(stringProps.indexOf("then"), stringProps.lastIndexOf("then"));
+}, "[[OwnPropertyKeys]] should not reorder where 'then' appears if it's a named subframe, nor add another copy of 'then'");
+
+addTest(function() {
assert_true(B.eval('parent.C') === C, "A and B observe the same identity for C's Window");
assert_true(B.eval('parent.C.location') === C.location, "A and B observe the same identity for C's Location");
}, "A and B jointly observe the same identity for cross-origin Window and Location");
@@ -393,16 +416,43 @@
assert_equals({}.toString.call(C.location), "[object Object]");
}, "{}.toString.call() does the right thing on cross-origin objects");
+addPromiseTest(function() {
+ return Promise.resolve(C).then((arg) => {
+ assert_equals(arg, C);
+ });
+}, "Resolving a promise with a cross-origin window without a 'then' subframe should work.");
+
+addPromiseTest(function() {
+ return Promise.resolve(D).then((arg) => {
+ assert_equals(arg, D);
+ });
+}, "Resolving a promise with a cross-origin window with a 'then' subframe should work.");
+
+addPromiseTest(function() {
+ return Promise.resolve(D.location).then((arg) => {
+ assert_equals(arg, D.location);
+ });
+}, "Resolving a promise with a cross-origin location should work.");
+
// We do a fresh load of the subframes for each test to minimize side-effects.
// It would be nice to reload ourselves as well, but we can't do that without
// disrupting the test harness.
+function testDone() {
+ if (testList.length != 0) {
+ reloadSubframes(runNextTest);
+ } else {
+ done();
+ }
+}
+
function runNextTest() {
var entry = testList.shift();
- test(() => entry[0](), entry[1])
- if (testList.length != 0)
- reloadSubframes(runNextTest);
- else
- done();
+ if (entry.promiseTest) {
+ promise_test(() => entry.func().finally(testDone), entry.desc);
+ } else {
+ test(entry.func, entry.desc);
+ testDone();
+ }
}
reloadSubframes(runNextTest);
diff --git a/html/browsers/origin/cross-origin-objects/frame-with-then.html b/html/browsers/origin/cross-origin-objects/frame-with-then.html
new file mode 100644
index 0000000..96cdf1e
--- /dev/null
+++ b/html/browsers/origin/cross-origin-objects/frame-with-then.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <body>
+ <!--- Some frames to test ordering -->
+ <iframe name="a"></iframe>
+ <!-- A subframe to test "then" behavior -->
+ <iframe name="then"></iframe>
+ <iframe name="b"></iframe>
+ </body>
+</html>
diff --git a/html/browsers/origin/cross-origin-objects/frame.html b/html/browsers/origin/cross-origin-objects/frame.html
index 341da6a..0d81624 100644
--- a/html/browsers/origin/cross-origin-objects/frame.html
+++ b/html/browsers/origin/cross-origin-objects/frame.html
@@ -6,6 +6,10 @@
// properly ignored cross-origin.
window.frames = "override";
+ // Also add a |then| property to test that it doesn't get exposed.
+ window.then = "something";
+ window.location.then = "something-else";
+
// If we get a postMessage, we grab references to everything and set
// document.domain to trim off our topmost subdomain.
window.onmessage = function(evt) {
diff --git a/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js b/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js
new file mode 100644
index 0000000..6d540ce
--- /dev/null
+++ b/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js
@@ -0,0 +1,38 @@
+[
+ undefined,
+ 42,
+ function() { return "hi" },
+ "hi",
+ {},
+ [],
+ Symbol()
+].forEach(val => {
+ test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ win = frame.contentWindow;
+ t.add_cleanup(() => frame.remove());
+
+ assert_own_property(win, "opener");
+ assert_equals(win.opener, null);
+ const beforeDesc = Object.getOwnPropertyDescriptor(win, "opener"),
+ openerGet = beforeDesc.get,
+ openerSet = beforeDesc.set;
+ assert_own_property(beforeDesc, "get");
+ assert_own_property(beforeDesc, "set");
+ assert_true(beforeDesc.enumerable);
+ assert_true(beforeDesc.configurable);
+
+ win.opener = val;
+ assert_equals(win.opener, val);
+ assert_equals(openerGet(), null);
+
+ const desc = Object.getOwnPropertyDescriptor(win, "opener");
+ assert_equals(desc.value, val);
+ assert_true(desc.writable);
+ assert_true(desc.enumerable);
+ assert_true(desc.configurable);
+
+ openerSet("x");
+ assert_equals(win.opener, "x");
+ }, "Setting window.opener to " + String(val)); // String() needed for symbols
+});
diff --git a/html/dom/documents/dom-tree-accessors/Document.body.html b/html/dom/documents/dom-tree-accessors/Document.body.html
index 7d85488..f421250 100644
--- a/html/dom/documents/dom-tree-accessors/Document.body.html
+++ b/html/dom/documents/dom-tree-accessors/Document.body.html
@@ -216,4 +216,12 @@
assert_equals(f2.nextSibling, f1, "New frameset should have replaced the body");
}, "Setting document.body to a frameset will replace the first existing body/frameset.");
+test(function() {
+ var doc = createDocument();
+ doc.appendChild(doc.createElement("test"));
+ var new_body = doc.createElement("body");
+ doc.body = new_body;
+ assert_equals(doc.documentElement.firstChild, new_body, "new_body should be inserted");
+ assert_equals(doc.body, null, "Getter should return null when the root is not html");
+}, "Setting document.body to a new body element when the root element is a test element.");
</script>
diff --git a/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html b/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html
new file mode 100644
index 0000000..42da515
--- /dev/null
+++ b/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>contentEditable inherit from light tree parent</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#contenteditable">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>You should see the word PASS two times below and no FAIL.</p>
+<div id="host1" contenteditable><div>FAILPASS</div></div>
+<div id="host2" contenteditable><div>FAILPASS</div></div>
+<script>
+ test(() => {
+ const root = host1.attachShadow({mode:"open"});
+ root.innerHTML = "<slot></slot>";
+ const text = host1.firstChild.firstChild;
+ const selection = window.getSelection();
+ selection.collapse(text, 0);
+ selection.extend(text, 4);
+ host1.focus();
+ document.execCommand("delete");
+ host1.blur();
+ assert_equals(text.data, "PASS", "Text should be PASS after FAIL is deleted");
+ }, "Slotted child of contenteditable host should be editable - slot direct child of shadow root");
+
+ test(() => {
+ const root = host2.attachShadow({mode:"open"});
+ root.innerHTML = "<div><slot></slot></div>";
+ const text = host2.firstChild.firstChild;
+ const selection = window.getSelection();
+ selection.collapse(text, 0);
+ selection.extend(text, 4);
+ host2.focus();
+ document.execCommand("delete");
+ host2.blur();
+ assert_equals(text.data, "PASS", "Text should be PASS after FAIL is deleted");
+ }, "Slotted child of contenteditable host should be editable - slot wrapped in shadow tree ancestor");
+</script>
diff --git a/html/infrastructure/common-dom-interfaces/collections/historical.html b/html/infrastructure/common-dom-interfaces/collections/historical.html
index a26dd4c..ef8345a 100644
--- a/html/infrastructure/common-dom-interfaces/collections/historical.html
+++ b/html/infrastructure/common-dom-interfaces/collections/historical.html
@@ -5,6 +5,8 @@
<div id=log></div>
<form id=form><input name=foo></form>
<select id=select><option name=bar></select>
+<div id=dupe>
+<div id=dupe>
<script>
test(function() {
var collection = document.getElementById('form').elements;
@@ -22,4 +24,10 @@
});
}, 'HTMLOptionsCollection legacycaller should not be supported');
+test(function() {
+ var collection = document.all('dupe', 0);
+ // If the second argument were used, it would return the first item of the
+ // collection instead of the whole collection.
+ assert_equals(collection.length, 2, 'length');
+}, 'HTMLAllCollection legacycaller with two arguments should not be supported');
</script>
diff --git a/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html b/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html
index e17c0eb..d425996 100644
--- a/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html
+++ b/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html
@@ -22,6 +22,7 @@
<div id="undefined"></div>
<div id="null"></div>
<div name="divwithname"></div>
+<div id="-0"></div>
<script>
var anchors = document.querySelectorAll("a");
var divs = document.querySelectorAll("div");
@@ -33,19 +34,20 @@
}, "document.all is an HTMLAllCollection");
test(function() {
- assert_equals(document.all.length, 23);
+ assert_equals(document.all.length, 24);
}, "length attribute");
// indexed property getter
test(function() {
assert_equals(document.all[0], document.documentElement);
- assert_equals(document.all[22], scripts[2]);
+ assert_equals(document.all[-0], document.documentElement);
+ assert_equals(document.all[23], scripts[2]);
}, "indexed property getter");
test(function() {
assert_equals(document.all[-1], undefined);
- assert_equals(document.all[23], undefined);
+ assert_equals(document.all[24], undefined);
assert_equals(document.all[42], undefined);
assert_equals(document.all[43], undefined);
assert_equals(document.all[4294967294], undefined);
@@ -84,8 +86,8 @@
test(function() {
assert_equals(document.all["0"], document.documentElement);
- assert_equals(document.all["22"], document.scripts[2]);
- assert_equals(document.all["23"], undefined);
+ assert_equals(document.all["23"], document.scripts[2]);
+ assert_equals(document.all["24"], undefined);
assert_equals(document.all["42"], undefined);
assert_equals(document.all["43"], undefined);
}, "named property getter with \"array index property name\"");
@@ -97,6 +99,7 @@
assert_equals(document.all["4294967294"], undefined);
assert_equals(document.all["4294967295"], divs[1]);
assert_equals(document.all["4294967296"], divs[2]);
+ assert_equals(document.all["-0"], divs[6]);
}, "named property getter with invalid \"array index property name\"");
test(function() {
@@ -130,8 +133,8 @@
test(function() {
assert_equals(document.all.namedItem("0"), null);
- assert_equals(document.all.namedItem("22"), null);
assert_equals(document.all.namedItem("23"), null);
+ assert_equals(document.all.namedItem("24"), null);
assert_equals(document.all.namedItem("42"), spans[0]);
assert_equals(document.all.namedItem("43"), null);
}, "namedItem method with \"array index property name\"");
@@ -143,6 +146,7 @@
assert_equals(document.all.namedItem("4294967294"), divs[0]);
assert_equals(document.all.namedItem("4294967295"), divs[1]);
assert_equals(document.all.namedItem("4294967296"), divs[2]);
+ assert_equals(document.all.namedItem("-0"), divs[6]);
}, "namedItem method with invalid \"array index property name\"");
test(function() {
@@ -183,16 +187,16 @@
test(function() {
assert_equals(document.all("0"), document.documentElement);
- assert_equals(document.all("22"), document.scripts[2]);
- assert_equals(document.all("23"), null);
+ assert_equals(document.all("23"), document.scripts[2]);
+ assert_equals(document.all("24"), null);
assert_equals(document.all("42"), null);
assert_equals(document.all("43"), null);
}, "legacy caller with \"array index property name\"");
test(function() {
assert_equals(document.all(0), document.documentElement);
- assert_equals(document.all(22), document.scripts[2]);
- assert_equals(document.all(23), null);
+ assert_equals(document.all(23), document.scripts[2]);
+ assert_equals(document.all(24), null);
assert_equals(document.all(42), null);
assert_equals(document.all(43), null);
}, "legacy caller with \"array index property name\" as number");
@@ -204,6 +208,7 @@
assert_equals(document.all("4294967294"), null);
assert_equals(document.all("4294967295"), divs[1]);
assert_equals(document.all("4294967296"), divs[2]);
+ assert_equals(document.all("-0"), divs[6]);
}, "legacy caller with invalid \"array index property name\"");
test(function() {
@@ -262,16 +267,16 @@
test(function() {
assert_equals(document.all.item("0"), document.documentElement);
- assert_equals(document.all.item("22"), document.scripts[2]);
- assert_equals(document.all.item("23"), null);
+ assert_equals(document.all.item("23"), document.scripts[2]);
+ assert_equals(document.all.item("24"), null);
assert_equals(document.all.item("42"), null);
assert_equals(document.all.item("43"), null);
}, "item method with \"array index property name\"");
test(function() {
assert_equals(document.all.item(0), document.documentElement);
- assert_equals(document.all.item(22), document.scripts[2]);
- assert_equals(document.all.item(23), null);
+ assert_equals(document.all.item(23), document.scripts[2]);
+ assert_equals(document.all.item(24), null);
assert_equals(document.all.item(42), null);
assert_equals(document.all.item(43), null);
}, "item method with \"array index property name\" as number");
@@ -283,6 +288,7 @@
assert_equals(document.all.item("4294967294"), null);
assert_equals(document.all.item("4294967295"), divs[1]);
assert_equals(document.all.item("4294967296"), divs[2]);
+ assert_equals(document.all.item("-0"), divs[6]);
}, "item method with invalid \"array index property name\"");
test(function() {
diff --git a/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-01.html b/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-01.html
index 38364cd..e6f0c2b 100644
--- a/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-01.html
+++ b/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/document-color-01.html
@@ -7,47 +7,89 @@
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
+function setColorAttributes(doc, color) {
+ doc.fgColor = color;
+ doc.bgColor = color;
+ doc.linkColor = color;
+ doc.vlinkColor = color;
+ doc.alinkColor = color;
+}
+
+function checkColorAttributes(doc, expected) {
+ assert_equals(document.fgColor, expected);
+ assert_equals(document.bgColor, expected);
+ assert_equals(document.linkColor, expected);
+ assert_equals(document.vlinkColor, expected);
+ assert_equals(document.alinkColor, expected);
+}
+
test(function() {
- document.fgColor = "green";
- document.bgColor = "green";
- document.linkColor = "green";
- document.vlinkColor = "green";
- document.alinkColor = "green";
+ setColorAttributes(document, 'green');
var body = document.documentElement.removeChild(document.body);
-
+ this.add_cleanup(function() {
+ // Re-add body and reset color attributes.
+ document.body = body;
+ setColorAttributes(document, '');
+ });
// When there is no body element, the color attributes return an
// empty string upon getting.
- assert_equals(document.fgColor, "");
- assert_equals(document.bgColor, "");
- assert_equals(document.linkColor, "");
- assert_equals(document.vlinkColor, "");
- assert_equals(document.alinkColor, "");
-
- // Re-add body and reset color attributes.
- document.body = body;
- document.fgColor = "";
- document.bgColor = "";
- document.linkColor = "";
- document.vlinkColor = "";
- document.alinkColor = "";
+ checkColorAttributes(document, '');
}, "getting document color attributes with no body");
test(function() {
var body = document.documentElement.removeChild(document.body);
+ this.add_cleanup(function() {
+ document.body = body;
+ });
// When there is no body element, setting the color attributes has no effect.
- document.fgColor = "red";
- document.bgColor = "red";
- document.linkColor = "red";
- document.vlinkColor = "red";
- document.alinkColor = "red";
- assert_equals(document.fgColor, "");
- assert_equals(document.bgColor, "");
- assert_equals(document.linkColor, "");
- assert_equals(document.vlinkColor, "");
- assert_equals(document.alinkColor, "");
-
- document.body = body;
+ setColorAttributes(document, 'red');
+ checkColorAttributes(document, '');
}, "setting document color attributes with no body");
+
+function testBogusRootElement(doc) {
+ doc.replaceChild(doc.createElement('test'), doc.documentElement);
+ var new_body = doc.createElement('body');
+ doc.documentElement.appendChild(new_body);
+
+ setColorAttributes(doc, 'red');
+
+ assert_equals(new_body.attributes.length, 0, 'new_body.attributes.length');
+ checkColorAttributes(doc, '');
+}
+
+function createIframeDoc(markup) {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ var doc = iframe.contentDocument;
+ doc.open();
+ doc.write(markup);
+ doc.close();
+ return doc;
+}
+
+test(function() {
+ // Use standards mode for doc
+ var doc = createIframeDoc('<!doctype html>');
+ testBogusRootElement(doc);
+}, "document color attributes when the root element is a test element (iframe)");
+
+test(function() {
+ var doc = document.implementation.createHTMLDocument();
+ testBogusRootElement(doc);
+}, "document color attributes when the root element is a test element (createHTMLDocument)");
+
+test(function() {
+ var doc = createIframeDoc('<!doctype html><frameset text=red link=red vlink=red alink=red bgcolor=red>');
+ assert_equals(doc.body.attributes.length, 5, 'attributes.length on the frameset');
+ checkColorAttributes(doc, '');
+}, "getting document color attributes when document.body is a frameset");
+
+test(function() {
+ var doc = createIframeDoc('<!doctype html><frameset>');
+ setColorAttributes(doc, 'red');
+ assert_equals(doc.body.attributes.length, 0, 'attributes.length on the frameset');
+ checkColorAttributes(doc, '');
+}, "setting document color attributes when document.body is a frameset");
</script>
diff --git a/html/semantics/embedded-content/media-elements/track/track-element/src-empty-string.html b/html/semantics/embedded-content/media-elements/track/track-element/src-empty-string.html
new file mode 100644
index 0000000..27c76b6
--- /dev/null
+++ b/html/semantics/embedded-content/media-elements/track/track-element/src-empty-string.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>Setting HTMLTrackElement.src to the empty string fires 'error' and sets readyState to ERROR</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/media.html#sourcing-out-of-band-text-tracks">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video></video>
+<script>
+async_test(t => {
+ let track = document.createElement("track");
+ track.src = '';
+ track.default = true;
+ track.onerror = t.step_func_done(() => {
+ assert_equals(track.readyState, HTMLTrackElement.ERROR);
+ });
+ track.onload = t.unreached_func('fired load');
+
+ assert_equals(track.readyState, HTMLTrackElement.NONE);
+
+ document.querySelector('video').appendChild(track);
+});
+</script>
diff --git a/html/semantics/forms/textfieldselection/defaultSelection.html b/html/semantics/forms/textfieldselection/defaultSelection.html
new file mode 100644
index 0000000..eb9bb40
--- /dev/null
+++ b/html/semantics/forms/textfieldselection/defaultSelection.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title></title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<textarea>g</textarea>
+<input type="text" value="foo">
+</input>
+<script>
+test(function() {
+ let textarea = document.querySelector('textarea');
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 0);
+}, "Default selectionStart and selectionEnd for textarea");
+
+test(function() {
+ let textarea = document.querySelector('input');
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 0);
+}, "Default selectionStart and selectionEnd for input");
+
+test(function() {
+ let textarea = document.querySelector('textarea');
+ textarea.value="g";
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 0);
+}, "selectionStart and selectionEnd do not change when same value set again");
+
+test(function() {
+ let textarea = document.querySelector('textarea');
+ textarea.value="G";
+ assert_equals(textarea.selectionStart, 1);
+ assert_equals(textarea.selectionEnd, 1);
+}, "selectionStart and selectionEnd change when value changed to upper case");
+</script>
diff --git a/html/semantics/forms/textfieldselection/setSelectionRange.html b/html/semantics/forms/textfieldselection/setSelectionRange.html
new file mode 100644
index 0000000..bdf52a7
--- /dev/null
+++ b/html/semantics/forms/textfieldselection/setSelectionRange.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title></title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<textarea>
+
+</textarea>
+<script>
+test(function() {
+ let textarea = document.querySelector('textarea');
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 0);
+ textarea.setSelectionRange(0, 1);
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 1);
+}, "setSelectionRange on line boundaries");
+</script>
diff --git a/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py b/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py
new file mode 100644
index 0000000..5df883c
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py
@@ -0,0 +1,4 @@
+def main(request, response):
+ headers = [("Content-Type", "text/javascript"), ("Cache-control", "public, max-age=100")]
+ body = "throw('fox');"
+ return 200, headers, body
diff --git a/html/semantics/scripting-1/the-script-element/emptyish-script-elements.html b/html/semantics/scripting-1/the-script-element/emptyish-script-elements.html
new file mode 100644
index 0000000..37f4a87
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/emptyish-script-elements.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Treatment of various empty-ish script elements</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#already-started">
+<link rel="help" href="https://github.com/whatwg/html/issues/3419">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script id="no-children"></script>
+<script id="whitespace-child"> </script>
+
+<script id="gets-a-no-text-child"></script>
+<script id="gets-an-empty-text-child"></script>
+<script id="gets-a-text-child"></script>
+<script id="gets-a-comment-child"></script>
+<script id="gets-a-text-descendant"></script>
+
+<script>
+"use strict";
+
+test(() => {
+ const el = document.querySelector("#no-children");
+ el.appendChild(document.createTextNode("window.noChildrenExecuted = true;"));
+ assert_true(window.noChildrenExecuted);
+}, "A script with no children bails early, before setting already-started, so can be executed when adding text");
+
+test(() => {
+ const el = document.querySelector("#whitespace-child");
+ el.appendChild(document.createTextNode("window.whitespaceChildExecuted = true;"));
+ assert_equals(window.whitespaceChildExecuted, undefined);
+}, "A script with a whitespace child executes, setting already-started, so adding text is a no-op");
+
+test(() => {
+ const el = document.querySelector("#gets-a-no-text-child");
+ el.appendChild(document.createElement("span"));
+ el.appendChild(document.createTextNode("window.getsANoTextChildExecuted = true;"));
+ assert_true(window.getsANoTextChildExecuted);
+}, "A script with an empty element inserted bails early, before setting already-started, so can be executed when adding text");
+
+test(() => {
+ const el = document.querySelector("#gets-an-empty-text-child");
+ el.appendChild(document.createTextNode(""));
+ el.appendChild(document.createTextNode("window.getsAnEmptyTextChildExecuted = true;"));
+ assert_true(window.getsAnEmptyTextChildExecuted);
+}, "A script with an empty text node inserted bails early, before setting already-started, so can be executed when adding text");
+
+test(() => {
+ const el = document.querySelector("#gets-a-text-child");
+ el.appendChild(document.createTextNode("window.getsATextChildExecuted1 = true;"));
+ el.appendChild(document.createTextNode("window.getsATextChildExecuted2 = true;"));
+ assert_true(window.getsATextChildExecuted1);
+ assert_equals(window.getsATextChildExecuted2, undefined);
+}, "A script with a text child inserted executes, setting already-started, so adding text is a no-op");
+
+test(() => {
+ const el = document.querySelector("#gets-a-comment-child");
+ el.appendChild(document.createComment("window.getsACommentChild1 = true;"));
+ el.appendChild(document.createTextNode("window.getsACommentChild2 = true;"));
+ assert_equals(window.getsACommentChild1, undefined);
+ assert_true(window.getsACommentChild2);
+}, "A script with a comment child inserted bails early, before setting already-started, so can be executed when adding text");
+
+test(() => {
+ const el = document.querySelector("#gets-a-text-descendant");
+ const child = document.createElement("span");
+ child.appendChild(document.createTextNode("window.getsATextDescendantExecuted1 = true;"));
+ el.appendChild(child);
+ el.appendChild(document.createTextNode("window.getsATextDescendantExecuted2 = true;"));
+ assert_equals(window.getsATextDescendantExecuted1, undefined);
+ assert_true(window.getsATextDescendantExecuted2);
+}, "A script with an element containing text inserted bails early, before setting already-started, so can be executed when adding text");
+</script>
diff --git a/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html b/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html
new file mode 100644
index 0000000..255e79e
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<script src="cacheable-script-throw.py?iframe"></script>
diff --git a/html/semantics/scripting-1/the-script-element/muted-errors.sub.html b/html/semantics/scripting-1/the-script-element/muted-errors.sub.html
new file mode 100644
index 0000000..a42179d
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/muted-errors.sub.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<title>Muted Errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// https://html.spec.whatwg.org/#report-the-error
+// If script's muted errors is true, then set message to "Script error.",
+// urlString to the empty string, line and col to 0, and errorValue to null.
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+ window.addEventListener("error", ev => log.push(ev));
+
+ function check(shouldBeMuted) {
+ assert_equals(log.length, 1);
+ var ev = log[0];
+ log = [];
+ if (shouldBeMuted) {
+ assert_equals(ev.message, "Script error.");
+ assert_equals(ev.error, null, 'error');
+ assert_equals(ev.filename, "", 'filename');
+ assert_equals(ev.lineno, 0, 'lineno');
+ assert_equals(ev.colno, 0, 'colno');
+ } else {
+ assert_not_equals(ev.message, "Script error.");
+ assert_not_equals(ev.error, null);
+ }
+ }
+
+ var test1 = async_test("Errors for same-origin script shouldn't be muted");
+ var check1 = test1.step_func_done(() => check(false));
+
+ var test2 = async_test("Errors for cross-origin script should be muted");
+ var check2 = test2.step_func_done(() => check(true));
+
+ var test3 = async_test("Errors for cross-origin script should be muted " +
+ "even if the script is once loaded as same-origin");
+ function step3() {
+ var script = document.createElement('script');
+ script.setAttribute('src', "//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py?iframe");
+ script.onerror = test3.unreached_func();
+ script.onload = test3.step_func_done(() => check(true));
+ document.body.appendChild(script);
+ }
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script src="cacheable-script-throw.py" onerror="test1.unreached_func()()" onload="check1()"></script>
+<script src="//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py"
+ onerror="test2.unreached_func()()" onload="check2()"></script>
+<iframe src="//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html"
+ onerror="test3.unreached_func()()" onload="step3()"></iframe>
diff --git a/interfaces/accelerometer.idl b/interfaces/accelerometer.idl
index df78885..7e5509d 100644
--- a/interfaces/accelerometer.idl
+++ b/interfaces/accelerometer.idl
@@ -1,11 +1,17 @@
-[Constructor(optional SensorOptions options), SecureContext, Exposed=Window]
+enum LocalCoordinateSystem { "device", "screen" };
+
+dictionary SpatialSensorOptions : SensorOptions {
+ LocalCoordinateSystem referenceFrame = "device";
+};
+
+[Constructor(optional SpatialSensorOptions options), SecureContext, Exposed=Window]
interface Accelerometer : Sensor {
readonly attribute double? x;
readonly attribute double? y;
readonly attribute double? z;
};
-[Constructor(optional SensorOptions options), SecureContext, Exposed=Window]
+[Constructor(optional SpatialSensorOptions options), SecureContext, Exposed=Window]
interface LinearAccelerationSensor : Accelerometer {
};
diff --git a/lint.whitelist b/lint.whitelist
index 2f9b44d..d3dc428 100644
--- a/lint.whitelist
+++ b/lint.whitelist
@@ -225,6 +225,7 @@
SET TIMEOUT: user-timing/*
SET TIMEOUT: webaudio/js/lodash.js
SET TIMEOUT: webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
+SET TIMEOUT: webauthn/*timeout.https.html
SET TIMEOUT: webdriver/*
SET TIMEOUT: webmessaging/*
SET TIMEOUT: websockets/*
@@ -793,6 +794,8 @@
CSS-COLLIDING-REF-NAME: css/CSS2/ui/overflow-applies-to-001-ref.xht
CSS-COLLIDING-REF-NAME: css/CSS2/visuren/inline-formatting-context-001-ref.xht
CSS-COLLIDING-REF-NAME: css/CSS2/linebox/inline-formatting-context-001-ref.xht
+CSS-COLLIDING-REF-NAME: css/css-transforms/individual-transform/individual-transform-1-ref.html
+CSS-COLLIDING-REF-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/transforms/individual-transform-1-ref.html
CSS-COLLIDING-SUPPORT-NAME: css/css-backgrounds/support/red.png
CSS-COLLIDING-SUPPORT-NAME: css/compositing/mix-blend-mode/support/red.png
CSS-COLLIDING-SUPPORT-NAME: css/compositing/background-blending/support/red.png
diff --git a/media/foo-no-cors.vtt b/media/foo-no-cors.vtt
new file mode 100644
index 0000000..b533895
--- /dev/null
+++ b/media/foo-no-cors.vtt
@@ -0,0 +1,4 @@
+WEBVTT
+
+00:00:00.000 --> 00:00:05.000
+Foo
diff --git a/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html b/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
new file mode 100644
index 0000000..e75fb44
--- /dev/null
+++ b/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>MediaStreamTrack GetCapabilities</title>
+<p class="instructions">This test checks for the presence of
+<code>echoCancellation</code> and <code>deviceId</code> fields
+in <code>MediaStreamTrack.getCapabilities()</code> method.</p>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+ promise_test(() => {
+ return navigator.mediaDevices.getUserMedia({audio: true})
+ .then(stream => {
+ var capabilities = stream.getAudioTracks()[0].getCapabilities();
+ assert_true(undefined !== capabilities.deviceId, "MediaTrackCapabilities's deviceId should exist.");
+ assert_true(undefined !== capabilities.echoCancellation, "MediaTrackCapabilities's echoCancellation should exist.");
+ });
+});
+</script>
diff --git a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
index 57210ef..ef66d5e 100644
--- a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
+++ b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
@@ -16,17 +16,16 @@
var offscreenCanvas = new OffscreenCanvas(100, 50);
var ctx = offscreenCanvas.getContext('2d');
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
-_assertPixelApprox(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
t.done();
diff --git a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
index 45dfff6..3a17cfe 100644
--- a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
+++ b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
@@ -12,17 +12,16 @@
var offscreenCanvas = new OffscreenCanvas(100, 50);
var ctx = offscreenCanvas.getContext('2d');
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
-_assertPixelApprox(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
t.done();
diff --git a/offscreen-canvas/tools/tests2d.yaml b/offscreen-canvas/tools/tests2d.yaml
index fc3b158..f542d3c 100644
--- a/offscreen-canvas/tools/tests2d.yaml
+++ b/offscreen-canvas/tools/tests2d.yaml
@@ -4417,17 +4417,16 @@
testing:
- 2d.drawImage.zerocanvas
code: |
- ctx.fillStyle = '#0f0';
- ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
- ctx.drawImage(offscreenCanvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
- ctx.drawImage(offscreenCanvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
- ctx.drawImage(offscreenCanvas2, 0, 0);
- @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
- name: 2d.drawImage.wrongtype
desc: Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError
diff --git a/picture-in-picture/not-processing-user-gesture.html b/picture-in-picture/not-processing-user-gesture.html
deleted file mode 100644
index 0075894..0000000
--- a/picture-in-picture/not-processing-user-gesture.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<title>Test request Picture-in-Picture requires a user gesture</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body></body>
-<script>
-promise_test(t => {
- return promise_rejects(t, 'NotAllowedError',
- document.createElement('video').requestPictureInPicture());
-}, );
-</script>
diff --git a/picture-in-picture/picture-in-picture-window.html b/picture-in-picture/picture-in-picture-window.html
new file mode 100644
index 0000000..4bee95d
--- /dev/null
+++ b/picture-in-picture/picture-in-picture-window.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Test Picture-in-Picture window</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/picture-in-picture-helpers.js"></script>
+<body></body>
+<script>
+promise_test(t => {
+ return requestPictureInPictureWithTrustedClick(document.createElement('video'))
+ .then(pipWindow => {
+ assert_not_equals(pipWindow.width, 0);
+ assert_not_equals(pipWindow.height, 0);
+ });
+}, 'Picture-in-Picture window dimensions are set after entering Picture-in-Picture');
+
+promise_test(t => {
+ const video1 = document.createElement('video');
+ const video2 = document.createElement('video');
+ return requestPictureInPictureWithTrustedClick(video1)
+ .then(pipWindow1 => {
+ return requestPictureInPictureWithTrustedClick(video2)
+ .then(pipWindow2 => {
+ assert_equals(pipWindow1.width, 0);
+ assert_equals(pipWindow1.height, 0);
+ assert_not_equals(pipWindow2.width, 0);
+ assert_not_equals(pipWindow2.height, 0);
+ });
+ });
+}, 'Picture-in-Picture window dimensions are set to 0 after entering ' +
+ 'Picture-in-Picture for another video');
+
+promise_test(t => {
+ return requestPictureInPictureWithTrustedClick(document.createElement('video'))
+ .then(pipWindow => {
+ return document.exitPictureInPicture()
+ .then(() => {
+ assert_equals(pipWindow.width, 0);
+ assert_equals(pipWindow.height, 0);
+ });
+ })
+}, 'Picture-in-Picture window dimensions are set to 0 after exiting Picture-in-Picture');
+
+promise_test(t => {
+ const video = document.createElement('video');
+ let thePipWindow;
+
+ video.addEventListener('leavepictureinpicture', t.step_func_done(event => {
+ assert_equals(thePipWindow.width, 0);
+ assert_equals(thePipWindow.height, 0);
+ }));
+
+ return requestPictureInPictureWithTrustedClick(video)
+ .then(pipWindow => {
+ thePipWindow = pipWindow;
+ video.disablePictureInPicture = true;
+ });
+}, 'Picture-in-Picture window dimensions are set to 0 if ' +
+ 'disablePictureInPicture becomes true');
+</script>
diff --git a/picture-in-picture/request-picture-in-picture.html b/picture-in-picture/request-picture-in-picture.html
index eaabcb7..32bbfc2 100644
--- a/picture-in-picture/request-picture-in-picture.html
+++ b/picture-in-picture/request-picture-in-picture.html
@@ -9,5 +9,21 @@
<script>
promise_test(t => {
return requestPictureInPictureWithTrustedClick(document.createElement('video'));
-});
+}, 'request Picture-in-Picture resolves on user click');
+
+promise_test(t => {
+ return promise_rejects(t, 'NotAllowedError',
+ document.createElement('video').requestPictureInPicture());
+}, 'request Picture-in-Picture requires a user gesture');
+
+promise_test(t => {
+ return callWithTrustedClick(() => {
+ const first = document.createElement('video').requestPictureInPicture();
+ const second = document.createElement('video').requestPictureInPicture();
+ return Promise.all([
+ first,
+ promise_rejects(t, 'NotAllowedError', second)
+ ]);
+ });
+}, 'request Picture-in-Picture consumes user gesture');
</script>
diff --git a/picture-in-picture/shadow-dom.html b/picture-in-picture/shadow-dom.html
new file mode 100644
index 0000000..4f4c955
--- /dev/null
+++ b/picture-in-picture/shadow-dom.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>Test for pictureInPictureElement adjustment for Shadow DOM</title>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/picture-in-picture-helpers.js"></script>
+<script src='../shadow-dom/resources/shadow-dom.js'></script>
+<body>
+<div id='host'>
+ <template data-mode='open' id='root'>
+ <slot></slot>
+ </template>
+ <div id='host2'>
+ <template data-mode='open' id='root2'>
+ <div id='host3'>
+ <template data-mode='open' id='root3'>
+ <video id='video'></video>
+ <div id='host4'>
+ <template data-mode='open' id='root4'>
+ <div></div>
+ </template>
+ </div>
+ </template>
+ </div>
+ <div id='host5'>
+ <template data-mode='open' id='root5'>
+ <div></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+</body>
+<script>
+promise_test(t => {
+ const ids = createTestTree(host);
+ document.body.appendChild(ids.host);
+
+ assert_equals(document.pictureInPictureElement, null);
+ assert_equals(ids.root.pictureInPictureElement, null);
+ assert_equals(ids.root2.pictureInPictureElement, null);
+ assert_equals(ids.root3.pictureInPictureElement, null);
+ assert_equals(ids.root4.pictureInPictureElement, null);
+ assert_equals(ids.root5.pictureInPictureElement, null);
+
+ return requestPictureInPictureWithTrustedClick(ids.video)
+ .then(() => {
+ assert_equals(document.pictureInPictureElement, ids.host2);
+ assert_equals(ids.root.pictureInPictureElement, null);
+ assert_equals(ids.root2.pictureInPictureElement, ids.host3);
+ assert_equals(ids.root3.pictureInPictureElement, ids.video);
+ assert_equals(ids.root4.pictureInPictureElement, null);
+ assert_equals(ids.root5.pictureInPictureElement, null);
+ })
+});
+</script>
\ No newline at end of file
diff --git a/pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html b/pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html
index 92fe7f2..8ac35f8 100644
--- a/pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html
+++ b/pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html
@@ -20,7 +20,7 @@
var test_pointerEvent = setup_pointerevent_test("no pointercapture while pointerlock", ['mouse']);
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
-
+
on_event(div1, 'pointerdown', function(event) {
div2.setPointerCapture(event.pointerId);
});
@@ -33,8 +33,11 @@
test_pointerEvent.done();
}
});
+ on_event(document, 'contextmenu', function(event) {
+ event.preventDefault();
+ });
on_event(div2, 'pointermove', function(event) {
- if (got_capture && !lock_requested) {
+ if (event.button == 2 && got_capture && !lock_requested) {
div1.requestPointerLock();
lock_requested = true;
}
@@ -45,6 +48,9 @@
on_event(div2, 'lostpointercapture', function(event) {
lost_capture = true;
});
+ on_event(document,"pointerlockerror", function() {
+ assert_unreached("Pointer lock error");
+ })
}
</script>
</head>
@@ -56,6 +62,8 @@
<ol>
<li>Press left button down on the green rectangle and hold it.</li>
<li>Move the mouse inside the green rectangle.</li>
+ <li>Click right button while keeping left button down</li>
+ <li>Keep moving the mouse inside the green rectangle.</li>
</ol>
Test passes if the pointer capture is released on the yellow rectangle when the green rectangle gets the pointer lock.
diff --git a/resource-timing/clear_resource_timing_functionality.html b/resource-timing/clear_resource_timing_functionality.html
new file mode 100644
index 0000000..eaf21b4
--- /dev/null
+++ b/resource-timing/clear_resource_timing_functionality.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>This test validates the functionality of clearResourceTimings method in resource timing.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+<script>
+ setup({ explicit_done: true });
+ const context = new PerformanceContext(performance);
+ function onload_test()
+ {
+ test_equals(context.getEntriesByType('resource').length, 4, 4 + ' resource timing entries should be stored in this page.');
+ context.clearResourceTimings();
+ test_equals(context.getEntriesByType('resource').length, 0, 'No resource timing entries should be stored after clearResourceTimings.');
+ done();
+ }
+</script>
+</head>
+<body onload=onload_test()>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_TAO_cross_origin_redirect.html b/resource-timing/resource_timing_TAO_cross_origin_redirect.html
new file mode 100644
index 0000000..a91eaf8
--- /dev/null
+++ b/resource-timing/resource_timing_TAO_cross_origin_redirect.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>This test validates the values in resource timing for a timing allowed cross-origin redirect.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+
+<script>
+ setup({explicit_done: true});
+ function onload_test() {
+ const context = new PerformanceContext(performance);
+ const entry = context.getEntriesByName(document.getElementById('frameContext').src, 'resource')[0];
+
+ test_greater_than(entry.redirectStart, 0, 'redirectStart should be greater than 0 in timing allowed cross-origin redirect.');
+ test_equals(entry.redirectStart, entry.startTime, 'redirectStart should be equal to startTime in timing allowed cross-origin redirect.');
+ test_greater_or_equals(entry.redirectEnd, entry.redirectStart, 'redirectEnd should be no less than redirectStart in timing allowed cross-origin redirect.');
+ test_greater_or_equals(entry.fetchStart, entry.redirectEnd, 'fetchStart should be no less than redirectEnd in timing allowed cross-origin redirect.');
+ done();
+ }
+</script>
+
+</head>
+<body>
+<iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
+<script>
+ const destUrl = '/common/redirect.py?location=/resource-timing/resources/iframe_TAO_match_origin.html';
+
+ const frameContext = document.getElementById('frameContext');
+ frameContext.onload = onload_test;
+ frameContext.src = destUrl;
+</script>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_buffer_full_when_populate_entries.html b/resource-timing/resource_timing_buffer_full_when_populate_entries.html
new file mode 100644
index 0000000..3e62b19
--- /dev/null
+++ b/resource-timing/resource_timing_buffer_full_when_populate_entries.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<title>This test validates the functionality of onresourcetimingbufferfull in resource timing.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+</head>
+<body onload=onload_test()>
+<script>
+ const context = new PerformanceContext(performance);
+ const bufferSize = 5;
+ context.setResourceTimingBufferSize(bufferSize);
+ let bufferFullCount = 0;
+ function buffer_full_callback() {
+ bufferFullCount++;
+ }
+ context.registerResourceTimingBufferFullCallback(buffer_full_callback);
+ // Scripts appended in JS to ensure setResourceTimingBufferSize is called before.
+ function appendScript(src) {
+ const script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = src;
+ document.body.appendChild(script);
+ }
+ appendScript('resources/empty.js');
+ appendScript('resources/empty_script.js');
+ appendScript('resources/resource_timing_test0.js');
+ setup({ explicit_done: true });
+ function onload_test() {
+ test_equals(context.getEntriesByType('resource').length, bufferSize, 'There should only be |bufferSize| resource entries.');
+ test_equals(bufferFullCount, 1, 'onresourcetimingbufferfull should have been invoked once buffer is full.');
+ done();
+ }
+</script>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_buffer_full_when_shrink_buffer_size.html b/resource-timing/resource_timing_buffer_full_when_shrink_buffer_size.html
new file mode 100644
index 0000000..e42c19d
--- /dev/null
+++ b/resource-timing/resource_timing_buffer_full_when_shrink_buffer_size.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>This test validates the functionality of onresourcetimingbufferfull in resource timing.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+<script>
+ const context = new PerformanceContext(performance);
+ let bufferFullCount = 0;
+ function buffer_full_call_back() {
+ bufferFullCount++;
+ }
+ context.registerResourceTimingBufferFullCallback(buffer_full_call_back);
+ setup({ explicit_done: true });
+ function onload_test() {
+ context.setResourceTimingBufferSize(3);
+ context.setResourceTimingBufferSize(0);
+ test_equals(context.getEntriesByType('resource').length, 4, 'There are 4 scripts, and setResourceTimingBufferSize does not reduce the size.');
+ test_equals(bufferFullCount, 0, 'onresourcetimingbufferfull should not be invoked during setResourceTimingBufferSize.');
+ done();
+ }
+</script>
+</head>
+<body onload=onload_test()>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_cross_origin_redirect.html b/resource-timing/resource_timing_cross_origin_redirect.html
new file mode 100644
index 0000000..9342f5b
--- /dev/null
+++ b/resource-timing/resource_timing_cross_origin_redirect.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>This test validates the values in resource timing for a cross-origin redirect.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+
+<script>
+ setup({explicit_done: true});
+ function onload_test() {
+ const context = new PerformanceContext(performance);
+ const entry = context.getEntriesByName(document.getElementById('frameContext').src, 'resource')[0];
+
+ test_equals(entry.redirectStart, 0, 'redirectStart should be 0 in cross-origin redirect.');
+ test_equals(entry.redirectEnd, 0, 'redirectEnd should be 0 in cross-origin redirect.');
+ test_equals(entry.domainLookupStart, 0, 'domainLookupStart should be 0 in cross-origin redirect.');
+ test_equals(entry.domainLookupEnd, 0, 'domainLookupEnd should be 0 in cross-origin redirect.');
+ test_equals(entry.connectStart, 0, 'connectStart should be 0 in cross-origin redirect.');
+ test_equals(entry.connectEnd, 0, 'connectEnd should be 0 in cross-origin redirect.');
+ test_equals(entry.requestStart, 0, 'requestStart should be 0 in cross-origin redirect.');
+ test_equals(entry.responseStart, 0, 'responseStart should be 0 in cross-origin redirect.');
+ test_equals(entry.secureConnectionStart, 0, 'secureConnectionStart should be 0 in cross-origin redirect.');
+ test_greater_than(entry.fetchStart, 0, 'fetchStart should be greater than 0 in cross-origin redirect.');
+ test_greater_than(entry.responseEnd, 0, 'responseEnd should be greater than 0 in cross-origin redirect.');
+ done();
+ }
+</script>
+</head>
+<body>
+<iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
+<script>
+ let destUrl = '/common/redirect.py?location=';
+ // Add www to get a cross origin frame.
+ destUrl += 'http://www.' + document.location.host + '/resource-timing/resources/blank_page_green.htm';
+
+ const frameContext = document.getElementById('frameContext');
+ frameContext.onload = onload_test;
+ frameContext.src = destUrl;
+</script>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_same_origin_redirect.html b/resource-timing/resource_timing_same_origin_redirect.html
new file mode 100644
index 0000000..d9fbf94
--- /dev/null
+++ b/resource-timing/resource_timing_same_origin_redirect.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>This test validates the values of the redirectStart/End in resource timing for a same-origin resource redirect.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+
+<script>
+ setup({explicit_done: true});
+ function onload_test() {
+ const context = new PerformanceContext(performance);
+ const entry = context.getEntriesByName(document.getElementById('frameContext').src, 'resource')[0];
+
+ test_greater_than(entry.redirectStart, 0, 'redirectStart should be greater than 0 in same-origin redirect.');
+ test_equals(entry.redirectStart, entry.startTime, 'redirectStart should be equal to startTime in same-origin redirect.');
+ test_noless_than(entry.redirectEnd, entry.redirectStart, 'redirectEnd should be no less than redirectStart in same-origin redirect.');
+ test_noless_than(entry.fetchStart, entry.redirectEnd, 'fetchStart should be no less than redirectEnd in same-origin redirect.');
+ done();
+ }
+</script>
+
+</head>
+<body>
+<iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
+<script>
+ let destUrl = '/common/redirect.py';
+ destUrl += '?location=/resource-timing/resources/blank_page_green.htm';
+
+ const frameContext = document.getElementById('frameContext');
+ frameContext.onload = onload_test;
+ frameContext.src = destUrl;
+</script>
+</body>
+</html>
diff --git a/resource-timing/resource_timing_store_and_clear_during_callback.html b/resource-timing/resource_timing_store_and_clear_during_callback.html
new file mode 100644
index 0000000..218fc0c
--- /dev/null
+++ b/resource-timing/resource_timing_store_and_clear_during_callback.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head onload>
+<meta charset="utf-8" />
+<title>This test validates the behavior of read and clear operation in onresourcetimingbufferfull callback of resource timing.</title>
+<link rel="author" title="Intel" href="http://www.intel.com/" />
+<link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+</head>
+<body onload=onload_test()>
+<script>
+ const context = new PerformanceContext(performance);
+ const resource_timing_buffer_size = 1;
+ let global_buffer = [];
+ function store_and_clear() {
+ const entryList = context.getEntriesByType('resource');
+ entryList.forEach(function (entry) {
+ global_buffer.push(entry);
+ });
+ context.clearResourceTimings();
+ }
+ context.registerResourceTimingBufferFullCallback(store_and_clear);
+ context.setResourceTimingBufferSize(resource_timing_buffer_size);
+ // Scripts appended in JS to ensure setResourceTimingBufferSize is called before.
+ function appendScript(src) {
+ const script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = src;
+ document.body.appendChild(script);
+ }
+ appendScript('resources/empty.js');
+ appendScript('resources/empty_script.js');
+ appendScript('resources/resource_timing_test0.js');
+ setup({ explicit_done: true });
+ function onload_test() {
+ test_equals(context.getEntriesByType('resource').length, 0, 'No entry should be stored in resource timing buffer since its cleared once an item arrived.');
+ // The entry for empty.js must not be in the global buffer, but all others should be.
+ test_equals(global_buffer.length, 6, '6 resource timing entries should be moved to global buffer.');
+ const index = window.location.pathname.lastIndexOf('resource-timing');
+ const pathname = window.location.pathname.substring(0, index);
+ let expected_entries = {};
+ expected_entries[pathname + 'resources/testharness.js'] = 'script';
+ expected_entries[pathname + 'resources/testharnessreport.js'] = 'script';
+ expected_entries[pathname + 'resource-timing/resources/webperftestharness.js'] = 'script';
+ expected_entries[pathname + 'resource-timing/resources/webperftestharnessextension.js'] = 'script';
+ expected_entries[pathname + 'resource-timing/resources/empty_script.js'] = 'script';
+ expected_entries[pathname + 'resource-timing/resources/resource_timing_test0.js'] = 'script';
+ test_resource_entries(global_buffer, expected_entries);
+ done();
+ }
+</script>
+</body>
+</html>
diff --git a/service-workers/cache-storage/script-tests/cache-put.js b/service-workers/cache-storage/script-tests/cache-put.js
index 467e0b3..38d2564 100644
--- a/service-workers/cache-storage/script-tests/cache-put.js
+++ b/service-workers/cache-storage/script-tests/cache-put.js
@@ -335,4 +335,12 @@
});
}, 'Cache.put should store Response.redirect() correctly');
+cache_test(async (cache) => {
+ var request = new Request(test_url);
+ var response = new Response(new Blob([test_body]));
+ await cache.put(request, response);
+ var cachedResponse = await cache.match(request);
+ assert_equals(await cachedResponse.text(), test_body);
+ }, 'Cache.put called with simple Request and blob Response');
+
done();
diff --git a/service-workers/cache-storage/window/cache-put.https.html b/service-workers/cache-storage/window/cache-put.https.html
index ded6e84..1ee14bd 100644
--- a/service-workers/cache-storage/window/cache-put.https.html
+++ b/service-workers/cache-storage/window/cache-put.https.html
@@ -6,3 +6,16 @@
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helpers.js"></script>
<script src="../script-tests/cache-put.js"></script>
+<script>
+cache_test(async (cache) => {
+ var formData = new FormData();
+ formData.append("name", "value");
+
+ var request = new Request(test_url);
+ var response = new Response(formData);
+ await cache.put(request, response);
+ var cachedResponse = await cache.match(request);
+ var cachedResponseText = await cachedResponse.text();
+ assert_true(cachedResponseText.indexOf("name=\"name\"\r\n\r\nvalue") !== -1);
+ }, 'Cache.put called with simple Request and form data Response');
+</script>
diff --git a/service-workers/service-worker/fetch-request-redirect.https.html b/service-workers/service-worker/fetch-request-redirect.https.html
index 18bfa61..e8e90cf 100644
--- a/service-workers/service-worker/fetch-request-redirect.https.html
+++ b/service-workers/service-worker/fetch-request-redirect.https.html
@@ -4,19 +4,22 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/media.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
-
+var test_scope = ""
function assert_resolves(promise, description) {
- return promise.catch(function(reason) {
- throw new Error(description + ' - ' + reason.message);
- });
+ return promise.then(
+ () => test(() => {}, description + " - " + test_scope),
+ (e) => test(() => { throw e; }, description + " - " + test_scope)
+ );
}
function assert_rejects(promise, description) {
- return promise.then(
- function() { throw new Error(description); },
- function() {});
+ return promise.then(
+ () => test(() => { assert_unreached(); }, description + " - " + test_scope),
+ () => test(() => {}, description + " - " + test_scope)
+ );
}
function iframe_test(url, timeout_enabled) {
@@ -52,11 +55,13 @@
}
promise_test(function(t) {
+ test_scope = "default";
+
var SCOPE = 'resources/fetch-request-redirect-iframe.html';
var SCRIPT = 'resources/fetch-rewrite-worker.js';
var REDIRECT_URL = base_path() + 'resources/redirect.py?Redirect=';
var IMAGE_URL = base_path() + 'resources/square.png';
- var AUDIO_URL = base_path() + 'resources/silence.oga';
+ var AUDIO_URL = getAudioURI("/media/sound_5");
var XHR_URL = base_path() + 'resources/simple.txt';
var HTML_URL = base_path() + 'resources/dummy.html';
@@ -73,108 +78,106 @@
return wait_for_state(t, worker, 'activated');
})
.then(function() { return with_iframe(SCOPE); })
- .then(function(f) {
- frame = f;
- return Promise.all([
+ .then(async function(f) {
+ frame = f;
// XMLHttpRequest tests.
- assert_resolves(frame.contentWindow.xhr(XHR_URL),
- 'Normal XHR should succeed.'),
- assert_resolves(frame.contentWindow.xhr(REDIRECT_TO_XHR_URL),
- 'Redirected XHR should succeed.'),
- assert_resolves(
+ await assert_resolves(frame.contentWindow.xhr(XHR_URL),
+ 'Normal XHR should succeed.');
+ await assert_resolves(frame.contentWindow.xhr(REDIRECT_TO_XHR_URL),
+ 'Redirected XHR should succeed.');
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&redirect-mode=follow'),
- 'Redirected XHR with Request.redirect=follow should succeed.'),
- assert_rejects(
+ 'Redirected XHR with Request.redirect=follow should succeed.');
+ await assert_rejects(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&redirect-mode=error'),
- 'Redirected XHR with Request.redirect=error should fail.'),
- assert_rejects(
+ 'Redirected XHR with Request.redirect=error should fail.');
+ await assert_rejects(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&redirect-mode=manual'),
- 'Redirected XHR with Request.redirect=manual should fail.'),
+ 'Redirected XHR with Request.redirect=manual should fail.');
// Image loading tests.
- assert_resolves(frame.contentWindow.load_image(IMAGE_URL),
- 'Normal image resource should be loaded.'),
- assert_resolves(
+ await assert_resolves(frame.contentWindow.load_image(IMAGE_URL),
+ 'Normal image resource should be loaded.');
+ await assert_resolves(
frame.contentWindow.load_image(REDIRECT_TO_IMAGE_URL),
- 'Redirected image resource should be loaded.'),
- assert_resolves(
+ 'Redirected image resource should be loaded.');
+ await assert_resolves(
frame.contentWindow.load_image(
'./?url=' + encodeURIComponent(REDIRECT_TO_IMAGE_URL) +
'&redirect-mode=follow'),
'Loading redirected image with Request.redirect=follow should' +
- ' succeed.'),
- assert_rejects(
+ ' succeed.');
+ await assert_rejects(
frame.contentWindow.load_image(
'./?url=' + encodeURIComponent(REDIRECT_TO_IMAGE_URL) +
'&redirect-mode=error'),
'Loading redirected image with Request.redirect=error should ' +
- 'fail.'),
- assert_rejects(
+ 'fail.');
+ await assert_rejects(
frame.contentWindow.load_image(
'./?url=' + encodeURIComponent(REDIRECT_TO_IMAGE_URL) +
'&redirect-mode=manual'),
'Loading redirected image with Request.redirect=manual should' +
- ' fail.'),
+ ' fail.');
// Audio loading tests.
- assert_resolves(frame.contentWindow.load_audio(AUDIO_URL),
- 'Normal audio resource should be loaded.'),
- assert_resolves(
+ await assert_resolves(frame.contentWindow.load_audio(AUDIO_URL),
+ 'Normal audio resource should be loaded.');
+ await assert_resolves(
frame.contentWindow.load_audio(REDIRECT_TO_AUDIO_URL),
- 'Redirected audio resource should be loaded.'),
- assert_resolves(
+ 'Redirected audio resource should be loaded.');
+ await assert_resolves(
frame.contentWindow.load_audio(
'./?url=' + encodeURIComponent(REDIRECT_TO_AUDIO_URL) +
'&redirect-mode=follow'),
'Loading redirected audio with Request.redirect=follow should' +
- ' succeed.'),
- assert_rejects(
+ ' succeed.');
+ await assert_rejects(
frame.contentWindow.load_audio(
'./?url=' + encodeURIComponent(REDIRECT_TO_AUDIO_URL) +
'&redirect-mode=error'),
'Loading redirected audio with Request.redirect=error should ' +
- 'fail.'),
- assert_rejects(
+ 'fail.');
+ await assert_rejects(
frame.contentWindow.load_audio(
'./?url=' + encodeURIComponent(REDIRECT_TO_AUDIO_URL) +
'&redirect-mode=manual'),
'Loading redirected audio with Request.redirect=manual should' +
- ' fail.'),
+ ' fail.');
// Iframe tests.
- assert_resolves(iframe_test(HTML_URL),
- 'Normal iframe loading should succeed.'),
- assert_resolves(
+ await assert_resolves(iframe_test(HTML_URL),
+ 'Normal iframe loading should succeed.');
+ await assert_resolves(
iframe_test(REDIRECT_TO_HTML_URL),
- 'Normal redirected iframe loading should succeed.'),
- assert_rejects(
+ 'Normal redirected iframe loading should succeed.');
+ await assert_rejects(
iframe_test(SCOPE + '?url=' +
encodeURIComponent(REDIRECT_TO_HTML_URL) +
'&redirect-mode=follow',
true /* timeout_enabled */),
'Redirected iframe loading with Request.redirect=follow should'+
- ' fail.'),
- assert_rejects(
+ ' fail.');
+ await assert_rejects(
iframe_test(SCOPE + '?url=' +
encodeURIComponent(REDIRECT_TO_HTML_URL) +
'&redirect-mode=error',
true /* timeout_enabled */),
'Redirected iframe loading with Request.redirect=error should '+
- 'fail.'),
- assert_resolves(
+ 'fail.');
+ await assert_resolves(
iframe_test(SCOPE + '?url=' +
encodeURIComponent(REDIRECT_TO_HTML_URL) +
'&redirect-mode=manual',
true /* timeout_enabled */),
'Redirected iframe loading with Request.redirect=manual should'+
- ' succeed.'),
- ]);
+ ' succeed.');
})
.then(function() {
frame.remove();
@@ -184,6 +187,8 @@
// test for reponse.redirected
promise_test(function(t) {
+ test_scope = "redirected";
+
var SCOPE = 'resources/fetch-request-redirect-iframe.html';
var SCRIPT = 'resources/fetch-rewrite-worker.js';
var REDIRECT_URL = base_path() + 'resources/redirect.py?Redirect=';
@@ -207,35 +212,34 @@
return wait_for_state(t, worker, 'activated');
})
.then(function() { return with_iframe(SCOPE); })
- .then(function(f) {
+ .then(async function(f) {
frame = f;
- return Promise.all([
// XMLHttpRequest tests.
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(XHR_URL) +
'&expected_redirected=false' +
'&expected_resolves=true'),
'Normal XHR should be resolved and response should not be ' +
- 'redirected.'),
- assert_resolves(
+ 'redirected.');
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&expected_redirected=true' +
'&expected_resolves=true'),
'Redirected XHR should be resolved and response should be ' +
- 'redirected.'),
+ 'redirected.');
// tests for request's mode = cors
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(XHR_URL) +
'&mode=cors' +
'&expected_redirected=false' +
'&expected_resolves=true'),
'Normal XHR should be resolved and response should not be ' +
- 'redirected even with CORS mode.'),
- assert_resolves(
+ 'redirected even with CORS mode.');
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&mode=cors' +
@@ -243,12 +247,12 @@
'&expected_redirected=true' +
'&expected_resolves=true'),
'Redirected XHR should be resolved and response.redirected ' +
- 'should be redirected with CORS mode.'),
+ 'should be redirected with CORS mode.');
// tests for request's mode = no-cors
// The response.redirect should be false since we will not add
// redirected url list when redirect-mode is not follow.
- assert_rejects(
+ await assert_rejects(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&mode=no-cors' +
@@ -256,19 +260,18 @@
'&expected_redirected=false' +
'&expected_resolves=false'),
'Redirected XHR should be reject and response should be ' +
- 'redirected with NO-CORS mode and redirect-mode=manual.'),
+ 'redirected with NO-CORS mode and redirect-mode=manual.');
// tests for redirecting to a cors
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.load_image(
'./?url=' + encodeURIComponent(REDIRECT_TO_CROSS_ORIGIN) +
'&mode=no-cors' +
'&redirect-mode=follow' +
'&expected_redirected=false' +
'&expected_resolves=true'),
- 'Redirected COS image should be reject and response should ' +
- 'not be redirected with NO-CORS mode.'),
- ]);
+ 'Redirected CORS image should be reject and response should ' +
+ 'not be redirected with NO-CORS mode.');
})
.then(function() {
frame.remove();
@@ -278,6 +281,8 @@
// test for reponse.redirected after cached
promise_test(function(t) {
+ test_scope = "cache";
+
var SCOPE = 'resources/fetch-request-redirect-iframe.html';
var SCRIPT = 'resources/fetch-rewrite-worker.js';
var REDIRECT_URL = base_path() + 'resources/redirect.py?Redirect=';
@@ -301,29 +306,28 @@
return wait_for_state(t, worker, 'activated');
})
.then(function() { return with_iframe(SCOPE); })
- .then(function(f) {
+ .then(async function(f) {
frame = f;
- return Promise.all([
// XMLHttpRequest tests.
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(XHR_URL) +
'&expected_redirected=false' +
'&expected_resolves=true' +
'&cache'),
'Normal XHR should be resolved and response should not be ' +
- 'redirected.'),
- assert_resolves(
+ 'redirected.');
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&expected_redirected=true' +
'&expected_resolves=true' +
'&cache'),
'Redirected XHR should be resolved and response should be ' +
- 'redirected.'),
+ 'redirected.');
// tests for request's mode = cors
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(XHR_URL) +
'&mode=cors' +
@@ -331,8 +335,8 @@
'&expected_resolves=true' +
'&cache'),
'Normal XHR should be resolved and response should not be ' +
- 'redirected even with CORS mode.'),
- assert_resolves(
+ 'redirected even with CORS mode.');
+ await assert_resolves(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&mode=cors' +
@@ -341,12 +345,12 @@
'&expected_resolves=true' +
'&cache'),
'Redirected XHR should be resolved and response.redirected ' +
- 'should be redirected with CORS mode.'),
+ 'should be redirected with CORS mode.');
// tests for request's mode = no-cors
// The response.redirect should be false since we will not add
// redirected url list when redirect-mode is not follow.
- assert_rejects(
+ await assert_rejects(
frame.contentWindow.xhr(
'./?url=' + encodeURIComponent(REDIRECT_TO_XHR_URL) +
'&mode=no-cors' +
@@ -355,10 +359,10 @@
'&expected_resolves=false' +
'&cache'),
'Redirected XHR should be reject and response should be ' +
- 'redirected with NO-CORS mode and redirect-mode=manual.'),
+ 'redirected with NO-CORS mode and redirect-mode=manual.');
// tests for redirecting to a cors
- assert_resolves(
+ await assert_resolves(
frame.contentWindow.load_image(
'./?url=' + encodeURIComponent(REDIRECT_TO_CROSS_ORIGIN) +
'&mode=no-cors' +
@@ -366,9 +370,8 @@
'&expected_redirected=false' +
'&expected_resolves=true' +
'&cache'),
- 'Redirected COS image should be reject and response should ' +
- 'not be redirected with NO-CORS mode.'),
- ]);
+ 'Redirected CORS image should be reject and response should ' +
+ 'not be redirected with NO-CORS mode.');
})
.then(function() {
frame.remove();
diff --git a/service-workers/service-worker/http-to-https-redirect-and-register.https.html b/service-workers/service-worker/http-to-https-redirect-and-register.https.html
index d78b23a..d1c6678 100644
--- a/service-workers/service-worker/http-to-https-redirect-and-register.https.html
+++ b/service-workers/service-worker/http-to-https-redirect-and-register.https.html
@@ -8,11 +8,13 @@
<script>
'use strict';
+var host_info = get_host_info();
+
// Loads a non-secure url in a new window, which redirects to |target_url|.
// That page then registers a service worker, and messages back with the result.
// Returns a promise that resolves with the result.
function redirect_and_register(target_url) {
- var redirect_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() +
+ var redirect_url = host_info.HTTP_REMOTE_ORIGIN + base_path() +
'resources/redirect.py?Redirect=';
var child = window.open(redirect_url + encodeURIComponent(target_url));
return new Promise(resolve => {
@@ -35,7 +37,7 @@
}, 'register on a secure page after redirect from an non-secure url');
promise_test(function(t) {
- var target_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() +
+ var target_url = host_info.HTTP_REMOTE_ORIGIN + base_path() +
'resources/http-to-https-redirect-and-register-iframe.html';
return redirect_and_register(target_url)
diff --git a/service-workers/service-worker/resources/vtt-frame.html b/service-workers/service-worker/resources/vtt-frame.html
new file mode 100644
index 0000000..c3ac803
--- /dev/null
+++ b/service-workers/service-worker/resources/vtt-frame.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Page Title</title>
+<video>
+ <track>
+</video>
diff --git a/service-workers/service-worker/update-bytecheck.https.html b/service-workers/service-worker/update-bytecheck.https.html
index 6e4c6ec..ec3d15a 100644
--- a/service-workers/service-worker/update-bytecheck.https.html
+++ b/service-workers/service-worker/update-bytecheck.https.html
@@ -5,6 +5,7 @@
<script src="resources/testharness-helpers.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
<script>
/*
@@ -26,11 +27,12 @@
{cors: true, main: 'time', imported: 'default'},
{cors: true, main: 'time', imported: 'time' }];
+const host_info = get_host_info();
settings.reduce((p, s) => {
return p.then(promise_test(function(t) {
var path = !s.cors ? ''
- : 'https://www1.web-platform.test:8443/' +
- 'service-workers/service-worker/resources/';
+ : host_info.HTTPS_REMOTE_ORIGIN +
+ '/service-workers/service-worker/resources/';
var script = 'resources/bytecheck-worker.py' +
'?main=' + s.main +
'&imported=' + s.imported +
diff --git a/service-workers/service-worker/webvtt-cross-origin.https.html b/service-workers/service-worker/webvtt-cross-origin.https.html
new file mode 100644
index 0000000..a2b741b
--- /dev/null
+++ b/service-workers/service-worker/webvtt-cross-origin.https.html
@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>cross-origin webvtt returned by service worker is detected</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body>
+<script>
+// This file tests opaque responses for WebVTT text track. It creates
+// an iframe with a <track> element, controlled by a service worker.
+// Each test tries to load a text track, the service worker intercepts the
+// requests and responds with opaque or non-opaque responses. The opaque
+// responses should result in load errors.
+
+const host_info = get_host_info();
+const kScript = 'resources/fetch-rewrite-worker.js';
+// Add '?ignore' so the service worker falls back for the navigation.
+const kScope = 'resources/vtt-frame.html?ignore';
+let frame;
+
+function load_track(url) {
+ const track = frame.contentDocument.querySelector('track');
+ const result = new Promise((resolve, reject) => {
+ track.onload = (e => {
+ resolve('load event');
+ });
+ track.onerror = (e => {
+ resolve('error event');
+ });
+ });
+
+ track.src = url;
+ // Setting mode to hidden seems needed, or else the text track requests don't
+ // occur.
+ track.track.mode = 'hidden';
+ return result;
+}
+
+promise_test(t => {
+ return service_worker_unregister_and_register(t, kScript, kScope)
+ .then(registration => {
+ promise_test(() => {
+ frame.remove();
+ return registration.unregister();
+ }, 'restore global state');
+
+ return wait_for_state(t, registration.installing, 'activated');
+ })
+ .then(() => {
+ return with_iframe(kScope);
+ })
+ .then(f => {
+ frame = f;
+ })
+ }, 'initialize global state');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a same-origin URL.
+ url += '?url=' + host_info.HTTPS_ORIGIN + '/media/foo.vtt';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'same-origin text track should load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a cross-origin URL.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'cross-origin text track with no-cors request should not load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a cross-origin URL that
+ // doesn't support CORS.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/media/foo-no-cors.vtt';
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'cross-origin text track with rejected cors request should not load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a cross-origin URL.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ // Add '&credentials=anonymous' to allow Access-Control-Allow-Origin=* so
+ // that CORS will succeed if the service approves it.
+ url += '&credentials=anonymous';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'cross-origin text track with approved cors request should load');
+
+// Redirect tests.
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a same-origin URL that redirects...
+ redirector_url = host_info.HTTPS_ORIGIN + base_path() + 'resources/redirect.py?Redirect=';
+ // ... to a same-origin URL.
+ redirect_target = host_info.HTTPS_ORIGIN + '/media/foo.vtt';
+ url += '?url=' + encodeURIComponent(redirector_url + encodeURIComponent(redirect_target));
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'same-origin text track that redirects same-origin should load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a same-origin URL that redirects...
+ redirector_url = host_info.HTTPS_ORIGIN + base_path() + 'resources/redirect.py?Redirect=';
+ // ... to a cross-origin URL.
+ redirect_target = host_info.HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ url += '?url=' + encodeURIComponent(redirector_url + encodeURIComponent(redirect_target));
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'same-origin text track that redirects cross-origin should not load');
+
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a same-origin URL that redirects...
+ redirector_url = host_info.HTTPS_ORIGIN + base_path() + 'resources/redirect.py?Redirect=';
+ // ... to a cross-origin URL.
+ redirect_target = host_info.HTTPS_REMOTE_ORIGIN + '/media/foo-no-cors.vtt';
+ url += '?url=' + encodeURIComponent(redirector_url + encodeURIComponent(redirect_target));
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ // Add '&credentials=anonymous' to allow Access-Control-Allow-Origin=* so
+ // that CORS will succeed if the server approves it.
+ url += '&credentials=anonymous';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'same-origin text track that redirects to a cross-origin text track with rejected cors should not load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to fetch a same-origin URL that redirects...
+ redirector_url = host_info.HTTPS_ORIGIN + base_path() + 'resources/redirect.py?Redirect=';
+ // ... to a cross-origin URL.
+ redirect_target = host_info.HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ url += '?url=' + encodeURIComponent(redirector_url + encodeURIComponent(redirect_target));
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ // Add '&credentials=anonymous' to allow Access-Control-Allow-Origin=* so
+ // that CORS will succeed if the server approves it.
+ url += '&credentials=anonymous';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'same-origin text track that redirects to a cross-origin text track with approved cors should load');
+</script>
+</body>
diff --git a/streams/readable-byte-streams/properties.js b/streams/readable-byte-streams/properties.js
index 02d0294..975fba7 100644
--- a/streams/readable-byte-streams/properties.js
+++ b/streams/readable-byte-streams/properties.js
@@ -88,7 +88,7 @@
assert_not_equals(viewPropDesc.get, undefined, 'view should have a getter');
assert_equals(viewPropDesc.set, undefined, 'view should not have a setter');
assert_not_equals(byobRequest.view, undefined, 'has a non-undefined view property');
- assert_equals(byobRequest.constructor.length, 2, 'constructor has 1 parameter');
+ assert_equals(byobRequest.constructor.length, 0, 'constructor has 0 parameters');
assert_equals(byobRequest.respond.length, 1, 'respond has 1 parameter');
assert_equals(byobRequest.respondWithNewView.length, 1, 'releaseLock has 1 parameter');
diff --git a/tools/ci/commands.json b/tools/ci/commands.json
index d682d2a..a8db428 100644
--- a/tools/ci/commands.json
+++ b/tools/ci/commands.json
@@ -2,5 +2,6 @@
"test-jobs": {"path": "jobs.py", "script": "run", "parser": "create_parser", "help": "List test jobs that should run for a set of commits",
"virtualenv": false},
"check-stability": {"path": "check_stability.py", "script": "run", "parser": "get_parser", "parse_known": true, "help": "Check test stability",
- "virtualenv": true, "install": ["requests"], "requirements": ["../wptrunner/requirements.txt"]}
+ "virtualenv": true, "install": ["requests"], "requirements": ["../wptrunner/requirements.txt"]},
+ "make-hosts-file": {"path": "make_hosts_file.py", "script": "run", "parser": "create_parser", "help": "Output a hosts file to stdout", "virtualenv": false}
}
diff --git a/tools/ci/lib.sh b/tools/ci/lib.sh
index db49ec6..2273793 100644
--- a/tools/ci/lib.sh
+++ b/tools/ci/lib.sh
@@ -6,15 +6,7 @@
echo "## /etc/hosts ##"
cat /etc/hosts
sudo sed -i 's/^::1\s*localhost/::1/' /etc/hosts
- sudo sh -c 'echo "
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
-" >> /etc/hosts'
+ ./wpt make-hosts-file | sudo tee -a /etc/hosts
echo "== /etc/hosts =="
cat /etc/hosts
echo "----------------"
diff --git a/tools/ci/make_hosts_file.py b/tools/ci/make_hosts_file.py
new file mode 100644
index 0000000..b3c7758
--- /dev/null
+++ b/tools/ci/make_hosts_file.py
@@ -0,0 +1,19 @@
+import argparse
+import os
+
+from ..localpaths import repo_root
+
+from ..serve.serve import load_config, normalise_config, make_hosts_file
+
+def create_parser():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("address", default="127.0.0.1", nargs="?", help="Address that hosts should point at")
+ return parser
+
+def run(**kwargs):
+ config = load_config(os.path.join(repo_root, "config.default.json"),
+ os.path.join(repo_root, "config.json"))
+
+ config = normalise_config(config, {})
+
+ print(make_hosts_file(config, kwargs["address"]))
diff --git a/tools/conftest.py b/tools/conftest.py
index 894fe62..4ce5e74 100644
--- a/tools/conftest.py
+++ b/tools/conftest.py
@@ -1,5 +1,6 @@
import platform
import os
+import sys
from hypothesis import settings, HealthCheck
@@ -11,3 +12,11 @@
settings.load_profile(os.getenv("HYPOTHESIS_PROFILE",
"default" if impl != "PyPy" else "pypy"))
+
+# serve can't even be imported on Py3, so totally ignore it even from collection
+collect_ignore = []
+if sys.version_info[0] >= 3:
+ serve = os.path.join(os.path.dirname(__file__), "serve")
+ collect_ignore.extend([os.path.join(root, f)
+ for root, _, files in os.walk(serve)
+ for f in files])
diff --git a/tools/serve/serve.py b/tools/serve/serve.py
index c77badc..9c5e7ca 100644
--- a/tools/serve/serve.py
+++ b/tools/serve/serve.py
@@ -203,6 +203,8 @@
u"天気の良い日",
u"élève"]
+not_subdomains = [u"nonexistent-origin"]
+
class RoutesBuilder(object):
def __init__(self):
self.forbidden_override = [("GET", "/tools/runner/*", handlers.file_handler),
@@ -468,6 +470,24 @@
for subdomain in subdomains}
+def get_not_subdomains(host):
+ #This assumes that the tld is ascii-only or already in punycode
+ return {subdomain: (subdomain.encode("idna"), host)
+ for subdomain in not_subdomains}
+
+
+def make_hosts_file(config, host):
+ rv = []
+
+ for domain in config["domains"].values():
+ rv.append("%s\t%s\n" % (host, domain))
+
+ for not_domain in config.get("not_domains", {}).values():
+ rv.append("0.0.0.0\t%s\n" % not_domain)
+
+ return "".join(rv)
+
+
def start_servers(host, ports, paths, routes, bind_hostname, config, ssl_config,
**kwargs):
servers = defaultdict(list)
@@ -626,6 +646,7 @@
def normalise_config(config, ports):
host = config["external_host"] if config["external_host"] else config["host"]
domains = get_subdomains(host)
+ not_domains = get_not_subdomains(host)
ports_ = {}
for scheme, ports_used in ports.iteritems():
ports_[scheme] = ports_used
@@ -633,6 +654,9 @@
for key, value in domains.iteritems():
domains[key] = ".".join(value)
+ for key, value in not_domains.iteritems():
+ not_domains[key] = ".".join(value)
+
domains[""] = host
ports_ = {}
@@ -644,6 +668,7 @@
config_ = config.copy()
config_["host"] = host
config_["domains"] = domains
+ config_["not_domains"] = not_domains
config_["ports"] = ports_
return config_
diff --git a/tools/serve/test_serve.py b/tools/serve/test_serve.py
new file mode 100644
index 0000000..3337601
--- /dev/null
+++ b/tools/serve/test_serve.py
@@ -0,0 +1,12 @@
+from . import serve
+
+def test_make_hosts_file():
+ hosts = serve.make_hosts_file({
+ "domains": {"www": "www.foo.bar.test", "www1": "www1.foo.bar.test"},
+ "not_domains": {"aaa": "aaa.foo.bar.test", "bbb": "bbb.foo.bar.test"}
+ }, "127.1.1.1")
+ lines = hosts.split("\n")
+ assert "127.1.1.1\twww.foo.bar.test" in lines
+ assert "127.1.1.1\twww1.foo.bar.test" in lines
+ assert "0.0.0.0\taaa.foo.bar.test" in lines
+ assert "0.0.0.0\tbbb.foo.bar.test" in lines
diff --git a/tools/webdriver/webdriver/transport.py b/tools/webdriver/webdriver/transport.py
index d62271f..9a1670a 100644
--- a/tools/webdriver/webdriver/transport.py
+++ b/tools/webdriver/webdriver/transport.py
@@ -39,8 +39,8 @@
try:
body = json.load(http_response, cls=decoder, **kwargs)
except ValueError:
- raise ValueError("Failed to decode response body as JSON:\n"
- "%s" % json.dumps(body, indent=2))
+ raise ValueError("Failed to decode response body as JSON:\n" +
+ http_response.read())
return cls(http_response.status, body)
diff --git a/tools/wpt/run.py b/tools/wpt/run.py
index f3fbcbd..236299e 100644
--- a/tools/wpt/run.py
+++ b/tools/wpt/run.py
@@ -11,6 +11,8 @@
sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
from . import browser, utils, virtualenv
+from ..serve import serve
+
logger = None
@@ -94,13 +96,10 @@
def check_environ(product):
if product not in ("firefox", "servo"):
- expected_hosts = ["web-platform.test",
- "www.web-platform.test",
- "www1.web-platform.test",
- "www2.web-platform.test",
- "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
- "xn--lve-6lad.web-platform.test",
- "nonexistent-origin.web-platform.test"]
+ expected_hosts = {".".join(x)
+ for x in serve.get_subdomains("web-platform.test").values()}
+ expected_hosts |= {".".join(x)
+ for x in serve.get_not_subdomains("web-platform.test").values()}
missing_hosts = set(expected_hosts)
if platform.uname()[0] != "Windows":
hosts_path = "/etc/hosts"
@@ -114,13 +113,17 @@
for host in hosts:
missing_hosts.discard(host)
if missing_hosts:
- raise WptrunError("""Missing hosts file configuration. Expected entries like:
+ if platform.uname()[0] != "Windows":
+ message = """Missing hosts file configuration. Run
-%s
+python wpt make-hosts-file >> %s
-See README.md for more details.""" % "\n".join("%s\t%s" %
- ("127.0.0.1" if "nonexistent" not in host else "0.0.0.0", host)
- for host in expected_hosts))
+from a shell with Administrator privileges.""" % hosts_path
+ else:
+ message = """Missing hosts file configuration. Run
+
+./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
+ raise WptrunError(message)
class BrowserSetup(object):
diff --git a/tools/wptrunner/MANIFEST.in b/tools/wptrunner/MANIFEST.in
index 7083923..d3b530a 100644
--- a/tools/wptrunner/MANIFEST.in
+++ b/tools/wptrunner/MANIFEST.in
@@ -5,4 +5,3 @@
include wptrunner/*.js
include wptrunner/executors/*.js
include wptrunner/config.json
-include wptrunner/browsers/server-locations.txt
\ No newline at end of file
diff --git a/tools/wptrunner/setup.py b/tools/wptrunner/setup.py
index 7da5141..148a1d2 100644
--- a/tools/wptrunner/setup.py
+++ b/tools/wptrunner/setup.py
@@ -52,7 +52,6 @@
"testharness_runner.html",
"config.json",
"wptrunner.default.ini",
- "browsers/server-locations.txt",
"browsers/sauce_setup/*",
"prefs/*"]},
include_package_data=True,
diff --git a/tools/wptrunner/wptrunner/browsers/chrome.py b/tools/wptrunner/wptrunner/browsers/chrome.py
index 215fccf..7f9a21c 100644
--- a/tools/wptrunner/wptrunner/browsers/chrome.py
+++ b/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -60,8 +60,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class ChromeBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/chrome_android.py b/tools/wptrunner/wptrunner/browsers/chrome_android.py
index 47090be..3e832cb 100644
--- a/tools/wptrunner/wptrunner/browsers/chrome_android.py
+++ b/tools/wptrunner/wptrunner/browsers/chrome_android.py
@@ -68,8 +68,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class ChromeAndroidBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/edge.py b/tools/wptrunner/wptrunner/browsers/edge.py
index db4ae00..094405c 100644
--- a/tools/wptrunner/wptrunner/browsers/edge.py
+++ b/tools/wptrunner/wptrunner/browsers/edge.py
@@ -38,8 +38,7 @@
return []
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
class EdgeBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/firefox.py b/tools/wptrunner/wptrunner/browsers/firefox.py
index 6d1f58d..57e0527 100644
--- a/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -3,12 +3,12 @@
import signal
import subprocess
import sys
+import tempfile
import mozinfo
import mozleak
from mozprocess import ProcessHandler
from mozprofile import FirefoxProfile, Preferences
-from mozprofile.permissions import ServerLocations
from mozrunner import FirefoxRunner
from mozrunner.utils import get_stack_fixer_function
from mozcrash import mozcrash
@@ -23,7 +23,6 @@
from ..executors.executormarionette import (MarionetteTestharnessExecutor,
MarionetteRefTestExecutor,
MarionetteWdspecExecutor)
-from ..environment import hostnames
here = os.path.join(os.path.split(__file__)[0])
@@ -80,7 +79,8 @@
**kwargs),
"leak_check": kwargs["leak_check"],
"stylo_threads": kwargs["stylo_threads"],
- "chaos_mode_flags": kwargs["chaos_mode_flags"]}
+ "chaos_mode_flags": kwargs["chaos_mode_flags"],
+ "config": kwargs["config"]}
def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
@@ -102,7 +102,7 @@
if kwargs["binary_args"]:
options["args"] = kwargs["binary_args"]
options["prefs"] = {
- "network.dns.localDomains": ",".join(hostnames)
+ "network.dns.localDomains": ",".join(server_config['domains'].values())
}
capabilities["moz:firefoxOptions"] = options
if kwargs["certutil_binary"] is None:
@@ -143,7 +143,7 @@
symbols_path=None, stackwalk_binary=None, certutil_binary=None,
ca_certificate_path=None, e10s=False, stackfix_dir=None,
binary_args=None, timeout_multiplier=None, leak_check=False, stylo_threads=1,
- chaos_mode_flags=None):
+ chaos_mode_flags=None, config=None):
Browser.__init__(self, logger)
self.binary = binary
self.prefs_root = prefs_root
@@ -159,6 +159,7 @@
self.certutil_binary = certutil_binary
self.e10s = e10s
self.binary_args = binary_args
+ self.config = config
if stackfix_dir:
self.stack_fixer = get_stack_fixer_function(stackfix_dir,
self.symbols_path)
@@ -189,15 +190,12 @@
if self.chaos_mode_flags is not None:
env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
- locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
-
preferences = self.load_prefs()
- self.profile = FirefoxProfile(locations=locations,
- preferences=preferences)
+ self.profile = FirefoxProfile(preferences=preferences)
self.profile.set_preferences({"marionette.port": self.marionette_port,
"dom.disable_open_during_load": False,
- "network.dns.localDomains": ",".join(hostnames),
+ "network.dns.localDomains": ",".join(self.config['domains'].values()),
"network.proxy.type": 0,
"places.history.enabled": False,
"dom.send_after_paint_to_content": True,
diff --git a/tools/wptrunner/wptrunner/browsers/ie.py b/tools/wptrunner/wptrunner/browsers/ie.py
index 13f5827..9c0007e 100644
--- a/tools/wptrunner/wptrunner/browsers/ie.py
+++ b/tools/wptrunner/wptrunner/browsers/ie.py
@@ -42,8 +42,7 @@
return []
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
class InternetExplorerBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/opera.py b/tools/wptrunner/wptrunner/browsers/opera.py
index 57edfa0..693a19a 100644
--- a/tools/wptrunner/wptrunner/browsers/opera.py
+++ b/tools/wptrunner/wptrunner/browsers/opera.py
@@ -60,8 +60,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class OperaBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/sauce.py b/tools/wptrunner/wptrunner/browsers/sauce.py
index 4c1be1c..42c83c5 100644
--- a/tools/wptrunner/wptrunner/browsers/sauce.py
+++ b/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -113,8 +113,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
@@ -128,6 +127,7 @@
class SauceConnect():
def __init__(self, **kwargs):
+ self.config = kwargs["config"]
self.sauce_user = kwargs["sauce_user"]
self.sauce_key = kwargs["sauce_key"]
self.sauce_tunnel_id = kwargs["sauce_tunnel_id"]
@@ -153,8 +153,7 @@
"--metrics-address=0.0.0.0:9876",
"--readyfile=./sauce_is_ready",
"--tunnel-domains",
- "web-platform.test",
- "*.web-platform.test"
+ ",".join(self.config['domains'].values())
])
# Timeout config vars
diff --git a/tools/wptrunner/wptrunner/browsers/server-locations.txt b/tools/wptrunner/wptrunner/browsers/server-locations.txt
deleted file mode 100644
index 5dcaf4b..0000000
--- a/tools/wptrunner/wptrunner/browsers/server-locations.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-http://localhost:8000 primary
-
-http://web-platform.test:8000
-http://www.web-platform.test:8000
-http://www1.web-platform.test:8000
-http://www2.web-platform.test:8000
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8000
-http://xn--lve-6lad.web-platform.test:8000
-
-http://web-platform.test:8001
-http://www.web-platform.test:8001
-http://www1.web-platform.test:8001
-http://www2.web-platform.test:8001
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8001
-http://xn--lve-6lad.web-platform.test:8001
-
-https://web-platform.test:8443
-https://www.web-platform.test:8443
-https://www1.web-platform.test:8443
-https://www2.web-platform.test:8443
-https://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8443
-https://xn--lve-6lad.web-platform.test:8443
-
-# These are actually ws servers, but until mozprofile is
-# fixed we have to pretend that they are http servers
-http://web-platform.test:8888
-http://www.web-platform.test:8888
-http://www1.web-platform.test:8888
-http://www2.web-platform.test:8888
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8888
-http://xn--lve-6lad.web-platform.test:8888
diff --git a/tools/wptrunner/wptrunner/browsers/servodriver.py b/tools/wptrunner/wptrunner/browsers/servodriver.py
index c251de8..89504b2 100644
--- a/tools/wptrunner/wptrunner/browsers/servodriver.py
+++ b/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -1,9 +1,12 @@
import os
+import shutil
import subprocess
import tempfile
from mozprocess import ProcessHandler
+from tools.serve.serve import make_hosts_file
+
from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor,
@@ -26,14 +29,6 @@
"update_properties": "update_properties",
}
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
def check_args(**kwargs):
require_arg(kwargs, "binary")
@@ -69,10 +64,10 @@
return ["debug", "os", "version", "processor", "bits"], None
-def make_hosts_file():
+def write_hosts_file(config):
hosts_fd, hosts_path = tempfile.mkstemp()
with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
+ f.write(make_hosts_file(config, "127.0.0.1"))
return hosts_path
@@ -87,7 +82,7 @@
self.webdriver_port = None
self.proc = None
self.debug_info = debug_info
- self.hosts_path = make_hosts_file()
+ self.hosts_path = write_hosts_file()
self.command = None
self.user_stylesheets = user_stylesheets if user_stylesheets else []
@@ -158,6 +153,7 @@
def cleanup(self):
self.stop()
+ shutil.rmtree(os.path.dirname(self.hosts_file))
def executor_browser(self):
assert self.webdriver_port is not None
diff --git a/tools/wptrunner/wptrunner/environment.py b/tools/wptrunner/wptrunner/environment.py
index 7115341..22b02a9 100644
--- a/tools/wptrunner/wptrunner/environment.py
+++ b/tools/wptrunner/wptrunner/environment.py
@@ -18,14 +18,6 @@
sslutils = None
-hostnames = ["web-platform.test",
- "www.web-platform.test",
- "www1.web-platform.test",
- "www2.web-platform.test",
- "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
- "xn--lve-6lad.web-platform.test"]
-
-
def do_delayed_imports(logger, test_paths):
global serve, sslutils
diff --git a/tools/wptrunner/wptrunner/executors/executorservo.py b/tools/wptrunner/wptrunner/executors/executorservo.py
index ca8ec8a..3cf402d 100644
--- a/tools/wptrunner/wptrunner/executors/executorservo.py
+++ b/tools/wptrunner/wptrunner/executors/executorservo.py
@@ -13,6 +13,8 @@
from mozprocess import ProcessHandler
+from tools.serve.serve import make_hosts_file
+
from .base import (ExecutorException,
Protocol,
RefTestImplementation,
@@ -30,18 +32,10 @@
extra_timeout = 5 # seconds
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
-def make_hosts_file():
+def write_hosts_file(config):
hosts_fd, hosts_path = tempfile.mkstemp()
with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
+ f.write(make_hosts_file(config, "127.0.0.1"))
return hosts_path
@@ -57,7 +51,7 @@
self.result_data = None
self.result_flag = None
self.protocol = Protocol(self, browser)
- self.hosts_path = make_hosts_file()
+ self.hosts_path = write_hosts_file(server_config)
def teardown(self):
try:
diff --git a/tools/wptrunner/wptrunner/hosts.py b/tools/wptrunner/wptrunner/hosts.py
deleted file mode 100644
index 915c17f..0000000
--- a/tools/wptrunner/wptrunner/hosts.py
+++ /dev/null
@@ -1,100 +0,0 @@
-from __future__ import unicode_literals
-
-
-class HostsLine(object):
- def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None):
- self.ip_address = ip_address
- self.canonical_hostname = canonical_hostname
- self.aliases = aliases if aliases is not None else []
- self.comment = comment
- if self.ip_address is None:
- assert self.canonical_hostname is None
- assert not self.aliases
- assert self.comment is not None
-
- @classmethod
- def from_string(cls, line):
- if not line.strip():
- return
-
- line = line.strip()
-
- ip_address = None
- canonical_hostname = None
- aliases = []
- comment = None
-
- comment_parts = line.split("#", 1)
- if len(comment_parts) > 1:
- comment = comment_parts[1]
-
- data = comment_parts[0].strip()
-
- if data:
- fields = data.split()
- if len(fields) < 2:
- raise ValueError("Invalid hosts line")
-
- ip_address = fields[0]
- canonical_hostname = fields[1]
- aliases = fields[2:]
-
- return cls(ip_address, canonical_hostname, aliases, comment)
-
-
-class HostsFile(object):
- def __init__(self):
- self.data = []
- self.by_hostname = {}
-
- def set_host(self, host):
- if host.canonical_hostname is None:
- self.data.append(host)
- elif host.canonical_hostname in self.by_hostname:
- old_host = self.by_hostname[host.canonical_hostname]
- old_host.ip_address = host.ip_address
- old_host.aliases = host.aliases
- old_host.comment = host.comment
- else:
- self.data.append(host)
- self.by_hostname[host.canonical_hostname] = host
-
- @classmethod
- def from_file(cls, f):
- rv = cls()
- for line in f:
- host = HostsLine.from_string(line)
- if host is not None:
- rv.set_host(host)
- return rv
-
- def to_string(self):
- field_widths = [0, 0]
- for line in self.data:
- if line.ip_address is not None:
- field_widths[0] = max(field_widths[0], len(line.ip_address))
- field_widths[1] = max(field_widths[1], len(line.canonical_hostname))
-
- lines = []
-
- for host in self.data:
- line = ""
- if host.ip_address is not None:
- ip_string = host.ip_address.ljust(field_widths[0])
- hostname_str = host.canonical_hostname
- if host.aliases:
- hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]),
- " ".join(host.aliases))
- line = "%s %s" % (ip_string, hostname_str)
- if host.comment:
- if line:
- line += " "
- line += "#%s" % host.comment
- lines.append(line)
-
- lines.append("")
-
- return "\n".join(lines)
-
- def to_file(self, f):
- f.write(self.to_string().encode("utf8"))
diff --git a/tools/wptrunner/wptrunner/tests/browsers/__init__.py b/tools/wptrunner/wptrunner/tests/browsers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/wptrunner/wptrunner/tests/browsers/__init__.py
diff --git a/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py b/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
index bf3e487..019b538 100644
--- a/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
+++ b/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
@@ -20,6 +20,9 @@
exists.return_value = True
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -46,6 +49,9 @@
exists.return_value = readyfile
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -68,6 +74,9 @@
exists.return_value = False
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -82,3 +91,34 @@
# Check we actually kill it after termination fails
Popen.return_value.terminate.assert_called()
Popen.return_value.kill.assert_called()
+
+
+def test_sauceconnect_tunnel_domains():
+ with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+ mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+ mock.patch.object(sauce.os.path, "exists") as exists:
+ Popen.return_value.poll.return_value = None
+ Popen.return_value.returncode = None
+ exists.return_value = True
+
+ sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"foo": "foo.bar.example.com", "": "example.net"}
+ },
+ sauce_user="aaa",
+ sauce_key="bbb",
+ sauce_tunnel_id="ccc",
+ sauce_connect_binary="ddd")
+
+ sauce_connect.__enter__(None)
+
+ Popen.assert_called_once()
+ args, kwargs = Popen.call_args
+ cmd = args[0]
+ assert "--tunnel-domains" in cmd
+ i = cmd.index("--tunnel-domains")
+ rest = cmd[i+1:]
+ assert len(rest) >= 1
+ if len(rest) > 1:
+ assert rest[1].startswith("-"), "--tunnel-domains takes a comma separated list (not a space separated list)"
+ assert set(rest[0].split(",")) == {"foo.bar.example.com", "example.net"}
diff --git a/tools/wptrunner/wptrunner/tests/test_hosts.py b/tools/wptrunner/wptrunner/tests/test_hosts.py
deleted file mode 100644
index e7d41f3..0000000
--- a/tools/wptrunner/wptrunner/tests/test_hosts.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import unittest
-import sys
-from os.path import join, dirname
-from cStringIO import StringIO
-
-sys.path.insert(0, join(dirname(__file__), "..", ".."))
-
-from wptrunner import hosts
-
-
-class HostsTest(unittest.TestCase):
- def do_test(self, input, expected):
- host_file = hosts.HostsFile.from_file(StringIO(input))
- self.assertEquals(host_file.to_string(), expected)
-
- def test_simple(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_blank_lines(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-
-\r
- \t
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_whitespace(self):
- self.do_test(""" \t127.0.0.1 \tlocalhost alias # comment \r
- \t# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_alignment(self):
- self.do_test("""127.0.0.1 \tlocalhost alias
-192.168.1.1 another_host another_alias
-""","""127.0.0.1 localhost alias
-192.168.1.1 another_host another_alias
-""")
-
- def test_multiple_same_name(self):
- # The semantics are that we overwrite earlier entries with the same name
- self.do_test("""127.0.0.1 \tlocalhost alias
-192.168.1.1 localhost another_alias""","""192.168.1.1 localhost another_alias
-""")
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tools/wptrunner/wptrunner/wptrunner.py b/tools/wptrunner/wptrunner/wptrunner.py
index 6677902..d3d9d07 100644
--- a/tools/wptrunner/wptrunner/wptrunner.py
+++ b/tools/wptrunner/wptrunner/wptrunner.py
@@ -218,6 +218,7 @@
browser_kwargs = get_browser_kwargs(test_type,
run_info,
ssl_env=ssl_env,
+ config=test_environment.config,
**kwargs)
executor_cls = executor_classes.get(test_type)
diff --git a/tools/wptserve/wptserve/pipes.py b/tools/wptserve/wptserve/pipes.py
index b71c8af..534afed 100644
--- a/tools/wptserve/wptserve/pipes.py
+++ b/tools/wptserve/wptserve/pipes.py
@@ -392,6 +392,12 @@
value = request.headers
elif field == "GET":
value = FirstWrapper(request.GET)
+ elif field == "domains":
+ if ('not_domains' in request.server.config and
+ tokens[1][1] in request.server.config['not_domains']):
+ value = request.server.config['not_domains']
+ else:
+ value = request.server.config['domains']
elif field in request.server.config:
value = request.server.config[tokens[0][1]]
elif field == "location":
diff --git a/webaudio/resources/biquad-filters.js b/webaudio/resources/biquad-filters.js
new file mode 100644
index 0000000..4674363
--- /dev/null
+++ b/webaudio/resources/biquad-filters.js
@@ -0,0 +1,376 @@
+// A biquad filter has a z-transform of
+// H(z) = (b0 + b1 / z + b2 / z^2) / (1 + a1 / z + a2 / z^2)
+//
+// The formulas for the various filters were taken from
+// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt.
+
+
+// Lowpass filter.
+function createLowpassFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+
+ if (freq == 1) {
+ // The formula below works, except for roundoff. When freq = 1,
+ // the filter is just a wire, so hardwire the coefficients.
+ b0 = 1;
+ b1 = 0;
+ b2 = 0;
+ a0 = 1;
+ a1 = 0;
+ a2 = 0;
+ } else {
+ let theta = Math.PI * freq;
+ let alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20));
+ let cosw = Math.cos(theta);
+ let beta = (1 - cosw) / 2;
+
+ b0 = beta;
+ b1 = 2 * beta;
+ b2 = beta;
+ a0 = 1 + alpha;
+ a1 = -2 * cosw;
+ a2 = 1 - alpha;
+ }
+
+ return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+}
+
+function createHighpassFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+
+ if (freq == 1) {
+ // The filter is 0
+ b0 = 0;
+ b1 = 0;
+ b2 = 0;
+ a0 = 1;
+ a1 = 0;
+ a2 = 0;
+ } else if (freq == 0) {
+ // The filter is 1. Computation of coefficients below is ok, but
+ // there's a pole at 1 and a zero at 1, so round-off could make
+ // the filter unstable.
+ b0 = 1;
+ b1 = 0;
+ b2 = 0;
+ a0 = 1;
+ a1 = 0;
+ a2 = 0;
+ } else {
+ let theta = Math.PI * freq;
+ let alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20));
+ let cosw = Math.cos(theta);
+ let beta = (1 + cosw) / 2;
+
+ b0 = beta;
+ b1 = -2 * beta;
+ b2 = beta;
+ a0 = 1 + alpha;
+ a1 = -2 * cosw;
+ a2 = 1 - alpha;
+ }
+
+ return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+}
+
+function normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2) {
+ let scale = 1 / a0;
+
+ return {
+ b0: b0 * scale,
+ b1: b1 * scale,
+ b2: b2 * scale,
+ a1: a1 * scale,
+ a2: a2 * scale
+ };
+}
+
+function createBandpassFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ if (freq > 0 && freq < 1) {
+ let w0 = Math.PI * freq;
+ if (q > 0) {
+ let alpha = Math.sin(w0) / (2 * q);
+ let k = Math.cos(w0);
+
+ b0 = alpha;
+ b1 = 0;
+ b2 = -alpha;
+ a0 = 1 + alpha;
+ a1 = -2 * k;
+ a2 = 1 - alpha;
+
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ } else {
+ // q = 0, and frequency is not 0 or 1. The above formula has a
+ // divide by zero problem. The limit of the z-transform as q
+ // approaches 0 is 1, so set the filter that way.
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+ } else {
+ // When freq = 0 or 1, the z-transform is identically 0,
+ // independent of q.
+ coef = { b0: 0, b1: 0, b2: 0, a1: 0, a2: 0 }
+ }
+
+ return coef;
+}
+
+function createLowShelfFilter(freq, q, gain) {
+ // q not used
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ let S = 1;
+ let A = Math.pow(10, gain / 40);
+
+ if (freq == 1) {
+ // The filter is just a constant gain
+ coef = {b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0};
+ } else if (freq == 0) {
+ // The filter is 1
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ } else {
+ let w0 = Math.PI * freq;
+ let alpha = 1 / 2 * Math.sin(w0) * Math.sqrt((A + 1 / A) * (1 / S - 1) + 2);
+ let k = Math.cos(w0);
+ let k2 = 2 * Math.sqrt(A) * alpha;
+ let Ap1 = A + 1;
+ let Am1 = A - 1;
+
+ b0 = A * (Ap1 - Am1 * k + k2);
+ b1 = 2 * A * (Am1 - Ap1 * k);
+ b2 = A * (Ap1 - Am1 * k - k2);
+ a0 = Ap1 + Am1 * k + k2;
+ a1 = -2 * (Am1 + Ap1 * k);
+ a2 = Ap1 + Am1 * k - k2;
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ }
+
+ return coef;
+}
+
+function createHighShelfFilter(freq, q, gain) {
+ // q not used
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ let A = Math.pow(10, gain / 40);
+
+ if (freq == 1) {
+ // When freq = 1, the z-transform is 1
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ } else if (freq > 0) {
+ let w0 = Math.PI * freq;
+ let S = 1;
+ let alpha = 0.5 * Math.sin(w0) * Math.sqrt((A + 1 / A) * (1 / S - 1) + 2);
+ let k = Math.cos(w0);
+ let k2 = 2 * Math.sqrt(A) * alpha;
+ let Ap1 = A + 1;
+ let Am1 = A - 1;
+
+ b0 = A * (Ap1 + Am1 * k + k2);
+ b1 = -2 * A * (Am1 + Ap1 * k);
+ b2 = A * (Ap1 + Am1 * k - k2);
+ a0 = Ap1 - Am1 * k + k2;
+ a1 = 2 * (Am1 - Ap1 * k);
+ a2 = Ap1 - Am1 * k - k2;
+
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ } else {
+ // When freq = 0, the filter is just a gain
+ coef = {b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+
+ return coef;
+}
+
+function createPeakingFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ let A = Math.pow(10, gain / 40);
+
+ if (freq > 0 && freq < 1) {
+ if (q > 0) {
+ let w0 = Math.PI * freq;
+ let alpha = Math.sin(w0) / (2 * q);
+ let k = Math.cos(w0);
+
+ b0 = 1 + alpha * A;
+ b1 = -2 * k;
+ b2 = 1 - alpha * A;
+ a0 = 1 + alpha / A;
+ a1 = -2 * k;
+ a2 = 1 - alpha / A;
+
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ } else {
+ // q = 0, we have a divide by zero problem in the formulas
+ // above. But if we look at the z-transform, we see that the
+ // limit as q approaches 0 is A^2.
+ coef = {b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+ } else {
+ // freq = 0 or 1, the z-transform is 1
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+
+ return coef;
+}
+
+function createNotchFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ if (freq > 0 && freq < 1) {
+ if (q > 0) {
+ let w0 = Math.PI * freq;
+ let alpha = Math.sin(w0) / (2 * q);
+ let k = Math.cos(w0);
+
+ b0 = 1;
+ b1 = -2 * k;
+ b2 = 1;
+ a0 = 1 + alpha;
+ a1 = -2 * k;
+ a2 = 1 - alpha;
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ } else {
+ // When q = 0, we get a divide by zero above. The limit of the
+ // z-transform as q approaches 0 is 0, so set the coefficients
+ // appropriately.
+ coef = {b0: 0, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+ } else {
+ // When freq = 0 or 1, the z-transform is 1
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+
+ return coef;
+}
+
+function createAllpassFilter(freq, q, gain) {
+ let b0;
+ let b1;
+ let b2;
+ let a0;
+ let a1;
+ let a2;
+ let coef;
+
+ if (freq > 0 && freq < 1) {
+ if (q > 0) {
+ let w0 = Math.PI * freq;
+ let alpha = Math.sin(w0) / (2 * q);
+ let k = Math.cos(w0);
+
+ b0 = 1 - alpha;
+ b1 = -2 * k;
+ b2 = 1 + alpha;
+ a0 = 1 + alpha;
+ a1 = -2 * k;
+ a2 = 1 - alpha;
+ coef = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
+ } else {
+ // q = 0
+ coef = {b0: -1, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+ } else {
+ coef = {b0: 1, b1: 0, b2: 0, a1: 0, a2: 0};
+ }
+
+ return coef;
+}
+
+function filterData(filterCoef, signal, len) {
+ let y = new Array(len);
+ let b0 = filterCoef.b0;
+ let b1 = filterCoef.b1;
+ let b2 = filterCoef.b2;
+ let a1 = filterCoef.a1;
+ let a2 = filterCoef.a2;
+
+ // Prime the pump. (Assumes the signal has length >= 2!)
+ y[0] = b0 * signal[0];
+ y[1] = b0 * signal[1] + b1 * signal[0] - a1 * y[0];
+
+ // Filter all of the signal that we have.
+ for (let k = 2; k < Math.min(signal.length, len); ++k) {
+ y[k] = b0 * signal[k] + b1 * signal[k - 1] + b2 * signal[k - 2] -
+ a1 * y[k - 1] - a2 * y[k - 2];
+ }
+
+ // If we need to filter more, but don't have any signal left,
+ // assume the signal is zero.
+ for (let k = signal.length; k < len; ++k) {
+ y[k] = -a1 * y[k - 1] - a2 * y[k - 2];
+ }
+
+ return y;
+}
+
+// Map the filter type name to a function that computes the filter coefficents
+// for the given filter type.
+let filterCreatorFunction = {
+ 'lowpass': createLowpassFilter,
+ 'highpass': createHighpassFilter,
+ 'bandpass': createBandpassFilter,
+ 'lowshelf': createLowShelfFilter,
+ 'highshelf': createHighShelfFilter,
+ 'peaking': createPeakingFilter,
+ 'notch': createNotchFilter,
+ 'allpass': createAllpassFilter
+};
+
+let filterTypeName = {
+ 'lowpass': 'Lowpass filter',
+ 'highpass': 'Highpass filter',
+ 'bandpass': 'Bandpass filter',
+ 'lowshelf': 'Lowshelf filter',
+ 'highshelf': 'Highshelf filter',
+ 'peaking': 'Peaking filter',
+ 'notch': 'Notch filter',
+ 'allpass': 'Allpass filter'
+};
+
+function createFilter(filterType, freq, q, gain) {
+ return filterCreatorFunction[filterType](freq, q, gain);
+}
diff --git a/webaudio/resources/distance-model-testing.js b/webaudio/resources/distance-model-testing.js
new file mode 100644
index 0000000..1b9adde
--- /dev/null
+++ b/webaudio/resources/distance-model-testing.js
@@ -0,0 +1,193 @@
+let sampleRate = 44100.0;
+
+// How many panner nodes to create for the test.
+let nodesToCreate = 100;
+
+// Time step when each panner node starts.
+let timeStep = 0.001;
+
+// Make sure we render long enough to get all of our nodes.
+let renderLengthSeconds = timeStep * (nodesToCreate + 1);
+
+// Length of an impulse signal.
+let pulseLengthFrames = Math.round(timeStep * sampleRate);
+
+// Globals to make debugging a little easier.
+let context;
+let impulse;
+let bufferSource;
+let panner;
+let position;
+let time;
+
+// For the record, these distance formulas were taken from the OpenAL
+// spec
+// (http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf),
+// not the code. The Web Audio spec follows the OpenAL formulas.
+
+function linearDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ distance = Math.min(distance, panner.maxDistance);
+ let rolloff = panner.rolloffFactor;
+ let gain =
+ (1 -
+ rolloff * (distance - panner.refDistance) /
+ (panner.maxDistance - panner.refDistance));
+
+ return gain;
+}
+
+function inverseDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ distance = Math.min(distance, panner.maxDistance);
+ let rolloff = panner.rolloffFactor;
+ let gain = panner.refDistance /
+ (panner.refDistance + rolloff * (distance - panner.refDistance));
+
+ return gain;
+}
+
+function exponentialDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ distance = Math.min(distance, panner.maxDistance);
+ let rolloff = panner.rolloffFactor;
+ let gain = Math.pow(distance / panner.refDistance, -rolloff);
+
+ return gain;
+}
+
+// Map the distance model to the function that implements the model
+let distanceModelFunction = {
+ 'linear': linearDistance,
+ 'inverse': inverseDistance,
+ 'exponential': exponentialDistance
+};
+
+function createGraph(context, distanceModel, nodeCount) {
+ bufferSource = new Array(nodeCount);
+ panner = new Array(nodeCount);
+ position = new Array(nodeCount);
+ time = new Array(nodesToCreate);
+
+ impulse = createImpulseBuffer(context, pulseLengthFrames);
+
+ // Create all the sources and panners.
+ //
+ // We MUST use the EQUALPOWER panning model so that we can easily
+ // figure out the gain introduced by the panner.
+ //
+ // We want to stay in the middle of the panning range, which means
+ // we want to stay on the z-axis. If we don't, then the effect of
+ // panning model will be much more complicated. We're not testing
+ // the panner, but the distance model, so we want the panner effect
+ // to be simple.
+ //
+ // The panners are placed at a uniform intervals between the panner
+ // reference distance and the panner max distance. The source is
+ // also started at regular intervals.
+ for (let k = 0; k < nodeCount; ++k) {
+ bufferSource[k] = context.createBufferSource();
+ bufferSource[k].buffer = impulse;
+
+ panner[k] = context.createPanner();
+ panner[k].panningModel = 'equalpower';
+ panner[k].distanceModel = distanceModel;
+
+ let distanceStep =
+ (panner[k].maxDistance - panner[k].refDistance) / nodeCount;
+ position[k] = distanceStep * k + panner[k].refDistance;
+ panner[k].setPosition(0, 0, position[k]);
+
+ bufferSource[k].connect(panner[k]);
+ panner[k].connect(context.destination);
+
+ time[k] = k * timeStep;
+ bufferSource[k].start(time[k]);
+ }
+}
+
+// distanceModel should be the distance model string like
+// "linear", "inverse", or "exponential".
+function createTestAndRun(context, distanceModel, should) {
+ // To test the distance models, we create a number of panners at
+ // uniformly spaced intervals on the z-axis. Each of these are
+ // started at equally spaced time intervals. After rendering the
+ // signals, we examine where each impulse is located and the
+ // attenuation of the impulse. The attenuation is compared
+ // against our expected attenuation.
+
+ createGraph(context, distanceModel, nodesToCreate);
+
+ return context.startRendering().then(
+ buffer => checkDistanceResult(buffer, distanceModel, should));
+}
+
+// The gain caused by the EQUALPOWER panning model, if we stay on the
+// z axis, with the default orientations.
+function equalPowerGain() {
+ return Math.SQRT1_2;
+}
+
+function checkDistanceResult(renderedBuffer, model, should) {
+ renderedData = renderedBuffer.getChannelData(0);
+
+ // The max allowed error between the actual gain and the expected
+ // value. This is determined experimentally. Set to 0 to see
+ // what the actual errors are.
+ let maxAllowedError = 3.3e-6;
+
+ let success = true;
+
+ // Number of impulses we found in the rendered result.
+ let impulseCount = 0;
+
+ // Maximum relative error in the gain of the impulses.
+ let maxError = 0;
+
+ // Array of locations of the impulses that were not at the
+ // expected location. (Contains the actual and expected frame
+ // of the impulse.)
+ let impulsePositionErrors = new Array();
+
+ // Step through the rendered data to find all the non-zero points
+ // so we can find where our distance-attenuated impulses are.
+ // These are tested against the expected attenuations at that
+ // distance.
+ for (let k = 0; k < renderedData.length; ++k) {
+ if (renderedData[k] != 0) {
+ // Convert from string to index.
+ let distanceFunction = distanceModelFunction[model];
+ let expected =
+ distanceFunction(panner[impulseCount], 0, 0, position[impulseCount]);
+
+ // Adjust for the center-panning of the EQUALPOWER panning
+ // model that we're using.
+ expected *= equalPowerGain();
+
+ let error = Math.abs(renderedData[k] - expected) / Math.abs(expected);
+
+ maxError = Math.max(maxError, Math.abs(error));
+
+ should(renderedData[k]).beCloseTo(expected, {threshold: maxAllowedError});
+
+ // Keep track of any impulses that aren't where we expect them
+ // to be.
+ let expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
+ if (k != expectedOffset) {
+ impulsePositionErrors.push({actual: k, expected: expectedOffset});
+ }
+ ++impulseCount;
+ }
+ }
+ should(impulseCount, 'Number of impulses').beEqualTo(nodesToCreate);
+
+ should(maxError, 'Max error in distance gains')
+ .beLessThanOrEqualTo(maxAllowedError);
+
+ // Display any timing errors that we found.
+ if (impulsePositionErrors.length > 0) {
+ let actual = impulsePositionErrors.map(x => x.actual);
+ let expected = impulsePositionErrors.map(x => x.expected);
+ should(actual, 'Actual impulse positions found').beEqualToArray(expected);
+ }
+}
diff --git a/webaudio/resources/panner-formulas.js b/webaudio/resources/panner-formulas.js
new file mode 100644
index 0000000..ae6f516
--- /dev/null
+++ b/webaudio/resources/panner-formulas.js
@@ -0,0 +1,190 @@
+// For the record, these distance formulas were taken from the OpenAL
+// spec
+// (http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf),
+// not the code. The Web Audio spec follows the OpenAL formulas.
+
+function linearDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ let dref = Math.min(panner.refDistance, panner.maxDistance);
+ let dmax = Math.max(panner.refDistance, panner.maxDistance);
+ distance = Math.max(Math.min(distance, dmax), dref);
+ let rolloff = Math.max(Math.min(panner.rolloffFactor, 1), 0);
+ if (dref === dmax)
+ return 1 - rolloff;
+
+ let gain = (1 - rolloff * (distance - dref) / (dmax - dref));
+
+ return gain;
+}
+
+function inverseDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ distance = Math.max(distance, panner.refDistance);
+ let rolloff = panner.rolloffFactor;
+ let gain = panner.refDistance /
+ (panner.refDistance +
+ rolloff * (Math.max(distance, panner.refDistance) - panner.refDistance));
+
+ return gain;
+}
+
+function exponentialDistance(panner, x, y, z) {
+ let distance = Math.sqrt(x * x + y * y + z * z);
+ distance = Math.max(distance, panner.refDistance);
+ let rolloff = panner.rolloffFactor;
+ let gain = Math.pow(distance / panner.refDistance, -rolloff);
+
+ return gain;
+}
+
+// Simple implementations of 3D vectors implemented as a 3-element array.
+
+// x - y
+function vec3Sub(x, y) {
+ let z = new Float32Array(3);
+ z[0] = x[0] - y[0];
+ z[1] = x[1] - y[1];
+ z[2] = x[2] - y[2];
+
+ return z;
+}
+
+// x/|x|
+function vec3Normalize(x) {
+ let mag = Math.hypot(...x);
+ return x.map(function(c) {
+ return c / mag;
+ });
+}
+
+// x == 0?
+function vec3IsZero(x) {
+ return x[0] === 0 && x[1] === 0 && x[2] === 0;
+}
+
+// Vector cross product
+function vec3Cross(u, v) {
+ let cross = new Float32Array(3);
+ cross[0] = u[1] * v[2] - u[2] * v[1];
+ cross[1] = u[2] * v[0] - u[0] * v[2];
+ cross[2] = u[0] * v[1] - u[1] * v[0];
+ return cross;
+}
+
+// Dot product
+function vec3Dot(x, y) {
+ return x[0] * y[0] + x[1] * y[1] + x[2] * y[2];
+}
+
+// a*x, for scalar a
+function vec3Scale(a, x) {
+ return x.map(function(c) {
+ return a * c;
+ });
+}
+
+function calculateAzimuth(source, listener, listenerForward, listenerUp) {
+ let sourceListener = vec3Sub(source, listener);
+
+ if (vec3IsZero(sourceListener))
+ return 0;
+
+ sourceListener = vec3Normalize(sourceListener);
+
+ let listenerRight = vec3Normalize(vec3Cross(listenerForward, listenerUp));
+ let listenerForwardNorm = vec3Normalize(listenerForward);
+
+ let up = vec3Cross(listenerRight, listenerForwardNorm);
+ let upProjection = vec3Dot(sourceListener, up);
+
+ let projectedSource =
+ vec3Normalize(vec3Sub(sourceListener, vec3Scale(upProjection, up)));
+
+ let azimuth =
+ 180 / Math.PI * Math.acos(vec3Dot(projectedSource, listenerRight));
+
+ // Source in front or behind the listener
+ let frontBack = vec3Dot(projectedSource, listenerForwardNorm);
+ if (frontBack < 0)
+ azimuth = 360 - azimuth;
+
+ // Make azimuth relative to "front" and not "right" listener vector.
+ if (azimuth >= 0 && azimuth <= 270)
+ azimuth = 90 - azimuth;
+ else
+ azimuth = 450 - azimuth;
+
+ // We don't need elevation, so we're skipping that computation.
+ return azimuth;
+}
+
+// Map our position angle to the azimuth angle (in degrees).
+//
+// An angle of 0 corresponds to an azimuth of 90 deg; pi, to -90 deg.
+function angleToAzimuth(angle) {
+ return 90 - angle * 180 / Math.PI;
+}
+
+// The gain caused by the EQUALPOWER panning model
+function equalPowerGain(azimuth, numberOfChannels) {
+ let halfPi = Math.PI / 2;
+
+ if (azimuth < -90)
+ azimuth = -180 - azimuth;
+ else
+ azimuth = 180 - azimuth;
+
+ if (numberOfChannels == 1) {
+ let panPosition = (azimuth + 90) / 180;
+
+ let gainL = Math.cos(halfPi * panPosition);
+ let gainR = Math.sin(halfPi * panPosition);
+
+ return {left: gainL, right: gainR};
+ } else {
+ if (azimuth <= 0) {
+ let panPosition = (azimuth + 90) / 90;
+
+ let gainL = Math.cos(halfPi * panPosition);
+ let gainR = Math.sin(halfPi * panPosition);
+
+ return {left: gainL, right: gainR};
+ } else {
+ let panPosition = azimuth / 90;
+
+ let gainL = Math.cos(halfPi * panPosition);
+ let gainR = Math.sin(halfPi * panPosition);
+
+ return {left: gainL, right: gainR};
+ }
+ }
+}
+
+function applyPanner(azimuth, srcL, srcR, numberOfChannels) {
+ let length = srcL.length;
+ let outL = new Float32Array(length);
+ let outR = new Float32Array(length);
+
+ if (numberOfChannels == 1) {
+ for (let k = 0; k < length; ++k) {
+ let gains = equalPowerGain(azimuth[k], numberOfChannels);
+
+ outL[k] = srcL[k] * gains.left;
+ outR[k] = srcR[k] * gains.right;
+ }
+ } else {
+ for (let k = 0; k < length; ++k) {
+ let gains = equalPowerGain(azimuth[k], numberOfChannels);
+
+ if (azimuth[k] <= 0) {
+ outL[k] = srcL[k] + srcR[k] * gains.left;
+ outR[k] = srcR[k] * gains.right;
+ } else {
+ outL[k] = srcL[k] * gains.left;
+ outR[k] = srcR[k] + srcL[k] * gains.right;
+ }
+ }
+ }
+
+ return {left: outL, right: outR};
+}
diff --git a/webaudio/resources/panner-model-testing.js b/webaudio/resources/panner-model-testing.js
new file mode 100644
index 0000000..662fb1d
--- /dev/null
+++ b/webaudio/resources/panner-model-testing.js
@@ -0,0 +1,181 @@
+let sampleRate = 44100.0;
+
+let numberOfChannels = 1;
+
+// Time step when each panner node starts.
+let timeStep = 0.001;
+
+// Length of the impulse signal.
+let pulseLengthFrames = Math.round(timeStep * sampleRate);
+
+// How many panner nodes to create for the test
+let nodesToCreate = 100;
+
+// Be sure we render long enough for all of our nodes.
+let renderLengthSeconds = timeStep * (nodesToCreate + 1);
+
+// These are global mostly for debugging.
+let context;
+let impulse;
+let bufferSource;
+let panner;
+let position;
+let time;
+
+let renderedBuffer;
+let renderedLeft;
+let renderedRight;
+
+function createGraph(context, nodeCount, positionSetter) {
+ bufferSource = new Array(nodeCount);
+ panner = new Array(nodeCount);
+ position = new Array(nodeCount);
+ time = new Array(nodeCount);
+ // Angle between panner locations. (nodeCount - 1 because we want
+ // to include both 0 and 180 deg.
+ let angleStep = Math.PI / (nodeCount - 1);
+
+ if (numberOfChannels == 2) {
+ impulse = createStereoImpulseBuffer(context, pulseLengthFrames);
+ } else
+ impulse = createImpulseBuffer(context, pulseLengthFrames);
+
+ for (let k = 0; k < nodeCount; ++k) {
+ bufferSource[k] = context.createBufferSource();
+ bufferSource[k].buffer = impulse;
+
+ panner[k] = context.createPanner();
+ panner[k].panningModel = 'equalpower';
+ panner[k].distanceModel = 'linear';
+
+ let angle = angleStep * k;
+ position[k] = {angle: angle, x: Math.cos(angle), z: Math.sin(angle)};
+ positionSetter(panner[k], position[k].x, 0, position[k].z);
+
+ bufferSource[k].connect(panner[k]);
+ panner[k].connect(context.destination);
+
+ // Start the source
+ time[k] = k * timeStep;
+ bufferSource[k].start(time[k]);
+ }
+}
+
+function createTestAndRun(
+ context, should, nodeCount, numberOfSourceChannels, positionSetter) {
+ numberOfChannels = numberOfSourceChannels;
+
+ createGraph(context, nodeCount, positionSetter);
+
+ return context.startRendering().then(buffer => checkResult(buffer, should));
+}
+
+// Map our position angle to the azimuth angle (in degrees).
+//
+// An angle of 0 corresponds to an azimuth of 90 deg; pi, to -90 deg.
+function angleToAzimuth(angle) {
+ return 90 - angle * 180 / Math.PI;
+}
+
+// The gain caused by the EQUALPOWER panning model
+function equalPowerGain(angle) {
+ let azimuth = angleToAzimuth(angle);
+
+ if (numberOfChannels == 1) {
+ let panPosition = (azimuth + 90) / 180;
+
+ let gainL = Math.cos(0.5 * Math.PI * panPosition);
+ let gainR = Math.sin(0.5 * Math.PI * panPosition);
+
+ return {left: gainL, right: gainR};
+ } else {
+ if (azimuth <= 0) {
+ let panPosition = (azimuth + 90) / 90;
+
+ let gainL = 1 + Math.cos(0.5 * Math.PI * panPosition);
+ let gainR = Math.sin(0.5 * Math.PI * panPosition);
+
+ return {left: gainL, right: gainR};
+ } else {
+ let panPosition = azimuth / 90;
+
+ let gainL = Math.cos(0.5 * Math.PI * panPosition);
+ let gainR = 1 + Math.sin(0.5 * Math.PI * panPosition);
+
+ return {left: gainL, right: gainR};
+ }
+ }
+}
+
+function checkResult(renderedBuffer, should) {
+ renderedLeft = renderedBuffer.getChannelData(0);
+ renderedRight = renderedBuffer.getChannelData(1);
+
+ // The max error we allow between the rendered impulse and the
+ // expected value. This value is experimentally determined. Set
+ // to 0 to make the test fail to see what the actual error is.
+ let maxAllowedError = 1.3e-6;
+
+ let success = true;
+
+ // Number of impulses found in the rendered result.
+ let impulseCount = 0;
+
+ // Max (relative) error and the index of the maxima for the left
+ // and right channels.
+ let maxErrorL = 0;
+ let maxErrorIndexL = 0;
+ let maxErrorR = 0;
+ let maxErrorIndexR = 0;
+
+ // Number of impulses that don't match our expected locations.
+ let timeCount = 0;
+
+ // Locations of where the impulses aren't at the expected locations.
+ let timeErrors = new Array();
+
+ for (let k = 0; k < renderedLeft.length; ++k) {
+ // We assume that the left and right channels start at the same instant.
+ if (renderedLeft[k] != 0 || renderedRight[k] != 0) {
+ // The expected gain for the left and right channels.
+ let pannerGain = equalPowerGain(position[impulseCount].angle);
+ let expectedL = pannerGain.left;
+ let expectedR = pannerGain.right;
+
+ // Absolute error in the gain.
+ let errorL = Math.abs(renderedLeft[k] - expectedL);
+ let errorR = Math.abs(renderedRight[k] - expectedR);
+
+ if (Math.abs(errorL) > maxErrorL) {
+ maxErrorL = Math.abs(errorL);
+ maxErrorIndexL = impulseCount;
+ }
+ if (Math.abs(errorR) > maxErrorR) {
+ maxErrorR = Math.abs(errorR);
+ maxErrorIndexR = impulseCount;
+ }
+
+ // Keep track of the impulses that didn't show up where we
+ // expected them to be.
+ let expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
+ if (k != expectedOffset) {
+ timeErrors[timeCount] = {actual: k, expected: expectedOffset};
+ ++timeCount;
+ }
+ ++impulseCount;
+ }
+ }
+
+ should(impulseCount, 'Number of impulses found').beEqualTo(nodesToCreate);
+
+ should(
+ timeErrors.map(x => x.actual),
+ 'Offsets of impulses at the wrong position')
+ .beEqualToArray(timeErrors.map(x => x.expected));
+
+ should(maxErrorL, 'Error in left channel gain values')
+ .beLessThanOrEqualTo(maxAllowedError);
+
+ should(maxErrorR, 'Error in right channel gain values')
+ .beLessThanOrEqualTo(maxAllowedError);
+}
diff --git a/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html
new file mode 100644
index 0000000..da36d58
--- /dev/null
+++ b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html
@@ -0,0 +1,204 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Basic IIRFilterNode Properties
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let sampleRate = 48000;
+ let testFrames = 100;
+
+ // Global context that can be used by the individual tasks. It must be
+ // defined by the initialize task.
+ let context;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define('initialize', (task, should) => {
+ should(() => {
+ context = new OfflineAudioContext(1, testFrames, sampleRate);
+ }, 'Initialize context for testing').notThrow();
+ task.done();
+ });
+
+ audit.define('existence', (task, should) => {
+ should(context.createIIRFilter, 'context.createIIRFilter').exist();
+ task.done();
+ });
+
+ audit.define('parameters', (task, should) => {
+ // Create a really simple IIR filter. Doesn't much matter what.
+ let coef = Float32Array.from([1]);
+
+ let f = context.createIIRFilter(coef, coef);
+
+ should(f.numberOfInputs, 'numberOfInputs').beEqualTo(1);
+ should(f.numberOfOutputs, 'numberOfOutputs').beEqualTo(1);
+ should(f.channelCountMode, 'channelCountMode').beEqualTo('max');
+ should(f.channelInterpretation, 'channelInterpretation')
+ .beEqualTo('speakers');
+
+ task.done();
+ });
+
+ audit.define('exceptions-createIIRFilter', (task, should) => {
+ should(function() {
+ // Two args are required.
+ context.createIIRFilter();
+ }, 'createIIRFilter()').throw('TypeError');
+
+ should(function() {
+ // Two args are required.
+ context.createIIRFilter(new Float32Array(1));
+ }, 'createIIRFilter(new Float32Array(1))').throw('TypeError');
+
+ should(function() {
+ // null is not valid
+ context.createIIRFilter(null, null);
+ }, 'createIIRFilter(null, null)').throw('TypeError');
+
+ should(function() {
+ // There has to be at least one coefficient.
+ context.createIIRFilter([], []);
+ }, 'createIIRFilter([], [])').throw('NotSupportedError');
+
+ should(function() {
+ // There has to be at least one coefficient.
+ context.createIIRFilter([1], []);
+ }, 'createIIRFilter([1], [])').throw('NotSupportedError');
+
+ should(function() {
+ // There has to be at least one coefficient.
+ context.createIIRFilter([], [1]);
+ }, 'createIIRFilter([], [1])').throw('NotSupportedError');
+
+ should(
+ function() {
+ // Max allowed size for the coefficient arrays.
+ let fb = new Float32Array(20);
+ fb[0] = 1;
+ context.createIIRFilter(fb, fb);
+ },
+ 'createIIRFilter(new Float32Array(20), new Float32Array(20))')
+ .notThrow();
+
+ should(
+ function() {
+ // Max allowed size for the feedforward coefficient array.
+ let coef = new Float32Array(21);
+ coef[0] = 1;
+ context.createIIRFilter(coef, [1]);
+ },
+ 'createIIRFilter(new Float32Array(21), [1])')
+ .throw('NotSupportedError');
+
+ should(
+ function() {
+ // Max allowed size for the feedback coefficient array.
+ let coef = new Float32Array(21);
+ coef[0] = 1;
+ context.createIIRFilter([1], coef);
+ },
+ 'createIIRFilter([1], new Float32Array(21))')
+ .throw('NotSupportedError');
+
+ should(
+ function() {
+ // First feedback coefficient can't be 0.
+ context.createIIRFilter([1], new Float32Array(2));
+ },
+ 'createIIRFilter([1], new Float32Array(2))')
+ .throw('InvalidStateError');
+
+ should(
+ function() {
+ // feedforward coefficients can't all be zero.
+ context.createIIRFilter(new Float32Array(10), [1]);
+ },
+ 'createIIRFilter(new Float32Array(10), [1])')
+ .throw('InvalidStateError');
+
+ should(function() {
+ // Feedback coefficients must be finite.
+ context.createIIRFilter([1], [1, Infinity, NaN]);
+ }, 'createIIRFilter([1], [1, NaN, Infinity])').throw('TypeError');
+
+ should(function() {
+ // Feedforward coefficients must be finite.
+ context.createIIRFilter([1, Infinity, NaN], [1]);
+ }, 'createIIRFilter([1, NaN, Infinity], [1])').throw('TypeError');
+
+ should(function() {
+ // Test that random junk in the array is converted to NaN.
+ context.createIIRFilter([1, 'abc', []], [1]);
+ }, 'createIIRFilter([1, \'abc\', []], [1])').throw('TypeError');
+
+ task.done();
+ });
+
+ audit.define('exceptions-getFrequencyData', (task, should) => {
+ // Create a really simple IIR filter. Doesn't much matter what.
+ let coef = Float32Array.from([1]);
+
+ let f = context.createIIRFilter(coef, coef);
+
+ should(
+ function() {
+ // frequencyHz can't be null.
+ f.getFrequencyResponse(
+ null, new Float32Array(1), new Float32Array(1));
+ },
+ 'getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))')
+ .throw('TypeError');
+
+ should(
+ function() {
+ // magResponse can't be null.
+ f.getFrequencyResponse(
+ new Float32Array(1), null, new Float32Array(1));
+ },
+ 'getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))')
+ .throw('TypeError');
+
+ should(
+ function() {
+ // phaseResponse can't be null.
+ f.getFrequencyResponse(
+ new Float32Array(1), new Float32Array(1), null);
+ },
+ 'getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)')
+ .throw('TypeError');
+
+ should(
+ function() {
+ // magResponse array must the same length as frequencyHz
+ f.getFrequencyResponse(
+ new Float32Array(10), new Float32Array(1),
+ new Float32Array(20));
+ },
+ 'getFrequencyResponse(new Float32Array(10), new Float32Array(1), new Float32Array(20))')
+ .throw('InvalidAccessError');
+
+ should(
+ function() {
+ // phaseResponse array must be the same length as frequencyHz
+ f.getFrequencyResponse(
+ new Float32Array(10), new Float32Array(20),
+ new Float32Array(1));
+ },
+ 'getFrequencyResponse(new Float32Array(10), new Float32Array(20), new Float32Array(1))')
+ .throw('InvalidAccessError');
+
+ task.done();
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html
new file mode 100644
index 0000000..c98555f
--- /dev/null
+++ b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test IIRFilter getFrequencyResponse() functionality
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/biquad-filters.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let sampleRate = 48000;
+ // Some short duration; we're not actually looking at the rendered output.
+ let testDurationSec = 0.01;
+
+ // Number of frequency samples to take.
+ let numberOfFrequencies = 1000;
+
+ let audit = Audit.createTaskRunner();
+
+
+ // Compute a set of linearly spaced frequencies.
+ function createFrequencies(nFrequencies, sampleRate) {
+ let frequencies = new Float32Array(nFrequencies);
+ let nyquist = sampleRate / 2;
+ let freqDelta = nyquist / nFrequencies;
+
+ for (let k = 0; k < nFrequencies; ++k) {
+ frequencies[k] = k * freqDelta;
+ }
+
+ return frequencies;
+ }
+
+ audit.define('1-pole IIR', (task, should) => {
+ let context = new OfflineAudioContext(
+ 1, testDurationSec * sampleRate, sampleRate);
+
+ let iir = context.createIIRFilter([1], [1, -0.9]);
+ let frequencies =
+ createFrequencies(numberOfFrequencies, context.sampleRate);
+
+ let iirMag = new Float32Array(numberOfFrequencies);
+ let iirPhase = new Float32Array(numberOfFrequencies);
+ let trueMag = new Float32Array(numberOfFrequencies);
+ let truePhase = new Float32Array(numberOfFrequencies);
+
+ // The IIR filter is
+ // H(z) = 1/(1 - 0.9*z^(-1)).
+ //
+ // The frequency response is
+ // H(exp(j*w)) = 1/(1 - 0.9*exp(-j*w)).
+ //
+ // Thus, the magnitude is
+ // |H(exp(j*w))| = 1/sqrt(1.81-1.8*cos(w)).
+ //
+ // The phase is
+ // arg(H(exp(j*w)) = atan(0.9*sin(w)/(.9*cos(w)-1))
+
+ let frequencyScale = Math.PI / (sampleRate / 2);
+
+ for (let k = 0; k < frequencies.length; ++k) {
+ let omega = frequencyScale * frequencies[k];
+ trueMag[k] = 1 / Math.sqrt(1.81 - 1.8 * Math.cos(omega));
+ truePhase[k] =
+ Math.atan(0.9 * Math.sin(omega) / (0.9 * Math.cos(omega) - 1));
+ }
+
+ iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
+
+ // Thresholds were experimentally determined.
+ should(iirMag, '1-pole IIR Magnitude Response')
+ .beCloseToArray(trueMag, {absoluteThreshold: 2.8611e-6});
+ should(iirPhase, '1-pole IIR Phase Response')
+ .beCloseToArray(truePhase, {absoluteThreshold: 1.7882e-7});
+
+ task.done();
+ });
+
+ audit.define('compare IIR and biquad', (task, should) => {
+ // Create an IIR filter equivalent to the biquad filter. Compute the
+ // frequency response for both and verify that they are the same.
+ let context = new OfflineAudioContext(
+ 1, testDurationSec * sampleRate, sampleRate);
+
+ let biquad = context.createBiquadFilter();
+ let coef = createFilter(
+ biquad.type, biquad.frequency.value / (context.sampleRate / 2),
+ biquad.Q.value, biquad.gain.value);
+
+ let iir = context.createIIRFilter(
+ [coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
+
+ let frequencies =
+ createFrequencies(numberOfFrequencies, context.sampleRate);
+ let biquadMag = new Float32Array(numberOfFrequencies);
+ let biquadPhase = new Float32Array(numberOfFrequencies);
+ let iirMag = new Float32Array(numberOfFrequencies);
+ let iirPhase = new Float32Array(numberOfFrequencies);
+
+ biquad.getFrequencyResponse(frequencies, biquadMag, biquadPhase);
+ iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
+
+ // Thresholds were experimentally determined.
+ should(iirMag, 'IIR Magnitude Response').beCloseToArray(biquadMag, {
+ absoluteThreshold: 2.7419e-5
+ });
+ should(iirPhase, 'IIR Phase Response').beCloseToArray(biquadPhase, {
+ absoluteThreshold: 2.7657e-5
+ });
+
+ task.done();
+ });
+
+ audit.define(
+ {
+ label: 'getFrequencyResponse',
+ description: 'Test out-of-bounds frequency values'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(1, 1, sampleRate);
+ let filter = new IIRFilterNode(
+ context, {feedforward: [1], feedback: [1, -.9]});
+
+ // Frequencies to test. These are all outside the valid range of
+ // frequencies of 0 to Nyquist.
+ let freq = new Float32Array(2);
+ freq[0] = -1;
+ freq[1] = context.sampleRate / 2 + 1;
+
+ let mag = new Float32Array(freq.length);
+ let phase = new Float32Array(freq.length);
+
+ filter.getFrequencyResponse(freq, mag, phase);
+
+ // Verify that the returned magnitude and phase entries are alL NaN
+ // since the frequencies are outside the valid range
+ for (let k = 0; k < mag.length; ++k) {
+ should(mag[k],
+ 'Magnitude response at frequency ' + freq[k])
+ .beNaN();
+ }
+
+ for (let k = 0; k < phase.length; ++k) {
+ should(phase[k],
+ 'Phase response at frequency ' + freq[k])
+ .beNaN();
+ }
+
+ task.done();
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html
new file mode 100644
index 0000000..aa38a6b
--- /dev/null
+++ b/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter.html
@@ -0,0 +1,572 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Basic IIRFilterNode Operation
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/biquad-filters.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let sampleRate = 24000;
+ let testDurationSec = 0.25;
+ let testFrames = testDurationSec * sampleRate;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define('coefficient-normalization', (task, should) => {
+ // Test that the feedback coefficients are normalized. Do this be
+ // creating two IIRFilterNodes. One has normalized coefficients, and
+ // one doesn't. Compute the difference and make sure they're the same.
+ let context = new OfflineAudioContext(2, testFrames, sampleRate);
+
+ // Use a simple impulse as the source.
+ let buffer = context.createBuffer(1, 1, sampleRate);
+ buffer.getChannelData(0)[0] = 1;
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+
+ // Gain node for computing the difference between the filters.
+ let gain = context.createGain();
+ gain.gain.value = -1;
+
+ // The IIR filters. Use a common feedforward array.
+ let ff = [1];
+
+ let fb1 = [1, .9];
+
+ let fb2 = new Float64Array(2);
+ // Scale the feedback coefficients by an arbitrary factor.
+ let coefScaleFactor = 2;
+ for (let k = 0; k < fb2.length; ++k) {
+ fb2[k] = coefScaleFactor * fb1[k];
+ }
+
+ let iir1;
+ let iir2;
+
+ should(function() {
+ iir1 = context.createIIRFilter(ff, fb1);
+ }, 'createIIRFilter with normalized coefficients').notThrow();
+
+ should(function() {
+ iir2 = context.createIIRFilter(ff, fb2);
+ }, 'createIIRFilter with unnormalized coefficients').notThrow();
+
+ // Create the graph. The output of iir1 (normalized coefficients) is
+ // channel 0, and the output of iir2 (unnormalized coefficients), with
+ // appropriate scaling, is channel 1.
+ let merger = context.createChannelMerger(2);
+ source.connect(iir1);
+ source.connect(iir2);
+ iir1.connect(merger, 0, 0);
+ iir2.connect(gain);
+
+ // The gain for the gain node should be set to compensate for the
+ // scaling of the coefficients. Since iir2 has scaled the coefficients
+ // by coefScaleFactor, the output is reduced by the same factor, so
+ // adjust the gain to scale the output of iir2 back up.
+ gain.gain.value = coefScaleFactor;
+ gain.connect(merger, 0, 1);
+
+ merger.connect(context.destination);
+
+ source.start();
+
+ // Rock and roll!
+
+ context.startRendering()
+ .then(function(result) {
+ // Find the max amplitude of the result, which should be near
+ // zero.
+ let iir1Data = result.getChannelData(0);
+ let iir2Data = result.getChannelData(1);
+
+ // Threshold isn't exactly zero because the arithmetic is done
+ // differently between the IIRFilterNode and the BiquadFilterNode.
+ should(
+ iir2Data,
+ 'Output of IIR filter with unnormalized coefficients')
+ .beCloseToArray(iir1Data, {absoluteThreshold: 2.1958e-38});
+ })
+ .then(() => task.done());
+ });
+
+ audit.define('one-zero', (task, should) => {
+ // Create a simple 1-zero filter and compare with the expected output.
+ let context = new OfflineAudioContext(1, testFrames, sampleRate);
+
+ // Use a simple impulse as the source
+ let buffer = context.createBuffer(1, 1, sampleRate);
+ buffer.getChannelData(0)[0] = 1;
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+
+ // The filter is y(n) = 0.5*(x(n) + x(n-1)), a simple 2-point moving
+ // average. This is rather arbitrary; keep it simple.
+
+ let iir = context.createIIRFilter([0.5, 0.5], [1]);
+
+ // Create the graph
+ source.connect(iir);
+ iir.connect(context.destination);
+
+ // Rock and roll!
+ source.start();
+
+ context.startRendering()
+ .then(function(result) {
+ let actual = result.getChannelData(0);
+ let expected = new Float64Array(testFrames);
+ // The filter is a simple 2-point moving average of an impulse, so
+ // the first two values are non-zero and the rest are zero.
+ expected[0] = 0.5;
+ expected[1] = 0.5;
+ should(actual, 'IIR 1-zero output').beCloseToArray(expected, {
+ absoluteThreshold: 0
+ });
+ })
+ .then(() => task.done());
+ });
+
+ audit.define('one-pole', (task, should) => {
+ // Create a simple 1-pole filter and compare with the expected output.
+
+ // The filter is y(n) + c*y(n-1)= x(n). The analytical response is
+ // (-c)^n, so choose a suitable number of frames to run the test for
+ // where the output isn't flushed to zero.
+ let c = 0.9;
+ let eps = 1e-20;
+ let duration = Math.floor(Math.log(eps) / Math.log(Math.abs(c)));
+ let context = new OfflineAudioContext(1, duration, sampleRate);
+
+ // Use a simple impulse as the source
+ let buffer = context.createBuffer(1, 1, sampleRate);
+ buffer.getChannelData(0)[0] = 1;
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+
+ let iir = context.createIIRFilter([1], [1, c]);
+
+ // Create the graph
+ source.connect(iir);
+ iir.connect(context.destination);
+
+ // Rock and roll!
+ source.start();
+
+ context.startRendering()
+ .then(function(result) {
+ let actual = result.getChannelData(0);
+ let expected = new Float64Array(actual.length);
+
+ // The filter is a simple 1-pole filter: y(n) = -c*y(n-k)+x(n),
+ // with an impulse as the input.
+ expected[0] = 1;
+ for (k = 1; k < testFrames; ++k) {
+ expected[k] = -c * expected[k - 1];
+ }
+
+ // Threshold isn't exactly zero due to round-off in the
+ // single-precision IIRFilterNode computations versus the
+ // double-precision Javascript computations.
+ should(actual, 'IIR 1-pole output').beCloseToArray(expected, {
+ absoluteThreshold: 2.7657e-8
+ });
+ })
+ .then(() => task.done());
+ });
+
+ // Return a function suitable for use as a defineTask function. This
+ // function creates an IIRFilterNode equivalent to the specified
+ // BiquadFilterNode and compares the outputs. The outputs from the two
+ // filters should be virtually identical.
+ function testWithBiquadFilter(filterType, errorThreshold, snrThreshold) {
+ return (task, should) => {
+ let context = new OfflineAudioContext(2, testFrames, sampleRate);
+
+ // Use a constant (step function) as the source
+ let buffer = createConstantBuffer(context, testFrames, 1);
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+
+
+ // Create the biquad. Choose some rather arbitrary values for Q and
+ // gain for the biquad so that the shelf filters aren't identical.
+ let biquad = context.createBiquadFilter();
+ biquad.type = filterType;
+ biquad.Q.value = 10;
+ biquad.gain.value = 10;
+
+ // Create the equivalent IIR Filter node by computing the coefficients
+ // of the given biquad filter type.
+ let nyquist = sampleRate / 2;
+ let coef = createFilter(
+ filterType, biquad.frequency.value / nyquist, biquad.Q.value,
+ biquad.gain.value);
+
+ let iir = context.createIIRFilter(
+ [coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
+
+ let merger = context.createChannelMerger(2);
+ // Create the graph
+ source.connect(biquad);
+ source.connect(iir);
+
+ biquad.connect(merger, 0, 0);
+ iir.connect(merger, 0, 1);
+
+ merger.connect(context.destination);
+
+ // Rock and roll!
+ source.start();
+
+ context.startRendering()
+ .then(function(result) {
+ // Find the max amplitude of the result, which should be near
+ // zero.
+ let expected = result.getChannelData(0);
+ let actual = result.getChannelData(1);
+
+ // On MacOSX, WebAudio uses an optimized Biquad implementation
+ // that is different from the implementation used for Linux and
+ // Windows. This will cause the output to differ, even if the
+ // threshold passes. Thus, only print out a very small number
+ // of elements of the array where we have tested that they are
+ // consistent.
+ should(actual, 'IIRFilter for Biquad ' + filterType)
+ .beCloseToArray(expected, errorThreshold);
+
+ let snr = 10 * Math.log10(computeSNR(actual, expected));
+ should(snr, 'SNR for IIRFIlter for Biquad ' + filterType)
+ .beGreaterThanOrEqualTo(snrThreshold);
+ })
+ .then(() => task.done());
+ };
+ }
+
+ // Thresholds here are experimentally determined.
+ let biquadTestConfigs = [
+ {
+ filterType: 'lowpass',
+ snrThreshold: 91.221,
+ errorThreshold: {relativeThreshold: 4.9834e-5}
+ },
+ {
+ filterType: 'highpass',
+ snrThreshold: 105.4590,
+ errorThreshold: {absoluteThreshold: 2.9e-6, relativeThreshold: 3e-5}
+ },
+ {
+ filterType: 'bandpass',
+ snrThreshold: 104.060,
+ errorThreshold: {absoluteThreshold: 2e-7, relativeThreshold: 8.7e-4}
+ },
+ {
+ filterType: 'notch',
+ snrThreshold: 91.312,
+ errorThreshold: {absoluteThreshold: 0, relativeThreshold: 4.22e-5}
+ },
+ {
+ filterType: 'allpass',
+ snrThreshold: 91.319,
+ errorThreshold: {absoluteThreshold: 0, relativeThreshold: 4.31e-5}
+ },
+ {
+ filterType: 'lowshelf',
+ snrThreshold: 90.609,
+ errorThreshold: {absoluteThreshold: 0, relativeThreshold: 2.98e-5}
+ },
+ {
+ filterType: 'highshelf',
+ snrThreshold: 103.159,
+ errorThreshold: {absoluteThreshold: 0, relativeThreshold: 1.24e-5}
+ },
+ {
+ filterType: 'peaking',
+ snrThreshold: 91.504,
+ errorThreshold: {absoluteThreshold: 0, relativeThreshold: 5.05e-5}
+ }
+ ];
+
+ // Create a set of tasks based on biquadTestConfigs.
+ for (k = 0; k < biquadTestConfigs.length; ++k) {
+ let config = biquadTestConfigs[k];
+ let name = k + ': ' + config.filterType;
+ audit.define(
+ name,
+ testWithBiquadFilter(
+ config.filterType, config.errorThreshold, config.snrThreshold));
+ }
+
+ audit.define('multi-channel', (task, should) => {
+ // Multi-channel test. Create a biquad filter and the equivalent IIR
+ // filter. Filter the same multichannel signal and compare the results.
+ let nChannels = 3;
+ let context =
+ new OfflineAudioContext(nChannels, testFrames, sampleRate);
+
+ // Create a set of oscillators as the multi-channel source.
+ let source = [];
+
+ for (k = 0; k < nChannels; ++k) {
+ source[k] = context.createOscillator();
+ source[k].type = 'sawtooth';
+ // The frequency of the oscillator is pretty arbitrary, but each
+ // oscillator should have a different frequency.
+ source[k].frequency.value = 100 + k * 100;
+ }
+
+ let merger = context.createChannelMerger(3);
+
+ let biquad = context.createBiquadFilter();
+
+ // Create the equivalent IIR Filter node.
+ let nyquist = sampleRate / 2;
+ let coef = createFilter(
+ biquad.type, biquad.frequency.value / nyquist, biquad.Q.value,
+ biquad.gain.value);
+ let fb = [1, coef.a1, coef.a2];
+ let ff = [coef.b0, coef.b1, coef.b2];
+
+ let iir = context.createIIRFilter(ff, fb);
+ // Gain node to compute the difference between the IIR and biquad
+ // filter.
+ let gain = context.createGain();
+ gain.gain.value = -1;
+
+ // Create the graph.
+ for (k = 0; k < nChannels; ++k)
+ source[k].connect(merger, 0, k);
+
+ merger.connect(biquad);
+ merger.connect(iir);
+ iir.connect(gain);
+ biquad.connect(context.destination);
+ gain.connect(context.destination);
+
+ for (k = 0; k < nChannels; ++k)
+ source[k].start();
+
+ context.startRendering()
+ .then(function(result) {
+ let errorThresholds = [3.7671e-5, 3.0071e-5, 2.6241e-5];
+
+ // Check the difference signal on each channel
+ for (channel = 0; channel < result.numberOfChannels; ++channel) {
+ // Find the max amplitude of the result, which should be near
+ // zero.
+ let data = result.getChannelData(channel);
+ let maxError =
+ data.reduce(function(reducedValue, currentValue) {
+ return Math.max(reducedValue, Math.abs(currentValue));
+ });
+
+ should(
+ maxError,
+ 'Max difference between IIR and Biquad on channel ' +
+ channel)
+ .beLessThanOrEqualTo(errorThresholds[channel]);
+ }
+
+ })
+ .then(() => task.done());
+ });
+
+ // Apply an IIRFilter to the given input signal.
+ //
+ // IIR filter in the time domain is
+ //
+ // y[n] = sum(ff[k]*x[n-k], k, 0, M) - sum(fb[k]*y[n-k], k, 1, N)
+ //
+ function iirFilter(input, feedforward, feedback) {
+ // For simplicity, create an x buffer that contains the input, and a y
+ // buffer that contains the output. Both of these buffers have an
+ // initial work space to implement the initial memory of the filter.
+ let workSize = Math.max(feedforward.length, feedback.length);
+ let x = new Float32Array(input.length + workSize);
+
+ // Float64 because we want to match the implementation that uses doubles
+ // to minimize roundoff.
+ let y = new Float64Array(input.length + workSize);
+
+ // Copy the input over.
+ for (let k = 0; k < input.length; ++k)
+ x[k + feedforward.length] = input[k];
+
+ // Run the filter
+ for (let n = 0; n < input.length; ++n) {
+ let index = n + workSize;
+ let yn = 0;
+ for (let k = 0; k < feedforward.length; ++k)
+ yn += feedforward[k] * x[index - k];
+ for (let k = 0; k < feedback.length; ++k)
+ yn -= feedback[k] * y[index - k];
+
+ y[index] = yn;
+ }
+
+ return y.slice(workSize).map(Math.fround);
+ }
+
+ // Cascade the two given biquad filters to create one IIR filter.
+ function cascadeBiquads(f1Coef, f2Coef) {
+ // The biquad filters are:
+ //
+ // f1 = (b10 + b11/z + b12/z^2)/(1 + a11/z + a12/z^2);
+ // f2 = (b20 + b21/z + b22/z^2)/(1 + a21/z + a22/z^2);
+ //
+ // To cascade them, multiply the two transforms together to get a fourth
+ // order IIR filter.
+
+ let numProduct = [
+ f1Coef.b0 * f2Coef.b0, f1Coef.b0 * f2Coef.b1 + f1Coef.b1 * f2Coef.b0,
+ f1Coef.b0 * f2Coef.b2 + f1Coef.b1 * f2Coef.b1 + f1Coef.b2 * f2Coef.b0,
+ f1Coef.b1 * f2Coef.b2 + f1Coef.b2 * f2Coef.b1, f1Coef.b2 * f2Coef.b2
+ ];
+
+ let denProduct = [
+ 1, f2Coef.a1 + f1Coef.a1,
+ f2Coef.a2 + f1Coef.a1 * f2Coef.a1 + f1Coef.a2,
+ f1Coef.a1 * f2Coef.a2 + f1Coef.a2 * f2Coef.a1, f1Coef.a2 * f2Coef.a2
+ ];
+
+ return {
+ ff: numProduct, fb: denProduct
+ }
+ }
+
+ // Find the magnitude of the root of the quadratic that has the maximum
+ // magnitude.
+ //
+ // The quadratic is z^2 + a1 * z + a2 and we want the root z that has the
+ // largest magnitude.
+ function largestRootMagnitude(a1, a2) {
+ let discriminant = a1 * a1 - 4 * a2;
+ if (discriminant < 0) {
+ // Complex roots: -a1/2 +/- i*sqrt(-d)/2. Thus the magnitude of each
+ // root is the same and is sqrt(a1^2/4 + |d|/4)
+ let d = Math.sqrt(-discriminant);
+ return Math.hypot(a1 / 2, d / 2);
+ } else {
+ // Real roots
+ let d = Math.sqrt(discriminant);
+ return Math.max(Math.abs((-a1 + d) / 2), Math.abs((-a1 - d) / 2));
+ }
+ }
+
+ audit.define('4th-order-iir', (task, should) => {
+ // Cascade 2 lowpass biquad filters and compare that with the equivalent
+ // 4th order IIR filter.
+
+ let nyquist = sampleRate / 2;
+ // Compute the coefficients of a lowpass filter.
+
+ // First some preliminary stuff. Compute the coefficients of the
+ // biquad. This is used to figure out how frames to use in the test.
+ let biquadType = 'lowpass';
+ let biquadCutoff = 350;
+ let biquadQ = 5;
+ let biquadGain = 1;
+
+ let coef = createFilter(
+ biquadType, biquadCutoff / nyquist, biquadQ, biquadGain);
+
+ // Cascade the biquads together to create an equivalent IIR filter.
+ let cascade = cascadeBiquads(coef, coef);
+
+ // Since we're cascading two identical biquads, the root of denominator
+ // of the IIR filter is repeated, so the root of the denominator with
+ // the largest magnitude occurs twice. The impulse response of the IIR
+ // filter will be roughly c*(r*r)^n at time n, where r is the root of
+ // largest magnitude. This approximation gets better as n increases.
+ // We can use this to get a rough idea of when the response has died
+ // down to a small value.
+
+ // This is the value we will use to determine how many frames to render.
+ // Rendering too many is a waste of time and also makes it hard to
+ // compare the actual result to the expected because the magnitudes are
+ // so small that they could be mostly round-off noise.
+ //
+ // Find magnitude of the root with largest magnitude
+ let rootMagnitude = largestRootMagnitude(coef.a1, coef.a2);
+
+ // Find n such that |r|^(2*n) <= eps. That is, n = log(eps)/(2*log(r)).
+ // Somewhat arbitrarily choose eps = 1e-20;
+ let eps = 1e-20;
+ let framesForTest =
+ Math.floor(Math.log(eps) / (2 * Math.log(rootMagnitude)));
+
+ // We're ready to create the graph for the test. The offline context
+ // has two channels: channel 0 is the expected (cascaded biquad) result
+ // and channel 1 is the actual IIR filter result.
+ let context = new OfflineAudioContext(2, framesForTest, sampleRate);
+
+ // Use a simple impulse with a large (arbitrary) amplitude as the source
+ let amplitude = 1;
+ let buffer = context.createBuffer(1, testFrames, sampleRate);
+ buffer.getChannelData(0)[0] = amplitude;
+ let source = context.createBufferSource();
+ source.buffer = buffer;
+
+ // Create the two biquad filters. Doesn't really matter what, but for
+ // simplicity we choose identical lowpass filters with the same
+ // parameters.
+ let biquad1 = context.createBiquadFilter();
+ biquad1.type = biquadType;
+ biquad1.frequency.value = biquadCutoff;
+ biquad1.Q.value = biquadQ;
+
+ let biquad2 = context.createBiquadFilter();
+ biquad2.type = biquadType;
+ biquad2.frequency.value = biquadCutoff;
+ biquad2.Q.value = biquadQ;
+
+ let iir = context.createIIRFilter(cascade.ff, cascade.fb);
+
+ // Create the merger to get the signals into multiple channels
+ let merger = context.createChannelMerger(2);
+
+ // Create the graph, filtering the source through two biquads.
+ source.connect(biquad1);
+ biquad1.connect(biquad2);
+ biquad2.connect(merger, 0, 0);
+
+ source.connect(iir);
+ iir.connect(merger, 0, 1);
+
+ merger.connect(context.destination);
+
+ // Now filter the source through the IIR filter.
+ let y = iirFilter(buffer.getChannelData(0), cascade.ff, cascade.fb);
+
+ // Rock and roll!
+ source.start();
+
+ context.startRendering()
+ .then(function(result) {
+ let expected = result.getChannelData(0);
+ let actual = result.getChannelData(1);
+
+ should(actual, '4-th order IIRFilter (biquad ref)')
+ .beCloseToArray(expected, {
+ // Thresholds experimentally determined.
+ absoluteThreshold: 1.59e-7,
+ relativeThreshold: 2.11e-5,
+ });
+
+ let snr = 10 * Math.log10(computeSNR(actual, expected));
+ should(snr, 'SNR of 4-th order IIRFilter (biquad ref)')
+ .beGreaterThanOrEqualTo(108.947);
+ })
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html b/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html
new file mode 100644
index 0000000..383e2c6
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ distance-exponential.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/distance-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ audit.define(
+ {
+ label: 'test',
+ description: 'Exponential distance model for PannerNode'
+ },
+ (task, should) => {
+ // Create offline audio context.
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(context, 'exponential', should)
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html b/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html
new file mode 100644
index 0000000..a4ff984
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/distance-inverse.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ distance-inverse.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/distance-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ audit.define('test', (task, should) => {
+ // Create offline audio context.
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(context, 'inverse', should).then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html b/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html
new file mode 100644
index 0000000..812fea3
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/distance-linear.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ distance-linear.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/distance-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ audit.define(
+ {label: 'test', description: 'Linear distance model PannerNode'},
+ (task, should) => {
+ // Create offline audio context.
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(context, 'linear', should).then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html
new file mode 100644
index 0000000..5c3df0e
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-basic.html
@@ -0,0 +1,298 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Basic PannerNode with Automation Position Properties
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/panner-formulas.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let sampleRate = 48000;
+
+ // These tests are quite slow, so don't run for many frames. 256 frames
+ // should be enough to demonstrate that automations are working.
+ let renderFrames = 256;
+ let renderDuration = renderFrames / sampleRate;
+
+ let audit = Audit.createTaskRunner();
+
+ // Array of tests for setting the panner positions. These tests basically
+ // verify that the position setters for the panner and listener are
+ // working correctly.
+ let testConfig = [
+ {
+ setter: 'positionX',
+ },
+ {
+ setter: 'positionY',
+ },
+ {
+ setter: 'positionZ',
+ }
+ ];
+
+ // Create tests for the panner position setters. Both mono and steroe
+ // sources are tested.
+ for (let k = 0; k < testConfig.length; ++k) {
+ let config = testConfig[k];
+ // Function to create the test to define the test.
+ let tester = function(config, channelCount) {
+ return (task, should) => {
+ let nodes = createGraph(channelCount);
+ let {context, source, panner} = nodes;
+
+ let message = channelCount == 1 ? 'Mono' : 'Stereo';
+ message += ' panner.' + config.setter;
+
+ testPositionSetter(should, {
+ nodes: nodes,
+ pannerSetter: panner[config.setter],
+ message: message
+ }).then(() => task.done());
+ }
+ };
+
+ audit.define('Stereo panner.' + config.setter, tester(config, 2));
+ audit.define('Mono panner.' + config.setter, tester(config, 1));
+ }
+
+ // Create tests for the listener position setters. Both mono and steroe
+ // sources are tested.
+ for (let k = 0; k < testConfig.length; ++k) {
+ let config = testConfig[k];
+ // Function to create the test to define the test.
+ let tester = function(config, channelCount) {
+ return (task, should) => {
+ let nodes = createGraph(channelCount);
+ let {context, source, panner} = nodes;
+
+ let message = channelCount == 1 ? 'Mono' : 'Stereo';
+ message += ' listener.' + config.setter;
+
+ // Some relatively arbitrary (non-default) position for the source
+ // location.
+ panner.setPosition(1, 0, 1);
+
+ testPositionSetter(should, {
+ nodes: nodes,
+ pannerSetter: context.listener[config.setter],
+ message: message
+ }).then(() => task.done());
+ }
+ };
+
+ audit.define('Stereo listener.' + config.setter, tester(config, 2));
+ audit.define('Mono listener.' + config.setter, tester(config, 1));
+ }
+
+ // Test setPosition method.
+ audit.define('setPosition', (task, should) => {
+ let {context, panner, source} = createGraph(2);
+
+ // Initialize source position (values don't really matter).
+ panner.setPosition(1, 1, 1);
+
+ // After some (unimportant) time, move the panner to a (any) new
+ // location.
+ let suspendFrame = 128;
+ context.suspend(suspendFrame / sampleRate)
+ .then(function() {
+ panner.setPosition(-100, 2000, 8000);
+ })
+ .then(context.resume.bind(context));
+
+ context.startRendering()
+ .then(function(resultBuffer) {
+ verifyPannerOutputChanged(
+ should, resultBuffer,
+ {message: 'setPosition', suspendFrame: suspendFrame});
+ })
+ .then(() => task.done());
+ });
+
+ audit.define('orientation setter', (task, should) => {
+ let {context, panner, source} = createGraph(2);
+
+ // For orientation to matter, we need to make the source directional,
+ // and also move away from the listener (because the default location is
+ // 0,0,0).
+ panner.setPosition(0, 0, 1);
+ panner.coneInnerAngle = 0;
+ panner.coneOuterAngle = 360;
+ panner.coneOuterGain = .001;
+
+ // After some (unimportant) time, change the panner orientation to a new
+ // orientation. The only constraint is that the orientation changes
+ // from before.
+ let suspendFrame = 128;
+ context.suspend(suspendFrame / sampleRate)
+ .then(function() {
+ panner.orientationX.value = -100;
+ panner.orientationY.value = 2000;
+ panner.orientationZ.value = 8000;
+ })
+ .then(context.resume.bind(context));
+
+ context.startRendering()
+ .then(function(resultBuffer) {
+ verifyPannerOutputChanged(should, resultBuffer, {
+ message: 'panner.orientation{XYZ}',
+ suspendFrame: suspendFrame
+ });
+ })
+ .then(() => task.done());
+ });
+
+ audit.define('forward setter', (task, should) => {
+ let {context, panner, source} = createGraph(2);
+
+ // For orientation to matter, we need to make the source directional,
+ // and also move away from the listener (because the default location is
+ // 0,0,0).
+ panner.setPosition(0, 0, 1);
+ panner.coneInnerAngle = 0;
+ panner.coneOuterAngle = 360;
+ panner.coneOuterGain = .001;
+
+ // After some (unimportant) time, change the panner orientation to a new
+ // orientation. The only constraint is that the orientation changes
+ // from before.
+ let suspendFrame = 128;
+ context.suspend(suspendFrame / sampleRate)
+ .then(function() {
+ context.listener.forwardX.value = -100;
+ context.listener.forwardY.value = 2000;
+ context.listener.forwardZ.value = 8000;
+ })
+ .then(context.resume.bind(context));
+
+ context.startRendering()
+ .then(function(resultBuffer) {
+ verifyPannerOutputChanged(should, resultBuffer, {
+ message: 'listener.forward{XYZ}',
+ suspendFrame: suspendFrame
+ });
+ })
+ .then(() => task.done());
+ });
+
+ audit.define('up setter', (task, should) => {
+ let {context, panner, source} = createGraph(2);
+
+ // For orientation to matter, we need to make the source directional,
+ // and also move away from the listener (because the default location is
+ // 0,0,0).
+ panner.setPosition(0, 0, 1);
+ panner.coneInnerAngle = 0;
+ panner.coneOuterAngle = 360;
+ panner.coneOuterGain = .001;
+ panner.setPosition(1, 0, 1);
+
+ // After some (unimportant) time, change the panner orientation to a new
+ // orientation. The only constraint is that the orientation changes
+ // from before.
+ let suspendFrame = 128;
+ context.suspend(suspendFrame / sampleRate)
+ .then(function() {
+ context.listener.upX.value = 100;
+ context.listener.upY.value = 100;
+ context.listener.upZ.value = 100;
+ ;
+ })
+ .then(context.resume.bind(context));
+
+ context.startRendering()
+ .then(function(resultBuffer) {
+ verifyPannerOutputChanged(
+ should, resultBuffer,
+ {message: 'listener.up{XYZ}', suspendFrame: suspendFrame});
+ })
+ .then(() => task.done());
+ });
+
+ audit.run();
+
+ function createGraph(channelCount) {
+ let context = new OfflineAudioContext(2, renderFrames, sampleRate);
+ let panner = context.createPanner();
+ let source = context.createBufferSource();
+ source.buffer =
+ createConstantBuffer(context, 1, channelCount == 1 ? 1 : [1, 2]);
+ source.loop = true;
+
+ source.connect(panner);
+ panner.connect(context.destination);
+
+ source.start();
+ return {context: context, source: source, panner: panner};
+ }
+
+ function testPositionSetter(should, options) {
+ let {nodes, pannerSetter, message} = options;
+
+ let {context, source, panner} = nodes;
+
+ // Set panner x position. (Value doesn't matter);
+ pannerSetter.value = 1;
+
+ // Wait a bit and set a new position. (Actual time and position doesn't
+ // matter).
+ let suspendFrame = 128;
+ context.suspend(suspendFrame / sampleRate)
+ .then(function() {
+ pannerSetter.value = 10000;
+ })
+ .then(context.resume.bind(context));
+
+ return context.startRendering().then(function(resultBuffer) {
+ verifyPannerOutputChanged(
+ should, resultBuffer,
+ {message: message, suspendFrame: suspendFrame});
+ });
+ }
+
+ function verifyPannerOutputChanged(should, resultBuffer, options) {
+ let {message, suspendFrame} = options;
+ // Verify that the first part of output is constant. (Doesn't matter
+ // what.)
+ let data0 = resultBuffer.getChannelData(0);
+ let data1 = resultBuffer.getChannelData(1);
+
+ let middle = '[0, ' + suspendFrame + ') ';
+ should(
+ data0.slice(0, suspendFrame),
+ message + '.value frame ' + middle + 'channel 0')
+ .beConstantValueOf(data0[0]);
+ should(
+ data1.slice(0, suspendFrame),
+ message + '.value frame ' + middle + 'channel 1')
+ .beConstantValueOf(data1[0]);
+
+ // The rest after suspendTime should be constant and different from the
+ // first part.
+ middle = '[' + suspendFrame + ', ' + renderFrames + ') ';
+ should(
+ data0.slice(suspendFrame),
+ message + '.value frame ' + middle + 'channel 0')
+ .beConstantValueOf(data0[suspendFrame]);
+ should(
+ data1.slice(suspendFrame),
+ message + '.value frame ' + middle + 'channel 1')
+ .beConstantValueOf(data1[suspendFrame]);
+ should(
+ data0[suspendFrame],
+ message + ': Output at frame ' + suspendFrame + ' channel 0')
+ .notBeEqualTo(data0[0]);
+ should(
+ data1[suspendFrame],
+ message + ': Output at frame ' + suspendFrame + ' channel 1')
+ .notBeEqualTo(data1[0]);
+ }
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html
new file mode 100644
index 0000000..7afc9c2
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-equalpower-stereo.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ panner-automation-equalpower-stereo.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/panner-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ // To test the panner, we create a number of panner nodes
+ // equally spaced on a semicircle at unit distance. The
+ // semicircle covers the azimuth range from -90 to 90 deg,
+ // covering full left to full right. Each source is an impulse
+ // turning at a different time and we check that the rendered
+ // impulse has the expected gain.
+ audit.define(
+ {
+ label: 'test',
+ description:
+ 'Equal-power panner model of AudioPannerNode with stereo source',
+ },
+ (task, should) => {
+ // Create offline audio context.
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(
+ context, should, nodesToCreate, 2,
+ function(panner, x, y, z) {
+ panner.positionX.value = x;
+ panner.positionY.value = y;
+ panner.positionZ.value = z;
+ })
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html
new file mode 100644
index 0000000..8e09e86
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-automation-position.html
@@ -0,0 +1,265 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Automation of PannerNode Positions
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/panner-formulas.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let sampleRate = 48000;
+ // These tests are quite slow, so don't run for many frames. 256 frames
+ // should be enough to demonstrate that automations are working.
+ let renderFrames = 256;
+ let renderDuration = renderFrames / sampleRate;
+
+ let context;
+ let panner;
+
+ let audit = Audit.createTaskRunner();
+
+ // Set of tests for the panner node with automations applied to the
+ // position of the source.
+ let testConfigs = [
+ {
+ // Distance model parameters for the panner
+ distanceModel: {model: 'inverse', rolloff: 1},
+ // Initial location of the source
+ startPosition: [0, 0, 1],
+ // Final position of the source. For this test, we only want to move
+ // on the z axis which
+ // doesn't change the azimuth angle.
+ endPosition: [0, 0, 10000],
+ },
+ {
+ distanceModel: {model: 'inverse', rolloff: 1},
+ startPosition: [0, 0, 1],
+ // An essentially random end position, but it should be such that
+ // azimuth angle changes as
+ // we move from the start to the end.
+ endPosition: [20000, 30000, 10000],
+ errorThreshold: [
+ {
+ // Error threshold for 1-channel case
+ relativeThreshold: 4.8124e-7
+ },
+ {
+ // Error threshold for 2-channel case
+ relativeThreshold: 4.3267e-7
+ }
+ ],
+ },
+ {
+ distanceModel: {model: 'exponential', rolloff: 1.5},
+ startPosition: [0, 0, 1],
+ endPosition: [20000, 30000, 10000],
+ errorThreshold:
+ [{relativeThreshold: 5.0783e-7}, {relativeThreshold: 5.2180e-7}]
+ },
+ {
+ distanceModel: {model: 'linear', rolloff: 1},
+ startPosition: [0, 0, 1],
+ endPosition: [20000, 30000, 10000],
+ errorThreshold: [
+ {relativeThreshold: 6.5324e-6}, {relativeThreshold: 6.5756e-6}
+ ]
+ }
+ ];
+
+ for (let k = 0; k < testConfigs.length; ++k) {
+ let config = testConfigs[k];
+ let tester = function(c, channelCount) {
+ return (task, should) => {
+ runTest(should, c, channelCount).then(() => task.done());
+ }
+ };
+
+ let baseTestName = config.distanceModel.model +
+ ' rolloff: ' + config.distanceModel.rolloff;
+
+ // Define tasks for both 1-channel and 2-channel
+ audit.define(k + ': 1-channel ' + baseTestName, tester(config, 1));
+ audit.define(k + ': 2-channel ' + baseTestName, tester(config, 2));
+ }
+
+ audit.run();
+
+ function runTest(should, options, channelCount) {
+ // Output has 5 channels: channels 0 and 1 are for the stereo output of
+ // the panner node. Channels 2-5 are the for automation of the x,y,z
+ // coordinate so that we have actual coordinates used for the panner
+ // automation.
+ context = new OfflineAudioContext(5, renderFrames, sampleRate);
+
+ // Stereo source for the panner.
+ let source = context.createBufferSource();
+ source.buffer = createConstantBuffer(
+ context, renderFrames, channelCount == 1 ? 1 : [1, 2]);
+
+ panner = context.createPanner();
+ panner.distanceModel = options.distanceModel.model;
+ panner.rolloffFactor = options.distanceModel.rolloff;
+ panner.panningModel = 'equalpower';
+
+ // Source and gain node for the z-coordinate calculation.
+ let dist = context.createBufferSource();
+ dist.buffer = createConstantBuffer(context, 1, 1);
+ dist.loop = true;
+ let gainX = context.createGain();
+ let gainY = context.createGain();
+ let gainZ = context.createGain();
+ dist.connect(gainX);
+ dist.connect(gainY);
+ dist.connect(gainZ);
+
+ // Set the gain automation to match the z-coordinate automation of the
+ // panner.
+
+ // End the automation some time before the end of the rendering so we
+ // can verify that automation has the correct end time and value.
+ let endAutomationTime = 0.75 * renderDuration;
+
+ gainX.gain.setValueAtTime(options.startPosition[0], 0);
+ gainX.gain.linearRampToValueAtTime(
+ options.endPosition[0], endAutomationTime);
+ gainY.gain.setValueAtTime(options.startPosition[1], 0);
+ gainY.gain.linearRampToValueAtTime(
+ options.endPosition[1], endAutomationTime);
+ gainZ.gain.setValueAtTime(options.startPosition[2], 0);
+ gainZ.gain.linearRampToValueAtTime(
+ options.endPosition[2], endAutomationTime);
+
+ dist.start();
+
+ // Splitter and merger to map the panner output and the z-coordinate
+ // automation to the correct channels in the destination.
+ let splitter = context.createChannelSplitter(2);
+ let merger = context.createChannelMerger(5);
+
+ source.connect(panner);
+ // Split the output of the panner to separate channels
+ panner.connect(splitter);
+
+ // Merge the panner outputs and the z-coordinate output to the correct
+ // destination channels.
+ splitter.connect(merger, 0, 0);
+ splitter.connect(merger, 1, 1);
+ gainX.connect(merger, 0, 2);
+ gainY.connect(merger, 0, 3);
+ gainZ.connect(merger, 0, 4);
+
+ merger.connect(context.destination);
+
+ // Initialize starting point of the panner.
+ panner.positionX.setValueAtTime(options.startPosition[0], 0);
+ panner.positionY.setValueAtTime(options.startPosition[1], 0);
+ panner.positionZ.setValueAtTime(options.startPosition[2], 0);
+
+ // Automate z coordinate to move away from the listener
+ panner.positionX.linearRampToValueAtTime(
+ options.endPosition[0], 0.75 * renderDuration);
+ panner.positionY.linearRampToValueAtTime(
+ options.endPosition[1], 0.75 * renderDuration);
+ panner.positionZ.linearRampToValueAtTime(
+ options.endPosition[2], 0.75 * renderDuration);
+
+ source.start();
+
+ // Go!
+ return context.startRendering().then(function(renderedBuffer) {
+ // Get the panner outputs
+ let data0 = renderedBuffer.getChannelData(0);
+ let data1 = renderedBuffer.getChannelData(1);
+ let xcoord = renderedBuffer.getChannelData(2);
+ let ycoord = renderedBuffer.getChannelData(3);
+ let zcoord = renderedBuffer.getChannelData(4);
+
+ // We're doing a linear ramp on the Z axis with the equalpower panner,
+ // so the equalpower panning gain remains constant. We only need to
+ // model the distance effect.
+
+ // Compute the distance gain
+ let distanceGain = new Float32Array(xcoord.length);
+ ;
+
+ if (panner.distanceModel === 'inverse') {
+ for (let k = 0; k < distanceGain.length; ++k) {
+ distanceGain[k] =
+ inverseDistance(panner, xcoord[k], ycoord[k], zcoord[k])
+ }
+ } else if (panner.distanceModel === 'linear') {
+ for (let k = 0; k < distanceGain.length; ++k) {
+ distanceGain[k] =
+ linearDistance(panner, xcoord[k], ycoord[k], zcoord[k])
+ }
+ } else if (panner.distanceModel === 'exponential') {
+ for (let k = 0; k < distanceGain.length; ++k) {
+ distanceGain[k] =
+ exponentialDistance(panner, xcoord[k], ycoord[k], zcoord[k])
+ }
+ }
+
+ // Compute the expected result. Since we're on the z-axis, the left
+ // and right channels pass through the equalpower panner unchanged.
+ // Only need to apply the distance gain.
+ let buffer0 = source.buffer.getChannelData(0);
+ let buffer1 =
+ channelCount == 2 ? source.buffer.getChannelData(1) : buffer0;
+
+ let azimuth = new Float32Array(buffer0.length);
+
+ for (let k = 0; k < data0.length; ++k) {
+ azimuth[k] = calculateAzimuth(
+ [xcoord[k], ycoord[k], zcoord[k]],
+ [
+ context.listener.positionX.value,
+ context.listener.positionY.value,
+ context.listener.positionZ.value
+ ],
+ [
+ context.listener.forwardX.value,
+ context.listener.forwardY.value,
+ context.listener.forwardZ.value
+ ],
+ [
+ context.listener.upX.value, context.listener.upY.value,
+ context.listener.upZ.value
+ ]);
+ }
+
+ let expected = applyPanner(azimuth, buffer0, buffer1, channelCount);
+ let expected0 = expected.left;
+ let expected1 = expected.right;
+
+ for (let k = 0; k < expected0.length; ++k) {
+ expected0[k] *= distanceGain[k];
+ expected1[k] *= distanceGain[k];
+ }
+
+ let info = options.distanceModel.model +
+ ', rolloff: ' + options.distanceModel.rolloff;
+ let prefix = channelCount + '-channel ' +
+ '[' + options.startPosition[0] + ', ' + options.startPosition[1] +
+ ', ' + options.startPosition[2] + '] -> [' +
+ options.endPosition[0] + ', ' + options.endPosition[1] + ', ' +
+ options.endPosition[2] + ']: ';
+
+ let errorThreshold = 0;
+
+ if (options.errorThreshold)
+ errorThreshold = options.errorThreshold[channelCount - 1]
+
+ should(data0, prefix + 'distanceModel: ' + info + ', left channel')
+ .beCloseToArray(expected0, {absoluteThreshold: errorThreshold});
+ should(data1, prefix + 'distanceModel: ' + info + ', right channel')
+ .beCloseToArray(expected1, {absoluteThreshold: errorThreshold});
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html b/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html
new file mode 100644
index 0000000..dae58c9
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping.html
@@ -0,0 +1,233 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Clamping of Distance for PannerNode
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ // Arbitrary sample rate and render length.
+ let sampleRate = 48000;
+ let renderFrames = 128;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define('ref-distance-error', (task, should) => {
+ testDistanceLimits(should, {name: 'refDistance', isZeroAllowed: true});
+ task.done();
+ });
+
+ audit.define('max-distance-error', (task, should) => {
+ testDistanceLimits(should, {name: 'maxDistance', isZeroAllowed: false});
+ task.done();
+ });
+
+ function testDistanceLimits(should, options) {
+ // Verify that exceptions are thrown for invalid values of refDistance.
+ let context = new OfflineAudioContext(1, renderFrames, sampleRate);
+
+ let attrName = options.name;
+ let prefix = 'new PannerNode(c, {' + attrName + ': ';
+
+ should(function() {
+ let nodeOptions = {};
+ nodeOptions[attrName] = -1;
+ new PannerNode(context, nodeOptions);
+ }, prefix + '-1})').throw('RangeError');
+
+ if (options.isZeroAllowed) {
+ should(function() {
+ let nodeOptions = {};
+ nodeOptions[attrName] = 0;
+ new PannerNode(context, nodeOptions);
+ }, prefix + '0})').notThrow();
+ } else {
+ should(function() {
+ let nodeOptions = {};
+ nodeOptions[attrName] = 0;
+ new PannerNode(context, nodeOptions);
+ }, prefix + '0})').throw('RangeError');
+ }
+
+ // The smallest representable positive single float.
+ let leastPositiveDoubleFloat = 4.9406564584124654e-324;
+
+ should(function() {
+ let nodeOptions = {};
+ nodeOptions[attrName] = leastPositiveDoubleFloat;
+ new PannerNode(context, nodeOptions);
+ }, prefix + leastPositiveDoubleFloat + '})').notThrow();
+
+ prefix = 'panner.' + attrName + ' = ';
+ panner = new PannerNode(context);
+ should(function() {
+ panner[attrName] = -1;
+ }, prefix + '-1').throw('RangeError');
+
+ if (options.isZeroAllowed) {
+ should(function() {
+ panner[attrName] = 0;
+ }, prefix + '0').notThrow();
+ } else {
+ should(function() {
+ panner[attrName] = 0;
+ }, prefix + '0').throw('RangeError');
+ }
+
+ should(function() {
+ panner[attrName] = leastPositiveDoubleFloat;
+ }, prefix + leastPositiveDoubleFloat).notThrow();
+ }
+
+ audit.define('min-distance', (task, should) => {
+ // Test clamping of panner distance to refDistance for all of the
+ // distance models. The actual distance is arbitrary as long as it's
+ // less than refDistance. We test default and non-default values for
+ // the panner's refDistance and maxDistance.
+ // correctly.
+ Promise
+ .all([
+ runTest(should, {
+ distance: 0.01,
+ distanceModel: 'linear',
+ }),
+ runTest(should, {
+ distance: 0.01,
+ distanceModel: 'exponential',
+ }),
+ runTest(should, {
+ distance: 0.01,
+ distanceModel: 'inverse',
+ }),
+ runTest(should, {
+ distance: 2,
+ distanceModel: 'linear',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ runTest(should, {
+ distance: 2,
+ distanceModel: 'exponential',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ runTest(should, {
+ distance: 2,
+ distanceModel: 'inverse',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ ])
+ .then(() => task.done());
+ });
+
+ audit.define('max-distance', (task, should) => {
+ // Like the "min-distance" task, but for clamping to the max
+ // distance. The actual distance is again arbitrary as long as it is
+ // greater than maxDistance.
+ Promise
+ .all([
+ runTest(should, {
+ distance: 20000,
+ distanceModel: 'linear',
+ }),
+ runTest(should, {
+ distance: 21000,
+ distanceModel: 'exponential',
+ }),
+ runTest(should, {
+ distance: 23000,
+ distanceModel: 'inverse',
+ }),
+ runTest(should, {
+ distance: 5000,
+ distanceModel: 'linear',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ runTest(should, {
+ distance: 5000,
+ distanceModel: 'exponential',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ runTest(should, {
+ distance: 5000,
+ distanceModel: 'inverse',
+ maxDistance: 1000,
+ refDistance: 10,
+ }),
+ ])
+ .then(() => task.done());
+ });
+
+ function runTest(should, options) {
+ let context = new OfflineAudioContext(2, renderFrames, sampleRate);
+ let src = new OscillatorNode(context, {
+ type: 'sawtooth',
+ frequency: 20 * 440,
+ });
+
+ // Set panner options. Use a non-default rolloffFactor so that the
+ // various distance models look distinctly different.
+ let pannerOptions = {};
+ Object.assign(pannerOptions, options, {rolloffFactor: 0.5});
+
+ let pannerRef = new PannerNode(context, pannerOptions);
+ let pannerTest = new PannerNode(context, pannerOptions);
+
+ // Split the panner output so we can grab just one of the output
+ // channels.
+ let splitRef = new ChannelSplitterNode(context, {numberOfOutputs: 2});
+ let splitTest = new ChannelSplitterNode(context, {numberOfOutputs: 2});
+
+ // Merge the panner outputs back into one stereo stream for the
+ // destination.
+ let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
+
+ src.connect(pannerTest).connect(splitTest).connect(merger, 0, 0);
+ src.connect(pannerRef).connect(splitRef).connect(merger, 0, 1);
+
+ merger.connect(context.destination);
+
+ // Move the panner some distance away. Arbitrarily select the x
+ // direction. For the reference panner, manually clamp the distance.
+ // All models clamp the distance to a minimum of refDistance. Only the
+ // linear model also clamps to a maximum of maxDistance.
+ let xRef = Math.max(options.distance, pannerRef.refDistance);
+
+ if (pannerRef.distanceModel === 'linear') {
+ xRef = Math.min(xRef, pannerRef.maxDistance);
+ }
+
+ let xTest = options.distance;
+
+ pannerRef.positionZ.setValueAtTime(xRef, 0);
+ pannerTest.positionZ.setValueAtTime(xTest, 0);
+
+ src.start();
+
+ return context.startRendering().then(function(resultBuffer) {
+ let actual = resultBuffer.getChannelData(0);
+ let expected = resultBuffer.getChannelData(1);
+
+ should(
+ xTest < pannerRef.refDistance || xTest > pannerRef.maxDistance,
+ 'Model: ' + options.distanceModel + ': Distance (' + xTest +
+ ') is outside the range [' + pannerRef.refDistance + ', ' +
+ pannerRef.maxDistance + ']')
+ .beEqualTo(true);
+ should(actual, 'Test panner output ' + JSON.stringify(options))
+ .beEqualToArray(expected);
+ });
+ }
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html b/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html
new file mode 100644
index 0000000..2a0225b
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower-stereo.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ panner-equalpower-stereo.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/panner-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ // To test the panner, we create a number of panner nodes
+ // equally spaced on a semicircle at unit distance. The
+ // semicircle covers the azimuth range from -90 to 90 deg,
+ // covering full left to full right. Each source is an impulse
+ // turning at a different time and we check that the rendered
+ // impulse has the expected gain.
+ audit.define(
+ {
+ label: 'test',
+ description:
+ 'Equal-power panner model of AudioPannerNode with stereo source'
+ },
+ (task, should) => {
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(
+ context, should, nodesToCreate, 2,
+ function(panner, x, y, z) {
+ panner.setPosition(x, y, z);
+ })
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html b/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html
new file mode 100644
index 0000000..3ff21b6
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-equalpower.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ panner-equalpower.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/panner-model-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ // To test the panner, we create a number of panner nodes
+ // equally spaced on a semicircle at unit distance. The
+ // semicircle covers the azimuth range from -90 to 90 deg,
+ // covering full left to full right. Each source is an impulse
+ // turning at a different time and we check that the rendered
+ // impulse has the expected gain.
+ audit.define(
+ {
+ label: 'test',
+ description: 'Equal-power panner model of AudioPannerNode',
+ },
+ (task, should) => {
+ // Create offline audio context.
+ context = new OfflineAudioContext(
+ 2, sampleRate * renderLengthSeconds, sampleRate);
+
+ createTestAndRun(
+ context, should, nodesToCreate, 1,
+ function(panner, x, y, z) {
+ panner.setPosition(x, y, z);
+ })
+ .then(() => task.done());
+ ;
+ });
+
+ // Test that a mono source plays out on both the left and right channels
+ // when the source and listener positions are the same.
+ audit.define(
+ {
+ label: 'mono source=listener',
+ description: 'Source and listener at the same position'
+ },
+ (task, should) => {
+ // Must be stereo to verify output and only need a short duration
+ let context =
+ new OfflineAudioContext(2, 0.25 * sampleRate, sampleRate);
+
+ // Arbitrary position for source and listener. Just so we don't use
+ // defaults positions.
+ let x = 1;
+ let y = 2;
+ let z = 3;
+
+ context.listener.setPosition(x, y, z);
+
+ let src = new OscillatorNode(context);
+ let panner = new PannerNode(context, {
+ panningModel: 'equalpower',
+ positionX: x,
+ positionY: y,
+ positionZ: z
+ });
+
+ src.connect(panner).connect(context.destination);
+
+ src.start();
+
+ context.startRendering()
+ .then(renderedBuffer => {
+ // Verify that both channels have the same data because they
+ // should when the source and listener are at the same
+ // position
+ let c0 = renderedBuffer.getChannelData(0);
+ let c1 = renderedBuffer.getChannelData(1);
+ should(c0, 'Mono: Left and right channels').beEqualToArray(c1);
+ })
+ .then(() => task.done());
+ });
+
+ // Test that a stereo source plays out on both the left and right channels
+ // when the source and listener positions are the same.
+ audit.define(
+ {
+ label: 'stereo source=listener',
+ description: 'Source and listener at the same position'
+ },
+ (task, should) => {
+ // Must be stereo to verify output and only need a short duration.
+ let context =
+ new OfflineAudioContext(2, 0.25 * sampleRate, sampleRate);
+
+ // Arbitrary position for source and listener. Just so we don't use
+ // defaults positions.
+ let x = 1;
+ let y = 2;
+ let z = 3;
+
+ context.listener.setPosition(x, y, z);
+
+ let src = new OscillatorNode(context);
+ let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
+ let panner = new PannerNode(context, {
+ panningModel: 'equalpower',
+ positionX: x,
+ positionY: y,
+ positionZ: z
+ });
+
+ // Make the oscillator a stereo signal (with identical signals on
+ // each channel).
+ src.connect(merger, 0, 0);
+ src.connect(merger, 0, 1);
+
+ merger.connect(panner).connect(context.destination);
+
+ src.start();
+
+ context.startRendering()
+ .then(renderedBuffer => {
+ // Verify that both channels have the same data because they
+ // should when the source and listener are at the same
+ // position.
+ let c0 = renderedBuffer.getChannelData(0);
+ let c1 = renderedBuffer.getChannelData(1);
+ should(c0, 'Stereo: Left and right channels').beEqualToArray(c1);
+ })
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html b/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html
new file mode 100644
index 0000000..e1519f8
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Clamping of PannerNode rolloffFactor
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ // Fairly arbitrary sample rate and render frames.
+ let sampleRate = 16000;
+ let renderFrames = 2048;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define('linear-clamp-low', (task, should) => {
+ runTest(should, {
+ distanceModel: 'linear',
+ // Fairly arbitrary value outside the nominal range
+ rolloffFactor: -1,
+ clampedRolloff: 0
+ }).then(() => task.done());
+ });
+
+ audit.define('linear-clamp-high', (task, should) => {
+ runTest(should, {
+ distanceModel: 'linear',
+ // Fairly arbitrary value outside the nominal range
+ rolloffFactor: 2,
+ clampedRolloff: 1
+ }).then(() => task.done());
+ });
+
+ audit.define('inverse-clamp', (task, should) => {
+ runTest(should, {
+ distanceModel: 'inverse',
+ // Fairly arbitrary value outside the nominal range
+ rolloffFactor: -1,
+ clampedRolloff: 0
+ }).then(() => task.done());
+ });
+
+ audit.define('exponential-clamp', (task, should) => {
+ runTest(should, {
+ distanceModel: 'exponential',
+ // Fairly arbitrary value outside the nominal range
+ rolloffFactor: -2,
+ clampedRolloff: 0
+ }).then(() => task.done());
+ });
+
+ // Test clamping of the rolloffFactor. The test is done by comparing the
+ // output of a panner with the rolloffFactor set outside the nominal range
+ // against the output of a panner with the rolloffFactor clamped to the
+ // nominal range. The outputs should be the same.
+ //
+ // The |options| dictionary should contain the members
+ // distanceModel - The distance model to use for the panners
+ // rolloffFactor - The desired rolloffFactor. Should be outside the
+ // nominal range of the distance model.
+ // clampedRolloff - The rolloffFactor (above) clamped to the nominal
+ // range for the given distance model.
+ function runTest(should, options) {
+ // Offline context with two channels. The first channel is the panner
+ // node under test. The second channel is the reference panner node.
+ let context = new OfflineAudioContext(2, renderFrames, sampleRate);
+
+ // The source for the panner nodes. This is fairly arbitrary.
+ let src = new OscillatorNode(context, {type: 'sawtooth'});
+
+ // Create the test panner with the specified rolloff factor. The
+ // position is fairly arbitrary, but something that is not the default
+ // is good to show the distance model had some effect.
+ let pannerTest = new PannerNode(context, {
+ rolloffFactor: options.rolloffFactor,
+ distanceModel: options.distanceModel,
+ positionX: 5000
+ });
+
+ // Create the reference panner with the rolloff factor clamped to the
+ // appropriate limit.
+ let pannerRef = new PannerNode(context, {
+ rolloffFactor: options.clampedRolloff,
+ distanceModel: options.distanceModel,
+ positionX: 5000
+ });
+
+
+ // Connect the source to the panners to the destination appropriately.
+ let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
+
+
+ src.connect(pannerTest).connect(merger, 0, 0);
+ src.connect(pannerRef).connect(merger, 0, 1);
+
+ merger.connect(context.destination);
+
+ src.start();
+
+ return context.startRendering().then(function(resultBuffer) {
+ // The two channels should be the same due to the clamping. Verify
+ // that they are the same.
+ let actual = resultBuffer.getChannelData(0);
+ let expected = resultBuffer.getChannelData(1);
+
+ let message = 'Panner distanceModel: "' + options.distanceModel +
+ '", rolloffFactor: ' + options.rolloffFactor;
+
+ should(actual, message).beEqualToArray(expected);
+ });
+ }
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html b/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html
new file mode 100644
index 0000000..32402f5
--- /dev/null
+++ b/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html
@@ -0,0 +1,152 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ pannernode-basic.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let context;
+ let panner;
+ let audit = Audit.createTaskRunner();
+
+ audit.define('initialize', (task, should) => {
+ should(() => {
+ context = new AudioContext();
+ panner = context.createPanner();
+ }, 'Initialize context and panner').notThrow();
+ task.done();
+ });
+
+ audit.define('basic', (task, should) => {
+ should(panner.numberOfInputs, 'panner.numberOfInputs').beEqualTo(1);
+ should(panner.numberOfOutputs, 'panner.numberOfOutputs').beEqualTo(1);
+ should(panner.refDistance, 'panner.refDistance').beEqualTo(1);
+ panner.refDistance = 270.5;
+ should(panner.refDistance, 'panner.refDistance = 270.5')
+ .beEqualTo(270.5);
+ should(panner.maxDistance, 'panner.maxDistance').beEqualTo(10000);
+ panner.maxDistance = 100.5;
+ should(panner.maxDistance, 'panner.maxDistance = 100.5')
+ .beEqualTo(100.5);
+ should(panner.rolloffFactor, 'panner.rolloffFactor').beEqualTo(1);
+ panner.rolloffFactor = 0.75;
+ should(panner.rolloffFactor, 'panner.rolloffFactor = 0.75')
+ .beEqualTo(0.75);
+ should(panner.coneInnerAngle, 'panner.coneInnerAngle').beEqualTo(360);
+ panner.coneInnerAngle = 240.5;
+ should(panner.coneInnerAngle, 'panner.coneInnerAngle = 240.5')
+ .beEqualTo(240.5);
+ should(panner.coneOuterAngle, 'panner.coneOuterAngle').beEqualTo(360);
+ panner.coneOuterAngle = 166.5;
+ should(panner.coneOuterAngle, 'panner.coneOuterAngle = 166.5')
+ .beEqualTo(166.5);
+ should(panner.coneOuterGain, 'panner.coneOuterGain').beEqualTo(0);
+ panner.coneOuterGain = 0.25;
+ should(panner.coneOuterGain, 'panner.coneOuterGain = 0.25')
+ .beEqualTo(0.25);
+ should(panner.panningModel, 'panner.panningModel')
+ .beEqualTo('equalpower');
+ should(panner.distanceModel)
+ .beEqualTo('inverse', 'panner.distanceModel');
+
+ should(panner.positionX.value, 'panner.positionX').beEqualTo(0);
+ should(panner.positionY.value, 'panner.positionY').beEqualTo(0);
+ should(panner.positionZ.value, 'panner.positionZ').beEqualTo(0);
+ should(panner.orientationX.value, 'panner.orientationX').beEqualTo(1);
+ should(panner.orientationY.value, 'panner.orientationY').beEqualTo(0);
+ should(panner.orientationZ.value, 'panner.orientationZ').beEqualTo(0);
+
+ task.done();
+ });
+
+ audit.define('listener', (task, should) => {
+ should(context.listener.positionX.value, 'listener.positionX')
+ .beEqualTo(0);
+ should(context.listener.positionY.value, 'listener.positionY')
+ .beEqualTo(0);
+ should(context.listener.positionZ.value, 'listener.positionZ')
+ .beEqualTo(0);
+ should(context.listener.forwardX.value, 'listener.forwardX')
+ .beEqualTo(0);
+ should(context.listener.forwardY.value, 'listener.forwardY')
+ .beEqualTo(0);
+ should(context.listener.forwardZ.value, 'listener.forwardZ')
+ .beEqualTo(-1);
+ should(context.listener.upX.value, 'listener.upX').beEqualTo(0);
+ should(context.listener.upY.value, 'listener.upY').beEqualTo(1);
+ should(context.listener.upZ.value, 'listener.upZ').beEqualTo(0);
+
+ task.done();
+ });
+
+ audit.define('panning models', (task, should) => {
+ // Check that the .panningModel attribute can be set to all legal
+ // values.
+ let panningModels = ['equalpower', 'HRTF'];
+
+ for (let i = 0; i < panningModels.length; ++i) {
+ should(function() {
+ panner.panningModel = panningModels[i];
+ }, 'Set panner.panningModel = "' + panningModels[i] + '"').notThrow();
+
+ should(
+ panner.panningModel,
+ 'panner.panningModel = "' + panningModels[i] + '"')
+ .beEqualTo(panningModels[i]);
+ }
+
+ should(function() {
+ panner.panningModel = 'invalid';
+ }, 'panner.panningModel = "invalid"').notThrow();
+
+ should(panner.panningModel, 'panner.panningModel after invalid setter')
+ .beEqualTo('HRTF');
+
+ // Check that numerical values are no longer supported. We shouldn't
+ // throw and the value shouldn't be changed.
+ panner.panningModel = 'HRTF';
+ should(function() {
+ panner.panningModel = 1;
+ }, 'panner.panningModel = 1').notThrow();
+
+ should(panner.panningModel, 'panner.panningModel').beEqualTo('HRTF');
+
+ task.done();
+ });
+
+ audit.define('distance models', (task, should) => {
+ // Check that the .panningModel attribute can be set to all legal
+ // values.
+ let distanceModels = ['linear', 'inverse', 'exponential'];
+
+ for (let i = 0; i < distanceModels.length; ++i) {
+ should(function() {
+ panner.distanceModel = distanceModels[i];
+ }, 'panner.distanceModel = "' + distanceModels[i] + '"').notThrow();
+
+ should(
+ panner.distanceModel,
+ 'panner.distanceModel = "' + distanceModels[i] + '"')
+ .beEqualTo(distanceModels[i]);
+ }
+
+ should(function() {
+ panner.distanceModel = 'invalid';
+ }, 'panner.distanceModel = "invalid"').notThrow();
+
+ should(panner.distanceModel, 'panner.distanceModel')
+ .beEqualTo('exponential');
+
+ task.done();
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/webauthn/createcredential-badargs-attestation.https.html b/webauthn/createcredential-badargs-attestation.https.html
new file mode 100644
index 0000000..a56f4f0
--- /dev/null
+++ b/webauthn/createcredential-badargs-attestation.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() attestation parameter Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // attestation bad values
+ new CreateCredentialsTest("options.publicKey.attestation", {}).runTest("Bad attestation parameter: attestation is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", []).runTest("Bad attestation parameter: attestation is empty array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", null).runTest("Bad attestation parameter: attestation is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", "noneofyourbusiness").runTest("Bad attestation parameter: attestation is \"noneofyourbusiness\"", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", "").runTest("Bad attestation parameter: attestation is empty string", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-authnrselection.https.html b/webauthn/createcredential-badargs-authnrselection.https.html
new file mode 100644
index 0000000..2c42135
--- /dev/null
+++ b/webauthn/createcredential-badargs-authnrselection.https.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() authenticator selection Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var defaultAuthnrSel = {
+ authenticatorAttachment: "cross-platform",
+ requireResidentKey: false,
+ userVerification: "preferred"
+ };
+ // attachment
+ var authnrSelAttachPlatform = cloneObject(defaultAuthnrSel);
+ authnrSelAttachPlatform.authenticatorAttachment = "platform";
+ var authnrSelBadAttachEmptyStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachEmptyStr.authenticatorAttachment = "";
+ var authnrSelBadAttachEmptyObj = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachEmptyObj.authenticatorAttachment = {};
+ var authnrSelBadAttachNull = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachNull.authenticatorAttachment = null;
+ // resident key
+ var authnrSelRkTrue = cloneObject(defaultAuthnrSel);
+ authnrSelRkTrue.requireResidentKey = true;
+ var authnrSelRkBadString = cloneObject(defaultAuthnrSel);
+ authnrSelRkBadString.requireResidentKey = "foo";
+ // user verification
+ var authnrSelUvRequired = cloneObject(defaultAuthnrSel);
+ authnrSelUvRequired.userVerification = "required";
+ var authnrSelBadUvEmptyStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvEmptyStr.userVerification = "";
+ var authnrSelBadUvEmptyObj = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvEmptyObj.userVerification = {};
+ var authnrSelBadUvStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvStr.userVerification = "requiredshirtshoestshirt";
+ var authnrSelBadUvNull = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvNull.userVerification = null;
+
+ // authenticatorSelection bad values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", []).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", null).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", "").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", "none").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is string", new TypeError());
+
+ // authenticatorSelection bad attachment values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is null", new TypeError());
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachPlatform).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment platform", "NotAllowedError");
+
+ // authenticatorSelection bad requireResidentKey values
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkTrue).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey true", "NotAllowedError");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkBadString).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey is string", new TypeError());
+ // TODO: not sure if rk is "boolean" or "truthy"; add test cases if it should only accept boolean values
+
+ // authenticatorSelection bad userVerification values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification bad value", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification null", new TypeError());
+ // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvRequired).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification required", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cloneObject */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-challenge.https.html b/webauthn/createcredential-badargs-challenge.https.html
new file mode 100644
index 0000000..0ad67f2
--- /dev/null
+++ b/webauthn/createcredential-badargs-challenge.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() challenge Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad challenge values
+ new CreateCredentialsTest({path: "options.publicKey.challenge", value: undefined}).runTest("Bad challenge: challenge missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", "hi mom").runTest("Bad challenge: challenge is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", null).runTest("Bad challenge: challenge is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", {}).runTest("Bad challenge: challenge is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", new Array()).runTest("Bad challenge: challenge is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(0)).runTest("Bad challenge: challenge is empty ArrayBuffer", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-rp.https.html b/webauthn/createcredential-badargs-rp.https.html
index f06e02c..9958b2c 100644
--- a/webauthn/createcredential-badargs-rp.https.html
+++ b/webauthn/createcredential-badargs-rp.https.html
@@ -12,29 +12,29 @@
"use strict";
// rp bad values
- new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).testBadArgs("rp missing");
- new CreateCredentialsTest("options.publicKey.rp", "hi mom").testBadArgs("rp is string");
- // new CreateCredentialsTest("options.publicKey.rp", {}).testBadArgs("rp is empty object");
+ new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).runTest("Bad rp: rp missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp", "hi mom").runTest("Bad rp: rp is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp", {}).runTest("Bad rp: rp is empty object", new TypeError());
- // rp.id
- // new CreateCredentialsTest({path: "options.publicKey.rp.id", value: undefined}).testBadArgs("rp missing id");
- new CreateCredentialsTest("options.publicKey.rp.id", {}).testBadArgs("Bad rp: id is object");
- new CreateCredentialsTest("options.publicKey.rp.id", null).testBadArgs("Bad rp: id is null");
- new CreateCredentialsTest("options.publicKey.rp.id", "").testBadArgs("Bad rp: id is empty String");
+ // // rp.id
+ new CreateCredentialsTest("options.publicKey.rp.id", {}).runTest("Bad rp: id is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.id", null).runTest("Bad rp: id is null", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "").runTest("Bad rp: id is empty String", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "invalid domain.com").runTest("Bad rp: id is invalid domain (has space)", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "-invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with dash)", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "0invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with number)", "SecurityError");
- // rp.name
- // new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).testBadArgs("rp missing name");
- new CreateCredentialsTest("options.publicKey.rp.name", {}).testBadArgs("Bad rp: name is object");
- new CreateCredentialsTest("options.publicKey.rp.name", null).testBadArgs("Bad rp: name is null");
- new CreateCredentialsTest("options.publicKey.rp.name", "").testBadArgs("Bad rp: name is empty String");
+ // // rp.name
+ new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", {}).runTest("Bad rp: name is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", null).runTest("Bad rp: name is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", "").runTest("Bad rp: name is empty String", new TypeError());
- // rp.icon
- // new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).testBadArgs("rp missing icon");
- new CreateCredentialsTest("options.publicKey.rp.icon", {}).testBadArgs("Bad rp: icon is object");
- new CreateCredentialsTest("options.publicKey.rp.icon", null).testBadArgs("Bad rp: icon is null");
- new CreateCredentialsTest("options.publicKey.rp.icon", "").testBadArgs("Bad rp: icon is empty String");
- // TODO: see https://github.com/w3c/webauthn/issues/587 for the 'undefined' tests that are commented out above
- // TODO: unicode tests for icon URL (see also: USVString)
+ // // rp.icon
+ new CreateCredentialsTest("options.publicKey.rp.icon", {}).runTest("Bad rp: icon is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.icon", null).runTest("Bad rp: icon is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.icon", "").runTest("Bad rp: icon is empty String", new TypeError());
+ // // TODO: unicode tests for icon URL (see also: USVString)
});
/* JSHINT */
diff --git a/webauthn/createcredential-badargs-user.https.html b/webauthn/createcredential-badargs-user.https.html
new file mode 100644
index 0000000..dd1870a
--- /dev/null
+++ b/webauthn/createcredential-badargs-user.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() user Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // user bad values
+ new CreateCredentialsTest({path: "options.publicKey.user", value: undefined}).runTest("Bad user: user missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user", "hi mom").runTest("Bad user: user is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user", {}).runTest("Bad user: user is empty object", new TypeError());
+
+ // // user.id
+ new CreateCredentialsTest({path: "options.publicKey.user.id", value: undefined}).runTest("Bad user: id is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", {}).runTest("Bad user: id is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", null).runTest("Bad user: id is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", "").runTest("Bad user: id is empty String", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Array()).runTest("Bad user: id is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(0)).runTest("Bad user: id is empty ArrayBuffer", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(65)).runTest("Bad user: ArrayBuffer id is too long (65 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(33)).runTest("Bad user: Int16Array id is too long (66 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(17)).runTest("Bad user: Int32Array id is too long (68 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(17)).runTest("Bad user: Float32Array id is too long (68 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Float64Array(9)).runTest("Bad user: Float64Array id is too long (72 bytes)", new TypeError());
+ var buf = new ArrayBuffer(65);
+ new CreateCredentialsTest("options.publicKey.user.id", new DataView(buf)).runTest("Bad user: id is too long (65 bytes)", new TypeError());
+
+ // // user.name
+ new CreateCredentialsTest({path: "options.publicKey.user.name", value: undefined}).runTest("user missing name", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", {}).runTest("Bad user: name is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", null).runTest("Bad user: name is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", "").runTest("Bad user: name is empty String", new TypeError());
+
+ // // user.icon
+ new CreateCredentialsTest("options.publicKey.user.icon", {}).runTest("Bad user: icon is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.icon", null).runTest("Bad user: icon is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.icon", "").runTest("Bad user: icon is empty String", new TypeError());
+ // // TODO: unicode tests for icon URL (see also: USVString)
+
+ // // user.displayName
+ new CreateCredentialsTest({path: "options.publicKey.user.displayName", value: undefined}).runTest("Bad user: displayName is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", {}).runTest("Bad user: displayName is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", null).runTest("Bad user: displayName is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", "").runTest("Bad user: displayName is empty String", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-excludecredentials.https.html b/webauthn/createcredential-excludecredentials.https.html
new file mode 100644
index 0000000..a4cfb0a
--- /dev/null
+++ b/webauthn/createcredential-excludecredentials.https.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() excludeCredentials Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad excludeCredentials values
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", "hi mom").runTest("Bad excludeCredentials: string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", {}).runTest("Bad excludeCredentials: empty object", new TypeError());
+ // TODO: bad excludeCredentials with [{.type}] or [{.id}] or [{.transports}] wrong
+
+ // good excludeCredentials values
+ new CreateCredentialsTest({path: "options.publicKey.excludeCredentials", value: undefined}).runTest("excludeCredentials missing");
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", []).runTest("excludeCredentials empty array");
+
+ // proper excludeCredentials behavior
+ // should error on excluding existing credential
+ promise_test((t) => {
+ var cred1;
+ return Promise.resolve()
+ .then(() => {
+ return createCredential();
+ })
+ .then((cred) => {
+ cred1 = cred;
+ var excludeCred = {
+ id: cred.rawId,
+ type: "public-key"
+ };
+ var args = {
+ options: {
+ publicKey: {
+ excludeCredentials: [excludeCred]
+ }
+ }
+ };
+ var p = createCredential(args);
+ return promise_rejects (t, "NotAllowedError", p, "expected to fail on excluded credenetial");
+ });
+ }, "exclude existing credential");
+
+ // should not error on excluding random credential
+ promise_test(() => {
+ return Promise.resolve()
+ .then(() => {
+ return createCredential();
+ })
+ .then(() => {
+ var randomCredId = new Uint8Array(162);
+ window.crypto.getRandomValues(randomCredId);
+
+ var excludeCred = {
+ id: randomCredId,
+ type: "public-key"
+ };
+ var args = {
+ options: {
+ publicKey: {
+ excludeCredentials: [excludeCred]
+ }
+ }
+ };
+ return createCredential(args);
+ });
+ }, "exclude random (non-existing) credential");
+
+ // TODO: exclude including transport type (USB, BLE, NFC)
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test, promise_rejects */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-extensions.https.html b/webauthn/createcredential-extensions.https.html
new file mode 100644
index 0000000..3b3c9bf
--- /dev/null
+++ b/webauthn/createcredential-extensions.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var dummyExtension = {
+ foo: true,
+ bar: "yup"
+ };
+
+ // bad extension values
+ new CreateCredentialsTest("options.publicKey.extensions", "hi mom").runTest("Bad extensions: extensions is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", null).runTest("Bad extensions: extensions is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", []).runTest("Bad extensions: extensions is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0)).runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+ var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: badJson}).runTest("Bad extensions: malformatted JSON", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: dummyExtension}).runTest("Bad extensions: JavaScript object", new TypeError());
+ var badExtId = {};
+ badExtId[createRandomString(65)] = dummyExtension;
+ new CreateCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension}).runTest("Bad extensions: extension ID too long", new TypeError());
+
+ // phony extensions
+ // TODO: not sure if this should pass or fail
+ // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+ var randomExtId = {};
+ randomExtId[createRandomString(64)] = dummyExtension;
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)}).runTest("extensions is a nonsensical JSON string");
+
+ // TODO
+ // defined extensions:
+ // * appid
+ // * txAuthSimple
+ // * txAuthGeneric
+ // * authnSel
+ // * exts
+ // * uvi
+ // * loc
+ // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createRandomString */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-passing.https.html b/webauthn/createcredential-passing.https.html
index a66d3c1..25dba1d 100644
--- a/webauthn/createcredential-passing.https.html
+++ b/webauthn/createcredential-passing.https.html
@@ -12,9 +12,108 @@
"use strict";
// CreateCredentialTest passing tests
- new CreateCredentialsTest().test();
+
+ // default arguments
+ new CreateCredentialsTest().runTest("passing credentials.create() with default arguments");
+
+ // rp
+ new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.host}).runTest("passing credentials.create() with rpId (host and port)");
+ new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.hostname}).runTest("passing credentials.create() with rpId (hostname)");
+ new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).runTest("passing credentials.create() without rp.icon");
+
+ // user
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(1)).runTest("very short user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(64)).runTest("max length user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Uint8Array(64)).runTest("Uint8Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int8Array(64)).runTest("Int8Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(32)).runTest("Int16Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(16)).runTest("Int32Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(16)).runTest("Float32Array user id");
+ var dvBuf1 = new ArrayBuffer(16);
+ new CreateCredentialsTest("options.publicKey.user.id", new DataView(dvBuf1)).runTest("DataView user id");
+ new CreateCredentialsTest({path: "options.publicKey.user.icon", value: undefined}).runTest("passing credentials.create() without user.icon");
+
+ // good challenge values
+ // all these challenges are zero-filled buffers... think anyone will complain?
+ new CreateCredentialsTest("options.publicKey.challenge", new Int16Array(33)).runTest("Int16Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Int32Array(17)).runTest("Int32Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Float32Array(17)).runTest("Float32Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Float64Array(9)).runTest("Float64Array challenge");
+ var dvBuf2 = new ArrayBuffer(65);
+ new CreateCredentialsTest("options.publicKey.challenge", new DataView(dvBuf2)).runTest("DataView challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(8192)).runTest("Absurdly large challenge");
+
+ // good pubKeyCredParams values
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", []).runTest("Bad pubKeyCredParams: pubKeyCredParams is empty Array");
+ const pkParamEC256 = {
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA256
+ };
+ const pkParamEC512 = {
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA512
+ };
+ // XXX: presumes all mock authenticators support EC256
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256]).runTest("EC256 pubKeyCredParams");
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+ .runTest("SelectEC256 pubKeyCredParams from a list");
+ // TODO: currently most browsers are mocking FIDO U2F, which is EC256 only
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512]).runTest("EC512 pubKeyCredParams");
+
+ // NOTE: excludeCredentials parameter -- see also: createcredential-excludecredentials.https.html
+
+ // timeout
+ new CreateCredentialsTest({path: "options.publicKey.timeout", value: undefined}).runTest("passing credentials.create() with no timeout");
+
+ // valid authenticatorSelection values
+ var defaultAuthnrSel = {
+ authenticatorAttachment: "cross-platform",
+ requireResidentKey: false,
+ userVerification: "preferred"
+ };
+ // attachment
+ var authnrSelAttachUndef = cloneObject(defaultAuthnrSel);
+ authnrSelAttachUndef.authenticatorAttachment = undefined;
+ // resident key
+ var authnrSelRkUndef = cloneObject(defaultAuthnrSel);
+ authnrSelRkUndef.requireResidentKey = undefined;
+ var authnrSelRkFalse = cloneObject(defaultAuthnrSel);
+ authnrSelRkFalse.requireResidentKey = false;
+ // user verification
+ var authnrSelUvUndef = cloneObject(defaultAuthnrSel);
+ authnrSelUvUndef.userVerification = undefined;
+ var authnrSelUvDiscouraged = cloneObject(defaultAuthnrSel);
+ authnrSelUvDiscouraged.userVerification = "discouraged";
+ new CreateCredentialsTest({path: "options.publicKey.authenticatorSelection", value: undefined}).runTest("authenticatorSelection is undefined");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", {}).runTest("authenticatorSelection is empty object");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", cloneObject(defaultAuthnrSel)).runTest("authenticatorSelection default values");
+
+ // authnr selection attachment
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachUndef).runTest("authenticatorSelection attachment undefined");
+
+ // authnr selection resident key
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkUndef).runTest("authenticatorSelection residentKey undefined");
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkFalse).runTest("authenticatorSelection residentKey false");
+
+ // authnr selection user verification
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvUndef).runTest("authenticatorSelection userVerification undefined");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvDiscouraged).runTest("authenticatorSelection userVerification discouraged");
+
+
+ // good attestation values
+ new CreateCredentialsTest("options.publicKey.attestation", "none").runTest("attestation parameter: attestation is \"none\"");
+ new CreateCredentialsTest("options.publicKey.attestation", "indirect").runTest("attestation parameter: attestation is \"indirect\"");
+ new CreateCredentialsTest("options.publicKey.attestation", "direct").runTest("attestation parameter: attestation is \"direct\"");
+ new CreateCredentialsTest({path: "options.publicKey.attestation", value: undefined}).runTest("attestation parameter: attestation is undefined");
+ // TODO: test this with multiple mock authenticators to make sure that the right options are chosen when available?
+
+ // good extension values
+ new CreateCredentialsTest({path: "options.publicKey.extensions", value: undefined}).runTest("extensions undefined");
+ new CreateCredentialsTest("options.publicKey.extensions", {}).runTest("extensions are empty object");
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""}).runTest("extensions are dict of empty strings");
});
/* JSHINT */
-/* globals standardSetup, CreateCredentialsTest */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA256, cose_alg_ECDSA_w_SHA512, cloneObject */
</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-pubkeycredparams.https.html b/webauthn/createcredential-pubkeycredparams.https.html
new file mode 100644
index 0000000..325191c
--- /dev/null
+++ b/webauthn/createcredential-pubkeycredparams.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() pubKeyCredParams Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var badType = {
+ type: "something-else",
+ alg: cose_alg_ECDSA_w_SHA512
+ };
+ var badTypeEmptyString = cloneObject(badType);
+ badTypeEmptyString.type = "";
+ var badTypeNull = cloneObject(badType);
+ badTypeNull.type = null;
+ var badTypeEmptyObj = cloneObject(badType);
+ badTypeEmptyObj.type = {};
+
+ var badAlg = {
+ type: "public-key",
+ alg: 42
+ };
+ var badAlgZero = cloneObject(badAlg);
+ badAlgZero.alg = 0;
+
+ // bad pubKeyCredParams values
+ new CreateCredentialsTest({path: "options.publicKey.pubKeyCredParams", value: undefined}).runTest("Bad pubKeyCredParams: pubKeyCredParams is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", "hi mom").runTest("Bad pubKeyCredParams: pubKeyCredParams is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", null).runTest("Bad pubKeyCredParams: pubKeyCredParams is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badType]).runTest("Bad pubKeyCredParams: first param has bad type (\"something-else\")", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyString]).runTest("Bad pubKeyCredParams: first param has bad type (\"\")", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeNull]).runTest("Bad pubKeyCredParams: first param has bad type (null)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyObj]).runTest("Bad pubKeyCredParams: first param has bad type (empty object)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlg]).runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotSupportedError");
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlgZero]).runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotSupportedError");
+
+ // TODO: come back to this when mock authenticators support multiple cryptos so that we can test the preference ranking
+ // function verifyEC256(res) {
+ // debug ("verifyEC256 got", res);
+ // debug ("client data JSON", ab2str(res.response.clientDataJSON));
+ // parseAuthenticatorData(res.response.attestationObject);
+ // }
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256, pkParamEC512])
+ // .afterTest(verifyEC256)
+ // .runTest("EC256, EC512 pubKeyCredParams");
+ // function verifyEC512(res) {
+ // debug ("verifyEC512 got", res);
+ // debug ("client data JSON", ab2str(res.response.clientDataJSON));
+ // // parseAuthenticatorData(res.response.attestationObject);
+ // printHex ("clientDataJSON", res.response.clientDataJSON);
+ // printHex ("attestationObject", res.response.attestationObject);
+ // }
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+ // .afterTest(verifyEC512)
+ // .runTest("EC512, EC256 pubKeyCredParams");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA512, cloneObject */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-timeout.https.html b/webauthn/createcredential-timeout.https.html
new file mode 100644
index 0000000..b94ae58
--- /dev/null
+++ b/webauthn/createcredential-timeout.https.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad timeout values
+ // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+ // new CreateCredentialsTest({path: "options.publicKey.timeout", value: -1}).runTest("Bad timeout: negative", new TypeError());
+ // new CreateCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1}).runTest("Bad timeout: too big", new TypeError());
+
+ // timeout test
+ // XXX: this probably always passes with most mock authenticators unless
+ // some setup happens right here to make sure they don't return a credential
+ // right away. So... uhh... I guess test this with a real authenticator if you
+ // want to see if it really works.
+ promise_test(() => {
+ return new Promise((resolve, reject) => {
+ var args = {
+ options: {
+ publicKey: {
+ timeout: 1
+ }
+ }
+ };
+
+ setTimeout(() => {
+ reject(new Error ("timed out"));
+ }, 1000);
+
+ createCredential(args).then((res) => {
+ resolve(res);
+ });
+ });
+ }, "ensure create credential times out");
+ // TODO: createCredential.timeout > 1s && setTimeout < 1s
+ // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-badargs-rpid.https.html b/webauthn/getcredential-badargs-rpid.https.html
new file mode 100644
index 0000000..9e8da4d
--- /dev/null
+++ b/webauthn/getcredential-badargs-rpid.https.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn credential.get() rpId Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ new GetCredentialsTest("options.publicKey.rpId", "")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: empty string", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", null)
+ .addCredential(credPromise)
+ .runTest("Bad rpId: null", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "invalid domain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (has space)", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "-invaliddomain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (starts with dash)", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "0invaliddomain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (starts with number)", "SecurityError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-badargs-userverification.https.html b/webauthn/getcredential-badargs-userverification.https.html
new file mode 100644
index 0000000..6101540
--- /dev/null
+++ b/webauthn/getcredential-badargs-userverification.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() user verification Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ // authenticatorSelection bad userVerification values
+ new GetCredentialsTest("options.publicKey.userVerification", "")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: empty string", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", {})
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: empty object", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", "requiredshirtshoestshirt")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: bad value", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", null)
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: null", new TypeError());
+ // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+ new GetCredentialsTest("options.publicKey.userVerification", "required")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: \"required\"", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-extensions.https.html b/webauthn/getcredential-extensions.https.html
new file mode 100644
index 0000000..bad5ce4
--- /dev/null
+++ b/webauthn/getcredential-extensions.https.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var dummyExtension = {
+ foo: true,
+ bar: "yup"
+ };
+ var credPromise = createCredential();
+
+ // bad extension values
+ new GetCredentialsTest("options.publicKey.extensions", "hi mom")
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is string", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", null)
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is null", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", [])
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is empty Array", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0))
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+ var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+ new GetCredentialsTest("options.publicKey.extensions", {foo: badJson})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: malformatted JSON", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", {foo: dummyExtension})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: JavaScript object", new TypeError());
+ var badExtId = {};
+ badExtId[createRandomString(65)] = dummyExtension;
+ new GetCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extension ID too long", new TypeError());
+
+ // phony extensions
+ // TODO: not sure if this should pass or fail
+ // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+ var randomExtId = {};
+ randomExtId[createRandomString(64)] = dummyExtension;
+ new GetCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)})
+ .addCredential(credPromise)
+ .runTest("extensions is a nonsensical JSON string");
+
+ // TODO
+ // defined extensions:
+ // * appid
+ // * txAuthSimple
+ // * txAuthGeneric
+ // * authnSel
+ // * exts
+ // * uvi
+ // * loc
+ // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createRandomString, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-passing.https.html b/webauthn/getcredential-passing.https.html
index c7cf794..58b085f 100644
--- a/webauthn/getcredential-passing.https.html
+++ b/webauthn/getcredential-passing.https.html
@@ -11,11 +11,56 @@
standardSetup(function() {
"use strict";
- // GetCredentialsTest passing tests
- // new GetCredentialsTest().addCredential();
- new GetCredentialsTest().addCredential().test();
+ var credPromise = createCredential();
+
+ // GetCredentialsTest with default args
+ new GetCredentialsTest()
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with default args");
+
+ // timeout
+ new GetCredentialsTest({path: "options.publicKey.timeout", value: undefined})
+ .addCredential(credPromise)
+ .runTest("passing credentials.create() with no timeout");
+
+ // rpId
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: undefined})
+ .addCredential(credPromise)
+ .runTest("rpId undefined");
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.host})
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with rpId (host and port)");
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.hostname})
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with rpId (hostname)");
+
+ // allowCredentials
+ new GetCredentialsTest({path: "options.publicKey.allowCredentials", value: undefined})
+ .runTest("no credential specified");
+
+ // authnr selection user verification
+ new GetCredentialsTest({path: "options.publicKey.userVerification", value: undefined})
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification undefined");
+ new GetCredentialsTest("options.publicKey.userVerification", "preferred")
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification preferred");
+ new GetCredentialsTest("options.publicKey.userVerification", "discouraged")
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification discouraged");
+
+ // good extension values
+ new GetCredentialsTest({path: "options.publicKey.extensions", value: undefined})
+ .addCredential(credPromise)
+ .runTest("extensions undefined");
+ new GetCredentialsTest("options.publicKey.extensions", {})
+ .addCredential(credPromise)
+ .runTest("extensions are empty object");
+ new GetCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""})
+ .addCredential(credPromise)
+ .runTest("extensions are dict of empty strings");
});
/* JSHINT */
-/* globals standardSetup, GetCredentialsTest */
+/* globals standardSetup, GetCredentialsTest, createCredential */
</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-timeout.https.html b/webauthn/getcredential-timeout.https.html
new file mode 100644
index 0000000..8f5c2f3
--- /dev/null
+++ b/webauthn/getcredential-timeout.https.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ // bad timeout values
+ // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+ // new GetCredentialsTest({path: "options.publicKey.timeout", value: -1})
+ // .addCredential(credPromise)
+ // .runTest("Bad timeout: negative", new TypeError());
+ // new GetCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1})
+ // .addCredential(credPromise)
+ // .runTest("Bad timeout: too big", new TypeError());
+
+ // timeout test
+ // XXX: this probably always passes with most mock authenticators unless
+ // some setup happens right here to make sure they don't return a credential
+ // right away. So... uhh... I guess test this with a real authenticator if you
+ // want to see if it really works.
+ var timer;
+ function startTimer() {
+ timer = setTimeout(() => {
+ throw new Error("Timer went off before timeout");
+ }, 1000);
+ }
+ function stopTimer() {
+ clearTimeout(timer);
+ }
+ new GetCredentialsTest({path: "options.publicKey.timeout", value: 1})
+ .addCredential(credPromise)
+ .beforeTest(startTimer)
+ .afterTest(stopTimer)
+ .runTest("ensure create credential times out");
+ // TODO: createCredential.timeout > 1s && setTimeout < 1s
+ // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/helpers.js b/webauthn/helpers.js
index 11d0aee..568d3e2 100644
--- a/webauthn/helpers.js
+++ b/webauthn/helpers.js
@@ -1,5 +1,4 @@
-
-/* Useful constants for working with COSE key objects */
+// Useful constants for working with COSE key objects
const cose_kty = 1;
const cose_kty_ec2 = 2;
const cose_alg = 3;
@@ -11,6 +10,117 @@
const cose_crv_y = -3;
/**
+ * These are the default arguments that will be passed to navigator.credentials.create()
+ * unless modified by a specific test case
+ */
+var createCredentialDefaultArgs = {
+ options: {
+ publicKey: {
+ // Relying Party:
+ rp: {
+ name: "Acme",
+ icon: "https://www.w3.org/StyleSheets/TR/2016/logos/W3C"
+ },
+
+ // User:
+ user: {
+ id: new Uint8Array(16), // Won't survive the copy, must be rebuilt
+ name: "john.p.smith@example.com",
+ displayName: "John P. Smith",
+ icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
+ },
+
+ pubKeyCredParams: [{
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA256,
+ }],
+
+ timeout: 60000, // 1 minute
+ excludeCredentials: [] // No excludeList
+ }
+ }
+};
+
+/**
+ * These are the default arguments that will be passed to navigator.credentials.get()
+ * unless modified by a specific test case
+ */
+var getCredentialDefaultArgs = {
+ options: {
+ publicKey: {
+ timeout: 60000
+ // allowCredentials: [newCredential]
+ }
+ }
+};
+
+function createCredential(opts) {
+ opts = opts || {};
+
+ // set the default options
+ var createArgs = cloneObject(createCredentialDefaultArgs);
+ let challengeBytes = new Uint8Array(16);
+ window.crypto.getRandomValues(challengeBytes);
+ createArgs.options.publicKey.challenge = challengeBytes;
+ createArgs.options.publicKey.user.id = new Uint8Array(16);
+
+ // change the defaults with any options that were passed in
+ extendObject (createArgs, opts);
+
+ // create the credential, return the Promise
+ return navigator.credentials.create(createArgs.options);
+}
+
+function createRandomString(len) {
+ var text = "";
+ var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ for(var i = 0; i < len; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+}
+
+
+function ab2str(buf) {
+ return String.fromCharCode.apply(null, new Uint8Array(buf));
+}
+
+// Useful constants for working with attestation data
+const authenticator_data_user_present = 0x01;
+const authenticator_data_user_verified = 0x04;
+const authenticator_data_attested_cred_data = 0x40;
+const authenticator_data_extension_data = 0x80;
+
+function parseAuthenticatorData(buf) {
+ if (buf.byteLength < 37) {
+ throw new TypeError ("parseAuthenticatorData: buffer must be at least 37 bytes");
+ }
+
+ printHex ("authnrData", buf);
+
+ var authnrData = new DataView(buf);
+ var authnrDataObj = {};
+ authnrDataObj.length = buf.byteLength;
+
+ authnrDataObj.rpIdHash = new Uint8Array (buf.slice (0,32));
+ authnrDataObj.rawFlags = authnrData.getUint8(32);
+ authnrDataObj.counter = authnrData.getUint32(33, false);
+ authnrDataObj.rawCounter = [];
+ authnrDataObj.rawCounter[0] = authnrData.getUint8(33);
+ authnrDataObj.rawCounter[1] = authnrData.getUint8(34);
+ authnrDataObj.rawCounter[2] = authnrData.getUint8(35);
+ authnrDataObj.rawCounter[3] = authnrData.getUint8(36);
+ authnrDataObj.flags = {};
+
+ authnrDataObj.flags.userPresent = (authnrDataObj.rawFlags&authenticator_data_user_present)?true:false;
+ authnrDataObj.flags.userVerified = (authnrDataObj.rawFlags&authenticator_data_user_verified)?true:false;
+ authnrDataObj.flags.attestedCredentialData = (authnrDataObj.rawFlags&authenticator_data_attested_cred_data)?true:false;
+ authnrDataObj.flags.extensionData = (authnrDataObj.rawFlags&authenticator_data_extension_data)?true:false;
+
+ return authnrDataObj;
+}
+
+/**
* TestCase
*
* A generic template for test cases
@@ -118,66 +228,127 @@
/**
* run the test function with the top-level properties of the test object applied as arguments
+ * expects the test to pass, and then validates the results
*/
- test(desc) {
- promise_test(() => {
- return this.doIt()
- .then((ret) => {
- // check the result
- this.validateRet(ret);
- return ret;
- });
- }, desc);
+ testPasses(desc) {
+ return this.doIt()
+ .then((ret) => {
+ // check the result
+ this.validateRet(ret);
+ return ret;
+ });
+ }
+
+ /**
+ * run the test function with the top-level properties of the test object applied as arguments
+ * expects the test to fail
+ */
+ testFails(t, testDesc, expectedErr) {
+ return promise_rejects(t, expectedErr, this.doIt(), "Expected bad parameters to fail");
+ }
+
+ /**
+ * Runs the test that's implemented by the class by calling the doIt() function
+ * @param {String} desc A description of the test being run
+ * @param [Error|String] expectedErr A string matching an error type, such as "SecurityError" or an object with a .name value that is an error type string
+ */
+ runTest(desc, expectedErr) {
+ promise_test((t) => {
+ return Promise.resolve().then(() => {
+ return this.testSetup();
+ }).then(() => {
+ if (expectedErr === undefined) {
+ return this.testPasses(desc);
+ } else {
+ return this.testFails(t, desc, expectedErr);
+ }
+ }).then((res) => {
+ return this.testTeardown(res);
+ })
+ }, desc)
+ }
+
+ /**
+ * called before runTest
+ * virtual method expected to be overridden by child class if needed
+ */
+ testSetup() {
+ if (this.beforeTestFn) {
+ this.beforeTestFn.call(this);
+ }
+
+ return Promise.resolve();
+ }
+
+ /**
+ * Adds a callback function that gets called in the TestCase context
+ * and within the testing process.
+ */
+ beforeTest(fn) {
+ if (typeof fn !== "function") {
+ throw new Error ("Tried to call non-function before test");
+ }
+
+ this.beforeTestFn = fn;
+
+ return this;
+ }
+
+ /**
+ * called after runTest
+ * virtual method expected to be overridden by child class if needed
+ */
+ testTeardown(res) {
+ if (this.afterTestFn) {
+ this.afterTestFn.call(this, res);
+ }
+
+ return Promise.resolve();
+ }
+
+ /**
+ * Adds a callback function that gets called in the TestCase context
+ * and within the testing process. Good for validating results.
+ */
+ afterTest(fn) {
+ if (typeof fn !== "function") {
+ throw new Error ("Tried to call non-function after test");
+ }
+
+ this.afterTestFn = fn;
+
+ return this;
}
/**
* validates the value returned from the test function
+ * virtual method expected to be overridden by child class
*/
validateRet() {
throw new Error("Not implemented");
}
-
- /**
- * calls doIt() with testObject() and expects it to fail with a TypeError()
- */
- testBadArgs(testDesc) {
- promise_test(function(t) {
- return promise_rejects(t, new TypeError(), this.doIt(), "Expected bad parameters to fail");
- }.bind(this), testDesc);
- }
}
-var createCredentialDefaultArgs = {
- options: {
- publicKey: {
- // Relying Party:
- rp: {
- name: "Acme"
- },
-
- // User:
- user: {
- id: new Uint8Array(), // Won't survive the copy, must be rebuilt
- name: "john.p.smith@example.com",
- displayName: "John P. Smith",
- icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
- },
-
- pubKeyCredParams: [{
- type: "public-key",
- alg: cose_alg_ECDSA_w_SHA256,
- }],
-
- timeout: 60000, // 1 minute
- excludeCredentials: [] // No excludeList
- }
- }
-};
-
function cloneObject(o) {
return JSON.parse(JSON.stringify(o));
}
+function extendObject(dst, src) {
+ Object.keys(src).forEach(function(key) {
+ if (isSimpleObject(src[key])) {
+ extendObject (dst[key], src[key]);
+ } else {
+ dst[key] = src[key];
+ }
+ });
+}
+
+function isSimpleObject(o) {
+ return (typeof o === "object" &&
+ !Array.isArray(o) &&
+ !(o instanceof ArrayBuffer));
+}
+
/**
* CreateCredentialTest
*
@@ -198,7 +369,7 @@
window.crypto.getRandomValues(challengeBytes);
this.testObject = cloneObject(createCredentialDefaultArgs);
// cloneObject can't clone the BufferSource in user.id, so let's recreate it.
- this.testObject.options.publicKey.user.id = new Uint8Array();
+ this.testObject.options.publicKey.user.id = new Uint8Array(16);
this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
@@ -235,15 +406,8 @@
// default arguments
let challengeBytes = new Uint8Array(16);
window.crypto.getRandomValues(challengeBytes);
- this.testObject = {
- options: {
- publicKey: {
- challenge: challengeBytes,
- // timeout: 60000,
- // allowCredentials: [newCredential]
- }
- }
- };
+ this.testObject = cloneObject(getCredentialDefaultArgs);
+ this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
this.argOrder = [
@@ -266,33 +430,28 @@
// if a Promise was passed in, add it to the list
if (arg instanceof Promise) {
this.credentialPromiseList.push(arg);
- return;
+ return this;
}
// if a credential object was passed in, convert it to a Promise for consistency
if (typeof arg === "object") {
this.credentialPromiseList.push(Promise.resolve(arg));
- return;
+ return this;
}
- // if a credential wasn't passed in, create one
- let challengeBytes = new Uint8Array(16);
- window.crypto.getRandomValues(challengeBytes);
- var createArgs = cloneObject(createCredentialDefaultArgs);
- createArgs.options.publicKey.challenge = challengeBytes;
- createArgs.options.publicKey.user.id = new Uint8Array();
- var p = navigator.credentials.create(createArgs.options);
+ // if no credential specified then create one
+ var p = createCredential();
this.credentialPromiseList.push(p);
return this;
}
- test() {
+ testSetup(desc) {
if (!this.credentialPromiseList.length) {
throw new Error("Attempting list without defining credential to test");
}
- Promise.all(this.credentialPromiseList)
+ return Promise.all(this.credentialPromiseList)
.then((credList) => {
var idList = credList.map((cred) => {
return {
@@ -302,12 +461,15 @@
};
});
this.testObject.options.publicKey.allowCredentials = idList;
- return super.test();
+ // return super.test(desc);
+ })
+ .catch((err) => {
+ throw Error(err);
});
}
validateRet(ret) {
- validatePublicKeyCredential (ret);
+ validatePublicKeyCredential(ret);
validateAuthenticatorAssertionResponse(ret.response);
}
}
@@ -335,12 +497,16 @@
function validateAuthenticatorAttestationResponse(attr) {
// class
assert_class_string(attr, "AuthenticatorAttestationResponse", "Expected credentials.create() to return instance of 'AuthenticatorAttestationResponse' class");
+
// clientDataJSON
assert_idl_attribute(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with clientDataJSON attribute");
assert_readonly(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with readonly clientDataJSON attribute");
+ // TODO: clientDataJSON() and make sure fields are correct
+
// attestationObject
assert_idl_attribute(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with attestationObject attribute");
assert_readonly(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with readonly attestationObject attribute");
+ // TODO: parseAuthenticatorData() and make sure flags are correct
}
/**
@@ -349,15 +515,20 @@
function validateAuthenticatorAssertionResponse(assert) {
// class
assert_class_string(assert, "AuthenticatorAssertionResponse", "Expected credentials.create() to return instance of 'AuthenticatorAssertionResponse' class");
+
// clientDataJSON
assert_idl_attribute(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with clientDataJSON attribute");
assert_readonly(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with readonly clientDataJSON attribute");
+ // TODO: clientDataJSON() and make sure fields are correct
+
// signature
assert_idl_attribute(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with signature attribute");
assert_readonly(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with readonly signature attribute");
+
// authenticatorData
assert_idl_attribute(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with authenticatorData attribute");
assert_readonly(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with readonly authenticatorData attribute");
+ // TODO: parseAuthenticatorData() and make sure flags are correct
}
//************* BEGIN DELETE AFTER 1/1/2018 *************** //
@@ -370,8 +541,8 @@
// note that the polyfill only gets loaded if navigator.credentials create doesn't exist
// AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
function ensureInterface() {
- if (typeof navigator.credentials.create !== "function") {
- debug = console.log;
+ if (typeof navigator.credentials === "object" && typeof navigator.credentials.create !== "function") {
+ // debug = onsole.log;
return loadJavaScript("/webauthn/webauthn-polyfill/webauthn-polyfill.js")
.then(() => {
diff --git a/webauthn/securecontext.http.html b/webauthn/securecontext.http.html
index 82464bd..5278695 100644
--- a/webauthn/securecontext.http.html
+++ b/webauthn/securecontext.http.html
@@ -17,7 +17,7 @@
// Example 1
// http://example.com/ opened in a top-level browsing context is not a secure context, as it was not delivered over an authenticated and encrypted channel.
test (() => {
- assert_false (typeof navigator.credentials.create === "function");
+ assert_false (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "no navigator.credentials.create in non-secure context");
// Example 4: TODO
diff --git a/webauthn/securecontext.https.html b/webauthn/securecontext.https.html
index 9810a7f..6c9aabd 100644
--- a/webauthn/securecontext.https.html
+++ b/webauthn/securecontext.https.html
@@ -17,7 +17,7 @@
// Example 2
// https://example.com/ opened in a top-level browsing context is a secure context, as it was delivered over an authenticated and encrypted channel.
test (() => {
- assert_true (typeof navigator.credentials.create === "function");
+ assert_true (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "navigator.credentials.create exists in secure context");
// Example 3: TODO
diff --git a/webdriver/tests/actions/mouse.py b/webdriver/tests/actions/mouse.py
index bb7e145..f852653 100644
--- a/webdriver/tests/actions/mouse.py
+++ b/webdriver/tests/actions/mouse.py
@@ -1,6 +1,6 @@
import pytest
-from tests.actions.support.mouse import get_center
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
from tests.actions.support.refine import get_events, filter_dict
from tests.support.asserts import assert_move_to_coordinates
from tests.support.inline import inline
@@ -12,11 +12,6 @@
return inline(content)
-# TODO use pytest.approx once we upgrade to pytest > 3.0
-def approx(n, m, tolerance=1):
- return abs(n - m) <= tolerance
-
-
def test_click_at_coordinates(session, test_actions_page, mouse_chain):
div_point = {
"x": 82,
@@ -35,7 +30,7 @@
assert e["button"] == 0
expected = [
{"type": "mousedown", "buttons": 1},
- {"type": "mouseup", "buttons": 0},
+ {"type": "mouseup", "buttons": 0},
{"type": "click", "buttons": 0},
]
filtered_events = [filter_dict(e, expected[0]) for e in events]
@@ -55,7 +50,7 @@
events = get_events(session)
expected = [
{"type": "mousedown", "button": 2},
- {"type": "contextmenu", "button": 2},
+ {"type": "contextmenu", "button": 2},
]
assert len(events) == 4
filtered_events = [filter_dict(e, expected[0]) for e in events]
@@ -68,7 +63,7 @@
def test_click_element_center(session, test_actions_page, mouse_chain):
outer = session.find.css("#outer", all=False)
- center = get_center(outer.rect)
+ center = get_inview_center(outer.rect, get_viewport_rect(session))
mouse_chain.click(element=outer).perform()
events = get_events(session)
assert len(events) == 4
@@ -76,8 +71,8 @@
assert ["mousemove", "mousedown", "mouseup", "click"] == event_types
for e in events:
if e["type"] != "mousemove":
- assert approx(e["pageX"], center["x"])
- assert approx(e["pageY"], center["y"])
+ assert pytest.approx(e["pageX"], center["x"])
+ assert pytest.approx(e["pageY"], center["y"])
assert e["target"] == "outer"
@@ -102,8 +97,9 @@
@pytest.mark.parametrize("drag_duration", [0, 300, 800])
-@pytest.mark.parametrize("dx, dy",
- [(20, 0), (0, 15), (10, 15), (-20, 0), (10, -15), (-10, -15)])
+@pytest.mark.parametrize("dx, dy", [
+ (20, 0), (0, 15), (10, 15), (-20, 0), (10, -15), (-10, -15)
+])
def test_drag_and_drop(session,
test_actions_page,
mouse_chain,
@@ -112,7 +108,7 @@
drag_duration):
drag_target = session.find.css("#dragTarget", all=False)
initial_rect = drag_target.rect
- initial_center = get_center(initial_rect)
+ initial_center = get_inview_center(initial_rect, get_viewport_rect(session))
# Conclude chain with extra move to allow time for last queued
# coordinate-update of drag_target and to test that drag_target is "dropped".
mouse_chain \
@@ -125,8 +121,8 @@
# mouseup that ends the drag is at the expected destination
e = get_events(session)[1]
assert e["type"] == "mouseup"
- assert approx(e["pageX"], initial_center["x"] + dx)
- assert approx(e["pageY"], initial_center["y"] + dy)
+ assert pytest.approx(e["pageX"], initial_center["x"] + dx)
+ assert pytest.approx(e["pageY"], initial_center["y"] + dy)
# check resulting location of the dragged element
final_rect = drag_target.rect
assert initial_rect["x"] + dx == final_rect["x"]
diff --git a/webdriver/tests/actions/mouse_dblclick.py b/webdriver/tests/actions/mouse_dblclick.py
index e9e4c26..bdd3905 100644
--- a/webdriver/tests/actions/mouse_dblclick.py
+++ b/webdriver/tests/actions/mouse_dblclick.py
@@ -1,6 +1,6 @@
import pytest
-from tests.actions.support.mouse import get_center
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
from tests.actions.support.refine import get_events, filter_dict
from tests.support.asserts import assert_move_to_coordinates
@@ -63,7 +63,7 @@
def test_dblclick_with_pause_after_second_pointerdown(dblclick_session, mouse_chain):
outer = dblclick_session.find.css("#outer", all=False)
- center = get_center(outer.rect)
+ center = get_inview_center(outer.rect, get_viewport_rect(dblclick_session))
mouse_chain \
.pointer_move(int(center["x"]), int(center["y"])) \
.click() \
@@ -88,7 +88,7 @@
def test_no_dblclick(dblclick_session, mouse_chain):
outer = dblclick_session.find.css("#outer", all=False)
- center = get_center(outer.rect)
+ center = get_inview_center(outer.rect, get_viewport_rect(dblclick_session))
mouse_chain \
.pointer_move(int(center["x"]), int(center["y"])) \
.click() \
diff --git a/webdriver/tests/actions/pointer_origin.py b/webdriver/tests/actions/pointer_origin.py
new file mode 100644
index 0000000..cad59f0
--- /dev/null
+++ b/webdriver/tests/actions/pointer_origin.py
@@ -0,0 +1,129 @@
+import pytest
+
+from webdriver import MoveTargetOutOfBoundsException
+
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
+from tests.support.inline import inline
+
+
+def origin_doc(inner_style, outer_style=""):
+ return inline("""
+ <div id="outer" style="{1}"
+ onmousemove="window.coords = {{x: event.clientX, y: event.clientY}}">
+ <div id="inner" style="{0}"></div>
+ </div>
+ """.format(inner_style, outer_style))
+
+
+def get_click_coordinates(session):
+ return session.execute_script("return window.coords;")
+
+
+def test_viewport_inside(session, mouse_chain):
+ point = {"x": 50, "y": 50}
+
+ session.url = origin_doc("width: 100px; height: 50px; background: green;")
+ mouse_chain \
+ .pointer_move(point["x"], point["y"], origin="viewport") \
+ .perform()
+
+ click_coords = session.execute_script("return window.coords;")
+ assert pytest.approx(click_coords["x"], point["x"])
+ assert pytest.approx(click_coords["y"], point["y"])
+
+
+def test_viewport_outside(session, mouse_chain):
+ with pytest.raises(MoveTargetOutOfBoundsException):
+ mouse_chain \
+ .pointer_move(-50, -50, origin="viewport") \
+ .perform()
+
+
+def test_pointer_inside(session, mouse_chain):
+ start_point = {"x": 50, "y": 50}
+ offset = {"x": 10, "y": 5}
+
+ session.url = origin_doc("width: 100px; height: 50px; background: green;")
+ mouse_chain \
+ .pointer_move(start_point["x"], start_point["y"]) \
+ .pointer_move(offset["x"], offset["y"], origin="pointer") \
+ .perform()
+
+ click_coords = session.execute_script("return window.coords;")
+ assert pytest.approx(click_coords["x"], start_point["x"] + offset["x"])
+ assert pytest.approx(click_coords["y"], start_point["y"] + offset["y"])
+
+
+def test_pointer_outside(session, mouse_chain):
+ with pytest.raises(MoveTargetOutOfBoundsException):
+ mouse_chain \
+ .pointer_move(-50, -50, origin="pointer") \
+ .perform()
+
+
+def test_element_center_point(session, mouse_chain):
+ session.url = origin_doc("width: 100px; height: 50px; background: green;")
+ elem = session.find.css("#inner", all=False)
+ center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+ mouse_chain \
+ .pointer_move(0, 0, origin=elem) \
+ .perform()
+
+ click_coords = get_click_coordinates(session)
+ assert pytest.approx(click_coords["x"], center["x"])
+ assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_center_point_with_offset(session, mouse_chain):
+ session.url = origin_doc("width: 100px; height: 50px; background: green;")
+ elem = session.find.css("#inner", all=False)
+ center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+ mouse_chain \
+ .pointer_move(10, 15, origin=elem) \
+ .perform()
+
+ click_coords = get_click_coordinates(session)
+ assert pytest.approx(click_coords["x"], center["x"] + 10)
+ assert pytest.approx(click_coords["y"], center["y"] + 15)
+
+
+def test_element_in_view_center_point_partly_visible(session, mouse_chain):
+ session.url = origin_doc("""width: 100px; height: 50px; background: green;
+ position: relative; left: -50px; top: -25px;""")
+ elem = session.find.css("#inner", all=False)
+ center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+ mouse_chain \
+ .pointer_move(0, 0, origin=elem) \
+ .perform()
+
+ click_coords = get_click_coordinates(session)
+ assert pytest.approx(click_coords["x"], center["x"])
+ assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_larger_than_viewport(session, mouse_chain):
+ session.url = origin_doc("width: 300vw; height: 300vh; background: green;")
+ elem = session.find.css("#inner", all=False)
+ center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+ mouse_chain \
+ .pointer_move(0, 0, origin=elem) \
+ .perform()
+
+ click_coords = get_click_coordinates(session)
+ assert pytest.approx(click_coords["x"], center["x"])
+ assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_outside_of_view_port(session, mouse_chain):
+ session.url = origin_doc("""width: 100px; height: 50px; background: green;
+ position: relative; left: -200px; top: -100px;""")
+ elem = session.find.css("#inner", all=False)
+
+ with pytest.raises(MoveTargetOutOfBoundsException):
+ mouse_chain \
+ .pointer_move(0, 0, origin=elem) \
+ .perform()
diff --git a/webdriver/tests/actions/support/mouse.py b/webdriver/tests/actions/support/mouse.py
index d627ebb..b3672eb 100644
--- a/webdriver/tests/actions/support/mouse.py
+++ b/webdriver/tests/actions/support/mouse.py
@@ -1,5 +1,26 @@
-def get_center(rect):
+def get_viewport_rect(session):
+ return session.execute_script("""
+ return {
+ height: window.innerHeight || document.documentElement.clientHeight,
+ width: window.innerWidth || document.documentElement.clientWidth,
+ };
+ """)
+
+
+def get_inview_center(elem_rect, viewport_rect):
+ x = {
+ "left": max(0, min(elem_rect["x"], elem_rect["x"] + elem_rect["width"])),
+ "right": min(viewport_rect["width"], max(elem_rect["x"],
+ elem_rect["x"] + elem_rect["width"])),
+ }
+
+ y = {
+ "top": max(0, min(elem_rect["y"], elem_rect["y"] + elem_rect["height"])),
+ "bottom": min(viewport_rect["height"], max(elem_rect["y"],
+ elem_rect["y"] + elem_rect["height"])),
+ }
+
return {
- "x": rect["width"] / 2 + rect["x"],
- "y": rect["height"] / 2 + rect["y"],
+ "x": (x["left"] + x["right"]) / 2,
+ "y": (y["top"] + y["bottom"]) / 2,
}
diff --git a/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html b/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html
index 8a40f9a..06408d0 100644
--- a/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html
+++ b/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html
@@ -14,7 +14,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
return sender.replaceTrack(tracks[1])
.then(t.step_func(() => {
assert_equals(sender.track, tracks[1]);
@@ -30,7 +30,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
return sender.replaceTrack(null)
.then(t.step_func(() => {
assert_equals(sender.track, null);
@@ -46,7 +46,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
assert_equals(sender.track, tracks[0]);
sender.replaceTrack(tracks[1]);
// replaceTrack() is asynchronous, there should be no synchronously
@@ -64,7 +64,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
caller.close();
return sender.replaceTrack(tracks[1])
.then(t.step_func(() => {
@@ -86,7 +86,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
caller.removeTrack(sender);
// replaceTrack() should fail because the sender should be inactive after
// removeTrack().
@@ -110,7 +110,7 @@
const caller = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0]);
+ const sender = caller.addTrack(tracks[0], streams[0]);
let p = sender.replaceTrack(tracks[1])
caller.removeTrack(sender);
// replaceTrack() should fail because it executes steps in parallel and