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