@media rules ignored in user agent style sheet html.css
[WebKit-https.git] / Source / WebCore / style / StyleScope.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6  * Copyright (C) 2004-2009, 2011-2012, 2015-2017 Apple Inc. All rights reserved.
7  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
9  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "StyleScope.h"
30
31 #include "CSSFontSelector.h"
32 #include "CSSStyleSheet.h"
33 #include "Element.h"
34 #include "ElementChildIterator.h"
35 #include "ExtensionStyleSheets.h"
36 #include "HTMLHeadElement.h"
37 #include "HTMLIFrameElement.h"
38 #include "HTMLLinkElement.h"
39 #include "HTMLSlotElement.h"
40 #include "HTMLStyleElement.h"
41 #include "InspectorInstrumentation.h"
42 #include "ProcessingInstruction.h"
43 #include "SVGStyleElement.h"
44 #include "Settings.h"
45 #include "ShadowRoot.h"
46 #include "StyleInvalidator.h"
47 #include "StyleResolver.h"
48 #include "StyleSheetContents.h"
49 #include "StyleSheetList.h"
50 #include "UserContentController.h"
51 #include "UserContentURLPattern.h"
52 #include "UserStyleSheet.h"
53 #include <wtf/SetForScope.h>
54
55 namespace WebCore {
56
57 using namespace ContentExtensions;
58 using namespace HTMLNames;
59
60 namespace Style {
61
62 Scope::Scope(Document& document)
63     : m_document(document)
64     , m_pendingUpdateTimer(*this, &Scope::pendingUpdateTimerFired)
65 {
66 }
67
68 Scope::Scope(ShadowRoot& shadowRoot)
69     : m_document(shadowRoot.documentScope())
70     , m_shadowRoot(&shadowRoot)
71     , m_pendingUpdateTimer(*this, &Scope::pendingUpdateTimerFired)
72 {
73 }
74
75 Scope::~Scope()
76 {
77     ASSERT(!hasPendingSheets());
78 }
79
80 bool Scope::shouldUseSharedUserAgentShadowTreeStyleResolver() const
81 {
82     if (!m_shadowRoot)
83         return false;
84     if (m_shadowRoot->mode() != ShadowRootMode::UserAgent)
85         return false;
86     // If we have stylesheets in the user agent shadow tree use per-scope resolver.
87     if (!m_styleSheetCandidateNodes.isEmpty())
88         return false;
89     return true;
90 }
91
92 StyleResolver& Scope::resolver()
93 {
94     if (shouldUseSharedUserAgentShadowTreeStyleResolver())
95         return m_document.userAgentShadowTreeStyleResolver();
96
97     if (!m_resolver) {
98         SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
99
100         m_resolver = std::make_unique<StyleResolver>(m_document);
101
102         if (!m_shadowRoot) {
103             m_document.fontSelector().buildStarted();
104             m_resolver->ruleSets().initializeUserStyle();
105         } else {
106             m_resolver->ruleSets().setIsForShadowScope();
107             m_resolver->ruleSets().setUsesSharedUserStyle(m_shadowRoot->mode() != ShadowRootMode::UserAgent);
108         }
109
110         m_resolver->addCurrentSVGFontFaceRules();
111         m_resolver->appendAuthorStyleSheets(m_activeStyleSheets);
112
113         if (!m_shadowRoot)
114             m_document.fontSelector().buildCompleted();
115     }
116     ASSERT(!m_shadowRoot || &m_document == &m_shadowRoot->document());
117     ASSERT(&m_resolver->document() == &m_document);
118     return *m_resolver;
119 }
120
121 StyleResolver* Scope::resolverIfExists()
122 {
123     if (shouldUseSharedUserAgentShadowTreeStyleResolver())
124         return &m_document.userAgentShadowTreeStyleResolver();
125
126     return m_resolver.get();
127 }
128
129 void Scope::clearResolver()
130 {
131     m_resolver = nullptr;
132
133     if (!m_shadowRoot)
134         m_document.didClearStyleResolver();
135 }
136
137 Scope& Scope::forNode(Node& node)
138 {
139     ASSERT(node.isConnected());
140     auto* shadowRoot = node.containingShadowRoot();
141     if (shadowRoot)
142         return shadowRoot->styleScope();
143     return node.document().styleScope();
144 }
145
146 Scope* Scope::forOrdinal(Element& element, ScopeOrdinal ordinal)
147 {
148     switch (ordinal) {
149     case ScopeOrdinal::Element:
150         return &forNode(element);
151     case ScopeOrdinal::ContainingHost: {
152         auto* containingShadowRoot = element.containingShadowRoot();
153         if (!containingShadowRoot)
154             return nullptr;
155         return &forNode(*containingShadowRoot->host());
156     }
157     case ScopeOrdinal::Shadow: {
158         auto* shadowRoot = element.shadowRoot();
159         if (!shadowRoot)
160             return nullptr;
161         return &shadowRoot->styleScope();
162     }
163     default: {
164         ASSERT(ordinal >= ScopeOrdinal::FirstSlot);
165         auto slotIndex = ScopeOrdinal::FirstSlot;
166         for (auto* slot = element.assignedSlot(); slot; slot = slot->assignedSlot(), ++slotIndex) {
167             if (slotIndex == ordinal)
168                 return &forNode(*slot);
169         }
170         return nullptr;
171     }
172     }
173 }
174
175 void Scope::setPreferredStylesheetSetName(const String& name)
176 {
177     if (m_preferredStylesheetSetName == name)
178         return;
179     m_preferredStylesheetSetName = name;
180     didChangeActiveStyleSheetCandidates();
181 }
182
183 void Scope::setSelectedStylesheetSetName(const String& name)
184 {
185     if (m_selectedStylesheetSetName == name)
186         return;
187     m_selectedStylesheetSetName = name;
188     didChangeActiveStyleSheetCandidates();
189 }
190
191
192 void Scope::addPendingSheet(const Element& element)
193 {
194     ASSERT(!hasPendingSheet(element));
195
196     bool isInHead = ancestorsOfType<HTMLHeadElement>(element).first();
197     if (isInHead)
198         m_elementsInHeadWithPendingSheets.add(&element);
199     else
200         m_elementsInBodyWithPendingSheets.add(&element);
201 }
202
203 // This method is called whenever a top-level stylesheet has finished loading.
204 void Scope::removePendingSheet(const Element& element)
205 {
206     ASSERT(hasPendingSheet(element));
207
208     if (!m_elementsInHeadWithPendingSheets.remove(&element))
209         m_elementsInBodyWithPendingSheets.remove(&element);
210
211     didRemovePendingStylesheet();
212 }
213
214 void Scope::addPendingSheet(const ProcessingInstruction& processingInstruction)
215 {
216     ASSERT(!m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
217
218     m_processingInstructionsWithPendingSheets.add(&processingInstruction);
219 }
220
221 void Scope::removePendingSheet(const ProcessingInstruction& processingInstruction)
222 {
223     ASSERT(m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
224
225     m_processingInstructionsWithPendingSheets.remove(&processingInstruction);
226
227     didRemovePendingStylesheet();
228 }
229
230 void Scope::didRemovePendingStylesheet()
231 {
232     if (hasPendingSheets())
233         return;
234
235     didChangeActiveStyleSheetCandidates();
236
237     if (!m_shadowRoot)
238         m_document.didRemoveAllPendingStylesheet();
239 }
240
241 bool Scope::hasPendingSheet(const Element& element) const
242 {
243     return m_elementsInHeadWithPendingSheets.contains(&element) || hasPendingSheetInBody(element);
244 }
245
246 bool Scope::hasPendingSheetInBody(const Element& element) const
247 {
248     return m_elementsInBodyWithPendingSheets.contains(&element);
249 }
250
251 bool Scope::hasPendingSheet(const ProcessingInstruction& processingInstruction) const
252 {
253     return m_processingInstructionsWithPendingSheets.contains(&processingInstruction);
254 }
255
256 void Scope::addStyleSheetCandidateNode(Node& node, bool createdByParser)
257 {
258     if (!node.isConnected())
259         return;
260     
261     // Until the <body> exists, we have no choice but to compare document positions,
262     // since styles outside of the body and head continue to be shunted into the head
263     // (and thus can shift to end up before dynamically added DOM content that is also
264     // outside the body).
265     if ((createdByParser && m_document.bodyOrFrameset()) || m_styleSheetCandidateNodes.isEmpty()) {
266         m_styleSheetCandidateNodes.add(&node);
267         return;
268     }
269
270     // Determine an appropriate insertion point.
271     auto begin = m_styleSheetCandidateNodes.begin();
272     auto end = m_styleSheetCandidateNodes.end();
273     auto it = end;
274     Node* followingNode = nullptr;
275     do {
276         --it;
277         Node* n = *it;
278         unsigned short position = n->compareDocumentPosition(node);
279         if (position == Node::DOCUMENT_POSITION_FOLLOWING) {
280             m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
281             return;
282         }
283         followingNode = n;
284     } while (it != begin);
285     
286     m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
287 }
288
289 void Scope::removeStyleSheetCandidateNode(Node& node)
290 {
291     if (m_styleSheetCandidateNodes.remove(&node))
292         didChangeActiveStyleSheetCandidates();
293 }
294
295 #if ENABLE(XSLT)
296 // FIXME: <https://webkit.org/b/178830> Remove XSLT relaed code from Style::Scope.
297 Vector<Ref<ProcessingInstruction>> Scope::collectXSLTransforms()
298 {
299     Vector<Ref<ProcessingInstruction>> processingInstructions;
300     for (auto& node : m_styleSheetCandidateNodes) {
301         if (is<ProcessingInstruction>(*node) && downcast<ProcessingInstruction>(*node).isXSL())
302             processingInstructions.append(downcast<ProcessingInstruction>(*node));
303     }
304     return processingInstructions;
305 }
306 #endif
307
308 void Scope::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
309 {
310     if (!m_document.settings().authorAndUserStylesEnabled())
311         return;
312
313     for (auto& node : m_styleSheetCandidateNodes) {
314         RefPtr<StyleSheet> sheet;
315         if (is<ProcessingInstruction>(*node)) {
316             if (!downcast<ProcessingInstruction>(*node).isCSS())
317                 continue;
318             // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
319             sheet = downcast<ProcessingInstruction>(*node).sheet();
320         } else if (is<HTMLLinkElement>(*node) || is<HTMLStyleElement>(*node) || is<SVGStyleElement>(*node)) {
321             Element& element = downcast<Element>(*node);
322             AtomicString title = element.attributeWithoutSynchronization(titleAttr);
323             bool enabledViaScript = false;
324             if (is<HTMLLinkElement>(element)) {
325                 // <LINK> element
326                 HTMLLinkElement& linkElement = downcast<HTMLLinkElement>(element);
327                 if (linkElement.isDisabled())
328                     continue;
329                 enabledViaScript = linkElement.isEnabledViaScript();
330                 if (linkElement.styleSheetIsLoading()) {
331                     // it is loading but we should still decide which style sheet set to use
332                     if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) {
333                         if (!linkElement.attributeWithoutSynchronization(relAttr).contains("alternate")) {
334                             m_preferredStylesheetSetName = title;
335                             m_selectedStylesheetSetName = title;
336                         }
337                     }
338                     continue;
339                 }
340                 if (!linkElement.sheet())
341                     title = nullAtom();
342             }
343             // Get the current preferred styleset. This is the
344             // set of sheets that will be enabled.
345             if (is<SVGStyleElement>(element))
346                 sheet = downcast<SVGStyleElement>(element).sheet();
347             else if (is<HTMLLinkElement>(element))
348                 sheet = downcast<HTMLLinkElement>(element).sheet();
349             else
350                 sheet = downcast<HTMLStyleElement>(element).sheet();
351             // Check to see if this sheet belongs to a styleset
352             // (thus making it PREFERRED or ALTERNATE rather than
353             // PERSISTENT).
354             auto& rel = element.attributeWithoutSynchronization(relAttr);
355             if (!enabledViaScript && !title.isEmpty()) {
356                 // Yes, we have a title.
357                 if (m_preferredStylesheetSetName.isEmpty()) {
358                     // No preferred set has been established. If
359                     // we are NOT an alternate sheet, then establish
360                     // us as the preferred set. Otherwise, just ignore
361                     // this sheet.
362                     if (is<HTMLStyleElement>(element) || !rel.contains("alternate"))
363                         m_preferredStylesheetSetName = m_selectedStylesheetSetName = title;
364                 }
365                 if (title != m_preferredStylesheetSetName)
366                     sheet = nullptr;
367             }
368
369             if (rel.contains("alternate") && title.isEmpty())
370                 sheet = nullptr;
371         }
372         if (sheet)
373             sheets.append(WTFMove(sheet));
374     }
375 }
376
377 Scope::StyleResolverUpdateType Scope::analyzeStyleSheetChange(const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc)
378 {
379     requiresFullStyleRecalc = true;
380     
381     unsigned newStylesheetCount = newStylesheets.size();
382
383     if (!resolverIfExists())
384         return Reconstruct;
385
386     auto& styleResolver = *resolverIfExists();
387
388     // Find out which stylesheets are new.
389     unsigned oldStylesheetCount = m_activeStyleSheets.size();
390     if (newStylesheetCount < oldStylesheetCount)
391         return Reconstruct;
392
393     Vector<StyleSheetContents*> addedSheets;
394     unsigned newIndex = 0;
395     for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
396         if (newIndex >= newStylesheetCount)
397             return Reconstruct;
398         while (m_activeStyleSheets[oldIndex] != newStylesheets[newIndex]) {
399             addedSheets.append(&newStylesheets[newIndex]->contents());
400             ++newIndex;
401             if (newIndex == newStylesheetCount)
402                 return Reconstruct;
403         }
404         ++newIndex;
405     }
406     bool hasInsertions = !addedSheets.isEmpty();
407     while (newIndex < newStylesheetCount) {
408         addedSheets.append(&newStylesheets[newIndex]->contents());
409         ++newIndex;
410     }
411     // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
412     // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
413     auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
414
415     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
416     if (!m_document.bodyOrFrameset() || m_document.hasNodesWithNonFinalStyle() || m_document.hasNodesWithMissingStyle())
417         return styleResolverUpdateType;
418
419     Invalidator invalidator(addedSheets, styleResolver.mediaQueryEvaluator());
420     if (invalidator.dirtiesAllStyle())
421         return styleResolverUpdateType;
422
423     if (m_shadowRoot)
424         invalidator.invalidateStyle(*m_shadowRoot);
425     else
426         invalidator.invalidateStyle(m_document);
427
428     requiresFullStyleRecalc = false;
429
430     return styleResolverUpdateType;
431 }
432
433 static void filterEnabledNonemptyCSSStyleSheets(Vector<RefPtr<CSSStyleSheet>>& result, const Vector<RefPtr<StyleSheet>>& sheets)
434 {
435     for (auto& sheet : sheets) {
436         if (!is<CSSStyleSheet>(*sheet))
437             continue;
438         CSSStyleSheet& styleSheet = downcast<CSSStyleSheet>(*sheet);
439         if (styleSheet.isLoading())
440             continue;
441         if (styleSheet.disabled())
442             continue;
443         if (!styleSheet.length())
444             continue;
445         result.append(&styleSheet);
446     }
447 }
448
449 void Scope::updateActiveStyleSheets(UpdateType updateType)
450 {
451     ASSERT(!m_pendingUpdate);
452
453     if (!m_document.hasLivingRenderTree())
454         return;
455
456     if (m_document.inStyleRecalc() || m_document.inRenderTreeUpdate()) {
457         // Protect against deleting style resolver in the middle of a style resolution.
458         // Crash stacks indicate we can get here when a resource load fails synchronously (for example due to content blocking).
459         // FIXME: These kind of cases should be eliminated and this path replaced by an assert.
460         m_pendingUpdate = UpdateType::ContentsOrInterpretation;
461         m_document.scheduleForcedStyleRecalc();
462         return;
463     }
464
465     Vector<RefPtr<StyleSheet>> activeStyleSheets;
466     collectActiveStyleSheets(activeStyleSheets);
467
468     Vector<RefPtr<CSSStyleSheet>> activeCSSStyleSheets;
469     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
470     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
471     filterEnabledNonemptyCSSStyleSheets(activeCSSStyleSheets, activeStyleSheets);
472
473     bool requiresFullStyleRecalc = true;
474     StyleResolverUpdateType styleResolverUpdateType = Reconstruct;
475     if (updateType == UpdateType::ActiveSet)
476         styleResolverUpdateType = analyzeStyleSheetChange(activeCSSStyleSheets, requiresFullStyleRecalc);
477
478     updateStyleResolver(activeCSSStyleSheets, styleResolverUpdateType);
479
480     m_weakCopyOfActiveStyleSheetListForFastLookup = nullptr;
481     m_activeStyleSheets.swap(activeCSSStyleSheets);
482     m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
483
484     InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
485
486     for (const auto& sheet : m_activeStyleSheets) {
487         if (sheet->contents().usesStyleBasedEditability())
488             m_usesStyleBasedEditability = true;
489     }
490
491     // FIXME: Move this code somewhere else.
492     if (requiresFullStyleRecalc) {
493         if (m_shadowRoot) {
494             for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot))
495                 shadowChild.invalidateStyleForSubtree();
496             if (m_shadowRoot->host()) {
497                 if (!resolver().ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
498                     m_shadowRoot->host()->invalidateStyle();
499                 if (!resolver().ruleSets().authorStyle().slottedPseudoElementRules().isEmpty()) {
500                     for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot->host()))
501                         shadowChild.invalidateStyle();
502                 }
503             }
504         } else
505             m_document.scheduleForcedStyleRecalc();
506     }
507 }
508
509 void Scope::updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>& activeStyleSheets, StyleResolverUpdateType updateType)
510 {
511     if (updateType == Reconstruct) {
512         clearResolver();
513         return;
514     }
515     auto& styleResolver = resolver();
516
517     SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
518     if (updateType == Reset) {
519         styleResolver.ruleSets().resetAuthorStyle();
520         styleResolver.appendAuthorStyleSheets(activeStyleSheets);
521     } else {
522         ASSERT(updateType == Additive);
523         unsigned firstNewIndex = m_activeStyleSheets.size();
524         Vector<RefPtr<CSSStyleSheet>> newStyleSheets;
525         newStyleSheets.appendRange(activeStyleSheets.begin() + firstNewIndex, activeStyleSheets.end());
526         styleResolver.appendAuthorStyleSheets(newStyleSheets);
527     }
528 }
529
530 const Vector<RefPtr<CSSStyleSheet>> Scope::activeStyleSheetsForInspector()
531 {
532     Vector<RefPtr<CSSStyleSheet>> result;
533
534     result.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
535     result.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
536
537     for (auto& styleSheet : m_styleSheetsForStyleSheetList) {
538         if (!is<CSSStyleSheet>(*styleSheet))
539             continue;
540
541         CSSStyleSheet& sheet = downcast<CSSStyleSheet>(*styleSheet);
542         if (sheet.disabled())
543             continue;
544
545         result.append(&sheet);
546     }
547
548     return result;
549 }
550
551 bool Scope::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
552 {
553     if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
554         m_weakCopyOfActiveStyleSheetListForFastLookup = std::make_unique<HashSet<const CSSStyleSheet*>>();
555         for (auto& activeStyleSheet : m_activeStyleSheets)
556             m_weakCopyOfActiveStyleSheetListForFastLookup->add(activeStyleSheet.get());
557     }
558     return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
559 }
560
561 void Scope::flushPendingSelfUpdate()
562 {
563     ASSERT(m_pendingUpdate);
564
565     auto updateType = *m_pendingUpdate;
566
567     clearPendingUpdate();
568     updateActiveStyleSheets(updateType);
569 }
570
571 void Scope::flushPendingDescendantUpdates()
572 {
573     ASSERT(m_hasDescendantWithPendingUpdate);
574     ASSERT(!m_shadowRoot);
575     for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
576         descendantShadowRoot->styleScope().flushPendingUpdate();
577     m_hasDescendantWithPendingUpdate = false;
578 }
579
580 void Scope::clearPendingUpdate()
581 {
582     m_pendingUpdateTimer.stop();
583     m_pendingUpdate = { };
584 }
585
586 void Scope::scheduleUpdate(UpdateType update)
587 {
588     // FIXME: The m_isUpdatingStyleResolver test is here because extension stylesheets can get us here from StyleResolver::appendAuthorStyleSheets.
589     if (update == UpdateType::ContentsOrInterpretation && !m_isUpdatingStyleResolver)
590         clearResolver();
591
592     if (!m_pendingUpdate || *m_pendingUpdate < update) {
593         m_pendingUpdate = update;
594         if (m_shadowRoot)
595             m_document.styleScope().m_hasDescendantWithPendingUpdate = true;
596     }
597
598     if (m_pendingUpdateTimer.isActive())
599         return;
600     m_pendingUpdateTimer.startOneShot(0_s);
601 }
602
603 void Scope::didChangeActiveStyleSheetCandidates()
604 {
605     scheduleUpdate(UpdateType::ActiveSet);
606 }
607
608 void Scope::didChangeStyleSheetContents()
609 {
610     scheduleUpdate(UpdateType::ContentsOrInterpretation);
611 }
612
613 void Scope::didChangeStyleSheetEnvironment()
614 {
615     if (!m_shadowRoot) {
616         for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots()) {
617             // Stylesheets is author shadow roots are potentially affected.
618             if (descendantShadowRoot->mode() != ShadowRootMode::UserAgent)
619                 descendantShadowRoot->styleScope().scheduleUpdate(UpdateType::ContentsOrInterpretation);
620         }
621     }
622     scheduleUpdate(UpdateType::ContentsOrInterpretation);
623 }
624
625 void Scope::pendingUpdateTimerFired()
626 {
627     flushPendingUpdate();
628 }
629
630 const Vector<RefPtr<StyleSheet>>& Scope::styleSheetsForStyleSheetList()
631 {
632     // FIXME: StyleSheetList content should be updated separately from style resolver updates.
633     flushPendingUpdate();
634     return m_styleSheetsForStyleSheetList;
635 }
636
637 }
638 }