LCOV - code coverage report
Current view: top level - dom/svg - SVGMotionSMILType.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 197 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 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             : /* implementation of nsISMILType for use by <animateMotion> element */
       8             : 
       9             : #include "SVGMotionSMILType.h"
      10             : 
      11             : #include "gfx2DGlue.h"
      12             : #include "mozilla/gfx/Point.h"
      13             : #include "nsSMILValue.h"
      14             : #include "nsDebug.h"
      15             : #include "nsMathUtils.h"
      16             : #include "nsISupportsUtils.h"
      17             : #include "nsTArray.h"
      18             : #include <math.h>
      19             : 
      20             : using namespace mozilla::gfx;
      21             : 
      22             : namespace mozilla {
      23             : 
      24             : /*static*/ SVGMotionSMILType SVGMotionSMILType::sSingleton;
      25             : 
      26             : 
      27             : // Helper enum, for distinguishing between types of MotionSegment structs
      28             : enum SegmentType {
      29             :   eSegmentType_Translation,
      30             :   eSegmentType_PathPoint
      31             : };
      32             : 
      33             : // Helper Structs: containers for params to define our MotionSegment
      34             : // (either simple translation or point-on-a-path)
      35             : struct TranslationParams {  // Simple translation
      36             :   float mX;
      37             :   float mY;
      38             : };
      39             : struct PathPointParams {  // Point along a path
      40             :   // Refcounted: need to AddRef/Release.  This can't be an nsRefPtr because
      41             :   // this struct is used inside a union so it can't have a default constructor.
      42             :   Path* MOZ_OWNING_REF mPath;
      43             :   float mDistToPoint; // Distance from path start to the point on the path that
      44             :                       // we're interested in.
      45             : };
      46             : 
      47             : /**
      48             :  * Helper Struct: MotionSegment
      49             :  *
      50             :  * Instances of this class represent the points that we move between during
      51             :  * <animateMotion>.  Each nsSMILValue will get a nsTArray of these (generally
      52             :  * with at most 1 entry in the array, except for in SandwichAdd).  (This
      53             :  * matches our behavior in nsSVGTransformSMILType.)
      54             :  *
      55             :  * NOTE: In general, MotionSegments are represented as points on a path
      56             :  * (eSegmentType_PathPoint), so that we can easily interpolate and compute
      57             :  * distance *along their path*.  However, Add() outputs MotionSegments as
      58             :  * simple translations (eSegmentType_Translation), because adding two points
      59             :  * from a path (e.g. when accumulating a repeated animation) will generally
      60             :  * take you to an arbitrary point *off* of the path.
      61             :  */
      62             : struct MotionSegment
      63             : {
      64             :   // Default constructor just locks us into being a Translation, and leaves
      65             :   // other fields uninitialized (since client is presumably about to set them)
      66             :   MotionSegment()
      67             :     : mSegmentType(eSegmentType_Translation)
      68             :   { }
      69             : 
      70             :   // Constructor for a translation
      71           0 :   MotionSegment(float aX, float aY, float aRotateAngle)
      72           0 :     : mRotateType(eRotateType_Explicit), mRotateAngle(aRotateAngle),
      73           0 :       mSegmentType(eSegmentType_Translation)
      74             :   {
      75           0 :     mU.mTranslationParams.mX = aX;
      76           0 :     mU.mTranslationParams.mY = aY;
      77           0 :   }
      78             : 
      79             :   // Constructor for a point on a path (NOTE: AddRef's)
      80           0 :   MotionSegment(Path* aPath, float aDistToPoint,
      81             :                 RotateType aRotateType, float aRotateAngle)
      82           0 :     : mRotateType(aRotateType), mRotateAngle(aRotateAngle),
      83           0 :       mSegmentType(eSegmentType_PathPoint)
      84             :   {
      85           0 :     mU.mPathPointParams.mPath = aPath;
      86           0 :     mU.mPathPointParams.mDistToPoint = aDistToPoint;
      87             : 
      88           0 :     NS_ADDREF(mU.mPathPointParams.mPath); // Retain a reference to path
      89           0 :   }
      90             : 
      91             :   // Copy constructor (NOTE: AddRef's if we're eSegmentType_PathPoint)
      92           0 :   MotionSegment(const MotionSegment& aOther)
      93           0 :     : mRotateType(aOther.mRotateType), mRotateAngle(aOther.mRotateAngle),
      94           0 :       mSegmentType(aOther.mSegmentType)
      95             :   {
      96           0 :     if (mSegmentType == eSegmentType_Translation) {
      97           0 :       mU.mTranslationParams = aOther.mU.mTranslationParams;
      98             :     } else { // mSegmentType == eSegmentType_PathPoint
      99           0 :       mU.mPathPointParams = aOther.mU.mPathPointParams;
     100           0 :       NS_ADDREF(mU.mPathPointParams.mPath); // Retain a reference to path
     101             :     }
     102           0 :   }
     103             : 
     104             :   // Destructor (releases any reference we were holding onto)
     105           0 :   ~MotionSegment()
     106           0 :   {
     107           0 :     if (mSegmentType == eSegmentType_PathPoint) {
     108           0 :       NS_RELEASE(mU.mPathPointParams.mPath);
     109             :     }
     110           0 :   }
     111             : 
     112             :   // Comparison operators
     113           0 :   bool operator==(const MotionSegment& aOther) const
     114             :   {
     115             :     // Compare basic params
     116           0 :     if (mSegmentType != aOther.mSegmentType ||
     117           0 :         mRotateType  != aOther.mRotateType ||
     118           0 :         (mRotateType == eRotateType_Explicit &&  // Technically, angle mismatch
     119           0 :          mRotateAngle != aOther.mRotateAngle)) { // only matters for Explicit.
     120           0 :       return false;
     121             :     }
     122             : 
     123             :     // Compare translation params, if we're a translation.
     124           0 :     if (mSegmentType == eSegmentType_Translation) {
     125           0 :       return mU.mTranslationParams.mX == aOther.mU.mTranslationParams.mX &&
     126           0 :              mU.mTranslationParams.mY == aOther.mU.mTranslationParams.mY;
     127             :     }
     128             : 
     129             :     // Else, compare path-point params, if we're a path point.
     130           0 :     return (mU.mPathPointParams.mPath == aOther.mU.mPathPointParams.mPath) &&
     131           0 :       (mU.mPathPointParams.mDistToPoint ==
     132           0 :        aOther.mU.mPathPointParams.mDistToPoint);
     133             :   }
     134             : 
     135           0 :   bool operator!=(const MotionSegment& aOther) const
     136             :   {
     137           0 :     return !(*this == aOther);
     138             :   }
     139             : 
     140             :   // Member Data
     141             :   // -----------
     142             :   RotateType mRotateType; // Explicit angle vs. auto vs. auto-reverse.
     143             :   float mRotateAngle;     // Only used if mRotateType == eRotateType_Explicit.
     144             :   const SegmentType mSegmentType; // This determines how we interpret
     145             :                                   // mU. (const for safety/sanity)
     146             : 
     147             :   union { // Union to let us hold the params for either segment-type.
     148             :     TranslationParams mTranslationParams;
     149             :     PathPointParams mPathPointParams;
     150             :   } mU;
     151             : };
     152             : 
     153             : typedef FallibleTArray<MotionSegment> MotionSegmentArray;
     154             : 
     155             : // Helper methods to cast nsSMILValue.mU.mPtr to the right pointer-type
     156             : static MotionSegmentArray&
     157           0 : ExtractMotionSegmentArray(nsSMILValue& aValue)
     158             : {
     159           0 :   return *static_cast<MotionSegmentArray*>(aValue.mU.mPtr);
     160             : }
     161             : 
     162             : static const MotionSegmentArray&
     163           0 : ExtractMotionSegmentArray(const nsSMILValue& aValue)
     164             : {
     165           0 :   return *static_cast<const MotionSegmentArray*>(aValue.mU.mPtr);
     166             : }
     167             : 
     168             : // nsISMILType Methods
     169             : // -------------------
     170             : 
     171             : void
     172           0 : SVGMotionSMILType::Init(nsSMILValue& aValue) const
     173             : {
     174           0 :   MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL type");
     175             : 
     176           0 :   aValue.mType = this;
     177           0 :   aValue.mU.mPtr = new MotionSegmentArray(1);
     178           0 : }
     179             : 
     180             : void
     181           0 : SVGMotionSMILType::Destroy(nsSMILValue& aValue) const
     182             : {
     183           0 :   MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL type");
     184             : 
     185           0 :   MotionSegmentArray* arr = static_cast<MotionSegmentArray*>(aValue.mU.mPtr);
     186           0 :   delete arr;
     187             : 
     188           0 :   aValue.mU.mPtr = nullptr;
     189           0 :   aValue.mType = nsSMILNullType::Singleton();
     190           0 : }
     191             : 
     192             : nsresult
     193           0 : SVGMotionSMILType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
     194             : {
     195           0 :   MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types");
     196           0 :   MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type");
     197             : 
     198           0 :   const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aSrc);
     199           0 :   MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
     200           0 :   if (!dstArr.Assign(srcArr, fallible)) {
     201           0 :     return NS_ERROR_OUT_OF_MEMORY;
     202             :   }
     203             : 
     204           0 :   return NS_OK;
     205             : }
     206             : 
     207             : bool
     208           0 : SVGMotionSMILType::IsEqual(const nsSMILValue& aLeft,
     209             :                            const nsSMILValue& aRight) const
     210             : {
     211           0 :   MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types");
     212           0 :   MOZ_ASSERT(aLeft.mType == this, "Unexpected SMIL type");
     213             : 
     214           0 :   const MotionSegmentArray& leftArr = ExtractMotionSegmentArray(aLeft);
     215           0 :   const MotionSegmentArray& rightArr = ExtractMotionSegmentArray(aRight);
     216             : 
     217             :   // If array-lengths don't match, we're trivially non-equal.
     218           0 :   if (leftArr.Length() != rightArr.Length()) {
     219           0 :     return false;
     220             :   }
     221             : 
     222             :   // Array-lengths match -- check each array-entry for equality.
     223           0 :   uint32_t length = leftArr.Length(); // == rightArr->Length(), if we get here
     224           0 :   for (uint32_t i = 0; i < length; ++i) {
     225           0 :     if (leftArr[i] != rightArr[i]) {
     226           0 :       return false;
     227             :     }
     228             :   }
     229             : 
     230           0 :   return true; // If we get here, we found no differences.
     231             : }
     232             : 
     233             : // Helper method for Add & CreateMatrix
     234             : inline static void
     235           0 : GetAngleAndPointAtDistance(Path* aPath, float aDistance,
     236             :                            RotateType aRotateType,
     237             :                            float& aRotateAngle, // in & out-param.
     238             :                            Point& aPoint)       // out-param.
     239             : {
     240           0 :   if (aRotateType == eRotateType_Explicit) {
     241             :     // Leave aRotateAngle as-is.
     242           0 :     aPoint = aPath->ComputePointAtLength(aDistance);
     243             :   } else {
     244           0 :     Point tangent; // Unit vector tangent to the point we find.
     245           0 :     aPoint = aPath->ComputePointAtLength(aDistance, &tangent);
     246           0 :     float tangentAngle = atan2(tangent.y, tangent.x);
     247           0 :     if (aRotateType == eRotateType_Auto) {
     248           0 :       aRotateAngle = tangentAngle;
     249             :     } else {
     250           0 :       MOZ_ASSERT(aRotateType == eRotateType_AutoReverse);
     251           0 :       aRotateAngle = M_PI + tangentAngle;
     252             :     }
     253             :   }
     254           0 : }
     255             : 
     256             : nsresult
     257           0 : SVGMotionSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
     258             :                        uint32_t aCount) const
     259             : {
     260           0 :   MOZ_ASSERT(aDest.mType == aValueToAdd.mType,
     261             :              "Incompatible SMIL types");
     262           0 :   MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type");
     263             : 
     264           0 :   MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
     265           0 :   const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aValueToAdd);
     266             : 
     267             :   // We're doing a simple add here (as opposed to a sandwich add below).  We
     268             :   // only do this when we're accumulating a repeat result.
     269             :   // NOTE: In other nsISMILTypes, we use this method with a barely-initialized
     270             :   // |aDest| value to assist with "by" animation.  (In this case,
     271             :   // "barely-initialized" would mean dstArr.Length() would be empty.)  However,
     272             :   // we don't do this for <animateMotion>, because we instead use our "by"
     273             :   // value to construct an equivalent "path" attribute, and we use *that* for
     274             :   // our actual animation.
     275           0 :   MOZ_ASSERT(srcArr.Length() == 1, "Invalid source segment arr to add");
     276           0 :   MOZ_ASSERT(dstArr.Length() == 1, "Invalid dest segment arr to add to");
     277           0 :   const MotionSegment& srcSeg = srcArr[0];
     278           0 :   const MotionSegment& dstSeg = dstArr[0];
     279           0 :   MOZ_ASSERT(srcSeg.mSegmentType == eSegmentType_PathPoint,
     280             :              "expecting to be adding points from a motion path");
     281           0 :   MOZ_ASSERT(dstSeg.mSegmentType == eSegmentType_PathPoint,
     282             :              "expecting to be adding points from a motion path");
     283             : 
     284           0 :   const PathPointParams& srcParams = srcSeg.mU.mPathPointParams;
     285           0 :   const PathPointParams& dstParams = dstSeg.mU.mPathPointParams;
     286             : 
     287           0 :   MOZ_ASSERT(srcSeg.mRotateType  == dstSeg.mRotateType &&
     288             :              srcSeg.mRotateAngle == dstSeg.mRotateAngle,
     289             :              "unexpected angle mismatch");
     290           0 :   MOZ_ASSERT(srcParams.mPath == dstParams.mPath,
     291             :              "unexpected path mismatch");
     292           0 :   Path* path = srcParams.mPath;
     293             : 
     294             :   // Use destination to get our rotate angle.
     295           0 :   float rotateAngle = dstSeg.mRotateAngle;
     296           0 :   Point dstPt;
     297           0 :   GetAngleAndPointAtDistance(path, dstParams.mDistToPoint, dstSeg.mRotateType,
     298           0 :                              rotateAngle, dstPt);
     299             : 
     300           0 :   Point srcPt = path->ComputePointAtLength(srcParams.mDistToPoint);
     301             : 
     302           0 :   float newX = dstPt.x + srcPt.x * aCount;
     303           0 :   float newY = dstPt.y + srcPt.y * aCount;
     304             : 
     305             :   // Replace destination's current value -- a point-on-a-path -- with the
     306             :   // translation that results from our addition.
     307           0 :   dstArr.ReplaceElementAt(0, MotionSegment(newX, newY, rotateAngle));
     308           0 :   return NS_OK;
     309             : }
     310             : 
     311             : nsresult
     312           0 : SVGMotionSMILType::SandwichAdd(nsSMILValue& aDest,
     313             :                                const nsSMILValue& aValueToAdd) const
     314             : {
     315           0 :   MOZ_ASSERT(aDest.mType == aValueToAdd.mType,
     316             :              "Incompatible SMIL types");
     317           0 :   MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type");
     318           0 :   MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
     319           0 :   const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aValueToAdd);
     320             : 
     321             :   // We're only expecting to be adding 1 segment on to the list
     322           0 :   MOZ_ASSERT(srcArr.Length() == 1,
     323             :              "Trying to do sandwich add of more than one value");
     324             : 
     325           0 :   if (!dstArr.AppendElement(srcArr[0], fallible)) {
     326           0 :     return NS_ERROR_OUT_OF_MEMORY;
     327             :   }
     328             : 
     329           0 :   return NS_OK;
     330             : }
     331             : 
     332             : nsresult
     333           0 : SVGMotionSMILType::ComputeDistance(const nsSMILValue& aFrom,
     334             :                                    const nsSMILValue& aTo,
     335             :                                    double& aDistance) const
     336             : {
     337           0 :   MOZ_ASSERT(aFrom.mType == aTo.mType, "Incompatible SMIL types");
     338           0 :   MOZ_ASSERT(aFrom.mType == this, "Unexpected SMIL type");
     339           0 :   const MotionSegmentArray& fromArr = ExtractMotionSegmentArray(aFrom);
     340           0 :   const MotionSegmentArray& toArr = ExtractMotionSegmentArray(aTo);
     341             : 
     342             :   // ComputeDistance is only used for calculating distances between single
     343             :   // values in a values array. So we should only have one entry in each array.
     344           0 :   MOZ_ASSERT(fromArr.Length() == 1,
     345             :              "Wrong number of elements in from value");
     346           0 :   MOZ_ASSERT(toArr.Length() == 1,
     347             :              "Wrong number of elements in to value");
     348             : 
     349           0 :   const MotionSegment& from = fromArr[0];
     350           0 :   const MotionSegment& to = toArr[0];
     351             : 
     352           0 :   MOZ_ASSERT(from.mSegmentType == to.mSegmentType,
     353             :              "Mismatched MotionSegment types");
     354           0 :   if (from.mSegmentType == eSegmentType_PathPoint) {
     355           0 :     const PathPointParams& fromParams = from.mU.mPathPointParams;
     356           0 :     const PathPointParams& toParams   = to.mU.mPathPointParams;
     357           0 :     MOZ_ASSERT(fromParams.mPath == toParams.mPath,
     358             :                "Interpolation endpoints should be from same path");
     359           0 :     MOZ_ASSERT(fromParams.mDistToPoint <= toParams.mDistToPoint,
     360             :                "To value shouldn't be before from value on path");
     361           0 :     aDistance = fabs(toParams.mDistToPoint - fromParams.mDistToPoint);
     362             :   } else {
     363           0 :     const TranslationParams& fromParams = from.mU.mTranslationParams;
     364           0 :     const TranslationParams& toParams   = to.mU.mTranslationParams;
     365           0 :     float dX = toParams.mX - fromParams.mX;
     366           0 :     float dY = toParams.mY - fromParams.mY;
     367           0 :     aDistance = NS_hypot(dX, dY);
     368             :   }
     369             : 
     370           0 :   return NS_OK;
     371             : }
     372             : 
     373             : // Helper method for Interpolate()
     374             : static inline float
     375           0 : InterpolateFloat(const float& aStartFlt, const float& aEndFlt,
     376             :                  const double& aUnitDistance)
     377             : {
     378           0 :   return aStartFlt + aUnitDistance * (aEndFlt - aStartFlt);
     379             : }
     380             : 
     381             : nsresult
     382           0 : SVGMotionSMILType::Interpolate(const nsSMILValue& aStartVal,
     383             :                                const nsSMILValue& aEndVal,
     384             :                                double aUnitDistance,
     385             :                                nsSMILValue& aResult) const
     386             : {
     387           0 :   MOZ_ASSERT(aStartVal.mType == aEndVal.mType,
     388             :              "Trying to interpolate different types");
     389           0 :   MOZ_ASSERT(aStartVal.mType == this,
     390             :              "Unexpected types for interpolation");
     391           0 :   MOZ_ASSERT(aResult.mType == this, "Unexpected result type");
     392           0 :   MOZ_ASSERT(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
     393             :              "unit distance value out of bounds");
     394             : 
     395           0 :   const MotionSegmentArray& startArr = ExtractMotionSegmentArray(aStartVal);
     396           0 :   const MotionSegmentArray& endArr = ExtractMotionSegmentArray(aEndVal);
     397           0 :   MotionSegmentArray& resultArr = ExtractMotionSegmentArray(aResult);
     398             : 
     399           0 :   MOZ_ASSERT(startArr.Length() <= 1,
     400             :              "Invalid start-point for animateMotion interpolation");
     401           0 :   MOZ_ASSERT(endArr.Length() == 1,
     402             :              "Invalid end-point for animateMotion interpolation");
     403           0 :   MOZ_ASSERT(resultArr.IsEmpty(),
     404             :              "Expecting result to be just-initialized w/ empty array");
     405             : 
     406           0 :   const MotionSegment& endSeg = endArr[0];
     407           0 :   MOZ_ASSERT(endSeg.mSegmentType == eSegmentType_PathPoint,
     408             :              "Expecting to be interpolating along a path");
     409             : 
     410           0 :   const PathPointParams& endParams = endSeg.mU.mPathPointParams;
     411             :   // NOTE: path & angle should match between start & end (since presumably
     412             :   // start & end came from the same <animateMotion> element), unless start is
     413             :   // empty. (as it would be for pure 'to' animation)
     414           0 :   Path* path = endParams.mPath;
     415           0 :   RotateType rotateType  = endSeg.mRotateType;
     416           0 :   float rotateAngle      = endSeg.mRotateAngle;
     417             : 
     418             :   float startDist;
     419           0 :   if (startArr.IsEmpty()) {
     420           0 :     startDist = 0.0f;
     421             :   } else {
     422           0 :     const MotionSegment& startSeg = startArr[0];
     423           0 :     MOZ_ASSERT(startSeg.mSegmentType == eSegmentType_PathPoint,
     424             :                "Expecting to be interpolating along a path");
     425           0 :     const PathPointParams& startParams = startSeg.mU.mPathPointParams;
     426           0 :     MOZ_ASSERT(startSeg.mRotateType  == endSeg.mRotateType &&
     427             :                startSeg.mRotateAngle == endSeg.mRotateAngle,
     428             :                "unexpected angle mismatch");
     429           0 :     MOZ_ASSERT(startParams.mPath == endParams.mPath,
     430             :                "unexpected path mismatch");
     431           0 :     startDist = startParams.mDistToPoint;
     432             :   }
     433             : 
     434             :   // Get the interpolated distance along our path.
     435           0 :   float resultDist = InterpolateFloat(startDist, endParams.mDistToPoint,
     436           0 :                                       aUnitDistance);
     437             : 
     438             :   // Construct the intermediate result segment, and put it in our outparam.
     439             :   // AppendElement has guaranteed success here, since Init() allocates 1 slot.
     440           0 :   MOZ_ALWAYS_TRUE(resultArr.AppendElement(MotionSegment(path, resultDist,
     441             :                                                         rotateType,
     442             :                                                         rotateAngle),
     443             :                                           fallible));
     444           0 :   return NS_OK;
     445             : }
     446             : 
     447             : /* static */ gfx::Matrix
     448           0 : SVGMotionSMILType::CreateMatrix(const nsSMILValue& aSMILVal)
     449             : {
     450           0 :   const MotionSegmentArray& arr = ExtractMotionSegmentArray(aSMILVal);
     451             : 
     452           0 :   gfx::Matrix matrix;
     453           0 :   uint32_t length = arr.Length();
     454           0 :   for (uint32_t i = 0; i < length; i++) {
     455           0 :     Point point;  // initialized below
     456           0 :     float rotateAngle = arr[i].mRotateAngle; // might get updated below
     457           0 :     if (arr[i].mSegmentType == eSegmentType_Translation) {
     458           0 :       point.x = arr[i].mU.mTranslationParams.mX;
     459           0 :       point.y = arr[i].mU.mTranslationParams.mY;
     460           0 :       MOZ_ASSERT(arr[i].mRotateType == eRotateType_Explicit,
     461             :                  "'auto'/'auto-reverse' should have been converted to "
     462             :                  "explicit angles when we generated this translation");
     463             :     } else {
     464           0 :       GetAngleAndPointAtDistance(arr[i].mU.mPathPointParams.mPath,
     465           0 :                                  arr[i].mU.mPathPointParams.mDistToPoint,
     466           0 :                                  arr[i].mRotateType,
     467           0 :                                  rotateAngle, point);
     468             :     }
     469           0 :     matrix.PreTranslate(point.x, point.y);
     470           0 :     matrix.PreRotate(rotateAngle);
     471             :   }
     472           0 :   return matrix;
     473             : }
     474             : 
     475             : /* static */ nsSMILValue
     476           0 : SVGMotionSMILType::ConstructSMILValue(Path* aPath,
     477             :                                       float aDist,
     478             :                                       RotateType aRotateType,
     479             :                                       float aRotateAngle)
     480             : {
     481           0 :   nsSMILValue smilVal(&SVGMotionSMILType::sSingleton);
     482           0 :   MotionSegmentArray& arr = ExtractMotionSegmentArray(smilVal);
     483             : 
     484             :   // AppendElement has guaranteed success here, since Init() allocates 1 slot.
     485           0 :   MOZ_ALWAYS_TRUE(arr.AppendElement(MotionSegment(aPath, aDist,
     486             :                                                   aRotateType, aRotateAngle),
     487             :                                     fallible));
     488           0 :   return smilVal;
     489             : }
     490             : 
     491             : } // namespace mozilla

Generated by: LCOV version 1.13