Title: [165136] branches/safari-537.75-branch/Source/WebCore

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;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to