forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			526 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			526 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| /*
 | |
|  * A base class which implements nsIStyleSheetLinkingElement and can
 | |
|  * be subclassed by various content nodes that want to load
 | |
|  * stylesheets (<style>, <link>, processing instructions, etc).
 | |
|  */
 | |
| 
 | |
| #include "nsStyleLinkElement.h"
 | |
| 
 | |
| #include "mozilla/StyleSheetHandle.h"
 | |
| #include "mozilla/StyleSheetHandleInlines.h"
 | |
| #include "mozilla/css/Loader.h"
 | |
| #include "mozilla/dom/Element.h"
 | |
| #include "mozilla/dom/FragmentOrElement.h"
 | |
| #include "mozilla/dom/HTMLLinkElement.h"
 | |
| #include "mozilla/dom/ShadowRoot.h"
 | |
| #include "mozilla/dom/SRILogHelper.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsIDocument.h"
 | |
| #include "nsIDOMComment.h"
 | |
| #include "nsIDOMNode.h"
 | |
| #include "nsIDOMStyleSheet.h"
 | |
| #include "nsUnicharUtils.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsXPCOMCIDInternal.h"
 | |
| #include "nsUnicharInputStream.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsStyleUtil.h"
 | |
| #include "nsQueryObject.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| nsStyleLinkElement::nsStyleLinkElement()
 | |
|   : mDontLoadStyle(false)
 | |
|   , mUpdatesEnabled(true)
 | |
|   , mLineNumber(1)
 | |
| {
 | |
| }
 | |
| 
 | |
| nsStyleLinkElement::~nsStyleLinkElement()
 | |
| {
 | |
|   nsStyleLinkElement::SetStyleSheet(nullptr);
 | |
| }
 | |
| 
 | |
| void
 | |
| nsStyleLinkElement::Unlink()
 | |
| {
 | |
|   nsStyleLinkElement::SetStyleSheet(nullptr);
 | |
| }
 | |
| 
 | |
| void
 | |
| nsStyleLinkElement::Traverse(nsCycleCollectionTraversalCallback &cb)
 | |
| {
 | |
|   nsStyleLinkElement* tmp = this;
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheet);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP 
 | |
| nsStyleLinkElement::SetStyleSheet(StyleSheetHandle aStyleSheet)
 | |
| {
 | |
|   if (mStyleSheet) {
 | |
|     mStyleSheet->SetOwningNode(nullptr);
 | |
|   }
 | |
| 
 | |
|   mStyleSheet = aStyleSheet;
 | |
|   if (mStyleSheet) {
 | |
|     nsCOMPtr<nsINode> node = do_QueryObject(this);
 | |
|     if (node) {
 | |
|       mStyleSheet->SetOwningNode(node);
 | |
|     }
 | |
|   }
 | |
|     
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP_(StyleSheetHandle)
 | |
| nsStyleLinkElement::GetStyleSheet()
 | |
| {
 | |
|   return mStyleSheet;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP 
 | |
| nsStyleLinkElement::InitStyleLinkElement(bool aDontLoadStyle)
 | |
| {
 | |
|   mDontLoadStyle = aDontLoadStyle;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsStyleLinkElement::SetEnableUpdates(bool aEnableUpdates)
 | |
| {
 | |
|   mUpdatesEnabled = aEnableUpdates;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsStyleLinkElement::GetCharset(nsAString& aCharset)
 | |
| {
 | |
|   // descendants have to implement this themselves
 | |
|   return NS_ERROR_NOT_IMPLEMENTED;
 | |
| }
 | |
| 
 | |
| /* virtual */ void
 | |
| nsStyleLinkElement::OverrideBaseURI(nsIURI* aNewBaseURI)
 | |
| {
 | |
|   NS_NOTREACHED("Base URI can't be overriden in this implementation "
 | |
|                 "of nsIStyleSheetLinkingElement.");
 | |
| }
 | |
| 
 | |
| /* virtual */ void
 | |
| nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
 | |
| {
 | |
|   mLineNumber = aLineNumber;
 | |
| }
 | |
| 
 | |
| /* virtual */ uint32_t
 | |
| nsStyleLinkElement::GetLineNumber()
 | |
| {
 | |
|   return mLineNumber;
 | |
| }
 | |
| 
 | |
| /* static */ bool
 | |
| nsStyleLinkElement::IsImportEnabled()
 | |
| {
 | |
|   static bool sAdded = false;
 | |
|   static bool sImportsEnabled;
 | |
|   if (!sAdded) {
 | |
|     // This part runs only once because of the static flag.
 | |
|     Preferences::AddBoolVarCache(&sImportsEnabled,
 | |
|                                  "dom.htmlimports.enabled",
 | |
|                                  false);
 | |
|     sAdded = true;
 | |
|   }
 | |
| 
 | |
|   return sImportsEnabled;
 | |
| }
 | |
| 
 | |
| static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
 | |
| {
 | |
|   // Keep this in sync with sRelValues in HTMLLinkElement.cpp
 | |
|   if (aLink.EqualsLiteral("prefetch"))
 | |
|     return nsStyleLinkElement::ePREFETCH;
 | |
|   else if (aLink.EqualsLiteral("dns-prefetch"))
 | |
|     return nsStyleLinkElement::eDNS_PREFETCH;
 | |
|   else if (aLink.EqualsLiteral("stylesheet"))
 | |
|     return nsStyleLinkElement::eSTYLESHEET;
 | |
|   else if (aLink.EqualsLiteral("next"))
 | |
|     return nsStyleLinkElement::eNEXT;
 | |
|   else if (aLink.EqualsLiteral("alternate"))
 | |
|     return nsStyleLinkElement::eALTERNATE;
 | |
|   else if (aLink.EqualsLiteral("import") &&
 | |
|            nsStyleLinkElement::IsImportEnabled())
 | |
|     return nsStyleLinkElement::eHTMLIMPORT;
 | |
|   else if (aLink.EqualsLiteral("preconnect"))
 | |
|     return nsStyleLinkElement::ePRECONNECT;
 | |
|   else 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| uint32_t nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes, nsIPrincipal* aPrincipal)
 | |
| {
 | |
|   uint32_t linkMask = 0;
 | |
|   nsAString::const_iterator start, done;
 | |
|   aTypes.BeginReading(start);
 | |
|   aTypes.EndReading(done);
 | |
|   if (start == done)
 | |
|     return linkMask;
 | |
| 
 | |
|   nsAString::const_iterator current(start);
 | |
|   bool inString = !nsContentUtils::IsHTMLWhitespace(*current);
 | |
|   nsAutoString subString;
 | |
|   
 | |
|   while (current != done) {
 | |
|     if (nsContentUtils::IsHTMLWhitespace(*current)) {
 | |
|       if (inString) {
 | |
|         nsContentUtils::ASCIIToLower(Substring(start, current), subString);
 | |
|         linkMask |= ToLinkMask(subString, aPrincipal);
 | |
|         inString = false;
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       if (!inString) {
 | |
|         start = current;
 | |
|         inString = true;
 | |
|       }
 | |
|     }
 | |
|     ++current;
 | |
|   }
 | |
|   if (inString) {
 | |
|     nsContentUtils::ASCIIToLower(Substring(start, current), subString);
 | |
|     linkMask |= ToLinkMask(subString, aPrincipal);
 | |
|   }
 | |
|   return linkMask;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
 | |
|                                      bool* aWillNotify,
 | |
|                                      bool* aIsAlternate,
 | |
|                                      bool aForceReload)
 | |
| {
 | |
|   if (aForceReload) {
 | |
|     // We remove this stylesheet from the cache to load a new version.
 | |
|     nsCOMPtr<nsIContent> thisContent;
 | |
|     CallQueryInterface(this, getter_AddRefs(thisContent));
 | |
|     nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
 | |
|       thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
 | |
|     if (doc && doc->CSSLoader()->GetEnabled() &&
 | |
|         mStyleSheet && !mStyleSheet->IsInline()) {
 | |
|       doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
 | |
|     }
 | |
|   }
 | |
|   return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aWillNotify,
 | |
|                             aIsAlternate, aForceReload);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
 | |
|                                              ShadowRoot *aOldShadowRoot,
 | |
|                                              bool aForceUpdate)
 | |
| {
 | |
|   bool notify, alternate;
 | |
|   return DoUpdateStyleSheet(aOldDocument, aOldShadowRoot, nullptr, ¬ify,
 | |
|                             &alternate, aForceUpdate);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| IsScopedStyleElement(nsIContent* aContent)
 | |
| {
 | |
|   // This is quicker than, say, QIing aContent to nsStyleLinkElement
 | |
|   // and then calling its virtual GetStyleSheetInfo method to find out
 | |
|   // if it is scoped.
 | |
|   return (aContent->IsHTMLElement(nsGkAtoms::style) ||
 | |
|           aContent->IsSVGElement(nsGkAtoms::style)) &&
 | |
|          aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| HasScopedStyleSheetChild(nsIContent* aContent)
 | |
| {
 | |
|   for (nsIContent* n = aContent->GetFirstChild(); n; n = n->GetNextSibling()) {
 | |
|     if (IsScopedStyleElement(n)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| // Called when aElement has had a <style scoped> child removed.
 | |
| static void
 | |
| UpdateIsElementInStyleScopeFlagOnSubtree(Element* aElement)
 | |
| {
 | |
|   NS_ASSERTION(aElement->IsElementInStyleScope(),
 | |
|                "only call UpdateIsElementInStyleScopeFlagOnSubtree on a "
 | |
|                "subtree that has IsElementInStyleScope boolean flag set");
 | |
| 
 | |
|   if (HasScopedStyleSheetChild(aElement)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aElement->ClearIsElementInStyleScope();
 | |
| 
 | |
|   nsIContent* n = aElement->GetNextNode(aElement);
 | |
|   while (n) {
 | |
|     if (HasScopedStyleSheetChild(n)) {
 | |
|       n = n->GetNextNonChildNode(aElement);
 | |
|     } else {
 | |
|       if (n->IsElement()) {
 | |
|         n->ClearIsElementInStyleScope();
 | |
|       }
 | |
|       n = n->GetNextNode(aElement);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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;
 | |
|   }
 | |
| 
 | |
|   // XXXheycam ServoStyleSheets do not support <style scoped>.
 | |
|   Element* oldScopeElement = nullptr;
 | |
|   if (mStyleSheet) {
 | |
|     if (mStyleSheet->IsServo()) {
 | |
|       NS_WARNING("stylo: ServoStyleSheets don't support <style scoped>");
 | |
|     } else {
 | |
|       oldScopeElement = mStyleSheet->AsGecko()->GetScopeElement();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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, fallible)) {
 | |
|       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 {
 | |
|     nsAutoString integrity;
 | |
|     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
 | |
|     if (!integrity.IsEmpty()) {
 | |
|       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
 | |
|               ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
 | |
|                NS_ConvertUTF16toUTF8(integrity).get()));
 | |
|     }
 | |
| 
 | |
|     // if referrer attributes are enabled in preferences, load the link's referrer
 | |
|     // attribute. If the link does not provide a referrer attribute, ignore this
 | |
|     // and use the document's referrer policy
 | |
| 
 | |
|     net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
 | |
|     if (referrerPolicy == net::RP_Unset) {
 | |
|       referrerPolicy = doc->GetReferrerPolicy();
 | |
|     }
 | |
| 
 | |
|     // 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(), referrerPolicy, integrity,
 | |
|                     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;
 | |
| }
 | |
| 
 | |
| 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);
 | |
|   }
 | |
| }
 | 
