Bug 1273706 - Part 7: Add support to StyleAnimationValues for storing lists of values. r?heycam draft
authorJonathan Chan <jyc@eqv.io>
Thu, 18 Aug 2016 13:25:31 -0700
changeset 402896 34404ba89f84f6d2e77ccb079117ee11824202a5
parent 402895 16d66cf7b281e2ca1c4764a28d2c962593693039
child 402897 c3e7cd099dc0483ad1d490796b54a72b823294f9
push id26775
push userjchan@mozilla.com
push dateThu, 18 Aug 2016 22:38:41 +0000
reviewersheycam
bugs1273706
milestone51.0a1
Bug 1273706 - Part 7: Add support to StyleAnimationValues for storing lists of values. r?heycam The lists are homogeneous lists of style animation values. We also implement computing distances & interpolating between them. The lists are simple lists, not repeatable lists. [1] This is for support of custom properties with syntax like <number>+, which indicates a list of <number>s with length at least one. Currently the syntax only supports homogeneous non-empty list. [1]: https://github.com/w3c/css-houdini-drafts/issues/273 MozReview-Commit-ID: 6DHgXxwpgVl
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -945,16 +945,35 @@ StyleAnimationValue::ComputeDistance(nsC
       } while (list1 && list2);
       if (list1 || list2) {
         // We can't interpolate lists of different lengths.
         return false;
       }
       aDistance = sqrt(squareDistance);
       return true;
     }
+    case eUnit_List: {
+      const nsTArray<StyleAnimationValue>* start = aStartValue.mValue.mList;
+      const nsTArray<StyleAnimationValue>* end = aEndValue.mValue.mList;
+      if (start->Length() != end->Length()) {
+        // These are simple lists, not repeatable lists.
+        return false;
+      }
+      double dist2 = 0;
+      for (size_t i = 0; i < start->Length(); i++) {
+        double d = 0;
+        if (!ComputeDistance(aProperty, (*start)[i], (*end)[i], d)) {
+          return false;
+        }
+        // We square the component distances just like we do above.
+        dist2 += d * d;
+      }
+      aDistance = sqrt(dist2);
+      return true;
+    }
   }
 
   MOZ_ASSERT(false, "Can't compute distance using the given common unit");
   return false;
 }
 
 #define MAX_PACKED_COLOR_COMPONENT 255
 
@@ -2741,16 +2760,36 @@ StyleAnimationValue::AddWeighted(nsCSSPr
       UniquePtr<nsCSSValuePairList> result =
         AddCSSValuePairList(aProperty, aCoeff1, list1, aCoeff2, list2);
       if (!result) {
         return false;
       }
       aResultValue.SetAndAdoptCSSValuePairListValue(result.release());
       return true;
     }
+    case eUnit_List: {
+      const nsTArray<StyleAnimationValue>* start = aValue1.mValue.mList;
+      const nsTArray<StyleAnimationValue>* end = aValue2.mValue.mList;
+      if (start->Length() != end->Length()) {
+        // These are simple lists, not repeatable lists.
+        return false;
+      }
+      UniquePtr<nsTArray<StyleAnimationValue>> result
+        (new nsTArray<StyleAnimationValue>(start->Length()));
+      for (size_t i = 0; i < start->Length(); i++) {
+        StyleAnimationValue val;
+        if (!AddWeighted(aProperty, aCoeff1, (*start)[i], aCoeff2, (*end)[i],
+                         val)) {
+          return false;
+        }
+        result->AppendElement(Move(val));
+      }
+      aResultValue.SetAndAdoptListValue(Move(result));
+      return true;
+    }
   }
 
   MOZ_ASSERT(false, "Can't interpolate using the given common unit");
   return false;
 }
 
 already_AddRefed<css::StyleRule>
 BuildStyleRule(nsCSSPropertyID aProperty,
@@ -3119,16 +3158,32 @@ StyleAnimationValue::UncomputeValue(nsCS
     case eUnit_Transform:
       aSpecifiedValue.
         SetSharedListValue(aComputedValue.GetCSSValueSharedListValue());
       break;
     case eUnit_CSSValuePairList:
       aSpecifiedValue.
         SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
       break;
+    case eUnit_List: {
+      nsCSSValueList* toList = aSpecifiedValue.SetListValue();
+      const nsTArray<StyleAnimationValue>* fromList =
+        aComputedValue.mValue.mList;
+      for (size_t i = 0; i < fromList->Length(); i++) {
+        const StyleAnimationValue& term = (*fromList)[i];
+        nsCSSValue value;
+        StyleAnimationValue::UncomputeValue(eCSSProperty_UNKNOWN, term, value);
+        toList->mValue = value;
+        if (i != fromList->Length() - 1) {
+          toList->mNext = new nsCSSValueList;
+          toList = toList->mNext;
+        }
+      }
+      break;
+    }
     default:
       return false;
   }
   return true;
 }
 
 bool
 StyleAnimationValue::UncomputeValue(nsCSSPropertyID aProperty,
@@ -4362,16 +4417,20 @@ StyleAnimationValue::operator=(const Sty
                  "value pair lists may not be null");
       mValue.mCSSValuePairList = aOther.mValue.mCSSValuePairList->Clone();
       break;
     case eUnit_UnparsedString:
       MOZ_ASSERT(aOther.mValue.mString, "expecting non-null string");
       mValue.mString = aOther.mValue.mString;
       mValue.mString->AddRef();
       break;
+    case eUnit_List:
+      MOZ_ASSERT(aOther.mValue.mList, "lists may not be null");
+      mValue.mList = new nsTArray<StyleAnimationValue>(*aOther.mValue.mList);
+      break;
   }
 
   return *this;
 }
 
 void
 StyleAnimationValue::SetNormalValue()
 {
@@ -4503,16 +4562,28 @@ StyleAnimationValue::SetCSSValueArrayVal
   MOZ_ASSERT(aValue != nullptr,
              "not currently expecting any arrays to be null");
   mUnit = aUnit;
   mValue.mCSSValueArray = aValue;
   mValue.mCSSValueArray->AddRef();
 }
 
 void
+StyleAnimationValue::SetAndAdoptListValue(UniquePtr<nsTArray<StyleAnimationValue>> aList)
+{
+  MOZ_ASSERT(aList, "lists may not be null");
+  FreeValue();
+  MOZ_ASSERT(aList->Length() >= 1,
+             "These should only be created for custom properties, whose syntax "
+             "only allows at least one element in lists.");
+  mUnit = eUnit_List;
+  mValue.mList = aList.release();
+}
+
+void
 StyleAnimationValue::SetAndAdoptCSSValueListValue(nsCSSValueList *aValueList,
                                                   Unit aUnit)
 {
   FreeValue();
   MOZ_ASSERT(IsCSSValueListUnit(aUnit), "bad unit");
   MOZ_ASSERT(aUnit == eUnit_Shadow || aUnit == eUnit_Filter ||
              aValueList != nullptr,
              "value lists other than shadows and filters may not be null");
@@ -4556,16 +4627,18 @@ StyleAnimationValue::FreeValue()
     delete mValue.mCSSRect;
   } else if (IsCSSValuePairListUnit(mUnit)) {
     delete mValue.mCSSValuePairList;
   } else if (IsCSSValueArrayUnit(mUnit)) {
     mValue.mCSSValueArray->Release();
   } else if (IsStringUnit(mUnit)) {
     MOZ_ASSERT(mValue.mString, "expecting non-null string");
     mValue.mString->Release();
+  } else if (mUnit == eUnit_List) {
+    delete mValue.mList;
   }
 }
 
 bool
 StyleAnimationValue::operator==(const StyleAnimationValue& aOther) const
 {
   if (mUnit != aOther.mUnit) {
     return false;
@@ -4612,13 +4685,15 @@ StyleAnimationValue::operator==(const St
     case eUnit_Transform:
       return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList;
     case eUnit_CSSValuePairList:
       return nsCSSValuePairList::Equal(mValue.mCSSValuePairList,
                                        aOther.mValue.mCSSValuePairList);
     case eUnit_UnparsedString:
       return (NS_strcmp(GetStringBufferValue(),
                         aOther.GetStringBufferValue()) == 0);
+    case eUnit_List:
+      return *mValue.mList == *aOther.mValue.mList;
   }
 
   NS_NOTREACHED("incomplete case");
   return false;
 }
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -11,16 +11,17 @@
 #include "mozilla/gfx/MatrixFwd.h"
 #include "mozilla/UniquePtr.h"
 #include "nsStringFwd.h"
 #include "nsStringBuffer.h"
 #include "nsCoord.h"
 #include "nsColor.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
+#include "nsTArray.h"
 
 class nsIFrame;
 class nsStyleContext;
 class gfx3DMatrix;
 
 namespace mozilla {
 
 namespace css {
@@ -282,17 +283,21 @@ public:
     eUnit_CSSRect, // nsCSSRect* (never null)
     eUnit_Dasharray, // nsCSSValueList* (never null)
     eUnit_Shadow, // nsCSSValueList* (may be null)
     eUnit_Shape,  // nsCSSValue::Array* (never null)
     eUnit_Filter, // nsCSSValueList* (may be null)
     eUnit_Transform, // nsCSSValueList* (never null)
     eUnit_BackgroundPositionCoord, // nsCSSValueList* (never null)
     eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
-    eUnit_UnparsedString // nsStringBuffer* (never null)
+    eUnit_UnparsedString, // nsStringBuffer* (never null)
+    eUnit_List, // nsTArray<StyleAnimationValue>* (never null)
+                // Currently only used for custom props! Length >= 1.
+                // All StyleAnimationValues in the list must have the same
+                // simple type (not a list or other compound value).
   };
 
 private:
   Unit mUnit;
   union {
     int32_t mInt;
     nscoord mCoord;
     float mFloat;
@@ -301,16 +306,17 @@ private:
     nsCSSValuePair* mCSSValuePair;
     nsCSSValueTriplet* mCSSValueTriplet;
     nsCSSRect* mCSSRect;
     nsCSSValue::Array* mCSSValueArray;
     nsCSSValueList* mCSSValueList;
     nsCSSValueSharedList* mCSSValueSharedList;
     nsCSSValuePairList* mCSSValuePairList;
     nsStringBuffer* mString;
+    nsTArray<StyleAnimationValue>* mList;
   } mValue;
 
 public:
   Unit GetUnit() const {
     NS_ASSERTION(mUnit != eUnit_Null, "uninitialized");
     return mUnit;
   }
 
@@ -371,16 +377,20 @@ public:
   nsCSSValuePairList* GetCSSValuePairListValue() const {
     NS_ASSERTION(IsCSSValuePairListUnit(mUnit), "unit mismatch");
     return mValue.mCSSValuePairList;
   }
   const char16_t* GetStringBufferValue() const {
     NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch");
     return GetBufferValue(mValue.mString);
   }
+  nsTArray<StyleAnimationValue>* GetListValue() const {
+    NS_ASSERTION(mUnit == eUnit_List, "unit mismatch");
+    return mValue.mList;
+  }
 
   void GetStringValue(nsAString& aBuffer) const {
     NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch");
     aBuffer.Truncate();
     uint32_t len = NS_strlen(GetBufferValue(mValue.mString));
     mValue.mString->ToString(len, aBuffer);
   }
 
@@ -449,16 +459,17 @@ public:
   // These setters take ownership of |aValue|, and are therefore named
   // "SetAndAdopt*".
   void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit);
   void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
   void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit);
   void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit);
   void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit);
   void SetAndAdoptCSSValuePairListValue(nsCSSValuePairList *aValue);
+  void SetAndAdoptListValue(UniquePtr<nsTArray<StyleAnimationValue>> aList);
 
   void SetTransformValue(nsCSSValueSharedList* aList);
 
   StyleAnimationValue& operator=(const StyleAnimationValue& aOther);
 
   bool operator==(const StyleAnimationValue& aOther) const;
   bool operator!=(const StyleAnimationValue& aOther) const
     { return !(*this == aOther); }