ladybird/Tests/LibWeb/Text/input/HTML/parser-created-style-script-blocking.html
Sam Atkins 89bdc5f889 LibWeb/SVG: Apply parser-created style timing
Let SVGStyleElement delegate style updates through StyleElementBase so
parser-created inline SVG `<style>` elements update when they are popped
from the parser stack, just like HTML style elements.

This lets SVG style imports participate in script-blocking stylesheet
checks while keeping dynamic text, type, and media changes from
re-blocking parser scripts.
2026-06-04 16:39:54 +01:00

180 lines
8.5 KiB
HTML

<!DOCTYPE html>
<script src="../include.js"></script>
<script>
asyncTest(async done => {
internals.setTestTimeout(10000);
const httpServer = httpTestServer();
const scriptStart = "<scr" + "ipt>";
const scriptEnd = "</scr" + "ipt>";
async function slowStyleSheet(path, body = "body { color: rgb(1, 2, 3); }") {
return await httpServer.createEcho("GET", path, {
status: 200,
headers: {
"Cache-Control": "no-store",
"Content-Type": "text/css",
},
body,
delay_ms: 800,
});
}
async function runFrame(path, body) {
const url = await httpServer.createEcho("GET", path, {
status: 200,
headers: {
"Cache-Control": "no-store",
"Content-Type": "text/html",
},
body,
});
return await new Promise(resolve => {
const frame = document.createElement("iframe");
window.addEventListener("message", event => {
frame.remove();
resolve(event.data);
}, { once: true });
frame.src = url;
document.body.appendChild(frame);
});
}
const parserBlockingStyle = await slowStyleSheet("/parser-created-style-script-blocking.css");
const parserBlockingColor = await runFrame("/parser-created-style-script-blocking-page", `
<!DOCTYPE html>
<style>@import url("${parserBlockingStyle}");</style>
<body>
${scriptStart}
parent.postMessage(getComputedStyle(document.body).color, "*");
${scriptEnd}
`);
println(`Parser-created style import available to following script: ${parserBlockingColor}`);
const svgParserBlockingStyle = await slowStyleSheet("/parser-created-svg-style-script-blocking.css");
const svgParserBlockingBlocked = await runFrame("/parser-created-svg-style-script-blocking-page", `
<!DOCTYPE html>
${scriptStart}
window.svgParserBlockingStart = performance.now();
${scriptEnd}
<svg><style>@import url("${svgParserBlockingStyle}");</style></svg>
${scriptStart}
parent.postMessage(performance.now() - window.svgParserBlockingStart >= 700, "*");
${scriptEnd}
`);
println(`Parser-created SVG style import blocked following parser script: ${svgParserBlockingBlocked}`);
const dynamicUpdateStyle = await slowStyleSheet("/dynamic-style-update-should-not-block.css");
const dynamicUpdateBlocked = await runFrame("/dynamic-style-update-should-not-block-page", `
<!DOCTYPE html>
<style id="style"></style>
${scriptStart}
window.dynamicUpdateStart = performance.now();
document.getElementById("style").textContent = '@import url("${dynamicUpdateStyle}");';
${scriptEnd}
${scriptStart}
parent.postMessage(performance.now() - window.dynamicUpdateStart >= 700, "*");
${scriptEnd}
`);
println(`Dynamic style update blocked following parser script: ${dynamicUpdateBlocked}`);
const dynamicSvgUpdateStyle = await slowStyleSheet("/dynamic-svg-style-update-should-not-block.css");
const dynamicSvgUpdateBlocked = await runFrame("/dynamic-svg-style-update-should-not-block-page", `
<!DOCTYPE html>
<svg><style id="style"></style></svg>
${scriptStart}
window.dynamicSvgUpdateStart = performance.now();
document.getElementById("style").textContent = '@import url("${dynamicSvgUpdateStyle}");';
${scriptEnd}
${scriptStart}
parent.postMessage(performance.now() - window.dynamicSvgUpdateStart >= 700, "*");
${scriptEnd}
`);
println(`Dynamic SVG style update blocked following parser script: ${dynamicSvgUpdateBlocked}`);
const dynamicSvgTypeStyle = await slowStyleSheet("/dynamic-svg-style-type-update-should-not-block.css");
const dynamicSvgTypeBlocked = await runFrame("/dynamic-svg-style-type-update-should-not-block-page", `
<!DOCTYPE html>
<svg><style id="style" type="text/plain">@import url("${dynamicSvgTypeStyle}");</style></svg>
${scriptStart}
window.dynamicSvgTypeStart = performance.now();
document.getElementById("style").setAttribute("type", "text/css");
${scriptEnd}
${scriptStart}
parent.postMessage(performance.now() - window.dynamicSvgTypeStart >= 700, "*");
${scriptEnd}
`);
println(`Dynamic SVG style type change blocked following parser script: ${dynamicSvgTypeBlocked}`);
const removedStyle = await slowStyleSheet("/removed-parser-created-style-should-unblock.css");
const removedStyleBlocked = await runFrame("/removed-parser-created-style-should-unblock-page", `
<!DOCTYPE html>
${scriptStart}
window.removeStart = performance.now();
setTimeout(() => document.getElementById("style").remove(), 0);
${scriptEnd}
<style id="style">@import url("${removedStyle}");</style>
${scriptStart}
parent.postMessage(performance.now() - window.removeStart >= 700, "*");
${scriptEnd}
`);
println(`Removed parser-created style blocked until import finished: ${removedStyleBlocked}`);
const nonMatchingMedia = await slowStyleSheet("/non-matching-media-style-should-not-block.css");
const nonMatchingMediaBlocked = await runFrame("/non-matching-media-style-should-not-block-page", `
<!DOCTYPE html>
${scriptStart}
window.mediaStart = performance.now();
${scriptEnd}
<style media="not all">@import url("${nonMatchingMedia}");</style>
${scriptStart}
parent.postMessage(performance.now() - window.mediaStart >= 700, "*");
${scriptEnd}
`);
println(`Non-matching media style blocked following parser script: ${nonMatchingMediaBlocked}`);
const nonMatchingSvgMedia = await slowStyleSheet("/non-matching-svg-media-style-should-not-block.css");
const nonMatchingSvgMediaBlocked = await runFrame("/non-matching-svg-media-style-should-not-block-page", `
<!DOCTYPE html>
${scriptStart}
window.svgMediaStart = performance.now();
${scriptEnd}
<svg><style media="not all">@import url("${nonMatchingSvgMedia}");</style></svg>
${scriptStart}
parent.postMessage(performance.now() - window.svgMediaStart >= 700, "*");
${scriptEnd}
`);
println(`Non-matching SVG media style blocked following parser script: ${nonMatchingSvgMediaBlocked}`);
const changedMedia = await slowStyleSheet("/changed-media-style-should-unblock.css");
const changedMediaBlocked = await runFrame("/changed-media-style-should-unblock-page", `
<!DOCTYPE html>
${scriptStart}
window.mediaChangeStart = performance.now();
setTimeout(() => document.getElementById("style").media = "not all", 0);
${scriptEnd}
<style id="style">@import url("${changedMedia}");</style>
${scriptStart}
parent.postMessage(performance.now() - window.mediaChangeStart >= 700, "*");
${scriptEnd}
`);
println(`Media change blocked until import finished: ${changedMediaBlocked}`);
const changedSvgMedia = await slowStyleSheet("/changed-svg-media-style-should-unblock.css");
const changedSvgMediaBlocked = await runFrame("/changed-svg-media-style-should-unblock-page", `
<!DOCTYPE html>
${scriptStart}
window.svgMediaChangeStart = performance.now();
setTimeout(() => document.getElementById("style").media = "not all", 0);
${scriptEnd}
<svg><style id="style">@import url("${changedSvgMedia}");</style></svg>
${scriptStart}
parent.postMessage(performance.now() - window.svgMediaChangeStart >= 700, "*");
${scriptEnd}
`);
println(`SVG media change blocked until import finished: ${changedSvgMediaBlocked}`);
done();
});
</script>