mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-06 01:26:22 +00:00
LibWeb: Include own shadow root in for_each_shadow_including_descendant
Fixes a crash in wpt.live/css/cssom/CSSStyleSheet-constructable.html
This commit is contained in:
parent
409758f040
commit
d980321a77
Notes:
github-actions[bot]
2025-07-11 14:22:20 +00:00
Author: https://github.com/Calme1709
Commit: d980321a77
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5402
3 changed files with 848 additions and 10 deletions
|
@ -126,6 +126,15 @@ inline TraversalDecision Node::for_each_shadow_including_inclusive_descendant(Ca
|
|||
if (callback(*this) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
|
||||
if (this->for_each_shadow_including_descendant(callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline TraversalDecision Node::for_each_shadow_including_descendant(Callback callback)
|
||||
{
|
||||
if (is_element()) {
|
||||
if (auto shadow_root = static_cast<Element*>(this)->shadow_root()) {
|
||||
if (shadow_root->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break)
|
||||
|
@ -141,14 +150,4 @@ inline TraversalDecision Node::for_each_shadow_including_inclusive_descendant(Ca
|
|||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline TraversalDecision Node::for_each_shadow_including_descendant(Callback callback)
|
||||
{
|
||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||
if (child->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 32 tests
|
||||
|
||||
24 Pass
|
||||
8 Fail
|
||||
Pass document.adoptedStyleSheets should initially have length 0.
|
||||
Pass new CSSStyleSheet produces empty CSSStyleSheet
|
||||
Pass title can be set in the CSSStyleSheet constructor
|
||||
Pass CSSStyleSheet.replace produces Promise<CSSStyleSheet>
|
||||
Pass Constructed style sheets can be applied on document
|
||||
Pass Constructed style sheets can be applied on shadow root
|
||||
Pass Re-attaching shadow host with adopted stylesheets work
|
||||
Fail Attaching a shadow root that already has adopted stylesheets work
|
||||
Pass Re-attaching shadow host and updating attributes work
|
||||
Pass Changes to constructed stylesheets through CSSOM is reflected
|
||||
Pass Constructed stylesheet can be used and modified in multiple TreeScopes
|
||||
Pass Stylesheets constructed on the main Document cannot be used in iframes
|
||||
Pass Stylesheet constructed on iframe cannot be used in the main Document
|
||||
Pass Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet is in the same document tree as the AdoptedStyleSheets
|
||||
Pass Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees
|
||||
Pass CSSStyleSheet.replaceSync replaces stylesheet text synchronously
|
||||
Fail CSSStyleSheet.replaceSync correctly updates the style of its adopters synchronously
|
||||
Fail Adopted sheets are ordered after non-adopted sheets in the shadow root
|
||||
Fail Adopted sheets are ordered after non-adopted sheets in the document
|
||||
Pass Inserting an @import rule through insertRule on a constructed stylesheet throws an exception
|
||||
Fail CSSStyleSheet.replaceSync should not trigger any loads from @import rules
|
||||
Pass CSSStyleSheet.replace allows, but ignores, import rule inside
|
||||
Fail CSSStyleSheet.replace ignores @import rule but still loads other rules
|
||||
Pass CSSStyleSheet.replaceSync allows, but ignores, import rule inside
|
||||
Pass CSSStyleSheet.replace does not reject on failed imports
|
||||
Pass Cloning a shadow host will not clone shadow root, and also adoptedStyleSheets
|
||||
Pass Importing a shadow host will not copy shadow root, and also adoptedStyleSheets
|
||||
Fail Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document
|
||||
Fail Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document
|
||||
Pass Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.
|
||||
Pass Modifying an adopted stylesheet on a disconnected shadow root should not crash.
|
||||
Pass Constructing a sheet with the default base URL uses the constructor document's base URL for CSS rules
|
|
@ -0,0 +1,801 @@
|
|||
<!DOCTYPE html>
|
||||
<title>CSSStyleSheet constructor and adoptedStyleSheets</title>
|
||||
<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
|
||||
<link rel="help" href="https://wicg.github.io/construct-stylesheets/">
|
||||
<script src = '../../resources/testharness.js'></script>
|
||||
<script src = '../../resources/testharnessreport.js'></script>
|
||||
|
||||
<section id="firstSection">
|
||||
<div>
|
||||
<span class="green"></span>
|
||||
<span class="red"></span>
|
||||
<span class="blue"></span>
|
||||
<span class="white"></span>
|
||||
<span class="yellow"></span>
|
||||
</div>
|
||||
</section>
|
||||
<section id="shadowHost"></section>
|
||||
<section id="thirdSection"></section>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
const greenStyleText = ".green { color: green; }";
|
||||
const redStyleTexts = [".red { color: red; }", ".red + span + span { color: red; }"];
|
||||
const blueStyleTexts = [".blue { color: blue; }", ".blue + span + span { color: blue; }"];
|
||||
const whiteStyleText = "* { color: white; }";
|
||||
const yellowStyleText = ".yellow { color: yellow; }";
|
||||
|
||||
const firstDiv = document.querySelector('#firstSection > div');
|
||||
const secondDiv = firstDiv.cloneNode(true);
|
||||
const shadowHost = document.querySelector('#shadowHost');
|
||||
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
|
||||
shadowRoot.appendChild(secondDiv);
|
||||
|
||||
const greenSpan = firstDiv.children[0];
|
||||
const redSpan = firstDiv.children[1];
|
||||
const blueSpan = firstDiv.children[2];
|
||||
const whiteSpan = firstDiv.children[3];
|
||||
const yellowSpan = firstDiv.children[4];
|
||||
const greenShadowSpan = secondDiv.children[0];
|
||||
const redShadowSpan = secondDiv.children[1];
|
||||
const blueShadowSpan = secondDiv.children[2];
|
||||
const whiteShadowSpan = secondDiv.children[3];
|
||||
const yellowShadowSpan = secondDiv.children[4];
|
||||
|
||||
test(() => {
|
||||
assert_equals(document.adoptedStyleSheets.length, 0);
|
||||
}, "document.adoptedStyleSheets should initially have length 0.");
|
||||
|
||||
test(() => {
|
||||
const sheet = new CSSStyleSheet({disabled: true, media: "screen, print"});
|
||||
assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
|
||||
assert_equals(sheet.ownerNode, null);
|
||||
assert_equals(sheet.ownerRule, null);
|
||||
assert_equals(sheet.media.length, 2);
|
||||
assert_equals(sheet.media.item(0), "screen");
|
||||
assert_equals(sheet.media.item(1), "print");
|
||||
assert_true(sheet.disabled);
|
||||
assert_equals(sheet.cssRules.length, 0);
|
||||
|
||||
sheet.insertRule(redStyleTexts[0]);
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
|
||||
|
||||
sheet.insertRule(redStyleTexts[1]);
|
||||
assert_equals(sheet.cssRules.length, 2);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
|
||||
|
||||
const sheet2 = new CSSStyleSheet({});
|
||||
assert_equals(sheet2.title, null, "The title attribute must return the title or null if title is the empty string");
|
||||
assert_equals(sheet2.ownerNode, null);
|
||||
assert_equals(sheet2.ownerRule, null);
|
||||
assert_equals(sheet2.media.length, 0);
|
||||
assert_false(sheet2.disabled);
|
||||
assert_equals(sheet2.cssRules.length, 0);
|
||||
|
||||
sheet2.insertRule(redStyleTexts[1]);
|
||||
assert_equals(sheet2.cssRules.length, 1);
|
||||
assert_equals(sheet2.cssRules[0].cssText, redStyleTexts[1]);
|
||||
|
||||
sheet2.deleteRule(0);
|
||||
assert_equals(sheet2.cssRules.length, 0);
|
||||
|
||||
const sheet3 = new CSSStyleSheet();
|
||||
assert_equals(sheet3.title, null, "The title attribute must return the title or null if title is the empty string");
|
||||
assert_equals(sheet3.ownerNode, null);
|
||||
assert_equals(sheet3.ownerRule, null);
|
||||
assert_equals(sheet3.media.length, 0);
|
||||
assert_false(sheet3.disabled);
|
||||
assert_equals(sheet3.cssRules.length, 0);
|
||||
|
||||
sheet3.insertRule(redStyleTexts[1]);
|
||||
assert_equals(sheet3.cssRules.length, 1);
|
||||
assert_equals(sheet3.cssRules[0].cssText, redStyleTexts[1]);
|
||||
|
||||
sheet3.deleteRule(0);
|
||||
assert_equals(sheet3.cssRules.length, 0);
|
||||
}, 'new CSSStyleSheet produces empty CSSStyleSheet');
|
||||
|
||||
test(() => {
|
||||
const sheet = new CSSStyleSheet({title: "something"});
|
||||
assert_equals(sheet.title, null, "title and alternate are not supported by the constructor. https://github.com/WICG/construct-stylesheets/issues/105");
|
||||
}, "title can be set in the CSSStyleSheet constructor");
|
||||
|
||||
promise_test(() => {
|
||||
const sheet = new CSSStyleSheet({disabled: true, media: "screen, print"});
|
||||
const promise_sheet = sheet.replace(redStyleTexts[0]);
|
||||
return promise_sheet.then(function(sheet) {
|
||||
assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
|
||||
assert_equals(sheet.ownerNode, null);
|
||||
assert_equals(sheet.ownerRule, null);
|
||||
assert_equals(sheet.media.length, 2);
|
||||
assert_equals(sheet.media.item(0), "screen");
|
||||
assert_equals(sheet.media.item(1), "print");
|
||||
assert_true(sheet.disabled);
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
|
||||
|
||||
sheet.insertRule(redStyleTexts[1]);
|
||||
assert_equals(sheet.cssRules.length, 2);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
|
||||
});
|
||||
}, 'CSSStyleSheet.replace produces Promise<CSSStyleSheet>');
|
||||
|
||||
function createAllSheetsPromise() {
|
||||
const greenSheet = new CSSStyleSheet();
|
||||
const redSheet = new CSSStyleSheet({media: "screen, print"});
|
||||
const blueSheet = new CSSStyleSheet({disabled: true});
|
||||
const whiteSheet = new CSSStyleSheet({disabled: true});
|
||||
const yellowSheet = new CSSStyleSheet({disabled: false});
|
||||
|
||||
const greenPromise = greenSheet.replace(greenStyleText);
|
||||
const redPromise = redSheet.replace(redStyleTexts[0] + redStyleTexts[1]);
|
||||
const bluePromise = blueSheet.replace(blueStyleTexts[0] + blueStyleTexts[1]);
|
||||
const whitePromise = whiteSheet.replace(whiteStyleText);
|
||||
const yellowPromise = yellowSheet.replace(yellowStyleText);
|
||||
return [greenPromise, redPromise, bluePromise, whitePromise, yellowPromise];
|
||||
}
|
||||
|
||||
promise_test(() => {
|
||||
return Promise.all(createAllSheetsPromise()).then(values => {
|
||||
const greenStyleSheet = values[0];
|
||||
const redStyleSheet = values[1];
|
||||
const blueStyleSheet = values[2];
|
||||
const whiteStyleSheet = values[3];
|
||||
const yellowStyleSheet = values[4];
|
||||
|
||||
// Lists of style sheets can be created, assigned and read.
|
||||
|
||||
// disabled stylesheets aren't applied
|
||||
document.adoptedStyleSheets = [whiteStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
// disable dsheets don't block other styles from applying
|
||||
document.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];
|
||||
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");
|
||||
|
||||
document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");
|
||||
document.adoptedStyleSheets = [];
|
||||
});
|
||||
}, 'Constructed style sheets can be applied on document');
|
||||
|
||||
promise_test(() => {
|
||||
return Promise.all(createAllSheetsPromise()).then(values => {
|
||||
const greenStyleSheet = values[0];
|
||||
const redStyleSheet = values[1];
|
||||
const blueStyleSheet = values[2];
|
||||
const whiteStyleSheet = values[3];
|
||||
const yellowStyleSheet = values[4];
|
||||
shadowRoot.adoptedStyleSheets = [whiteStyleSheet];
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
shadowRoot.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");
|
||||
|
||||
shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");
|
||||
});
|
||||
}, 'Constructed style sheets can be applied on shadow root');
|
||||
|
||||
promise_test(() => {
|
||||
return Promise.all(createAllSheetsPromise()).then(values => {
|
||||
const greenStyleSheet = values[0];
|
||||
const redStyleSheet = values[1];
|
||||
shadowRoot.adoptedStyleSheets = [greenStyleSheet];
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies connected");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)", "Style applies when connected");
|
||||
let hostParent = shadowHost.parentNode;
|
||||
hostParent.removeChild(shadowHost);
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "", "Style doesn't apply when detached");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "", "Style doesn't apply when detached");
|
||||
shadowRoot.adoptedStyleSheets = [redStyleSheet, greenStyleSheet];
|
||||
hostParent.appendChild(shadowHost);
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies after reattach");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)", "Style applies after reattach");
|
||||
});
|
||||
}, 'Re-attaching shadow host with adopted stylesheets work');
|
||||
|
||||
test(() => {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync(":host { color: red; }");
|
||||
const host = document.createElement("div");
|
||||
let sr = host.attachShadow({mode: "open"});
|
||||
sr.adoptedStyleSheets = [sheet];
|
||||
document.body.appendChild(host);
|
||||
assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies when connected");
|
||||
sheet.replaceSync(":host { color: blue; }");
|
||||
assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Style update applies when connected");
|
||||
}, 'Attaching a shadow root that already has adopted stylesheets work');
|
||||
|
||||
test(() => {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync(":host([red]) { color: red; } :host(.blue) { color: blue; }");
|
||||
const host = document.createElement("div");
|
||||
host.toggleAttribute("red");
|
||||
document.body.appendChild(host);
|
||||
assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "No style applies yet");
|
||||
|
||||
let sr = host.attachShadow({mode: "open"});
|
||||
sr.adoptedStyleSheets = [sheet];
|
||||
|
||||
assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after adding style");
|
||||
document.body.removeChild(host);
|
||||
document.body.appendChild(host);
|
||||
assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after reattachment");
|
||||
host.toggleAttribute("red");
|
||||
assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "Attribute updates to the element after reattachment apply");
|
||||
host.classList.toggle("blue");
|
||||
assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Class updates to the element after reattachment apply");
|
||||
|
||||
}, "Re-attaching shadow host and updating attributes work");
|
||||
|
||||
promise_test(() => {
|
||||
const plainSheet = new CSSStyleSheet();
|
||||
const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
|
||||
return redStyleSheetPromise.then(function(redStyleSheet) {
|
||||
document.adoptedStyleSheets = [redStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
redStyleSheet.insertRule(redStyleTexts[1]);
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
redStyleSheet.deleteRule(1);
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
redStyleSheet.cssRules[0].style.color = "white";
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 255, 255)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
});
|
||||
}, 'Changes to constructed stylesheets through CSSOM is reflected');
|
||||
|
||||
promise_test(() => {
|
||||
const plainSheet = new CSSStyleSheet();
|
||||
const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
|
||||
return redStyleSheetPromise.then(function(redStyleSheet) {
|
||||
document.adoptedStyleSheets = [redStyleSheet];
|
||||
shadowRoot.adoptedStyleSheets = [redStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
shadowRoot.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
|
||||
document.adoptedStyleSheets = [];
|
||||
});
|
||||
}, 'Constructed stylesheet can be used and modified in multiple TreeScopes');
|
||||
|
||||
promise_test(() => {
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
const thirdDiv = firstDiv.cloneNode(true);
|
||||
iframe.contentDocument.body.appendChild(thirdDiv);
|
||||
const greenIframeSpan = thirdDiv.children[0];
|
||||
const redIframeSpan = thirdDiv.children[1];
|
||||
const blueIframeSpan = thirdDiv.children[2];
|
||||
const whiteIframeSpan = thirdDiv.children[3];
|
||||
const yellowIframeSpan = thirdDiv.children[4];
|
||||
|
||||
const plainSheet = new CSSStyleSheet();
|
||||
const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
|
||||
return redStyleSheetPromise.then(function(redStyleSheet) {
|
||||
assert_throws_dom(
|
||||
'NotAllowedError',
|
||||
iframe.contentWindow.DOMException,
|
||||
() => { iframe.contentDocument.adoptedStyleSheets = [redStyleSheet]; }
|
||||
);
|
||||
assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
document.adoptedStyleSheets = [redStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
document.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
});
|
||||
}, 'Stylesheets constructed on the main Document cannot be used in iframes');
|
||||
|
||||
promise_test(async () => {
|
||||
const iframe = document.createElement("iframe");
|
||||
const iframeLoaded = new Promise(resolve => iframe.addEventListener("load", resolve));
|
||||
document.body.appendChild(iframe);
|
||||
await iframeLoaded;
|
||||
const thirdDiv = firstDiv.cloneNode(true);
|
||||
iframe.contentDocument.body.appendChild(thirdDiv);
|
||||
const greenIframeSpan = thirdDiv.children[0];
|
||||
const redIframeSpan = thirdDiv.children[1];
|
||||
const blueIframeSpan = thirdDiv.children[2];
|
||||
const whiteIframeSpan = thirdDiv.children[3];
|
||||
const yellowIframeSpan = thirdDiv.children[4];
|
||||
|
||||
// Make sure both the main Document and the iframe are not styled
|
||||
const emptyStyleSheet = new CSSStyleSheet();
|
||||
document.adoptedStyleSheets = [emptyStyleSheet];
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
const iframePlainSheet = new iframe.contentWindow.CSSStyleSheet();
|
||||
const iframeRedStyleSheetPromise = iframePlainSheet.replace(redStyleTexts[0]);
|
||||
return iframeRedStyleSheetPromise.then(function(iframeRedStyleSheet) {
|
||||
assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [iframeRedStyleSheet]; });
|
||||
assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
iframe.contentDocument.adoptedStyleSheets = [iframeRedStyleSheet];
|
||||
assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
|
||||
|
||||
iframe.contentDocument.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
|
||||
assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
|
||||
assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(255, 0, 0)");
|
||||
assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
|
||||
});
|
||||
}, 'Stylesheet constructed on iframe cannot be used in the main Document');
|
||||
</script>
|
||||
|
||||
<div id="divNonConstructed" class="nonConstructed">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
`use strict`;
|
||||
const shadowRootNonConstructed = divNonConstructed.attachShadow({mode:'open'})
|
||||
nonConstructedStyle = document.createElement("style");
|
||||
shadowRootNonConstructed.appendChild(nonConstructedStyle);
|
||||
nonConstructedStyle.sheet.insertRule(".nonConstructed { color: red; }", 0);
|
||||
const nonConstructedStyleSheet = nonConstructedStyle.sheet;
|
||||
|
||||
test(() => {
|
||||
assert_equals(getComputedStyle(divNonConstructed).color, "rgb(0, 0, 0)");
|
||||
assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [nonConstructedStyleSheet]; });
|
||||
}, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet is in the same document tree as the AdoptedStyleSheets');
|
||||
|
||||
test(() => {
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
iframeDiv = iframe.contentDocument.createElement("div");
|
||||
iframeDiv.classList.add("nonConstructed");
|
||||
iframe.contentDocument.body.appendChild(iframeDiv);
|
||||
|
||||
assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
|
||||
assert_throws_dom('NotAllowedError', iframe.contentWindow.DOMException, () => {
|
||||
iframe.contentDocument.adoptedStyleSheets = [nonConstructedStyleSheet];
|
||||
});
|
||||
assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
|
||||
|
||||
iframeStyle = iframe.contentDocument.createElement("style");
|
||||
iframe.contentDocument.body.appendChild(iframeStyle);
|
||||
iframeStyle.sheet.insertRule(".nonConstructedSpan { color: red; }");
|
||||
const iframeStyleSheet = iframeStyle.sheet;
|
||||
nonConstructedSpan = document.createElement("span");
|
||||
nonConstructedSpan.classList.add(".nonConstructedSpan");
|
||||
divNonConstructed.appendChild(nonConstructedSpan);
|
||||
|
||||
assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
|
||||
assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [iframeStyleSheet]; });
|
||||
assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
|
||||
}, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees');
|
||||
|
||||
function attachShadowDiv(host) {
|
||||
const shadowRoot = host.attachShadow({mode: 'open'});
|
||||
const shadowDiv = document.createElement("div");
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
return shadowDiv;
|
||||
}
|
||||
|
||||
test(() => {
|
||||
const sheet = new CSSStyleSheet();
|
||||
assert_equals(sheet.cssRules.length, 0);
|
||||
|
||||
sheet.replaceSync(redStyleTexts[0])
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
assert_equals(redStyleTexts[0], sheet.cssRules[0].cssText);
|
||||
|
||||
sheet.replaceSync(redStyleTexts[1]);
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
assert_equals(redStyleTexts[1], sheet.cssRules[0].cssText);
|
||||
}, 'CSSStyleSheet.replaceSync replaces stylesheet text synchronously');
|
||||
|
||||
test(() => {
|
||||
// Attach a div inside a shadow root with the class ".red".
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
shadowDiv.classList.add("red");
|
||||
// Create empty stylesheet.
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
// Replace the stylesheet text that will color it red.
|
||||
sheet.replaceSync(redStyleTexts[0]);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
|
||||
sheet.insertRule(redStyleTexts[1]);
|
||||
assert_equals(sheet.cssRules.length, 2);
|
||||
assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
|
||||
}, 'CSSStyleSheet.replaceSync correctly updates the style of its adopters synchronously');
|
||||
|
||||
test(() => {
|
||||
// Attach a div inside a shadow root with the class ".red".
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
shadowDiv.classList.add("target");
|
||||
|
||||
// Create empty stylesheet.
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
|
||||
// Replace the stylesheet text that will color it red.
|
||||
sheet.replaceSync(".target { color: red; }");
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
|
||||
|
||||
// Create a style element that will set colors to white.
|
||||
const style = document.createElement("style");
|
||||
style.textContent = ".target { color: white; }";
|
||||
span.shadowRoot.appendChild(style)
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
|
||||
|
||||
span.shadowRoot.adoptedStyleSheets = [];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
|
||||
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
|
||||
|
||||
sheet.disabled = true;
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
|
||||
|
||||
sheet.disabled = false;
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again");
|
||||
}, 'Adopted sheets are ordered after non-adopted sheets in the shadow root')
|
||||
|
||||
test(() => {
|
||||
// Attach a div inside a shadow root with the class ".red".
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
span.classList.add("target");
|
||||
|
||||
// Create empty stylesheet.
|
||||
const sheet = new CSSStyleSheet();
|
||||
document.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(span).color, "rgb(0, 0, 0)");
|
||||
|
||||
// Replace the stylesheet text that will color it red.
|
||||
sheet.replaceSync(".target { color: red; }");
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)");
|
||||
|
||||
// Create a style element that will set colors to white.
|
||||
const style = document.createElement("style");
|
||||
style.textContent = ".target { color: white; }";
|
||||
span.appendChild(style)
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
|
||||
|
||||
document.adoptedStyleSheets = [];
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
|
||||
|
||||
document.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
|
||||
|
||||
sheet.disabled = true;
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
|
||||
|
||||
sheet.disabled = false;
|
||||
assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again")
|
||||
}, 'Adopted sheets are ordered after non-adopted sheets in the document')
|
||||
|
||||
const import_text = '@import url("support/constructable-import.css");';
|
||||
|
||||
test(() => {
|
||||
assert_throws_dom("SyntaxError", () => { (new CSSStyleSheet).insertRule(import_text) });
|
||||
}, 'Inserting an @import rule through insertRule on a constructed stylesheet throws an exception');
|
||||
|
||||
promise_test(t => {
|
||||
const importUrl = "support/constructable-import.css";
|
||||
const sheet = new CSSStyleSheet();
|
||||
|
||||
sheet.replaceSync(`@import url("${importUrl}");`);
|
||||
|
||||
const timeAfterReplaceSync = performance.now();
|
||||
let link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = importUrl;
|
||||
|
||||
return new Promise(resolve => {
|
||||
link.addEventListener("error", t.unreached_func("Load shouldn't fail"));
|
||||
link.addEventListener("load", t.step_func(() => {
|
||||
let entries = window.performance.getEntriesByType('resource').filter(entry => entry.name.includes(importUrl));
|
||||
assert_equals(entries.length, 1, "There should be only one entry for the import URL");
|
||||
assert_greater_than_equal(entries[0].startTime, timeAfterReplaceSync, "The entry's start time should be after replaceSync threw");
|
||||
link.remove();
|
||||
resolve();
|
||||
}));
|
||||
document.body.appendChild(link);
|
||||
});
|
||||
}, "CSSStyleSheet.replaceSync should not trigger any loads from @import rules")
|
||||
|
||||
promise_test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
// Replace and assert that the imported rule is NOT applied.
|
||||
const sheet_promise = sheet.replace(import_text);
|
||||
return sheet_promise.then((sheet) => {
|
||||
// replace() ignores @import rules:
|
||||
assert_equals(sheet.cssRules.length, 0);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
}).catch((reason) => {
|
||||
assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
|
||||
});
|
||||
}, 'CSSStyleSheet.replace allows, but ignores, import rule inside');
|
||||
|
||||
promise_test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const targetSpan = document.createElement("span");
|
||||
targetSpan.classList.add("target");
|
||||
shadowDiv.appendChild(targetSpan);
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
// Replace and assert that the imported rule is NOT applied, but regular rule does apply.
|
||||
const sheet_promise = sheet.replace(import_text + ".target { color: blue; }");
|
||||
return sheet_promise.then((sheet) => {
|
||||
assert_equals(sheet.cssRules.length, 1);
|
||||
// @import not applied:
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
// regular rule applied:
|
||||
assert_equals(getComputedStyle(targetSpan).color, "rgb(0, 0, 255)");
|
||||
}).catch((reason) => {
|
||||
assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
|
||||
});
|
||||
}, 'CSSStyleSheet.replace ignores @import rule but still loads other rules');
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
// Replace and assert that the imported rule is NOT applied.
|
||||
try {
|
||||
sheet.replaceSync(import_text);
|
||||
// replaceSync() ignores @import rules:
|
||||
assert_equals(sheet.cssRules.length, 0);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
} catch(reason) {
|
||||
assert_unreached(`replaceSync threw an exception (${reason}) when it shouldn't have`);
|
||||
}
|
||||
}, 'CSSStyleSheet.replaceSync allows, but ignores, import rule inside');
|
||||
|
||||
promise_test(() => {
|
||||
const sheet = new CSSStyleSheet();
|
||||
const sheet_promise = sheet.replace("@import url('not-there.css');");
|
||||
|
||||
return sheet_promise.then((sheet) => {
|
||||
// No exception here
|
||||
}).catch((reason) => {
|
||||
assert_unreached("Promise was rejected");
|
||||
});
|
||||
}, 'CSSStyleSheet.replace does not reject on failed imports');
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
|
||||
const newSpan = span.cloneNode(true);
|
||||
assert_equals(newSpan.shadowRoot, null);
|
||||
}, 'Cloning a shadow host will not clone shadow root, and also adoptedStyleSheets');
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
const newSpan = iframe.contentDocument.importNode(span, true);
|
||||
iframe.contentDocument.body.appendChild(newSpan);
|
||||
assert_equals(newSpan.shadowRoot, null);
|
||||
}, 'Importing a shadow host will not copy shadow root, and also adoptedStyleSheets');
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync("* { color: red; }");
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
|
||||
|
||||
document.adoptNode(span);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentDocument.adoptNode(span);
|
||||
iframe.contentDocument.body.appendChild(span);
|
||||
assert_not_equals(span.shadowRoot, null);
|
||||
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 0);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
const div = document.createElement("div");
|
||||
thirdSection.appendChild(span);
|
||||
span.appendChild(div);
|
||||
const shadowDiv = attachShadowDiv(div);
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync("* { color: red; }");
|
||||
div.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
|
||||
|
||||
document.adoptNode(span);
|
||||
assert_equals(div.shadowRoot.adoptedStyleSheets.length, 1);
|
||||
assert_equals(div.shadowRoot.adoptedStyleSheets[0], sheet);
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentDocument.adoptNode(span);
|
||||
iframe.contentDocument.body.appendChild(span);
|
||||
assert_not_equals(div.shadowRoot, null);
|
||||
assert_equals(div.shadowRoot.adoptedStyleSheets.length, 0);
|
||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||
}, `Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document`);
|
||||
|
||||
test(() => {
|
||||
const host = document.createElement("div");
|
||||
const root = host.attachShadow({mode: "open"});
|
||||
root.adoptedStyleSheets = [new CSSStyleSheet()];
|
||||
document.body.offsetTop;
|
||||
}, 'Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.');
|
||||
|
||||
test(() => {
|
||||
const host = document.createElement("div");
|
||||
thirdSection.appendChild(host);
|
||||
const root = host.attachShadow({mode: "open"});
|
||||
const sheet = new CSSStyleSheet();
|
||||
root.adoptedStyleSheets = [sheet];
|
||||
host.remove();
|
||||
sheet.replaceSync('');
|
||||
}, 'Modifying an adopted stylesheet on a disconnected shadow root should not crash.');
|
||||
|
||||
function currentLocation() {
|
||||
const sections = location.href.split("/")
|
||||
sections.pop();
|
||||
return sections.join("/");
|
||||
}
|
||||
|
||||
test(() => {
|
||||
const span = document.createElement("span");
|
||||
thirdSection.appendChild(span);
|
||||
const shadowDiv = attachShadowDiv(span);
|
||||
|
||||
const fileName = "example.png"
|
||||
const fullPath = `${currentLocation()}/${fileName}`
|
||||
|
||||
const sheet = new CSSStyleSheet();
|
||||
span.shadowRoot.adoptedStyleSheets = [sheet];
|
||||
|
||||
sheet.replaceSync(`* { background-image: url("${fileName}"); }`);
|
||||
const styleFromRelative = getComputedStyle(shadowDiv).backgroundImage;
|
||||
|
||||
sheet.replaceSync(`* { background-image: url("${fullPath}"); }`);
|
||||
const styleFromFull = getComputedStyle(shadowDiv).backgroundImage;
|
||||
|
||||
assert_equals(styleFromRelative, styleFromFull);
|
||||
}, "Constructing a sheet with the default base URL uses the constructor document's base URL for CSS rules");
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue