Diff
Modified: branches/safari-537.75-branch/Source/WebCore/ChangeLog (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/ChangeLog 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/ChangeLog 2014-03-05 23:35:14 UTC (rev 165136)
@@ -1,5 +1,89 @@
2014-03-05 Matthew Hanson <[email protected]>
+ Merge r153829
+
+ 2013-08-08 Andreas Kling <[email protected]>
+
+ Inserting multiple rules into an empty style sheet should avoid style recalc if possible.
+ <http://webkit.org/b/119568>
+
+ Reviewed by Antti Koivisto.
+
+ As a follow-up to <http://webkit.org/b/119475>, where I added a hack for inserting
+ a single rule into an empty style sheet, this broadens the optimization to support
+ any number of rules.
+
+ This optimizes the scenario where a style sheet is added to the DOM and then populated
+ rule-by-rule via CSSOM insertRule()/addRule() calls. Previously we'd do a full style
+ recalc for this case, but now we'll treat it the same as a full sheet added at once.
+
+ * css/CSSStyleSheet.h:
+ * css/CSSStyleSheet.cpp:
+ (WebCore::CSSStyleSheet::willMutateRules):
+
+ Made willMutateRules() return whether the style sheet contents were cloned by the
+ copy-on-write mechanism.
+
+ * dom/Document.h:
+ (WebCore::CSSStyleSheet::didMutateRules):
+ (WebCore::CSSStyleSheet::insertRule):
+
+ Replaced the InsertionIntoEmptySheet mutation type by a general RuleInsertion.
+ The mutation callback checks if we're inserting into a rule that's not (yet) part
+ of the document's active sheet set. In that case, we defer doing the style sheet
+ until all the insertions are done (or something forces us to style+layout.)
+
+ Note that this optimization only happens if the style sheet had a single client.
+ Shared style sheets that just got cloned before mutation may have pointers into
+ them from the Document's StyleResolver, so we're forced to do an immediate sheet
+ update in that case.
+
+ (WebCore::CSSStyleSheet::RuleMutationScope::RuleMutationScope):
+ (WebCore::CSSStyleSheet::RuleMutationScope::~RuleMutationScope):
+
+ Moved these out-of-line.
+
+ (WebCore::CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration):
+ * css/PropertySetCSSStyleDeclaration.cpp:
+ (WebCore::StyleRuleCSSStyleDeclaration::didMutate):
+
+ Made a separate mutation callback for CSSStyleDeclaration since its needs are
+ so simple compared to the mutation callback from CSSStyleSheet. Seems better
+ than adding yet another mode to the enum.
+
+ * dom/Document.cpp:
+ (WebCore::Document::Document):
+ (WebCore::Document::recalcStyle):
+ (WebCore::Document::styleResolverChanged):
+ (WebCore::Document::optimizedStyleSheetUpdateTimerFired):
+ (WebCore::Document::scheduleOptimizedStyleSheetUpdate):
+
+ Added mechanism to defer doing a RecalcStyleIfNeeded.
+
+ (WebCore::Document::updateStyleIfNeeded):
+
+ Synchronize the optimized style sheet update if there's one scheduled.
+ This ensures that stuff like layout-dependent property access won't operate
+ on stale style.
+
+ * dom/DocumentStyleSheetCollection.h:
+ (WebCore::DocumentStyleSheetCollection::pendingUpdateType):
+ (WebCore::DocumentStyleSheetCollection::setPendingUpdateType):
+ (WebCore::DocumentStyleSheetCollection::flushPendingUpdates):
+ * dom/DocumentStyleSheetCollection.cpp:
+ (WebCore::DocumentStyleSheetCollection::DocumentStyleSheetCollection):
+ (WebCore::DocumentStyleSheetCollection::updateActiveStyleSheets):
+
+ Have DSSC track the kind of style sheet update it needs to do (instead of just
+ a boolean "needs update.") This is used by Document::recalcStyle() to make sure
+ the right kind of update happens if there's one scheduled.
+
+ (WebCore::DocumentStyleSheetCollection::activeStyleSheetsContains):
+
+ Added helper to check if a CSSStyleSheet is part of the active set.
+
+2014-03-05 Matthew Hanson <[email protected]>
+
Merge r159970.
2013-12-02 Brady Eidson <[email protected]>
Modified: branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.cpp (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.cpp 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.cpp 2014-03-05 23:35:14 UTC (rev 165136)
@@ -1,6 +1,6 @@
/*
* (C) 1999-2003 Lars Knoll ([email protected])
- * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2006, 2007, 2012, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,6 +29,7 @@
#include "CSSStyleRule.h"
#include "CachedCSSStyleSheet.h"
#include "Document.h"
+#include "DocumentStyleSheetCollection.h"
#include "ExceptionCode.h"
#include "HTMLNames.h"
#include "MediaList.h"
@@ -125,12 +126,12 @@
m_contents->unregisterClient(this);
}
-void CSSStyleSheet::willMutateRules()
+CSSStyleSheet::WhetherContentsWereClonedForMutation CSSStyleSheet::willMutateRules()
{
// If we are the only client it is safe to mutate.
if (m_contents->hasOneClient() && !m_contents->isInMemoryCache()) {
m_contents->setMutable();
- return;
+ return ContentsWereNotClonedForMutation;
}
// Only cacheable stylesheets should have multiple clients.
ASSERT(m_contents->isCacheable());
@@ -144,17 +145,32 @@
// Any existing CSSOM wrappers need to be connected to the copied child rules.
reattachChildRuleCSSOMWrappers();
+
+ return ContentsWereClonedForMutation;
}
-void CSSStyleSheet::didMutateRules(RuleMutationType mutationType)
+void CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration()
{
ASSERT(m_contents->isMutable());
ASSERT(m_contents->hasOneClient());
+ didMutate();
+}
+void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation)
+{
+ ASSERT(m_contents->isMutable());
+ ASSERT(m_contents->hasOneClient());
+
Document* owner = ownerDocument();
if (!owner)
return;
- owner->styleResolverChanged(mutationType == InsertionIntoEmptySheet ? DeferRecalcStyleIfNeeded : DeferRecalcStyle);
+
+ if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !owner->styleSheetCollection()->activeStyleSheetsContains(this)) {
+ owner->scheduleOptimizedStyleSheetUpdate();
+ return;
+ }
+
+ owner->styleResolverChanged(DeferRecalcStyle);
}
void CSSStyleSheet::didMutate()
@@ -278,8 +294,7 @@
return 0;
}
- RuleMutationType mutationType = !length() ? InsertionIntoEmptySheet : OtherMutation;
- RuleMutationScope mutationScope(this, mutationType);
+ RuleMutationScope mutationScope(this, RuleInsertion);
bool success = m_contents->wrapperInsertRule(rule, index);
if (!success) {
@@ -385,4 +400,27 @@
m_childRuleCSSOMWrappers.clear();
}
+CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType)
+ : m_styleSheet(sheet)
+ , m_mutationType(mutationType)
+{
+ ASSERT(m_styleSheet);
+ m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
}
+
+CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
+ : m_styleSheet(rule ? rule->parentStyleSheet() : 0)
+ , m_mutationType(OtherMutation)
+ , m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation)
+{
+ if (m_styleSheet)
+ m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
+}
+
+CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
+{
+ if (m_styleSheet)
+ m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation);
+}
+
+}
Modified: branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.h (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.h 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/css/CSSStyleSheet.h 2014-03-05 23:35:14 UTC (rev 165136)
@@ -85,7 +85,8 @@
void setMediaQueries(PassRefPtr<MediaQuerySet>);
void setTitle(const String& title) { m_title = title; }
- enum RuleMutationType { OtherMutation, InsertionIntoEmptySheet };
+ enum RuleMutationType { OtherMutation, RuleInsertion };
+ enum WhetherContentsWereClonedForMutation { ContentsWereNotClonedForMutation = 0, ContentsWereClonedForMutation };
class RuleMutationScope {
WTF_MAKE_NONCOPYABLE(RuleMutationScope);
@@ -97,10 +98,12 @@
private:
CSSStyleSheet* m_styleSheet;
RuleMutationType m_mutationType;
+ WhetherContentsWereClonedForMutation m_contentsWereClonedForMutation;
};
- void willMutateRules();
- void didMutateRules(RuleMutationType = OtherMutation);
+ WhetherContentsWereClonedForMutation willMutateRules();
+ void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation);
+ void didMutateRuleFromCSSStyleDeclaration();
void didMutate();
void clearChildRuleCSSOMWrappers();
@@ -131,28 +134,6 @@
mutable OwnPtr<CSSRuleList> m_ruleListCSSOMWrapper;
};
-inline CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType)
- : m_styleSheet(sheet)
- , m_mutationType(mutationType)
-{
- if (m_styleSheet)
- m_styleSheet->willMutateRules();
-}
-
-inline CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
- : m_styleSheet(rule ? rule->parentStyleSheet() : 0)
- , m_mutationType(OtherMutation)
-{
- if (m_styleSheet)
- m_styleSheet->willMutateRules();
-}
-
-inline CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
-{
- if (m_styleSheet)
- m_styleSheet->didMutateRules(m_mutationType);
-}
-
} // namespace
#endif
Modified: branches/safari-537.75-branch/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp 2014-03-05 23:35:14 UTC (rev 165136)
@@ -331,9 +331,9 @@
if (type == PropertyChanged)
m_cssomCSSValueClones.clear();
- // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
+ // Style sheet mutation needs to be signaled even if the change failed. willMutate*/didMutate* must pair.
if (m_parentRule && m_parentRule->parentStyleSheet())
- m_parentRule->parentStyleSheet()->didMutateRules();
+ m_parentRule->parentStyleSheet()->didMutateRuleFromCSSStyleDeclaration();
}
CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
Modified: branches/safari-537.75-branch/Source/WebCore/dom/Document.cpp (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/dom/Document.cpp 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/dom/Document.cpp 2014-03-05 23:35:14 UTC (rev 165136)
@@ -419,6 +419,7 @@
, m_visuallyOrdered(false)
, m_readyState(Complete)
, m_bParsing(false)
+ , m_optimizedStyleSheetUpdateTimer(this, &Document::optimizedStyleSheetUpdateTimerFired)
, m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
, m_pendingStyleRecalcShouldForce(false)
, m_inStyleRecalc(false)
@@ -1763,8 +1764,7 @@
// re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed
// hits a null-dereference due to security code always assuming the document has a SecurityOrigin.
- if (m_styleSheetCollection->needsUpdateActiveStylesheetsOnStyleRecalc())
- m_styleSheetCollection->updateActiveStyleSheets(DocumentStyleSheetCollection::FullUpdate);
+ m_styleSheetCollection->flushPendingUpdates();
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
@@ -1843,7 +1843,10 @@
{
ASSERT(isMainThread());
ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
-
+
+ if (m_optimizedStyleSheetUpdateTimer.isActive())
+ styleResolverChanged(RecalcStyleIfNeeded);
+
if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache())
return;
@@ -3134,8 +3137,24 @@
m_mediaQueryMatcher->styleResolverChanged();
}
+void Document::optimizedStyleSheetUpdateTimerFired(Timer<Document>*)
+{
+ styleResolverChanged(RecalcStyleIfNeeded);
+}
+
+void Document::scheduleOptimizedStyleSheetUpdate()
+{
+ if (m_optimizedStyleSheetUpdateTimer.isActive())
+ return;
+ styleSheetCollection()->setPendingUpdateType(DocumentStyleSheetCollection::OptimizedUpdate);
+ m_optimizedStyleSheetUpdateTimer.startOneShot(0);
+}
+
void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag)
{
+ if (m_optimizedStyleSheetUpdateTimer.isActive())
+ m_optimizedStyleSheetUpdateTimer.stop();
+
// 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 (!attached() || (!m_didCalculateStyleResolver && !haveStylesheetsLoaded())) {
Modified: branches/safari-537.75-branch/Source/WebCore/dom/Document.h (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/dom/Document.h 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/dom/Document.h 2014-03-05 23:35:14 UTC (rev 165136)
@@ -484,6 +484,8 @@
*/
void styleResolverChanged(StyleResolverUpdateFlag);
+ void scheduleOptimizedStyleSheetUpdate();
+
void didAccessStyleResolver();
void evaluateMediaQueryList();
@@ -697,6 +699,7 @@
bool hasPendingStyleRecalc() const;
bool hasPendingForcedStyleRecalc() const;
void styleRecalcTimerFired(Timer<Document>*);
+ void optimizedStyleSheetUpdateTimerFired(Timer<Document>*);
void registerNodeList(LiveNodeListBase*);
void unregisterNodeList(LiveNodeListBase*);
@@ -1362,7 +1365,8 @@
bool m_visuallyOrdered;
ReadyState m_readyState;
bool m_bParsing;
-
+
+ Timer<Document> m_optimizedStyleSheetUpdateTimer;
Timer<Document> m_styleRecalcTimer;
bool m_pendingStyleRecalcShouldForce;
bool m_inStyleRecalc;
Modified: branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.cpp (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.cpp 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.cpp 2014-03-05 23:35:14 UTC (rev 165136)
@@ -58,7 +58,7 @@
, m_pendingStylesheets(0)
, m_injectedStyleSheetCacheValid(false)
, m_hadActiveLoadingStylesheet(false)
- , m_needsUpdateActiveStylesheetsOnStyleRecalc(false)
+ , m_pendingUpdateType(NoUpdate)
, m_usesSiblingRules(false)
, m_usesSiblingRulesOverride(false)
, m_usesFirstLineRules(false)
@@ -453,7 +453,7 @@
// 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;
+ m_pendingUpdateType = FullUpdate;
m_document->scheduleForcedStyleRecalc();
return false;
@@ -487,15 +487,27 @@
}
resetCSSFeatureFlags();
}
+
+ m_weakCopyOfActiveStyleSheetListForFastLookup.clear();
m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
m_usesRemUnits = styleSheetsUseRemUnits(m_activeAuthorStyleSheets);
- m_needsUpdateActiveStylesheetsOnStyleRecalc = false;
+ m_pendingUpdateType = NoUpdate;
m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
return requiresFullStyleRecalc;
}
+bool DocumentStyleSheetCollection::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
+{
+ if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
+ m_weakCopyOfActiveStyleSheetListForFastLookup = adoptPtr(new HashSet<const CSSStyleSheet*>);
+ for (unsigned i = 0; i < m_activeAuthorStyleSheets.size(); ++i)
+ m_weakCopyOfActiveStyleSheetListForFastLookup->add(m_activeAuthorStyleSheets[i].get());
+ }
+ return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
}
+
+}
Modified: branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.h (165135 => 165136)
--- branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.h 2014-03-05 23:33:21 UTC (rev 165135)
+++ branches/safari-537.75-branch/Source/WebCore/dom/DocumentStyleSheetCollection.h 2014-03-05 23:35:14 UTC (rev 165136)
@@ -71,9 +71,21 @@
void addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet);
void addUserSheet(PassRefPtr<StyleSheetContents> userSheet);
- bool needsUpdateActiveStylesheetsOnStyleRecalc() const { return m_needsUpdateActiveStylesheetsOnStyleRecalc; }
+ enum UpdateFlag { NoUpdate = 0, OptimizedUpdate, FullUpdate };
- enum UpdateFlag { FullUpdate, OptimizedUpdate };
+ UpdateFlag pendingUpdateType() const { return m_pendingUpdateType; }
+ void setPendingUpdateType(UpdateFlag updateType)
+ {
+ if (updateType > m_pendingUpdateType)
+ m_pendingUpdateType = updateType;
+ }
+
+ void flushPendingUpdates()
+ {
+ if (m_pendingUpdateType != NoUpdate)
+ updateActiveStyleSheets(m_pendingUpdateType);
+ }
+
bool updateActiveStyleSheets(UpdateFlag);
String preferredStylesheetSetName() const { return m_preferredStylesheetSetName; }
@@ -103,6 +115,8 @@
void combineCSSFeatureFlags();
void resetCSSFeatureFlags();
+ bool activeStyleSheetsContains(const CSSStyleSheet*) const;
+
private:
DocumentStyleSheetCollection(Document*);
@@ -119,6 +133,9 @@
Vector<RefPtr<StyleSheet> > m_styleSheetsForStyleSheetList;
Vector<RefPtr<CSSStyleSheet> > m_activeAuthorStyleSheets;
+ // This is a mirror of m_activeAuthorStyleSheets that gets populated on demand for activeStyleSheetsContains().
+ mutable OwnPtr<HashSet<const CSSStyleSheet*>> m_weakCopyOfActiveStyleSheetListForFastLookup;
+
// Track the number of currently loading top-level stylesheets needed for rendering.
// Sheets loaded using the @import directive are not included in this count.
// We use this count of pending sheets to detect when we can begin attaching
@@ -135,7 +152,7 @@
Vector<RefPtr<CSSStyleSheet> > m_authorStyleSheets;
bool m_hadActiveLoadingStylesheet;
- bool m_needsUpdateActiveStylesheetsOnStyleRecalc;
+ UpdateFlag m_pendingUpdateType;
typedef ListHashSet<Node*, 32> StyleSheetCandidateListHashSet;
StyleSheetCandidateListHashSet m_styleSheetCandidateNodes;