• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2005, 2006, 2007, 2008, 2009, 2011, 2012 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 "core/dom/StyleEngine.h"
30 
31 #include "core/HTMLNames.h"
32 #include "core/css/CSSFontSelector.h"
33 #include "core/css/CSSStyleSheet.h"
34 #include "core/css/FontFaceCache.h"
35 #include "core/css/StyleSheetContents.h"
36 #include "core/dom/DocumentStyleSheetCollector.h"
37 #include "core/dom/Element.h"
38 #include "core/dom/ProcessingInstruction.h"
39 #include "core/dom/ShadowTreeStyleSheetCollection.h"
40 #include "core/dom/shadow/ShadowRoot.h"
41 #include "core/html/HTMLIFrameElement.h"
42 #include "core/html/HTMLLinkElement.h"
43 #include "core/html/imports/HTMLImportsController.h"
44 #include "core/inspector/InspectorInstrumentation.h"
45 #include "core/page/InjectedStyleSheets.h"
46 #include "core/page/Page.h"
47 #include "core/frame/Settings.h"
48 #include "platform/URLPatternMatcher.h"
49 
50 namespace WebCore {
51 
52 using namespace HTMLNames;
53 
StyleEngine(Document & document)54 StyleEngine::StyleEngine(Document& document)
55     : m_document(&document)
56     , m_isMaster(!document.importsController() || document.importsController()->master() == &document)
57     , m_pendingStylesheets(0)
58     , m_injectedStyleSheetCacheValid(false)
59 #if ENABLE(OILPAN)
60     , m_documentStyleSheetCollection(new DocumentStyleSheetCollection(document))
61 #else
62     , m_documentStyleSheetCollection(document)
63 #endif
64     , m_documentScopeDirty(true)
65     , m_usesSiblingRules(false)
66     , m_usesSiblingRulesOverride(false)
67     , m_usesFirstLineRules(false)
68     , m_usesFirstLetterRules(false)
69     , m_usesRemUnits(false)
70     , m_maxDirectAdjacentSelectors(0)
71     , m_ignorePendingStylesheets(false)
72     , m_didCalculateResolver(false)
73     // We don't need to create CSSFontSelector for imported document or
74     // HTMLTemplateElement's document, because those documents have no frame.
75     , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : nullptr)
76     , m_xslStyleSheet(nullptr)
77 {
78     if (m_fontSelector)
79         m_fontSelector->registerForInvalidationCallbacks(this);
80 }
81 
~StyleEngine()82 StyleEngine::~StyleEngine()
83 {
84 }
85 
86 #if !ENABLE(OILPAN)
detachFromDocument()87 void StyleEngine::detachFromDocument()
88 {
89     // Cleanup is performed eagerly when the StyleEngine is removed from the
90     // document. The StyleEngine is unreachable after this, since only the
91     // document has a reference to it.
92     for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i)
93         m_injectedAuthorStyleSheets[i]->clearOwnerNode();
94     for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i)
95         m_authorStyleSheets[i]->clearOwnerNode();
96 
97     if (m_fontSelector) {
98         m_fontSelector->clearDocument();
99         m_fontSelector->unregisterForInvalidationCallbacks(this);
100     }
101 
102     // Decrement reference counts for things we could be keeping alive.
103     m_fontSelector.clear();
104     m_resolver.clear();
105     m_styleSheetCollectionMap.clear();
106 }
107 #endif
108 
master()109 inline Document* StyleEngine::master()
110 {
111     if (isMaster())
112         return m_document;
113     HTMLImportsController* import = document().importsController();
114     if (!import) // Document::import() can return null while executing its destructor.
115         return 0;
116     return import->master();
117 }
118 
insertTreeScopeInDocumentOrder(TreeScopeSet & treeScopes,TreeScope * treeScope)119 void StyleEngine::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope)
120 {
121     if (treeScopes.isEmpty()) {
122         treeScopes.add(treeScope);
123         return;
124     }
125     if (treeScopes.contains(treeScope))
126         return;
127 
128     TreeScopeSet::iterator begin = treeScopes.begin();
129     TreeScopeSet::iterator end = treeScopes.end();
130     TreeScopeSet::iterator it = end;
131     TreeScope* followingTreeScope = 0;
132     do {
133         --it;
134         TreeScope* n = *it;
135         unsigned short position = n->comparePosition(*treeScope);
136         if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
137             treeScopes.insertBefore(followingTreeScope, treeScope);
138             return;
139         }
140         followingTreeScope = n;
141     } while (it != begin);
142 
143     treeScopes.insertBefore(followingTreeScope, treeScope);
144 }
145 
ensureStyleSheetCollectionFor(TreeScope & treeScope)146 TreeScopeStyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope)
147 {
148     if (treeScope == m_document)
149         return documentStyleSheetCollection();
150 
151     StyleSheetCollectionMap::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr);
152     if (result.isNewEntry)
153         result.storedValue->value = adoptPtrWillBeNoop(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
154     return result.storedValue->value.get();
155 }
156 
styleSheetCollectionFor(TreeScope & treeScope)157 TreeScopeStyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope)
158 {
159     if (treeScope == m_document)
160         return documentStyleSheetCollection();
161 
162     StyleSheetCollectionMap::iterator it = m_styleSheetCollectionMap.find(&treeScope);
163     if (it == m_styleSheetCollectionMap.end())
164         return 0;
165     return it->value.get();
166 }
167 
styleSheetsForStyleSheetList(TreeScope & treeScope)168 const WillBeHeapVector<RefPtrWillBeMember<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope)
169 {
170     if (treeScope == m_document)
171         return documentStyleSheetCollection()->styleSheetsForStyleSheetList();
172 
173     return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList();
174 }
175 
activeAuthorStyleSheets() const176 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const
177 {
178     return documentStyleSheetCollection()->activeAuthorStyleSheets();
179 }
180 
combineCSSFeatureFlags(const RuleFeatureSet & features)181 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features)
182 {
183     // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after).
184     m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules();
185     m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules();
186     m_maxDirectAdjacentSelectors = max(m_maxDirectAdjacentSelectors, features.maxDirectAdjacentSelectors());
187 }
188 
resetCSSFeatureFlags(const RuleFeatureSet & features)189 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features)
190 {
191     m_usesSiblingRules = features.usesSiblingRules();
192     m_usesFirstLineRules = features.usesFirstLineRules();
193     m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors();
194 }
195 
injectedAuthorStyleSheets() const196 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const
197 {
198     updateInjectedStyleSheetCache();
199     return m_injectedAuthorStyleSheets;
200 }
201 
updateInjectedStyleSheetCache() const202 void StyleEngine::updateInjectedStyleSheetCache() const
203 {
204     if (m_injectedStyleSheetCacheValid)
205         return;
206     m_injectedStyleSheetCacheValid = true;
207     m_injectedAuthorStyleSheets.clear();
208 
209     Page* owningPage = document().page();
210     if (!owningPage)
211         return;
212 
213     const InjectedStyleSheetEntryVector& entries = InjectedStyleSheets::instance().entries();
214     for (unsigned i = 0; i < entries.size(); ++i) {
215         const InjectedStyleSheetEntry* entry = entries[i].get();
216         if (entry->injectedFrames() == InjectStyleInTopFrameOnly && document().ownerElement())
217             continue;
218         if (!URLPatternMatcher::matchesPatterns(document().url(), entry->whitelist()))
219             continue;
220         RefPtrWillBeRawPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(m_document, KURL());
221         m_injectedAuthorStyleSheets.append(groupSheet);
222         groupSheet->contents()->parseString(entry->source());
223     }
224 }
225 
invalidateInjectedStyleSheetCache()226 void StyleEngine::invalidateInjectedStyleSheetCache()
227 {
228     m_injectedStyleSheetCacheValid = false;
229     markDocumentDirty();
230     // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets
231     // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet().
232     document().styleResolverChanged();
233 }
234 
addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet)235 void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet)
236 {
237     m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
238     document().addedStyleSheet(m_authorStyleSheets.last().get());
239     markDocumentDirty();
240 }
241 
addPendingSheet()242 void StyleEngine::addPendingSheet()
243 {
244     m_pendingStylesheets++;
245 }
246 
247 // This method is called whenever a top-level stylesheet has finished loading.
removePendingSheet(Node * styleSheetCandidateNode)248 void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode)
249 {
250     ASSERT(styleSheetCandidateNode);
251     TreeScope* treeScope = isHTMLStyleElement(*styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : m_document.get();
252     markTreeScopeDirty(*treeScope);
253 
254     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
255     ASSERT(m_pendingStylesheets > 0);
256 
257     m_pendingStylesheets--;
258     if (m_pendingStylesheets)
259         return;
260 
261     // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know
262     // what's new. We should track that to tell the style system what changed.
263     document().didRemoveAllPendingStylesheet();
264 }
265 
modifiedStyleSheet(StyleSheet * sheet)266 void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
267 {
268     if (!sheet)
269         return;
270 
271     Node* node = sheet->ownerNode();
272     if (!node || !node->inDocument())
273         return;
274 
275     TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document;
276     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
277 
278     markTreeScopeDirty(treeScope);
279 }
280 
addStyleSheetCandidateNode(Node * node,bool createdByParser)281 void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser)
282 {
283     if (!node->inDocument())
284         return;
285 
286     TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document;
287     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
288     ASSERT(!isXSLStyleSheet(*node));
289     TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
290     ASSERT(collection);
291     collection->addStyleSheetCandidateNode(node, createdByParser);
292 
293     markTreeScopeDirty(treeScope);
294     if (treeScope != m_document)
295         insertTreeScopeInDocumentOrder(m_activeTreeScopes, &treeScope);
296 }
297 
removeStyleSheetCandidateNode(Node * node)298 void StyleEngine::removeStyleSheetCandidateNode(Node* node)
299 {
300     removeStyleSheetCandidateNode(node, 0, *m_document);
301 }
302 
removeStyleSheetCandidateNode(Node * node,ContainerNode * scopingNode,TreeScope & treeScope)303 void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode, TreeScope& treeScope)
304 {
305     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
306     ASSERT(!isXSLStyleSheet(*node));
307 
308     TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
309     ASSERT(collection);
310     collection->removeStyleSheetCandidateNode(node, scopingNode);
311 
312     markTreeScopeDirty(treeScope);
313     m_activeTreeScopes.remove(&treeScope);
314 }
315 
addXSLStyleSheet(ProcessingInstruction * node,bool createdByParser)316 void StyleEngine::addXSLStyleSheet(ProcessingInstruction* node, bool createdByParser)
317 {
318     if (!node->inDocument())
319         return;
320 
321     ASSERT(isXSLStyleSheet(*node));
322     bool needToUpdate = false;
323     if (createdByParser || !m_xslStyleSheet) {
324         needToUpdate = !m_xslStyleSheet;
325     } else {
326         unsigned position = m_xslStyleSheet->compareDocumentPositionInternal(node, Node::TreatShadowTreesAsDisconnected);
327         needToUpdate = position & Node::DOCUMENT_POSITION_FOLLOWING;
328     }
329 
330     if (!needToUpdate)
331         return;
332 
333     markTreeScopeDirty(*m_document);
334     m_xslStyleSheet = node;
335 }
336 
removeXSLStyleSheet(ProcessingInstruction * node)337 void StyleEngine::removeXSLStyleSheet(ProcessingInstruction* node)
338 {
339     ASSERT(isXSLStyleSheet(*node));
340     if (m_xslStyleSheet != node)
341         return;
342 
343     markTreeScopeDirty(*m_document);
344     m_xslStyleSheet = nullptr;
345 }
346 
modifiedStyleSheetCandidateNode(Node * node)347 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node)
348 {
349     if (!node->inDocument())
350         return;
351 
352     TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document;
353     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
354     markTreeScopeDirty(treeScope);
355 }
356 
enableExitTransitionStylesheets()357 void StyleEngine::enableExitTransitionStylesheets()
358 {
359     TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(*m_document);
360     collection->enableExitTransitionStylesheets();
361 }
362 
shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const363 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const
364 {
365     return m_documentScopeDirty || updateMode == FullStyleUpdate;
366 }
367 
shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const368 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const
369 {
370     return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
371 }
372 
clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet treeScopes)373 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet treeScopes)
374 {
375     for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
376         TreeScope& treeScope = **it;
377         ASSERT(treeScope != m_document);
378         ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope));
379         ASSERT(collection);
380         collection->clearMediaQueryRuleSetStyleSheets();
381     }
382 }
383 
clearMediaQueryRuleSetStyleSheets()384 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
385 {
386     documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
387     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
388     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
389 }
390 
updateStyleSheetsInImport(DocumentStyleSheetCollector & parentCollector)391 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector)
392 {
393     ASSERT(!isMaster());
394     WillBeHeapVector<RefPtrWillBeMember<StyleSheet> > sheetsForList;
395     ImportedDocumentStyleSheetCollector subcollector(parentCollector, sheetsForList);
396     documentStyleSheetCollection()->collectStyleSheets(this, subcollector);
397     documentStyleSheetCollection()->swapSheetsForSheetList(sheetsForList);
398 }
399 
updateActiveStyleSheets(StyleResolverUpdateMode updateMode)400 void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
401 {
402     ASSERT(isMaster());
403     ASSERT(!document().inStyleRecalc());
404 
405     if (!document().isActive())
406         return;
407 
408     if (shouldUpdateDocumentStyleSheetCollection(updateMode))
409         documentStyleSheetCollection()->updateActiveStyleSheets(this, updateMode);
410 
411     if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
412         TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
413         HashSet<TreeScope*> treeScopesRemoved;
414 
415         for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
416             TreeScope* treeScope = *it;
417             ASSERT(treeScope != m_document);
418             ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
419             ASSERT(collection);
420             collection->updateActiveStyleSheets(this, updateMode);
421             if (!collection->hasStyleSheetCandidateNodes())
422                 treeScopesRemoved.add(treeScope);
423         }
424         m_activeTreeScopes.removeAll(treeScopesRemoved);
425     }
426 
427     InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
428     m_usesRemUnits = documentStyleSheetCollection()->usesRemUnits();
429 
430     m_dirtyTreeScopes.clear();
431     m_documentScopeDirty = false;
432 }
433 
activeStyleSheetsForInspector() const434 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > StyleEngine::activeStyleSheetsForInspector() const
435 {
436     if (m_activeTreeScopes.isEmpty())
437         return documentStyleSheetCollection()->activeAuthorStyleSheets();
438 
439     WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > activeStyleSheets;
440 
441     activeStyleSheets.appendVector(documentStyleSheetCollection()->activeAuthorStyleSheets());
442 
443     TreeScopeSet::const_iterator begin = m_activeTreeScopes.begin();
444     TreeScopeSet::const_iterator end = m_activeTreeScopes.end();
445     for (TreeScopeSet::const_iterator it = begin; it != end; ++it) {
446         if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it))
447             activeStyleSheets.appendVector(collection->activeAuthorStyleSheets());
448     }
449 
450     // FIXME: Inspector needs a vector which has all active stylesheets.
451     // However, creating such a large vector might cause performance regression.
452     // Need to implement some smarter solution.
453     return activeStyleSheets;
454 }
455 
didRemoveShadowRoot(ShadowRoot * shadowRoot)456 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
457 {
458     m_styleSheetCollectionMap.remove(shadowRoot);
459 }
460 
appendActiveAuthorStyleSheets()461 void StyleEngine::appendActiveAuthorStyleSheets()
462 {
463     ASSERT(isMaster());
464 
465     m_resolver->setBuildScopedStyleTreeInDocumentOrder(true);
466     m_resolver->appendAuthorStyleSheets(documentStyleSheetCollection()->activeAuthorStyleSheets());
467 
468     TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
469     TreeScopeSet::iterator end = m_activeTreeScopes.end();
470     for (TreeScopeSet::iterator it = begin; it != end; ++it) {
471         if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) {
472             m_resolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped());
473             m_resolver->appendAuthorStyleSheets(collection->activeAuthorStyleSheets());
474         }
475     }
476     m_resolver->finishAppendAuthorStyleSheets();
477     m_resolver->setBuildScopedStyleTreeInDocumentOrder(false);
478 }
479 
createResolver()480 void StyleEngine::createResolver()
481 {
482     // It is a programming error to attempt to resolve style on a Document
483     // which is not in a frame. Code which hits this should have checked
484     // Document::isActive() before calling into code which could get here.
485 
486     ASSERT(document().frame());
487 
488     m_resolver = adoptPtrWillBeNoop(new StyleResolver(*m_document));
489     appendActiveAuthorStyleSheets();
490     combineCSSFeatureFlags(m_resolver->ensureUpdatedRuleFeatureSet());
491 }
492 
clearResolver()493 void StyleEngine::clearResolver()
494 {
495     ASSERT(!document().inStyleRecalc());
496     ASSERT(isMaster() || !m_resolver);
497     if (m_resolver)
498         document().updateStyleInvalidationIfNeeded();
499     m_resolver.clear();
500 }
501 
clearMasterResolver()502 void StyleEngine::clearMasterResolver()
503 {
504     if (Document* master = this->master())
505         master->styleEngine()->clearResolver();
506 }
507 
resolverAccessCount() const508 unsigned StyleEngine::resolverAccessCount() const
509 {
510     return m_resolver ? m_resolver->accessCount() : 0;
511 }
512 
didDetach()513 void StyleEngine::didDetach()
514 {
515     clearResolver();
516 }
517 
shouldClearResolver() const518 bool StyleEngine::shouldClearResolver() const
519 {
520     return !m_didCalculateResolver && !haveStylesheetsLoaded();
521 }
522 
shouldApplyXSLTransform() const523 bool StyleEngine::shouldApplyXSLTransform() const
524 {
525     if (!RuntimeEnabledFeatures::xsltEnabled())
526         return false;
527     return m_xslStyleSheet && !m_document->transformSourceDocument();
528 }
529 
resolverChanged(StyleResolverUpdateMode mode)530 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode)
531 {
532     if (!isMaster()) {
533         if (Document* master = this->master())
534             master->styleResolverChanged(mode);
535         return;
536     }
537 
538     // Don't bother updating, since we haven't loaded all our style info yet
539     // and haven't calculated the style selector for the first time.
540     if (!document().isActive() || shouldClearResolver()) {
541         clearResolver();
542         return;
543     }
544 
545     if (shouldApplyXSLTransform()) {
546         // Processing instruction (XML documents only).
547         // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
548         // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
549         if (!m_document->parsing() && !m_xslStyleSheet->isLoading())
550             m_document->applyXSLTransform(m_xslStyleSheet.get());
551         return;
552     }
553 
554     m_didCalculateResolver = true;
555     updateActiveStyleSheets(mode);
556 }
557 
clearFontCache()558 void StyleEngine::clearFontCache()
559 {
560     // We should not recreate FontSelector. Instead, clear fontFaceCache.
561     if (m_fontSelector)
562         m_fontSelector->fontFaceCache()->clear();
563     if (m_resolver)
564         m_resolver->invalidateMatchedPropertiesCache();
565 }
566 
updateGenericFontFamilySettings()567 void StyleEngine::updateGenericFontFamilySettings()
568 {
569     // FIXME: we should not update generic font family settings when
570     // document is inactive.
571     ASSERT(document().isActive());
572 
573     if (!m_fontSelector)
574         return;
575 
576     m_fontSelector->updateGenericFontFamilySettings(*m_document);
577     if (m_resolver)
578         m_resolver->invalidateMatchedPropertiesCache();
579 }
580 
removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>> & fontFaceRules)581 void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
582 {
583     if (!m_fontSelector)
584         return;
585 
586     FontFaceCache* cache = m_fontSelector->fontFaceCache();
587     for (unsigned i = 0; i < fontFaceRules.size(); ++i)
588         cache->remove(fontFaceRules[i]);
589     if (m_resolver)
590         m_resolver->invalidateMatchedPropertiesCache();
591 }
592 
markTreeScopeDirty(TreeScope & scope)593 void StyleEngine::markTreeScopeDirty(TreeScope& scope)
594 {
595     if (scope == m_document) {
596         markDocumentDirty();
597         return;
598     }
599 
600     m_dirtyTreeScopes.add(&scope);
601 }
602 
markDocumentDirty()603 void StyleEngine::markDocumentDirty()
604 {
605     m_documentScopeDirty = true;
606     if (document().importLoader())
607         document().importsController()->master()->styleEngine()->markDocumentDirty();
608 }
609 
isCacheableForStyleElement(const StyleSheetContents & contents)610 static bool isCacheableForStyleElement(const StyleSheetContents& contents)
611 {
612     // FIXME: Support copying import rules.
613     if (!contents.importRules().isEmpty())
614         return false;
615     // Until import rules are supported in cached sheets it's not possible for loading to fail.
616     ASSERT(!contents.didLoadErrorOccur());
617     // It is not the original sheet anymore.
618     if (contents.isMutable())
619         return false;
620     if (!contents.hasSyntacticallyValidCSSHeader())
621         return false;
622     return true;
623 }
624 
createSheet(Element * e,const String & text,TextPosition startPosition,bool createdByParser)625 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::createSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser)
626 {
627     RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr;
628 
629     e->document().styleEngine()->addPendingSheet();
630 
631     if (!e->document().inQuirksMode()) {
632         AtomicString textContent(text);
633 
634         WillBeHeapHashMap<AtomicString, RawPtrWillBeMember<StyleSheetContents> >::AddResult result = m_textToSheetCache.add(textContent, nullptr);
635         if (result.isNewEntry || !result.storedValue->value) {
636             styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser);
637             if (result.isNewEntry && isCacheableForStyleElement(*styleSheet->contents())) {
638                 result.storedValue->value = styleSheet->contents();
639                 m_sheetToTextCache.add(styleSheet->contents(), textContent);
640             }
641         } else {
642             StyleSheetContents* contents = result.storedValue->value;
643             ASSERT(contents);
644             ASSERT(isCacheableForStyleElement(*contents));
645             ASSERT(contents->singleOwnerDocument() == e->document());
646             styleSheet = CSSStyleSheet::createInline(contents, e, startPosition);
647         }
648     } else {
649         // FIXME: currently we don't cache StyleSheetContents inQuirksMode.
650         styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser);
651     }
652 
653     ASSERT(styleSheet);
654     styleSheet->setTitle(e->title());
655     return styleSheet;
656 }
657 
parseSheet(Element * e,const String & text,TextPosition startPosition,bool createdByParser)658 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::parseSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser)
659 {
660     RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr;
661     styleSheet = CSSStyleSheet::createInline(e, KURL(), startPosition, e->document().inputEncoding());
662     styleSheet->contents()->parseStringAtPosition(text, startPosition, createdByParser);
663     return styleSheet;
664 }
665 
removeSheet(StyleSheetContents * contents)666 void StyleEngine::removeSheet(StyleSheetContents* contents)
667 {
668     WillBeHeapHashMap<RawPtrWillBeMember<StyleSheetContents>, AtomicString>::iterator it = m_sheetToTextCache.find(contents);
669     if (it == m_sheetToTextCache.end())
670         return;
671 
672     m_textToSheetCache.remove(it->value);
673     m_sheetToTextCache.remove(contents);
674 }
675 
fontsNeedUpdate(CSSFontSelector *)676 void StyleEngine::fontsNeedUpdate(CSSFontSelector*)
677 {
678     if (!document().isActive())
679         return;
680 
681     if (m_resolver)
682         m_resolver->invalidateMatchedPropertiesCache();
683     document().setNeedsStyleRecalc(SubtreeStyleChange);
684 }
685 
trace(Visitor * visitor)686 void StyleEngine::trace(Visitor* visitor)
687 {
688     visitor->trace(m_document);
689     visitor->trace(m_injectedAuthorStyleSheets);
690     visitor->trace(m_authorStyleSheets);
691     visitor->trace(m_documentStyleSheetCollection);
692     visitor->trace(m_styleSheetCollectionMap);
693     visitor->trace(m_resolver);
694     visitor->trace(m_fontSelector);
695     visitor->trace(m_textToSheetCache);
696     visitor->trace(m_sheetToTextCache);
697     visitor->trace(m_xslStyleSheet);
698     CSSFontSelectorClient::trace(visitor);
699 }
700 
701 }
702