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 blink {
     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     , 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 
     78 StyleEngine::~StyleEngine()
     79 {
     80 }
     81 
     82 #if !ENABLE(OILPAN)
     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 
    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 
    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 
    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 
    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 
    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 
    175 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const
    176 {
    177     return documentStyleSheetCollection()->activeAuthorStyleSheets();
    178 }
    179 
    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 
    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 
    195 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const
    196 {
    197     updateInjectedStyleSheetCache();
    198     return m_injectedAuthorStyleSheets;
    199 }
    200 
    201 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 
    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 
    234 void StyleEngine::compatibilityModeChanged()
    235 {
    236     if (!m_injectedAuthorStyleSheets.isEmpty())
    237         invalidateInjectedStyleSheetCache();
    238 }
    239 
    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 
    247 void StyleEngine::addPendingSheet()
    248 {
    249     m_pendingStylesheets++;
    250 }
    251 
    252 // This method is called whenever a top-level stylesheet has finished loading.
    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 
    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 
    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 
    303 void StyleEngine::removeStyleSheetCandidateNode(Node* node)
    304 {
    305     removeStyleSheetCandidateNode(node, 0, *m_document);
    306 }
    307 
    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 
    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 
    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 
    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 
    362 void StyleEngine::enableExitTransitionStylesheets()
    363 {
    364     TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(*m_document);
    365     collection->enableExitTransitionStylesheets();
    366 }
    367 
    368 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const
    369 {
    370     return m_documentScopeDirty || updateMode == FullStyleUpdate;
    371 }
    372 
    373 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const
    374 {
    375     return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
    376 }
    377 
    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 
    389 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
    390 {
    391     documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
    392     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
    393     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
    394 }
    395 
    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 
    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 
    439 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 
    461 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
    462 {
    463     if (shadowRoot->scopedStyleResolver())
    464         removeScopedStyleResolver(shadowRoot->scopedStyleResolver());
    465     m_styleSheetCollectionMap.remove(shadowRoot);
    466 }
    467 
    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 
    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 
    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 
    512 void StyleEngine::clearMasterResolver()
    513 {
    514     if (Document* master = this->master())
    515         master->styleEngine()->clearResolver();
    516 }
    517 
    518 unsigned StyleEngine::resolverAccessCount() const
    519 {
    520     return m_resolver ? m_resolver->accessCount() : 0;
    521 }
    522 
    523 void StyleEngine::didDetach()
    524 {
    525     clearResolver();
    526 }
    527 
    528 bool StyleEngine::shouldClearResolver() const
    529 {
    530     return !m_didCalculateResolver && !haveStylesheetsLoaded();
    531 }
    532 
    533 bool StyleEngine::shouldApplyXSLTransform() const
    534 {
    535     if (!RuntimeEnabledFeatures::xsltEnabled())
    536         return false;
    537     return m_xslStyleSheet && !m_document->transformSourceDocument();
    538 }
    539 
    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 
    568 void StyleEngine::clearFontCache()
    569 {
    570     if (m_fontSelector)
    571         m_fontSelector->fontFaceCache()->clearCSSConnected();
    572     if (m_resolver)
    573         m_resolver->invalidateMatchedPropertiesCache();
    574 }
    575 
    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 
    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 
    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 
    612 void StyleEngine::markDocumentDirty()
    613 {
    614     m_documentScopeDirty = true;
    615     if (document().importLoader())
    616         document().importsController()->master()->styleEngine()->markDocumentDirty();
    617 }
    618 
    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 
    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 
    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 
    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 
    685 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 
    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 
    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