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 "HTMLNames.h"
     32 #include "SVGNames.h"
     33 #include "core/css/CSSFontSelector.h"
     34 #include "core/css/CSSStyleSheet.h"
     35 #include "core/css/StyleInvalidationAnalysis.h"
     36 #include "core/css/StyleSheetContents.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/HTMLImport.h"
     43 #include "core/html/HTMLLinkElement.h"
     44 #include "core/html/HTMLStyleElement.h"
     45 #include "core/inspector/InspectorInstrumentation.h"
     46 #include "core/page/Page.h"
     47 #include "core/page/PageGroup.h"
     48 #include "core/frame/Settings.h"
     49 #include "core/svg/SVGStyleElement.h"
     50 #include "platform/URLPatternMatcher.h"
     51 
     52 namespace WebCore {
     53 
     54 using namespace HTMLNames;
     55 
     56 StyleEngine::StyleEngine(Document& document)
     57     : m_document(document)
     58     , m_isMaster(HTMLImport::isMaster(&document))
     59     , m_pendingStylesheets(0)
     60     , m_injectedStyleSheetCacheValid(false)
     61     , m_needsUpdateActiveStylesheetsOnStyleRecalc(false)
     62     , m_documentStyleSheetCollection(document)
     63     , m_documentScopeDirty(true)
     64     , m_usesSiblingRules(false)
     65     , m_usesSiblingRulesOverride(false)
     66     , m_usesFirstLineRules(false)
     67     , m_usesFirstLetterRules(false)
     68     , m_usesRemUnits(false)
     69     , m_maxDirectAdjacentSelectors(0)
     70     , m_ignorePendingStylesheets(false)
     71     , m_didCalculateResolver(false)
     72     , m_lastResolverAccessCount(0)
     73     , m_resolverThrowawayTimer(this, &StyleEngine::resolverThrowawayTimerFired)
     74     // We don't need to create CSSFontSelector for imported document or
     75     // HTMLTemplateElement's document, because those documents have no frame.
     76     , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : 0)
     77 {
     78 }
     79 
     80 StyleEngine::~StyleEngine()
     81 {
     82     for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i)
     83         m_injectedAuthorStyleSheets[i]->clearOwnerNode();
     84     for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i)
     85         m_authorStyleSheets[i]->clearOwnerNode();
     86 
     87     if (m_fontSelector) {
     88         m_fontSelector->clearDocument();
     89         if (m_resolver)
     90             m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get());
     91     }
     92 }
     93 
     94 inline Document* StyleEngine::master()
     95 {
     96     if (isMaster())
     97         return &m_document;
     98     HTMLImport* import = m_document.import();
     99     if (!import) // Document::import() can return null while executing its destructor.
    100         return 0;
    101     return import->master();
    102 }
    103 
    104 void StyleEngine::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope)
    105 {
    106     if (treeScopes.isEmpty()) {
    107         treeScopes.add(treeScope);
    108         return;
    109     }
    110     if (treeScopes.contains(treeScope))
    111         return;
    112 
    113     TreeScopeSet::iterator begin = treeScopes.begin();
    114     TreeScopeSet::iterator end = treeScopes.end();
    115     TreeScopeSet::iterator it = end;
    116     TreeScope* followingTreeScope = 0;
    117     do {
    118         --it;
    119         TreeScope* n = *it;
    120         unsigned short position = n->comparePosition(*treeScope);
    121         if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
    122             treeScopes.insertBefore(followingTreeScope, treeScope);
    123             return;
    124         }
    125         followingTreeScope = n;
    126     } while (it != begin);
    127 
    128     treeScopes.insertBefore(followingTreeScope, treeScope);
    129 }
    130 
    131 StyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope)
    132 {
    133     if (treeScope == m_document)
    134         return &m_documentStyleSheetCollection;
    135 
    136     HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr);
    137     if (result.isNewEntry)
    138         result.iterator->value = adoptPtr(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
    139     return result.iterator->value.get();
    140 }
    141 
    142 StyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope)
    143 {
    144     if (treeScope == m_document)
    145         return &m_documentStyleSheetCollection;
    146 
    147     HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::iterator it = m_styleSheetCollectionMap.find(&treeScope);
    148     if (it == m_styleSheetCollectionMap.end())
    149         return 0;
    150     return it->value.get();
    151 }
    152 
    153 const Vector<RefPtr<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope)
    154 {
    155     if (treeScope == m_document)
    156         return m_documentStyleSheetCollection.styleSheetsForStyleSheetList();
    157 
    158     return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList();
    159 }
    160 
    161 const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const
    162 {
    163     return m_documentStyleSheetCollection.activeAuthorStyleSheets();
    164 }
    165 
    166 void StyleEngine::getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const
    167 {
    168     activeAuthorStyleSheets.append(&m_documentStyleSheetCollection.activeAuthorStyleSheets());
    169 
    170     HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values begin = m_styleSheetCollectionMap.values().begin();
    171     HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values end = m_styleSheetCollectionMap.values().end();
    172     HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values it = begin;
    173     for (; it != end; ++it) {
    174         const StyleSheetCollection* collection = it->get();
    175         activeAuthorStyleSheets.append(&collection->activeAuthorStyleSheets());
    176     }
    177 }
    178 
    179 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features)
    180 {
    181     // 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).
    182     m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules();
    183     m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules();
    184     m_maxDirectAdjacentSelectors = max(m_maxDirectAdjacentSelectors, features.maxDirectAdjacentSelectors());
    185 }
    186 
    187 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features)
    188 {
    189     m_usesSiblingRules = features.usesSiblingRules();
    190     m_usesFirstLineRules = features.usesFirstLineRules();
    191     m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors();
    192 }
    193 
    194 const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const
    195 {
    196     updateInjectedStyleSheetCache();
    197     return m_injectedAuthorStyleSheets;
    198 }
    199 
    200 void StyleEngine::updateInjectedStyleSheetCache() const
    201 {
    202     if (m_injectedStyleSheetCacheValid)
    203         return;
    204     m_injectedStyleSheetCacheValid = true;
    205     m_injectedAuthorStyleSheets.clear();
    206 
    207     Page* owningPage = m_document.page();
    208     if (!owningPage)
    209         return;
    210 
    211     const PageGroup& pageGroup = owningPage->group();
    212     const InjectedStyleSheetVector& sheets = pageGroup.injectedStyleSheets();
    213     for (unsigned i = 0; i < sheets.size(); ++i) {
    214         const InjectedStyleSheet* sheet = sheets[i].get();
    215         if (sheet->injectedFrames() == InjectStyleInTopFrameOnly && m_document.ownerElement())
    216             continue;
    217         if (!URLPatternMatcher::matchesPatterns(m_document.url(), sheet->whitelist()))
    218             continue;
    219         RefPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(const_cast<Document*>(&m_document), KURL());
    220         m_injectedAuthorStyleSheets.append(groupSheet);
    221         groupSheet->contents()->parseString(sheet->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     m_document.styleResolverChanged(RecalcStyleDeferred);
    232 }
    233 
    234 void StyleEngine::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet)
    235 {
    236     m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, &m_document));
    237     m_document.addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately);
    238     markDocumentDirty();
    239 }
    240 
    241 void StyleEngine::addPendingSheet()
    242 {
    243     master()->styleEngine()->notifyPendingStyleSheetAdded();
    244 }
    245 
    246 // This method is called whenever a top-level stylesheet has finished loading.
    247 void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType notification)
    248 {
    249     TreeScope* treeScope = isHTMLStyleElement(styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : &m_document;
    250     markTreeScopeDirty(*treeScope);
    251     master()->styleEngine()->notifyPendingStyleSheetRemoved(notification);
    252 }
    253 
    254 void StyleEngine::notifyPendingStyleSheetAdded()
    255 {
    256     ASSERT(isMaster());
    257     m_pendingStylesheets++;
    258 }
    259 
    260 void StyleEngine::notifyPendingStyleSheetRemoved(RemovePendingSheetNotificationType notification)
    261 {
    262     ASSERT(isMaster());
    263     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
    264     ASSERT(m_pendingStylesheets > 0);
    265 
    266     m_pendingStylesheets--;
    267     if (m_pendingStylesheets)
    268         return;
    269 
    270     if (notification == RemovePendingSheetNotifyLater) {
    271         m_document.setNeedsNotifyRemoveAllPendingStylesheet();
    272         return;
    273     }
    274 
    275     // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know
    276     // what's new. We should track that to tell the style system what changed.
    277     m_document.didRemoveAllPendingStylesheet();
    278 }
    279 
    280 void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
    281 {
    282     if (!sheet)
    283         return;
    284 
    285     Node* node = sheet->ownerNode();
    286     if (!node || !node->inDocument())
    287         return;
    288 
    289     TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
    290     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
    291 
    292     markTreeScopeDirty(treeScope);
    293 }
    294 
    295 void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser)
    296 {
    297     if (!node->inDocument())
    298         return;
    299 
    300     TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
    301     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
    302 
    303     StyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
    304     ASSERT(collection);
    305     collection->addStyleSheetCandidateNode(node, createdByParser);
    306 
    307     markTreeScopeDirty(treeScope);
    308     if (treeScope != m_document)
    309         insertTreeScopeInDocumentOrder(m_activeTreeScopes, &treeScope);
    310 }
    311 
    312 void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode)
    313 {
    314     TreeScope& treeScope = scopingNode ? scopingNode->treeScope() : m_document;
    315     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
    316 
    317     StyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
    318     ASSERT(collection);
    319     collection->removeStyleSheetCandidateNode(node, scopingNode);
    320 
    321     markTreeScopeDirty(treeScope);
    322     m_activeTreeScopes.remove(&treeScope);
    323 }
    324 
    325 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node)
    326 {
    327     if (!node->inDocument())
    328         return;
    329 
    330     TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
    331     ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
    332     markTreeScopeDirty(treeScope);
    333 }
    334 
    335 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode)
    336 {
    337     return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
    338 }
    339 
    340 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet treeScopes)
    341 {
    342     for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
    343         TreeScope& treeScope = **it;
    344         ASSERT(treeScope != m_document);
    345         ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope));
    346         ASSERT(collection);
    347         collection->clearMediaQueryRuleSetStyleSheets();
    348     }
    349 }
    350 
    351 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
    352 {
    353     m_documentStyleSheetCollection.clearMediaQueryRuleSetStyleSheets();
    354     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
    355     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
    356 }
    357 
    358 void StyleEngine::collectDocumentActiveStyleSheets(StyleSheetCollectionBase& collection)
    359 {
    360     ASSERT(isMaster());
    361 
    362     if (HTMLImport* rootImport = m_document.import()) {
    363         for (HTMLImport* import = traverseFirstPostOrder(rootImport); import; import = traverseNextPostOrder(import)) {
    364             Document* document = import->document();
    365             if (!document)
    366                 continue;
    367             StyleEngine* engine = document->styleEngine();
    368             DocumentStyleSheetCollection::CollectFor collectFor = document == &m_document ?
    369                 DocumentStyleSheetCollection::CollectForList : DocumentStyleSheetCollection::DontCollectForList;
    370             engine->m_documentStyleSheetCollection.collectStyleSheets(engine, collection, collectFor);
    371         }
    372     } else {
    373         m_documentStyleSheetCollection.collectStyleSheets(this, collection, DocumentStyleSheetCollection::CollectForList);
    374     }
    375 }
    376 
    377 bool StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
    378 {
    379     ASSERT(isMaster());
    380 
    381     if (m_document.inStyleRecalc()) {
    382         // SVG <use> element may manage to invalidate style selector in the middle of a style recalc.
    383         // https://bugs.webkit.org/show_bug.cgi?id=54344
    384         // FIXME: This should be fixed in SVG and the call site replaced by ASSERT(!m_inStyleRecalc).
    385         m_needsUpdateActiveStylesheetsOnStyleRecalc = true;
    386         return false;
    387 
    388     }
    389     if (!m_document.isActive())
    390         return false;
    391 
    392     bool requiresFullStyleRecalc = false;
    393     if (m_documentScopeDirty || updateMode == FullStyleUpdate)
    394         requiresFullStyleRecalc = m_documentStyleSheetCollection.updateActiveStyleSheets(this, updateMode);
    395 
    396     if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
    397         TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
    398         HashSet<TreeScope*> treeScopesRemoved;
    399 
    400         for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
    401             TreeScope* treeScope = *it;
    402             ASSERT(treeScope != m_document);
    403             ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
    404             ASSERT(collection);
    405             collection->updateActiveStyleSheets(this, updateMode);
    406             if (!collection->hasStyleSheetCandidateNodes())
    407                 treeScopesRemoved.add(treeScope);
    408         }
    409         if (!treeScopesRemoved.isEmpty())
    410             for (HashSet<TreeScope*>::iterator it = treeScopesRemoved.begin(); it != treeScopesRemoved.end(); ++it)
    411                 m_activeTreeScopes.remove(*it);
    412     }
    413     m_needsUpdateActiveStylesheetsOnStyleRecalc = false;
    414     activeStyleSheetsUpdatedForInspector();
    415     m_usesRemUnits = m_documentStyleSheetCollection.usesRemUnits();
    416 
    417     if (m_documentScopeDirty || updateMode == FullStyleUpdate)
    418         m_document.notifySeamlessChildDocumentsOfStylesheetUpdate();
    419 
    420     m_dirtyTreeScopes.clear();
    421     m_documentScopeDirty = false;
    422 
    423     return requiresFullStyleRecalc;
    424 }
    425 
    426 void StyleEngine::activeStyleSheetsUpdatedForInspector()
    427 {
    428     if (m_activeTreeScopes.isEmpty()) {
    429         InspectorInstrumentation::activeStyleSheetsUpdated(&m_document, m_documentStyleSheetCollection.styleSheetsForStyleSheetList());
    430         return;
    431     }
    432     Vector<RefPtr<StyleSheet> > activeStyleSheets;
    433 
    434     activeStyleSheets.append(m_documentStyleSheetCollection.styleSheetsForStyleSheetList());
    435 
    436     TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
    437     TreeScopeSet::iterator end = m_activeTreeScopes.end();
    438     for (TreeScopeSet::iterator it = begin; it != end; ++it) {
    439         if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it))
    440             activeStyleSheets.append(collection->styleSheetsForStyleSheetList());
    441     }
    442 
    443     // FIXME: Inspector needs a vector which has all active stylesheets.
    444     // However, creating such a large vector might cause performance regression.
    445     // Need to implement some smarter solution.
    446     InspectorInstrumentation::activeStyleSheetsUpdated(&m_document, activeStyleSheets);
    447 }
    448 
    449 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
    450 {
    451     m_styleSheetCollectionMap.remove(shadowRoot);
    452 }
    453 
    454 void StyleEngine::appendActiveAuthorStyleSheets()
    455 {
    456     ASSERT(isMaster());
    457 
    458     m_resolver->setBuildScopedStyleTreeInDocumentOrder(true);
    459     m_resolver->appendAuthorStyleSheets(0, m_documentStyleSheetCollection.activeAuthorStyleSheets());
    460 
    461     TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
    462     TreeScopeSet::iterator end = m_activeTreeScopes.end();
    463     for (TreeScopeSet::iterator it = begin; it != end; ++it) {
    464         if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) {
    465             m_resolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped());
    466             m_resolver->appendAuthorStyleSheets(0, collection->activeAuthorStyleSheets());
    467         }
    468     }
    469     m_resolver->finishAppendAuthorStyleSheets();
    470     m_resolver->setBuildScopedStyleTreeInDocumentOrder(false);
    471 }
    472 
    473 void StyleEngine::createResolver()
    474 {
    475     // It is a programming error to attempt to resolve style on a Document
    476     // which is not in a frame. Code which hits this should have checked
    477     // Document::isActive() before calling into code which could get here.
    478 
    479     ASSERT(m_document.frame());
    480     ASSERT(m_fontSelector);
    481 
    482     m_resolver = adoptPtr(new StyleResolver(m_document));
    483     appendActiveAuthorStyleSheets();
    484     m_fontSelector->registerForInvalidationCallbacks(m_resolver.get());
    485     combineCSSFeatureFlags(m_resolver->ensureRuleFeatureSet());
    486 }
    487 
    488 void StyleEngine::clearResolver()
    489 {
    490     ASSERT(!m_document.inStyleRecalc());
    491     ASSERT(isMaster() || !m_resolver);
    492     ASSERT(m_fontSelector || !m_resolver);
    493     if (m_resolver)
    494         m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get());
    495     m_resolver.clear();
    496 }
    497 
    498 void StyleEngine::clearMasterResolver()
    499 {
    500     if (Document* master = this->master())
    501         master->styleEngine()->clearResolver();
    502 }
    503 
    504 unsigned StyleEngine::resolverAccessCount() const
    505 {
    506     return m_resolver ? m_resolver->accessCount() : 0;
    507 }
    508 
    509 void StyleEngine::resolverThrowawayTimerFired(Timer<StyleEngine>*)
    510 {
    511     if (resolverAccessCount() == m_lastResolverAccessCount)
    512         clearResolver();
    513     m_lastResolverAccessCount = resolverAccessCount();
    514 }
    515 
    516 void StyleEngine::didAttach()
    517 {
    518     m_resolverThrowawayTimer.startRepeating(60);
    519 }
    520 
    521 void StyleEngine::didDetach()
    522 {
    523     m_resolverThrowawayTimer.stop();
    524     clearResolver();
    525 }
    526 
    527 bool StyleEngine::shouldClearResolver() const
    528 {
    529     return !m_didCalculateResolver && !haveStylesheetsLoaded();
    530 }
    531 
    532 StyleResolverChange StyleEngine::resolverChanged(RecalcStyleTime time, StyleResolverUpdateMode mode)
    533 {
    534     StyleResolverChange change;
    535 
    536     if (!isMaster()) {
    537         if (Document* master = this->master())
    538             master->styleResolverChanged(time, mode);
    539         return change;
    540     }
    541 
    542     // Don't bother updating, since we haven't loaded all our style info yet
    543     // and haven't calculated the style selector for the first time.
    544     if (!m_document.isActive() || shouldClearResolver()) {
    545         clearResolver();
    546         return change;
    547     }
    548 
    549     m_didCalculateResolver = true;
    550     if (m_document.didLayoutWithPendingStylesheets() && !hasPendingSheets())
    551         change.setNeedsRepaint();
    552 
    553     if (updateActiveStyleSheets(mode))
    554         change.setNeedsStyleRecalc();
    555 
    556     return change;
    557 }
    558 
    559 void StyleEngine::resetFontSelector()
    560 {
    561     if (!m_fontSelector)
    562         return;
    563 
    564     m_fontSelector->clearDocument();
    565     if (m_resolver) {
    566         m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get());
    567         m_resolver->invalidateMatchedPropertiesCache();
    568     }
    569 
    570     // If the document has been already detached, we don't need to recreate
    571     // CSSFontSelector.
    572     if (m_document.isActive()) {
    573         m_fontSelector = CSSFontSelector::create(&m_document);
    574         if (m_resolver)
    575             m_fontSelector->registerForInvalidationCallbacks(m_resolver.get());
    576     } else {
    577         m_fontSelector = 0;
    578     }
    579 }
    580 
    581 void StyleEngine::markTreeScopeDirty(TreeScope& scope)
    582 {
    583     if (scope == m_document) {
    584         markDocumentDirty();
    585         return;
    586     }
    587 
    588     m_dirtyTreeScopes.add(&scope);
    589 }
    590 
    591 void StyleEngine::markDocumentDirty()
    592 {
    593     m_documentScopeDirty = true;
    594     if (!HTMLImport::isMaster(&m_document))
    595         m_document.import()->master()->styleEngine()->markDocumentDirty();
    596 }
    597 
    598 }
    599