Bug 550426 - Add support for {background,mask}-position-{x,y}, StyleAnimation changes. r?dbaron draft
authorMarkus Stange <mstange@themasta.com>
Thu, 21 Apr 2016 20:23:35 -0400
changeset 357909 b9b207a936b8352a420363f0a405bbc90001d52b
parent 357908 ef1e3ce484b4f309a4a3a4d04c9a96e693a1a1bb
child 357910 988b74833e05499f7d23e9a70e4b790f7b8d067f
push id16882
push usermstange@themasta.com
push dateFri, 29 Apr 2016 20:27:29 +0000
reviewersdbaron
bugs550426
milestone49.0a1
Bug 550426 - Add support for {background,mask}-position-{x,y}, StyleAnimation changes. r?dbaron MozReview-Commit-ID: 8Qb0asWMgVA ***
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
layout/style/test/test_transitions_per_property.html
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -444,16 +444,42 @@ CalcPositionSquareDistance(const nsCSSVa
     float difflen = calcVal[i+2].mLength - calcVal[i].mLength;
     float diffpct = calcVal[i+2].mPercent - calcVal[i].mPercent;
     squareDistance += difflen * difflen + diffpct * diffpct;
   }
 
   return squareDistance;
 }
 
+static PixelCalcValue
+CalcBackgroundCoord(const nsCSSValue& aCoord)
+{
+  NS_ASSERTION(aCoord.GetUnit() == eCSSUnit_Array,
+               "Expected array");
+
+  nsCSSValue::Array* array = aCoord.GetArrayValue();
+  MOZ_ASSERT(array->Count() == 2 &&
+             array->Item(0).GetUnit() == eCSSUnit_Null &&
+             array->Item(1).GetUnit() != eCSSUnit_Null,
+             "Invalid position value");
+  return ExtractCalcValue(array->Item(1));
+}
+
+double
+CalcPositionCoordSquareDistance(const nsCSSValue& aPos1,
+                                const nsCSSValue& aPos2)
+{
+  PixelCalcValue calcVal1 = CalcBackgroundCoord(aPos1);
+  PixelCalcValue calcVal2 = CalcBackgroundCoord(aPos2);
+
+  float difflen = calcVal2.mLength - calcVal1.mLength;
+  float diffpct = calcVal2.mPercent - calcVal1.mPercent;
+  return difflen * difflen + diffpct * diffpct;
+}
+
 // CLASS METHODS
 // -------------
 
 bool
 StyleAnimationValue::ComputeDistance(nsCSSProperty aProperty,
                                      const StyleAnimationValue& aStartValue,
                                      const StyleAnimationValue& aEndValue,
                                      double& aDistance)
@@ -839,26 +865,26 @@ StyleAnimationValue::ComputeDistance(nsC
     case eUnit_Shape: {
       return false;
     }
     case eUnit_Filter:
       // FIXME: Support paced animations for filter function interpolation.
     case eUnit_Transform: {
       return false;
     }
-    case eUnit_BackgroundPosition: {
+    case eUnit_BackgroundPositionCoord: {
       const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
       const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
 
       double squareDistance = 0.0;
       MOZ_ASSERT(!position1 == !position2, "lists should be same length");
 
       while (position1 && position2) {
-        squareDistance += CalcPositionSquareDistance(position1->mValue,
-                                                     position2->mValue);
+        squareDistance += CalcPositionCoordSquareDistance(position1->mValue,
+                                                          position2->mValue);
         position1 = position1->mNext;
         position2 = position2->mNext;
       }
       // fail if lists differ in length.
       if (position1 || position2) {
         return false;
       }
 
@@ -2186,16 +2212,36 @@ AddTransformLists(double aCoeff1, const 
   } while (aList1);
   MOZ_ASSERT(!aList2, "list length mismatch");
   MOZ_ASSERT(!*resultTail,
              "resultTail isn't pointing to the tail");
 
   return result.forget();
 }
 
+static void
+AddPositionCoords(double aCoeff1, const nsCSSValue& aPos1,
+                  double aCoeff2, const nsCSSValue& aPos2,
+                  nsCSSValue& aResultPos)
+{
+  const nsCSSValue::Array* posArray1 = aPos1.GetArrayValue();
+  const nsCSSValue::Array* posArray2 = aPos2.GetArrayValue();
+  nsCSSValue::Array* resultPosArray = nsCSSValue::Array::Create(2);
+  aResultPos.SetArrayValue(resultPosArray, eCSSUnit_Array);
+
+  /* Only compute element 1. The <position-coord> is
+   * 'uncomputed' to only that element.
+   */
+  const nsCSSValue& v1 = posArray1->Item(1);
+  const nsCSSValue& v2 = posArray2->Item(1);
+  nsCSSValue& vr = resultPosArray->Item(1);
+  AddCSSValueCanonicalCalc(aCoeff1, v1,
+                           aCoeff2, v2, vr);
+}
+
 bool
 StyleAnimationValue::AddWeighted(nsCSSProperty aProperty,
                                  double aCoeff1,
                                  const StyleAnimationValue& aValue1,
                                  double aCoeff2,
                                  const StyleAnimationValue& aValue2,
                                  StyleAnimationValue& aResultValue)
 {
@@ -2660,40 +2706,40 @@ StyleAnimationValue::AddWeighted(nsCSSPr
             result = AddDifferentTransformLists(aCoeff1, list1, aCoeff2, list2);
           }
         }
       }
 
       aResultValue.SetTransformValue(new nsCSSValueSharedList(result.forget()));
       return true;
     }
-    case eUnit_BackgroundPosition: {
+    case eUnit_BackgroundPositionCoord: {
       const nsCSSValueList *position1 = aValue1.GetCSSValueListValue();
       const nsCSSValueList *position2 = aValue2.GetCSSValueListValue();
       nsAutoPtr<nsCSSValueList> result;
       nsCSSValueList **resultTail = getter_Transfers(result);
       while (position1 && position2) {
         nsCSSValueList *item = new nsCSSValueList;
         *resultTail = item;
         resultTail = &item->mNext;
 
-        AddPositions(aCoeff1, position1->mValue,
-                     aCoeff2, position2->mValue, item->mValue);
+        AddPositionCoords(aCoeff1, position1->mValue,
+                          aCoeff2, position2->mValue, item->mValue);
 
         position1 = position1->mNext;
         position2 = position2->mNext;
       }
 
       // Check for different lengths
       if (position1 || position2) {
         return false;
       }
 
       aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
-                                                eUnit_BackgroundPosition);
+                                                eUnit_BackgroundPositionCoord);
       return true;
     }
     case eUnit_CSSValuePairList: {
       const nsCSSValuePairList *list1 = aValue1.GetCSSValuePairListValue();
       const nsCSSValuePairList *list2 = aValue2.GetCSSValuePairListValue();
       UniquePtr<nsCSSValuePairList> result =
         AddCSSValuePairList(aProperty, aCoeff1, list1, aCoeff2, list2);
       if (!result) {
@@ -3052,17 +3098,17 @@ StyleAnimationValue::UncomputeValue(nsCS
     } break;
     case eUnit_CSSRect: {
       nsCSSRect& rect = aSpecifiedValue.SetRectValue();
       rect = *aComputedValue.GetCSSRectValue();
     } break;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Filter:
-    case eUnit_BackgroundPosition:
+    case eUnit_BackgroundPositionCoord:
       {
         nsCSSValueList* computedList = aComputedValue.GetCSSValueListValue();
         if (computedList) {
           aSpecifiedValue.SetDependentListValue(computedList);
         } else {
           aSpecifiedValue.SetNoneValue();
         }
       }
@@ -3091,17 +3137,17 @@ StyleAnimationValue::UncomputeValue(nsCS
                                     StyleAnimationValue&& aComputedValue,
                                     nsCSSValue& aSpecifiedValue)
 {
   Unit unit = aComputedValue.GetUnit();
   switch (unit) {
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Filter:
-    case eUnit_BackgroundPosition:
+    case eUnit_BackgroundPositionCoord:
       {
         UniquePtr<nsCSSValueList> computedList =
           aComputedValue.TakeCSSValueListValue();
         if (computedList) {
           aSpecifiedValue.AdoptListValue(Move(computedList));
         } else {
           aSpecifiedValue.SetNoneValue();
         }
@@ -3271,16 +3317,33 @@ SetPositionValue(const nsStyleImageLayer
   // we'll just have a normalized "x,y" position, with no edge names needed.
   nsCSSValue& xValue = posArray->Item(1);
   nsCSSValue& yValue = posArray->Item(3);
 
   SetCalcValue(&aPos.mXPosition, xValue);
   SetCalcValue(&aPos.mYPosition, yValue);
 }
 
+static void
+SetPositionCoordValue(const nsStyleImageLayers::Position::PositionCoord& aPosCoord,
+                      nsCSSValue& aCSSValue)
+{
+  RefPtr<nsCSSValue::Array> posArray = nsCSSValue::Array::Create(2);
+  aCSSValue.SetArrayValue(posArray.get(), eCSSUnit_Array);
+
+  // NOTE: Array entry #0 here is intentionally left untouched, with
+  // eCSSUnit_Null.  The purpose of this entry in our specified-style
+  // <position-coord> representation is to store edge names.  But for values
+  // extracted from computed style (which is what we're dealing with here),
+  // we'll just have a normalized "x"/"y" position, with no edge names needed.
+  nsCSSValue& value = posArray->Item(1);
+
+  SetCalcValue(&aPosCoord, value);
+}
+
 /*
  * Assign |aOutput = aInput|, except with any non-pixel lengths
  * replaced with the equivalent in pixels, and any non-canonical calc()
  * expressions replaced with canonical ones.
  */
 static void
 SubstitutePixelValues(nsStyleContext* aStyleContext,
                       const nsCSSValue& aInput, nsCSSValue& aOutput)
@@ -3314,32 +3377,53 @@ SubstitutePixelValues(nsStyleContext* aS
     aOutput.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(len),
                           eCSSUnit_Pixel);
   } else {
     aOutput = aInput;
   }
 }
 
 static void
-ExtractImageLayerPositionList(const nsStyleImageLayers& aLayer,
-                              StyleAnimationValue& aComputedValue)
+ExtractImageLayerPositionXList(const nsStyleImageLayers& aLayer,
+                               StyleAnimationValue& aComputedValue)
 {
-  MOZ_ASSERT(aLayer.mPositionCount > 0, "unexpected count");
+  MOZ_ASSERT(aLayer.mPositionXCount > 0, "unexpected count");
 
   nsAutoPtr<nsCSSValueList> result;
   nsCSSValueList **resultTail = getter_Transfers(result);
-  for (uint32_t i = 0, i_end = aLayer.mPositionCount; i != i_end; ++i) {
+  for (uint32_t i = 0, i_end = aLayer.mPositionXCount; i != i_end; ++i) {
     nsCSSValueList *item = new nsCSSValueList;
     *resultTail = item;
     resultTail = &item->mNext;
-    SetPositionValue(aLayer.mLayers[i].mPosition, item->mValue);
+    SetPositionCoordValue(aLayer.mLayers[i].mPosition.mXPosition,
+                          item->mValue);
   }
 
   aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
-    StyleAnimationValue::eUnit_BackgroundPosition);
+    StyleAnimationValue::eUnit_BackgroundPositionCoord);
+}
+
+static void
+ExtractImageLayerPositionYList(const nsStyleImageLayers& aLayer,
+                               StyleAnimationValue& aComputedValue)
+{
+  MOZ_ASSERT(aLayer.mPositionYCount > 0, "unexpected count");
+
+  nsAutoPtr<nsCSSValueList> result;
+  nsCSSValueList **resultTail = getter_Transfers(result);
+  for (uint32_t i = 0, i_end = aLayer.mPositionYCount; i != i_end; ++i) {
+    nsCSSValueList *item = new nsCSSValueList;
+    *resultTail = item;
+    resultTail = &item->mNext;
+    SetPositionCoordValue(aLayer.mLayers[i].mPosition.mYPosition,
+                          item->mValue);
+  }
+
+  aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
+    StyleAnimationValue::eUnit_BackgroundPositionCoord);
 }
 
 static void
 ExtractImageLayerSizePairList(const nsStyleImageLayers& aLayer,
                               StyleAnimationValue& aComputedValue)
 {
   MOZ_ASSERT(aLayer.mSizeCount > 0, "unexpected count");
 
@@ -3816,27 +3900,44 @@ StyleAnimationValue::ExtractComputedValu
           nsAutoPtr<nsCSSValue> val(new nsCSSValue);
           SetPositionValue(stylePos->mObjectPosition, *val);
 
           aComputedValue.SetAndAdoptCSSValueValue(val.forget(),
                                                   eUnit_ObjectPosition);
           break;
         }
 
-        case eCSSProperty_background_position: {
+        case eCSSProperty_background_position_x: {
           const nsStyleImageLayers& layers =
             static_cast<const nsStyleBackground*>(styleStruct)->mImage;
-          ExtractImageLayerPositionList(layers, aComputedValue);
+          ExtractImageLayerPositionXList(layers, aComputedValue);
           break;
         }
+        case eCSSProperty_background_position_y: {
+          const nsStyleImageLayers& layers =
+            static_cast<const nsStyleBackground*>(styleStruct)->mImage;
+          ExtractImageLayerPositionYList(layers, aComputedValue);
+          break;
+
+
+
+
+        }
 #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
-        case eCSSProperty_mask_position: {
+        case eCSSProperty_mask_position_x: {
           const nsStyleImageLayers& layers =
             static_cast<const nsStyleSVGReset*>(styleStruct)->mMask;
-          ExtractImageLayerPositionList(layers, aComputedValue);
+          ExtractImageLayerPositionXList(layers, aComputedValue);
+          break;
+        }
+        case eCSSProperty_mask_position_y: {
+          const nsStyleImageLayers& layers =
+            static_cast<const nsStyleSVGReset*>(styleStruct)->mMask;
+          ExtractImageLayerPositionYList(layers, aComputedValue);
+
           break;
         }
 #endif
         case eCSSProperty_background_size: {
           const nsStyleImageLayers& layers =
             static_cast<const nsStyleBackground*>(styleStruct)->mImage;
           ExtractImageLayerSizePairList(layers, aComputedValue);
           break;
@@ -4243,17 +4344,17 @@ StyleAnimationValue::operator=(const Sty
       break;
     case eUnit_CSSRect:
       MOZ_ASSERT(aOther.mValue.mCSSRect, "rects may not be null");
       mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
       break;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Filter:
-    case eUnit_BackgroundPosition:
+    case eUnit_BackgroundPositionCoord:
       MOZ_ASSERT(mUnit == eUnit_Shadow || mUnit == eUnit_Filter ||
                  aOther.mValue.mCSSValueList,
                  "value lists other than shadows and filters may not be null");
       if (aOther.mValue.mCSSValueList) {
         mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone();
       } else {
         mValue.mCSSValueList = nullptr;
       }
@@ -4507,17 +4608,17 @@ StyleAnimationValue::operator==(const St
       return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
     case eUnit_CSSValueTriplet:
       return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet;
     case eUnit_CSSRect:
       return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Filter:
-    case eUnit_BackgroundPosition:
+    case eUnit_BackgroundPositionCoord:
       return nsCSSValueList::Equal(mValue.mCSSValueList,
                                    aOther.mValue.mCSSValueList);
     case eUnit_Shape:
       return *mValue.mCSSValueArray == *aOther.mValue.mCSSValueArray;
     case eUnit_Transform:
       return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList;
     case eUnit_CSSValuePairList:
       return nsCSSValuePairList::Equal(mValue.mCSSValuePairList,
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -280,17 +280,17 @@ public:
     eUnit_CSSValuePair, // nsCSSValuePair* (never null)
     eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
     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_BackgroundPosition, // nsCSSValueList* (never null)
+    eUnit_BackgroundPositionCoord, // nsCSSValueList* (never null)
     eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
     eUnit_UnparsedString // nsStringBuffer* (never null)
   };
 
 private:
   Unit mUnit;
   union {
     int32_t mInt;
@@ -481,17 +481,17 @@ private:
     return aUnit == eUnit_CSSRect;
   }
   static bool IsCSSValueArrayUnit(Unit aUnit) {
     return aUnit == eUnit_Shape;
   }
   static bool IsCSSValueListUnit(Unit aUnit) {
     return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter ||
            aUnit == eUnit_Shadow ||
-           aUnit == eUnit_BackgroundPosition;
+           aUnit == eUnit_BackgroundPositionCoord;
   }
   static bool IsCSSValueSharedListValue(Unit aUnit) {
     return aUnit == eUnit_Transform;
   }
   static bool IsCSSValuePairListUnit(Unit aUnit) {
     return aUnit == eUnit_CSSValuePairList;
   }
   static bool IsStringUnit(Unit aUnit) {
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -277,16 +277,30 @@ var supported_properties = {
 };
 
 if (SupportsMaskShorthand()) {
   supported_properties["mask-position"] = [ test_background_position_transition,
                                      // FIXME: We don't currently test clamping,
                                      // since mask-position uses calc() as
                                      // an intermediate form.
                                      /* test_length_percent_pair_unclamped */ ];
+  supported_properties["mask-position-x"] = [ test_background_position_coord_transition,
+                                              test_length_transition,
+                                              test_percent_transition,
+                                            // FIXME: We don't currently test clamping,
+                                            // since background-position-x uses calc() as
+                                            // an intermediate form.
+                                            /* test_length_percent_pair_unclamped */ ];
+  supported_properties["mask-position-y"] = [ test_background_position_coord_transition,
+                                              test_length_transition,
+                                              test_percent_transition,
+                                            // FIXME: We don't currently test clamping,
+                                            // since background-position-y uses calc() as
+                                            // an intermediate form.
+                                            /* test_length_percent_pair_unclamped */ ];
   supported_properties["mask-size"] = [ test_background_size_transition,
                                      // FIXME: We don't currently test clamping,
                                      // since mask-size uses calc() as an
                                      // intermediate form.
                                      /* test_length_percent_pair_clamped */ ];
 }
 
 var div = document.getElementById("display");