Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  *           (C) 2006 Alexey Proskuryakov (ap (at) 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 
     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 
     82 StyleEngine::~StyleEngine()
     83 {
     84 }
     85 
     86 #if !ENABLE(OILPAN)
     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 
    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 
    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 
    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 
    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 
    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 
    176 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const
    177 {
    178     return documentStyleSheetCollection()->activeAuthorStyleSheets();
    179 }
    180 
    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 
    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 
    196 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const
    197 {
    198     updateInjectedStyleSheetCache();
    199     return m_injectedAuthorStyleSheets;
    200 }
    201 
    202 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 
    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 
    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 
    242 void StyleEngine::addPendingSheet()
    243 {
    244     m_pendingStylesheets++;
    245 }
    246 
    247 // This method is called whenever a top-level stylesheet has finished loading.
    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 
    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 
    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 
    298 void StyleEngine::removeStyleSheetCandidateNode(Node* node)
    299 {
    300     removeStyleSheetCandidateNode(node, 0, *m_document);
    301 }
    302 
    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 
    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 
    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 
    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 
    357 void StyleEngine::enableExitTransitionStylesheets()
    358 {
    359     TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(*m_document);
    360     collection->enableExitTransitionStylesheets();
    361 }
    362 
    363 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const
    364 {
    365     return m_documentScopeDirty || updateMode == FullStyleUpdate;
    366 }
    367 
    368 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const
    369 {
    370     return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
    371 }
    372 
    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 
    384 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
    385 {
    386     documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
    387     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
    388     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
    389 }
    390 
    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 
    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 
    434 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 
    456 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
    457 {
    458     m_styleSheetCollectionMap.remove(shadowRoot);
    459 }
    460 
    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 
    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 
    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 
    502 void StyleEngine::clearMasterResolver()
    503 {
    504     if (Document* master = this->master())
    505         master->styleEngine()->clearResolver();
    506 }
    507 
    508 unsigned StyleEngine::resolverAccessCount() const
    509 {
    510     return m_resolver ? m_resolver->accessCount() : 0;
    511 }
    512 
    513 void StyleEngine::didDetach()
    514 {
    515     clearResolver();
    516 }
    517 
    518 bool StyleEngine::shouldClearResolver() const
    519 {
    520     return !m_didCalculateResolver && !haveStylesheetsLoaded();
    521 }
    522 
    523 bool StyleEngine::shouldApplyXSLTransform() const
    524 {
    525     if (!RuntimeEnabledFeatures::xsltEnabled())
    526         return false;
    527     return m_xslStyleSheet && !m_document->transformSourceDocument();
    528 }
    529 
    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 
    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 
    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 
    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 
    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 
    603 void StyleEngine::markDocumentDirty()
    604 {
    605     m_documentScopeDirty = true;
    606     if (document().importLoader())
    607         document().importsController()->master()->styleEngine()->markDocumentDirty();
    608 }
    609 
    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 
    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 
    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 
    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 
    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 
    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