LCOV - app.info - content/svg/content/src/SVGMotionSMILType.cpp

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