summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-font-loading
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-font-loading')
-rw-r--r--testing/web-platform/tests/css/css-font-loading/META.yml4
-rw-r--r--testing/web-platform/tests/css/css-font-loading/empty-family-load.html18
-rw-r--r--testing/web-platform/tests/css/css-font-loading/font-face-reject.html18
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates.html56
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-load-in-modal-dialog.html30
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-override-descriptor-getter-setter.sub.html222
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors-ref.html27
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors.html29
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor.html30
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-add-css-connected.html28
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2.html17
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected.html23
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2-ref.html13
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2.html19
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected.html23
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-has.html37
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-connected.html27
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-wide-keywords.html48
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-load-var.html44
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-loading-worker-crash.html7
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-no-root-element.html12
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-update-after-stylesheet-change.html27
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfaceset-worker-fontface-crash.html32
-rw-r--r--testing/web-platform/tests/css/css-font-loading/fontfacesetloadevent-constructor.html20
-rw-r--r--testing/web-platform/tests/css/css-font-loading/idlharness.https.html29
-rw-r--r--testing/web-platform/tests/css/css-font-loading/nonexistent-file-url.html19
-rw-r--r--testing/web-platform/tests/css/css-font-loading/resources/GenI102.woff2bin0 -> 102536 bytes
-rw-r--r--testing/web-platform/tests/css/css-font-loading/resources/GenR102.woff2bin0 -> 106560 bytes
-rw-r--r--testing/web-platform/tests/css/css-font-loading/resources/Rochester.otfbin0 -> 27260 bytes
-rw-r--r--testing/web-platform/tests/css/css-font-loading/support/fontfaceset-loading-worker.js8
33 files changed, 924 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-font-loading/META.yml b/testing/web-platform/tests/css/css-font-loading/META.yml
new file mode 100644
index 0000000000..3ac9b655b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/META.yml
@@ -0,0 +1,4 @@
+spec: https://drafts.csswg.org/css-font-loading/
+suggested_reviewers:
+ - tabatkins
+ - svgeesus
diff --git a/testing/web-platform/tests/css/css-font-loading/empty-family-load.html b/testing/web-platform/tests/css/css-font-loading/empty-family-load.html
new file mode 100644
index 0000000000..a2aa374af7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/empty-family-load.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Dominik Röttsches" href="drott@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-load">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4510">
+<meta name="assert" content="Ensure that an empty font family name loads and resolves to array." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(function(t) {
+ var testFontFace = new FontFace('a', 'url(a)');
+ document.fonts.add(testFontFace);
+ return document.fonts.load("1px \"\"").then(function(result) {
+ assert_true(Array.isArray(result),
+ "Resolved promise's value must be an array.") });
+})
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/font-face-reject.html b/testing/web-platform/tests/css/css-font-loading/font-face-reject.html
new file mode 100644
index 0000000000..47456de443
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/font-face-reject.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Dominik Röttsches" href="drott@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-load">
+<meta name="assert" content="Ensure that a UA triggered font load (through the use in the test div) leads to rejecting
+ the promise." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(function(t) {
+ var testFontFace = new FontFace('TestFontFace', 'local("nonexistentfont-9a1a9f78-c8d4-11e9-af16-448a5b2c326f")');
+ document.fonts.add(testFontFace);
+ return promise_rejects_dom(t, 'NetworkError', testFontFace.loaded);
+})
+</script>
+<body>
+<div style="font-family: TestFontFace;">a</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates-ref.html b/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates-ref.html
new file mode 100644
index 0000000000..513867b350
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Font Loading reference: modification of descriptors</title>
+<style>
+@font-face { font-family: test; src: url(resources/GenR102.woff2); }
+@font-face { font-family: test; font-style:italic; src: url(resources/GenI102.woff2); }
+body { font-family: sans-serif; }
+.test { font-family: test, sans-serif; }
+</style>
+<body>
+<div>
+All lines below should use the same serif font, with the word "weight" in italics:
+<p class=test>Using original family name of a FontFace</p>
+<p class=test>Using updated family name of a FontFace</p>
+<p class=test>Using updated <i>weight</i> descriptors</p>
+<p class=test>Using updated unicode-range descriptors</p>
+</div>
+</body>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates.html b/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates.html
new file mode 100644
index 0000000000..038b96da1e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-descriptor-updates.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<meta charset=utf-8>
+<title>CSS Font Loading test: modification of descriptors</title>
+<link rel="author" title="Jonathan Kew" href="jkew@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
+<meta name="assert" content="If descriptors of a FontFace are modified, the new values should take effect">
+<link rel="match" href="fontface-descriptor-updates-ref.html">
+<style>
+body { font-family: sans-serif; }
+#test1 { font-family: test1, sans-serif; }
+#test2 { font-family: test2, monospace; }
+#test3 { font-family: test3, sans-serif; }
+#test4 { font-family: test4, monospace; }
+</style>
+<script>
+function run() {
+ let f1 = new FontFace("test1", "url(resources/GenR102.woff2)");
+ document.fonts.add(f1);
+ let f2 = new FontFace("to_be_updated", "url(resources/GenR102.woff2)");
+ document.fonts.add(f2);
+ let f3 = new FontFace("test3", "url(resources/GenR102.woff2)", { weight: 700 });
+ document.fonts.add(f3);
+ let f4 = new FontFace("test3", "url(resources/GenI102.woff2)");
+ document.fonts.add(f4);
+ let f5 = new FontFace("test4", "url(resources/GenR102.woff2)", { unicodeRange: "U+002?" });
+ document.fonts.add(f5);
+ let f6 = new FontFace("test4", "url(resources/GenI102.woff2)", { unicodeRange: "U+00??" });
+ document.fonts.add(f6);
+
+ // Change family name to make f2 match #test2
+ f2.family = "test2";
+
+ // Swap weight descriptors so that f3 is regular and f4 (italic face) is regarded as bold
+ f3.weight = 400;
+ f4.weight = 700;
+
+ // Update unicode-range so that f5 will be used for all characters in #test4
+ f5.unicodeRange = "U+00??";
+ f6.unicodeRange = "U+0000";
+
+ document.fonts.ready.then(function() {
+ document.documentElement.classList.remove("reftest-wait");
+ })
+}
+</script>
+<body onload="run()">
+<div>
+All lines below should use the same serif font, with the word "weight" in italics:
+<p id=test1>Using original family name of a FontFace</p>
+<p id=test2>Using updated family name of a FontFace</p>
+<p id=test3>Using updated <b>weight</b> descriptors</p>
+<p id=test4>Using updated unicode-range descriptors</p>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-load-in-modal-dialog.html b/testing/web-platform/tests/css/css-font-loading/fontface-load-in-modal-dialog.html
new file mode 100644
index 0000000000..8838e05eaf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-load-in-modal-dialog.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<link rel="author" title="Xiaocheng Hu" href="xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-load">
+<link rel="help" href="https://crbug.com/1092411">
+<meta name="assert" content="Ensure that content of a modal dialog is re-rendered with loaded web font." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#target {
+ font: 25px/1 custom-font, monospace;
+}
+</style>
+<dialog><span id=target>0123456789</span></dialog>
+<script>
+document.querySelector('dialog').showModal();
+
+function raf() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+}
+
+promise_test(async () => {
+ await raf();
+
+ const face = new FontFace('custom-font', 'url(/fonts/Ahem.ttf)');
+ document.fonts.add(face);
+ await face.load();
+
+ assert_equals(target.offsetWidth, 250);
+}, 'Modal dialog content should be re-rendered with loaded web font');
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptor-getter-setter.sub.html b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptor-getter-setter.sub.html
new file mode 100644
index 0000000000..a3d8ccec36
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptor-getter-setter.sub.html
@@ -0,0 +1,222 @@
+<!DOCTYPE html>
+<title>Tests getters and setters of the font metrics override descriptors of FontFace</title>
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+function rejection(promise) {
+ return new Promise((resolve, reject) => promise.then(reject, resolve));
+}
+
+// ascentOverride
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-initial',
+ 'url(https://{{host}}/font.woff)');
+ assert_equals(face.ascentOverride, 'normal');
+}, "Initial value of ascentOverride should be 'normal'");
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-initialize-with-normal',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: 'normal'});
+ assert_equals(face.ascentOverride, 'normal');
+}, "Initialize ascentOverride with 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-initialize-with-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: '50%'});
+ assert_equals(face.ascentOverride, '50%');
+}, "Initialize ascentOverride with a percentage should succeed");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'ascent-override-initialize-with-negative-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: '-50%'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize ascentOverride with a negative percentage should fail");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'ascent-override-initialize-with-non-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: '10px'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize ascentOverride with a non-percentage should fail");
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-normal-to-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: 'normal'});
+ face.ascentOverride = '50%';
+ assert_equals(face.ascentOverride, '50%');
+}, "Changing ascentOverride from 'normal' to percentage should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-percentage-to-normal',
+ 'url(https://{{host}}/font.woff)',
+ {ascentOverride: '50%'});
+ face.ascentOverride = 'normal';
+ assert_equals(face.ascentOverride, 'normal');
+}, "Changing ascentOverride from percentage to 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'ascent-override-set-to-invalid',
+ 'url(https://{{host}}/font.woff)');
+ assert_throws_dom('SyntaxError', () => {face.ascentOverride = '10px'});
+}, "Changing ascentOverride to invalid value should fail");
+
+// descentOverride
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-initial',
+ 'url(https://{{host}}/font.woff)');
+ assert_equals(face.descentOverride, 'normal');
+}, "Initial value of descentOverride should be 'normal'");
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-initialize-with-normal',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: 'normal'});
+ assert_equals(face.descentOverride, 'normal');
+}, "Initialize descentOverride with 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-initialize-with-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: '50%'});
+ assert_equals(face.descentOverride, '50%');
+}, "Initialize descentOverride with a percentage should succeed");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'descent-override-initialize-with-negative-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: '-50%'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize descentOverride with a negative percentage should fail");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'descent-override-initialize-with-non-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: '10px'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize descentOverride with a non-percentage should fail");
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-normal-to-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: 'normal'});
+ face.descentOverride = '50%';
+ assert_equals(face.descentOverride, '50%');
+}, "Changing descentOverride from 'normal' to percentage should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-percentage-to-normal',
+ 'url(https://{{host}}/font.woff)',
+ {descentOverride: '50%'});
+ face.descentOverride = 'normal';
+ assert_equals(face.descentOverride, 'normal');
+}, "Changing descentOverride from percentage to 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'descent-override-set-to-invalid',
+ 'url(https://{{host}}/font.woff)');
+ assert_throws_dom('SyntaxError', () => {face.descentOverride = '10px'});
+}, "Changing descentOverride to invalid value should fail");
+
+// lineGapOverride
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-initial',
+ 'url(https://{{host}}/font.woff)');
+ assert_equals(face.lineGapOverride, 'normal');
+}, "Initial value of lineGapOverride should be 'normal'");
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-initialize-with-normal',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: 'normal'});
+ assert_equals(face.lineGapOverride, 'normal');
+}, "Initialize lineGapOverride with 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-initialize-with-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: '50%'});
+ assert_equals(face.lineGapOverride, '50%');
+}, "Initialize lineGapOverride with a percentage should succeed");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'lineGap-override-initialize-with-negative-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: '-50%'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize lineGapOverride with a negative percentage should fail");
+
+promise_test(async () => {
+ const face = new FontFace(
+ 'lineGap-override-initialize-with-non-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: '10px'});
+ const error = await rejection(face.load());
+ assert_equals('error', face.status);
+ assert_throws_dom('SyntaxError', () => {throw error});
+}, "Initialize lineGapOverride with a non-percentage should fail");
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-normal-to-percentage',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: 'normal'});
+ face.lineGapOverride = '50%';
+ assert_equals(face.lineGapOverride, '50%');
+}, "Changing lineGapOverride from 'normal' to percentage should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-percentage-to-normal',
+ 'url(https://{{host}}/font.woff)',
+ {lineGapOverride: '50%'});
+ face.lineGapOverride = 'normal';
+ assert_equals(face.lineGapOverride, 'normal');
+}, "Changing lineGapOverride from percentage to 'normal' should succeed");
+
+test(() => {
+ const face = new FontFace(
+ 'lineGap-override-set-to-invalid',
+ 'url(https://{{host}}/font.woff)');
+ assert_throws_dom('SyntaxError', () => {face.lineGapOverride = '10px'});
+}, "Changing lineGapOverride to invalid value should fail");
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors-ref.html b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors-ref.html
new file mode 100644
index 0000000000..a08e7e97e0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Tests that the ascentOverride, descentOverride and lineGapOverride attributes of FontFace work</title>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+#target {
+ position: absolute;
+ font-family: Ahem;
+ font-size: 20px;
+}
+
+#first-line {
+ position: absolute;
+ left: 0;
+ top: 0.7em;
+}
+
+#second-line {
+ position: absolute;
+ left: 0;
+ top: 3.7em;
+}
+</style>
+
+<div id="target">
+ <div id="first-line">XXXXX</div>
+ <div id="second-line">XXXXX</div>
+</div>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors.html b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors.html
new file mode 100644
index 0000000000..34506b1547
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-override-descriptors.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Tests that the ascentOverride, descentOverride and lineGapOverride attributes of FontFace work</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc">
+<link rel="match" href="fontface-override-descriptors-ref.html">
+<script>
+const face = new FontFace(
+ 'Ahem',
+ 'local("Ahem"), url("/fonts/Ahem.ttf")',
+ {ascentOverride: '100%', descentOverride: '100%', lineGapOverride: '100%'});
+document.fonts.add(face);
+
+// Line height is ascent + descent + lineGap = 3em
+// Baseline is placed at lineGap * 0.5 + ascent = 1.5em below line box top
+// Since each Ahem 'X' glyph has 0.8em above baseline, the top of each glyph
+// should be placed at 0.7em below line box top
+</script>
+<style>
+#target {
+ position: absolute;
+ font-family: Ahem;
+ font-size: 20px;
+}
+</style>
+
+<div id="target">
+ XXXXX<br>
+ XXXXX
+</div>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor-ref.html b/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor-ref.html
new file mode 100644
index 0000000000..e752f4110c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests that the sizeAdjust attribute of FontFace works</title>
+<script>
+/* Load Ahem similarly to the testcase so that Gecko gives it the
+ same antialiasing treatment. */
+const ahem = new FontFace(
+ 'Ahem-normal',
+ 'local("Ahem"), url("/fonts/Ahem.ttf")');
+document.fonts.add(ahem);
+</script>
+<style>
+#target {
+ font-family: "Ahem-normal";
+ font-size: 40px;
+ letter-spacing: 10px;
+}
+span {
+ font-size: 50%;
+}
+</style>
+
+<p>The first and fourth characters should be double-sized:</p>
+<div id="target">
+ F<span>oo</span>B<span>ar</span>
+</div>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor.html b/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor.html
new file mode 100644
index 0000000000..40e7a7f70a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontface-size-adjust-descriptor.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Tests that the sizeAdjust attribute of FontFace works</title>
+<meta charset="utf-8">
+<link rel="author" href="mailto:jkew@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontface-interface">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-size-adjust-desc">
+<link rel="match" href="fontface-size-adjust-descriptor-ref.html">
+<script>
+const ahem = new FontFace(
+ 'Ahem-normal',
+ 'local("Ahem"), url("/fonts/Ahem.ttf")');
+document.fonts.add(ahem);
+const large = new FontFace(
+ 'Ahem-large',
+ 'local("Ahem"), url("/fonts/Ahem.ttf")',
+ {sizeAdjust: "200%", unicodeRange: "U+20,U+41-5A"});
+document.fonts.add(large);
+</script>
+<style>
+#target {
+ font-family: "Ahem-large", "Ahem-normal";
+ font-size: 20px;
+ letter-spacing: 10px;
+}
+</style>
+
+<p>The first and fourth characters should be double-sized:</p>
+<div id="target">
+ FooBar
+</div>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-add-css-connected.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-add-css-connected.html
new file mode 100644
index 0000000000..874558ca85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-add-css-connected.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-add">
+<meta name="assert" content="Ensure that calling add() with a CSS-connected FontFace throws." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<script>
+test(function(t) {
+ let font = document.fonts.keys().next().value;
+ let fontFaceSet = new FontFaceSet([]);
+ assert_equals(fontFaceSet.size, 0);
+ assert_throws_dom("InvalidModificationError", function() { fontFaceSet.add(font); });
+ assert_equals(fontFaceSet.size, 0);
+ let newFont = new FontFace("MyFont", "url('resources/Rochester.otf')");
+ fontFaceSet.add(newFont);
+ assert_equals(fontFaceSet.size, 1);
+ fontFaceSet.add(newFont);
+ assert_equals(fontFaceSet.size, 1);
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2-ref.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2-ref.html
new file mode 100644
index 0000000000..4c13ebc11c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-clear">
+<meta name="assert" content="Ensure that calling clear() does not remove CSS-connected FontFaces." />
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<div style="font: 48px 'WebFont';">Hi</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2.html
new file mode 100644
index 0000000000..af285460ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-clear">
+<meta name="assert" content="Ensure that calling clear() does not remove CSS-connected FontFaces." />
+<link rel="match" href="fontfaceset-clear-css-connected-2-ref.html">
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<div style="font: 48px 'WebFont';">Hi</div>
+<script>
+document.fonts.clear();
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected.html
new file mode 100644
index 0000000000..66f786d953
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-clear-css-connected.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-clear">
+<meta name="assert" content="Ensure that calling clear() does not remove CSS-connected FontFaces." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<script>
+test(function(t) {
+ let fonts = document.fonts;
+ let font = fonts.keys().next().value;
+ assert_equals(fonts.size, 1);
+ fonts.clear();
+ assert_equals(fonts.size, 1);
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2-ref.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2-ref.html
new file mode 100644
index 0000000000..e183c44e89
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-delete">
+<meta name="assert" content="Ensure that calling delete() with a CSS-connected FontFace has no effect." />
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<div style="font: 48px 'WebFont';">Hi</div>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2.html
new file mode 100644
index 0000000000..250ebb2b3b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected-2.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-delete">
+<meta name="assert" content="Ensure that calling delete() with a CSS-connected FontFace has no effect." />
+<link rel="match" href="fontfaceset-delete-css-connected-2-ref.html">
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<div style="font: 48px 'WebFont';">Hi</div>
+<script>
+let fonts = document.fonts;
+let font = fonts.keys().next().value;
+fonts.delete(font);
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected.html
new file mode 100644
index 0000000000..becea05273
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-delete-css-connected.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-delete">
+<meta name="assert" content="Ensure that calling delete() on a CSS-connected FontFace has no effect." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+<script>
+test(function(t) {
+ let fonts = document.fonts;
+ let font = fonts.keys().next().value;
+ assert_equals(fonts.size, 1);
+ fonts.delete(font);
+ assert_equals(fonts.size, 1);
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-has.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-has.html
new file mode 100644
index 0000000000..acfeda840f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-has.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head id="head">
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#dom-fontfaceset-has">
+<meta name="assert" content="Ensure that calling FontFaceSet.has() works properly." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style">
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<script>
+test(function(t) {
+ let fonts = document.fonts;
+ let font = [...fonts.keys()][0];
+ let font2 = new FontFace("WebFont2", "url('resources/GenR102.woff2') format('woff2')");
+ assert_true(fonts.has(font));
+ assert_false(fonts.has(font2));
+ fonts.add(font2);
+ assert_true(fonts.has(font));
+ assert_true(fonts.has(font2));
+ document.getElementById("head").removeChild(document.getElementById("style"));
+ assert_false(fonts.has(font));
+ assert_true(fonts.has(font2));
+ fonts.delete(font2);
+ assert_false(fonts.has(font));
+ assert_false(fonts.has(font2));
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-connected.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-connected.html
new file mode 100644
index 0000000000..2e6249526c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-connected.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head id="head">
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#document-font-face-set">
+<meta name="assert" content="Ensure that calling FontFaceSet.load() operates on the up-to-date @font-face blocks." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style">
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<script>
+promise_test(async function(t) {
+ let fonts = document.fonts;
+ document.getElementById("head").removeChild(document.getElementById("style"));
+ let result = await fonts.load("12px 'WebFont'");
+ assert_equals(result.length, 0);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-wide-keywords.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-wide-keywords.html
new file mode 100644
index 0000000000..b5716fb4a0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-css-wide-keywords.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>SyntaxError thrown when matching CSS-wide keyword</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-set-load">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#find-the-matching-font-faces">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+ function load_on_worker(keyword) {
+ return new Promise((resolve, reject) =>{
+ var blob = new Blob([`
+ self.fonts.load('${keyword}').then(
+ ()=>{ self.postMessage('success') },
+ (e)=>{ self.postMessage(e) }
+ );
+ `]);
+ var blob_url = window.URL.createObjectURL(blob);
+ let worker = new Worker(blob_url);
+ worker.onmessage = msg => {
+ if (msg === 'success')
+ resolve(msg.data)
+ else
+ reject(msg.data)
+ }
+ });
+ }
+
+ // https://drafts.csswg.org/css-font-loading/#find-the-matching-font-faces
+ // forbids CSS-wide keywords as the value of the font given to the
+ // load method (equivalent to the font shorthand). Note that the test
+ // for this case will also pass when the system-wide keyword simply
+ // isn't supported, since the syntax won't be valid syntax for the
+ // 'font' shorthand.
+ // https://drafts.csswg.org/css-fonts-4/#family-name-syntax also
+ // forbids using the CSS-wide keywords as unquoted keywords within
+ // <font-family>.
+ for (let [description_prefix, syntax_prefix] of [["", ""], ["value with ", "medium "]]) {
+ for (let keyword of ["initial", "inherit", "unset", "default", "revert", "revert-layer"]) {
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', document.fonts.load(`${syntax_prefix}${keyword}`));
+ }, `Loading ${description_prefix}CSS-wide keyword "${keyword}" causes SyntaxError (document)`)
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', load_on_worker(`${syntax_prefix}${keyword}`));
+ }, `Loading ${description_prefix}CSS-wide keyword "${keyword}" causes SyntaxError (worker)`)
+ }
+ }
+
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-var.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-var.html
new file mode 100644
index 0000000000..1d74f8ed2a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-load-var.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>SyntaxError thrown when matching loading values with var()</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-set-load">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#find-the-matching-font-faces">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+ function load_on_worker(keyword) {
+ return new Promise((resolve, reject) =>{
+ var blob = new Blob([`
+ self.fonts.load('${keyword}').then(
+ ()=>{ self.postMessage('success') },
+ (e)=>{ self.postMessage(e) }
+ );
+ `]);
+ var blob_url = window.URL.createObjectURL(blob);
+ let worker = new Worker(blob_url);
+ worker.onmessage = msg => {
+ if (msg === 'success')
+ resolve(msg.data)
+ else
+ reject(msg.data)
+ }
+ });
+ }
+
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', document.fonts.load('var(--x) serif'));
+ }, 'Loading "var(--x) serif" causes SyntaxError (document)')
+
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', document.fonts.load('var(--x, 10px) serif'));
+ }, 'Loading "var(--x, 10px) serif" causes SyntaxError (document)')
+
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', load_on_worker('var(--x) serif'));
+ }, 'Loading "var(--x) serif" causes SyntaxError (worker)')
+
+ promise_test(test => {
+ return promise_rejects_dom(test, 'SyntaxError', load_on_worker('var(--x, 10px) serif'));
+ }, 'Loading "var(--x, 10px) serif" causes SyntaxError (worker)')
+
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-loading-worker-crash.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-loading-worker-crash.html
new file mode 100644
index 0000000000..552722b6ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-loading-worker-crash.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script>
+document.addEventListener("DOMContentLoaded", function() {
+ let a = new SharedWorker("support/fontfaceset-loading-worker.js")
+ a.port.postMessage([], [])
+})
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-no-root-element.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-no-root-element.html
new file mode 100644
index 0000000000..130019162f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-no-root-element.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Font Loading test: Load Document FontFaceSet font without documentElement</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-set-load">
+<link rel="help" href="https://crbug.com/971035">
+<script>
+ test(() => {
+ document.documentElement.remove();
+ var face = new FontFace("Ahem", "url(/fonts/Ahem.ttf)");
+ document.fonts.add(face);
+ document.fonts.load("12px Ahem");
+ }, "Trigger font load after removing documentElement. Should not crash.");
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-update-after-stylesheet-change.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-update-after-stylesheet-change.html
new file mode 100644
index 0000000000..f645f52029
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-update-after-stylesheet-change.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head id="head">
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#document-font-face-set">
+<meta name="assert" content="Ensure that stylesheet changes are reflected in document.fonts." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style">
+@font-face {
+ font-family: "WebFont";
+ src: url("resources/Rochester.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<script>
+test(function(t) {
+ let fonts = document.fonts;
+ assert_equals(fonts.size, 1);
+ document.getElementById("head").removeChild(document.getElementById("style"));
+ assert_equals(fonts.size, 0);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfaceset-worker-fontface-crash.html b/testing/web-platform/tests/css/css-font-loading/fontfaceset-worker-fontface-crash.html
new file mode 100644
index 0000000000..11f7e1faf0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfaceset-worker-fontface-crash.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html class="test-wait">
+<iframe id="frame" srcdoc=""></iframe>
+<script id="worker1" type="javascript/worker">
+self.onmessage = async function(e) {
+ let a = new MessageEvent('message')
+ for (let e = 0; e < 255; e++) {
+ new Uint8ClampedArray(2048).fill(e)
+ }
+ try { self.dispatchEvent(a) } catch (e) {}
+ let x = new FontFace('foo', 'x')
+}
+</script>
+<script>
+function tick() {
+ return new Promise(r => {
+ requestAnimationFrame(() => requestAnimationFrame(r));
+ });
+}
+onload = async () => {
+ let win = document.querySelector("#frame").contentWindow;
+ const blob = new win.Blob([document.querySelector('#worker1').textContent], { type: "text/javascript" })
+ let worker = new win.Worker(win.URL.createObjectURL(blob))
+ worker.postMessage([], [])
+ await tick();
+ await tick();
+ win.location.reload(true)
+ await tick();
+ document.documentElement.className = "";
+};
+</script>
+
diff --git a/testing/web-platform/tests/css/css-font-loading/fontfacesetloadevent-constructor.html b/testing/web-platform/tests/css/css-font-loading/fontfacesetloadevent-constructor.html
new file mode 100644
index 0000000000..d5038ce690
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/fontfacesetloadevent-constructor.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>FontFaceSetLoadEvent constructor</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontfacesetloadevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ test(function() {
+ var ff = [];
+ var e = new FontFaceSetLoadEvent('type');
+ assert_array_equals(e.fontfaces, ff);
+ assert_not_equals(e.fontfaces, ff);
+ }, 'FontFaceSetLoadEvent constructor without FontFaceSetLoadEventInit dictionary');
+
+ test(function() {
+ var ff = [ new FontFace('family', 'src') ];
+ var e = new FontFaceSetLoadEvent('type', { fontfaces: ff });
+ assert_array_equals(e.fontfaces, ff);
+ assert_not_equals(e.fontfaces, ff);
+ }, 'FontFaceSetLoadEvent constructor with FontFaceSetLoadEventInit dictionary');
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/idlharness.https.html b/testing/web-platform/tests/css/css-font-loading/idlharness.https.html
new file mode 100644
index 0000000000..23fc2cb9e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/idlharness.https.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Font Loading API IDL tests</title>
+<meta name="timeout" content="long">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontfacesetloadevent">
+<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';
+
+idl_test(
+ ['css-font-loading'],
+ ['dom', 'html', 'cssom'],
+ idl_array => {
+ idl_array.add_objects({
+ Document: ['document'],
+ FontFace: ['fontFace'],
+ FontFaceSetLoadEvent: ['fontFaceSetLoadEvent'],
+ FontFaceSet: ['document.fonts'],
+ });
+ self.fontFace = new FontFace("family", "src");
+ // The `fontFace.loaded` promise will be rejected, so handle that to
+ // avoid an unhandled promise rejection manifesting as a harness error.
+ self.fontFace.loaded.catch(() => {});
+ self.fontFaceSetLoadEvent = new FontFaceSetLoadEvent("type");
+ }
+);
+</script>
diff --git a/testing/web-platform/tests/css/css-font-loading/nonexistent-file-url.html b/testing/web-platform/tests/css/css-font-loading/nonexistent-file-url.html
new file mode 100644
index 0000000000..02ff678b3e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/nonexistent-file-url.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Myles C. Maxfield" href="mmaxfield@apple.com">
+<link rel="help" href="https://drafts.csswg.org/css-font-loading-3/#font-face-css-connection">
+<meta name="assert" content="Ensure that a file URL in a font-face block appears in document.fonts." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("file://ThisIsNotARealFile.otf") format("opentype");
+}
+</style>
+<script>
+test(function(t) {
+ assert_equals(document.fonts.size, 1, "A nonexistent file URL should appear in document.fonts.");
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-font-loading/resources/GenI102.woff2 b/testing/web-platform/tests/css/css-font-loading/resources/GenI102.woff2
new file mode 100644
index 0000000000..117d4a8fe7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/resources/GenI102.woff2
Binary files differ
diff --git a/testing/web-platform/tests/css/css-font-loading/resources/GenR102.woff2 b/testing/web-platform/tests/css/css-font-loading/resources/GenR102.woff2
new file mode 100644
index 0000000000..6e8b6d17e2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/resources/GenR102.woff2
Binary files differ
diff --git a/testing/web-platform/tests/css/css-font-loading/resources/Rochester.otf b/testing/web-platform/tests/css/css-font-loading/resources/Rochester.otf
new file mode 100644
index 0000000000..79f63ced68
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/resources/Rochester.otf
Binary files differ
diff --git a/testing/web-platform/tests/css/css-font-loading/support/fontfaceset-loading-worker.js b/testing/web-platform/tests/css/css-font-loading/support/fontfaceset-loading-worker.js
new file mode 100644
index 0000000000..7357975661
--- /dev/null
+++ b/testing/web-platform/tests/css/css-font-loading/support/fontfaceset-loading-worker.js
@@ -0,0 +1,8 @@
+onconnect = async function(e) {
+ e.ports[0].onmessage = async () => {
+ let a = new FontFace("family_name_0", "url(/fonts/Ahem.ttf?fontfaceset-loading-worker)")
+ self.close()
+ await a.load()
+ let _ = new File([a])
+ }
+}