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