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