Unreviewed, rolling out r216069.
[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         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 bool Scope::hasPendingSheet(const ProcessingInstruction& processingInstruction) const
237 {
238     return m_processingInstructionsWithPendingSheets.contains(&processingInstruction);
239 }
240
241 void Scope::addStyleSheetCandidateNode(Node& node, bool createdByParser)
242 {
243     if (!node.isConnected())
244         return;
245     
246     // Until the <body> exists, we have no choice but to compare document positions,
247     // since styles outside of the body and head continue to be shunted into the head
248     // (and thus can shift to end up before dynamically added DOM content that is also
249     // outside the body).
250     if ((createdByParser && m_document.bodyOrFrameset()) || m_styleSheetCandidateNodes.isEmpty()) {
251         m_styleSheetCandidateNodes.add(&node);
252         return;
253     }
254
255     // Determine an appropriate insertion point.
256     auto begin = m_styleSheetCandidateNodes.begin();
257     auto end = m_styleSheetCandidateNodes.end();
258     auto it = end;
259     Node* followingNode = nullptr;
260     do {
261         --it;
262         Node* n = *it;
263         unsigned short position = n->compareDocumentPosition(node);
264         if (position == Node::DOCUMENT_POSITION_FOLLOWING) {
265             m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
266             return;
267         }
268         followingNode = n;
269     } while (it != begin);
270     
271     m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
272 }
273
274 void Scope::removeStyleSheetCandidateNode(Node& node)
275 {
276     if (m_styleSheetCandidateNodes.remove(&node))
277         didChangeActiveStyleSheetCandidates();
278 }
279
280 void Scope::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
281 {
282     if (!m_document.settings().authorAndUserStylesEnabled())
283         return;
284
285     for (auto& node : m_styleSheetCandidateNodes) {
286         StyleSheet* sheet = nullptr;
287         if (is<ProcessingInstruction>(*node)) {
288             // Processing instruction (XML documents only).
289             // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
290             ProcessingInstruction& pi = downcast<ProcessingInstruction>(*node);
291             sheet = pi.sheet();
292 #if ENABLE(XSLT)
293             // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
294             if (pi.isXSL() && !m_document.transformSourceDocument()) {
295                 // Don't apply XSL transforms until loading is finished.
296                 if (!m_document.parsing())
297                     m_document.applyXSLTransform(&pi);
298                 return;
299             }
300 #endif
301         } else if (is<HTMLLinkElement>(*node) || is<HTMLStyleElement>(*node) || is<SVGStyleElement>(*node)) {
302             Element& element = downcast<Element>(*node);
303             AtomicString title = element.attributeWithoutSynchronization(titleAttr);
304             bool enabledViaScript = false;
305             if (is<HTMLLinkElement>(element)) {
306                 // <LINK> element
307                 HTMLLinkElement& linkElement = downcast<HTMLLinkElement>(element);
308                 if (linkElement.isDisabled())
309                     continue;
310                 enabledViaScript = linkElement.isEnabledViaScript();
311                 if (linkElement.styleSheetIsLoading()) {
312                     // it is loading but we should still decide which style sheet set to use
313                     if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) {
314                         if (!linkElement.attributeWithoutSynchronization(relAttr).contains("alternate")) {
315                             m_preferredStylesheetSetName = title;
316                             m_selectedStylesheetSetName = title;
317                         }
318                     }
319                     continue;
320                 }
321                 if (!linkElement.sheet())
322                     title = nullAtom;
323             }
324             // Get the current preferred styleset. This is the
325             // set of sheets that will be enabled.
326             if (is<SVGStyleElement>(element))
327                 sheet = downcast<SVGStyleElement>(element).sheet();
328             else if (is<HTMLLinkElement>(element))
329                 sheet = downcast<HTMLLinkElement>(element).sheet();
330             else
331                 sheet = downcast<HTMLStyleElement>(element).sheet();
332             // Check to see if this sheet belongs to a styleset
333             // (thus making it PREFERRED or ALTERNATE rather than
334             // PERSISTENT).
335             auto& rel = element.attributeWithoutSynchronization(relAttr);
336             if (!enabledViaScript && !title.isEmpty()) {
337                 // Yes, we have a title.
338                 if (m_preferredStylesheetSetName.isEmpty()) {
339                     // No preferred set has been established. If
340                     // we are NOT an alternate sheet, then establish
341                     // us as the preferred set. Otherwise, just ignore
342                     // this sheet.
343                     if (is<HTMLStyleElement>(element) || !rel.contains("alternate"))
344                         m_preferredStylesheetSetName = m_selectedStylesheetSetName = title;
345                 }
346                 if (title != m_preferredStylesheetSetName)
347                     sheet = nullptr;
348             }
349
350             if (rel.contains("alternate") && title.isEmpty())
351                 sheet = nullptr;
352         }
353         if (sheet)
354             sheets.append(sheet);
355     }
356 }
357
358 Scope::StyleResolverUpdateType Scope::analyzeStyleSheetChange(const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc)
359 {
360     requiresFullStyleRecalc = true;
361     
362     unsigned newStylesheetCount = newStylesheets.size();
363
364     if (!resolverIfExists())
365         return Reconstruct;
366
367     auto& styleResolver = *resolverIfExists();
368
369     // Find out which stylesheets are new.
370     unsigned oldStylesheetCount = m_activeStyleSheets.size();
371     if (newStylesheetCount < oldStylesheetCount)
372         return Reconstruct;
373
374     Vector<StyleSheetContents*> addedSheets;
375     unsigned newIndex = 0;
376     for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
377         if (newIndex >= newStylesheetCount)
378             return Reconstruct;
379         while (m_activeStyleSheets[oldIndex] != newStylesheets[newIndex]) {
380             addedSheets.append(&newStylesheets[newIndex]->contents());
381             ++newIndex;
382             if (newIndex == newStylesheetCount)
383                 return Reconstruct;
384         }
385         ++newIndex;
386     }
387     bool hasInsertions = !addedSheets.isEmpty();
388     while (newIndex < newStylesheetCount) {
389         addedSheets.append(&newStylesheets[newIndex]->contents());
390         ++newIndex;
391     }
392     // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
393     // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
394     auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
395
396     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
397     if (!m_document.bodyOrFrameset() || m_document.hasNodesWithNonFinalStyle() || m_document.hasNodesWithMissingStyle())
398         return styleResolverUpdateType;
399
400     StyleInvalidationAnalysis invalidationAnalysis(addedSheets, styleResolver.mediaQueryEvaluator());
401     if (invalidationAnalysis.dirtiesAllStyle())
402         return styleResolverUpdateType;
403
404     if (m_shadowRoot)
405         invalidationAnalysis.invalidateStyle(*m_shadowRoot);
406     else
407         invalidationAnalysis.invalidateStyle(m_document);
408
409     requiresFullStyleRecalc = false;
410
411     return styleResolverUpdateType;
412 }
413
414 static void filterEnabledNonemptyCSSStyleSheets(Vector<RefPtr<CSSStyleSheet>>& result, const Vector<RefPtr<StyleSheet>>& sheets)
415 {
416     for (auto& sheet : sheets) {
417         if (!is<CSSStyleSheet>(*sheet))
418             continue;
419         CSSStyleSheet& styleSheet = downcast<CSSStyleSheet>(*sheet);
420         if (styleSheet.isLoading())
421             continue;
422         if (styleSheet.disabled())
423             continue;
424         if (!styleSheet.length())
425             continue;
426         result.append(&styleSheet);
427     }
428 }
429
430 void Scope::updateActiveStyleSheets(UpdateType updateType)
431 {
432     ASSERT(!m_pendingUpdate);
433
434     if (!m_document.hasLivingRenderTree())
435         return;
436
437     if (m_document.inStyleRecalc() || m_document.inRenderTreeUpdate()) {
438         // Protect against deleting style resolver in the middle of a style resolution.
439         // Crash stacks indicate we can get here when a resource load fails synchronously (for example due to content blocking).
440         // FIXME: These kind of cases should be eliminated and this path replaced by an assert.
441         m_pendingUpdate = UpdateType::ContentsOrInterpretation;
442         m_document.scheduleForcedStyleRecalc();
443         return;
444     }
445
446     Vector<RefPtr<StyleSheet>> activeStyleSheets;
447     collectActiveStyleSheets(activeStyleSheets);
448
449     Vector<RefPtr<CSSStyleSheet>> activeCSSStyleSheets;
450     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
451     activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
452     filterEnabledNonemptyCSSStyleSheets(activeCSSStyleSheets, activeStyleSheets);
453
454     bool requiresFullStyleRecalc = true;
455     StyleResolverUpdateType styleResolverUpdateType = Reconstruct;
456     if (updateType == UpdateType::ActiveSet)
457         styleResolverUpdateType = analyzeStyleSheetChange(activeCSSStyleSheets, requiresFullStyleRecalc);
458
459     updateStyleResolver(activeCSSStyleSheets, styleResolverUpdateType);
460
461     m_weakCopyOfActiveStyleSheetListForFastLookup = nullptr;
462     m_activeStyleSheets.swap(activeCSSStyleSheets);
463     m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
464
465     InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
466
467     for (const auto& sheet : m_activeStyleSheets) {
468         if (sheet->contents().usesStyleBasedEditability())
469             m_usesStyleBasedEditability = true;
470     }
471
472     // FIXME: Move this code somewhere else.
473     if (requiresFullStyleRecalc) {
474         if (m_shadowRoot) {
475             for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot))
476                 shadowChild.invalidateStyleForSubtree();
477             if (m_shadowRoot->host()) {
478                 if (!resolver().ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
479                     m_shadowRoot->host()->invalidateStyle();
480                 if (!resolver().ruleSets().authorStyle().slottedPseudoElementRules().isEmpty()) {
481                     for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot->host()))
482                         shadowChild.invalidateStyle();
483                 }
484             }
485         } else
486             m_document.scheduleForcedStyleRecalc();
487     }
488 }
489
490 void Scope::updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>& activeStyleSheets, StyleResolverUpdateType updateType)
491 {
492     if (updateType == Reconstruct) {
493         clearResolver();
494         return;
495     }
496     auto& styleResolver = resolver();
497
498     SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
499     if (updateType == Reset) {
500         styleResolver.ruleSets().resetAuthorStyle();
501         styleResolver.appendAuthorStyleSheets(activeStyleSheets);
502     } else {
503         ASSERT(updateType == Additive);
504         unsigned firstNewIndex = m_activeStyleSheets.size();
505         Vector<RefPtr<CSSStyleSheet>> newStyleSheets;
506         newStyleSheets.appendRange(activeStyleSheets.begin() + firstNewIndex, activeStyleSheets.end());
507         styleResolver.appendAuthorStyleSheets(newStyleSheets);
508     }
509 }
510
511 const Vector<RefPtr<CSSStyleSheet>> Scope::activeStyleSheetsForInspector()
512 {
513     Vector<RefPtr<CSSStyleSheet>> result;
514
515     result.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
516     result.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
517
518     for (auto& styleSheet : m_styleSheetsForStyleSheetList) {
519         if (!is<CSSStyleSheet>(*styleSheet))
520             continue;
521
522         CSSStyleSheet& sheet = downcast<CSSStyleSheet>(*styleSheet);
523         if (sheet.disabled())
524             continue;
525
526         result.append(&sheet);
527     }
528
529     return result;
530 }
531
532 bool Scope::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
533 {
534     if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
535         m_weakCopyOfActiveStyleSheetListForFastLookup = std::make_unique<HashSet<const CSSStyleSheet*>>();
536         for (auto& activeStyleSheet : m_activeStyleSheets)
537             m_weakCopyOfActiveStyleSheetListForFastLookup->add(activeStyleSheet.get());
538     }
539     return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
540 }
541
542 void Scope::flushPendingSelfUpdate()
543 {
544     ASSERT(m_pendingUpdate);
545
546     auto updateType = *m_pendingUpdate;
547
548     clearPendingUpdate();
549     updateActiveStyleSheets(updateType);
550 }
551
552 void Scope::flushPendingDescendantUpdates()
553 {
554     ASSERT(m_hasDescendantWithPendingUpdate);
555     ASSERT(!m_shadowRoot);
556     for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
557         descendantShadowRoot->styleScope().flushPendingUpdate();
558     m_hasDescendantWithPendingUpdate = false;
559 }
560
561 void Scope::clearPendingUpdate()
562 {
563     m_pendingUpdateTimer.stop();
564     m_pendingUpdate = { };
565 }
566
567 void Scope::scheduleUpdate(UpdateType update)
568 {
569     // FIXME: The m_isUpdatingStyleResolver test is here because extension stylesheets can get us here from StyleResolver::appendAuthorStyleSheets.
570     if (update == UpdateType::ContentsOrInterpretation && !m_isUpdatingStyleResolver)
571         clearResolver();
572
573     if (!m_pendingUpdate || *m_pendingUpdate < update) {
574         m_pendingUpdate = update;
575         if (m_shadowRoot)
576             m_document.styleScope().m_hasDescendantWithPendingUpdate = true;
577     }
578
579     if (m_pendingUpdateTimer.isActive())
580         return;
581     m_pendingUpdateTimer.startOneShot(0_s);
582 }
583
584 void Scope::didChangeActiveStyleSheetCandidates()
585 {
586     scheduleUpdate(UpdateType::ActiveSet);
587 }
588
589 void Scope::didChangeStyleSheetContents()
590 {
591     scheduleUpdate(UpdateType::ContentsOrInterpretation);
592 }
593
594 void Scope::didChangeStyleSheetEnvironment()
595 {
596     if (!m_shadowRoot) {
597         for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots()) {
598             // Stylesheets is author shadow roots are are potentially affected.
599             if (descendantShadowRoot->mode() != ShadowRootMode::UserAgent)
600                 descendantShadowRoot->styleScope().scheduleUpdate(UpdateType::ContentsOrInterpretation);
601         }
602     }
603     scheduleUpdate(UpdateType::ContentsOrInterpretation);
604 }
605
606 void Scope::pendingUpdateTimerFired()
607 {
608     flushPendingUpdate();
609 }
610
611 const Vector<RefPtr<StyleSheet>>& Scope::styleSheetsForStyleSheetList()
612 {
613     // FIXME: StyleSheetList content should be updated separately from style resolver updates.
614     flushPendingUpdate();
615     return m_styleSheetsForStyleSheetList;
616 }
617
618 }
619 }