LCOV - code coverage report
Current view: directory - content/svg/content/src - SVGMotionSMILType.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 185 2 1.1 %
Date: 2012-06-02 Functions: 23 2 8.7 %

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

Generated by: LCOV version 1.7