LCOV - code coverage report
Current view: top level - dom/smil - nsSMILCSSValueType.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 362 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* representation of a value for a SMIL-animated CSS property */
       8             : 
       9             : #include "nsSMILCSSValueType.h"
      10             : 
      11             : #include "nsComputedDOMStyle.h"
      12             : #include "nsString.h"
      13             : #include "nsSMILParserUtils.h"
      14             : #include "nsSMILValue.h"
      15             : #include "nsCSSProps.h"
      16             : #include "nsCSSValue.h"
      17             : #include "nsColor.h"
      18             : #include "nsPresContext.h"
      19             : #include "mozilla/ServoBindings.h"
      20             : #include "mozilla/StyleAnimationValue.h" // For AnimationValue
      21             : #include "mozilla/StyleSetHandleInlines.h"
      22             : #include "mozilla/dom/BaseKeyframeTypesBinding.h" // For CompositeOperation
      23             : #include "mozilla/dom/Element.h"
      24             : #include "nsDebug.h"
      25             : #include "nsStyleUtil.h"
      26             : #include "nsIDocument.h"
      27             : 
      28             : using namespace mozilla::dom;
      29             : using mozilla::StyleAnimationValue;
      30             : 
      31             : typedef AutoTArray<RefPtr<RawServoAnimationValue>, 1> ServoAnimationValues;
      32             : 
      33             : /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
      34             : 
      35           0 : struct ValueWrapper {
      36           0 :   ValueWrapper(nsCSSPropertyID aPropID, const AnimationValue& aValue)
      37           0 :     : mPropID(aPropID)
      38             :   {
      39           0 :     if (aValue.mServo) {
      40           0 :       mServoValues.AppendElement(aValue.mServo);
      41           0 :       return;
      42             :     }
      43           0 :     mGeckoValue = aValue.mGecko;
      44             :   }
      45           0 :   ValueWrapper(nsCSSPropertyID aPropID, const StyleAnimationValue& aValue)
      46           0 :     : mPropID(aPropID), mGeckoValue(aValue) {}
      47           0 :   ValueWrapper(nsCSSPropertyID aPropID,
      48             :                const RefPtr<RawServoAnimationValue>& aValue)
      49           0 :     : mPropID(aPropID), mServoValues{(aValue)} {}
      50           0 :   ValueWrapper(nsCSSPropertyID aPropID, ServoAnimationValues&& aValues)
      51           0 :     : mPropID(aPropID), mServoValues{aValues} {}
      52             : 
      53           0 :   bool operator==(const ValueWrapper& aOther) const
      54             :   {
      55           0 :     if (mPropID != aOther.mPropID) {
      56           0 :       return false;
      57             :     }
      58             : 
      59           0 :     if (!mServoValues.IsEmpty()) {
      60           0 :       size_t len = mServoValues.Length();
      61           0 :       if (len != aOther.mServoValues.Length()) {
      62           0 :         return false;
      63             :       }
      64           0 :       for (size_t i = 0; i < len; i++) {
      65           0 :         if (!Servo_AnimationValue_DeepEqual(mServoValues[i],
      66           0 :                                             aOther.mServoValues[i])) {
      67           0 :           return false;
      68             :         }
      69             :       }
      70           0 :       return true;
      71             :     }
      72             : 
      73           0 :     return mGeckoValue == aOther.mGeckoValue;
      74             :   }
      75             : 
      76             :   bool operator!=(const ValueWrapper& aOther) const
      77             :   {
      78             :     return !(*this == aOther);
      79             :   }
      80             : 
      81             :   nsCSSPropertyID mPropID;
      82             :   ServoAnimationValues mServoValues;
      83             :   StyleAnimationValue mGeckoValue;
      84             : 
      85             : };
      86             : 
      87             : // Helper Methods
      88             : // --------------
      89             : static const StyleAnimationValue*
      90           0 : GetZeroValueForUnit(StyleAnimationValue::Unit aUnit)
      91             : {
      92             :   static const StyleAnimationValue
      93           0 :     sZeroCoord(0, StyleAnimationValue::CoordConstructor);
      94             :   static const StyleAnimationValue
      95           0 :     sZeroPercent(0.0f, StyleAnimationValue::PercentConstructor);
      96             :   static const StyleAnimationValue
      97           0 :     sZeroFloat(0.0f,  StyleAnimationValue::FloatConstructor);
      98             :   static const StyleAnimationValue
      99           0 :     sZeroColor(NS_RGB(0,0,0), StyleAnimationValue::ColorConstructor);
     100             : 
     101           0 :   MOZ_ASSERT(aUnit != StyleAnimationValue::eUnit_Null,
     102             :              "Need non-null unit for a zero value");
     103           0 :   switch (aUnit) {
     104             :     case StyleAnimationValue::eUnit_Coord:
     105           0 :       return &sZeroCoord;
     106             :     case StyleAnimationValue::eUnit_Percent:
     107           0 :       return &sZeroPercent;
     108             :     case StyleAnimationValue::eUnit_Float:
     109           0 :       return &sZeroFloat;
     110             :     case StyleAnimationValue::eUnit_Color:
     111           0 :       return &sZeroColor;
     112             :     default:
     113           0 :       return nullptr;
     114             :   }
     115             : }
     116             : 
     117             : // This method requires at least one of its arguments to be non-null.
     118             : //
     119             : // If one argument is null, this method updates it to point to "zero"
     120             : // for the other argument's Unit (if applicable; otherwise, we return false).
     121             : //
     122             : // If neither argument is null, this method does nothing.
     123             : //
     124             : // |aZeroValueStorage| should be a reference to a RefPtr<RawServoAnimationValue>.
     125             : // This is used where we may need to allocate a new ServoAnimationValue to
     126             : // represent the appropriate zero value.
     127             : //
     128             : // Returns true on success, or otherwise.
     129             : static bool
     130           0 : FinalizeServoAnimationValues(const RefPtr<RawServoAnimationValue>*& aValue1,
     131             :                              const RefPtr<RawServoAnimationValue>*& aValue2,
     132             :                              RefPtr<RawServoAnimationValue>& aZeroValueStorage)
     133             : {
     134           0 :   MOZ_ASSERT(aValue1 || aValue2, "expecting at least one non-null value");
     135             : 
     136             :   // Are we missing either val? (If so, it's an implied 0 in other val's units)
     137             : 
     138           0 :   if (!aValue1) {
     139           0 :     aZeroValueStorage = Servo_AnimationValues_GetZeroValue(*aValue2).Consume();
     140           0 :     aValue1 = &aZeroValueStorage;
     141           0 :   } else if (!aValue2) {
     142           0 :     aZeroValueStorage = Servo_AnimationValues_GetZeroValue(*aValue1).Consume();
     143           0 :     aValue2 = &aZeroValueStorage;
     144             :   }
     145           0 :   return *aValue1 && *aValue2;
     146             : }
     147             : 
     148             : static bool
     149           0 : FinalizeStyleAnimationValues(const StyleAnimationValue*& aValue1,
     150             :                              const StyleAnimationValue*& aValue2)
     151             : {
     152           0 :   MOZ_ASSERT(aValue1 || aValue2,
     153             :              "expecting at least one non-null value");
     154             : 
     155           0 :   if (!aValue1) {
     156           0 :     aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
     157           0 :     return !!aValue1; // Fail if we have no zero value for this unit.
     158             :   }
     159           0 :   if (!aValue2) {
     160           0 :     aValue2 = GetZeroValueForUnit(aValue1->GetUnit());
     161           0 :     return !!aValue2; // Fail if we have no zero value for this unit.
     162             :   }
     163             : 
     164             :   // Ok, both values were specified.
     165             :   // Need to handle a special-case, though: unitless nonzero length (parsed as
     166             :   // eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord).  These
     167             :   // won't interoperate in StyleAnimationValue, since their Units don't match.
     168             :   // In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value.
     169             :   const StyleAnimationValue& zeroCoord =
     170           0 :     *GetZeroValueForUnit(StyleAnimationValue::eUnit_Coord);
     171           0 :   if (*aValue1 == zeroCoord &&
     172           0 :       aValue2->GetUnit() == StyleAnimationValue::eUnit_Float) {
     173           0 :     aValue1 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float);
     174           0 :   } else if (*aValue2 == zeroCoord &&
     175           0 :              aValue1->GetUnit() == StyleAnimationValue::eUnit_Float) {
     176           0 :     aValue2 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float);
     177             :   }
     178             : 
     179           0 :   return true;
     180             : }
     181             : 
     182             : static void
     183           0 : InvertSign(StyleAnimationValue& aValue)
     184             : {
     185           0 :   switch (aValue.GetUnit()) {
     186             :     case StyleAnimationValue::eUnit_Coord:
     187           0 :       aValue.SetCoordValue(-aValue.GetCoordValue());
     188           0 :       break;
     189             :     case StyleAnimationValue::eUnit_Percent:
     190           0 :       aValue.SetPercentValue(-aValue.GetPercentValue());
     191           0 :       break;
     192             :     case StyleAnimationValue::eUnit_Float:
     193           0 :       aValue.SetFloatValue(-aValue.GetFloatValue());
     194           0 :       break;
     195             :     default:
     196           0 :       NS_NOTREACHED("Calling InvertSign with an unsupported unit");
     197           0 :       break;
     198             :   }
     199           0 : }
     200             : 
     201             : static ValueWrapper*
     202           0 : ExtractValueWrapper(nsSMILValue& aValue)
     203             : {
     204           0 :   return static_cast<ValueWrapper*>(aValue.mU.mPtr);
     205             : }
     206             : 
     207             : static const ValueWrapper*
     208           0 : ExtractValueWrapper(const nsSMILValue& aValue)
     209             : {
     210           0 :   return static_cast<const ValueWrapper*>(aValue.mU.mPtr);
     211             : }
     212             : 
     213             : // Class methods
     214             : // -------------
     215             : void
     216           0 : nsSMILCSSValueType::Init(nsSMILValue& aValue) const
     217             : {
     218           0 :   MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL value type");
     219             : 
     220           0 :   aValue.mU.mPtr = nullptr;
     221           0 :   aValue.mType = this;
     222           0 : }
     223             : 
     224             : void
     225           0 : nsSMILCSSValueType::Destroy(nsSMILValue& aValue) const
     226             : {
     227           0 :   MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type");
     228           0 :   delete static_cast<ValueWrapper*>(aValue.mU.mPtr);
     229           0 :   aValue.mType = nsSMILNullType::Singleton();
     230           0 : }
     231             : 
     232             : nsresult
     233           0 : nsSMILCSSValueType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
     234             : {
     235           0 :   MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types");
     236           0 :   MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value type");
     237           0 :   const ValueWrapper* srcWrapper = ExtractValueWrapper(aSrc);
     238           0 :   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
     239             : 
     240           0 :   if (srcWrapper) {
     241           0 :     if (!destWrapper) {
     242             :       // barely-initialized dest -- need to alloc & copy
     243           0 :       aDest.mU.mPtr = new ValueWrapper(*srcWrapper);
     244             :     } else {
     245             :       // both already fully-initialized -- just copy straight across
     246           0 :       *destWrapper = *srcWrapper;
     247             :     }
     248           0 :   } else if (destWrapper) {
     249             :     // fully-initialized dest, barely-initialized src -- clear dest
     250           0 :     delete destWrapper;
     251           0 :     aDest.mU.mPtr = destWrapper = nullptr;
     252             :   } // else, both are barely-initialized -- nothing to do.
     253             : 
     254           0 :   return NS_OK;
     255             : }
     256             : 
     257             : bool
     258           0 : nsSMILCSSValueType::IsEqual(const nsSMILValue& aLeft,
     259             :                             const nsSMILValue& aRight) const
     260             : {
     261           0 :   MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types");
     262           0 :   MOZ_ASSERT(aLeft.mType == this, "Unexpected SMIL value");
     263           0 :   const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
     264           0 :   const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
     265             : 
     266           0 :   if (leftWrapper) {
     267           0 :     if (rightWrapper) {
     268             :       // Both non-null
     269           0 :       NS_WARNING_ASSERTION(leftWrapper != rightWrapper,
     270             :                            "Two nsSMILValues with matching ValueWrapper ptr");
     271           0 :       return *leftWrapper == *rightWrapper;
     272             :     }
     273             :     // Left non-null, right null
     274           0 :     return false;
     275             :   }
     276           0 :   if (rightWrapper) {
     277             :     // Left null, right non-null
     278           0 :     return false;
     279             :   }
     280             :   // Both null
     281           0 :   return true;
     282             : }
     283             : 
     284             : static bool
     285           0 : AddOrAccumulateForServo(nsSMILValue& aDest,
     286             :                         const ValueWrapper* aValueToAddWrapper,
     287             :                         ValueWrapper* aDestWrapper,
     288             :                         CompositeOperation aCompositeOp,
     289             :                         uint64_t aCount)
     290             : {
     291             :   nsCSSPropertyID property = aValueToAddWrapper
     292           0 :                              ? aValueToAddWrapper->mPropID
     293           0 :                              : aDestWrapper->mPropID;
     294             :   size_t len = aValueToAddWrapper
     295           0 :                ? aValueToAddWrapper->mServoValues.Length()
     296           0 :                : aDestWrapper->mServoValues.Length();
     297             : 
     298           0 :   MOZ_ASSERT(!aValueToAddWrapper || !aDestWrapper ||
     299             :              aValueToAddWrapper->mServoValues.Length() ==
     300             :                aDestWrapper->mServoValues.Length(),
     301             :              "Both of values'length in the wrappers should be the same if "
     302             :              "both of them exist");
     303             : 
     304           0 :   for (size_t i = 0; i < len; i++) {
     305             :     const RefPtr<RawServoAnimationValue>* valueToAdd =
     306             :       aValueToAddWrapper
     307           0 :       ? &aValueToAddWrapper->mServoValues[i]
     308           0 :       : nullptr;
     309             :     const RefPtr<RawServoAnimationValue>* destValue =
     310             :       aDestWrapper
     311           0 :       ? &aDestWrapper->mServoValues[i]
     312           0 :       : nullptr;
     313           0 :     RefPtr<RawServoAnimationValue> zeroValueStorage;
     314           0 :     if (!FinalizeServoAnimationValues(valueToAdd, destValue, zeroValueStorage)) {
     315           0 :       return false;
     316             :     }
     317             : 
     318             :     // FinalizeServoAnimationValues may have updated destValue so we should make
     319             :     // sure the aDest and aDestWrapper outparams are up-to-date.
     320           0 :     if (aDestWrapper) {
     321           0 :       aDestWrapper->mServoValues[i] = *destValue;
     322             :     } else {
     323             :       // aDest may be a barely-initialized "zero" destination.
     324           0 :       aDest.mU.mPtr = aDestWrapper = new ValueWrapper(property, *destValue);
     325           0 :       aDestWrapper->mServoValues.SetLength(len);
     326             :     }
     327             : 
     328           0 :     RefPtr<RawServoAnimationValue> result;
     329           0 :     if (aCompositeOp == CompositeOperation::Add) {
     330           0 :       result = Servo_AnimationValues_Add(*destValue, *valueToAdd).Consume();
     331             :     } else {
     332           0 :       result = Servo_AnimationValues_Accumulate(*destValue,
     333             :                                                 *valueToAdd,
     334           0 :                                                 aCount).Consume();
     335             :     }
     336             : 
     337           0 :     if (!result) {
     338           0 :       return false;
     339             :     }
     340           0 :     aDestWrapper->mServoValues[i] = result;
     341             :   }
     342             : 
     343           0 :   return true;
     344             : }
     345             : 
     346             : static bool
     347           0 : AddOrAccumulate(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
     348             :                 CompositeOperation aCompositeOp, uint64_t aCount)
     349             : {
     350           0 :   MOZ_ASSERT(aValueToAdd.mType == aDest.mType,
     351             :              "Trying to add mismatching types");
     352           0 :   MOZ_ASSERT(aValueToAdd.mType == &nsSMILCSSValueType::sSingleton,
     353             :              "Unexpected SMIL value type");
     354           0 :   MOZ_ASSERT(aCompositeOp == CompositeOperation::Add ||
     355             :              aCompositeOp == CompositeOperation::Accumulate,
     356             :              "Composite operation should be add or accumulate");
     357           0 :   MOZ_ASSERT(aCompositeOp != CompositeOperation::Add || aCount == 1,
     358             :              "Count should be 1 if composite operation is add");
     359             : 
     360           0 :   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
     361           0 :   const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
     362           0 :   MOZ_ASSERT(destWrapper || valueToAddWrapper,
     363             :              "need at least one fully-initialized value");
     364             : 
     365             :   nsCSSPropertyID property = valueToAddWrapper
     366           0 :                              ? valueToAddWrapper->mPropID
     367           0 :                              : destWrapper->mPropID;
     368             :   // Special case: font-size-adjust and stroke-dasharray are explicitly
     369             :   // non-additive (even though StyleAnimationValue *could* support adding them)
     370           0 :   if (property == eCSSProperty_font_size_adjust ||
     371             :       property == eCSSProperty_stroke_dasharray) {
     372           0 :     return false;
     373             :   }
     374             :   // Skip font shorthand since it includes font-size-adjust.
     375           0 :   if (property == eCSSProperty_font) {
     376           0 :     return false;
     377             :   }
     378             : 
     379             :   bool isServo = valueToAddWrapper
     380           0 :                  ? !valueToAddWrapper->mServoValues.IsEmpty()
     381           0 :                  : !destWrapper->mServoValues.IsEmpty();
     382           0 :   if (isServo) {
     383             :     return AddOrAccumulateForServo(aDest,
     384             :                                    valueToAddWrapper,
     385             :                                    destWrapper,
     386             :                                    aCompositeOp,
     387           0 :                                    aCount);
     388             :   }
     389             : 
     390           0 :   const StyleAnimationValue* valueToAdd = valueToAddWrapper ?
     391           0 :     &valueToAddWrapper->mGeckoValue : nullptr;
     392           0 :   const StyleAnimationValue* destValue = destWrapper ?
     393           0 :     &destWrapper->mGeckoValue : nullptr;
     394           0 :   if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) {
     395           0 :     return false;
     396             :   }
     397             :   // Did FinalizeStyleAnimationValues change destValue?
     398             :   // If so, update outparam to use the new value.
     399           0 :   if (destWrapper && &destWrapper->mGeckoValue != destValue) {
     400           0 :     destWrapper->mGeckoValue = *destValue;
     401             :   }
     402             : 
     403             :   // Handle barely-initialized "zero" destination.
     404           0 :   if (!destWrapper) {
     405           0 :     aDest.mU.mPtr = destWrapper = new ValueWrapper(property, *destValue);
     406             :   }
     407             : 
     408             :   // For Gecko, we currently call Add for either composite mode.
     409             :   //
     410             :   // This is not ideal, but it doesn't make any difference for the set of
     411             :   // properties we currently allow adding in SMIL and this code path will
     412             :   // hopefully become obsolete before we expand that set.
     413           0 :   return StyleAnimationValue::Add(property,
     414             :                                   destWrapper->mGeckoValue,
     415           0 :                                   valueToAddWrapper->mGeckoValue, aCount);
     416             : }
     417             : 
     418             : nsresult
     419           0 : nsSMILCSSValueType::SandwichAdd(nsSMILValue& aDest,
     420             :                                 const nsSMILValue& aValueToAdd) const
     421             : {
     422           0 :   return AddOrAccumulate(aDest, aValueToAdd, CompositeOperation::Add, 1)
     423           0 :          ? NS_OK
     424           0 :          : NS_ERROR_FAILURE;
     425             : }
     426             : 
     427             : nsresult
     428           0 : nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
     429             :                         uint32_t aCount) const
     430             : {
     431           0 :   return AddOrAccumulate(aDest, aValueToAdd, CompositeOperation::Accumulate,
     432             :                          aCount)
     433           0 :          ? NS_OK
     434           0 :          : NS_ERROR_FAILURE;
     435             : }
     436             : 
     437             : static nsresult
     438           0 : ComputeDistanceForServo(const ValueWrapper* aFromWrapper,
     439             :                         const ValueWrapper& aToWrapper,
     440             :                         double& aDistance)
     441             : {
     442           0 :   size_t len = aToWrapper.mServoValues.Length();
     443           0 :   MOZ_ASSERT(!aFromWrapper || aFromWrapper->mServoValues.Length() == len,
     444             :              "From and to values length should be the same if "
     445             :              "The start value exists");
     446             : 
     447           0 :   double squareDistance = 0;
     448             : 
     449           0 :   for (size_t i = 0; i < len; i++) {
     450             :     const RefPtr<RawServoAnimationValue>* fromValue =
     451           0 :       aFromWrapper ? &aFromWrapper->mServoValues[0] : nullptr;
     452           0 :     const RefPtr<RawServoAnimationValue>* toValue = &aToWrapper.mServoValues[0];
     453           0 :     RefPtr<RawServoAnimationValue> zeroValueStorage;
     454           0 :     if (!FinalizeServoAnimationValues(fromValue, toValue, zeroValueStorage)) {
     455           0 :       return NS_ERROR_FAILURE;
     456             :     }
     457             : 
     458           0 :     double distance = Servo_AnimationValues_ComputeDistance(*fromValue, *toValue);
     459           0 :     if (len == 1) {
     460           0 :       aDistance = distance;
     461           0 :       return NS_OK;
     462             :     }
     463           0 :     squareDistance += distance * distance;
     464             :   }
     465             : 
     466           0 :   aDistance = sqrt(squareDistance);
     467             : 
     468           0 :   return NS_OK;
     469             : }
     470             : 
     471             : nsresult
     472           0 : nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
     473             :                                     const nsSMILValue& aTo,
     474             :                                     double& aDistance) const
     475             : {
     476           0 :   MOZ_ASSERT(aFrom.mType == aTo.mType,
     477             :              "Trying to compare different types");
     478           0 :   MOZ_ASSERT(aFrom.mType == this, "Unexpected source type");
     479             : 
     480           0 :   const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom);
     481           0 :   const ValueWrapper* toWrapper = ExtractValueWrapper(aTo);
     482           0 :   MOZ_ASSERT(toWrapper, "expecting non-null endpoint");
     483             : 
     484           0 :   if (!toWrapper->mServoValues.IsEmpty()) {
     485           0 :     return ComputeDistanceForServo(fromWrapper, *toWrapper, aDistance);
     486             :   }
     487             : 
     488           0 :   const StyleAnimationValue* fromCSSValue = fromWrapper ?
     489           0 :     &fromWrapper->mGeckoValue : nullptr;
     490           0 :   const StyleAnimationValue* toCSSValue = &toWrapper->mGeckoValue;
     491           0 :   if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
     492           0 :     return NS_ERROR_FAILURE;
     493             :   }
     494             : 
     495           0 :   return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
     496             :                                               fromWrapper->mGeckoValue,
     497             :                                               toWrapper->mGeckoValue,
     498             :                                               nullptr,
     499             :                                               aDistance)
     500           0 :          ? NS_OK
     501           0 :          : NS_ERROR_FAILURE;
     502             : }
     503             : 
     504             : static nsresult
     505           0 : InterpolateForGecko(const ValueWrapper* aStartWrapper,
     506             :                     const ValueWrapper& aEndWrapper,
     507             :                     double aUnitDistance,
     508             :                     nsSMILValue& aResult)
     509             : {
     510             :   const StyleAnimationValue* startCSSValue = aStartWrapper
     511           0 :                                              ? &aStartWrapper->mGeckoValue
     512           0 :                                              : nullptr;
     513           0 :   const StyleAnimationValue* endCSSValue = &aEndWrapper.mGeckoValue;
     514           0 :   if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
     515           0 :     return NS_ERROR_FAILURE;
     516             :   }
     517             : 
     518           0 :   StyleAnimationValue resultValue;
     519           0 :   if (StyleAnimationValue::Interpolate(aEndWrapper.mPropID,
     520             :                                        *startCSSValue,
     521             :                                        *endCSSValue,
     522             :                                        aUnitDistance, resultValue)) {
     523           0 :     aResult.mU.mPtr = new ValueWrapper(aEndWrapper.mPropID, resultValue);
     524           0 :     return NS_OK;
     525             :   }
     526           0 :   return NS_ERROR_FAILURE;
     527             : }
     528             : 
     529             : static nsresult
     530           0 : InterpolateForServo(const ValueWrapper* aStartWrapper,
     531             :                     const ValueWrapper& aEndWrapper,
     532             :                     double aUnitDistance,
     533             :                     nsSMILValue& aResult)
     534             : {
     535           0 :   ServoAnimationValues results;
     536           0 :   size_t len = aEndWrapper.mServoValues.Length();
     537           0 :   results.SetCapacity(len);
     538           0 :   MOZ_ASSERT(!aStartWrapper || aStartWrapper->mServoValues.Length() == len,
     539             :              "Start and end values length should be the same if "
     540             :              "The start value exists");
     541           0 :   for (size_t i = 0; i < len; i++) {
     542             :     const RefPtr<RawServoAnimationValue>*
     543             :       startValue = aStartWrapper
     544           0 :                    ? &aStartWrapper->mServoValues[i]
     545           0 :                    : nullptr;
     546           0 :     const RefPtr<RawServoAnimationValue>* endValue = &aEndWrapper.mServoValues[i];
     547           0 :     RefPtr<RawServoAnimationValue> zeroValueStorage;
     548           0 :     if (!FinalizeServoAnimationValues(startValue, endValue, zeroValueStorage)) {
     549           0 :       return NS_ERROR_FAILURE;
     550             :     }
     551             : 
     552             :     RefPtr<RawServoAnimationValue> result =
     553           0 :       Servo_AnimationValues_Interpolate(*startValue,
     554             :                                         *endValue,
     555           0 :                                         aUnitDistance).Consume();
     556           0 :     if (!result) {
     557           0 :       return NS_ERROR_FAILURE;
     558             :     }
     559           0 :     results.AppendElement(result);
     560             :   }
     561           0 :   aResult.mU.mPtr = new ValueWrapper(aEndWrapper.mPropID, Move(results));
     562             : 
     563           0 :   return NS_OK;
     564             : }
     565             : 
     566             : nsresult
     567           0 : nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
     568             :                                 const nsSMILValue& aEndVal,
     569             :                                 double aUnitDistance,
     570             :                                 nsSMILValue& aResult) const
     571             : {
     572           0 :   MOZ_ASSERT(aStartVal.mType == aEndVal.mType,
     573             :              "Trying to interpolate different types");
     574           0 :   MOZ_ASSERT(aStartVal.mType == this,
     575             :              "Unexpected types for interpolation");
     576           0 :   MOZ_ASSERT(aResult.mType == this, "Unexpected result type");
     577           0 :   MOZ_ASSERT(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
     578             :              "unit distance value out of bounds");
     579           0 :   MOZ_ASSERT(!aResult.mU.mPtr, "expecting barely-initialized outparam");
     580             : 
     581           0 :   const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal);
     582           0 :   const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
     583           0 :   MOZ_ASSERT(endWrapper, "expecting non-null endpoint");
     584             : 
     585           0 :   if (!endWrapper->mServoValues.IsEmpty()) {
     586             :     return InterpolateForServo(startWrapper,
     587             :                                *endWrapper,
     588             :                                aUnitDistance,
     589           0 :                                aResult);
     590             :   }
     591             : 
     592             :   return InterpolateForGecko(startWrapper,
     593             :                              *endWrapper,
     594             :                              aUnitDistance,
     595           0 :                              aResult);
     596             : }
     597             : 
     598             : // Helper function to extract presContext
     599             : static nsPresContext*
     600           0 : GetPresContextForElement(Element* aElem)
     601             : {
     602           0 :   nsIDocument* doc = aElem->GetUncomposedDoc();
     603           0 :   if (!doc) {
     604             :     // This can happen if we process certain types of restyles mid-sample
     605             :     // and remove anonymous animated content from the document as a result.
     606             :     // See bug 534975.
     607           0 :     return nullptr;
     608             :   }
     609           0 :   nsIPresShell* shell = doc->GetShell();
     610           0 :   return shell ? shell->GetPresContext() : nullptr;
     611             : }
     612             : 
     613             : static const nsDependentSubstring
     614           0 : GetNonNegativePropValue(const nsAString& aString, nsCSSPropertyID aPropID,
     615             :                         bool& aIsNegative)
     616             : {
     617             :   // If value is negative, we'll strip off the "-" so the CSS parser won't
     618             :   // barf, and then manually make the parsed value negative.
     619             :   // (This is a partial solution to let us accept some otherwise out-of-bounds
     620             :   // CSS values. Bug 501188 will provide a more complete fix.)
     621           0 :   aIsNegative = false;
     622           0 :   uint32_t subStringBegin = 0;
     623             : 
     624             :   // NOTE: We need to opt-out 'stroke-dasharray' from the negative-number
     625             :   // check.  Its values might look negative (e.g. by starting with "-1"), but
     626             :   // they're more complicated than our simple negation logic here can handle.
     627           0 :   if (aPropID != eCSSProperty_stroke_dasharray) {
     628           0 :     int32_t absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
     629           0 :     if (absValuePos > 0) {
     630           0 :       aIsNegative = true;
     631           0 :       subStringBegin = (uint32_t)absValuePos; // Start parsing after '-' sign
     632             :     }
     633             :   }
     634             : 
     635           0 :   return Substring(aString, subStringBegin);
     636             : }
     637             : 
     638             : // Helper function to parse a string into a StyleAnimationValue
     639             : static bool
     640           0 : ValueFromStringHelper(nsCSSPropertyID aPropID,
     641             :                       Element* aTargetElement,
     642             :                       nsPresContext* aPresContext,
     643             :                       nsStyleContext* aStyleContext,
     644             :                       const nsAString& aString,
     645             :                       StyleAnimationValue& aStyleAnimValue,
     646             :                       bool* aIsContextSensitive)
     647             : {
     648           0 :   bool isNegative = false;
     649             :   const nsDependentSubstring subString =
     650           0 :     GetNonNegativePropValue(aString, aPropID, isNegative);
     651             : 
     652           0 :   if (!StyleAnimationValue::ComputeValue(aPropID, aTargetElement, aStyleContext,
     653             :                                          subString, true, aStyleAnimValue,
     654             :                                          aIsContextSensitive)) {
     655           0 :     return false;
     656             :   }
     657           0 :   if (isNegative) {
     658           0 :     InvertSign(aStyleAnimValue);
     659             :   }
     660             : 
     661           0 :   if (aPropID == eCSSProperty_font_size) {
     662             :     // Divide out text-zoom, since SVG is supposed to ignore it
     663           0 :     MOZ_ASSERT(aStyleAnimValue.GetUnit() == StyleAnimationValue::eUnit_Coord,
     664             :                "'font-size' value with unexpected style unit");
     665           0 :     aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
     666           0 :                                   aPresContext->EffectiveTextZoom());
     667             :   }
     668           0 :   return true;
     669             : }
     670             : 
     671             : static ServoAnimationValues
     672           0 : ValueFromStringHelper(nsCSSPropertyID aPropID,
     673             :                       Element* aTargetElement,
     674             :                       nsPresContext* aPresContext,
     675             :                       nsStyleContext* aStyleContext,
     676             :                       const nsAString& aString)
     677             : {
     678           0 :   ServoAnimationValues result;
     679             : 
     680           0 :   nsIDocument* doc = aTargetElement->GetUncomposedDoc();
     681           0 :   if (!doc) {
     682           0 :     return result;
     683             :   }
     684             : 
     685             :   // Parse property
     686             :   // FIXME this is using the wrong base uri (bug 1343919)
     687           0 :   RefPtr<URLExtraData> data = new URLExtraData(doc->GetDocumentURI(),
     688           0 :                                                doc->GetDocumentURI(),
     689           0 :                                                doc->NodePrincipal());
     690           0 :   NS_ConvertUTF16toUTF8 value(aString);
     691             :   RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
     692           0 :     Servo_ParseProperty(aPropID,
     693             :                         &value,
     694             :                         data,
     695           0 :                         ParsingMode::AllowUnitlessLength |
     696             :                         ParsingMode::AllowAllNumericValues,
     697             :                         doc->GetCompatibilityMode(),
     698           0 :                         doc->CSSLoader()).Consume();
     699           0 :   if (!servoDeclarationBlock) {
     700           0 :     return result;
     701             :   }
     702             : 
     703             :   // Get a suitable style context for Servo
     704             :   const ServoComputedValues* currentStyle =
     705           0 :     aStyleContext->ComputedValues();
     706             : 
     707             :   // Compute value
     708           0 :   aPresContext->StyleSet()->AsServo()->GetAnimationValues(servoDeclarationBlock,
     709             :                                                           aTargetElement,
     710             :                                                           currentStyle,
     711           0 :                                                           result);
     712           0 :   if (result.IsEmpty()) {
     713           0 :     return result;
     714             :   }
     715             : 
     716           0 :   if (aPropID == eCSSProperty_font_size) {
     717             :     // FIXME (bug 1357296): Divide out text-zoom, since SVG is supposed to
     718             :     // ignore it.
     719           0 :     if (aPresContext->EffectiveTextZoom() != 1.0) {
     720             :       NS_WARNING("stylo: Dividing out text-zoom not yet supported"
     721           0 :                  " (bug 1357296)");
     722             :     }
     723             :   }
     724             : 
     725           0 :   return result;
     726             : }
     727             : 
     728             : // static
     729             : void
     730           0 : nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
     731             :                                     Element* aTargetElement,
     732             :                                     const nsAString& aString,
     733             :                                     nsSMILValue& aValue,
     734             :                                     bool* aIsContextSensitive)
     735             : {
     736           0 :   MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
     737           0 :   nsPresContext* presContext = GetPresContextForElement(aTargetElement);
     738           0 :   if (!presContext) {
     739           0 :     NS_WARNING("Not parsing animation value; unable to get PresContext");
     740           0 :     return;
     741             :   }
     742             : 
     743           0 :   nsIDocument* doc = aTargetElement->GetUncomposedDoc();
     744           0 :   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
     745             :                                                 doc->NodePrincipal(),
     746             :                                                 doc->GetDocumentURI(),
     747             :                                                 0, aString, nullptr)) {
     748           0 :     return;
     749             :   }
     750             : 
     751             :   RefPtr<nsStyleContext> styleContext =
     752           0 :     nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr,
     753           0 :                                         presContext->PresShell());
     754           0 :   if (!styleContext) {
     755           0 :     return;
     756             :   }
     757             : 
     758           0 :   if (aTargetElement->IsStyledByServo()) {
     759             :     ServoAnimationValues parsedValues =
     760             :       ValueFromStringHelper(aPropID, aTargetElement, presContext,
     761           0 :                             styleContext, aString);
     762           0 :     if (aIsContextSensitive) {
     763             :       // FIXME: Bug 1358955 - detect context-sensitive values and set this value
     764             :       // appropriately.
     765           0 :       *aIsContextSensitive = false;
     766             :     }
     767             : 
     768           0 :     if (!parsedValues.IsEmpty()) {
     769           0 :       sSingleton.Init(aValue);
     770           0 :       aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues));
     771             :     }
     772           0 :     return;
     773             :   }
     774             : 
     775           0 :   StyleAnimationValue parsedValue;
     776           0 :   if (ValueFromStringHelper(aPropID, aTargetElement, presContext, styleContext,
     777             :                             aString, parsedValue, aIsContextSensitive)) {
     778           0 :     sSingleton.Init(aValue);
     779           0 :     aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue);
     780             :   }
     781             : }
     782             : 
     783             : // static
     784             : nsSMILValue
     785           0 : nsSMILCSSValueType::ValueFromAnimationValue(nsCSSPropertyID aPropID,
     786             :                                             Element* aTargetElement,
     787             :                                             const AnimationValue& aValue)
     788             : {
     789           0 :   nsSMILValue result;
     790             : 
     791           0 :   nsIDocument* doc = aTargetElement->GetUncomposedDoc();
     792             :   // We'd like to avoid serializing |aValue| if possible, and since the
     793             :   // string passed to CSPAllowsInlineStyle is only used for reporting violations
     794             :   // and an intermediate CSS value is not likely to be particularly useful
     795             :   // in that case, we just use a generic placeholder string instead.
     796             :   static const nsLiteralString kPlaceholderText =
     797           0 :     NS_LITERAL_STRING("[SVG animation of CSS]");
     798           0 :   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
     799             :                                                 doc->NodePrincipal(),
     800             :                                                 doc->GetDocumentURI(),
     801           0 :                                                 0, kPlaceholderText, nullptr)) {
     802           0 :     return result;
     803             :   }
     804             : 
     805           0 :   sSingleton.Init(result);
     806           0 :   result.mU.mPtr = new ValueWrapper(aPropID, aValue);
     807             : 
     808           0 :   return result;
     809             : }
     810             : 
     811             : // static
     812             : void
     813           0 : nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
     814             :                                   nsAString& aString)
     815             : {
     816           0 :   MOZ_ASSERT(aValue.mType == &nsSMILCSSValueType::sSingleton,
     817             :              "Unexpected SMIL value type");
     818           0 :   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
     819           0 :   if (!wrapper) {
     820           0 :     return;
     821             :   }
     822             : 
     823           0 :   if (wrapper->mServoValues.IsEmpty()) {
     824             :     DebugOnly<bool> uncomputeResult =
     825           0 :       StyleAnimationValue::UncomputeValue(wrapper->mPropID,
     826             :                                           wrapper->mGeckoValue,
     827           0 :                                           aString);
     828           0 :     return;
     829             :   }
     830             : 
     831           0 :   if (nsCSSProps::IsShorthand(wrapper->mPropID)) {
     832             :     // In case of shorthand on servo, we iterate over all mServoValues array
     833             :     // since we have multiple AnimationValues in the array for each longhand
     834             :     // component.
     835           0 :     Servo_Shorthand_AnimationValues_Serialize(wrapper->mPropID,
     836             :                                               &wrapper->mServoValues,
     837           0 :                                               &aString);
     838           0 :     return;
     839             :   }
     840             : 
     841           0 :   Servo_AnimationValue_Serialize(wrapper->mServoValues[0],
     842           0 :                                  wrapper->mPropID,
     843           0 :                                  &aString);
     844             : }
     845             : 
     846             : // static
     847             : nsCSSPropertyID
     848           0 : nsSMILCSSValueType::PropertyFromValue(const nsSMILValue& aValue)
     849             : {
     850           0 :   if (aValue.mType != &nsSMILCSSValueType::sSingleton) {
     851           0 :     return eCSSProperty_UNKNOWN;
     852             :   }
     853             : 
     854           0 :   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
     855           0 :   if (!wrapper) {
     856           0 :     return eCSSProperty_UNKNOWN;
     857             :   }
     858             : 
     859           0 :   return wrapper->mPropID;
     860             : }

Generated by: LCOV version 1.13