LCOV - code coverage report
Current view: top level - dom/svg - SVGPathSegListSMILType.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 197 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 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             : #include "mozilla/DebugOnly.h"
       8             : 
       9             : #include "SVGPathSegListSMILType.h"
      10             : #include "nsSMILValue.h"
      11             : #include "SVGPathSegUtils.h"
      12             : #include "SVGPathData.h"
      13             : 
      14             : // Indices of boolean flags within 'arc' segment chunks in path-data arrays
      15             : // (where '0' would correspond to the index of the encoded segment type):
      16             : #define LARGE_ARC_FLAG_IDX 4
      17             : #define SWEEP_FLAG_IDX     5
      18             : 
      19             : namespace mozilla {
      20             : 
      21             : //----------------------------------------------------------------------
      22             : // nsISMILType implementation
      23             : 
      24             : void
      25           0 : SVGPathSegListSMILType::Init(nsSMILValue &aValue) const
      26             : {
      27           0 :   MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
      28           0 :   aValue.mU.mPtr = new SVGPathDataAndInfo();
      29           0 :   aValue.mType = this;
      30           0 : }
      31             : 
      32             : void
      33           0 : SVGPathSegListSMILType::Destroy(nsSMILValue& aValue) const
      34             : {
      35           0 :   NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
      36           0 :   delete static_cast<SVGPathDataAndInfo*>(aValue.mU.mPtr);
      37           0 :   aValue.mU.mPtr = nullptr;
      38           0 :   aValue.mType = nsSMILNullType::Singleton();
      39           0 : }
      40             : 
      41             : nsresult
      42           0 : SVGPathSegListSMILType::Assign(nsSMILValue& aDest,
      43             :                                const nsSMILValue& aSrc) const
      44             : {
      45           0 :   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
      46           0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
      47             : 
      48             :   const SVGPathDataAndInfo* src =
      49           0 :     static_cast<const SVGPathDataAndInfo*>(aSrc.mU.mPtr);
      50             :   SVGPathDataAndInfo* dest =
      51           0 :     static_cast<SVGPathDataAndInfo*>(aDest.mU.mPtr);
      52             : 
      53           0 :   return dest->CopyFrom(*src);
      54             : }
      55             : 
      56             : bool
      57           0 : SVGPathSegListSMILType::IsEqual(const nsSMILValue& aLeft,
      58             :                                 const nsSMILValue& aRight) const
      59             : {
      60           0 :   NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
      61           0 :   NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
      62             : 
      63           0 :   return *static_cast<const SVGPathDataAndInfo*>(aLeft.mU.mPtr) ==
      64           0 :          *static_cast<const SVGPathDataAndInfo*>(aRight.mU.mPtr);
      65             : }
      66             : 
      67             : static bool
      68           0 : ArcFlagsDiffer(SVGPathDataAndInfo::const_iterator aPathData1,
      69             :                SVGPathDataAndInfo::const_iterator aPathData2)
      70             : {
      71           0 :   MOZ_ASSERT
      72             :     (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData1[0])),
      73             :                                 "ArcFlagsDiffer called with non-arc segment");
      74           0 :   MOZ_ASSERT
      75             :     (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData2[0])),
      76             :                                 "ArcFlagsDiffer called with non-arc segment");
      77             : 
      78           0 :   return aPathData1[LARGE_ARC_FLAG_IDX] != aPathData2[LARGE_ARC_FLAG_IDX] ||
      79           0 :          aPathData1[SWEEP_FLAG_IDX]     != aPathData2[SWEEP_FLAG_IDX];
      80             : }
      81             : 
      82             : enum PathInterpolationResult {
      83             :   eCannotInterpolate,
      84             :   eRequiresConversion,
      85             :   eCanInterpolate
      86             : };
      87             : 
      88             : static PathInterpolationResult
      89           0 : CanInterpolate(const SVGPathDataAndInfo& aStart,
      90             :                const SVGPathDataAndInfo& aEnd)
      91             : {
      92           0 :   if (aStart.IsIdentity()) {
      93           0 :     return eCanInterpolate;
      94             :   }
      95             : 
      96           0 :   if (aStart.Length() != aEnd.Length()) {
      97           0 :     return eCannotInterpolate;
      98             :   }
      99             : 
     100           0 :   PathInterpolationResult result = eCanInterpolate;
     101             : 
     102           0 :   SVGPathDataAndInfo::const_iterator pStart = aStart.begin();
     103           0 :   SVGPathDataAndInfo::const_iterator pEnd = aEnd.begin();
     104           0 :   SVGPathDataAndInfo::const_iterator pStartDataEnd = aStart.end();
     105           0 :   SVGPathDataAndInfo::const_iterator pEndDataEnd = aEnd.end();
     106             : 
     107           0 :   while (pStart < pStartDataEnd && pEnd < pEndDataEnd) {
     108           0 :     uint32_t startType = SVGPathSegUtils::DecodeType(*pStart);
     109           0 :     uint32_t endType = SVGPathSegUtils::DecodeType(*pEnd);
     110             : 
     111           0 :     if (SVGPathSegUtils::IsArcType(startType) &&
     112           0 :         SVGPathSegUtils::IsArcType(endType) &&
     113           0 :         ArcFlagsDiffer(pStart, pEnd)) {
     114           0 :       return eCannotInterpolate;
     115             :     }
     116             : 
     117           0 :     if (startType != endType) {
     118           0 :       if (!SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType)) {
     119           0 :         return eCannotInterpolate;
     120             :       }
     121             : 
     122           0 :       result = eRequiresConversion;
     123             :     }
     124             : 
     125           0 :     pStart += 1 + SVGPathSegUtils::ArgCountForType(startType);
     126           0 :     pEnd += 1 + SVGPathSegUtils::ArgCountForType(endType);
     127             :   }
     128             : 
     129           0 :   MOZ_ASSERT(pStart <= pStartDataEnd && pEnd <= pEndDataEnd,
     130             :              "Iterated past end of buffer! (Corrupt path data?)");
     131             : 
     132           0 :   if (pStart != pStartDataEnd || pEnd != pEndDataEnd) {
     133           0 :     return eCannotInterpolate;
     134             :   }
     135             : 
     136           0 :   return result;
     137             : }
     138             : 
     139             : enum RelativenessAdjustmentType {
     140             :   eAbsoluteToRelative,
     141             :   eRelativeToAbsolute
     142             : };
     143             : 
     144             : static inline void
     145           0 : AdjustSegmentForRelativeness(RelativenessAdjustmentType aAdjustmentType,
     146             :                              const SVGPathDataAndInfo::iterator& aSegmentToAdjust,
     147             :                              const SVGPathTraversalState& aState)
     148             : {
     149           0 :   if (aAdjustmentType == eAbsoluteToRelative) {
     150           0 :     aSegmentToAdjust[0] -= aState.pos.x;
     151           0 :     aSegmentToAdjust[1] -= aState.pos.y;
     152             :   } else {
     153           0 :     aSegmentToAdjust[0] += aState.pos.x;
     154           0 :     aSegmentToAdjust[1] += aState.pos.y;
     155             :   }
     156           0 : }
     157             : 
     158             : /**
     159             :  * Helper function for AddWeightedPathSegLists, to add multiples of two
     160             :  * path-segments of the same type.
     161             :  *
     162             :  * NOTE: |aSeg1| is allowed to be nullptr, so we use |aSeg2| as the
     163             :  * authoritative source of things like segment-type and boolean arc flags.
     164             :  *
     165             :  * @param aCoeff1    The coefficient to use on the first segment.
     166             :  * @param aSeg1      An iterator pointing to the first segment.  This can be
     167             :  *                   null, which is treated as identity (zero).
     168             :  * @param aCoeff2    The coefficient to use on the second segment.
     169             :  * @param aSeg2      An iterator pointing to the second segment.
     170             :  * @param [out] aResultSeg An iterator pointing to where we should write the
     171             :  *                         result of this operation.
     172             :  */
     173             : static inline void
     174           0 : AddWeightedPathSegs(double aCoeff1,
     175             :                     SVGPathDataAndInfo::const_iterator& aSeg1,
     176             :                     double aCoeff2,
     177             :                     SVGPathDataAndInfo::const_iterator& aSeg2,
     178             :                     SVGPathDataAndInfo::iterator& aResultSeg)
     179             : {
     180           0 :   MOZ_ASSERT(aSeg2, "2nd segment must be non-null");
     181           0 :   MOZ_ASSERT(aResultSeg, "result segment must be non-null");
     182             : 
     183           0 :   uint32_t segType = SVGPathSegUtils::DecodeType(aSeg2[0]);
     184           0 :   MOZ_ASSERT(!aSeg1 || SVGPathSegUtils::DecodeType(*aSeg1) == segType,
     185             :              "unexpected segment type");
     186             : 
     187             :   // FIRST: Directly copy the arguments that don't make sense to add.
     188           0 :   aResultSeg[0] = aSeg2[0];  // encoded segment type
     189             : 
     190           0 :   bool isArcType = SVGPathSegUtils::IsArcType(segType);
     191           0 :   if (isArcType) {
     192             :     // Copy boolean arc flags.
     193           0 :     MOZ_ASSERT(!aSeg1 || !ArcFlagsDiffer(aSeg1, aSeg2),
     194             :                "Expecting arc flags to match");
     195           0 :     aResultSeg[LARGE_ARC_FLAG_IDX] = aSeg2[LARGE_ARC_FLAG_IDX];
     196           0 :     aResultSeg[SWEEP_FLAG_IDX]     = aSeg2[SWEEP_FLAG_IDX];
     197             :   }
     198             : 
     199             :   // SECOND: Add the arguments that are supposed to be added.
     200             :   // (The 1's below are to account for segment type)
     201           0 :   uint32_t numArgs = SVGPathSegUtils::ArgCountForType(segType);
     202           0 :   for (uint32_t i = 1; i < 1 + numArgs; ++i) {
     203             :      // Need to skip arc flags for arc-type segments. (already handled them)
     204           0 :     if (!(isArcType && (i == LARGE_ARC_FLAG_IDX || i == SWEEP_FLAG_IDX))) {
     205           0 :       aResultSeg[i] = (aSeg1 ? aCoeff1 * aSeg1[i] : 0.0) + aCoeff2 * aSeg2[i];
     206             :     }
     207             :   }
     208             : 
     209             :   // FINALLY: Shift iterators forward. ("1+" is to include seg-type)
     210           0 :   if (aSeg1) {
     211           0 :     aSeg1 += 1 + numArgs;
     212             :   }
     213           0 :   aSeg2 += 1 + numArgs;
     214           0 :   aResultSeg += 1 + numArgs;
     215           0 : }
     216             : 
     217             : /**
     218             :  * Helper function for Add & Interpolate, to add multiples of two path-segment
     219             :  * lists.
     220             :  *
     221             :  * NOTE: aList1 and aList2 are assumed to have their segment-types and
     222             :  * segment-count match exactly (unless aList1 is an identity value).
     223             :  *
     224             :  * NOTE: aResult, the output list, is expected to either be an identity value
     225             :  * (in which case we'll grow it) *or* to already have the exactly right length
     226             :  * (e.g. in cases where aList1 and aResult are actually the same list).
     227             :  *
     228             :  * @param aCoeff1    The coefficient to use on the first path segment list.
     229             :  * @param aList1     The first path segment list. Allowed to be identity.
     230             :  * @param aCoeff2    The coefficient to use on the second path segment list.
     231             :  * @param aList2     The second path segment list.
     232             :  * @param [out] aResultSeg The resulting path segment list. Allowed to be
     233             :  *                         identity, in which case we'll grow it to the right
     234             :  *                         size. Also allowed to be the same list as aList1.
     235             :  */
     236             : static nsresult
     237           0 : AddWeightedPathSegLists(double aCoeff1, const SVGPathDataAndInfo& aList1,
     238             :                         double aCoeff2, const SVGPathDataAndInfo& aList2,
     239             :                         SVGPathDataAndInfo& aResult)
     240             : {
     241           0 :   MOZ_ASSERT(aCoeff1 >= 0.0 && aCoeff2 >= 0.0,
     242             :              "expecting non-negative coefficients");
     243           0 :   MOZ_ASSERT(!aList2.IsIdentity(),
     244             :              "expecting 2nd list to be non-identity");
     245           0 :   MOZ_ASSERT(aList1.IsIdentity() || aList1.Length() == aList2.Length(),
     246             :              "expecting 1st list to be identity or to have same "
     247             :              "length as 2nd list");
     248           0 :   MOZ_ASSERT(aResult.IsIdentity() || aResult.Length() == aList2.Length(),
     249             :              "expecting result list to be identity or to have same "
     250             :              "length as 2nd list");
     251             : 
     252             :   SVGPathDataAndInfo::const_iterator iter1, end1;
     253           0 :   if (aList1.IsIdentity()) {
     254           0 :     iter1 = end1 = nullptr; // indicate that this is an identity list
     255             :   } else {
     256           0 :     iter1 = aList1.begin();
     257           0 :     end1 = aList1.end();
     258             :   }
     259           0 :   SVGPathDataAndInfo::const_iterator iter2 = aList2.begin();
     260           0 :   SVGPathDataAndInfo::const_iterator end2 = aList2.end();
     261             : 
     262             :   // Grow |aResult| if necessary. (NOTE: It's possible that aResult and aList1
     263             :   // are the same list, so this may implicitly resize aList1. That's fine,
     264             :   // because in that case, we will have already set iter1 to nullptr above, to
     265             :   // record that our first operand is an identity value.)
     266           0 :   if (aResult.IsIdentity()) {
     267           0 :     if (!aResult.SetLength(aList2.Length())) {
     268           0 :       return NS_ERROR_OUT_OF_MEMORY;
     269             :     }
     270           0 :     aResult.SetElement(aList2.Element()); // propagate target element info!
     271             :   }
     272             : 
     273           0 :   SVGPathDataAndInfo::iterator resultIter = aResult.begin();
     274             : 
     275           0 :   while ((!iter1 || iter1 != end1) &&
     276           0 :          iter2 != end2) {
     277             :     AddWeightedPathSegs(aCoeff1, iter1,
     278             :                         aCoeff2, iter2,
     279           0 :                         resultIter);
     280             :   }
     281           0 :   MOZ_ASSERT((!iter1 || iter1 == end1) &&
     282             :              iter2 == end2 &&
     283             :              resultIter == aResult.end(),
     284             :              "Very, very bad - path data corrupt");
     285           0 :   return NS_OK;
     286             : }
     287             : 
     288             : static void
     289           0 : ConvertPathSegmentData(SVGPathDataAndInfo::const_iterator& aStart,
     290             :                        SVGPathDataAndInfo::const_iterator& aEnd,
     291             :                        SVGPathDataAndInfo::iterator& aResult,
     292             :                        SVGPathTraversalState& aState)
     293             : {
     294           0 :   uint32_t startType = SVGPathSegUtils::DecodeType(*aStart);
     295           0 :   uint32_t endType = SVGPathSegUtils::DecodeType(*aEnd);
     296             : 
     297             :   uint32_t segmentLengthIncludingType =
     298           0 :       1 + SVGPathSegUtils::ArgCountForType(startType);
     299             : 
     300           0 :   SVGPathDataAndInfo::const_iterator pResultSegmentBegin = aResult;
     301             : 
     302           0 :   if (startType == endType) {
     303             :     // No conversion need, just directly copy aStart.
     304           0 :     aEnd += segmentLengthIncludingType;
     305           0 :     while (segmentLengthIncludingType) {
     306           0 :       *aResult++ = *aStart++;
     307           0 :       --segmentLengthIncludingType;
     308             :     }
     309           0 :     SVGPathSegUtils::TraversePathSegment(pResultSegmentBegin, aState);
     310           0 :     return;
     311             :   }
     312             : 
     313           0 :   MOZ_ASSERT
     314             :       (SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType),
     315             :        "Incompatible path segment types passed to ConvertPathSegmentData!");
     316             : 
     317             :   RelativenessAdjustmentType adjustmentType =
     318           0 :     SVGPathSegUtils::IsRelativeType(startType) ? eRelativeToAbsolute
     319           0 :                                                : eAbsoluteToRelative;
     320             : 
     321           0 :   MOZ_ASSERT
     322             :     (segmentLengthIncludingType ==
     323             :        1 + SVGPathSegUtils::ArgCountForType(endType),
     324             :      "Compatible path segment types for interpolation had different lengths!");
     325             : 
     326           0 :   aResult[0] = aEnd[0];
     327             : 
     328           0 :   switch (endType) {
     329             :     case PATHSEG_LINETO_HORIZONTAL_ABS:
     330             :     case PATHSEG_LINETO_HORIZONTAL_REL:
     331           0 :       aResult[1] = aStart[1] +
     332           0 :         (adjustmentType == eRelativeToAbsolute ? 1 : -1) * aState.pos.x;
     333           0 :       break;
     334             :     case PATHSEG_LINETO_VERTICAL_ABS:
     335             :     case PATHSEG_LINETO_VERTICAL_REL:
     336           0 :       aResult[1] = aStart[1] +
     337           0 :         (adjustmentType == eRelativeToAbsolute  ? 1 : -1) * aState.pos.y;
     338           0 :       break;
     339             :     case PATHSEG_ARC_ABS:
     340             :     case PATHSEG_ARC_REL:
     341           0 :       aResult[1] = aStart[1];
     342           0 :       aResult[2] = aStart[2];
     343           0 :       aResult[3] = aStart[3];
     344           0 :       aResult[4] = aStart[4];
     345           0 :       aResult[5] = aStart[5];
     346           0 :       aResult[6] = aStart[6];
     347           0 :       aResult[7] = aStart[7];
     348           0 :       AdjustSegmentForRelativeness(adjustmentType, aResult + 6, aState);
     349           0 :       break;
     350             :     case PATHSEG_CURVETO_CUBIC_ABS:
     351             :     case PATHSEG_CURVETO_CUBIC_REL:
     352           0 :       aResult[5] = aStart[5];
     353           0 :       aResult[6] = aStart[6];
     354           0 :       AdjustSegmentForRelativeness(adjustmentType, aResult + 5, aState);
     355             :       MOZ_FALLTHROUGH;
     356             :     case PATHSEG_CURVETO_QUADRATIC_ABS:
     357             :     case PATHSEG_CURVETO_QUADRATIC_REL:
     358             :     case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
     359             :     case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
     360           0 :       aResult[3] = aStart[3];
     361           0 :       aResult[4] = aStart[4];
     362           0 :       AdjustSegmentForRelativeness(adjustmentType, aResult + 3, aState);
     363             :       MOZ_FALLTHROUGH;
     364             :     case PATHSEG_MOVETO_ABS:
     365             :     case PATHSEG_MOVETO_REL:
     366             :     case PATHSEG_LINETO_ABS:
     367             :     case PATHSEG_LINETO_REL:
     368             :     case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
     369             :     case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
     370           0 :       aResult[1] = aStart[1];
     371           0 :       aResult[2] = aStart[2];
     372           0 :       AdjustSegmentForRelativeness(adjustmentType, aResult + 1, aState);
     373           0 :       break;
     374             :   }
     375             : 
     376           0 :   SVGPathSegUtils::TraversePathSegment(pResultSegmentBegin, aState);
     377           0 :   aStart += segmentLengthIncludingType;
     378           0 :   aEnd += segmentLengthIncludingType;
     379           0 :   aResult += segmentLengthIncludingType;
     380             : }
     381             : 
     382             : static void
     383           0 : ConvertAllPathSegmentData(SVGPathDataAndInfo::const_iterator aStart,
     384             :                           SVGPathDataAndInfo::const_iterator aStartDataEnd,
     385             :                           SVGPathDataAndInfo::const_iterator aEnd,
     386             :                           SVGPathDataAndInfo::const_iterator aEndDataEnd,
     387             :                           SVGPathDataAndInfo::iterator aResult)
     388             : {
     389           0 :   SVGPathTraversalState state;
     390           0 :   state.mode = SVGPathTraversalState::eUpdateOnlyStartAndCurrentPos;
     391           0 :   while (aStart < aStartDataEnd && aEnd < aEndDataEnd) {
     392           0 :     ConvertPathSegmentData(aStart, aEnd, aResult, state);
     393             :   }
     394           0 :   MOZ_ASSERT(aStart == aStartDataEnd && aEnd == aEndDataEnd,
     395             :              "Failed to convert all path segment data! (Corrupt?)");
     396           0 : }
     397             : 
     398             : nsresult
     399           0 : SVGPathSegListSMILType::Add(nsSMILValue& aDest,
     400             :                             const nsSMILValue& aValueToAdd,
     401             :                             uint32_t aCount) const
     402             : {
     403           0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
     404           0 :   NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
     405             : 
     406             :   SVGPathDataAndInfo& dest =
     407           0 :     *static_cast<SVGPathDataAndInfo*>(aDest.mU.mPtr);
     408             :   const SVGPathDataAndInfo& valueToAdd =
     409           0 :     *static_cast<const SVGPathDataAndInfo*>(aValueToAdd.mU.mPtr);
     410             : 
     411           0 :   if (valueToAdd.IsIdentity()) { // Adding identity value - no-op
     412           0 :     return NS_OK;
     413             :   }
     414             : 
     415           0 :   if (!dest.IsIdentity()) {
     416             :     // Neither value is identity; make sure they're compatible.
     417           0 :     MOZ_ASSERT(dest.Element() == valueToAdd.Element(),
     418             :                "adding values from different elements...?");
     419             : 
     420           0 :     PathInterpolationResult check = CanInterpolate(dest, valueToAdd);
     421           0 :     if (check == eCannotInterpolate) {
     422             :       // SVGContentUtils::ReportToConsole - can't add path segment lists with
     423             :       // different numbers of segments, with arcs that have different flag
     424             :       // values, or with incompatible segment types.
     425           0 :       return NS_ERROR_FAILURE;
     426             :     }
     427           0 :     if (check == eRequiresConversion) {
     428             :       // Convert dest, in-place, to match the types in valueToAdd:
     429           0 :       ConvertAllPathSegmentData(dest.begin(), dest.end(),
     430             :                                 valueToAdd.begin(), valueToAdd.end(),
     431           0 :                                 dest.begin());
     432             :     }
     433             :   }
     434             : 
     435           0 :   return AddWeightedPathSegLists(1.0, dest, aCount, valueToAdd, dest);
     436             : }
     437             : 
     438             : nsresult
     439           0 : SVGPathSegListSMILType::ComputeDistance(const nsSMILValue& aFrom,
     440             :                                         const nsSMILValue& aTo,
     441             :                                         double& aDistance) const
     442             : {
     443           0 :   NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
     444           0 :   NS_PRECONDITION(aTo.mType == this, "Incompatible SMIL type");
     445             : 
     446             :   // See https://bugzilla.mozilla.org/show_bug.cgi?id=522306#c18
     447             : 
     448             :   // SVGContentUtils::ReportToConsole
     449           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     450             : }
     451             : 
     452             : nsresult
     453           0 : SVGPathSegListSMILType::Interpolate(const nsSMILValue& aStartVal,
     454             :                                     const nsSMILValue& aEndVal,
     455             :                                     double aUnitDistance,
     456             :                                     nsSMILValue& aResult) const
     457             : {
     458           0 :   NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
     459             :                   "Trying to interpolate different types");
     460           0 :   NS_PRECONDITION(aStartVal.mType == this,
     461             :                   "Unexpected types for interpolation");
     462           0 :   NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
     463             : 
     464             :   const SVGPathDataAndInfo& start =
     465           0 :     *static_cast<const SVGPathDataAndInfo*>(aStartVal.mU.mPtr);
     466             :   const SVGPathDataAndInfo& end =
     467           0 :     *static_cast<const SVGPathDataAndInfo*>(aEndVal.mU.mPtr);
     468             :   SVGPathDataAndInfo& result =
     469           0 :     *static_cast<SVGPathDataAndInfo*>(aResult.mU.mPtr);
     470           0 :   MOZ_ASSERT(result.IsIdentity(),
     471             :              "expecting outparam to start out as identity");
     472             : 
     473           0 :   PathInterpolationResult check = CanInterpolate(start, end);
     474             : 
     475           0 :   if (check == eCannotInterpolate) {
     476             :     // SVGContentUtils::ReportToConsole - can't interpolate path segment lists with
     477             :     // different numbers of segments, with arcs with different flag values, or
     478             :     // with incompatible segment types.
     479           0 :     return NS_ERROR_FAILURE;
     480             :   }
     481             : 
     482           0 :   const SVGPathDataAndInfo* startListToUse = &start;
     483           0 :   if (check == eRequiresConversion) {
     484             :     // Can't convert |start| in-place, since it's const. Instead, we copy it
     485             :     // into |result|, converting the types as we go, and use that as our start.
     486           0 :     if (!result.SetLength(end.Length())) {
     487           0 :       return NS_ERROR_OUT_OF_MEMORY;
     488             :     }
     489           0 :     result.SetElement(end.Element()); // propagate target element info!
     490             : 
     491           0 :     ConvertAllPathSegmentData(start.begin(), start.end(),
     492             :                               end.begin(), end.end(),
     493           0 :                               result.begin());
     494           0 :     startListToUse = &result;
     495             :   }
     496             : 
     497           0 :   return AddWeightedPathSegLists(1.0 - aUnitDistance, *startListToUse,
     498           0 :                                  aUnitDistance, end, result);
     499             : }
     500             : 
     501             : } // namespace mozilla

Generated by: LCOV version 1.13