Support ::before/::after pseudo elements on elements with display:contents
[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().setUsesSharedUserStyle(m_shadowRoot->mode() != ShadowRootMode::UserAgent);
107
108         m_resolver->addCurrentSVGFontFaceRules();
109         m_resolver->appendAuthorStyleSheets(m_activeStyleSheets);
110
111         if (!m_shadowRoot)
112             m_document.fontSelector().buildCompleted();
113     }
114     ASSERT(!m_shadowRoot || &m_document == &m_shadowRoot->document());
115     ASSERT(&m_resolver->document() == &m_document);
116     return *m_resolver;
117 }
118
119 StyleResolver* Scope::resolverIfExists()
120 {
121     if (shouldUseSharedUserAgentShadowTreeStyleResolver())
122         return &m_document.userAgentShadowTreeStyleResolver();
123
124     return m_resolver.get();
125 }
126
127 void Scope::clearResolver()
128 {
129     m_resolver = nullptr;
130
131     if (!m_shadowRoot)
132         m_document.didClearStyleResolver();
133 }
134
135 Scope& Scope::forNode(Node& node)
136 {
137     ASSERT(node.isConnected());
138     auto* shadowRoot = node.containingShadowRoot();
139     if (shadowRoot)
140         return shadowRoot->styleScope();
141     return node.document().styleScope();
142 }
143
144 Scope* Scope::forOrdinal(Element& element, ScopeOrdinal ordinal)
145 {
146     switch (ordinal) {
147     case ScopeOrdinal::Element:
148         return &forNode(element);
149     case ScopeOrdinal::ContainingHost: {
150         auto* containingShadowRoot = element.containingShadowRoot();
151         if (!containingShadowRoot)
152             return nullptr;
153         return &forNode(*containingShadowRoot->host());
154     }
155     case ScopeOrdinal::Shadow: {
156         auto* shadowRoot = element.shadowRoot();
157         if (!shadowRoot)
158             return nullptr;
159         return &shadowRoot->styleScope();
160     }
161     default: {
162         ASSERT(ordinal >= ScopeOrdinal::FirstSlot);
163         auto slotIndex = ScopeOrdinal::FirstSlot;
164         for (auto* slot = element.assignedSlot(); slot; slot = slot->assignedSlot(), ++slotIndex) {
165             if (slotIndex == ordinal)
166                 return &forNode(*slot);
167         }
168         return nullptr;
169     }
170     }
171 }
172
173 void Scope::setPreferredStylesheetSetName(const String& name)
174 {
175     if (m_preferredStylesheetSetName == name)
176         return;
177     m_preferredStylesheetSetName = name;
178     didChangeActiveStyleSheetCandidates();
179 }
180
181 void Scope::setSelectedStylesheetSetName(const String& name)
182 {
183     if (m_selectedStylesheetSetName == name)
184         return;
185     m_selectedStylesheetSetName = name;
186     didChangeActiveStyleSheetCandidates();
187 }
188
189
190 void Scope::addPendingSheet(const Element& element)
191 {
192     ASSERT(!hasPendingSheet(element));
193
194     bool isInHead = ancestorsOfType<HTMLHeadElement>(element).first();
195     if (isInHead)
196         m_elementsInHeadWithPendingSheets.add(&element);
197     else
198         m_elementsInBodyWithPendingSheets.add(&element);
199 }
200
201 // This method is called whenever a top-level stylesheet has finished loading.
202 void Scope::removePendingSheet(const Element& element)
203 {
204     ASSERT(hasPendingSheet(element));
205
206     if (!m_elementsInHeadWithPendingSheets.remove(&element))
207         m_elementsInBodyWithPendingSheets.remove(&element);
208
209     didRemovePendingStylesheet();
210 }
211
212 void Scope::addPendingSheet(const ProcessingInstruction& processingInstruction)
213 {
214     ASSERT(!m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
215
216     m_processingInstructionsWithPendingSheets.add(&processingInstruction);
217 }
218
219 void Scope::removePendingSheet(const ProcessingInstruction& processingInstruction)
220 {
221     ASSERT(m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
222
223     m_processingInstructionsWithPendingSheets.remove(&processingInstruction);
224
225     didRemovePendingStylesheet();
226 }
227
228 void Scope::didRemovePendingStylesheet()
229 {
230     if (hasPendingSheets())
231         return;
232
233     didChangeActiveStyleSheetCandidates();
234
235     if (!m_shadowRoot)
236         m_document.didRemoveAllPendingStylesheet();
237 }
238
239 bool Scope::hasPendingSheet(const Element& element) const
240 {
241     return m_elementsInHeadWithPendingSheets.contains(&element) || hasPendingSheetInBody(element);
242 }
243
244 bool Scope::hasPendingSheetInBody(const Element& element) const
245 {
246     return m_elementsInBodyWithPendingSheets.contains(&element);
247 }
248
249 bool Scope::hasPendingSheet(const ProcessingInstruction& processingInstruction) const
250 {
251     return m_processingInstructionsWithPendingSheets.contains(&processingInstruction);
252 }
253
254 void Scope::addStyleSheetCandidateNode(Node& node, bool createdByParser)
255 {
256     if (!node.isConnected())
257         return;
258     
259     // Until the <body> exists, we have no choice but to compare document positions,
260     // since styles outside of the body and head continue to be shunted into the head
261     // (and thus can shift to end up before dynamically added DOM content that is also
262     // outside the body).
263     if ((createdByParser && m_document.bodyOrFrameset()) || m_styleSheetCandidateNodes.isEmpty()) {
264         m_styleSheetCandidateNodes.add(&node);
265         return;
266     }
267
268     // Determine an appropriate insertion point.
269     auto begin = m_styleSheetCandidateNodes.begin();
270     auto end = m_styleSheetCandidateNodes.end();
271     auto it = end;
272     Node* followingNode = nullptr;
273     do {
274         --it;
275         Node* n = *it;
276         unsigned short position = n->compareDocumentPosition(node);
277         if (position == Node::DOCUMENT_POSITION_FOLLOWING) {
278             m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
279             return;
280         }
281         followingNode = n;
282     } while (it != begin);
283     
284     m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
285 }
286
287 void Scope::removeStyleSheetCandidateNode(Node& node)
288 {
289     if (m_styleSheetCandidateNodes.remove(&node))
290         didChangeActiveStyleSheetCandidates();
291 }
292
293 void Scope::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
294 {
295     if (!m_document.settings().authorAndUserStylesEnabled())
296         return;
297
298     for (auto& node : m_styleSheetCandidateNodes) {
299         StyleSheet* sheet = nullptr;
300         if (is<ProcessingInstruction>(*node)) {
301             // Processing instruction (XML documents only).
302             // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
303             ProcessingInstruction& pi = downcast<ProcessingInstruction>(*node);
304             sheet = pi.sheet();
305 #if ENABLE(XSLT)
306             // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
307             if (pi.isXSL() && !m_document.transformSourceDocument()) {
308                 // Don't apply XSL transforms until loading is finished.
309                 if (!m_document.parsing())
310                     m_document.applyXSLTransform(&pi);
311                 return;
312             }
313 #endif
314         } else if (is<HTMLLinkElement>(*node) || is<HTMLStyleElement>(*node) || is<SVGStyleElement>(*node)) {
315             Element& element = downcast<Element>(*node);
316             AtomicString title = element.attributeWithoutSynchronization(titleAttr);
317             bool enabledViaScript = false;
318             if (is<HTMLLinkElement>(element)) {
319                 // <LINK> element
320                 HTMLLinkElement& linkElement = downcast<HTMLLinkElement>(element);
321                 if (linkElement.isDisabled())
322                     continue;
323                 enabledViaScript = linkElement.isEnabledViaScript();
324                 if (linkElement.styleSheetIsLoading()) {
325                     // it is loading but we should still decide which style sheet set to use
326                     if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) {
327                         if (!linkElement.attributeWithoutSynchronization(relAttr).contains("alternate")) {
328                             m_preferredStylesheetSetName = title;
329                             m_selectedStylesheetSetName = title;
330                         }
331                     }
332                     continue;
333                 }
334                 if (!linkElement.sheet())
335                     title = nullAtom();
336             }
337             // Get the current preferred styleset. This is the
338             // set of sheets that will be enabled.
339             if (is<SVGStyleElement>(element))
340                 sheet = downcast<SVGStyleElement>(element).sheet();
341             else if (is<HTMLLinkElement>(element))
342                 sheet = downcast<HTMLLinkElement>(element).sheet();
343             else
344                 sheet = downcast<HTMLStyleElement>(element).sheet();
345             // Check to see if this sheet belongs to a styleset
346             // (thus making it PREFERRED or ALTERNATE rather than
347             // PERSISTENT).
348             auto& rel = element.attributeWithoutSynchronization(relAttr);
349             if (!enabledViaScript && !title.isEmpty()) {
350                 // Yes, we have a title.
351                 if (m_preferredStylesheetSetName.isEmpty()) {
352                     // No preferred set has been established. If
353                     // we are NOT an alternate sheet, then establish
354                     // us as the preferred set. Otherwise, just ignore
355                     // this sheet.
356                     if (is<HTMLStyleElement>(element) || !rel.contains("alternate"))
357                         m_preferredStylesheetSetName = m_selectedStylesheetSetName = title;
358                 }
359                 if (title != m_preferredStylesheetSetName)
360                     sheet = nullptr;
361             }
362
363             if (rel.contains("alternate") && title.isEmpty())
364                 sheet = nullptr;
365         }
366         if (sheet)
367             sheets.append(sheet);
368     }
369 }
370
371 Scope::StyleResolverUpdateType Scope::analyzeStyleSheetChange(const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc)
372 {
373     requiresFullStyleRecalc = true;
374     
375     unsigned newStylesheetCount = newStylesheets.size();
376
377     if (!resolverIfExists())
378         return Reconstruct;
379
380     auto& styleResolver = *resolverIfExists();
381
382     // Find out which stylesheets are new.
383     unsigned oldStylesheetCount = m_activeStyleSheets.size();
384     if (newStylesheetCount < oldStylesheetCount)
385         return Reconstruct;
386
387     Vector<StyleSheetContents*> addedSheets;
388     unsigned newIndex = 0;
389     for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
390         if (newIndex >= newStylesheetCount)
391             return Reconstruct;
392         while (m_activeStyleSheets[oldIndex] != newStylesheets[newIndex]) {
393             addedSheets.append(&newStylesheets[newIndex]->contents());
394             ++newIndex;
395             if (newIndex == newStylesheetCount)
396                 return Reconstruct;
397         }
398         ++newIndex;
399     }
400     bool hasInsertions = !addedSheets.isEmpty();
401     while (newIndex < newStylesheetCount) {
402         addedSheets.append(&newStylesheets[newIndex]->contents());
403         ++newIndex;
404     }
405     // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
406     // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
407     auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
408
409     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
410     if (!m_document.bodyOrFrameset() || m_document.hasNodesWithNonFinalStyle() || m_document.hasNodesWithMissingStyle())
411         return styleResolverUpdateType;
412
413     Invalidator invalidator(addedSheets, styleResolver.mediaQueryEvaluator());
414     if (invalidator.dirtiesAllStyle())
415         return styleResolverUpdateType;
416
417     if (m_shadowRoot)
418         invalidator.invalidateStyle(*m_shadowRoot);
419     else
420         invalidator.invalidateStyle(m_document);
421
422     requiresFullStyleRecalc = false;
423
424     return styleResolverUpdateType;
425 }
426
427 static void filterEnabledNonemptyCSSStyleSheets(Vector<RefPtr<CSSStyleSheet>>& result, const Vector<RefPtr<StyleSheet>>& sheets)
428 {
429     for (auto& sheet : sheets) {
430         if (!is<CSSStyleSheet>(*sheet))
431             continue;
432         CSSStyleSheet& styleSheet = downcast<CSSStyleSheet>(*sheet);
433         if (styleSheet.isLoading())
434             continue;
435         if (styleSheet.disabled())
436             continue;
437         if (!styleSheet.length())
438             continue;
439         result.append(&styleSheet);
440     }
441 }
442
443 void Scope::updateActiveStyleSheets(UpdateType updateType)
444 {
445     ASSERT(!m_pendingUpdate);
446
447     if (!m_document.hasLivingRenderTree())
448         return;
449
450     if (m_document.inStyleRecalc() || m_document.inRenderTreeUpdate()) {
451         // Protect against deleting style resolver in the middle of a style resolution.
452         // Crash stacks indicate we can get here when a resource load fails synchronously (for example due to content blocking).
453         // FIXME: These kind of cases should be eliminated and this path replaced by an assert.
454         m_pendingUpdate = UpdateType::ContentsOrInterpretation;
455         m_document.scheduleForcedStyleRecalc();
456         return;
457     }
458
459     Vector<RefPtr<StyleSheet>> activeStyleSheets;
460     collectActiveStyleSheets(activeStyleSheets);
461
462     Vector<RefPtr<CSSStyleSheet>> activeCSSStyleSheets;
463     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
464     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
465     filterEnabledNonemptyCSSStyleSheets(activeCSSStyleSheets, activeStyleSheets);
466
467     bool requiresFullStyleRecalc = true;
468     StyleResolverUpdateType styleResolverUpdateType = Reconstruct;
469     if (updateType == UpdateType::ActiveSet)
470         styleResolverUpdateType = analyzeStyleSheetChange(activeCSSStyleSheets, requiresFullStyleRecalc);
471
472     updateStyleResolver(activeCSSStyleSheets, styleResolverUpdateType);
473
474     m_weakCopyOfActiveStyleSheetListForFastLookup = nullptr;
475     m_activeStyleSheets.swap(activeCSSStyleSheets);
476     m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
477
478     InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
479
480     for (const auto& sheet : m_activeStyleSheets) {
481         if (sheet->contents().usesStyleBasedEditability())
482             m_usesStyleBasedEditability = true;
483     }
484
485     // FIXME: Move this code somewhere else.
486     if (requiresFullStyleRecalc) {
487         if (m_shadowRoot) {
488             for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot))
489                 shadowChild.invalidateStyleForSubtree();
490             if (m_shadowRoot->host()) {
491                 if (!resolver().ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
492                     m_shadowRoot->host()->invalidateStyle();
493                 if (!resolver().ruleSets().authorStyle().slottedPseudoElementRules().isEmpty()) {
494                     for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot->host()))
495                         shadowChild.invalidateStyle();
496                 }
497             }
498         } else
499             m_document.scheduleForcedStyleRecalc();
500     }
501 }
502
503 void Scope::updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>& activeStyleSheets, StyleResolverUpdateType updateType)
504 {
505     if (updateType == Reconstruct) {
506         clearResolver();
507         return;
508     }
509     auto& styleResolver = resolver();
510
511     SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
512     if (updateType == Reset) {
513         styleResolver.ruleSets().resetAuthorStyle();
514         styleResolver.appendAuthorStyleSheets(activeStyleSheets);
515     } else {
516         ASSERT(updateType == Additive);
517         unsigned firstNewIndex = m_activeStyleSheets.size();
518         Vector<RefPtr<CSSStyleSheet>> newStyleSheets;
519         newStyleSheets.appendRange(activeStyleSheets.begin() + firstNewIndex, activeStyleSheets.end());
520         styleResolver.appendAuthorStyleSheets(newStyleSheets);
521     }
522 }
523
524 const Vector<RefPtr<CSSStyleSheet>> Scope::activeStyleSheetsForInspector()
525 {
526     Vector<RefPtr<CSSStyleSheet>> result;
527
528     result.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
529     result.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
530
531     for (auto& styleSheet : m_styleSheetsForStyleSheetList) {
532         if (!is<CSSStyleSheet>(*styleSheet))
533             continue;
534
535         CSSStyleSheet& sheet = downcast<CSSStyleSheet>(*styleSheet);
536         if (sheet.disabled())
537             continue;
538
539         result.append(&sheet);
540     }
541
542     return result;
543 }
544
545 bool Scope::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
546 {
547     if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
548         m_weakCopyOfActiveStyleSheetListForFastLookup = std::make_unique<HashSet<const CSSStyleSheet*>>();
549         for (auto& activeStyleSheet : m_activeStyleSheets)
550             m_weakCopyOfActiveStyleSheetListForFastLookup->add(activeStyleSheet.get());
551     }
552     return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
553 }
554
555 void Scope::flushPendingSelfUpdate()
556 {
557     ASSERT(m_pendingUpdate);
558
559     auto updateType = *m_pendingUpdate;
560
561     clearPendingUpdate();
562     updateActiveStyleSheets(updateType);
563 }
564
565 void Scope::flushPendingDescendantUpdates()
566 {
567     ASSERT(m_hasDescendantWithPendingUpdate);
568     ASSERT(!m_shadowRoot);
569     for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
570         descendantShadowRoot->styleScope().flushPendingUpdate();
571     m_hasDescendantWithPendingUpdate = false;
572 }
573
574 void Scope::clearPendingUpdate()
575 {
576     m_pendingUpdateTimer.stop();
577     m_pendingUpdate = { };
578 }
579
580 void Scope::scheduleUpdate(UpdateType update)
581 {
582     // FIXME: The m_isUpdatingStyleResolver test is here because extension stylesheets can get us here from StyleResolver::appendAuthorStyleSheets.
583     if (update == UpdateType::ContentsOrInterpretation && !m_isUpdatingStyleResolver)
584         clearResolver();
585
586     if (!m_pendingUpdate || *m_pendingUpdate < update) {
587         m_pendingUpdate = update;
588         if (m_shadowRoot)
589             m_document.styleScope().m_hasDescendantWithPendingUpdate = true;
590     }
591
592     if (m_pendingUpdateTimer.isActive())
593         return;
594     m_pendingUpdateTimer.startOneShot(0_s);
595 }
596
597 void Scope::didChangeActiveStyleSheetCandidates()
598 {
599     scheduleUpdate(UpdateType::ActiveSet);
600 }
601
602 void Scope::didChangeStyleSheetContents()
603 {
604     scheduleUpdate(UpdateType::ContentsOrInterpretation);
605 }
606
607 void Scope::didChangeStyleSheetEnvironment()
608 {
609     if (!m_shadowRoot) {
610         for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots()) {
611             // Stylesheets is author shadow roots are potentially affected.
612             if (descendantShadowRoot->mode() != ShadowRootMode::UserAgent)
613                 descendantShadowRoot->styleScope().scheduleUpdate(UpdateType::ContentsOrInterpretation);
614         }
615     }
616     scheduleUpdate(UpdateType::ContentsOrInterpretation);
617 }
618
619 void Scope::pendingUpdateTimerFired()
620 {
621     flushPendingUpdate();
622 }
623
624 const Vector<RefPtr<StyleSheet>>& Scope::styleSheetsForStyleSheetList()
625 {
626     // FIXME: StyleSheetList content should be updated separately from style resolver updates.
627     flushPendingUpdate();
628     return m_styleSheetsForStyleSheetList;
629 }
630
631 }
632 }