Bug 1380133 - Part 7: Use old ServoComputedValues in Gecko_CalcStyleDifference. draft
authorCameron McCormack <cam@mcc.id.au>
Mon, 17 Jul 2017 13:08:07 +0800
changeset 609640 15843e4800548d4a6a59499abbbe5e755bbad4f1
parent 609639 a9860d977e97ee29c12c3e45e167e944050c0b65
child 609641 9465794aea0112c781fc30b7423e125c5013a7ef
push id68611
push userbmo:cam@mcc.id.au
push dateMon, 17 Jul 2017 05:09:54 +0000
bugs1380133
milestone56.0a1
Bug 1380133 - Part 7: Use old ServoComputedValues in Gecko_CalcStyleDifference. MozReview-Commit-ID: DwxEAAOxQcr
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -357,28 +357,31 @@ Gecko_GetStyleContext(RawGeckoElementBor
 
 CSSPseudoElementType
 Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetPseudoElementType();
 }
 
 nsChangeHint
-Gecko_CalcStyleDifference(nsStyleContext* aOldStyleContext,
-                          RawServoComputedValuesBorrowed aComputedValues,
+Gecko_CalcStyleDifference(nsStyleContext* aOldSource,
+                          RawServoComputedValuesBorrowed aOldValues,
+                          RawServoComputedValuesBorrowed aNewValues,
                           bool* aAnyStyleChanged)
 {
-  MOZ_ASSERT(aOldStyleContext);
-  MOZ_ASSERT(aComputedValues);
+  MOZ_ASSERT(aOldValues);
+  MOZ_ASSERT(aNewValues);
 
   uint32_t equalStructs, samePointerStructs;
   nsChangeHint result =
-    aOldStyleContext->CalcStyleDifference(aComputedValues,
-                                          &equalStructs,
-                                          &samePointerStructs);
+    nsStyleContext::CalcStyleDifference(aOldSource,
+                                        aOldValues,
+                                        aNewValues,
+                                        &equalStructs,
+                                        &samePointerStructs);
   *aAnyStyleChanged = equalStructs != NS_STYLE_INHERIT_MASK;
   return result;
 }
 
 nsChangeHint
 Gecko_HintsHandledForDescendants(nsChangeHint aHint)
 {
   return aHint & ~NS_HintsNotHandledForDescendantsIn(aHint);
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -353,17 +353,18 @@ void Gecko_UnsetNodeFlags(RawGeckoNodeBo
 void Gecko_SetOwnerDocumentNeedsStyleFlush(RawGeckoElementBorrowed element);
 
 // Incremental restyle.
 // Also, we might want a ComputedValues to ComputedValues API for animations?
 // Not if we do them in Gecko...
 nsStyleContext* Gecko_GetStyleContext(RawGeckoElementBorrowed element,
                                       nsIAtom* aPseudoTagOrNull);
 mozilla::CSSPseudoElementType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
-nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
+nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* old_source,
+                                       RawServoComputedValuesBorrowed old_style,
                                        RawServoComputedValuesBorrowed new_style,
                                        bool* any_style_changed);
 nsChangeHint Gecko_HintsHandledForDescendants(nsChangeHint aHint);
 
 // Get an element snapshot for a given element from the table.
 const ServoElementSnapshot*
 Gecko_GetElementSnapshot(const mozilla::ServoElementSnapshotTable* table,
                          RawGeckoElementBorrowed element);
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -229,28 +229,28 @@ nsStyleContext::MoveTo(nsStyleContext* a
 
   if (mStyleIfVisited) {
     mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
     mStyleIfVisited->mParent = aNewParent;
     mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
   }
 }
 
-template<class StyleContextLike>
 bool
-nsStyleContext::EqualCustomProperties(StyleContextLike* aOther)
+nsStyleContext::EqualCustomProperties(nsStyleContext* aOther)
 {
   const nsStyleVariables* thisVariables = PeekStyleVariables();
   return !thisVariables ||
          thisVariables->mVariables == aOther->StyleVariables()->mVariables;
 }
 
 template<class StyleContextLike>
-nsChangeHint
-nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
+/* static */ nsChangeHint
+nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aOldContext,
+                                            StyleContextLike* aNewContext,
                                             uint32_t* aEqualStructs,
                                             uint32_t* aSamePointerStructs)
 {
   AUTO_PROFILER_LABEL("nsStyleContext::CalcStyleDifferenceInternal", CSS);
 
   static_assert(nsStyleStructID_Length <= 32,
                 "aEqualStructs is not big enough");
 
@@ -267,44 +267,44 @@ nsStyleContext::CalcStyleDifferenceInter
   // we could later get a small change in one of those structs that we
   // don't want to miss.
 
   DebugOnly<uint32_t> structsFound = 0;
 
   // FIXME(heycam): We should just do the comparison in
   // nsStyleVariables::CalcDifference, returning NeutralChange if there are
   // any Variables differences.
-  if (EqualCustomProperties(aNewContext)) {
+  if (aOldContext->EqualCustomProperties(aNewContext)) {
     *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
   }
 
-  if (PeekStyleVariables()) {
+  if (aOldContext->PeekStyleVariables()) {
     structsFound |= NS_STYLE_INHERIT_BIT(Variables);
   }
 
   DebugOnly<int> styleStructCount = 1;  // count Variables already
 
   // Servo's optimization to stop the cascade when there are no style changes
   // that children need to be recascade for relies on comparing all of the
   // structs, not just those that are returned from PeekStyleData, although
   // if PeekStyleData does return null we still don't want to accumulate
   // any change hints for those structs.
-  bool checkUnrequestedServoStructs = IsServo();
+  bool checkUnrequestedServoStructs = aOldContext->IsServo();
 
 #define EXPAND(...) __VA_ARGS__
 #define DO_STRUCT_DIFFERENCE_WITH_ARGS(struct_, extra_args_)                  \
   PR_BEGIN_MACRO                                                              \
-    const nsStyle##struct_* this##struct_ = PeekStyle##struct_();             \
+    const nsStyle##struct_* this##struct_ = aOldContext->PeekStyle##struct_();\
     bool unrequestedStruct;                                                   \
     if (this##struct_) {                                                      \
       unrequestedStruct = false;                                              \
       structsFound |= NS_STYLE_INHERIT_BIT(struct_);                          \
     } else if (checkUnrequestedServoStructs) {                                \
       this##struct_ =                                                         \
-        Servo_GetStyle##struct_(AsServo()->ComputedValues());                 \
+        aOldContext->PeekStyle##struct_##FromComputedValues();                \
       unrequestedStruct = true;                                               \
     } else {                                                                  \
       unrequestedStruct = false;                                              \
     }                                                                         \
     if (this##struct_) {                                                      \
       const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
       if (this##struct_ == other##struct_) {                                  \
         /* The very same struct, so we know that there will be no */          \
@@ -337,20 +337,20 @@ nsStyleContext::CalcStyleDifferenceInter
   DO_STRUCT_DIFFERENCE(Content);
   DO_STRUCT_DIFFERENCE(UserInterface);
   DO_STRUCT_DIFFERENCE(Visibility);
   DO_STRUCT_DIFFERENCE(Outline);
   DO_STRUCT_DIFFERENCE(TableBorder);
   DO_STRUCT_DIFFERENCE(Table);
   DO_STRUCT_DIFFERENCE(UIReset);
   DO_STRUCT_DIFFERENCE(Text);
-  DO_STRUCT_DIFFERENCE_WITH_ARGS(List, (, PeekStyleDisplay()));
+  DO_STRUCT_DIFFERENCE_WITH_ARGS(List, (, aOldContext->PeekStyleDisplay()));
   DO_STRUCT_DIFFERENCE(SVGReset);
   DO_STRUCT_DIFFERENCE(SVG);
-  DO_STRUCT_DIFFERENCE_WITH_ARGS(Position, (, PeekStyleVisibility()));
+  DO_STRUCT_DIFFERENCE_WITH_ARGS(Position, (, aOldContext->PeekStyleVisibility()));
   DO_STRUCT_DIFFERENCE(Font);
   DO_STRUCT_DIFFERENCE(Margin);
   DO_STRUCT_DIFFERENCE(Padding);
   DO_STRUCT_DIFFERENCE(Border);
   DO_STRUCT_DIFFERENCE(TextReset);
   DO_STRUCT_DIFFERENCE(Effects);
   DO_STRUCT_DIFFERENCE(Background);
   DO_STRUCT_DIFFERENCE(Color);
@@ -360,17 +360,17 @@ nsStyleContext::CalcStyleDifferenceInter
 #undef EXPAND
 
   MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
              "missing a call to DO_STRUCT_DIFFERENCE");
 
 #ifdef DEBUG
   #define STYLE_STRUCT(name_, callback_)                                      \
     MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) ==              \
-               !!PeekStyle##name_(),                                          \
+               !!aOldContext->PeekStyle##name_(),                             \
                "PeekStyleData results must not change in the middle of "      \
                "difference calculation.");
   #include "nsStyleStructList.h"
   #undef STYLE_STRUCT
 #endif
 
   // We check for struct pointer equality here rather than as part of the
   // DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
@@ -379,17 +379,17 @@ nsStyleContext::CalcStyleDifferenceInter
   // happen when the nsRuleNode::ComputeXXXData method looks up another
   // struct.)  This is important for callers in RestyleManager that
   // need to know the equality or not of the final set of cached struct
   // pointers.
   *aSamePointerStructs = 0;
 
 #define STYLE_STRUCT(name_, callback_)                                        \
   {                                                                           \
-    const nsStyle##name_* data = PeekStyle##name_();                          \
+    const nsStyle##name_* data = aOldContext->PeekStyle##name_();             \
     if (!data || data == aNewContext->Style##name_()) {                       \
       *aSamePointerStructs |= NS_STYLE_INHERIT_BIT(name_);                    \
     }                                                                         \
   }
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
   // Note that we do not check whether this->RelevantLinkVisited() !=
@@ -403,42 +403,34 @@ nsStyleContext::CalcStyleDifferenceInter
   // the page to measure.
   // However, we do need to compute the larger of the changes that can
   // happen depending on whether the link is visited or unvisited, since
   // doing only the one that's currently appropriate would expose which
   // links are in history to easy performance measurement.  Therefore,
   // here, we add nsChangeHint_RepaintFrame hints (the maximum for
   // things that can depend on :visited) for the properties on which we
   // call GetVisitedDependentColor.
-  auto* thisVis = GetStyleIfVisited();
-  auto* otherVis = aNewContext->GetStyleIfVisited();
+  StyleContextLike* thisVis = aOldContext->GetStyleIfVisited();
+  StyleContextLike* otherVis = aNewContext->GetStyleIfVisited();
   if (!thisVis != !otherVis) {
     // One style context has a style-if-visited and the other doesn't.
     // Presume a difference.
     hint |= nsChangeHint_RepaintFrame;
   } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
-    // Bug 1364484: Update comments here and potentially remove the assertion
-    // below once we return a non-null visited context in CalcStyleDifference
-    // using Servo values.  The approach is becoming quite similar to Gecko.
-    // We'll handle visited style differently in servo. Assert against being
-    // in the parallel traversal to avoid static analysis hazards when calling
-    // StyleFoo() below.
-    MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
-
     // Both style contexts have a style-if-visited.
     bool change = false;
 
-    // NB: Calling Peek on |this|, not |thisVis|, since callers may look
-    // at a struct on |this| without looking at the same struct on
+    // NB: Calling Peek on |aOldContext|, not |thisVis|, since callers may
+    // look at a struct on |this| without looking at the same struct on
     // |thisVis| (including this function if we skip one of these checks
     // due to change being true already or due to the old style context
     // not having a style-if-visited), but not the other way around.
 #define STYLE_FIELD(name_) thisVisStruct->name_ != otherVisStruct->name_
 #define STYLE_STRUCT(name_, fields_)                                    \
-    if (!change && PeekStyle##name_()) {                                \
+    if (!change && aOldContext->PeekStyle##name_()) {                   \
       const nsStyle##name_* thisVisStruct = thisVis->Style##name_();    \
       const nsStyle##name_* otherVisStruct = otherVis->Style##name_();  \
       if (MOZ_FOR_EACH_SEPARATED(STYLE_FIELD, (||), (), fields_)) {     \
         change = true;                                                  \
       }                                                                 \
     }
 #include "nsCSSVisitedDependentPropList.h"
 #undef STYLE_STRUCT
@@ -458,20 +450,22 @@ nsStyleContext::CalcStyleDifferenceInter
 
     // This depends on data in nsStyleDisplay, nsStyleEffects and
     // nsStyleSVGReset, so we do it here.
 
     // Note that it's perhaps good for this test to be last because it
     // doesn't use Peek* functions to get the structs on the old
     // context.  But this isn't a big concern because these struct
     // getters should be called during frame construction anyway.
-    if (ThreadsafeStyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
+    if (aOldContext->ThreadsafeStyleDisplay()->
+          IsAbsPosContainingBlockForAppropriateFrame(aOldContext) ==
         aNewContext->ThreadsafeStyleDisplay()->
           IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
-        ThreadsafeStyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
+        aOldContext->ThreadsafeStyleDisplay()->
+          IsFixedPosContainingBlockForAppropriateFrame(aOldContext) ==
         aNewContext->ThreadsafeStyleDisplay()->
           IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
       // While some styles that cause the frame to be a containing block
       // has changed, the overall result hasn't.
       hint &= ~nsChangeHint_UpdateContainingBlock;
     }
   }
 
@@ -480,17 +474,17 @@ nsStyleContext::CalcStyleDifferenceInter
   return hint & ~nsChangeHint_NeutralChange;
 }
 
 nsChangeHint
 nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
                                     uint32_t* aEqualStructs,
                                     uint32_t* aSamePointerStructs)
 {
-  return CalcStyleDifferenceInternal(aNewContext,
+  return CalcStyleDifferenceInternal(this, aNewContext,
                                      aEqualStructs,
                                      aSamePointerStructs);
 }
 
 class MOZ_STACK_CLASS FakeStyleContext
 {
 public:
   FakeStyleContext(RawServoComputedValuesBorrowed aComputedValues,
@@ -523,29 +517,77 @@ public:
   #undef STYLE_STRUCT
 
   bool EqualCustomProperties(FakeStyleContext* aOther)
   {
     return Servo_RawComputedValues_EqualCustomProperties(
         mComputedValues, aOther->mComputedValues);
   }
 
+  bool IsServo() const { return true; }
+
 private:
   RawServoComputedValuesBorrowed MOZ_NON_OWNING_REF mComputedValues;
   uint64_t mBits;
   FakeStyleContext* MOZ_NON_OWNING_REF mVisitedStyle;
 };
 
-nsChangeHint
-nsStyleContext::CalcStyleDifference(RawServoComputedValuesBorrowed aNewValues,
+/* static */ Maybe<FakeStyleContext>
+nsStyleContext::MakeFakeStyleContext(RawServoComputedValuesBorrowed aValues,
+                                     nsStyleContext* aSource,
+                                     FakeStyleContext* aVisitedStyle)
+{
+  if (!aValues) {
+    return Nothing();
+  }
+
+  uint64_t bits = aSource ? aSource->mBits : 0;
+  return Some(FakeStyleContext(aValues, bits, aVisitedStyle));
+}
+
+/* static */ Maybe<FakeStyleContext>
+nsStyleContext::MakeVisitedFakeStyleContext(
+    RawServoComputedValuesBorrowed aValues,
+    nsStyleContext* aSource)
+{
+  if (!aValues) {
+    return Nothing();
+  }
+
+  RawServoComputedValuesBorrowed visitedValues =
+    Servo_RawComputedValues_GetVisitedStyle(aValues);
+  if (!visitedValues) {
+    return Nothing();
+  }
+
+  return MakeFakeStyleContext(visitedValues, aSource, nullptr);
+}
+
+/* static */ nsChangeHint
+nsStyleContext::CalcStyleDifference(nsStyleContext* aSource,
+                                    RawServoComputedValuesBorrowed aOldValues,
+                                    RawServoComputedValuesBorrowed aNewValues,
                                     uint32_t* aEqualStructs,
                                     uint32_t* aSamePointerStructs)
 {
-  FakeStyleContext newContext(aNewValues, 0, nullptr);
-  return CalcStyleDifferenceInternal(&newContext,
+  nsStyleContext* visitedSource =
+    aSource ? aSource->GetStyleIfVisited() : nullptr;
+
+  Maybe<FakeStyleContext> oldVisitedContext =
+    MakeVisitedFakeStyleContext(aOldValues, visitedSource);
+  Maybe<FakeStyleContext> newVisitedContext =
+    MakeVisitedFakeStyleContext(aNewValues, nullptr);
+
+  FakeStyleContext oldContext(aOldValues, aSource ? aSource->mBits : 0,
+                              oldVisitedContext.ptrOr(nullptr));
+  FakeStyleContext newContext(aNewValues, 0,
+                              newVisitedContext.ptrOr(nullptr));
+
+  return CalcStyleDifferenceInternal(&oldContext,
+                                     &newContext,
                                      aEqualStructs,
                                      aSamePointerStructs);
 }
 
 namespace mozilla {
 
 void
 GeckoStyleContext::EnsureSameStructsCached(nsStyleContext* aOldContext)
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -4,23 +4,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* the interface (to internal code) for retrieving computed style data */
 
 #ifndef _nsStyleContext_h_
 #define _nsStyleContext_h_
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/RestyleLogging.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/ServoUtils.h"
 #include "mozilla/StyleComplexColor.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsStyleSet.h"
 
+class FakeStyleContext;
 class nsIAtom;
 class nsPresContext;
 
 namespace mozilla {
 enum class CSSPseudoElementType : uint8_t;
 class GeckoStyleContext;
 class ServoStyleContext;
 } // namespace mozilla
@@ -338,28 +340,41 @@ public:
   nsChangeHint CalcStyleDifference(nsStyleContext* aNewContext,
                                    uint32_t* aEqualStructs,
                                    uint32_t* aSamePointerStructs);
 
   /**
    * Like the above, but allows comparing ServoComputedValues instead of needing
    * a full-fledged style context.
    */
-  nsChangeHint CalcStyleDifference(RawServoComputedValuesBorrowed aNewValues,
-                                   uint32_t* aEqualStructs,
-                                   uint32_t* aSamePointerStructs);
+  static nsChangeHint CalcStyleDifference(
+      nsStyleContext* aOldSource,
+      RawServoComputedValuesBorrowed aOldValues,
+      RawServoComputedValuesBorrowed aNewValues,
+      uint32_t* aEqualStructs,
+      uint32_t* aSamePointerStructs);
 
 private:
   template<class StyleContextLike>
-  nsChangeHint CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
+  static
+  nsChangeHint CalcStyleDifferenceInternal(StyleContextLike* aOldContext,
+                                           StyleContextLike* aNewContext,
                                            uint32_t* aEqualStructs,
                                            uint32_t* aSamePointerStructs);
 
-  template<typename StyleContextLike>
-  bool EqualCustomProperties(StyleContextLike* aOther);
+  bool EqualCustomProperties(nsStyleContext* aOther);
+
+  static mozilla::Maybe<FakeStyleContext> MakeFakeStyleContext(
+      RawServoComputedValuesBorrowed aValues,
+      nsStyleContext* aSource,
+      FakeStyleContext* aVisitedStyle);
+
+  static mozilla::Maybe<FakeStyleContext> MakeVisitedFakeStyleContext(
+      RawServoComputedValuesBorrowed aValues,
+      nsStyleContext* aSource);
 
 public:
   /**
    * Get a color that depends on link-visitedness using this and
    * this->GetStyleIfVisited().
    *
    * @param aField A pointer to a member variable in a style struct.
    *               The member variable and its style struct must have