Index: third_party/WebKit/Source/core/dom/TreeScopeStyleSheetCollection.cpp |
diff --git a/third_party/WebKit/Source/core/dom/TreeScopeStyleSheetCollection.cpp b/third_party/WebKit/Source/core/dom/TreeScopeStyleSheetCollection.cpp |
index 918824798ed10537f1849443e14cd12541843d22..a64330698a590fa62ffe8da209d914a5272f575c 100644 |
--- a/third_party/WebKit/Source/core/dom/TreeScopeStyleSheetCollection.cpp |
+++ b/third_party/WebKit/Source/core/dom/TreeScopeStyleSheetCollection.cpp |
@@ -28,10 +28,10 @@ |
#include "core/dom/TreeScopeStyleSheetCollection.h" |
-#include "core/css/ActiveStyleSheets.h" |
#include "core/css/CSSStyleSheet.h" |
#include "core/css/StyleRuleImport.h" |
#include "core/css/StyleSheetContents.h" |
+#include "core/css/invalidation/StyleSheetInvalidationAnalysis.h" |
#include "core/css/resolver/StyleResolver.h" |
#include "core/dom/Element.h" |
#include "core/dom/StyleEngine.h" |
@@ -42,31 +42,139 @@ |
TreeScopeStyleSheetCollection::TreeScopeStyleSheetCollection( |
TreeScope& treeScope) |
- : m_treeScope(treeScope) {} |
+ : m_treeScope(treeScope), m_hadActiveLoadingStylesheet(false) {} |
void TreeScopeStyleSheetCollection::addStyleSheetCandidateNode(Node& node) { |
- if (node.isConnected()) |
- m_styleSheetCandidateNodes.add(&node); |
+ if (!node.isConnected()) |
+ return; |
+ |
+ m_styleSheetCandidateNodes.add(&node); |
} |
-bool TreeScopeStyleSheetCollection::mediaQueryAffectingValueChanged() { |
- bool needsActiveStyleUpdate = false; |
- for (const auto& activeSheet : m_activeAuthorStyleSheets) { |
- if (activeSheet.first->mediaQueries()) |
- needsActiveStyleUpdate = true; |
- StyleSheetContents* contents = activeSheet.first->contents(); |
+TreeScopeStyleSheetCollection::StyleResolverUpdateType |
+TreeScopeStyleSheetCollection::compareStyleSheets( |
+ const HeapVector<Member<CSSStyleSheet>>& oldStyleSheets, |
+ const HeapVector<Member<CSSStyleSheet>>& newStylesheets, |
+ HeapVector<Member<StyleSheetContents>>& addedSheets) { |
+ unsigned newStyleSheetCount = newStylesheets.size(); |
+ unsigned oldStyleSheetCount = oldStyleSheets.size(); |
+ DCHECK_GE(newStyleSheetCount, oldStyleSheetCount); |
+ |
+ if (!newStyleSheetCount) |
+ return Reconstruct; |
+ |
+ unsigned newIndex = 0; |
+ for (unsigned oldIndex = 0; oldIndex < oldStyleSheetCount; ++oldIndex) { |
+ while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) { |
+ addedSheets.append(newStylesheets[newIndex]->contents()); |
+ if (++newIndex == newStyleSheetCount) |
+ return Reconstruct; |
+ } |
+ if (++newIndex == newStyleSheetCount) |
+ return Reconstruct; |
+ } |
+ bool hasInsertions = !addedSheets.isEmpty(); |
+ while (newIndex < newStyleSheetCount) { |
+ addedSheets.append(newStylesheets[newIndex]->contents()); |
+ ++newIndex; |
+ } |
+ // If all new sheets were added at the end of the list we can just add them to |
+ // existing StyleResolver. If there were insertions we need to re-add all the |
+ // stylesheets so rules are ordered correctly. |
+ return hasInsertions ? Reset : Additive; |
+} |
+ |
+bool TreeScopeStyleSheetCollection::activeLoadingStyleSheetLoaded( |
+ const HeapVector<Member<CSSStyleSheet>>& newStyleSheets) { |
+ // StyleSheets of <style> elements that @import stylesheets are active but |
+ // loading. We need to trigger a full recalc when such loads are done. |
+ bool hasActiveLoadingStylesheet = false; |
+ for (const auto& sheet : newStyleSheets) { |
+ if (sheet->isLoading()) |
+ hasActiveLoadingStylesheet = true; |
+ } |
+ if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) { |
+ m_hadActiveLoadingStylesheet = false; |
+ return true; |
+ } |
+ m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet; |
+ return false; |
+} |
+ |
+static bool findFontFaceRulesFromStyleSheetContents( |
+ const HeapVector<Member<StyleSheetContents>>& sheets, |
+ HeapVector<Member<const StyleRuleFontFace>>& fontFaceRules) { |
+ bool hasFontFaceRule = false; |
+ |
+ for (const auto& sheet : sheets) { |
+ DCHECK(sheet); |
+ if (sheet->hasFontFaceRule()) { |
+ // FIXME: We don't need this for styles in shadow tree. |
+ sheet->findFontFaceRules(fontFaceRules); |
+ hasFontFaceRule = true; |
+ } |
+ } |
+ return hasFontFaceRule; |
+} |
+ |
+void TreeScopeStyleSheetCollection::analyzeStyleSheetChange( |
+ StyleResolverUpdateMode updateMode, |
+ const HeapVector<Member<CSSStyleSheet>>& newActiveAuthorStyleSheets, |
+ StyleSheetChange& change) { |
+ if (activeLoadingStyleSheetLoaded(newActiveAuthorStyleSheets)) |
+ return; |
+ |
+ if (updateMode != AnalyzedStyleUpdate) |
+ return; |
+ |
+ // Find out which stylesheets are new. |
+ HeapVector<Member<StyleSheetContents>> addedSheets; |
+ if (m_activeAuthorStyleSheets.size() <= newActiveAuthorStyleSheets.size()) { |
+ change.styleResolverUpdateType = compareStyleSheets( |
+ m_activeAuthorStyleSheets, newActiveAuthorStyleSheets, addedSheets); |
+ } else { |
+ StyleResolverUpdateType updateType = compareStyleSheets( |
+ newActiveAuthorStyleSheets, m_activeAuthorStyleSheets, addedSheets); |
+ if (updateType != Additive) { |
+ change.styleResolverUpdateType = updateType; |
+ } else { |
+ change.styleResolverUpdateType = Reset; |
+ // If @font-face is removed, needs full style recalc. |
+ if (findFontFaceRulesFromStyleSheetContents(addedSheets, |
+ change.fontFaceRulesToRemove)) |
+ return; |
+ } |
+ } |
+ |
+ // FIXME: If styleResolverUpdateType is Reconstruct, we should return early |
+ // here since we need to recalc the whole document. It's wrong to use |
+ // StyleSheetInvalidationAnalysis since it only looks at the addedSheets. |
+ |
+ // No point in doing the analysis work if we're just going to recalc the whole |
+ // document anyways. This needs to be done after the compareStyleSheets calls |
+ // above to ensure we don't throw away the StyleResolver if we don't need to. |
+ if (document().hasPendingForcedStyleRecalc()) |
+ return; |
+ |
+ // If we are already parsing the body and so may have significant amount of |
+ // elements, put some effort into trying to avoid style recalcs. |
+ if (!document().body() || document().hasNodesWithPlaceholderStyle()) |
+ return; |
+ StyleSheetInvalidationAnalysis invalidationAnalysis(*m_treeScope, |
+ addedSheets); |
+ if (invalidationAnalysis.dirtiesAllStyle()) |
+ return; |
+ invalidationAnalysis.invalidateStyle(); |
+ change.requiresFullStyleRecalc = false; |
+ return; |
+} |
+ |
+void TreeScopeStyleSheetCollection::clearMediaQueryRuleSetStyleSheets() { |
+ for (const auto& sheet : m_activeAuthorStyleSheets) { |
+ StyleSheetContents* contents = sheet->contents(); |
if (contents->hasMediaQueries()) |
contents->clearRuleSet(); |
} |
- return needsActiveStyleUpdate; |
-} |
- |
-void TreeScopeStyleSheetCollection::applyActiveStyleSheetChanges( |
- StyleSheetCollection& newCollection) { |
- document().styleEngine().applyRuleSetChanges( |
- treeScope(), activeAuthorStyleSheets(), |
- newCollection.activeAuthorStyleSheets()); |
- newCollection.swap(*this); |
} |
DEFINE_TRACE(TreeScopeStyleSheetCollection) { |