Implement imagesrcset and imagesizes attributes on link rel=preload
https://bugs.webkit.org/show_bug.cgi?id=192950

Patch by Rob Buis <rbuis@igalia.com> on 2019-05-17
Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Import relevant tests for this feature.

* web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt: Added.
* web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html: Added.
* web-platform-tests/preload/link-header-preload-delay-onload-expected.txt: Added.
* web-platform-tests/preload/link-header-preload-delay-onload.html: Added.
* web-platform-tests/preload/link-header-preload-delay-onload.html.headers: Added.
* web-platform-tests/preload/link-header-preload-expected.txt: Added.
* web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt: Added.
* web-platform-tests/preload/link-header-preload-imagesrcset.html: Added.
* web-platform-tests/preload/link-header-preload-imagesrcset.html.headers: Added.
* web-platform-tests/preload/link-header-preload-nonce-expected.txt: Added.
* web-platform-tests/preload/link-header-preload-nonce.html: Added.
* web-platform-tests/preload/link-header-preload-nonce.html.headers: Added.
* web-platform-tests/preload/link-header-preload.html: Added.
* web-platform-tests/preload/link-header-preload.html.headers: Added.
* web-platform-tests/preload/onload-event-expected.txt: Added.
* web-platform-tests/preload/onload-event.html: Added.
* web-platform-tests/preload/preload-csp.sub-expected.txt:
* web-platform-tests/preload/preload-csp.sub.html:
* web-platform-tests/preload/preload-default-csp.sub-expected.txt:
* web-platform-tests/preload/preload-default-csp.sub.html:
* web-platform-tests/preload/preload-with-type-expected.txt: Added.
* web-platform-tests/preload/preload-with-type.html: Added.
* web-platform-tests/preload/resources/A4.ogv: Added.
* web-platform-tests/preload/resources/A4.ogv.sub.headers: Added.
* web-platform-tests/preload/resources/cross-origin-module.py: Added.
(main):
* web-platform-tests/preload/resources/dummy-preloads-subresource.css: Added.
* web-platform-tests/preload/resources/dummy-preloads-subresource.css.sub.headers: Added.
* web-platform-tests/preload/resources/empty.html: Added.
* web-platform-tests/preload/resources/empty.html.sub.headers: Added.
* web-platform-tests/preload/resources/foo.vtt.sub.headers: Added.
* web-platform-tests/preload/resources/module1.js: Added.
* web-platform-tests/preload/resources/module2.js: Added.
* web-platform-tests/preload/resources/preload_helper.js:
(verifyNumberOfResourceTimingEntries):
(numberOfResourceTimingEntries):
(verifyLoadedAndNoDoubleDownload):
* web-platform-tests/preload/single-download-preload-expected.txt:
* web-platform-tests/preload/single-download-preload.html:

Source/WebCore:

Implement imagesrcset and imagesizes attributes for both Link header
and link element.

Tests: imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html
       imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html
       imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html
       imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html
       imported/w3c/web-platform-tests/preload/link-header-preload.html
       imported/w3c/web-platform-tests/preload/onload-event.html
       imported/w3c/web-platform-tests/preload/preload-with-type.html

* html/HTMLAttributeNames.in:
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::process):
* html/HTMLLinkElement.idl:
* loader/LinkHeader.cpp:
(WebCore::paramterNameFromString):
(WebCore::LinkHeader::setValue):
(WebCore::LinkHeader::LinkHeader):
* loader/LinkHeader.h:
(WebCore::LinkHeader::imageSrcSet const):
(WebCore::LinkHeader::imageSizes const):
(WebCore::LinkHeader::isViewportDependent const):
* loader/LinkLoader.cpp:
(WebCore::LinkLoader::loadLinksFromHeader):
(WebCore::LinkLoader::preloadIfNeeded):
(WebCore::LinkLoader::loadLink):
* loader/LinkLoader.h:

LayoutTests:

Write special expectation for link-header-preload-imagesrcset.html because test runner
uses different dimensions on iOS.

* platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt: Added.
* platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@245475 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index e15385e..3f60e38 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,16 @@
+2019-05-17  Rob Buis  <rbuis@igalia.com>
+
+        Implement imagesrcset and imagesizes attributes on link rel=preload
+        https://bugs.webkit.org/show_bug.cgi?id=192950
+
+        Reviewed by Youenn Fablet.
+
+        Write special expectation for link-header-preload-imagesrcset.html because test runner
+        uses different dimensions on iOS.
+
+        * platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt: Added.
+        * platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt: Added.
+
 2019-05-17  Shawn Roberts  <sroberts@apple.com>
 
         media/controls-after-reload.html failing on iOS after unskip
diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog
index 7e0e47b..b9152e7 100644
--- a/LayoutTests/imported/w3c/ChangeLog
+++ b/LayoutTests/imported/w3c/ChangeLog
@@ -1,3 +1,52 @@
+2019-05-17  Rob Buis  <rbuis@igalia.com>
+
+        Implement imagesrcset and imagesizes attributes on link rel=preload
+        https://bugs.webkit.org/show_bug.cgi?id=192950
+
+        Reviewed by Youenn Fablet.
+
+        Import relevant tests for this feature.
+
+        * web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt: Added.
+        * web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html: Added.
+        * web-platform-tests/preload/link-header-preload-delay-onload-expected.txt: Added.
+        * web-platform-tests/preload/link-header-preload-delay-onload.html: Added.
+        * web-platform-tests/preload/link-header-preload-delay-onload.html.headers: Added.
+        * web-platform-tests/preload/link-header-preload-expected.txt: Added.
+        * web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt: Added.
+        * web-platform-tests/preload/link-header-preload-imagesrcset.html: Added.
+        * web-platform-tests/preload/link-header-preload-imagesrcset.html.headers: Added.
+        * web-platform-tests/preload/link-header-preload-nonce-expected.txt: Added.
+        * web-platform-tests/preload/link-header-preload-nonce.html: Added.
+        * web-platform-tests/preload/link-header-preload-nonce.html.headers: Added.
+        * web-platform-tests/preload/link-header-preload.html: Added.
+        * web-platform-tests/preload/link-header-preload.html.headers: Added.
+        * web-platform-tests/preload/onload-event-expected.txt: Added.
+        * web-platform-tests/preload/onload-event.html: Added.
+        * web-platform-tests/preload/preload-csp.sub-expected.txt:
+        * web-platform-tests/preload/preload-csp.sub.html:
+        * web-platform-tests/preload/preload-default-csp.sub-expected.txt:
+        * web-platform-tests/preload/preload-default-csp.sub.html:
+        * web-platform-tests/preload/preload-with-type-expected.txt: Added.
+        * web-platform-tests/preload/preload-with-type.html: Added.
+        * web-platform-tests/preload/resources/A4.ogv: Added.
+        * web-platform-tests/preload/resources/A4.ogv.sub.headers: Added.
+        * web-platform-tests/preload/resources/cross-origin-module.py: Added.
+        (main):
+        * web-platform-tests/preload/resources/dummy-preloads-subresource.css: Added.
+        * web-platform-tests/preload/resources/dummy-preloads-subresource.css.sub.headers: Added.
+        * web-platform-tests/preload/resources/empty.html: Added.
+        * web-platform-tests/preload/resources/empty.html.sub.headers: Added.
+        * web-platform-tests/preload/resources/foo.vtt.sub.headers: Added.
+        * web-platform-tests/preload/resources/module1.js: Added.
+        * web-platform-tests/preload/resources/module2.js: Added.
+        * web-platform-tests/preload/resources/preload_helper.js:
+        (verifyNumberOfResourceTimingEntries):
+        (numberOfResourceTimingEntries):
+        (verifyLoadedAndNoDoubleDownload):
+        * web-platform-tests/preload/single-download-preload-expected.txt:
+        * web-platform-tests/preload/single-download-preload.html:
+
 2019-05-14  Oriol Brufau  <obrufau@igalia.com>
 
         [css-grid] Update grid when changing auto repeat type
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt
new file mode 100644
index 0000000..834fc93
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt
@@ -0,0 +1,3 @@
+
+PASS Makes sure that a dynamically added preload with imagesrcset works 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html b/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html
new file mode 100644
index 0000000..e1b8431
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<script>
+    var t = async_test('Makes sure that a dynamically added preload with imagesrcset works');
+</script>
+<body>
+<script>
+    t.step(function() {
+        verifyPreloadAndRTSupport();
+        var link = document.createElement("link");
+        link.as = "image";
+        link.rel = "preload";
+        link.href = "resources/square.png?default";
+        link.imageSrcset = "resources/square.png?200 200w, resources/square.png?400 400w, resources/square.png?800 800w";
+        link.imageSizes = "400px";
+        link.onload = t.step_func(function() {
+            t.step_timeout(function() {
+                verifyNumberOfResourceTimingEntries("resources/square.png?default", 0);
+                verifyNumberOfResourceTimingEntries("resources/square.png?200", 0);
+                verifyNumberOfResourceTimingEntries("resources/square.png?400", 1);
+                verifyNumberOfResourceTimingEntries("resources/square.png?800", 0);
+                t.done();
+            }, 0);
+        });
+        document.body.appendChild(link);
+    });
+</script>
+</body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload-expected.txt
new file mode 100644
index 0000000..93d88524
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload-expected.txt
@@ -0,0 +1,4 @@
+
+
+PASS Makes sure that Link headers preload resources and block window.onload after resource discovery 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html
new file mode 100644
index 0000000..a445d80
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<script>
+    var t = async_test('Makes sure that Link headers preload resources and block window.onload after resource discovery');
+</script>
+<body>
+<style>
+    #background {
+        width: 200px;
+        height: 200px;
+        background-image: url(resources/square.png?background);
+    }
+</style>
+<link rel="stylesheet" href="resources/dummy.css?link-header-preload-delay-onload">
+<script src="resources/dummy.js?link-header-preload-delay-onload"></script>
+<div id="background"></div>
+<script>
+    document.write('<img src="resources/square.png?link-header-preload-delay-onload">');
+    window.addEventListener("load", t.step_func(function() {
+        verifyPreloadAndRTSupport();
+        var entries = performance.getEntriesByType("resource");
+        var found_background_first = false;
+        for (var i = 0; i < entries.length; ++i) {
+            var entry = entries[i];
+            if (entry.name.indexOf("square") != -1) {
+                if (entry.name.indexOf("background") != -1)
+                    found_background_first = true;
+                break;
+            }
+        }
+        assert_true(found_background_first);
+        verifyLoadedAndNoDoubleDownload("resources/square.png?link-header-preload-delay-onload");
+        verifyLoadedAndNoDoubleDownload("resources/square.png?background");
+        verifyLoadedAndNoDoubleDownload("resources/dummy.js?link-header-preload-delay-onload");
+        verifyLoadedAndNoDoubleDownload("resources/dummy.css?link-header-preload-delay-onload");
+        t.done();
+    }));
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html.headers
new file mode 100644
index 0000000..a9ca424
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html.headers
@@ -0,0 +1,5 @@
+Link: </preload/resources/square.png?background>;rel=preload;as=image
+Link: </preload/resources/dummy.js?link-header-preload-delay-onload>;rel=preload;as=script
+Link: </preload/resources/dummy.css?link-header-preload-delay-onload>;rel=preload;as=style
+Link: </preload/resources/square.png?link-header-preload-delay-onload>;rel=preload;as=image
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-expected.txt
new file mode 100644
index 0000000..94c4b44
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-expected.txt
@@ -0,0 +1,3 @@
+
+PASS Makes sure that Link headers preload resources 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt
new file mode 100644
index 0000000..4a35913
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt
@@ -0,0 +1,3 @@
+
+PASS Makes sure that Link headers preload images with imagesrcset/imagesizes attributes. 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html
new file mode 100644
index 0000000..b41cbee
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Makes sure that Link headers preload images with imagesrcset/imagesizes attributes.</title>
+<link rel="help" href="https://github.com/w3c/preload/issues/120">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<body>
+<script>
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (numberOfResourceTimingEntries('resources/square.png?from-header&1x') == 1 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&2x') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&3x') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&base') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&200') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&400') == 1 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&800') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&150') == 0 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&300') == 1 &&
+            numberOfResourceTimingEntries('resources/square.png?from-header&600') == 0) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&1x', 1);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&2x', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&3x', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&base', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&200', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&400', 1);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&800', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&150', 0);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&300', 1);
+            verifyNumberOfResourceTimingEntries('resources/square.png?from-header&600', 0);
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
+    });
+</script>
+</body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html.headers
new file mode 100644
index 0000000..906de0c
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html.headers
@@ -0,0 +1,3 @@
+Link: <resources/square.png?from-header&1x>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&2x 2x, resources/square.png?from-header&3x 3x"
+Link: <resources/square.png?from-header&base>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&200 200w, resources/square.png?from-header&400 400w, resources/square.png?from-header&800 800w"; imagesizes=400px
+Link: <resources/square.png?from-header&base>; rel=preload; as=image; imagesrcset="resources/square.png?from-header&150 150w, resources/square.png?from-header&300 300w, resources/square.png?from-header&600 600w"; imagesizes="(min-width: 300px) 300px, 150px"
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce-expected.txt
new file mode 100644
index 0000000..3f6ce93
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/dummy.js?from-header&without-nonce because it does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/dummy.js?from-header&with-nonce because it does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 2659: Error: assert_equals: resources/dummy.js?from-header&with-nonce expected 1 but got 0
+
+FAIL Makes sure that Link headers preload resources with CSP nonce Error: assert_equals: resources/dummy.js?from-header&with-nonce expected 1 but got 0
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html
new file mode 100644
index 0000000..bfac563
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Makes sure that Link headers preload resources with CSP nonce</title>
+<script nonce="abc" src="/resources/testharness.js"></script>
+<script nonce="abc" src="/resources/testharnessreport.js"></script>
+<script nonce="abc" src="/preload/resources/preload_helper.js"></script>
+<body>
+<script nonce="abc">
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (numberOfResourceTimingEntries("resources/dummy.js?from-header&without-nonce") == 0 &&
+            numberOfResourceTimingEntries("resources/dummy.js?from-header&with-nonce") == 1) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
+            verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&without-nonce", 0);
+            verifyNumberOfResourceTimingEntries("resources/dummy.js?from-header&with-nonce", 1);
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
+    });
+</script>
+</body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html.headers
new file mode 100644
index 0000000..a54b693
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html.headers
@@ -0,0 +1,3 @@
+Content-Security-Policy: script-src 'nonce-abc'
+Link: </preload/resources/dummy.js?from-header&without-nonce>;rel=preload;as=script
+Link: </preload/resources/dummy.js?from-header&with-nonce>;rel=preload;as=script;nonce=abc
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html
new file mode 100644
index 0000000..4dfdfc8
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Makes sure that Link headers preload resources</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<body>
+<script>
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (numberOfResourceTimingEntries("resources/square.png?link-header-preload") == 1 &&
+            numberOfResourceTimingEntries("resources/dummy.js?link-header-preload") == 1 &&
+            numberOfResourceTimingEntries("resources/dummy.css?link-header-preload") == 1) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
+            verifyNumberOfResourceTimingEntries("resources/square.png?link-header-preload", 1);
+            verifyNumberOfResourceTimingEntries("resources/dummy.js?link-header-preload", 1);
+            verifyNumberOfResourceTimingEntries("resources/dummy.css?link-header-preload", 1);
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
+    });
+</script>
+</body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html.headers
new file mode 100644
index 0000000..293598e
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/link-header-preload.html.headers
@@ -0,0 +1,4 @@
+Link: </preload/resources/dummy.js?link-header-preload>;rel=preload;as=script
+Link: </preload/resources/dummy.css?link-header-preload>;rel=preload;as=style
+Link: </preload/resources/square.png?link-header-preload>;rel=preload;as=image
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event-expected.txt
new file mode 100644
index 0000000..0fb9be3
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 26: <link rel=preload> must have a valid `as` value
+CONSOLE MESSAGE: line 28: <link rel=preload> must have a valid `as` value
+
+PASS Makes sure that preloaded resources trigger the onload event 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event.html b/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event.html
new file mode 100644
index 0000000..9111cd8
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/onload-event.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>Makes sure that preloaded resources trigger the onload event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<script>
+    var scriptLoaded = false;
+    var styleLoaded = false;
+    var imageLoaded = false;
+    var fontLoaded = false;
+    var videoLoaded = false;
+    var audioLoaded = false;
+    var trackLoaded = false;
+    var gibberishLoaded = false;
+    var gibberishErrored = false;
+    var noTypeLoaded = false;
+    var fetchLoaded = false;
+</script>
+<link rel=preload href="resources/dummy.js" as=script onload="scriptLoaded = true;">
+<link rel=preload href="resources/dummy.css" as=style onload="styleLoaded = true;">
+<link rel=preload href="resources/square.png" as=image onload="imageLoaded = true;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font crossorigin onload="fontLoaded = true;">
+<link rel=preload href="resources/white.mp4" as=video onload="videoLoaded = true;">
+<link rel=preload href="resources/sound_5.oga" as=audio onload="audioLoaded = true;">
+<link rel=preload href="resources/foo.vtt" as=track onload="trackLoaded = true;">
+<link rel=preload href="resources/dummy.xml?foo=bar" as=foobarxmlthing onload="gibberishLoaded = true;" onerror="gibberishErrored = true;">
+<link rel=preload href="resources/dummy.xml?fetch" as=fetch onload="fetchLoaded = true;">
+<link rel=preload href="resources/dummy.xml" onload="noTypeLoaded = true;">
+<body>
+<script>
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (styleLoaded && scriptLoaded && imageLoaded && fontLoaded && videoLoaded && audioLoaded &&
+            trackLoaded && !gibberishLoaded && !gibberishErrored && fetchLoaded && !noTypeLoaded) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
+            assert_true(styleLoaded, "style triggered load event");
+            assert_true(scriptLoaded, "script triggered load event");
+            assert_true(imageLoaded, "image triggered load event");
+            assert_true(fontLoaded, "font triggered load event");
+            assert_true(videoLoaded, "video triggered load event");
+            assert_true(audioLoaded, "audio triggered load event");
+            assert_true(trackLoaded, "track triggered load event");
+            assert_false(gibberishLoaded, "gibberish as value triggered load event");
+            assert_false(gibberishErrored, "gibberish as value triggered error event");
+            assert_true(fetchLoaded, "fetch as value triggered load event");
+            assert_false(noTypeLoaded, "empty as triggered load event");
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
+    });
+</script>
+</body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub-expected.txt
index f6668c7..2a61cb6 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub-expected.txt
@@ -12,8 +12,8 @@
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/white.mp4 because it does not appear in the media-src directive of the Content Security Policy.
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/sound_5.oga because it does not appear in the media-src directive of the Content Security Policy.
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/foo.vtt because it does not appear in the media-src directive of the Content Security Policy.
-CONSOLE MESSAGE: line 16: <link rel=preload> must have a valid `as` value
-CONSOLE MESSAGE: line 17: <link rel=preload> must have a valid `as` value
+CONSOLE MESSAGE: line 14: <link rel=preload> must have a valid `as` value
+CONSOLE MESSAGE: line 15: <link rel=preload> must have a valid `as` value
 
 PASS Makes sure that preload requests respect CSP 
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub.html b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub.html
index 7fe06eb..62d0c71 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-csp.sub.html
@@ -1,11 +1,9 @@
 <!DOCTYPE html>
 <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; font-src 'none'; style-src 'none'; img-src 'none'; media-src 'none'; connect-src 'none'">
+<title>Makes sure that preload requests respect CSP</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/preload/resources/preload_helper.js"></script>
-<script>
-    var t = async_test('Makes sure that preload requests respect CSP');
-</script>
 <link rel=preload href="{{host}}:{{ports[http][1]}}/preload/resources/dummy.js" as=style>
 <link rel=preload href="resources/dummy.css" as=style>
 <link rel=preload href="resources/square.png" as=image>
@@ -17,9 +15,24 @@
 <link rel=preload href="resources/dummy.xml">
 <body>
 <script>
-    window.onload = t.step_func(function() {
-        t.step_timeout(function() {
-            verifyPreloadAndRTSupport();
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (numberOfResourceTimingEntries("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js") == 0 &&
+            numberOfResourceTimingEntries("resources/dummy.css") == 0 &&
+            numberOfResourceTimingEntries("resources/square.png") == 0 &&
+            numberOfResourceTimingEntries("/fonts/CanvasTest.ttf") == 0 &&
+            numberOfResourceTimingEntries("resources/white.mp4") == 0 &&
+            numberOfResourceTimingEntries("resources/sound_5.oga") == 0 &&
+            numberOfResourceTimingEntries("resources/foo.vtt") == 0 &&
+            numberOfResourceTimingEntries("resources/dummy.xml") == 0) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
             verifyNumberOfResourceTimingEntries("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js", 0);
             verifyNumberOfResourceTimingEntries("resources/dummy.css", 0);
             verifyNumberOfResourceTimingEntries("resources/square.png", 0);
@@ -28,8 +41,15 @@
             verifyNumberOfResourceTimingEntries("resources/sound_5.oga", 0);
             verifyNumberOfResourceTimingEntries("resources/foo.vtt", 0);
             verifyNumberOfResourceTimingEntries("resources/dummy.xml", 0);
-            t.done();
-        }, 5000);
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
     });
 </script>
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub-expected.txt
index 30cbfd5..f0fa7f2 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub-expected.txt
@@ -12,8 +12,8 @@
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/white.mp4 because it appears in neither the media-src directive nor the default-src directive of the Content Security Policy.
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/sound_5.oga because it appears in neither the media-src directive nor the default-src directive of the Content Security Policy.
 CONSOLE MESSAGE: Refused to load http://localhost:8800/preload/resources/foo.vtt because it appears in neither the media-src directive nor the default-src directive of the Content Security Policy.
-CONSOLE MESSAGE: line 16: <link rel=preload> must have a valid `as` value
-CONSOLE MESSAGE: line 17: <link rel=preload> must have a valid `as` value
+CONSOLE MESSAGE: line 14: <link rel=preload> must have a valid `as` value
+CONSOLE MESSAGE: line 15: <link rel=preload> must have a valid `as` value
 
 PASS Makes sure that preload requests respect CSP 
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub.html b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub.html
index 7813e36..9fc1194 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-default-csp.sub.html
@@ -1,11 +1,9 @@
 <!DOCTYPE html>
 <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; default-src 'none'">
+<title>Makes sure that preload requests respect CSP</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/preload/resources/preload_helper.js"></script>
-<script>
-    var t = async_test('Makes sure that preload requests respect CSP');
-</script>
 <link rel=preload href="{{host}}:{{ports[http][1]}}/preload/resources/dummy.js" as=style>
 <link rel=preload href="resources/dummy.css" as=style>
 <link rel=preload href="resources/square.png" as=image>
@@ -17,9 +15,24 @@
 <link rel=preload href="resources/dummy.xml">
 <body>
 <script>
-    window.onload = t.step_func(function() {
-        t.step_timeout(function() {
-            verifyPreloadAndRTSupport();
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (numberOfResourceTimingEntries("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js") == 0 &&
+            numberOfResourceTimingEntries("resources/dummy.css") == 0 &&
+            numberOfResourceTimingEntries("resources/square.png") == 0 &&
+            numberOfResourceTimingEntries("/fonts/CanvasTest.ttf") == 0 &&
+            numberOfResourceTimingEntries("resources/white.mp4") == 0 &&
+            numberOfResourceTimingEntries("resources/sound_5.oga") == 0 &&
+            numberOfResourceTimingEntries("resources/foo.vtt") == 0 &&
+            numberOfResourceTimingEntries("resources/dummy.xml") == 0) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
             verifyNumberOfResourceTimingEntries("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js", 0);
             verifyNumberOfResourceTimingEntries("resources/dummy.css", 0);
             verifyNumberOfResourceTimingEntries("resources/square.png", 0);
@@ -28,8 +41,15 @@
             verifyNumberOfResourceTimingEntries("resources/sound_5.oga", 0);
             verifyNumberOfResourceTimingEntries("resources/foo.vtt", 0);
             verifyNumberOfResourceTimingEntries("resources/dummy.xml", 0);
-            t.done();
-        }, 5000);
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
     });
 </script>
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type-expected.txt
new file mode 100644
index 0000000..1532e8c
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type-expected.txt
@@ -0,0 +1,3 @@
+
+PASS Makes sure that preloaded resources with a type attribute trigger the onload event 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type.html b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type.html
new file mode 100644
index 0000000..9805922
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/preload-with-type.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<title>Makes sure that preloaded resources with a type attribute trigger the onload event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<script src="/common/media.js"></script>
+<script>
+    var scriptLoaded = false;
+    var styleLoaded = false;
+    var imageLoaded = false;
+    var fontLoaded = false;
+    var videoLoaded = false;
+    var audioLoaded = false;
+    var trackLoaded = false;
+    var gibberishLoaded = 0;
+    var getFormat = function(url) {
+        var dot = url.lastIndexOf('.');
+        if (dot != -1) {
+            var extension = url.substring(dot + 1);
+            if (extension.startsWith("og"))
+                return "ogg";
+            return extension;
+        }
+        return null;
+    };
+    var videoURL = getVideoURI("resources/A4");
+    var audioURL = getAudioURI("resources/sound_5");
+    var videoFormat = getFormat(videoURL);
+    var audioFormat = getFormat(audioURL);
+</script>
+<link rel=preload href="resources/dummy.js" as=script type="text/javascript" onload="scriptLoaded = true;">
+<link rel=preload href="resources/dummy.css" as=style type="text/css" onload="styleLoaded = true;">
+<link rel=preload href="resources/square.png" as=image type="image/png" onload="imageLoaded = true;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font type="font/ttf" crossorigin onload="fontLoaded = true;">
+<script>
+    document.write('<link rel=preload href="' + videoURL + '" as=video type="video/' + videoFormat + '" onload="videoLoaded = true;">');
+    document.write('<link rel=preload href="' + audioURL + '" as=audio type="audio/' + audioFormat + '" onload="audioLoaded = true;">');
+</script>
+<link rel=preload href="resources/foo.vtt" as=track type="text/vtt" onload="trackLoaded = true;">
+<link rel=preload href="resources/dummy.js" as=script type="application/foobar" onload="gibberishLoaded++;">
+<link rel=preload href="resources/dummy.css" as=style type="text/foobar" onload="gibberishLoaded++;">
+<link rel=preload href="resources/square.png" as=image type="image/foobar" onload="gibberishLoaded++;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font type="font/foobar" crossorigin onload="gibberishLoaded++;">
+<script>
+    document.write('<link rel=preload href="' + videoURL + '" as=video type="video/foobar" onload="gibberishLoaded++;">');
+    document.write('<link rel=preload href="' + audioURL + '" as=audio type="audio/foobar" onload="gibberishLoaded++;">');
+</script>
+<link rel=preload href="resources/foo.vtt" as=track type="text/foobar" onload="gibberishLoaded++;">
+<body>
+<script>
+    setup({explicit_done: true});
+
+    var iterations = 0;
+
+    function check_finished() {
+        if (styleLoaded && scriptLoaded && imageLoaded && fontLoaded && videoLoaded && audioLoaded &&
+            trackLoaded && gibberishLoaded == 0) {
+            done();
+        }
+        iterations++;
+        if (iterations == 10) {
+            // At least one is expected to fail, but this should give details to the exact failure(s).
+            assert_true(styleLoaded, "style triggered load event");
+            assert_true(scriptLoaded, "script triggered load event");
+            assert_true(imageLoaded, "image triggered load event");
+            assert_true(fontLoaded, "font triggered load event");
+            assert_true(videoLoaded, "video triggered load event");
+            assert_true(audioLoaded, "audio triggered load event");
+            assert_true(trackLoaded, "track triggered load event");
+            assert_equals(gibberishLoaded, 0, "resources with gibberish type should not be loaded");
+            done();
+        } else {
+            step_timeout(check_finished, 500);
+        }
+    }
+
+    window.addEventListener("load", function() {
+        verifyPreloadAndRTSupport();
+        step_timeout(check_finished, 500);
+    });
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv
new file mode 100644
index 0000000..de99616
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv
Binary files differ
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv.sub.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv.sub.headers
new file mode 100644
index 0000000..360e668
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/A4.ogv.sub.headers
@@ -0,0 +1 @@
+Cache-Control: max-age=1000
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/cross-origin-module.py b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/cross-origin-module.py
new file mode 100644
index 0000000..f771c96
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/cross-origin-module.py
@@ -0,0 +1,9 @@
+def main(request, response):
+    headers = [
+        ("Content-Type", "text/javascript"),
+        ("Access-Control-Allow-Origin", request.headers.get("Origin")),
+        ("Timing-Allow-Origin", request.headers.get("Origin")),
+        ("Access-Control-Allow-Credentials", "true")
+    ]
+
+    return headers, "// Cross-origin module, nothing to see here"
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css
new file mode 100644
index 0000000..5097166
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css
@@ -0,0 +1 @@
+/* This is just a dummy, empty CSS file */
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css.sub.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css.sub.headers
new file mode 100644
index 0000000..f6b4b49
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/dummy-preloads-subresource.css.sub.headers
@@ -0,0 +1,2 @@
+Cache-Control: max-age=1000
+Link: </fonts/CanvasTest.ttf?link-header-on-subresource>; rel=preload;as=font;crossorigin
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html.sub.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html.sub.headers
new file mode 100644
index 0000000..360e668
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/empty.html.sub.headers
@@ -0,0 +1 @@
+Cache-Control: max-age=1000
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/foo.vtt.sub.headers b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/foo.vtt.sub.headers
new file mode 100644
index 0000000..360e668
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/foo.vtt.sub.headers
@@ -0,0 +1 @@
+Cache-Control: max-age=1000
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module1.js b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module1.js
new file mode 100644
index 0000000..9c3b675
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module1.js
@@ -0,0 +1,2 @@
+import { y } from './module2.js';
+export let x = y + 1;
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module2.js b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module2.js
new file mode 100644
index 0000000..e4e3217
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/module2.js
@@ -0,0 +1 @@
+export let y = 1;
diff --git a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/preload_helper.js b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/preload_helper.js
index f464908..1c7c1a2 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/preload/resources/preload_helper.js
+++ b/LayoutTests/imported/w3c/web-platform-tests/preload/resources/preload_helper.js
@@ -12,8 +12,12 @@
 
 function verifyNumberOfResourceTimingEntries(url, number)
 {
-    var numEntries = performance.getEntriesByName(getAbsoluteURL(url)).length;
-    assert_equals(numEntries, number, url);
+    assert_equals(numberOfResourceTimingEntries(url), number, url);
+}
+
+function numberOfResourceTimingEntries(url)
+{
+    return performance.getEntriesByName(getAbsoluteURL(url)).length;
 }
 
 // Verifies that the resource is loaded, but not downloaded from network
diff --git a/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt b/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt
new file mode 100644
index 0000000..cf91b1a
--- /dev/null
+++ b/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset-expected.txt
@@ -0,0 +1,3 @@
+
+FAIL Makes sure that a dynamically added preload with imagesrcset works assert_equals: resources/square.png?400 expected 1 but got 0
+
diff --git a/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt b/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt
new file mode 100644
index 0000000..4981a4f
--- /dev/null
+++ b/LayoutTests/platform/ios-simulator-12-wk2/imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset-expected.txt
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: The resource http://localhost:8800/preload/resources/square.png?from-header&2x was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.
+CONSOLE MESSAGE: The resource http://localhost:8800/preload/resources/square.png?from-header&800 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.
+CONSOLE MESSAGE: The resource http://localhost:8800/preload/resources/square.png?from-header&600 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.
+CONSOLE MESSAGE: line 2659: Error: assert_equals: resources/square.png?from-header&1x expected 1 but got 0
+
+FAIL Makes sure that Link headers preload images with imagesrcset/imagesizes attributes. Error: assert_equals: resources/square.png?from-header&1x expected 1 but got 0
+
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index f48b5fb..5b989f3 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,39 @@
+2019-05-17  Rob Buis  <rbuis@igalia.com>
+
+        Implement imagesrcset and imagesizes attributes on link rel=preload
+        https://bugs.webkit.org/show_bug.cgi?id=192950
+
+        Reviewed by Youenn Fablet.
+
+        Implement imagesrcset and imagesizes attributes for both Link header
+        and link element.
+
+        Tests: imported/w3c/web-platform-tests/preload/dynamic-adding-preload-imagesrcset.html
+               imported/w3c/web-platform-tests/preload/link-header-preload-delay-onload.html
+               imported/w3c/web-platform-tests/preload/link-header-preload-imagesrcset.html
+               imported/w3c/web-platform-tests/preload/link-header-preload-nonce.html
+               imported/w3c/web-platform-tests/preload/link-header-preload.html
+               imported/w3c/web-platform-tests/preload/onload-event.html
+               imported/w3c/web-platform-tests/preload/preload-with-type.html
+
+        * html/HTMLAttributeNames.in:
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::process):
+        * html/HTMLLinkElement.idl:
+        * loader/LinkHeader.cpp:
+        (WebCore::paramterNameFromString):
+        (WebCore::LinkHeader::setValue):
+        (WebCore::LinkHeader::LinkHeader):
+        * loader/LinkHeader.h:
+        (WebCore::LinkHeader::imageSrcSet const):
+        (WebCore::LinkHeader::imageSizes const):
+        (WebCore::LinkHeader::isViewportDependent const):
+        * loader/LinkLoader.cpp:
+        (WebCore::LinkLoader::loadLinksFromHeader):
+        (WebCore::LinkLoader::preloadIfNeeded):
+        (WebCore::LinkLoader::loadLink):
+        * loader/LinkLoader.h:
+
 2019-05-17  Keith Rollin  <krollin@apple.com>
 
         Re-enable generate-xcfilelists
diff --git a/Source/WebCore/html/HTMLAttributeNames.in b/Source/WebCore/html/HTMLAttributeNames.in
index 606cfb9..1e9a826 100644
--- a/Source/WebCore/html/HTMLAttributeNames.in
+++ b/Source/WebCore/html/HTMLAttributeNames.in
@@ -144,6 +144,8 @@
 hspace
 http_equiv
 id
+imagesizes
+imagesrcset
 incremental
 indeterminate
 inputmode
diff --git a/Source/WebCore/html/HTMLLinkElement.cpp b/Source/WebCore/html/HTMLLinkElement.cpp
index bb438be..adec9ea 100644
--- a/Source/WebCore/html/HTMLLinkElement.cpp
+++ b/Source/WebCore/html/HTMLLinkElement.cpp
@@ -262,7 +262,7 @@
 
     URL url = getNonEmptyURLAttribute(hrefAttr);
 
-    if (!m_linkLoader.loadLink(m_relAttribute, url, attributeWithoutSynchronization(asAttr), attributeWithoutSynchronization(mediaAttr), attributeWithoutSynchronization(typeAttr), attributeWithoutSynchronization(crossoriginAttr), document()))
+    if (!m_linkLoader.loadLink(m_relAttribute, url, attributeWithoutSynchronization(asAttr), attributeWithoutSynchronization(mediaAttr), attributeWithoutSynchronization(typeAttr), attributeWithoutSynchronization(crossoriginAttr), attributeWithoutSynchronization(imagesrcsetAttr),  attributeWithoutSynchronization(imagesizesAttr), document()))
         return;
 
     bool treatAsStyleSheet = m_relAttribute.isStyleSheet
diff --git a/Source/WebCore/html/HTMLLinkElement.idl b/Source/WebCore/html/HTMLLinkElement.idl
index 8c5c6ee..4fbb938 100644
--- a/Source/WebCore/html/HTMLLinkElement.idl
+++ b/Source/WebCore/html/HTMLLinkElement.idl
@@ -35,6 +35,8 @@
     [CEReactions=NotNeeded, Reflect] attribute DOMString type;
     [CEReactions=NotNeeded] attribute DOMString as;
     [CEReactions=NotNeeded] attribute DOMString? crossOrigin;
+    [CEReactions=NotNeeded, Reflect] attribute DOMString imageSrcset;
+    [CEReactions=NotNeeded, Reflect] attribute DOMString imageSizes;
 
     // DOM Level 2 Style
     readonly attribute StyleSheet sheet;
diff --git a/Source/WebCore/loader/LinkHeader.cpp b/Source/WebCore/loader/LinkHeader.cpp
index 0c7e766..32a338b 100644
--- a/Source/WebCore/loader/LinkHeader.cpp
+++ b/Source/WebCore/loader/LinkHeader.cpp
@@ -165,6 +165,10 @@
         return LinkHeader::LinkParameterHreflang;
     if (equalLettersIgnoringASCIICase(name, "as"))
         return LinkHeader::LinkParameterAs;
+    if (equalLettersIgnoringASCIICase(name, "imagesrcset"))
+        return LinkHeader::LinkParameterImageSrcSet;
+    if (equalLettersIgnoringASCIICase(name, "imagesizes"))
+        return LinkHeader::LinkParameterImageSizes;
     return LinkHeader::LinkParameterUnknown;
 }
 
@@ -264,27 +268,33 @@
     return !hasQuotes || completeQuotes;
 }
 
-void LinkHeader::setValue(LinkParameterName name, String value)
+void LinkHeader::setValue(LinkParameterName name, String&& value)
 {
     switch (name) {
     case LinkParameterRel:
         if (!m_rel)
-            m_rel = value;
+            m_rel = WTFMove(value);
         break;
     case LinkParameterAnchor:
         m_isValid = false;
         break;
     case LinkParameterCrossOrigin:
-        m_crossOrigin = value;
+        m_crossOrigin = WTFMove(value);
         break;
     case LinkParameterAs:
-        m_as = value;
+        m_as = WTFMove(value);
         break;
     case LinkParameterType:
-        m_mimeType = value;
+        m_mimeType = WTFMove(value);
         break;
     case LinkParameterMedia:
-        m_media = value;
+        m_media = WTFMove(value);
+        break;
+    case LinkParameterImageSrcSet:
+        m_imageSrcSet = WTFMove(value);
+        break;
+    case LinkParameterImageSizes:
+        m_imageSizes = WTFMove(value);
         break;
     case LinkParameterTitle:
     case LinkParameterRev:
@@ -336,7 +346,7 @@
             return;
         }
 
-        setValue(parameterName, parameterValue);
+        setValue(parameterName, WTFMove(parameterValue));
     }
     findNextHeader(position, end);
 }
diff --git a/Source/WebCore/loader/LinkHeader.h b/Source/WebCore/loader/LinkHeader.h
index 8e35474..467088b 100644
--- a/Source/WebCore/loader/LinkHeader.h
+++ b/Source/WebCore/loader/LinkHeader.h
@@ -41,7 +41,10 @@
     const String& mimeType() const { return m_mimeType; }
     const String& media() const { return m_media; }
     const String& crossOrigin() const { return m_crossOrigin; }
+    const String& imageSrcSet() const { return m_imageSrcSet; }
+    const String& imageSizes() const { return m_imageSizes; }
     bool valid() const { return m_isValid; }
+    bool isViewportDependent() const { return !media().isEmpty() || !imageSrcSet().isEmpty() || !imageSizes().isEmpty(); }
 
     enum LinkParameterName {
         LinkParameterRel,
@@ -55,10 +58,12 @@
         LinkParameterUnknown,
         LinkParameterCrossOrigin,
         LinkParameterAs,
+        LinkParameterImageSrcSet,
+        LinkParameterImageSizes,
     };
 
 private:
-    void setValue(LinkParameterName, String value);
+    void setValue(LinkParameterName, String&& value);
 
     String m_url;
     String m_rel;
@@ -66,6 +71,8 @@
     String m_mimeType;
     String m_media;
     String m_crossOrigin;
+    String m_imageSrcSet;
+    String m_imageSizes;
     bool m_isValid { true };
 };
 
diff --git a/Source/WebCore/loader/LinkLoader.cpp b/Source/WebCore/loader/LinkLoader.cpp
index 2cd76f9..32745d4 100644
--- a/Source/WebCore/loader/LinkLoader.cpp
+++ b/Source/WebCore/loader/LinkLoader.cpp
@@ -44,16 +44,19 @@
 #include "FrameLoader.h"
 #include "FrameLoaderClient.h"
 #include "FrameView.h"
+#include "HTMLSrcsetParser.h"
 #include "LinkHeader.h"
 #include "LinkPreloadResourceClients.h"
 #include "LinkRelAttribute.h"
 #include "LoaderStrategy.h"
 #include "MIMETypeRegistry.h"
+#include "MediaList.h"
 #include "MediaQueryEvaluator.h"
 #include "PlatformStrategies.h"
 #include "ResourceError.h"
 #include "RuntimeEnabledFeatures.h"
 #include "Settings.h"
+#include "SizesAttributeParser.h"
 #include "StyleResolver.h"
 
 namespace WebCore {
@@ -97,8 +100,8 @@
     for (auto& header : headerSet) {
         if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty())
             continue;
-        if ((mediaAttributeCheck == MediaAttributeCheck::MediaAttributeNotEmpty && header.media().isEmpty())
-            || (mediaAttributeCheck == MediaAttributeCheck::MediaAttributeEmpty && !header.media().isEmpty())) {
+        if ((mediaAttributeCheck == MediaAttributeCheck::MediaAttributeNotEmpty && !header.isViewportDependent())
+            || (mediaAttributeCheck == MediaAttributeCheck::MediaAttributeEmpty && header.isViewportDependent())) {
                 continue;
         }
 
@@ -108,7 +111,7 @@
         if (equalIgnoringFragmentIdentifier(url, baseURL))
             continue;
         preconnectIfNeeded(relAttribute, url, document, header.crossOrigin());
-        preloadIfNeeded(relAttribute, url, document, header.as(), header.media(), header.mimeType(), header.crossOrigin(), nullptr);
+        preloadIfNeeded(relAttribute, url, document, header.as(), header.media(), header.mimeType(), header.crossOrigin(), header.imageSrcSet(), header.imageSizes(), nullptr);
     }
 }
 
@@ -227,28 +230,39 @@
     });
 }
 
-std::unique_ptr<LinkPreloadResourceClient> LinkLoader::preloadIfNeeded(const LinkRelAttribute& relAttribute, const URL& href, Document& document, const String& as, const String& media, const String& mimeType, const String& crossOriginMode, LinkLoader* loader)
+std::unique_ptr<LinkPreloadResourceClient> LinkLoader::preloadIfNeeded(const LinkRelAttribute& relAttribute, const URL& href, Document& document, const String& as, const String& media, const String& mimeType, const String& crossOriginMode, const String& imageSrcSet, const String& imageSizes, LinkLoader* loader)
 {
     if (!document.loader() || !relAttribute.isLinkPreload)
         return nullptr;
 
     ASSERT(RuntimeEnabledFeatures::sharedFeatures().linkPreloadEnabled());
-    if (!href.isValid()) {
-        document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> has an invalid `href` value"_s);
-        return nullptr;
-    }
     auto type = LinkLoader::resourceTypeFromAsAttribute(as);
     if (!type) {
         document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> must have a valid `as` value"_s);
         return nullptr;
     }
+    URL url;
+    if (type == CachedResource::Type::ImageResource && !imageSrcSet.isEmpty()) {
+        auto sourceSize = SizesAttributeParser(imageSizes, document).length();
+        auto candidate = bestFitSourceForImageAttributes(document.deviceScaleFactor(), href.string(), imageSrcSet, sourceSize);
+        url = document.completeURL(URL({ }, candidate.string.toString()));
+    } else
+        url = document.completeURL(href);
+
+    if (!url.isValid()) {
+        if (imageSrcSet.isEmpty())
+            document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> has an invalid `href` value"_s);
+        else
+            document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> has an invalid `imagesrcset` value"_s);
+        return nullptr;
+    }
     if (!MediaQueryEvaluator::mediaAttributeMatches(document, media))
         return nullptr;
     if (!isSupportedType(type.value(), mimeType))
         return nullptr;
 
     auto options = CachedResourceLoader::defaultCachedResourceOptions();
-    auto linkRequest = createPotentialAccessControlRequest(document.completeURL(href), document, crossOriginMode, WTFMove(options));
+    auto linkRequest = createPotentialAccessControlRequest(url, document, crossOriginMode, WTFMove(options));
     linkRequest.setPriority(CachedResource::defaultPriorityForResourceType(type.value()));
     linkRequest.setInitiator("link");
     linkRequest.setIgnoreForRequestCount(true);
@@ -299,7 +313,7 @@
         m_preloadResourceClient->clear();
 }
 
-bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, const URL& href, const String& as, const String& media, const String& mimeType, const String& crossOrigin, Document& document)
+bool LinkLoader::loadLink(const LinkRelAttribute& relAttribute, const URL& href, const String& as, const String& media, const String& mimeType, const String& crossOrigin, const String& imageSrcSet, const String& imageSizes, Document& document)
 {
     if (relAttribute.isDNSPrefetch) {
         // FIXME: The href attribute of the link element can be in "//hostname" form, and we shouldn't attempt
@@ -311,7 +325,7 @@
     preconnectIfNeeded(relAttribute, href, document, crossOrigin);
 
     if (m_client.shouldLoadLink()) {
-        auto resourceClient = preloadIfNeeded(relAttribute, href, document, as, media, mimeType, crossOrigin, this);
+        auto resourceClient = preloadIfNeeded(relAttribute, href, document, as, media, mimeType, crossOrigin, imageSrcSet, imageSizes, this);
         if (m_preloadResourceClient)
             m_preloadResourceClient->clear();
         if (resourceClient)
diff --git a/Source/WebCore/loader/LinkLoader.h b/Source/WebCore/loader/LinkLoader.h
index 78606c2..c180a160 100644
--- a/Source/WebCore/loader/LinkLoader.h
+++ b/Source/WebCore/loader/LinkLoader.h
@@ -50,7 +50,7 @@
     explicit LinkLoader(LinkLoaderClient&);
     virtual ~LinkLoader();
 
-    bool loadLink(const LinkRelAttribute&, const URL&, const String& as, const String& media, const String& type, const String& crossOrigin, Document&);
+    bool loadLink(const LinkRelAttribute&, const URL&, const String& as, const String& media, const String& type, const String& crossOrigin, const String& imageSrcSet, const String& imageSizes, Document&);
     static Optional<CachedResource::Type> resourceTypeFromAsAttribute(const String& as);
 
     enum class MediaAttributeCheck { MediaAttributeEmpty, MediaAttributeNotEmpty, SkipMediaAttributeCheck };
@@ -63,7 +63,7 @@
 private:
     void notifyFinished(CachedResource&) override;
     static void preconnectIfNeeded(const LinkRelAttribute&, const URL& href, Document&, const String& crossOrigin);
-    static std::unique_ptr<LinkPreloadResourceClient> preloadIfNeeded(const LinkRelAttribute&, const URL& href, Document&, const String& as, const String& media, const String& type, const String& crossOriginMode, LinkLoader*);
+    static std::unique_ptr<LinkPreloadResourceClient> preloadIfNeeded(const LinkRelAttribute&, const URL& href, Document&, const String& as, const String& media, const String& type, const String& crossOriginMode, const String&, const String&, LinkLoader*);
     void prefetchIfNeeded(const LinkRelAttribute&, const URL& href, Document&);
 
     LinkLoaderClient& m_client;