Bug 1244590 - Part 12: Revise ComputeDistance. draft
authorBoris Chiou <boris.chiou@gmail.com>
Sat, 21 May 2016 19:04:55 +0800
changeset 369287 da5e7ba24fce1c2c7c188db5dcf5c74451bc9876
parent 369286 e4ddd129d7ad7258c411918fee59d375e5f70698
child 369288 4a55d9b857efa3fbd8d2e423d8ef532de8cad463
push id18826
push userbmo:boris.chiou@gmail.com
push dateSat, 21 May 2016 11:25:24 +0000
bugs1244590
milestone49.0a1
Bug 1244590 - Part 12: Revise ComputeDistance. MozReview-Commit-ID: J8d442aJP6O
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeUtils.cpp
dom/animation/KeyframeUtils.h
dom/base/nsDOMWindowUtils.cpp
dom/smil/nsSMILCSSValueType.cpp
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -572,17 +572,18 @@ KeyframeEffectReadOnly::UpdateProperties
                                               aStyleContext);
 
     if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
       // Cache the paced property and its StyleAnimationValues, so we don't have
       // to search them each time.
       UpdateKeyframePacedPropertyAnimValue(mKeyframes, keyframeAnimValues,
                                            mEffectOptions.mPacedProperty);
       KeyframeUtils::ApplySpacing(mKeyframes, SpacingMode::paced,
-                                  mEffectOptions.mPacedProperty);
+                                  mEffectOptions.mPacedProperty,
+                                  mTarget->mElement);
     }
 
     properties =
       KeyframeUtils::GetAnimationPropertiesFromKeyframes(mKeyframes,
                                                          keyframeAnimValues);
   }
 
   if (mProperties == properties) {
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -387,17 +387,18 @@ RequiresAdditiveAnimation(const nsTArray
                           nsIDocument* aDocument);
 
 static void
 ApplyDistributingOffset(const Range<Keyframe>& aDistributeRange,
                         size_t aPacedA = 0, size_t aPacedB = 0);
 
 static void
 ApplyPacedOffset(const Range<Keyframe>& aPaceRange,
-                 nsCSSProperty aProperty);
+                 nsCSSProperty aProperty,
+                 dom::Element* aElement);
 
 // ------------------------------------------------------------------
 //
 // Public API
 //
 // ------------------------------------------------------------------
 
 /* static */ nsTArray<Keyframe>
@@ -456,17 +457,18 @@ KeyframeUtils::GetKeyframesFromObject(JS
   }
 
   return keyframes;
 }
 
 /* static */ void
 KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
                             SpacingMode aSpacingMode,
-                            nsCSSProperty aProperty)
+                            nsCSSProperty aProperty,
+                            dom::Element* aElement)
 {
   if (aKeyframes.IsEmpty()) {
     return;
   }
 
   // Reset the computed offsets if using paced spacing.
   if (aSpacingMode == SpacingMode::paced) {
     for (Keyframe& keyframe : aKeyframes) {
@@ -517,17 +519,17 @@ KeyframeUtils::ApplySpacing(nsTArray<Key
         pA = pB = j;
       }
       // b) Apply evenly distributing offsets in (A, Paced A] and [Paced B, B).
       //    We should use relative indexes here, so pA - i and pB - i.
       ApplyDistributingOffset(Range<Keyframe>(&aKeyframes[i], j - i + 1),
                               pA - i, pB - i);
       // c) Apply paced offsets in (Paced A, Paced B).
       ApplyPacedOffset(Range<Keyframe>(&aKeyframes[pA], pB - pA + 1),
-                       aProperty);
+                       aProperty, aElement);
       // d) Fill null computed offsets in (Paced A, Paced B).
       for (size_t k = pA + 1; k < pB; ++k) {
         if (aKeyframes[k].mComputedOffset != -1.0) {
           continue;
         }
 
         size_t startIdx = k - 1;
         size_t endIdx = k + 1;
@@ -1311,17 +1313,18 @@ ApplyDistributingOffset(const Range<Keyf
  * Apply paced computed offsets in (Paced A, Paced B). We need the target
  * element and its style context to calculate the StyleAnimationValue.
  *
  * @param aPaceRange The set of keyframes in [Paced A, Paced B].
  * @param aProperty The paced property. (default eCSSProperty_UNKNOWN)
  */
 static void
 ApplyPacedOffset(const Range<Keyframe>& aPaceRange,
-                 nsCSSProperty aProperty)
+                 nsCSSProperty aProperty,
+                 dom::Element* aElement)
 {
   const size_t len = aPaceRange.length();
   if (len < 3) {
     // No space to fill.
     return;
   }
 
   const size_t pacedA = 0;
@@ -1366,17 +1369,18 @@ ApplyPacedOffset(const Range<Keyframe>& 
         const StyleAnimationValue& preValue = prePairs[subIdx].mValue;
         const StyleAnimationValue& curValue = curPairs[subIdx].mValue;
         nsCSSProperty subProperty = prePairs[subIdx].mProperty;
         MOZ_ASSERT(curPairs[subIdx].mProperty == subProperty,
                    "subProperty mismatch");
 
         double componentDist = 0.0;
         if (!StyleAnimationValue::ComputeDistance(subProperty, preValue,
-                                                  curValue, componentDist)) {
+                                                  curValue, aElement,
+                                                  componentDist)) {
           failed = true;
           break;
         }
         // debug
         /*{
           nsCString debug = nsCSSProps::GetStringValue(subProperty);
           printf_stderr("[Boris] pair(%zu, %zu): distance of [%s] is %lf\n",
               preIdx, i,
@@ -1401,23 +1405,49 @@ ApplyPacedOffset(const Range<Keyframe>& 
       // Note: IsPaceable() means mPacedPropertyAnimValue is not empty. If the
       // paced property is longhand, we just use the 1st value (index 0).
       const StyleAnimationValue& preValue =
         aPaceRange[preIdx].mPacedPropertyAnimValue[0].mValue;
       const StyleAnimationValue& curValue =
         aPaceRange[i].mPacedPropertyAnimValue[0].mValue;
 
       if (!StyleAnimationValue::ComputeDistance(aProperty, preValue,
-                                                curValue, dist)) {
+                                                curValue, aElement,
+                                                dist)) {
         failed = true;
         break;
       }
+
+      // debug
+      {
+        if (preValue.GetUnit() == StyleAnimationValue::eUnit_Coord) {
+          printf_stderr("[Boris] StyleAnimationValue[%zu] is: %lf\n",
+              preIdx, (double)preValue.GetCoordValue());
+        } else {
+          printf_stderr("[Boris] StyleAnimationValue[%zu] is unit: %d\n",
+              preIdx, preValue.GetUnit());
+        }
+
+        if (curValue.GetUnit() == StyleAnimationValue::eUnit_Coord) {
+          printf_stderr("[Boris] StyleAnimationValue[%zu] is: %lf\n",
+            i, (double)curValue.GetCoordValue());
+        } else {
+          printf_stderr("[Boris] StyleAnimationValue[%zu] is unit: %d\n",
+            i, curValue.GetUnit());
+        }
+        nsCString debug = nsCSSProps::GetStringValue(aProperty);
+        printf_stderr("[Boris] pair(%zu, %zu): distance of [%s] is %lf\n",
+            preIdx, i, debug.get(), dist);
+      }
     }
 
     cumulativeDist[i] = cumulativeDist[i - 1] + dist;
+    printf_stderr("[Boris] cumulativeDist[%zu] = %lf + %lf = %lf\n",
+        i, cumulativeDist[i-1], dist, cumulativeDist[i]);
+
     preIdx = i;
   }
 
   if (failed || cumulativeDist[len - 1] == 0.0) {
     return;
   }
 
   // b) Apply computed offset.
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -77,17 +77,18 @@ public:
    * http://w3c.github.io/web-animations/#spacing-keyframes
    *
    * @param aKeyframes The set of keyframes to adjust.
    * @param aSpacingMode The applied spacing mode to aKeyframes.
    */
   static void
   ApplySpacing(nsTArray<Keyframe>& aKeyframes,
                SpacingMode aSpacingMode,
-               nsCSSProperty aProperty = eCSSProperty_UNKNOWN);
+               nsCSSProperty aProperty = eCSSProperty_UNKNOWN,
+               dom::Element* aElement = nullptr);
 
   /**
    * Converts an array of Keyframe objects into an array of AnimationProperty
    * objects. This involves expanding shorthand properties into longhand
    * properties, creating an array of computed values for each longhand
    * property and determining the offset and timing function to use for each
    * value.
    *
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2531,17 +2531,18 @@ nsDOMWindowUtils::ComputeAnimationDistan
 
   StyleAnimationValue v1, v2;
   if (property == eCSSProperty_UNKNOWN ||
       !ComputeAnimationValue(property, content->AsElement(), aValue1, v1) ||
       !ComputeAnimationValue(property, content->AsElement(), aValue2, v2)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  if (!StyleAnimationValue::ComputeDistance(property, v1, v2, *aResult)) {
+  if (!StyleAnimationValue::ComputeDistance(property, v1, v2, nullptr,
+                                            *aResult)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -273,16 +273,17 @@ nsSMILCSSValueType::ComputeDistance(cons
     &fromWrapper->mCSSValue : nullptr;
   const StyleAnimationValue* toCSSValue = &toWrapper->mCSSValue;
   if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
     return NS_ERROR_FAILURE;
   }
 
   return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
                                               *fromCSSValue, *toCSSValue,
+                                              nullptr,
                                               aDistance) ?
     NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
                                 const nsSMILValue& aEndVal,
                                 double aUnitDistance,
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -26,16 +26,18 @@
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "gfxMatrix.h"
 #include "gfxQuaternion.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "gfx2DGlue.h"
 
+#include "nsROCSSPrimitiveValue.h"
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 // HELPER METHODS
 // --------------
 /*
  * Given two units, this method returns a common unit that they can both be
  * converted into, if possible.  This is intended to facilitate
@@ -470,27 +472,144 @@ CalcPositionCoordSquareDistance(const ns
   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;
 }
 
+bool
+GetContainingBlockFloatValue(const nsAString& aProperty,
+                             dom::Element* aElement,
+                             double& aResult)
+{
+  dom::Element* parentElement = aElement->GetParentElement();
+  if (!parentElement) {
+    return false;
+  }
+  nsIDocument* doc = parentElement->GetUncomposedDoc();
+  if (!doc) {
+    return false;
+  }
+  RefPtr<nsComputedDOMStyle> style =
+    NS_NewComputedDOMStyle(parentElement, EmptyString(), doc->GetShell());
+  if (!style) {
+    return false;
+  }
+  ErrorResult rv;
+  RefPtr<dom::CSSValue> cssValue = style->GetPropertyCSSValue(aProperty, rv);
+  if (rv.Failed()) {
+    return false;
+  }
+  nsROCSSPrimitiveValue* value = cssValue->AsPrimitiveValue();
+
+  if (value &&
+      value->PrimitiveType() == nsIDOMCSSPrimitiveValue::CSS_PX) {
+    aResult = (double)value->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_PX, rv);
+    if (rv.Failed()) {
+      return false;
+    }
+  } else {
+    return false;
+  }
+
+  { // debug
+    NS_ConvertUTF16toUTF8 debug(aProperty);
+    printf_stderr("[Boris] get parent %s value: %lf\n",
+        debug.get(), aResult);
+  }
+  return true;
+}
+
+bool
+CalculateCalcValue(nsCSSProperty aProperty,
+                   const StyleAnimationValue& aValue,
+                   dom::Element* aElement,
+                   double& aResult)
+{
+  printf_stderr("[Boris] CalcualteCalcValue\n");
+
+  if (aValue.GetUnit() == StyleAnimationValue::eUnit_Coord) {
+    aResult = (double)aValue.GetCoordValue();
+    return true;
+  }
+
+  if (aValue.GetUnit() != StyleAnimationValue::eUnit_Percent &&
+      aValue.GetUnit() != StyleAnimationValue::eUnit_Calc) {
+    return false;
+  }
+
+  double length = 0.0;
+  double percent = 0.0;
+  if (aValue.GetUnit() == StyleAnimationValue::eUnit_Percent) {
+    percent = aValue.GetPercentValue();
+  } else {
+    nsCSSValue *val = aValue.GetCSSValueValue();
+    PixelCalcValue pValue = ExtractCalcValueInternal(*val);
+    length = pValue.mLength;
+    percent = pValue.mPercent;
+  }
+
+  if (!aElement || nsCSSProps::IsShorthand(aProperty)) {
+    return false;
+  }
+
+  double base = 0.0;
+  switch (aProperty) {
+    case eCSSProperty_width:
+    case eCSSProperty_left:
+    case eCSSProperty_right:
+    case eCSSProperty_margin_left:
+    case eCSSProperty_margin_right:
+    case eCSSProperty_padding_left:
+    case eCSSProperty_padding_right:
+      if (!GetContainingBlockFloatValue(NS_LITERAL_STRING("width"),
+                                        aElement, base)) {
+        return false;
+      }
+    break;
+
+    case eCSSProperty_height:
+    case eCSSProperty_top:
+    case eCSSProperty_bottom:
+    case eCSSProperty_margin_top:
+    case eCSSProperty_margin_bottom:
+    case eCSSProperty_padding_top:
+    case eCSSProperty_padding_bottom:
+      if (!GetContainingBlockFloatValue(NS_LITERAL_STRING("height"),
+                                        aElement, base)) {
+        return false;
+      }
+    break;;
+
+    default:
+      // Not supported yet.
+      return false;
+  }
+
+  aResult = length +
+            percent * (double)nsPresContext::CSSPixelsToAppUnits((float)base);
+  return true;
+}
+
 // CLASS METHODS
 // -------------
 
 bool
 StyleAnimationValue::ComputeDistance(nsCSSProperty aProperty,
                                      const StyleAnimationValue& aStartValue,
                                      const StyleAnimationValue& aEndValue,
+                                     dom::Element* aElement,
                                      double& aDistance)
 {
   Unit commonUnit =
     GetCommonUnit(aProperty, aStartValue.GetUnit(), aEndValue.GetUnit());
+  printf_stderr("[Boris] common unit: %d\n", (int)commonUnit);
+
 
   switch (commonUnit) {
     case eUnit_Null:
     case eUnit_Auto:
     case eUnit_None:
     case eUnit_Normal:
     case eUnit_UnparsedString:
     case eUnit_URL:
@@ -580,16 +699,26 @@ StyleAnimationValue::ComputeDistance(nsC
       double diffR = startR - endR;
       double diffG = startG - endG;
       double diffB = startB - endB;
       aDistance = sqrt(diffA * diffA + diffR * diffR +
                        diffG * diffG + diffB * diffB);
       return true;
     }
     case eUnit_Calc: {
+      if (aElement) {
+        double v1 = 0.0;
+        double v2 = 0.0;
+        if (CalculateCalcValue(aProperty, aStartValue, aElement, v1) &&
+            CalculateCalcValue(aProperty, aEndValue, aElement, v2)) {
+          aDistance = Abs(v2 - v1);
+          return true;
+        }
+      }
+
       PixelCalcValue v1 = ExtractCalcValue(aStartValue);
       PixelCalcValue v2 = ExtractCalcValue(aEndValue);
       float difflen = v2.mLength - v1.mLength;
       float diffpct = v2.mPercent - v1.mPercent;
       aDistance = sqrt(difflen * difflen + diffpct * diffpct);
       return true;
     }
     case eUnit_ObjectPosition: {
@@ -844,16 +973,17 @@ StyleAnimationValue::ComputeDistance(nsC
             (color2.GetColorValue(), StyleAnimationValue::ColorConstructor);
           double colorDistance;
 
         #ifdef DEBUG
           bool ok =
         #endif
             StyleAnimationValue::ComputeDistance(eCSSProperty_color,
                                                  color1Value, color2Value,
+                                                 nullptr,
                                                  colorDistance);
           MOZ_ASSERT(ok, "should not fail");
           squareDistance += colorDistance * colorDistance;
         }
 
         shadow1 = shadow1->mNext;
         shadow2 = shadow2->mNext;
         MOZ_ASSERT(!shadow1 == !shadow2, "lists should be same length");
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -68,22 +68,24 @@ public:
    *
    * If this method succeeds, the returned distance value is guaranteed to be
    * non-negative.
    *
    * @param aStartValue The start of the interval for which the distance
    *                    should be calculated.
    * @param aEndValue   The end of the interval for which the distance
    *                    should be calculated.
+   * @param aElement    The context element.
    * @param aDistance   The result of the calculation.
    * @return true on success, false on failure.
    */
   static bool ComputeDistance(nsCSSProperty aProperty,
                               const StyleAnimationValue& aStartValue,
                               const StyleAnimationValue& aEndValue,
+                              dom::Element* aElement,
                               double& aDistance);
 
   /**
    * Calculates an interpolated value that is the specified |aPortion| between
    * the two given values.
    *
    * This really just does the following calculation:
    *   aResultValue = (1.0 - aPortion) * aStartValue + aPortion * aEndValue