Update web-platform-tests to revision b'aa0081aeb91d3890fbc8e21ccda3ab61ccd099fa'

Signed-off-by: WPT Sync Bot <ghbot+wpt-sync@servo.org>
This commit is contained in:
Servo WPT Sync
2025-03-23 13:05:37 +00:00
committed by WPT Sync Bot
parent 8b8b447ef0
commit 347c581a84
404 changed files with 11108 additions and 2362 deletions

View File

@@ -5,9 +5,6 @@
[Revoke blob URL after creating Request, then clone Request, will fetch]
expected: FAIL
[Revoke blob URL after calling fetch, fetch should succeed]
expected: FAIL
[url-with-fetch.any.worker.html]
[Revoke blob URL after creating Request, will fetch]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
[root-element-background-margin-opacity.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[animate-with-background-color-oklch-001.html]
expected: TIMEOUT

View File

@@ -0,0 +1,6 @@
[animate-with-background-color-oklch-002.html]
[Animate from legacy rgb to oklch]
expected: FAIL
[Animate from legacy rgb to color-mix oklch]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[chrome-bug-404743651.html]
expected: TIMEOUT

View File

@@ -27,3 +27,48 @@
[corner-shape-any.html?corner-shape=squircle&border-top-right-radius=30px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=superellipse(0.2)&border-radius=40px]
expected: FAIL
[corner-shape-any.html?corner-shape=squircle&border-radius=25%&border-width=20px]
expected: FAIL
[corner-shape-any.html?corner-top-right-shape=bevel&border-width=10px&border-color=black]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=bevel&border-radius=40px]
expected: FAIL
[corner-shape-any.html?corner-bottom-right-shape=bevel&border-width=10px&border-radius=20px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=scoop&border-radius=40px]
expected: FAIL
[corner-shape-any.html?corner-bottom-left-shape=bevel&border-width=10px&border-radius=20px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=superellipse(6)&border-radius=20%&border-width=10px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=bevel&border-radius=40px&border-width=10px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=superellipse(0.3)&border-radius=40%]
expected: FAIL
[corner-shape-any.html?corner-shape=squircle&border-top-left-radius=25%&border-width=10px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=superellipse(0.8)&border-radius=40px]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=superellipse(1.2)&border-radius=40px]
expected: FAIL
[corner-shape-any.html?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel]
expected: FAIL
[corner-shape-any.html?corner-top-left-shape=bevel&border-width=10px&border-color=black]
expected: FAIL

View File

@@ -1,26 +0,0 @@
[corner-shape-render.html?corner-bottom-left-shape=bevel]
expected: FAIL
[corner-shape-render.html?corner-top-left-shape=bevel]
expected: FAIL
[corner-shape-render.html?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel]
expected: FAIL
[corner-shape-render.html?corner-bottom-right-shape=bevel]
expected: FAIL
[corner-shape-render.html?corner-top-right-shape=bevel&corner-bottom-right-shape=bevel&border-radius=80px]
expected: FAIL
[corner-shape-render.html?corner-top-right-shape=bevel&corner-bottom-right-shape=bevel&border-bottom-right-radius=80px&border-width=32px]
expected: FAIL
[corner-shape-render.html?corner-top-left-shape=bevel&border-radius=40px]
expected: FAIL
[corner-shape-render.html?corner-shape=bevel]
expected: FAIL
[corner-shape-render.html?corner-top-right-shape=bevel]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[at-supports-selector-details-content-before.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[at-supports-selector-details-content.html]
expected: FAIL

View File

@@ -0,0 +1,15 @@
[CSS-supports-details-content-pseudo-parsing.html]
[selector() function accepts ::details-content]
expected: FAIL
[selector() function accepts ::details-content followed by ::before]
expected: FAIL
[selector() function accepts ::details-content followed by ::first-line]
expected: FAIL
[selector() function accepts ::details-content followed by a state pseudo-class]
expected: FAIL
[selector() function accepts ::details-content followed by :lang()]
expected: FAIL

View File

@@ -0,0 +1,12 @@
[flex-shorthand-calc.html]
[e.style['flex'\] = "sign(1em - 1px) sibling-index()" should set flex-basis]
expected: FAIL
[e.style['flex'\] = "sign(1em - 1px) sibling-index()" should set flex-grow]
expected: FAIL
[e.style['flex'\] = "sign(1em - 1px) sibling-index()" should set flex-shrink]
expected: FAIL
[e.style['flex'\] = "sign(1em - 1px) sibling-index()" should not set unrelated longhands]
expected: FAIL

View File

@@ -0,0 +1,6 @@
[flex-computed.html]
[Property flex value 'calc(10 + (sign(20cqw - 10px) * 5)) calc(10 + (sign(20cqw - 10px) * 5)) 1px']
expected: FAIL
[Property flex value '1 1 calc(10px + (sign(20cqw - 10px) * 5px))']
expected: FAIL

View File

@@ -0,0 +1,6 @@
[flex-valid.html]
[e.style['flex'\] = "calc(10 + (sign(20cqw - 10px) * 5)) calc(10 + (sign(20cqw - 10px) * 5)) 1px" should set the property value]
expected: FAIL
[e.style['flex'\] = "1 1 calc(10px + (sign(20cqw - 10px) * 5px))" should set the property value]
expected: FAIL

View File

@@ -1,2 +0,0 @@
[font-synthesis-08.html]
expected: FAIL

View File

@@ -0,0 +1,12 @@
[font-variation-settings-calc.html]
[e.style['font-variation-settings'\] = "\\"wght\\" sign(1em - 1px)" should set the property value]
expected: FAIL
[e.style['font-variation-settings'\] = "\\"wght\\" sibling-index()" should set the property value]
expected: FAIL
[Property font-variation-settings value '"wght" sign(1em - 1px)']
expected: FAIL
[Property font-variation-settings value '"wght" sibling-index()']
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-006.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-007.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-008.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-009.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-010.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-011.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-012.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-013.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-014.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[grid-gap-decorations-015.html]
expected: FAIL

View File

@@ -1,2 +0,0 @@
[masonry-order-002.html]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[grid-area-computed.html]
[Property grid-row-start value 'calc(10 + (sign(2cqw - 10px) * 5)) -a-']
expected: FAIL

View File

@@ -0,0 +1,2 @@
[conic-gradient-001.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[gradient-analogous-missing-components-004.html]
expected: FAIL

View File

@@ -0,0 +1,6 @@
[scroll-marker-15.html]
[::scroll-marker is not activated when its originating element is not scrolled into the view]
expected: FAIL
[::scroll-marker is activated when its originating element is scrolled into the view]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[scroll-marker-contain-001.tentative.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[scroll-marker-contain-002.tentative.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[scroll-marker-contain-003.tentative.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[scroll-marker-contain-004.tentative.html]
expected: FAIL

View File

@@ -1,2 +0,0 @@
[replaced-element-013.html]
expected: FAIL

View File

@@ -1,2 +0,0 @@
[replaced-element-014.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[table-cell-overflow-auto-scrolled.html]
expected: FAIL

View File

@@ -0,0 +1,6 @@
[cursor-calc-hotspot.html]
[cursor hotspot with sign() depending on font relative units]
expected: FAIL
[cursor hotspot depending on sibling-index()]
expected: FAIL

View File

@@ -0,0 +1,27 @@
[calc-complex-unresolved-serialize.html]
['calc(pow(2, sign(1em - 18px)))' as a computed value should serialize as '2'.]
expected: FAIL
['calc(pow(sign(1em - 18px), 2))' as a computed value should serialize as '1'.]
expected: FAIL
['calc(pow(sign(1em - 18px), sign(1em - 18px)))' as a computed value should serialize as '1'.]
expected: FAIL
['calc(pow(2, sibling-index())' as a specified value should serialize as 'calc(pow(2, sibling-index()))'.]
expected: FAIL
['calc(pow(2, sibling-index())' as a computed value should serialize as '2'.]
expected: FAIL
['calc(pow(sibling-index(), 2)' as a specified value should serialize as 'calc(pow(sibling-index(), 2))'.]
expected: FAIL
['calc(pow(sibling-index(), 2)' as a computed value should serialize as '1'.]
expected: FAIL
['calc(pow(sibling-index(), sibling-index())' as a specified value should serialize as 'calc(pow(sibling-index(), sibling-index()))'.]
expected: FAIL
['calc(pow(sibling-index(), sibling-index())' as a computed value should serialize as '1'.]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[feComposite-intersection-feTile-input.html]
expected: FAIL

View File

@@ -47,9 +47,6 @@
[sec-fetch-user]
expected: FAIL
[sec-fetch-dest]
expected: FAIL
[sec-fetch-storage-access - Same site]
expected: FAIL

View File

@@ -0,0 +1,6 @@
[empty-iframe-load-event.html]
[Check execution order from nested timeout]
expected: FAIL
[Check execution order on load handler]
expected: FAIL

View File

@@ -1,5 +1,5 @@
[createImageBitmap-transfer.html]
expected: ERROR
expected: TIMEOUT
[Transfer ImageBitmap created from a vector HTMLImageElement]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.disconnected.html]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[2d.text.measure.lang.html]
[Testing the lang attribute]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[2d.text.measure.lang.inherit.html]
[Testing the lang attribute]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.offscreen.lang.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.offscreen.lang.inherit.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.offscreen.transferred.lang.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.offscreen.transferred.lang.inherit.document.html]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[canvas.2d.offscreen.transferred.lang.inherit.html]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[2d.text.measure.lang.html]
[Testing the lang attribute]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[2d.text.measure.lang.inherit.html]
[Testing the lang attribute]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[2d.text.measure.lang.worker.html]
[Testing the lang attribute]
expected: FAIL

View File

@@ -0,0 +1,9 @@
[nameditem-01.html]
[img elements that have a name and id attribute with same value.]
expected: FAIL
[Dynamically updating the name attribute from img elements, should be accessible by values.]
expected: FAIL
[Dynamically updating the id attribute from img elements, should be accessible by values.]
expected: FAIL

View File

@@ -13,3 +13,15 @@
[An id shouldn't affect getting an embed by name]
expected: FAIL
[Dynamically removing the name attribute from embed elements, should not be accessible.]
expected: FAIL
[Dynamically updating the name attribute from embed elements, should be accessible by its name.]
expected: FAIL
[Dynamically updating the id attribute from embed elements, should be accessible only by its name.]
expected: FAIL
[embed elements that is removed, should not be accessible.]
expected: FAIL

View File

@@ -22,3 +22,18 @@
[An id shouldn't affect getting an object by name]
expected: FAIL
[Dynamically removing the name attribute from object elements, should not be accessible.]
expected: FAIL
[Dynamically removing the id attribute from object elements, should not be accessible.]
expected: FAIL
[Dynamically updating the name attribute from object elements, should be accessible by its name and id.]
expected: FAIL
[Dynamically updating the id attribute from object elements, should be accessible by its name and id.]
expected: FAIL
[object elements that is removed, should not be accessible.]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[element-render-blocking-040.html]
[blocking defers frames until full parsing]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[element-render-blocking-041.html]
[blocking defers frames until full parsing]
expected: FAIL

View File

@@ -1,12 +0,0 @@
[structured-cloning-error-stack-optional.sub.window.html]
[web API-created TypeError (structuredClone())]
expected: FAIL
[web API-created TypeError (worker)]
expected: FAIL
[web API-created TypeError (cross-site iframe)]
expected: FAIL
[web API-created TypeError (same-origin iframe)]
expected: FAIL

View File

@@ -0,0 +1,2 @@
[option-label-whitespace-2.html]
expected: FAIL

View File

@@ -1,2 +0,0 @@
[field-sizing-textarea-relayout.html]
expected: FAIL

View File

@@ -0,0 +1,4 @@
[currentTime.html]
expected: TIMEOUT
[setting currentTime when readyState is greater than HAVE_NOTHING]
expected: TIMEOUT

View File

@@ -1,3 +1,4 @@
[iframe_sandbox_popups_escaping-2.html]
expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT

View File

@@ -1,4 +1,4 @@
[iframe_sandbox_popups_escaping-3.html]
expected: TIMEOUT
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT
expected: FAIL

View File

@@ -1,4 +1,4 @@
[iframe_sandbox_popups_nonescaping-2.html]
expected: TIMEOUT
expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN

View File

@@ -1,4 +1,3 @@
[iframe_sandbox_popups_nonescaping-3.html]
expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN
expected: FAIL

View File

@@ -1,2 +0,0 @@
[image-loading-lazy-subframe-detached-crash.html]
expected: TIMEOUT

View File

@@ -1,4 +1,5 @@
[audio-tag.https.html]
expected: TIMEOUT
[Mixed-Content: Expects blocked for audio-tag to cross-http origin and keep-scheme redirection from https context.]
expected: FAIL
@@ -12,13 +13,13 @@
expected: FAIL
[Mixed-Content: Expects blocked for audio-tag to same-http origin and keep-scheme redirection from https context.]
expected: FAIL
expected: NOTRUN
[Mixed-Content: Expects blocked for audio-tag to same-http origin and no-redirect redirection from https context.]
expected: FAIL
expected: NOTRUN
[Mixed-Content: Expects blocked for audio-tag to same-http origin and swap-scheme redirection from https context.]
expected: FAIL
expected: NOTRUN
[Mixed-Content: Expects blocked for audio-tag to same-https origin and swap-scheme redirection from https context.]
expected: FAIL
expected: NOTRUN

View File

@@ -10,3 +10,12 @@
[ed25519-xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE= malformed-thing ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=]
expected: FAIL
[ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs= ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=]
expected: FAIL
[ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs= ed25519-xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE=]
expected: FAIL
[ed25519-JrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs= malformed-thing ed25519-xDnP380zcL4rJ76rXYjeHlfMyPZEOqpJYjsjEppbuXE=]
expected: FAIL

View File

@@ -123,4 +123,4 @@
expected: ERROR
[type.tentative.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
expected: TIMEOUT

View File

@@ -18,7 +18,7 @@
expected: ERROR
[valueOf.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
expected: TIMEOUT
[valueOf.any.shadowrealm-in-shadowrealm.html]
expected: ERROR

View File

@@ -54,7 +54,7 @@
expected: ERROR
[type.tentative.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
expected: TIMEOUT
[type.tentative.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR

View File

@@ -26,7 +26,7 @@ jobs:
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
# Based on https://docs.github.com/en/actions/publishing-packages/publishing-docker-images.
- name: Log in to the Container registry
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -31,6 +31,12 @@ promise_test(async t => {
await promise_rejects_dom(t, 'AbortError', createPromise);
}, 'AILanguageDetectorFactory.create() call with an aborted signal.');
promise_test(async t => {
await testAbortPromise(t, signal => {
return ai.languageDetector.create({signal});
});
}, 'Aborting AILanguageDetectorFactory.create().');
promise_test(async t => {
const controller = new AbortController();
controller.abort();

View File

@@ -60,7 +60,7 @@ promise_test(async t => {
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
assert_equals(translator.sourceLanguage, 'en');
assert_equals(translator.targetLanguage, 'ja');
}, 'AITranslator: sourceLanguage and targetLanguage are equal to their respective option passed in to AITranslatorFactory.create.')
}, 'AITranslator: sourceLanguage and targetLanguage are equal to their respective option passed in to AITranslatorFactory.create.');
promise_test(async (t) => {
const translator =
@@ -109,16 +109,22 @@ promise_test(async t => {
promise_test(async t => {
let monitorCalled = false;
let createdTranslator = false;
const progressEvents = [];
function monitor(m) {
monitorCalled = true;
m.addEventListener('downloadprogress', e => {
// No progress events should have been fired after we've created the
// translator.
assert_false(createdTranslator);
progressEvents.push(e);
});
}
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja', monitor});
createdTranslator = true;
// Monitor callback must be called.
assert_true(monitorCalled);
@@ -166,3 +172,41 @@ promise_test(async t => {
assert_not_equals(translatedTranslatableString[i], translatableStrings[i]);
}
}, 'AITranslator.translate() echos non-translatable content');
promise_test(async t => {
const translator =
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
const text = 'hello';
const inputUsage = await translator.measureInputUsage(text);
assert_greater_than_equal(translator.inputQuota, 0);
assert_greater_than_equal(inputUsage, 0);
if (inputUsage < translator.inputQuota) {
assert_equals(await translator.translate(text), 'こんにちは');
} else {
await promise_rejects_dom(
t, 'QuotaExceededError', translator.translate(text));
}
}, 'AITranslator.measureInputUsage() and inputQuota basic usage.');
promise_test(async t => {
const controller = new AbortController();
controller.abort();
const translator =
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
const measureInputUsagePromise =
translator.measureInputUsage('hello', {signal: controller.signal});
await promise_rejects_dom(t, 'AbortError', measureInputUsagePromise);
}, 'AITranslator.measureInputUsage() call with an aborted signal.');
promise_test(async t => {
const translator =
await createTranslator({sourceLanguage: 'en', targetLanguage: 'ja'});
await testAbortPromise(t, signal => {
return translator.measureInputUsage('hello', {signal});
});
}, 'Aborting AITranslator.measureInputUsage().');

View File

@@ -0,0 +1,149 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="support/clear-cache-helper.sub.js"></script>
<script>
"use strict";
const CLEAR_ORIGIN_CACHE = {
clear: "cache",
}
promise_test(test => {
const TEST_SITE = {
iframe: {
cache: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_not_equals);
}, "same site data also gets cleared in iframe");
promise_test(test => {
const TEST_SITE = {
iframe: {
cache: true,
secondOrigin: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "cross origin iframe data doesn't get cleared");
promise_test(test => {
const TEST_SITE = {
cache: true,
}
const CLEAR_ORIGIN_CACHE = {
iframe: {
clear: "cache",
secondOrigin: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clear in cross origin iframe doesn't affect embedder");
promise_test(test => {
const TEST_SITE = {
cache: true,
subdomain: true,
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clearing cache doesn't affect subdomain");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
cache: true,
}
}
const TEST_SITE_CLEAR_IFRAME = {
iframe: {
secondOrigin: true,
clear: "all",
}
}
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_not_equals);
}, "clear in cross origin iframe clears data from that iframe");
promise_test(test => {
const TEST_SITE = {
cache: true
};
const TEST_SITE_CLEAR_IFRAME = {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_equals);
}, "clear in cross origin iframe doesn't clear unpartitioned data from that cross origin");
promise_test(test => {
const TEST_SITE = {
secondOrigin: true,
iframe: {
cache: true,
}
}
const TEST_SITE_CLEAR_IFRAME = {
clear: "cache"
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_equals);
}, "clear in unpartitioned context doesn't clear partitioned data");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
iframe: {
cache: true,
}
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clear in unpartitioned context doesn't clear double partitioned data with intermediate cross origin");
promise_test(test => {
const TEST_SITE = {
cache: true,
};
const TEST_CLEAR_IFRAME_IFRAME = {
iframe: {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
}
return testCacheClear(test, [TEST_SITE, TEST_CLEAR_IFRAME_IFRAME, TEST_SITE], assert_equals);
}, "clear in double partitioned with intermediate cross origin context doesn't clear unpartitioned data");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
iframe: {
cache: true,
}
}
}
const TEST_CLEAR_IFRAME_IFRAME = {
iframe: {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
}
return testCacheClear(test, [TEST_SITE, TEST_CLEAR_IFRAME_IFRAME, TEST_SITE], assert_not_equals);
}, "clear double partitioned context with intermediate cross origin clears that partitioned data");
</script>
</body>
</html>

View File

@@ -4,100 +4,111 @@
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="support/clear-cache-helper.sub.js"></script>
<script>
// Here's the set-up for this test:
// Step 1 (main window) Open first window with first url putting some resource
// into the cache and maybe receiving clear-site-data header
// Step 2 (first window) Message main window with uuid
// Step 3 (main window) Open second window with second url
// Step 4 (second window) Message main window with uuid (either cached or non-cached)
// Optional Step 5 (main window) Open third window with third url
// Optional Step 6 (third window) Message main window with uuid (either cached or non-cached)
// Step 7 (main window): Assert first and last uuid not equal due to `clear-site-data: "cache"` header
function test_cache_clear(test, params1, params2, params3) {
let cache_helper = "cache_helper=" + self.crypto.randomUUID() + "&";
let firstUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params1
let secondUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params2;
let thirdUrl = params3 ? "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params3 : null;
return new Promise(resolve => {
window.addEventListener("message", test.step_func(e => {
// Result Step 2
let firstUuid = e.data;
window.addEventListener("message", test.step_func(e => {
// Result Step 4
let secondUuid = e.data;
if (thirdUrl === null) {
// Step 7, skipping the optional step 5 and 6
assert_not_equals(firstUuid, secondUuid);
resolve();
} else {
window.addEventListener("message", test.step_func(e => {
// Result Step 6
let thirdUuid = e.data;
// Step 7
assert_not_equals(firstUuid, thirdUuid);
resolve();
}), {once: true});
// Step 5
window.open(thirdUrl);
}
}), {once: true});
// Step 3
window.open(secondUrl);
}), {once: true});
// Step 1
window.open(firstUrl);
});
}
promise_test(t => {
return test_cache_clear(t, "response=single_html&cache&clear_first=cache", "response=single_html&cache&clear_first=cache");
promise_test(test => {
const TEST_SITE = {
cache: true,
clearFirst: "cache",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE], assert_not_equals);
}, "clear cache: Document with clear-cache header doesn't get cached");
promise_test(t => {
return test_cache_clear(t, "response=single_html&cache&clear_first=all", "response=single_html&cache&clear_first=all");
promise_test(test => {
const TEST_SITE = {
cache: true,
clearFirst: "all",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE], assert_not_equals);
}, "clear all: Document with clear-cache header doesn't get cached");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json&clear=cache", "response=html_embed_json&clear=cache");
}, "clear cache: Fetch on docment with clear-cache header doesn't get cached");
promise_test(test => {
const TEST_SITE_INITAL = {
response: "html_embed_json",
clear: "cache",
};
const TEST_SITE_FINAL = {
response: "html_embed_json",
};
// Clear-Cache header doesn't affect fetch on document due to clear-cache
// being initiated in a point of time. The fetch happens later and stays
// in the cache.
return testCacheClear(test, [TEST_SITE_INITAL, TEST_SITE_FINAL], assert_equals);
}, "clear cache: Fetch on docment with clear-cache header is unaffected");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json&clear=all", "response=html_embed_json&clear=all");
}, "clear all: Fetch on docment with clear-cache header doesn't get cached");
promise_test(test => {
const TEST_SITE_INITAL = {
response: "html_embed_json",
clear: "all",
};
const TEST_SITE_FINAL = {
response: "html_embed_json",
};
// same as above
return testCacheClear(test, [TEST_SITE_INITAL, TEST_SITE_FINAL], assert_equals);
}, "clear all: Fetch on docment with clear-cache header is unaffected");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=cache");
promise_test(test => {
const TEST_SITE_INITAL = {
response: "html_embed_json",
};
const TEST_SITE_FINAL = {
response: "html_embed_json",
clear: "cache",
};
return testCacheClear(test, [TEST_SITE_INITAL, TEST_SITE_FINAL], assert_not_equals);
}, "clear cache: Previously cached fetch gets cleared");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=all");
promise_test(test => {
const TEST_SITE_INITAL = {
response: "html_embed_json",
};
const TEST_SITE_FINAL = {
response: "html_embed_json",
clear: "all",
};
return testCacheClear(test, [TEST_SITE_INITAL, TEST_SITE_FINAL], assert_not_equals);
}, "clear all: Previously cached fetch gets cleared");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=cache", "response=html_embed_json");
promise_test(test => {
const TEST_SITE = {
response: "html_embed_json",
};
const TEST_SITE_CLEAR = {
clear: "cache",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR, TEST_SITE], assert_not_equals);
}, "clear cache: Clear fetch on intermediate navigation");
promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=all", "response=html_embed_json");
promise_test(test => {
const TEST_SITE = {
response: "html_embed_json",
};
const TEST_SITE_CLEAR = {
clear: "all",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR, TEST_SITE], assert_not_equals);
}, "clear all: Clear fetch on intermediate navigation");
promise_test(t => {
return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=cache", "response=single_html&cache");
promise_test(test => {
const TEST_SITE = {
cache: true,
};
const TEST_SITE_CLEAR = {
clear: "cache",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR, TEST_SITE], assert_not_equals);
}, "clear cache: Clear document in intermediate load");
promise_test(t => {
return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=all", "response=single_html&cache");
promise_test(test => {
const TEST_SITE = {
cache: true,
};
const TEST_SITE_CLEAR = {
clear: "all",
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR, TEST_SITE], assert_not_equals);
}, "clear all: Clear document in intermediate load");
</script>

View File

@@ -1,10 +1,7 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script>
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict"
/**
* Constructs a url for an intermediate "bounce" hop which represents a tracker.
@@ -18,7 +15,10 @@
* Clear-Site-Data header.
* @param {(null|'cache'|'all')} [options.clear_first] - whether to send the
* Clear-Site-Data header on first response
* @param {*} [options.iframe] - iframe same parameters as options (recursive)
* @param {string} [response] - which response to elict - defaults to "single_html". Other
* options can be found in "clear-site-data-cache.py" server helper.
* @param {*} [options.iframe] - iframe same parameters as options (recursive). Only works on
* "single_html" variation of response
*/
function getUrl(cacheHelper, {
subdomain = false,
@@ -26,6 +26,7 @@ function getUrl(cacheHelper, {
cache = false,
clear = null,
clearFirst = null,
response = "single_html",
iframe = null,
}) {
let url = "https://";
@@ -43,7 +44,7 @@ function getUrl(cacheHelper, {
url = new URL(url);
let params = new URLSearchParams();
params.append("cache_helper", cacheHelper);
params.append("response", "single_html")
params.append("response", response)
if (clear !== null) {
params.append("clear", clear);
}
@@ -130,142 +131,3 @@ function testCacheClear(test, params, assert) {
});
}
const CLEAR_ORIGIN_CACHE = {
clear: "cache",
}
promise_test(test => {
const TEST_SITE = {
iframe: {
cache: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_not_equals);
}, "same site data also gets cleared in iframe");
promise_test(test => {
const TEST_SITE = {
iframe: {
cache: true,
secondOrigin: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "cross origin iframe data doesn't get cleared");
promise_test(test => {
const TEST_SITE = {
cache: true,
}
const CLEAR_ORIGIN_CACHE = {
iframe: {
clear: "cache",
secondOrigin: true,
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clear in cross origin iframe doesn't affect embedder");
promise_test(test => {
const TEST_SITE = {
cache: true,
subdomain: true,
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clearing cache doesn't affect subdomain");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
cache: true,
}
}
const TEST_SITE_CLEAR_IFRAME = {
iframe: {
secondOrigin: true,
clear: "all",
}
}
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_not_equals);
}, "clear in cross origin iframe clears data from that iframe");
promise_test(test => {
const TEST_SITE = {
cache: true
};
const TEST_SITE_CLEAR_IFRAME = {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_equals);
}, "clear in cross origin iframe doesn't clear unpartitioned data from that cross origin");
promise_test(test => {
const TEST_SITE = {
secondOrigin: true,
iframe: {
cache: true,
}
}
const TEST_SITE_CLEAR_IFRAME = {
clear: "cache"
};
return testCacheClear(test, [TEST_SITE, TEST_SITE_CLEAR_IFRAME, TEST_SITE], assert_equals);
}, "clear in unpartitioned context doesn't clear partitioned data");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
iframe: {
cache: true,
}
}
}
return testCacheClear(test, [TEST_SITE, CLEAR_ORIGIN_CACHE, TEST_SITE], assert_equals);
}, "clear in unpartitioned context doesn't clear double partitioned data with intermediate cross origin");
promise_test(test => {
const TEST_SITE = {
cache: true,
};
const TEST_CLEAR_IFRAME_IFRAME = {
iframe: {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
}
return testCacheClear(test, [TEST_SITE, TEST_CLEAR_IFRAME_IFRAME, TEST_SITE], assert_equals);
}, "clear in double partitioned with intermediate cross origin context doesn't clear unpartitioned data");
promise_test(test => {
const TEST_SITE = {
iframe: {
secondOrigin: true,
iframe: {
cache: true,
}
}
}
const TEST_CLEAR_IFRAME_IFRAME = {
iframe: {
secondOrigin: true,
iframe: {
clear: "cache",
}
}
}
return testCacheClear(test, [TEST_SITE, TEST_CLEAR_IFRAME_IFRAME, TEST_SITE], assert_not_equals);
}, "clear double partitioned context with intermediate cross origin clears that partitioned data");
</script>
</body>
</html>

View File

@@ -0,0 +1,3 @@
<!DOCTYPE html>
<div style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px;
background: green; opacity: 0.5"></div>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<link rel="help" href="https://www.w3.org/TR/compositing-1/#pagebackdrop">
<link rel="help" href="https://crbug.com/40904650">
<link rel="match" href="root-element-background-margin-opacity-ref.html">
<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-10000">
<style>
html {
margin: 100px;
width: 100px;
height: 100px;
background: linear-gradient(green, green) top left no-repeat;
opacity: 0.5;
}
</style>

View File

@@ -59,7 +59,7 @@
<div class="container">
<div class="anchor"></div>
<div class="target" style="right: 20px;" data-expected-width="80" data-offset-x="20"></div>
<div class="target" style="right: 20px;" data-expected-width="80" data-offset-x="0"></div>
</div>
<div class="container">
@@ -80,7 +80,7 @@
<!-- both insets -->
<div class="container">
<div class="anchor"></div>
<div class="target" style="left: 10px; right: 20px;" data-expected-width="70" data-offset-x="30"></div>
<div class="target" style="left: 10px; right: 20px;" data-expected-width="70" data-offset-x="10"></div>
</div>
<div class="container">

View File

@@ -60,7 +60,7 @@
<div class="container">
<div class="anchor"></div>
<div class="target" style="bottom: 20px;" data-expected-height="80" data-offset-y="20"></div>
<div class="target" style="bottom: 20px;" data-expected-height="80" data-offset-y="0"></div>
</div>
<div class="container">
@@ -81,7 +81,7 @@
<!-- both insets -->
<div class="container">
<div class="anchor"></div>
<div class="target" style="top: 10px; bottom: 20px;" data-expected-height="70" data-offset-y="30"></div>
<div class="target" style="top: 10px; bottom: 20px;" data-expected-height="70" data-offset-y="10"></div>
</div>
<div class="container">

View File

@@ -61,7 +61,7 @@
<div class="container">
<div class="anchor"></div>
<div class="target" style="right: 20px;" data-expected-width="80" data-offset-x="20"></div>
<div class="target" style="right: 20px;" data-expected-width="80" data-offset-x="0"></div>
</div>
<div class="container">
@@ -82,7 +82,7 @@
<!-- both insets -->
<div class="container">
<div class="anchor"></div>
<div class="target" style="left: 10px; right: 20px;" data-expected-width="70" data-offset-x="30"></div>
<div class="target" style="left: 10px; right: 20px;" data-expected-width="70" data-offset-x="10"></div>
</div>
<div class="container">

View File

@@ -60,7 +60,7 @@
<div class="container">
<div class="anchor"></div>
<div class="target" style="bottom: 20px;" data-expected-height="80" data-offset-y="20"></div>
<div class="target" style="bottom: 20px;" data-expected-height="80" data-offset-y="0"></div>
</div>
<div class="container">
@@ -81,7 +81,7 @@
<!-- both insets -->
<div class="container">
<div class="anchor"></div>
<div class="target" style="top: 10px; bottom: 20px;" data-expected-height="70" data-offset-y="30"></div>
<div class="target" style="top: 10px; bottom: 20px;" data-expected-height="70" data-offset-y="10"></div>
</div>
<div class="container">

View File

@@ -8,6 +8,9 @@
position: relative;
width: 400px;
height: 400px;
margin: 0 auto;
border: 2px solid;
background: #eee;
}
#anchor {
position: absolute;
@@ -16,12 +19,15 @@
width: 100px;
height: 100px;
anchor-name: --anchor;
background: blue;
}
#anchored {
position: absolute;
align-self: stretch;
justify-self: stretch;
position-anchor: --anchor;
background: #FA08;
outline: 1px solid orange;
}
</style>
<div id="container">
@@ -40,17 +46,17 @@
}, "Offsets for position-area: " + position_area);
}
test_position_area("span-all", {left:0, top:0, width:400, height:400});
test_position_area("span-all", {left:-200, top:0, width:600, height:600});
test_position_area("left span-all", {left:-200, top:0, width:0, height:400});
test_position_area("span-left span-all", {left:-100, top:0, width:0, height:400});
test_position_area("span-all center", {left:-200, top:0, width:100, height:400});
test_position_area("span-right span-all", {left:-200, top:0, width:600, height:400});
test_position_area("right span-all", {left:-100, top:0, width:500, height:400});
test_position_area("left span-all", {left:-200, top:0, width:0, height:600});
test_position_area("span-left span-all", {left:-200, top:0, width:100, height:600});
test_position_area("span-all center", {left:-200, top:0, width:100, height:600});
test_position_area("span-right span-all", {left:-200, top:0, width:600, height:600});
test_position_area("right span-all", {left:-100, top:0, width:500, height:600});
test_position_area("top span-all", {left:0, top:0, width:400, height:500});
test_position_area("span-top span-all", {left:0, top:0, width:400, height:600});
test_position_area("center span-all", {left:0, top:500, width:400, height:100});
test_position_area("span-bottom span-all", {left:0, top:500, width:400, height:0});
test_position_area("bottom span-all", {left:0, top:600, width:400, height:0});
test_position_area("top span-all", {left:-200, top:0, width:600, height:500});
test_position_area("span-top span-all", {left:-200, top:0, width:600, height:600});
test_position_area("center span-all", {left:-200, top:500, width:600, height:100});
test_position_area("span-bottom span-all", {left:-200, top:500, width:600, height:100});
test_position_area("bottom span-all", {left:-200, top:600, width:600, height:0});
</script>

View File

@@ -8,6 +8,9 @@
position: relative;
width: 400px;
height: 400px;
margin: 100px auto;
border: 2px solid;
background: #eee;
}
#anchor {
position: absolute;
@@ -16,12 +19,15 @@
width: 100px;
height: 100px;
anchor-name: --anchor;
background: blue;
}
#anchored {
position: absolute;
align-self: stretch;
justify-self: stretch;
position-anchor: --anchor;
background: #FA08;
outline: 1px solid orange;
}
</style>
<div id="container">
@@ -40,17 +46,17 @@
}, "Offsets for position-area: " + position_area);
}
test_position_area("span-all", {left:0, top:0, width:400, height:400});
test_position_area("span-all", {left:0, top:-50, width:450, height:450});
test_position_area("left span-all", {left:0, top:0, width:350, height:400});
test_position_area("span-left span-all", {left:0, top:0, width:450, height:400});
test_position_area("span-all center", {left:350, top:0, width:100, height:400});
test_position_area("span-right span-all", {left:350, top:0, width:50, height:400});
test_position_area("right span-all", {left:450, top:0, width:0, height:400});
test_position_area("left span-all", {left:0, top:-50, width:350, height:450});
test_position_area("span-left span-all", {left:0, top:-50, width:450, height:450});
test_position_area("span-all center", {left:350, top:-50, width:100, height:450});
test_position_area("span-right span-all", {left:350, top:-50, width:100, height:450});
test_position_area("right span-all", {left:450, top:-50, width:0, height:450});
test_position_area("top span-all", {left:0, top:-50, width:400, height:0});
test_position_area("span-top span-all", {left:0, top:0, width:400, height:50});
test_position_area("center span-all", {left:0, top:-50, width:400, height:100});
test_position_area("span-bottom span-all", {left:0, top:-50, width:400, height:450});
test_position_area("bottom span-all", {left:0, top:50, width:400, height:350});
test_position_area("top span-all", {left:0, top:-50, width:450, height:0});
test_position_area("span-top span-all", {left:0, top:-50, width:450, height:100});
test_position_area("center span-all", {left:0, top:-50, width:450, height:100});
test_position_area("span-bottom span-all", {left:0, top:-50, width:450, height:450});
test_position_area("bottom span-all", {left:0, top:50, width:450, height:350});
</script>

View File

@@ -26,12 +26,17 @@
position: absolute;
width: 400px;
height: 400px;
margin: 0 auto;
border: 2px solid;
background: #eee;
}
#anchored {
position: absolute;
align-self: stretch;
justify-self: stretch;
position-anchor: --anchor;
background: #FA08;
outline: 1px solid orange;
}
#anchor {
margin-top: 150px;
@@ -39,6 +44,7 @@
width: 150px;
height: 75px;
anchor-name: --anchor;
background: blue;
}
</style>
<div id="container">

View File

@@ -0,0 +1,16 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Animations Test: animation with background-color "oklch"</title>
<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
<link rel="help" href="https://www.w3.org/TR/css-animations-2/">
<meta name="assert" content="Check that the background-color is animated with oklch correctly">
<style>
#box {
block-size: 200px;
inline-size: 200px;
background-color: oklch(45% 0.2 264);
}
</style>
<div id="box"></div>
</html>

View File

@@ -0,0 +1,34 @@
<!doctype html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Animations Test: animation with background-color "oklch"</title>
<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
<link rel="help" href="https://www.w3.org/TR/css-animations-2/">
<link rel="match" href="animate-with-background-color-oklch-001-ref.html">
<meta name="assert" content="Check that the background-color is animated with oklch correctly">
<style>
@keyframes bg-color-oklch {
to {
background-color: oklch(45% 0.2 264); /* blue */
}
}
#box {
block-size: 200px;
inline-size: 200px;
background-color: #ff0000;
animation: linear 1s forwards bg-color-oklch;
}
</style>
<div id="box"></div>
<script>
window.onload = () => {
requestAnimationFrame(() => {
const anim = document.getAnimations()[0];
anim.finish();
requestAnimationFrame(() => {
document.documentElement.classList.remove("reftest-wait");
});
});
};
</script>
</html>

View File

@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS animations with background-color from legacy rgb to oklch</title>
<link rel="author" title="CGQAQ" href="mailto:m.jason.liu@gmail.com">
<link rel="help" href="https://www.w3.org/TR/css-animations-2/">
</head>
<style>
@keyframes bg-color-oklch {
to {
background-color: oklch(45% 0.2 264); /* blue */
}
}
@keyframes bg-mix-color-oklch {
to {
background-color: color-mix(in oklch, oklch(45% 0.2 264), oklch(45% 0.2 264));
}
}
#target {
background: #ff0000;
animation-duration: 1s;
animation-timing-function: linear;
animation-play-state: paused;
animation-fill-mode: forwards;
height: 100px;
width: 100px;
}
.bg-color-oklch {
animation-name: bg-color-oklch;
}
.bg-mix-color-oklch {
animation-name: bg-mix-color-oklch;
}
</style>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="/css/support/color-testcommon.js"></script>
<body>
<div id="target"></div>
<div id="test"></div>
</body>
<script>
'use strict';
async function runAnimationTest(t, name, expected_colors) {
const target = document.getElementById('target');
target.classList.add(name);
t.add_cleanup(() => {
target.classList.remove(name);
});
const anim = document.getAnimations()[0];
await anim.ready;
expected_colors.forEach(data => {
anim.currentTime = 1000 * data.at;
const actual = getComputedStyle(target).backgroundColor;
const expected = data.value;
assert_equals(actual, expected, `Background color at ${100*data.at}% animation progress`);
});
}
const bg_color_legacy_rgb_to_oklch = [
{ at: 0, value: 'rgb(255, 0, 0)' },
{ at: 0.25, value: 'oklab(0.583475 0.163433 0.0446685)' },
{ at: 0.5, value: 'oklab(0.538983 0.101987 -0.0365225)' },
{ at: 0.75, value: 'oklab(0.494492 0.0405407 -0.117713)' },
{ at: 1, value: 'oklab(0.45 -0.0209057 -0.198904)' }
];
window.onload = async () => {
promise_test(t => {
return runAnimationTest(t, 'bg-color-oklch', bg_color_legacy_rgb_to_oklch);
}, 'Animate from legacy rgb to oklch');
promise_test(t => {
return runAnimationTest(t, 'bg-mix-color-oklch', bg_color_legacy_rgb_to_oklch);
}, 'Animate from legacy rgb to color-mix oklch');
};
</script>
</html>

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<title>CSS Animations: Chrome crash for getKeyframes() when animating background-image</title>
<link rel="help" href="https://crbug.com/404743651">
<style>
@keyframes animate {
to { background-image: url(foo.jpg); }
}
#target {
animation: animate 100s;
}
</style>
<div id="target"></div>
<script>
for (let anim of document.getAnimations()) {
anim.effect.getKeyframes();
}
</script>

View File

@@ -5,6 +5,11 @@
<script src="resources/resolve-corner-style.js"></script>
<script src="resources/corner-utils.js"></script>
<script src="resources/corner-shape.js"></script>
<style>
body {
margin: 0;
}
</style>
<script>
const canvas = document.getElementById("target");
const params = new URLSearchParams(location.search);

View File

@@ -4,6 +4,9 @@
<link rel="help" href="https://drafts.csswg.org/css-borders-4/#corner-shaping">
<link rel="match" href="corner-shape-any-ref.html">
<meta name="variant" content="?corner-shape=squircle&border-radius=50%">
<meta name="variant" content="?corner-shape=squircle&border-top-left-radius=25%&border-width=10px">
<meta name="variant" content="?corner-shape=squircle&border-radius=25%&border-width=20px">
<meta name="variant" content="?corner-top-left-shape=superellipse(6)&border-radius=20%&border-width=10px">
<meta name="variant" content="?corner-shape=squircle&border-top-left-radius=30%">
<meta name="variant" content="?corner-shape=squircle&border-top-right-radius=30px">
<meta name="variant" content="?corner-shape=straight&border-bottom-leftradius=5px">
@@ -13,13 +16,31 @@
<meta name="variant" content="?corner-top-right-shape=superellipse(0.1)&border-top-right-radius=50px">
<meta name="variant" content="?corner-bottom-left-shape=bevel&border-bottom-left-radius=30px">
<meta name="variant" content="?corner-bottom-right-shape=superellipse(1.9)&border-bottom-right-radius=50%">
<meta name="variant" content="?corner-top-left-shape=bevel&border-width=10px&border-color=black">
<meta name="variant" content="?corner-top-right-shape=bevel&border-width=10px&border-color=black">
<meta name="variant" content="?corner-bottom-left-shape=bevel&border-width=10px&border-radius=20px">
<meta name="variant" content="?corner-bottom-right-shape=bevel&border-width=10px&border-radius=20px">
<meta name="variant" content="?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel">
<meta name="variant" content="?corner-top-left-shape=bevel&border-radius=40px">
<meta name="variant" content="?corner-top-left-shape=scoop&border-radius=40px">
<meta name="variant" content="?corner-top-left-shape=superellipse(0.2)&border-radius=40px">
<meta name="variant" content="?corner-top-left-shape=superellipse(0.3)&border-radius=40%">
<meta name="variant" content="?corner-top-left-shape=superellipse(1.2)&border-radius=40px">
<meta name="variant" content="?corner-top-left-shape=superellipse(0.8)&border-radius=40px">
<meta name="variant" content="?corner-top-left-shape=bevel&border-radius=40px&border-width=10px">
<meta name="fuzzy" content="maxDifference=0-180;totalPixels=0-520">
<style>
body {
margin: 0;
}
#target {
width: 200px;
height: 100px;
box-sizing: border-box;
background: green;
border-style: solid;
border-color: black;
border-width: 0;
}
</style>
<div id="target"></div>

View File

@@ -1,172 +0,0 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>CSS Borders and Box Decorations 4: 'corner-shape' rendering</title>
</head>
<body>
<canvas width="200" height="200" id="canvas"></canvas>
<style>
canvas {
width: 200px;
height: 200px;
}
</style>
<script>
const canvas = document.getElementById("canvas");
const params = new URLSearchParams(location.search);
const style = Object.fromEntries(params.entries());
const { width, height } = canvas;
// Populate defaults and constraints.
for (const vSide of ["top", "bottom"]) {
for (const hSide of ["left", "right"]) {
let shape =
style[`corner-${vSide}-${hSide}-shape`] ||
style["corner-shape"] ||
"round";
const hWidth = parseFloat(
style[`border-${hSide}-width`] || style["border-width"] || "10px"
);
const vWidth = parseFloat(
style[`border-${vSide}-width`] || style["border-width"] || "10px"
);
let radius = (
style[`border-${vSide}-${hSide}-radius`] ||
style["border-radius"] ||
"20px"
).match(/[0-9]*(\.[0-9]+)?/)?.[0];
radius = [
Math.min(parseFloat(radius), width / 2),
Math.min(parseFloat(radius), height / 2)
];
style[`corner-${vSide}-${hSide}-shape`] = shape;
style[`border-${vSide}-${hSide}-radius`] = radius;
style[`border-${hSide}-width`] = hWidth;
style[`border-${vSide}-width`] = vWidth;
}
}
const ctx = canvas.getContext("2d");
const keywords = {bevel: 1, round: 2};
// Adjust outer width for curvature
const outer_width = ["top", "bottom"].flatMap((vSide) =>
["left", "right"].map((hSide) => {
const corner = `${vSide}-${hSide}`;
let shape = style[`corner-${corner}-shape`];
shape = keywords[shape] || shape;
const radius = style[`border-${corner}-radius`];
const hWidth = style[`border-${hSide}-width`];
const vWidth = style[`border-${vSide}-width`];
if (shape >= 2.)
return radius;
if (shape <= 0.5)
return [radius[0] - vWidth, radius[1] - hWidth];
const offset = Math.sqrt(2. / shape) - 1;
return [radius[0] - vWidth * offset, radius[1] - hWidth * offset];
})
);
let cursor = [];
function lineTo(x, y) {
ctx.lineTo(x, y);
cursor = [x, y];
}
function moveTo(x, y) {
ctx.moveTo(x, y);
cursor = [x, y];
}
function cornerTo(x, y, corner) {
if (x == cursor[0] && y === cursor[1]) return;
const shape = style[`corner-${corner}-shape`];
// TODO: add other curves.
if (shape === "bevel")
lineTo(x, y);
else {
ctx.arcTo(
corner === "top-left" || corner === "bottom-right" ? cursor[0] : x,
corner === "top-left" || corner === "bottom-right" ? y : cursor[1],
x,
y,
Math.abs(x - cursor[0])
);
cursor = [x, y];
}
}
ctx.clearRect(0, 0, width, height);
ctx.beginPath();
moveTo(width - outer_width[1][0], 0);
cornerTo(width, outer_width[1][1], "top-right");
lineTo(width, height - outer_width[3][1]);
cornerTo(width - outer_width[3][0], height, "bottom-right");
lineTo(outer_width[2][0], height);
cornerTo(0, height - outer_width[2][1], "bottom-left");
lineTo(0, outer_width[0][1]);
cornerTo(outer_width[0][0], 0, "top-left");
lineTo(width - outer_width[1][0], 0);
// Inner path
moveTo(
Math.max(style["border-top-left-radius"][0], style["border-left-width"]),
style["border-top-width"]
);
lineTo(width - style["border-top-right-radius"][0], style["border-top-width"]);
cornerTo(
width - style["border-right-width"],
Math.max(style["border-top-width"], style["border-top-right-radius"][1]),
"top-right"
);
lineTo(
width - style["border-right-width"],
height -
Math.max(
style["border-bottom-width"],
style["border-bottom-right-radius"][1]
)
);
cornerTo(
width -
Math.max(
style["border-right-width"],
style["border-bottom-right-radius"][0]
),
height - style["border-bottom-width"],
"bottom-right"
);
lineTo(
Math.max(style["border-left-width"], style["border-bottom-left-radius"][0]),
height - style["border-bottom-width"]
);
cornerTo(
style["border-left-width"],
height -
Math.max(style["border-top-width"], style["border-bottom-left-radius"][1]),
"bottom-left"
);
lineTo(
style["border-left-width"],
Math.max(style["border-top-width"], style["border-top-left-radius"][1])
);
cornerTo(
Math.max(style["border-left-width"], style["border-top-left-radius"][0]),
style["border-top-width"],
"top-left"
);
if ("background-color" in style) {
ctx.fillStyle = style["background-color"];
ctx.fill("nonzero");
}
ctx.fillStyle = "black";
ctx.fill("evenodd");
</script>

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>CSS Borders and Box Decorations 4: 'corner-shape' rendering</title>
<link rel="help" href="https://drafts.csswg.org/css-borders-4/#corner-shaping">
<link rel="match" href="corner-shape-render-ref.html">
<meta name="variant" content="?corner-shape=bevel">
<meta name="variant" content="?corner-top-left-shape=bevel">
<meta name="variant" content="?corner-top-right-shape=bevel">
<meta name="variant" content="?corner-bottom-left-shape=bevel">
<meta name="variant" content="?corner-bottom-right-shape=bevel">
<meta name="variant" content="?corner-bottom-right-shape=bevel&corner-bottom-left-shape=bevel">
<meta name="variant" content="?corner-top-left-shape=bevel&border-radius=40px">
<meta name="variant" content="?corner-top-right-shape=bevel&corner-bottom-right-shape=bevel&border-radius=80px">
<meta name="variant" content="?corner-top-right-shape=bevel&corner-bottom-right-shape=bevel&border-bottom-right-radius=80px&border-width=32px">
<meta name="fuzzy" content="maxDifference=0-82;totalPixels=0-800">
</head>
<body>
<style>
#target {
width: 200px;
height: 200px;
border-width: 10px;
border-radius: 20px;
border-style: solid;
box-sizing: border-box;
}
</style>
<div id="target"></div>
<script>
const target = document.getElementById("target");
const params = new URLSearchParams(location.search);
for (const [key, value] of params.entries()) {
target.style[key] = value;
}
</script>
</body>

View File

@@ -109,7 +109,7 @@ function render_rect_with_corner_shapes(style, ctx, width, height) {
}
function draw_inner_corner_from_params(params, phase = "both", direction) {
add_corner(ctx, ...params.inner_rect, params.shape, phase, direction);
add_corner(ctx, ...params.inner_rect, params.inner_shape, phase, direction);
}
function draw_inner_corner(corner, phase = "both", direction) {
@@ -123,7 +123,7 @@ function render_rect_with_corner_shapes(style, ctx, width, height) {
draw_outer_corner("bottom-left");
draw_outer_corner("top-left");
ctx.closePath();
ctx.clip("nonzero");
ctx.fill("nonzero");
const inner_rect = [
style["border-left-width"],

View File

@@ -7,8 +7,9 @@ function offset_for_curvature(curvature) {
// Find the superellipse's control point.
// we do that by approximating the superellipse as a quadratic
// curve that has the same point at t = 0.5.
if (curvature <= 0.001) return [1, -1];
const { x } = superellipse(curvature);
if (curvature <= 0.001)
return [1, -1];
const {x} = superellipse(Math.min(2, Math.max(0.5, curvature)));
const [a, b] = [x, 1 - x].map((m) => 2 * m - 0.5);
const magnitude = Math.hypot(a, b);
// Normalize a & b
@@ -17,6 +18,19 @@ function offset_for_curvature(curvature) {
return [norm_a, -norm_b];
}
function compute_inner_curvature(curvature, outer_length, inner_length) {
if (curvature === 0)
return 0;
if (curvature < 1)
return 1 /
compute_inner_curvature(1 / curvature, outer_length, inner_length);
const target_length = (inner_length - outer_length) / Math.SQRT2;
return Math.log(0.5) /
Math.log(
(Math.pow(0.5, 1 / curvature) * outer_length + target_length) /
inner_length);
}
/**
*
* @param {number} curvature
@@ -91,36 +105,49 @@ function resolve_corner_params(style, width, height, outset = null) {
};
return Object.fromEntries(
Object.entries(params).map(([corner, { outer, inset }]) => {
if (outset !== null) inset = [-outset, -outset];
const shape = style[`corner-${corner}-shape`];
const s1 = Math.sign(outer[2] - outer[0]);
const s2 = Math.sign(outer[3] - outer[1]);
const [sw1, sw2] = inset;
const inner_offset = [s1 * sw1, s2 * sw1, -s1 * sw2, -s2 * sw2];
Object.entries(params).map(([corner, {outer, inset}]) => {
const outer_rect = outer;
if (outset !== null)
inset = [-outset, -outset];
const shape = style[`corner-${corner}-shape`];
const s1 = Math.sign(outer[2] - outer[0]);
const s2 = Math.sign(outer[3] - outer[1]);
const [sw1, sw2] = inset;
const inner_offset = [s1 * sw1, s2 * sw1, -s1 * sw2, -s2 * sw2];
const offset = offset_for_curvature(shape);
if (Math.sign(inner_offset[0]) === Math.sign(inner_offset[1])) {
offset.reverse();
}
const offset = offset_for_curvature(shape);
if (Math.sign(inner_offset[0]) === Math.sign(inner_offset[1])) {
offset.reverse();
}
const inner_rect = [
outer[0] + inner_offset[0] * offset[0],
outer[1] + inner_offset[1] * offset[1],
outer[2] + inner_offset[2] * offset[1],
outer[3] + inner_offset[3] * offset[0],
];
const inner_rect = [
outer_rect[0] + inner_offset[0] * offset[0],
outer_rect[1] + inner_offset[1] * offset[1],
outer_rect[2] + inner_offset[2] * offset[1],
outer_rect[3] + inner_offset[3] * offset[0],
];
return [
corner,
{
outer_rect: outer,
shape,
inset,
inner_rect,
inner_offset,
},
];
})
);
let inner_shape = shape;
if (shape > 2 || shape < 0.5) {
const outer_length = Math.hypot(
outer_rect[2] - outer_rect[0], outer_rect[3] - outer_rect[1]);
const inner_length = Math.hypot(
inner_rect[2] - inner_rect[0], inner_rect[3] - inner_rect[1])
inner_shape =
compute_inner_curvature(shape, outer_length, inner_length);
}
return [
corner,
{
outer_rect,
shape,
inner_shape,
inset,
inner_rect,
inner_offset,
inner_shape
},
];
}));
}

View File

@@ -17,8 +17,8 @@ function resolve_corner_style(style, w, h) {
style['corner-shape'] || 'round';
const match = shape.match(/superellipse\((\.?[0-9]+(.[0-9]+)?)\)/);
shape = match ? +match[1] : keywords[shape];
const hWidth = style[`border-${hSide}-width`] || style['border-width'] || 0;
const vWidth = style[`border-${vSide}-width`] || style['border-width'] || 0;
const hWidth = parseFloat(style[`border-${hSide}-width`] || style['border-width'] || 0);
const vWidth = parseFloat(style[`border-${vSide}-width`] || style['border-width'] || 0);
let radius =
style[`border-${vSide}-${hSide}-radius`] || style['border-radius'] || 0;
if (!Array.isArray(radius))

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