Bug 1600624 - Fix import rules to properly unlink their stylesheet from its parent. r=heycam

Test is hopefully self-explanatory. The children setup here is a bit bogus as
noted here and other comments, will file a followup to clean it up.

Differential Revision: https://phabricator.services.mozilla.com/D55550

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-12-03 10:43:57 +00:00
Родитель 5ccf884103
Коммит 912559b8d2
5 изменённых файлов: 63 добавлений и 0 удалений

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

@ -76,6 +76,13 @@ dom::MediaList* CSSImportRule::GetMedia() const {
return mChildSheet ? mChildSheet->Media() : nullptr;
}
void CSSImportRule::DropSheetReference() {
if (mChildSheet) {
mChildSheet->RemoveFromParent();
}
Rule::DropSheetReference();
}
void CSSImportRule::GetHref(nsAString& aHref) const {
Servo_ImportRule_GetHref(mRawRule, &aHref);
}

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

@ -38,6 +38,9 @@ class CSSImportRule final : public css::Rule {
dom::MediaList* GetMedia() const;
StyleSheet* GetStyleSheet() const { return mChildSheet; }
// Clear the mSheet pointer on this rule and descendants.
void DropSheetReference() final;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;

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

@ -664,6 +664,36 @@ uint64_t StyleSheet::FindOwningWindowInnerID() const {
return windowID;
}
void StyleSheet::RemoveFromParent() {
if (!mParent) {
return;
}
// TODO(emilio): It seems we should actually use mozilla::LinkedList or such
// for this.
//
// Also this is still pretty bogus, see where we declare mFirstChild in
// StyleSheetInfo.
bool found = false;
for (auto* child = mParent->GetFirstChild(); child; child = child->mNext) {
if (child == this) {
// We can only get here if we're the first.
found = true;
mParent->Inner().mFirstChild = mNext;
break;
}
if (child->mNext == this) {
found = true;
child->mNext = mNext;
break;
}
}
MOZ_DIAGNOSTIC_ASSERT(found, "Should find the rule in the child list.");
mParent = nullptr;
ClearAssociatedDocumentOrShadowRoot();
mNext = nullptr;
}
void StyleSheet::UnparentChildren() {
// XXXbz this is a little bogus; see the XXX comment where we
// declare mFirstChild in StyleSheetInfo.

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

@ -396,6 +396,9 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
// This is true for any User Agent sheets once they are complete.
bool IsReadOnly() const;
// Removes a stylesheet from its parent sheet child list, if any.
void RemoveFromParent();
private:
// Returns the ShadowRoot that contains this stylesheet or our ancestor
// stylesheet, if any.

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

@ -0,0 +1,20 @@
<!doctype html>
<title>CSSImportRule correctly unlinks its child stylesheet from its parent</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/cssom/#the-cssimportrule-interface">
<style>
@import "data:text/css,:root{background:red}";
</style>
<script>
let t = async_test("@import stylesheet is properly unlinked from parent after removal");
window.onload = t.step_func_done(function() {
let sheet = document.styleSheets[0];
let childSheet = sheet.cssRules[0].styleSheet;
assert_not_equals(childSheet, null, "@import rule should have a stylesheet");
assert_equals(childSheet.parentStyleSheet, sheet, "@import rule should the correct parent");
sheet.deleteRule(0);
assert_equals(childSheet.parentStyleSheet, null, "@import rule should be correctly unlinked");
});
</script>