 Chromium Code Reviews
 Chromium Code Reviews Issue 42543007:
  StyleResolver should update RuleSets lazily.  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk
    
  
    Issue 42543007:
  StyleResolver should update RuleSets lazily.  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk| Index: Source/core/css/resolver/StyleResolver.cpp | 
| diff --git a/Source/core/css/resolver/StyleResolver.cpp b/Source/core/css/resolver/StyleResolver.cpp | 
| index 6dfb08aa3c2c651ec64586430ac7b64ccfcab7cf..e41d9186036a63e5484ceefc94e973a24d93f30f 100644 | 
| --- a/Source/core/css/resolver/StyleResolver.cpp | 
| +++ b/Source/core/css/resolver/StyleResolver.cpp | 
| @@ -57,6 +57,8 @@ | 
| #include "core/css/PageRuleCollector.h" | 
| #include "core/css/RuleSet.h" | 
| #include "core/css/StylePropertySet.h" | 
| +#include "core/css/StyleRuleImport.h" | 
| +#include "core/css/StyleSheetContents.h" | 
| #include "core/css/resolver/AnimatedStyleBuilder.h" | 
| #include "core/css/resolver/MatchResult.h" | 
| #include "core/css/resolver/MediaQueryResult.h" | 
| @@ -106,6 +108,11 @@ using namespace HTMLNames; | 
| RenderStyle* StyleResolver::s_styleNotYetAvailable; | 
| +inline bool isDocumentScope(const ContainerNode* scope) | 
| +{ | 
| + return !scope || scope->isDocumentNode(); | 
| 
esprehn
2013/11/15 10:36:32
We should really fix this so scope is never null,
 
tasak
2013/11/18 08:30:53
I added FIXME.
 | 
| +} | 
| + | 
| static StylePropertySet* leftToRightDeclaration() | 
| { | 
| DEFINE_STATIC_REF(MutableStylePropertySet, leftToRightDecl, (MutableStylePropertySet::create())); | 
| @@ -126,6 +133,7 @@ StyleResolver::StyleResolver(Document& document) | 
| : m_document(document) | 
| , m_fontSelector(CSSFontSelector::create(&document)) | 
| , m_viewportStyleResolver(ViewportStyleResolver::create(&document)) | 
| + , m_needCollectFeatures(false) | 
| , m_styleResourceLoader(document.fetcher()) | 
| , m_styleResolverStatsSequence(0) | 
| { | 
| @@ -178,6 +186,97 @@ void StyleResolver::initWatchedSelectorRules(const Vector<RefPtr<StyleRule> >& w | 
| m_watchedSelectorsRules->addStyleRule(watchedSelectors[i].get(), RuleHasNoSpecialState); | 
| } | 
| +void StyleResolver::filterViewportRules(const Vector<RefPtr<StyleRuleBase> >& rules, bool& needsResolveViewport) | 
| 
esprehn
2013/11/15 10:36:32
Return a boolean instead.
 
tasak
2013/11/18 08:30:53
Done.
 | 
| +{ | 
| + for (unsigned i = 0; i < rules.size(); ++i) { | 
| + StyleRuleBase* rule = rules[i].get(); | 
| + | 
| + if (rule->isViewportRule()) { | 
| + m_styleTree.ensureScopedStyleResolver(m_document)->addViewportRule(toStyleRuleViewport(rule)); | 
| + needsResolveViewport = true; | 
| + } else if (rule->isMediaRule()) { | 
| + const StyleRuleMedia* mediaRule = toStyleRuleMedia(rule); | 
| + if ((!mediaRule->mediaQueries() || m_medium->eval(mediaRule->mediaQueries(), viewportDependentMediaQueryResults()))) | 
| + filterViewportRules(mediaRule->childRules(), needsResolveViewport); | 
| + } | 
| + } | 
| +} | 
| + | 
| +void StyleResolver::filterViewportRulesFromSheet(StyleSheetContents* sheet, bool& needsResolveViewport) | 
| 
esprehn
2013/11/15 10:36:32
Ditto, return a boolean.
 
tasak
2013/11/18 08:30:53
Done.
 | 
| +{ | 
| + if (!sheet) | 
| + return; | 
| + | 
| + if (sheet->importRules().size() > 0) { | 
| 
esprehn
2013/11/15 10:36:32
There's no reason to check if the Vector size is >
 
tasak
2013/11/18 08:30:53
Done.
 | 
| + const Vector<RefPtr<StyleRuleImport> >& importRules = sheet->importRules(); | 
| + for (unsigned i = 0; i < importRules.size(); ++i) { | 
| + StyleRuleImport* importRule = importRules[i].get(); | 
| + filterViewportRulesFromSheet(importRule->styleSheet(), needsResolveViewport); | 
| + } | 
| + } | 
| + filterViewportRules(sheet->childRules(), needsResolveViewport); | 
| +} | 
| + | 
| +bool StyleResolver::filterViewportRulesFromAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets) | 
| +{ | 
| + bool needsResolveViewport = false; | 
| + | 
| + unsigned size = styleSheets.size(); | 
| + for (unsigned i = firstNew; i < size; ++i) { | 
| + CSSStyleSheet* cssSheet = styleSheets[i].get(); | 
| + ASSERT(!cssSheet->disabled()); | 
| + if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults)) | 
| + continue; | 
| + if (cssSheet->ownerNode()->isInShadowTree() || !isDocumentScope(ScopedStyleResolver::scopingNodeFor(cssSheet))) | 
| + continue; | 
| + filterViewportRulesFromSheet(cssSheet->contents(), needsResolveViewport); | 
| + } | 
| + return needsResolveViewport; | 
| +} | 
| + | 
| +void StyleResolver::lazyAppendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets) | 
| +{ | 
| + // FIXME: Currently We cannot lazy apppend stylesheets if the sheets have @viewport rules. | 
| + // Need to find the best place to update pending stylesheets for "viewport" rules. | 
| + bool needsResolveViewport = filterViewportRulesFromAuthorStyleSheets(firstNew, styleSheets); | 
| + | 
| + unsigned size = styleSheets.size(); | 
| + for (unsigned i = firstNew; i < size; ++i) | 
| + m_pendingStyleSheets.add(styleSheets[i].get()); | 
| + | 
| + if (needsResolveViewport) | 
| + collectViewportRules(); | 
| +} | 
| + | 
| +void StyleResolver::removePendingAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& styleSheets) | 
| +{ | 
| + for (unsigned i = 0; i < styleSheets.size(); ++i) | 
| + m_pendingStyleSheets.remove(styleSheets[i].get()); | 
| +} | 
| + | 
| +void StyleResolver::appendPendingAuthorStyleSheets() | 
| +{ | 
| + setBuildScopedStyleTreeInDocumentOrder(false); | 
| + for (ListHashSet<CSSStyleSheet*, 16>::iterator it = m_pendingStyleSheets.begin(); it != m_pendingStyleSheets.end(); ++it) { | 
| + CSSStyleSheet* cssSheet = *it; | 
| + ASSERT(!cssSheet->disabled()); | 
| + if (cssSheet->mediaQueries() && !m_medium->eval(cssSheet->mediaQueries(), &m_viewportDependentMediaQueryResults)) | 
| + continue; | 
| + | 
| + StyleSheetContents* sheet = cssSheet->contents(); | 
| + ContainerNode* scopingNode = ScopedStyleResolver::scopingNodeFor(cssSheet); | 
| + if (!scopingNode && cssSheet->ownerNode() && cssSheet->ownerNode()->isInShadowTree()) | 
| + continue; | 
| + | 
| + ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode); | 
| + ASSERT(resolver); | 
| + resolver->addRulesFromSheet(sheet, *m_medium, this, true); | 
| + m_inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet); | 
| + } | 
| + m_pendingStyleSheets.clear(); | 
| + finishAppendAuthorStyleSheets(); | 
| +} | 
| + | 
| void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets) | 
| { | 
| // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver | 
| @@ -196,7 +295,7 @@ void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefP | 
| ScopedStyleResolver* resolver = ensureScopedStyleResolver(scopingNode); | 
| ASSERT(resolver); | 
| - resolver->addRulesFromSheet(sheet, *m_medium, this); | 
| + resolver->addRulesFromSheet(sheet, *m_medium, this, false); | 
| m_inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet); | 
| } | 
| } | 
| @@ -209,6 +308,17 @@ void StyleResolver::finishAppendAuthorStyleSheets() | 
| document().renderer()->style()->font().update(fontSelector()); | 
| collectViewportRules(); | 
| + | 
| + document().styleEngine()->resetCSSFeatureFlags(m_features); | 
| +} | 
| + | 
| +void StyleResolver::resetRuleFeatures() | 
| +{ | 
| + // Need to recreate RuleFeatureSet. | 
| + m_features.clear(); | 
| + m_siblingRuleSet.clear(); | 
| + m_uncommonAttributeRuleSet.clear(); | 
| + m_needCollectFeatures = true; | 
| } | 
| void StyleResolver::addTreeBoundaryCrossingRules(const Vector<MinimalRuleData>& rules, ContainerNode* scope) | 
| @@ -260,6 +370,7 @@ void StyleResolver::resetAuthorStyle(const ContainerNode* scopingNode) | 
| treeBoundaryCrossingRules().reset(scopingNode); | 
| resolver->resetAuthorStyle(); | 
| + resetRuleFeatures(); | 
| if (!scopingNode) | 
| return; | 
| @@ -322,6 +433,7 @@ void StyleResolver::collectFeatures() | 
| m_siblingRuleSet = makeRuleSet(m_features.siblingRules); | 
| m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules); | 
| + m_needCollectFeatures = false; | 
| } | 
| bool StyleResolver::hasRulesForId(const AtomicString& id) const | 
| @@ -654,6 +766,8 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS | 
| { | 
| ASSERT(document().frame()); | 
| ASSERT(documentSettings()); | 
| + ASSERT(!hasPendingAuthorStyleSheets()); | 
| + ASSERT(!m_needCollectFeatures); | 
| // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer | 
| // will vanish if a style recalc happens during loading. | 
| @@ -747,6 +861,7 @@ PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* e, const Render | 
| { | 
| ASSERT(document().frame()); | 
| ASSERT(documentSettings()); | 
| + ASSERT(!hasPendingAuthorStyleSheets()); | 
| if (e == document().documentElement()) | 
| resetDirectionAndWritingModeOnDocument(document()); | 
| @@ -805,6 +920,7 @@ void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle& el | 
| if (!e || list.animationName().isEmpty()) | 
| return; | 
| + ASSERT(!hasPendingAuthorStyleSheets()); | 
| const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframesRule(this, e, list.animationName().impl()); | 
| if (!keyframesRule) | 
| return; | 
| @@ -913,6 +1029,7 @@ PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const P | 
| PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex) | 
| { | 
| + ASSERT(!hasPendingAuthorStyleSheets()); | 
| resetDirectionAndWritingModeOnDocument(document()); | 
| StyleResolverState state(document(), document().documentElement()); // m_rootElementStyle will be set to the document style. |