Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * A base class which implements nsIStyleSheetLinkingElement and can
9 : * be subclassed by various content nodes that want to load
10 : * stylesheets (<style>, <link>, processing instructions, etc).
11 : */
12 :
13 : #include "nsStyleLinkElement.h"
14 :
15 : #include "mozilla/StyleSheet.h"
16 : #include "mozilla/StyleSheetInlines.h"
17 : #include "mozilla/css/Loader.h"
18 : #include "mozilla/dom/Element.h"
19 : #include "mozilla/dom/FragmentOrElement.h"
20 : #include "mozilla/dom/HTMLLinkElement.h"
21 : #include "mozilla/dom/ShadowRoot.h"
22 : #include "mozilla/dom/SRILogHelper.h"
23 : #include "mozilla/Preferences.h"
24 : #include "nsIContent.h"
25 : #include "nsIDocument.h"
26 : #include "nsIDOMComment.h"
27 : #include "nsIDOMNode.h"
28 : #include "nsIDOMStyleSheet.h"
29 : #include "nsUnicharUtils.h"
30 : #include "nsCRT.h"
31 : #include "nsXPCOMCIDInternal.h"
32 : #include "nsUnicharInputStream.h"
33 : #include "nsContentUtils.h"
34 : #include "nsStyleUtil.h"
35 : #include "nsQueryObject.h"
36 : #include "nsIContentPolicyBase.h"
37 : #include "nsMimeTypes.h"
38 : #include "imgLoader.h"
39 : #include "MediaContainerType.h"
40 : #include "DecoderDoctorDiagnostics.h"
41 : #include "DecoderTraits.h"
42 : #include "MediaList.h"
43 : #include "nsAttrValueInlines.h"
44 :
45 : using namespace mozilla;
46 : using namespace mozilla::dom;
47 :
48 11 : nsStyleLinkElement::nsStyleLinkElement()
49 : : mDontLoadStyle(false)
50 : , mUpdatesEnabled(true)
51 11 : , mLineNumber(1)
52 : {
53 11 : }
54 :
55 0 : nsStyleLinkElement::~nsStyleLinkElement()
56 : {
57 0 : nsStyleLinkElement::SetStyleSheet(nullptr);
58 0 : }
59 :
60 : void
61 0 : nsStyleLinkElement::Unlink()
62 : {
63 0 : nsStyleLinkElement::SetStyleSheet(nullptr);
64 0 : }
65 :
66 : void
67 0 : nsStyleLinkElement::Traverse(nsCycleCollectionTraversalCallback &cb)
68 : {
69 0 : nsStyleLinkElement* tmp = this;
70 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheet);
71 0 : }
72 :
73 : NS_IMETHODIMP
74 11 : nsStyleLinkElement::SetStyleSheet(StyleSheet* aStyleSheet)
75 : {
76 11 : if (mStyleSheet) {
77 0 : mStyleSheet->SetOwningNode(nullptr);
78 : }
79 :
80 11 : mStyleSheet = aStyleSheet;
81 11 : if (mStyleSheet) {
82 22 : nsCOMPtr<nsINode> node = do_QueryObject(this);
83 11 : if (node) {
84 11 : mStyleSheet->SetOwningNode(node);
85 : }
86 : }
87 :
88 11 : return NS_OK;
89 : }
90 :
91 : NS_IMETHODIMP_(StyleSheet*)
92 0 : nsStyleLinkElement::GetStyleSheet()
93 : {
94 0 : return mStyleSheet;
95 : }
96 :
97 : NS_IMETHODIMP
98 11 : nsStyleLinkElement::InitStyleLinkElement(bool aDontLoadStyle)
99 : {
100 11 : mDontLoadStyle = aDontLoadStyle;
101 :
102 11 : return NS_OK;
103 : }
104 :
105 : NS_IMETHODIMP
106 22 : nsStyleLinkElement::SetEnableUpdates(bool aEnableUpdates)
107 : {
108 22 : mUpdatesEnabled = aEnableUpdates;
109 :
110 22 : return NS_OK;
111 : }
112 :
113 : NS_IMETHODIMP
114 0 : nsStyleLinkElement::GetCharset(nsAString& aCharset)
115 : {
116 : // descendants have to implement this themselves
117 0 : return NS_ERROR_NOT_IMPLEMENTED;
118 : }
119 :
120 : /* virtual */ void
121 0 : nsStyleLinkElement::OverrideBaseURI(nsIURI* aNewBaseURI)
122 : {
123 0 : NS_NOTREACHED("Base URI can't be overriden in this implementation "
124 : "of nsIStyleSheetLinkingElement.");
125 0 : }
126 :
127 : /* virtual */ void
128 5 : nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
129 : {
130 5 : mLineNumber = aLineNumber;
131 5 : }
132 :
133 : /* virtual */ uint32_t
134 0 : nsStyleLinkElement::GetLineNumber()
135 : {
136 0 : return mLineNumber;
137 : }
138 :
139 0 : static uint32_t ToLinkMask(const nsAString& aLink)
140 : {
141 : // Keep this in sync with sRelValues in HTMLLinkElement.cpp
142 0 : if (aLink.EqualsLiteral("prefetch"))
143 0 : return nsStyleLinkElement::ePREFETCH;
144 0 : else if (aLink.EqualsLiteral("dns-prefetch"))
145 0 : return nsStyleLinkElement::eDNS_PREFETCH;
146 0 : else if (aLink.EqualsLiteral("stylesheet"))
147 0 : return nsStyleLinkElement::eSTYLESHEET;
148 0 : else if (aLink.EqualsLiteral("next"))
149 0 : return nsStyleLinkElement::eNEXT;
150 0 : else if (aLink.EqualsLiteral("alternate"))
151 0 : return nsStyleLinkElement::eALTERNATE;
152 0 : else if (aLink.EqualsLiteral("preconnect"))
153 0 : return nsStyleLinkElement::ePRECONNECT;
154 0 : else if (aLink.EqualsLiteral("preload"))
155 0 : return nsStyleLinkElement::ePRELOAD;
156 0 : else if (aLink.EqualsLiteral("prerender"))
157 0 : return nsStyleLinkElement::ePRERENDER;
158 : else
159 0 : return 0;
160 : }
161 :
162 0 : uint32_t nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes)
163 : {
164 0 : uint32_t linkMask = 0;
165 0 : nsAString::const_iterator start, done;
166 0 : aTypes.BeginReading(start);
167 0 : aTypes.EndReading(done);
168 0 : if (start == done)
169 0 : return linkMask;
170 :
171 0 : nsAString::const_iterator current(start);
172 0 : bool inString = !nsContentUtils::IsHTMLWhitespace(*current);
173 0 : nsAutoString subString;
174 :
175 0 : while (current != done) {
176 0 : if (nsContentUtils::IsHTMLWhitespace(*current)) {
177 0 : if (inString) {
178 0 : nsContentUtils::ASCIIToLower(Substring(start, current), subString);
179 0 : linkMask |= ToLinkMask(subString);
180 0 : inString = false;
181 : }
182 : }
183 : else {
184 0 : if (!inString) {
185 0 : start = current;
186 0 : inString = true;
187 : }
188 : }
189 0 : ++current;
190 : }
191 0 : if (inString) {
192 0 : nsContentUtils::ASCIIToLower(Substring(start, current), subString);
193 0 : linkMask |= ToLinkMask(subString);
194 : }
195 0 : return linkMask;
196 : }
197 :
198 : // We will use official mime-types from:
199 : // https://www.iana.org/assignments/media-types/media-types.xhtml#font
200 : // We do not support old deprecated mime-types for preload feature.
201 : // (We currectly do not support font/collection)
202 : static uint32_t StyleLinkElementFontMimeTypesNum = 5;
203 : static const char* StyleLinkElementFontMimeTypes[] = {
204 : "font/otf",
205 : "font/sfnt",
206 : "font/ttf",
207 : "font/woff",
208 : "font/woff2"
209 : };
210 :
211 : bool
212 0 : IsFontMimeType(const nsAString& aType)
213 : {
214 0 : if (aType.IsEmpty()) {
215 0 : return true;
216 : }
217 0 : for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) {
218 0 : if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) {
219 0 : return true;
220 : }
221 : }
222 0 : return false;
223 : }
224 :
225 : bool
226 0 : nsStyleLinkElement::CheckPreloadAttrs(const nsAttrValue& aAs,
227 : const nsAString& aType,
228 : const nsAString& aMedia,
229 : nsIDocument* aDocument)
230 : {
231 0 : nsContentPolicyType policyType = Link::AsValueToContentPolicy(aAs);
232 0 : if (policyType == nsIContentPolicy::TYPE_INVALID) {
233 0 : return false;
234 : }
235 :
236 : // Check if media attribute is valid.
237 0 : if (!aMedia.IsEmpty()) {
238 0 : RefPtr<MediaList> mediaList = MediaList::Create(aDocument->GetStyleBackendType(),
239 0 : aMedia);
240 0 : nsIPresShell* shell = aDocument->GetShell();
241 0 : if (!shell) {
242 0 : return false;
243 : }
244 :
245 0 : nsPresContext* presContext = shell->GetPresContext();
246 0 : if (!presContext) {
247 0 : return false;
248 : }
249 0 : if (!mediaList->Matches(presContext)) {
250 0 : return false;
251 : }
252 : }
253 :
254 0 : if (aType.IsEmpty()) {
255 0 : return true;
256 : }
257 :
258 0 : nsString type = nsString(aType);
259 0 : ToLowerCase(type);
260 :
261 0 : if (policyType == nsIContentPolicy::TYPE_OTHER) {
262 0 : return true;
263 :
264 0 : } else if (policyType == nsIContentPolicy::TYPE_MEDIA) {
265 0 : if (aAs.GetEnumValue() == DESTINATION_TRACK) {
266 0 : if (type.EqualsASCII("text/vtt")) {
267 0 : return true;
268 : } else {
269 0 : return false;
270 : }
271 : }
272 0 : Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType);
273 0 : if (!mimeType) {
274 0 : return false;
275 : }
276 0 : DecoderDoctorDiagnostics diagnostics;
277 0 : CanPlayStatus status = DecoderTraits::CanHandleContainerType(*mimeType,
278 0 : &diagnostics);
279 : // Preload if this return CANPLAY_YES and CANPLAY_MAYBE.
280 0 : if (status == CANPLAY_NO) {
281 0 : return false;
282 : } else {
283 0 : return true;
284 : }
285 :
286 0 : } else if (policyType == nsIContentPolicy::TYPE_FONT) {
287 0 : if (IsFontMimeType(type)) {
288 0 : return true;
289 : } else {
290 0 : return false;
291 : }
292 :
293 0 : } else if (policyType == nsIContentPolicy::TYPE_IMAGE) {
294 0 : if (imgLoader::SupportImageWithMimeType(NS_ConvertUTF16toUTF8(type).get(),
295 : AcceptedMimeTypes::IMAGES_AND_DOCUMENTS)) {
296 0 : return true;
297 : } else {
298 0 : return false;
299 : }
300 :
301 0 : } else if (policyType == nsIContentPolicy::TYPE_SCRIPT) {
302 0 : if (nsContentUtils::IsJavascriptMIMEType(type)) {
303 0 : return true;
304 : } else {
305 0 : return false;
306 : }
307 :
308 0 : } else if (policyType == nsIContentPolicy::TYPE_STYLESHEET) {
309 0 : if (type.EqualsASCII("text/css")) {
310 0 : return true;
311 : } else {
312 0 : return false;
313 : }
314 : }
315 0 : return false;
316 : }
317 :
318 : NS_IMETHODIMP
319 11 : nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
320 : bool* aWillNotify,
321 : bool* aIsAlternate,
322 : bool aForceReload)
323 : {
324 11 : if (aForceReload) {
325 : // We remove this stylesheet from the cache to load a new version.
326 0 : nsCOMPtr<nsIContent> thisContent;
327 0 : CallQueryInterface(this, getter_AddRefs(thisContent));
328 0 : nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
329 0 : thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
330 0 : if (doc && doc->CSSLoader()->GetEnabled() &&
331 0 : mStyleSheet && !mStyleSheet->IsInline()) {
332 0 : doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
333 : }
334 : }
335 11 : return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aWillNotify,
336 11 : aIsAlternate, aForceReload);
337 : }
338 :
339 : nsresult
340 11 : nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
341 : ShadowRoot *aOldShadowRoot,
342 : bool aForceUpdate)
343 : {
344 : bool notify, alternate;
345 11 : return DoUpdateStyleSheet(aOldDocument, aOldShadowRoot, nullptr, ¬ify,
346 11 : &alternate, aForceUpdate);
347 : }
348 :
349 : static bool
350 0 : IsScopedStyleElement(nsIContent* aContent)
351 : {
352 : // This is quicker than, say, QIing aContent to nsStyleLinkElement
353 : // and then calling its virtual GetStyleSheetInfo method to find out
354 : // if it is scoped.
355 0 : return (aContent->IsHTMLElement(nsGkAtoms::style) ||
356 0 : aContent->IsSVGElement(nsGkAtoms::style)) &&
357 0 : aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
358 0 : aContent->OwnerDoc()->IsScopedStyleEnabled();
359 : }
360 :
361 : static bool
362 0 : HasScopedStyleSheetChild(nsIContent* aContent)
363 : {
364 0 : for (nsIContent* n = aContent->GetFirstChild(); n; n = n->GetNextSibling()) {
365 0 : if (IsScopedStyleElement(n)) {
366 0 : return true;
367 : }
368 : }
369 0 : return false;
370 : }
371 :
372 : // Called when aElement has had a <style scoped> child removed.
373 : static void
374 0 : UpdateIsElementInStyleScopeFlagOnSubtree(Element* aElement)
375 : {
376 0 : NS_ASSERTION(aElement->IsElementInStyleScope(),
377 : "only call UpdateIsElementInStyleScopeFlagOnSubtree on a "
378 : "subtree that has IsElementInStyleScope boolean flag set");
379 :
380 0 : if (HasScopedStyleSheetChild(aElement)) {
381 0 : return;
382 : }
383 :
384 0 : aElement->ClearIsElementInStyleScope();
385 :
386 0 : nsIContent* n = aElement->GetNextNode(aElement);
387 0 : while (n) {
388 0 : if (HasScopedStyleSheetChild(n)) {
389 0 : n = n->GetNextNonChildNode(aElement);
390 : } else {
391 0 : if (n->IsElement()) {
392 0 : n->ClearIsElementInStyleScope();
393 : }
394 0 : n = n->GetNextNode(aElement);
395 : }
396 : }
397 : }
398 :
399 : nsresult
400 22 : nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
401 : ShadowRoot* aOldShadowRoot,
402 : nsICSSLoaderObserver* aObserver,
403 : bool* aWillNotify,
404 : bool* aIsAlternate,
405 : bool aForceUpdate)
406 : {
407 22 : *aWillNotify = false;
408 :
409 44 : nsCOMPtr<nsIContent> thisContent;
410 22 : CallQueryInterface(this, getter_AddRefs(thisContent));
411 :
412 : // All instances of nsStyleLinkElement should implement nsIContent.
413 22 : NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE);
414 :
415 22 : if (thisContent->IsInAnonymousSubtree() &&
416 0 : thisContent->IsAnonymousContentInSVGUseSubtree()) {
417 : // Stylesheets in <use>-cloned subtrees are disabled until we figure out
418 : // how they should behave.
419 0 : return NS_OK;
420 : }
421 :
422 : // Check for a ShadowRoot because link elements are inert in a
423 : // ShadowRoot.
424 22 : ShadowRoot* containingShadow = thisContent->GetContainingShadow();
425 22 : if (thisContent->IsHTMLElement(nsGkAtoms::link) &&
426 0 : (aOldShadowRoot || containingShadow)) {
427 0 : return NS_OK;
428 : }
429 :
430 : // XXXheycam ServoStyleSheets do not support <style scoped>.
431 22 : Element* oldScopeElement = nullptr;
432 22 : if (mStyleSheet) {
433 0 : if (mStyleSheet->IsServo()) {
434 0 : NS_WARNING("stylo: ServoStyleSheets don't support <style scoped>");
435 : } else {
436 0 : oldScopeElement = mStyleSheet->AsGecko()->GetScopeElement();
437 : }
438 : }
439 :
440 22 : if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
441 0 : MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
442 : "ShadowRoot content is never in document, thus "
443 : "there should not be a old document and old "
444 : "ShadowRoot simultaneously.");
445 :
446 : // We're removing the link element from the document or shadow tree,
447 : // unload the stylesheet. We want to do this even if updates are
448 : // disabled, since otherwise a sheet with a stale linking element pointer
449 : // will be hanging around -- not good!
450 0 : if (aOldShadowRoot) {
451 0 : aOldShadowRoot->RemoveSheet(mStyleSheet);
452 : } else {
453 0 : aOldDocument->BeginUpdate(UPDATE_STYLE);
454 0 : aOldDocument->RemoveStyleSheet(mStyleSheet);
455 0 : aOldDocument->EndUpdate(UPDATE_STYLE);
456 : }
457 :
458 0 : nsStyleLinkElement::SetStyleSheet(nullptr);
459 0 : if (oldScopeElement) {
460 0 : UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
461 : }
462 : }
463 :
464 : // When static documents are created, stylesheets are cloned manually.
465 33 : if (mDontLoadStyle || !mUpdatesEnabled ||
466 11 : thisContent->OwnerDoc()->IsStaticDocument()) {
467 11 : return NS_OK;
468 : }
469 :
470 11 : nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
471 22 : thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
472 11 : if (!doc || !doc->CSSLoader()->GetEnabled()) {
473 0 : return NS_OK;
474 : }
475 :
476 : bool isInline;
477 22 : nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline);
478 :
479 11 : if (!aForceUpdate && mStyleSheet && !isInline && uri) {
480 0 : nsIURI* oldURI = mStyleSheet->GetSheetURI();
481 0 : if (oldURI) {
482 : bool equal;
483 0 : nsresult rv = oldURI->Equals(uri, &equal);
484 0 : if (NS_SUCCEEDED(rv) && equal) {
485 0 : return NS_OK; // We already loaded this stylesheet
486 : }
487 : }
488 : }
489 :
490 11 : if (mStyleSheet) {
491 0 : if (thisContent->IsInShadowTree()) {
492 0 : ShadowRoot* containingShadow = thisContent->GetContainingShadow();
493 0 : containingShadow->RemoveSheet(mStyleSheet);
494 : } else {
495 0 : doc->BeginUpdate(UPDATE_STYLE);
496 0 : doc->RemoveStyleSheet(mStyleSheet);
497 0 : doc->EndUpdate(UPDATE_STYLE);
498 : }
499 :
500 0 : nsStyleLinkElement::SetStyleSheet(nullptr);
501 : }
502 :
503 11 : if (!uri && !isInline) {
504 0 : return NS_OK; // If href is empty and this is not inline style then just bail
505 : }
506 :
507 22 : nsAutoString title, type, media;
508 : bool isScoped;
509 : bool isAlternate;
510 :
511 11 : GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate);
512 :
513 11 : if (!type.LowerCaseEqualsLiteral("text/css")) {
514 0 : return NS_OK;
515 : }
516 :
517 11 : Element* scopeElement = isScoped ? thisContent->GetParentElement() : nullptr;
518 11 : if (scopeElement) {
519 0 : NS_ASSERTION(isInline, "non-inline style must not have scope element");
520 0 : scopeElement->SetIsElementInStyleScopeFlagOnSubtree(true);
521 : }
522 :
523 11 : bool doneLoading = false;
524 11 : nsresult rv = NS_OK;
525 11 : if (isInline) {
526 10 : nsAutoString text;
527 5 : if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
528 0 : return NS_ERROR_OUT_OF_MEMORY;
529 : }
530 :
531 5 : MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
532 : "<link> is not 'inline', and needs different CSP checks");
533 10 : if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
534 5 : thisContent->NodePrincipal(),
535 : doc->GetDocumentURI(),
536 : mLineNumber, text, &rv))
537 0 : return rv;
538 :
539 : // Parse the style sheet.
540 5 : rv = doc->CSSLoader()->
541 5 : LoadInlineStyle(thisContent, text, mLineNumber, title, media,
542 : scopeElement, aObserver, &doneLoading, &isAlternate);
543 : }
544 : else {
545 12 : nsAutoString integrity;
546 6 : thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
547 6 : if (!integrity.IsEmpty()) {
548 0 : MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
549 : ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
550 : NS_ConvertUTF16toUTF8(integrity).get()));
551 : }
552 :
553 : // if referrer attributes are enabled in preferences, load the link's referrer
554 : // attribute. If the link does not provide a referrer attribute, ignore this
555 : // and use the document's referrer policy
556 :
557 6 : net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
558 6 : if (referrerPolicy == net::RP_Unset) {
559 6 : referrerPolicy = doc->GetReferrerPolicy();
560 : }
561 :
562 : // XXXbz clone the URI here to work around content policies modifying URIs.
563 12 : nsCOMPtr<nsIURI> clonedURI;
564 6 : uri->Clone(getter_AddRefs(clonedURI));
565 6 : NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
566 6 : rv = doc->CSSLoader()->
567 6 : LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
568 6 : GetCORSMode(), referrerPolicy, integrity,
569 : aObserver, &isAlternate);
570 6 : if (NS_FAILED(rv)) {
571 : // Don't propagate LoadStyleLink() errors further than this, since some
572 : // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
573 : // things like a stylesheet load being blocked by the security system.
574 0 : doneLoading = true;
575 0 : isAlternate = false;
576 0 : rv = NS_OK;
577 : }
578 : }
579 :
580 11 : NS_ENSURE_SUCCESS(rv, rv);
581 :
582 11 : *aWillNotify = !doneLoading;
583 11 : *aIsAlternate = isAlternate;
584 :
585 11 : return NS_OK;
586 : }
587 :
588 : void
589 0 : nsStyleLinkElement::UpdateStyleSheetScopedness(bool aIsNowScoped)
590 : {
591 0 : if (!mStyleSheet) {
592 0 : return;
593 : }
594 :
595 0 : if (mStyleSheet->IsServo()) {
596 : // XXXheycam ServoStyleSheets don't support <style scoped>.
597 0 : NS_ERROR("stylo: ServoStyleSheets don't support <style scoped>");
598 0 : return;
599 : }
600 :
601 0 : CSSStyleSheet* sheet = mStyleSheet->AsGecko();
602 :
603 0 : nsCOMPtr<nsIContent> thisContent;
604 0 : CallQueryInterface(this, getter_AddRefs(thisContent));
605 :
606 0 : Element* oldScopeElement = sheet->GetScopeElement();
607 0 : Element* newScopeElement = aIsNowScoped ?
608 0 : thisContent->GetParentElement() :
609 0 : nullptr;
610 :
611 0 : if (oldScopeElement == newScopeElement) {
612 0 : return;
613 : }
614 :
615 0 : nsIDocument* document = thisContent->GetOwnerDocument();
616 :
617 0 : if (thisContent->IsInShadowTree()) {
618 0 : ShadowRoot* containingShadow = thisContent->GetContainingShadow();
619 0 : containingShadow->RemoveSheet(mStyleSheet);
620 :
621 0 : sheet->SetScopeElement(newScopeElement);
622 :
623 0 : containingShadow->InsertSheet(mStyleSheet, thisContent);
624 : } else {
625 0 : document->BeginUpdate(UPDATE_STYLE);
626 0 : document->RemoveStyleSheet(mStyleSheet);
627 :
628 0 : sheet->SetScopeElement(newScopeElement);
629 :
630 0 : document->AddStyleSheet(mStyleSheet);
631 0 : document->EndUpdate(UPDATE_STYLE);
632 : }
633 :
634 0 : if (oldScopeElement) {
635 0 : UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
636 : }
637 0 : if (newScopeElement) {
638 0 : newScopeElement->SetIsElementInStyleScopeFlagOnSubtree(true);
639 : }
640 : }
|