void nsStyleLinkElement::UpdateStyleSheetScopedness(bool aIsNowScoped) { if (!mStyleSheet) { return; } if (mStyleSheet->IsServo()) { // XXXheycam ServoStyleSheets don't support <style scoped>. NS_ERROR("stylo: ServoStyleSheets don't support <style scoped>"); return; } CSSStyleSheet* sheet = mStyleSheet->AsGecko(); nsCOMPtr<nsIContent> thisContent; CallQueryInterface(this, getter_AddRefs(thisContent)); Element* oldScopeElement = sheet->GetScopeElement(); Element* newScopeElement = aIsNowScoped ? thisContent->GetParentElement() : nullptr; if (oldScopeElement == newScopeElement) { return; } nsIDocument* document = thisContent->GetOwnerDocument(); if (thisContent->IsInShadowTree()) { ShadowRoot* containingShadow = thisContent->GetContainingShadow(); containingShadow->RemoveSheet(mStyleSheet); sheet->SetScopeElement(newScopeElement); containingShadow->InsertSheet(mStyleSheet, thisContent); } else { document->BeginUpdate(UPDATE_STYLE); document->RemoveStyleSheet(mStyleSheet); sheet->SetScopeElement(newScopeElement); document->AddStyleSheet(mStyleSheet); document->EndUpdate(UPDATE_STYLE); } if (oldScopeElement) { UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement); } if (newScopeElement) { newScopeElement->SetIsElementInStyleScopeFlagOnSubtree(true); } }
void nsStyleLinkElement::UpdateStyleSheetScopedness(bool aIsNowScoped) { if (!mStyleSheet) { return; } nsCOMPtr<nsIContent> thisContent; CallQueryInterface(this, getter_AddRefs(thisContent)); Element* oldScopeElement = mStyleSheet->GetScopeElement(); Element* newScopeElement = aIsNowScoped ? thisContent->GetParentElement() : nullptr; if (oldScopeElement == newScopeElement) { return; } nsIDocument* document = thisContent->GetOwnerDocument(); if (thisContent->HasFlag(NODE_IS_IN_SHADOW_TREE)) { ShadowRoot* containingShadow = thisContent->GetContainingShadow(); containingShadow->RemoveSheet(mStyleSheet); mStyleSheet->SetScopeElement(newScopeElement); containingShadow->InsertSheet(mStyleSheet, thisContent); } else { document->BeginUpdate(UPDATE_STYLE); document->RemoveStyleSheet(mStyleSheet); mStyleSheet->SetScopeElement(newScopeElement); document->AddStyleSheet(mStyleSheet); document->EndUpdate(UPDATE_STYLE); } if (oldScopeElement) { UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement); } if (newScopeElement) { SetIsElementInStyleScopeFlagOnSubtree(newScopeElement); } }
nsresult nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument, ShadowRoot* aOldShadowRoot, nsICSSLoaderObserver* aObserver, bool* aWillNotify, bool* aIsAlternate, bool aForceUpdate) { *aWillNotify = false; nsCOMPtr<nsIContent> thisContent; CallQueryInterface(this, getter_AddRefs(thisContent)); // All instances of nsStyleLinkElement should implement nsIContent. NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE); if (thisContent->IsInAnonymousSubtree() && thisContent->IsAnonymousContentInSVGUseSubtree()) { // Stylesheets in <use>-cloned subtrees are disabled until we figure out // how they should behave. return NS_OK; } // Check for a ShadowRoot because link elements are inert in a // ShadowRoot. ShadowRoot* containingShadow = thisContent->GetContainingShadow(); if (thisContent->IsHTMLElement(nsGkAtoms::link) && (aOldShadowRoot || containingShadow)) { return NS_OK; } Element* oldScopeElement = GetScopeElement(mStyleSheet); if (mStyleSheet && (aOldDocument || aOldShadowRoot)) { MOZ_ASSERT(!(aOldDocument && aOldShadowRoot), "ShadowRoot content is never in document, thus " "there should not be a old document and old " "ShadowRoot simultaneously."); // We're removing the link element from the document or shadow tree, // unload the stylesheet. We want to do this even if updates are // disabled, since otherwise a sheet with a stale linking element pointer // will be hanging around -- not good! if (aOldShadowRoot) { aOldShadowRoot->RemoveSheet(mStyleSheet); } else { aOldDocument->BeginUpdate(UPDATE_STYLE); aOldDocument->RemoveStyleSheet(mStyleSheet); aOldDocument->EndUpdate(UPDATE_STYLE); } nsStyleLinkElement::SetStyleSheet(nullptr); if (oldScopeElement) { UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement); } } // When static documents are created, stylesheets are cloned manually. if (mDontLoadStyle || !mUpdatesEnabled || thisContent->OwnerDoc()->IsStaticDocument()) { return NS_OK; } nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ? thisContent->OwnerDoc() : thisContent->GetUncomposedDoc(); if (!doc || !doc->CSSLoader()->GetEnabled()) { return NS_OK; } bool isInline; nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline); if (!aForceUpdate && mStyleSheet && !isInline && uri) { nsIURI* oldURI = mStyleSheet->GetSheetURI(); if (oldURI) { bool equal; nsresult rv = oldURI->Equals(uri, &equal); if (NS_SUCCEEDED(rv) && equal) { return NS_OK; // We already loaded this stylesheet } } } if (mStyleSheet) { if (thisContent->IsInShadowTree()) { ShadowRoot* containingShadow = thisContent->GetContainingShadow(); containingShadow->RemoveSheet(mStyleSheet); } else { doc->BeginUpdate(UPDATE_STYLE); doc->RemoveStyleSheet(mStyleSheet); doc->EndUpdate(UPDATE_STYLE); } nsStyleLinkElement::SetStyleSheet(nullptr); } if (!uri && !isInline) { return NS_OK; // If href is empty and this is not inline style then just bail } nsAutoString title, type, media; bool isScoped; bool isAlternate; GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate); if (!type.LowerCaseEqualsLiteral("text/css")) { return NS_OK; } Element* scopeElement = isScoped ? thisContent->GetParentElement() : nullptr; if (scopeElement) { NS_ASSERTION(isInline, "non-inline style must not have scope element"); scopeElement->SetIsElementInStyleScopeFlagOnSubtree(true); } bool doneLoading = false; nsresult rv = NS_OK; if (isInline) { nsAutoString text; if (!nsContentUtils::GetNodeTextContent(thisContent, false, text)) { return NS_ERROR_OUT_OF_MEMORY; } MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link, "<link> is not 'inline', and needs different CSP checks"); if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent, thisContent->NodePrincipal(), doc->GetDocumentURI(), mLineNumber, text, &rv)) return rv; // Parse the style sheet. rv = doc->CSSLoader()-> LoadInlineStyle(thisContent, text, mLineNumber, title, media, scopeElement, aObserver, &doneLoading, &isAlternate); } else { // XXXbz clone the URI here to work around content policies modifying URIs. nsCOMPtr<nsIURI> clonedURI; uri->Clone(getter_AddRefs(clonedURI)); NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY); rv = doc->CSSLoader()-> LoadStyleLink(thisContent, clonedURI, title, media, isAlternate, GetCORSMode(), doc->GetReferrerPolicy(), aObserver, &isAlternate); if (NS_FAILED(rv)) { // Don't propagate LoadStyleLink() errors further than this, since some // consumers (e.g. nsXMLContentSink) will completely abort on innocuous // things like a stylesheet load being blocked by the security system. doneLoading = true; isAlternate = false; rv = NS_OK; } } NS_ENSURE_SUCCESS(rv, rv); *aWillNotify = !doneLoading; *aIsAlternate = isAlternate; return NS_OK; }