diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp | 485 |
1 files changed, 294 insertions, 191 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp index 54ce1fe3368..901bed5922c 100644 --- a/chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp +++ b/chromium/third_party/WebKit/Source/core/dom/StyleEngine.cpp @@ -28,25 +28,23 @@ #include "config.h" #include "core/dom/StyleEngine.h" -#include "HTMLNames.h" -#include "SVGNames.h" +#include "core/HTMLNames.h" #include "core/css/CSSFontSelector.h" #include "core/css/CSSStyleSheet.h" -#include "core/css/StyleInvalidationAnalysis.h" +#include "core/css/FontFaceCache.h" #include "core/css/StyleSheetContents.h" +#include "core/dom/DocumentStyleSheetCollector.h" #include "core/dom/Element.h" #include "core/dom/ProcessingInstruction.h" #include "core/dom/ShadowTreeStyleSheetCollection.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/html/HTMLIFrameElement.h" -#include "core/html/HTMLImport.h" #include "core/html/HTMLLinkElement.h" -#include "core/html/HTMLStyleElement.h" +#include "core/html/imports/HTMLImportsController.h" #include "core/inspector/InspectorInstrumentation.h" +#include "core/page/InjectedStyleSheets.h" #include "core/page/Page.h" -#include "core/page/PageGroup.h" #include "core/frame/Settings.h" -#include "core/svg/SVGStyleElement.h" #include "platform/URLPatternMatcher.h" namespace WebCore { @@ -54,12 +52,15 @@ namespace WebCore { using namespace HTMLNames; StyleEngine::StyleEngine(Document& document) - : m_document(document) - , m_isMaster(HTMLImport::isMaster(&document)) + : m_document(&document) + , m_isMaster(!document.importsController() || document.importsController()->master() == &document) , m_pendingStylesheets(0) , m_injectedStyleSheetCacheValid(false) - , m_needsUpdateActiveStylesheetsOnStyleRecalc(false) +#if ENABLE(OILPAN) + , m_documentStyleSheetCollection(new DocumentStyleSheetCollection(document)) +#else , m_documentStyleSheetCollection(document) +#endif , m_documentScopeDirty(true) , m_usesSiblingRules(false) , m_usesSiblingRulesOverride(false) @@ -69,16 +70,25 @@ StyleEngine::StyleEngine(Document& document) , m_maxDirectAdjacentSelectors(0) , m_ignorePendingStylesheets(false) , m_didCalculateResolver(false) - , m_lastResolverAccessCount(0) - , m_resolverThrowawayTimer(this, &StyleEngine::resolverThrowawayTimerFired) // We don't need to create CSSFontSelector for imported document or // HTMLTemplateElement's document, because those documents have no frame. - , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : 0) + , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : nullptr) + , m_xslStyleSheet(nullptr) { + if (m_fontSelector) + m_fontSelector->registerForInvalidationCallbacks(this); } StyleEngine::~StyleEngine() { +} + +#if !ENABLE(OILPAN) +void StyleEngine::detachFromDocument() +{ + // Cleanup is performed eagerly when the StyleEngine is removed from the + // document. The StyleEngine is unreachable after this, since only the + // document has a reference to it. for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i) m_injectedAuthorStyleSheets[i]->clearOwnerNode(); for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i) @@ -86,16 +96,21 @@ StyleEngine::~StyleEngine() if (m_fontSelector) { m_fontSelector->clearDocument(); - if (m_resolver) - m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get()); + m_fontSelector->unregisterForInvalidationCallbacks(this); } + + // Decrement reference counts for things we could be keeping alive. + m_fontSelector.clear(); + m_resolver.clear(); + m_styleSheetCollectionMap.clear(); } +#endif inline Document* StyleEngine::master() { if (isMaster()) - return &m_document; - HTMLImport* import = m_document.import(); + return m_document; + HTMLImportsController* import = document().importsController(); if (!import) // Document::import() can return null while executing its destructor. return 0; return import->master(); @@ -128,52 +143,39 @@ void StyleEngine::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeS treeScopes.insertBefore(followingTreeScope, treeScope); } -StyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope) +TreeScopeStyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope) { if (treeScope == m_document) - return &m_documentStyleSheetCollection; + return documentStyleSheetCollection(); - HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr); + StyleSheetCollectionMap::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr); if (result.isNewEntry) - result.iterator->value = adoptPtr(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope))); - return result.iterator->value.get(); + result.storedValue->value = adoptPtrWillBeNoop(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope))); + return result.storedValue->value.get(); } -StyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope) +TreeScopeStyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope) { if (treeScope == m_document) - return &m_documentStyleSheetCollection; + return documentStyleSheetCollection(); - HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::iterator it = m_styleSheetCollectionMap.find(&treeScope); + StyleSheetCollectionMap::iterator it = m_styleSheetCollectionMap.find(&treeScope); if (it == m_styleSheetCollectionMap.end()) return 0; return it->value.get(); } -const Vector<RefPtr<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope) +const WillBeHeapVector<RefPtrWillBeMember<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope) { if (treeScope == m_document) - return m_documentStyleSheetCollection.styleSheetsForStyleSheetList(); + return documentStyleSheetCollection()->styleSheetsForStyleSheetList(); return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList(); } -const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const -{ - return m_documentStyleSheetCollection.activeAuthorStyleSheets(); -} - -void StyleEngine::getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const +const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const { - activeAuthorStyleSheets.append(&m_documentStyleSheetCollection.activeAuthorStyleSheets()); - - HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values begin = m_styleSheetCollectionMap.values().begin(); - HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values end = m_styleSheetCollectionMap.values().end(); - HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values it = begin; - for (; it != end; ++it) { - const StyleSheetCollection* collection = it->get(); - activeAuthorStyleSheets.append(&collection->activeAuthorStyleSheets()); - } + return documentStyleSheetCollection()->activeAuthorStyleSheets(); } void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features) @@ -191,7 +193,7 @@ void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features) m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors(); } -const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const +const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const { updateInjectedStyleSheetCache(); return m_injectedAuthorStyleSheets; @@ -204,21 +206,20 @@ void StyleEngine::updateInjectedStyleSheetCache() const m_injectedStyleSheetCacheValid = true; m_injectedAuthorStyleSheets.clear(); - Page* owningPage = m_document.page(); + Page* owningPage = document().page(); if (!owningPage) return; - const PageGroup& pageGroup = owningPage->group(); - const InjectedStyleSheetVector& sheets = pageGroup.injectedStyleSheets(); - for (unsigned i = 0; i < sheets.size(); ++i) { - const InjectedStyleSheet* sheet = sheets[i].get(); - if (sheet->injectedFrames() == InjectStyleInTopFrameOnly && m_document.ownerElement()) + const InjectedStyleSheetEntryVector& entries = InjectedStyleSheets::instance().entries(); + for (unsigned i = 0; i < entries.size(); ++i) { + const InjectedStyleSheetEntry* entry = entries[i].get(); + if (entry->injectedFrames() == InjectStyleInTopFrameOnly && document().ownerElement()) continue; - if (!URLPatternMatcher::matchesPatterns(m_document.url(), sheet->whitelist())) + if (!URLPatternMatcher::matchesPatterns(document().url(), entry->whitelist())) continue; - RefPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(const_cast<Document*>(&m_document), KURL()); + RefPtrWillBeRawPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(m_document, KURL()); m_injectedAuthorStyleSheets.append(groupSheet); - groupSheet->contents()->parseString(sheet->source()); + groupSheet->contents()->parseString(entry->source()); } } @@ -228,38 +229,28 @@ void StyleEngine::invalidateInjectedStyleSheetCache() markDocumentDirty(); // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet(). - m_document.styleResolverChanged(RecalcStyleDeferred); + document().styleResolverChanged(); } -void StyleEngine::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet) +void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet) { - m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, &m_document)); - m_document.addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately); + m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document)); + document().addedStyleSheet(m_authorStyleSheets.last().get()); markDocumentDirty(); } void StyleEngine::addPendingSheet() { - master()->styleEngine()->notifyPendingStyleSheetAdded(); + m_pendingStylesheets++; } // This method is called whenever a top-level stylesheet has finished loading. -void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType notification) +void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode) { - TreeScope* treeScope = isHTMLStyleElement(styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : &m_document; + ASSERT(styleSheetCandidateNode); + TreeScope* treeScope = isHTMLStyleElement(*styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : m_document.get(); markTreeScopeDirty(*treeScope); - master()->styleEngine()->notifyPendingStyleSheetRemoved(notification); -} - -void StyleEngine::notifyPendingStyleSheetAdded() -{ - ASSERT(isMaster()); - m_pendingStylesheets++; -} -void StyleEngine::notifyPendingStyleSheetRemoved(RemovePendingSheetNotificationType notification) -{ - ASSERT(isMaster()); // Make sure we knew this sheet was pending, and that our count isn't out of sync. ASSERT(m_pendingStylesheets > 0); @@ -267,14 +258,9 @@ void StyleEngine::notifyPendingStyleSheetRemoved(RemovePendingSheetNotificationT if (m_pendingStylesheets) return; - if (notification == RemovePendingSheetNotifyLater) { - m_document.setNeedsNotifyRemoveAllPendingStylesheet(); - return; - } - // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know // what's new. We should track that to tell the style system what changed. - m_document.didRemoveAllPendingStylesheet(); + document().didRemoveAllPendingStylesheet(); } void StyleEngine::modifiedStyleSheet(StyleSheet* sheet) @@ -286,7 +272,7 @@ void StyleEngine::modifiedStyleSheet(StyleSheet* sheet) if (!node || !node->inDocument()) return; - TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document; + TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; ASSERT(isHTMLStyleElement(node) || treeScope == m_document); markTreeScopeDirty(treeScope); @@ -297,10 +283,10 @@ void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser) if (!node->inDocument()) return; - TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document; + TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; ASSERT(isHTMLStyleElement(node) || treeScope == m_document); - - StyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope); + ASSERT(!isXSLStyleSheet(*node)); + TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope); ASSERT(collection); collection->addStyleSheetCandidateNode(node, createdByParser); @@ -309,12 +295,17 @@ void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser) insertTreeScopeInDocumentOrder(m_activeTreeScopes, &treeScope); } -void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode) +void StyleEngine::removeStyleSheetCandidateNode(Node* node) +{ + removeStyleSheetCandidateNode(node, 0, *m_document); +} + +void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode, TreeScope& treeScope) { - TreeScope& treeScope = scopingNode ? scopingNode->treeScope() : m_document; ASSERT(isHTMLStyleElement(node) || treeScope == m_document); + ASSERT(!isXSLStyleSheet(*node)); - StyleSheetCollection* collection = styleSheetCollectionFor(treeScope); + TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(treeScope); ASSERT(collection); collection->removeStyleSheetCandidateNode(node, scopingNode); @@ -322,17 +313,59 @@ void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopi m_activeTreeScopes.remove(&treeScope); } +void StyleEngine::addXSLStyleSheet(ProcessingInstruction* node, bool createdByParser) +{ + if (!node->inDocument()) + return; + + ASSERT(isXSLStyleSheet(*node)); + bool needToUpdate = false; + if (createdByParser || !m_xslStyleSheet) { + needToUpdate = !m_xslStyleSheet; + } else { + unsigned position = m_xslStyleSheet->compareDocumentPositionInternal(node, Node::TreatShadowTreesAsDisconnected); + needToUpdate = position & Node::DOCUMENT_POSITION_FOLLOWING; + } + + if (!needToUpdate) + return; + + markTreeScopeDirty(*m_document); + m_xslStyleSheet = node; +} + +void StyleEngine::removeXSLStyleSheet(ProcessingInstruction* node) +{ + ASSERT(isXSLStyleSheet(*node)); + if (m_xslStyleSheet != node) + return; + + markTreeScopeDirty(*m_document); + m_xslStyleSheet = nullptr; +} + void StyleEngine::modifiedStyleSheetCandidateNode(Node* node) { if (!node->inDocument()) return; - TreeScope& treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document; + TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; ASSERT(isHTMLStyleElement(node) || treeScope == m_document); markTreeScopeDirty(treeScope); } -bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) +void StyleEngine::enableExitTransitionStylesheets() +{ + TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(*m_document); + collection->enableExitTransitionStylesheets(); +} + +bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const +{ + return m_documentScopeDirty || updateMode == FullStyleUpdate; +} + +bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const { return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate; } @@ -350,48 +383,30 @@ void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet tree void StyleEngine::clearMediaQueryRuleSetStyleSheets() { - m_documentStyleSheetCollection.clearMediaQueryRuleSetStyleSheets(); + documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets(); clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes); clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes); } -void StyleEngine::collectDocumentActiveStyleSheets(StyleSheetCollectionBase& collection) +void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector) { - ASSERT(isMaster()); - - if (HTMLImport* rootImport = m_document.import()) { - for (HTMLImport* import = traverseFirstPostOrder(rootImport); import; import = traverseNextPostOrder(import)) { - Document* document = import->document(); - if (!document) - continue; - StyleEngine* engine = document->styleEngine(); - DocumentStyleSheetCollection::CollectFor collectFor = document == &m_document ? - DocumentStyleSheetCollection::CollectForList : DocumentStyleSheetCollection::DontCollectForList; - engine->m_documentStyleSheetCollection.collectStyleSheets(engine, collection, collectFor); - } - } else { - m_documentStyleSheetCollection.collectStyleSheets(this, collection, DocumentStyleSheetCollection::CollectForList); - } + ASSERT(!isMaster()); + WillBeHeapVector<RefPtrWillBeMember<StyleSheet> > sheetsForList; + ImportedDocumentStyleSheetCollector subcollector(parentCollector, sheetsForList); + documentStyleSheetCollection()->collectStyleSheets(this, subcollector); + documentStyleSheetCollection()->swapSheetsForSheetList(sheetsForList); } -bool StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) +void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) { ASSERT(isMaster()); + ASSERT(!document().inStyleRecalc()); - if (m_document.inStyleRecalc()) { - // SVG <use> element may manage to invalidate style selector in the middle of a style recalc. - // https://bugs.webkit.org/show_bug.cgi?id=54344 - // FIXME: This should be fixed in SVG and the call site replaced by ASSERT(!m_inStyleRecalc). - m_needsUpdateActiveStylesheetsOnStyleRecalc = true; - return false; - - } - if (!m_document.isActive()) - return false; + if (!document().isActive()) + return; - bool requiresFullStyleRecalc = false; - if (m_documentScopeDirty || updateMode == FullStyleUpdate) - requiresFullStyleRecalc = m_documentStyleSheetCollection.updateActiveStyleSheets(this, updateMode); + if (shouldUpdateDocumentStyleSheetCollection(updateMode)) + documentStyleSheetCollection()->updateActiveStyleSheets(this, updateMode); if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) { TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes; @@ -406,44 +421,36 @@ bool StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) if (!collection->hasStyleSheetCandidateNodes()) treeScopesRemoved.add(treeScope); } - if (!treeScopesRemoved.isEmpty()) - for (HashSet<TreeScope*>::iterator it = treeScopesRemoved.begin(); it != treeScopesRemoved.end(); ++it) - m_activeTreeScopes.remove(*it); + m_activeTreeScopes.removeAll(treeScopesRemoved); } - m_needsUpdateActiveStylesheetsOnStyleRecalc = false; - activeStyleSheetsUpdatedForInspector(); - m_usesRemUnits = m_documentStyleSheetCollection.usesRemUnits(); - if (m_documentScopeDirty || updateMode == FullStyleUpdate) - m_document.notifySeamlessChildDocumentsOfStylesheetUpdate(); + InspectorInstrumentation::activeStyleSheetsUpdated(m_document); + m_usesRemUnits = documentStyleSheetCollection()->usesRemUnits(); m_dirtyTreeScopes.clear(); m_documentScopeDirty = false; - - return requiresFullStyleRecalc; } -void StyleEngine::activeStyleSheetsUpdatedForInspector() +const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > StyleEngine::activeStyleSheetsForInspector() const { - if (m_activeTreeScopes.isEmpty()) { - InspectorInstrumentation::activeStyleSheetsUpdated(&m_document, m_documentStyleSheetCollection.styleSheetsForStyleSheetList()); - return; - } - Vector<RefPtr<StyleSheet> > activeStyleSheets; + if (m_activeTreeScopes.isEmpty()) + return documentStyleSheetCollection()->activeAuthorStyleSheets(); - activeStyleSheets.append(m_documentStyleSheetCollection.styleSheetsForStyleSheetList()); + WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > activeStyleSheets; - TreeScopeSet::iterator begin = m_activeTreeScopes.begin(); - TreeScopeSet::iterator end = m_activeTreeScopes.end(); - for (TreeScopeSet::iterator it = begin; it != end; ++it) { - if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) - activeStyleSheets.append(collection->styleSheetsForStyleSheetList()); + activeStyleSheets.appendVector(documentStyleSheetCollection()->activeAuthorStyleSheets()); + + TreeScopeSet::const_iterator begin = m_activeTreeScopes.begin(); + TreeScopeSet::const_iterator end = m_activeTreeScopes.end(); + for (TreeScopeSet::const_iterator it = begin; it != end; ++it) { + if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) + activeStyleSheets.appendVector(collection->activeAuthorStyleSheets()); } // FIXME: Inspector needs a vector which has all active stylesheets. // However, creating such a large vector might cause performance regression. // Need to implement some smarter solution. - InspectorInstrumentation::activeStyleSheetsUpdated(&m_document, activeStyleSheets); + return activeStyleSheets; } void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot) @@ -456,14 +463,14 @@ void StyleEngine::appendActiveAuthorStyleSheets() ASSERT(isMaster()); m_resolver->setBuildScopedStyleTreeInDocumentOrder(true); - m_resolver->appendAuthorStyleSheets(0, m_documentStyleSheetCollection.activeAuthorStyleSheets()); + m_resolver->appendAuthorStyleSheets(documentStyleSheetCollection()->activeAuthorStyleSheets()); TreeScopeSet::iterator begin = m_activeTreeScopes.begin(); TreeScopeSet::iterator end = m_activeTreeScopes.end(); for (TreeScopeSet::iterator it = begin; it != end; ++it) { - if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) { + if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) { m_resolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped()); - m_resolver->appendAuthorStyleSheets(0, collection->activeAuthorStyleSheets()); + m_resolver->appendAuthorStyleSheets(collection->activeAuthorStyleSheets()); } } m_resolver->finishAppendAuthorStyleSheets(); @@ -476,22 +483,19 @@ void StyleEngine::createResolver() // which is not in a frame. Code which hits this should have checked // Document::isActive() before calling into code which could get here. - ASSERT(m_document.frame()); - ASSERT(m_fontSelector); + ASSERT(document().frame()); - m_resolver = adoptPtr(new StyleResolver(m_document)); + m_resolver = adoptPtrWillBeNoop(new StyleResolver(*m_document)); appendActiveAuthorStyleSheets(); - m_fontSelector->registerForInvalidationCallbacks(m_resolver.get()); - combineCSSFeatureFlags(m_resolver->ensureRuleFeatureSet()); + combineCSSFeatureFlags(m_resolver->ensureUpdatedRuleFeatureSet()); } void StyleEngine::clearResolver() { - ASSERT(!m_document.inStyleRecalc()); + ASSERT(!document().inStyleRecalc()); ASSERT(isMaster() || !m_resolver); - ASSERT(m_fontSelector || !m_resolver); if (m_resolver) - m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get()); + document().updateStyleInvalidationIfNeeded(); m_resolver.clear(); } @@ -506,21 +510,8 @@ unsigned StyleEngine::resolverAccessCount() const return m_resolver ? m_resolver->accessCount() : 0; } -void StyleEngine::resolverThrowawayTimerFired(Timer<StyleEngine>*) -{ - if (resolverAccessCount() == m_lastResolverAccessCount) - clearResolver(); - m_lastResolverAccessCount = resolverAccessCount(); -} - -void StyleEngine::didAttach() -{ - m_resolverThrowawayTimer.startRepeating(60); -} - void StyleEngine::didDetach() { - m_resolverThrowawayTimer.stop(); clearResolver(); } @@ -529,53 +520,74 @@ bool StyleEngine::shouldClearResolver() const return !m_didCalculateResolver && !haveStylesheetsLoaded(); } -StyleResolverChange StyleEngine::resolverChanged(RecalcStyleTime time, StyleResolverUpdateMode mode) +bool StyleEngine::shouldApplyXSLTransform() const { - StyleResolverChange change; + if (!RuntimeEnabledFeatures::xsltEnabled()) + return false; + return m_xslStyleSheet && !m_document->transformSourceDocument(); +} +void StyleEngine::resolverChanged(StyleResolverUpdateMode mode) +{ if (!isMaster()) { if (Document* master = this->master()) - master->styleResolverChanged(time, mode); - return change; + master->styleResolverChanged(mode); + return; } // Don't bother updating, since we haven't loaded all our style info yet // and haven't calculated the style selector for the first time. - if (!m_document.isActive() || shouldClearResolver()) { + if (!document().isActive() || shouldClearResolver()) { clearResolver(); - return change; + return; } - m_didCalculateResolver = true; - if (m_document.didLayoutWithPendingStylesheets() && !hasPendingSheets()) - change.setNeedsRepaint(); + if (shouldApplyXSLTransform()) { + // Processing instruction (XML documents only). + // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. + // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> + if (!m_document->parsing() && !m_xslStyleSheet->isLoading()) + m_document->applyXSLTransform(m_xslStyleSheet.get()); + return; + } - if (updateActiveStyleSheets(mode)) - change.setNeedsStyleRecalc(); + m_didCalculateResolver = true; + updateActiveStyleSheets(mode); +} - return change; +void StyleEngine::clearFontCache() +{ + // We should not recreate FontSelector. Instead, clear fontFaceCache. + if (m_fontSelector) + m_fontSelector->fontFaceCache()->clear(); + if (m_resolver) + m_resolver->invalidateMatchedPropertiesCache(); } -void StyleEngine::resetFontSelector() +void StyleEngine::updateGenericFontFamilySettings() { + // FIXME: we should not update generic font family settings when + // document is inactive. + ASSERT(document().isActive()); + if (!m_fontSelector) return; - m_fontSelector->clearDocument(); - if (m_resolver) { - m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get()); + m_fontSelector->updateGenericFontFamilySettings(*m_document); + if (m_resolver) m_resolver->invalidateMatchedPropertiesCache(); - } +} - // If the document has been already detached, we don't need to recreate - // CSSFontSelector. - if (m_document.isActive()) { - m_fontSelector = CSSFontSelector::create(&m_document); - if (m_resolver) - m_fontSelector->registerForInvalidationCallbacks(m_resolver.get()); - } else { - m_fontSelector = 0; - } +void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules) +{ + if (!m_fontSelector) + return; + + FontFaceCache* cache = m_fontSelector->fontFaceCache(); + for (unsigned i = 0; i < fontFaceRules.size(); ++i) + cache->remove(fontFaceRules[i]); + if (m_resolver) + m_resolver->invalidateMatchedPropertiesCache(); } void StyleEngine::markTreeScopeDirty(TreeScope& scope) @@ -591,8 +603,99 @@ void StyleEngine::markTreeScopeDirty(TreeScope& scope) void StyleEngine::markDocumentDirty() { m_documentScopeDirty = true; - if (!HTMLImport::isMaster(&m_document)) - m_document.import()->master()->styleEngine()->markDocumentDirty(); + if (document().importLoader()) + document().importsController()->master()->styleEngine()->markDocumentDirty(); +} + +static bool isCacheableForStyleElement(const StyleSheetContents& contents) +{ + // FIXME: Support copying import rules. + if (!contents.importRules().isEmpty()) + return false; + // Until import rules are supported in cached sheets it's not possible for loading to fail. + ASSERT(!contents.didLoadErrorOccur()); + // It is not the original sheet anymore. + if (contents.isMutable()) + return false; + if (!contents.hasSyntacticallyValidCSSHeader()) + return false; + return true; +} + +PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::createSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser) +{ + RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr; + + e->document().styleEngine()->addPendingSheet(); + + if (!e->document().inQuirksMode()) { + AtomicString textContent(text); + + WillBeHeapHashMap<AtomicString, RawPtrWillBeMember<StyleSheetContents> >::AddResult result = m_textToSheetCache.add(textContent, nullptr); + if (result.isNewEntry || !result.storedValue->value) { + styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser); + if (result.isNewEntry && isCacheableForStyleElement(*styleSheet->contents())) { + result.storedValue->value = styleSheet->contents(); + m_sheetToTextCache.add(styleSheet->contents(), textContent); + } + } else { + StyleSheetContents* contents = result.storedValue->value; + ASSERT(contents); + ASSERT(isCacheableForStyleElement(*contents)); + ASSERT(contents->singleOwnerDocument() == e->document()); + styleSheet = CSSStyleSheet::createInline(contents, e, startPosition); + } + } else { + // FIXME: currently we don't cache StyleSheetContents inQuirksMode. + styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser); + } + + ASSERT(styleSheet); + styleSheet->setTitle(e->title()); + return styleSheet; +} + +PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::parseSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser) +{ + RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr; + styleSheet = CSSStyleSheet::createInline(e, KURL(), startPosition, e->document().inputEncoding()); + styleSheet->contents()->parseStringAtPosition(text, startPosition, createdByParser); + return styleSheet; +} + +void StyleEngine::removeSheet(StyleSheetContents* contents) +{ + WillBeHeapHashMap<RawPtrWillBeMember<StyleSheetContents>, AtomicString>::iterator it = m_sheetToTextCache.find(contents); + if (it == m_sheetToTextCache.end()) + return; + + m_textToSheetCache.remove(it->value); + m_sheetToTextCache.remove(contents); +} + +void StyleEngine::fontsNeedUpdate(CSSFontSelector*) +{ + if (!document().isActive()) + return; + + if (m_resolver) + m_resolver->invalidateMatchedPropertiesCache(); + document().setNeedsStyleRecalc(SubtreeStyleChange); +} + +void StyleEngine::trace(Visitor* visitor) +{ + visitor->trace(m_document); + visitor->trace(m_injectedAuthorStyleSheets); + visitor->trace(m_authorStyleSheets); + visitor->trace(m_documentStyleSheetCollection); + visitor->trace(m_styleSheetCollectionMap); + visitor->trace(m_resolver); + visitor->trace(m_fontSelector); + visitor->trace(m_textToSheetCache); + visitor->trace(m_sheetToTextCache); + visitor->trace(m_xslStyleSheet); + CSSFontSelectorClient::trace(visitor); } } |