Bug 1737455 - Don't clear adoptedStyleSheets when adopting from a template document to its owner or vice versa. r=edgar

See https://github.com/WICG/construct-stylesheets/issues/133, which is
where this change was discussed (and then made to Chromium apparently).

I filed https://github.com/w3c/csswg-drafts/issues/7229 to put some
actual spec text here. Also, tweak the wpt which is supposed to test so
that it fails without this change.

Differential Revision: https://phabricator.services.mozilla.com/D144564
This commit is contained in:
Emilio Cobos Álvarez 2022-04-26 17:31:23 +00:00
Родитель 3bb799fbce
Коммит 0bc8695c2a
7 изменённых файлов: 36 добавлений и 24 удалений

Просмотреть файл

@ -2889,6 +2889,10 @@ class Document : public nsINode,
*/
Document* GetTemplateContentsOwner();
Document* GetTemplateContentsOwnerIfExists() const {
return mTemplateContentsOwner.get();
}
/**
* Returns true if this document is a static clone of a normal document.
*

Просмотреть файл

@ -620,11 +620,6 @@ int32_t DocumentOrShadowRoot::StyleOrderIndexOfSheet(
return mStyleSheets.IndexOf(&aSheet);
}
void DocumentOrShadowRoot::GetAdoptedStyleSheets(
nsTArray<RefPtr<StyleSheet>>& aAdoptedStyleSheets) const {
aAdoptedStyleSheets = mAdoptedStyleSheets.Clone();
}
void DocumentOrShadowRoot::TraverseSheetRefInStylesIfApplicable(
StyleSheet& aSheet, nsCycleCollectionTraversalCallback& cb) {
if (!aSheet.IsApplicable()) {

Просмотреть файл

@ -89,8 +89,6 @@ class DocumentOrShadowRoot : public RadioGroupManager {
StyleSheetList* StyleSheets();
void GetAdoptedStyleSheets(nsTArray<RefPtr<StyleSheet>>&) const;
void RemoveStyleSheet(StyleSheet&);
Element* GetElementById(const nsAString& aElementId);

Просмотреть файл

@ -101,6 +101,17 @@ JSObject* ShadowRoot::WrapNode(JSContext* aCx,
return mozilla::dom::ShadowRoot_Binding::Wrap(aCx, this, aGivenProto);
}
void ShadowRoot::NodeInfoChanged(Document* aOldDoc) {
DocumentFragment::NodeInfoChanged(aOldDoc);
Document* newDoc = OwnerDoc();
const bool fromOrToTemplate =
aOldDoc->GetTemplateContentsOwnerIfExists() == newDoc ||
newDoc->GetTemplateContentsOwnerIfExists() == aOldDoc;
if (!fromOrToTemplate) {
ClearAdoptedStyleSheets();
}
}
void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) {
if (aOther->IsUAWidget()) {
SetIsUAWidget();

Просмотреть файл

@ -185,10 +185,7 @@ class ShadowRoot final : public DocumentFragment,
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) final;
void NodeInfoChanged(Document* aOldDoc) override {
DocumentFragment::NodeInfoChanged(aOldDoc);
ClearAdoptedStyleSheets();
}
void NodeInfoChanged(Document* aOldDoc) override;
void AddToIdTable(Element* aElement, nsAtom* aId);
void RemoveFromIdTable(Element* aElement, nsAtom* aId);

Просмотреть файл

@ -1,4 +0,0 @@
[CSSStyleSheet-template-adoption.html]
[adoptedStyleSheets won'te be cleared when adopting into/from <template>s]
expected: FAIL

Просмотреть файл

@ -13,30 +13,41 @@
<script>
test(function() {
let sheet = new CSSStyleSheet();
sheet.replaceSync("div { color: red }");
sheet.replaceSync("div { color: blue }");
let host = document.getElementById("host");
let root = host.attachShadow({ mode: "open" });
root.innerHTML = `<div></div>`;
root.adoptedStyleSheets = [sheet];
assert_equals(root.adoptedStyleSheets.length, 1);
assert_equals(root.adoptedStyleSheets[0], sheet);
function assertAdoptedStyleSheet() {
assert_equals(host.ownerDocument, root.firstChild.ownerDocument, "Shadow root was not adopted?");
assert_equals(root.adoptedStyleSheets.length, 1);
assert_equals(root.adoptedStyleSheets[0], sheet);
if (root.ownerDocument == document) {
assert_equals(getComputedStyle(root.firstChild).color, "rgb(0, 0, 255)", "Sheet should apply");
}
}
assertAdoptedStyleSheet();
// adoptedStyleSheets is not cleared when adopted into a <template>.
const template = document.getElementById("template");
template.content.appendChild(host);
assert_equals(root.adoptedStyleSheets.length, 1);
assert_equals(root.adoptedStyleSheets[0], sheet);
assert_not_equals(host.ownerDocument, document, "Should've been adopted");
assertAdoptedStyleSheet();
// adoptedStyleSheets is not cleared when adopted back in the main document.
document.body.appendChild(host);
assert_equals(root.adoptedStyleSheets.length, 1);
assert_equals(root.adoptedStyleSheets[0], sheet);
assert_equals(host.ownerDocument, document, "Should've been re-adopted");
assertAdoptedStyleSheet();
// adoptedStyleSheets is not cleared when adopted into a nested <template>.
const nested_template = template.content.firstElementChild;
nested_template.content.appendChild(host);
assert_equals(root.adoptedStyleSheets.length, 1);
assert_equals(root.adoptedStyleSheets[0], sheet);
assert_not_equals(host.ownerDocument, document, "Should've been adopted");
assertAdoptedStyleSheet();
// adoptedStyleSheets is cleared when adopted into an <iframe>.
const iframe = document.createElement("iframe");