Bug 931668 - Part 9 (no part 8): Make nsStyleContext::CalcStyleDifference compare all structs and return a bitfield of which changed. r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Fri, 05 Sep 2014 13:48:44 +1000
changeset 203735 f50e9c82b3b4fd45c9db4b51e66889e01961b356
parent 203734 effdf9950e60f416333ce01df26bc65897ba1cbb
child 203736 8fae88effe0da5f1032df84c19d0c2c547363a5f
push id48735
push usercmccormack@mozilla.com
push dateFri, 05 Sep 2014 03:56:37 +0000
treeherdermozilla-inbound@635055d16df6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs931668
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 931668 - Part 9 (no part 8): Make nsStyleContext::CalcStyleDifference compare all structs and return a bitfield of which changed. r=dbaron
layout/base/RestyleManager.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2129,18 +2129,20 @@ RestyleManager::ReparentStyleContext(nsI
         TryStartingTransition(mPresContext, aFrame->GetContent(),
                               oldContext, &newContext);
       }
 #endif
 
       // Make sure to call CalcStyleDifference so that the new context ends
       // up resolving all the structs the old context resolved.
       if (!copyFromContinuation) {
+        uint32_t equalStructs;
         DebugOnly<nsChangeHint> styleChange =
-          oldContext->CalcStyleDifference(newContext, nsChangeHint(0));
+          oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
+                                          &equalStructs);
         // The style change is always 0 because we have the same rulenode and
         // CalcStyleDifference optimizes us away.  That's OK, though:
         // reparenting should never trigger a frame reconstruct, and whenever
         // it's happening we already plan to reflow and repaint the frames.
         NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
                      "Our frame tree is likely to be bogus!");
       }
 
@@ -2193,19 +2195,21 @@ RestyleManager::ReparentStyleContext(nsI
         newExtraContext = mPresContext->StyleSet()->
                             ReparentStyleContext(oldExtraContext,
                                                  newContext, nullptr, nullptr);
         if (newExtraContext) {
           if (newExtraContext != oldExtraContext) {
             // Make sure to call CalcStyleDifference so that the new
             // context ends up resolving all the structs the old context
             // resolved.
+            uint32_t equalStructs;
             DebugOnly<nsChangeHint> styleChange =
               oldExtraContext->CalcStyleDifference(newExtraContext,
-                                                   nsChangeHint(0));
+                                                   nsChangeHint(0),
+                                                   &equalStructs);
             // The style change is always 0 because we have the same
             // rulenode and CalcStyleDifference optimizes us away.  That's
             // OK, though: reparenting should never trigger a frame
             // reconstruct, and whenever it's happening we already plan to
             // reflow and repaint the frames.
             NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
                          "Our frame tree is likely to be bogus!");
           }
@@ -2327,18 +2331,21 @@ ElementRestyler::CaptureChange(nsStyleCo
                                nsChangeHint aChangeToAssume)
 {
   // Check some invariants about replacing one style context with another.
   NS_ASSERTION(aOldContext->GetPseudo() == aNewContext->GetPseudo(),
                "old and new style contexts should have the same pseudo");
   NS_ASSERTION(aOldContext->GetPseudoType() == aNewContext->GetPseudoType(),
                "old and new style contexts should have the same pseudo");
 
-  nsChangeHint ourChange = aOldContext->CalcStyleDifference(aNewContext,
-                             mParentFrameHintsNotHandledForDescendants);
+  uint32_t equalStructs;
+  nsChangeHint ourChange =
+    aOldContext->CalcStyleDifference(aNewContext,
+                                     mParentFrameHintsNotHandledForDescendants,
+                                     &equalStructs);
   NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
                (ourChange & nsChangeHint_NeedReflow),
                "Reflow hint bits set without actually asking for a reflow");
 
   // nsChangeHint_UpdateEffects is inherited, but it can be set due to changes
   // in inherited properties (fill and stroke).  Avoid propagating it into
   // text nodes.
   if ((ourChange & nsChangeHint_UpdateEffects) &&
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -432,25 +432,31 @@ nsStyleContext::ApplyStyleFixups(bool aS
   }
 
   // Compute User Interface style, to trigger loads of cursors
   StyleUserInterface();
 }
 
 nsChangeHint
 nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
-                                    nsChangeHint aParentHintsNotHandledForDescendants)
+                                    nsChangeHint aParentHintsNotHandledForDescendants,
+                                    uint32_t* aEqualStructs)
 {
   PROFILER_LABEL("nsStyleContext", "CalcStyleDifference",
     js::ProfileEntry::Category::CSS);
 
   NS_ABORT_IF_FALSE(NS_IsHintSubset(aParentHintsNotHandledForDescendants,
                                     nsChangeHint_Hints_NotHandledForDescendants),
                     "caller is passing inherited hints, but shouldn't be");
 
+  static_assert(nsStyleStructID_Length <= 32,
+                "aEqualStructs is not big enough");
+
+  *aEqualStructs = 0;
+
   nsChangeHint hint = NS_STYLE_HINT_NONE;
   NS_ENSURE_TRUE(aOther, hint);
   // We must always ensure that we populate the structs on the new style
   // context that are filled in on the old context, so that if we get
   // two style changes in succession, the second of which causes a real
   // style change, the PeekStyleData doesn't return null (implying that
   // nobody ever looked at that struct's data).  In other words, we
   // can't skip later structs if we get a big change up front, because
@@ -473,42 +479,66 @@ nsStyleContext::CalcStyleDifference(nsSt
   bool compare = mRuleNode != aOther->mRuleNode;
 
   // If we had any change in variable values, then we'll need to examine
   // all of the other style structs too, even if the new style context has
   // the same rule node as the old one.
   const nsStyleVariables* thisVariables = PeekStyleVariables();
   if (thisVariables) {
     const nsStyleVariables* otherVariables = aOther->StyleVariables();
-    if (thisVariables->mVariables != otherVariables->mVariables) {
+    if (thisVariables->mVariables == otherVariables->mVariables) {
+      *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
+    } else {
       compare = true;
     }
+  } else {
+    *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
   }
 
   DebugOnly<int> styleStructCount = 1;  // count Variables already
 
 #define DO_STRUCT_DIFFERENCE(struct_)                                         \
   PR_BEGIN_MACRO                                                              \
     const nsStyle##struct_* this##struct_ = PeekStyle##struct_();             \
     if (this##struct_) {                                                      \
       const nsStyle##struct_* other##struct_ = aOther->Style##struct_();      \
       nsChangeHint maxDifference = nsStyle##struct_::MaxDifference();         \
       nsChangeHint maxDifferenceNeverInherited =                              \
         nsStyle##struct_::MaxDifferenceNeverInherited();                      \
-      if ((compare ||                                                         \
-           (NS_SubtractHint(maxDifference, maxDifferenceNeverInherited) &     \
-            aParentHintsNotHandledForDescendants)) &&                         \
-          !NS_IsHintSubset(maxDifference, hint) &&                            \
-          this##struct_ != other##struct_) {                                  \
-        NS_ASSERTION(NS_IsHintSubset(                                         \
-             this##struct_->CalcDifference(*other##struct_),                  \
-             nsStyle##struct_::MaxDifference()),                              \
-             "CalcDifference() returned bigger hint than MaxDifference()");   \
-        NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_));  \
+      if (this##struct_ == other##struct_) {                                  \
+        /* The very same struct, so we know that there will be no */          \
+        /* differences.                                           */          \
+        *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                      \
+      } else if (compare ||                                                   \
+                 (NS_SubtractHint(maxDifference,                              \
+                                  maxDifferenceNeverInherited) &              \
+                  aParentHintsNotHandledForDescendants)) {                    \
+        nsChangeHint difference =                                             \
+            this##struct_->CalcDifference(*other##struct_);                   \
+        NS_ASSERTION(NS_IsHintSubset(difference, maxDifference),              \
+                     "CalcDifference() returned bigger hint than "            \
+                     "MaxDifference()");                                      \
+        NS_UpdateHint(hint, difference);                                      \
+        if (!difference) {                                                    \
+          *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                    \
+        }                                                                     \
+      } else {                                                                \
+        /* We still must call CalcDifference to see if there were any */      \
+        /* changes so that we can set *aEqualStructs appropriately.   */      \
+        nsChangeHint difference =                                             \
+            this##struct_->CalcDifference(*other##struct_);                   \
+        NS_ASSERTION(NS_IsHintSubset(difference, maxDifference),              \
+                     "CalcDifference() returned bigger hint than "            \
+                     "MaxDifference()");                                      \
+        if (!difference) {                                                    \
+          *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                    \
+        }                                                                     \
       }                                                                       \
+    } else {                                                                  \
+      *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                        \
     }                                                                         \
     styleStructCount++;                                                       \
   PR_END_MACRO
 
   // In general, we want to examine structs starting with those that can
   // cause the largest style change, down to those that can cause the
   // smallest.  This lets us skip later ones if we already have a hint
   // that subsumes their MaxDifference.  (As the hints get
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -307,19 +307,23 @@ public:
    * hints apply to the frame and its later continuations or ib-split
    * siblings.  Most (all of those except the "NotHandledForDescendants"
    * hints) also apply to all descendants.  The caller must pass in any
    * non-inherited hints that resulted from the parent style context's
    * style change.  The caller *may* pass more hints than needed, but
    * must not pass less than needed; therefore if the caller doesn't
    * know, the caller should pass
    * nsChangeHint_Hints_NotHandledForDescendants.
+   *
+   * aEqualStructs must not be null.  Into it will be stored a bitfield
+   * representing which structs were compared to be non-equal.
    */
   nsChangeHint CalcStyleDifference(nsStyleContext* aOther,
-                                   nsChangeHint aParentHintsNotHandledForDescendants);
+                                   nsChangeHint aParentHintsNotHandledForDescendants,
+                                   uint32_t* aEqualStructs);
 
   /**
    * Get a color that depends on link-visitedness using this and
    * this->GetStyleIfVisited().
    *
    * aProperty must be a color-valued property that StyleAnimationValue
    * knows how to extract.  It must also be a property that we know to
    * do change handling for in nsStyleContext::CalcDifference.