LCOV - code coverage report
Current view: directory - content/svg/content/src - SVGPathSegUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 248 0 0.0 %
Date: 2012-06-02 Functions: 27 0 0.0 %

       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 Mozilla SVG Project code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is the Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "SVGPathSegUtils.h"
      38                 : #include "nsSVGElement.h"
      39                 : #include "nsSVGSVGElement.h"
      40                 : #include "nsSVGPathDataParser.h"
      41                 : #include "nsString.h"
      42                 : #include "nsSVGUtils.h"
      43                 : #include "nsContentUtils.h"
      44                 : #include "nsTextFormatter.h"
      45                 : #include "prdtoa.h"
      46                 : #include <limits>
      47                 : #include "nsMathUtils.h"
      48                 : #include "prtypes.h"
      49                 : 
      50                 : using namespace mozilla;
      51                 : 
      52                 : static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
      53                 : static const PRUint32 MAX_RECURSION = 10;
      54                 : 
      55                 : 
      56                 : /* static */ void
      57               0 : SVGPathSegUtils::GetValueAsString(const float* aSeg, nsAString& aValue)
      58                 : {
      59                 :   // Adding new seg type? Is the formatting below acceptable for the new types?
      60                 :   PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
      61                 :                      nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
      62                 :   PR_STATIC_ASSERT(NS_SVG_PATH_SEG_MAX_ARGS == 7);
      63                 : 
      64               0 :   PRUint32 type = DecodeType(aSeg[0]);
      65               0 :   PRUnichar typeAsChar = GetPathSegTypeAsLetter(type);
      66                 : 
      67                 :   // Special case arcs:
      68               0 :   if (IsArcType(type)) {
      69               0 :     bool largeArcFlag = aSeg[4] != 0.0f;
      70               0 :     bool sweepFlag = aSeg[5] != 0.0f;
      71                 :     nsTextFormatter::ssprintf(aValue,
      72               0 :                               NS_LITERAL_STRING("%c%g,%g %g %d,%d %g,%g").get(),
      73               0 :                               typeAsChar, aSeg[1], aSeg[2], aSeg[3],
      74               0 :                               largeArcFlag, sweepFlag, aSeg[6], aSeg[7]);
      75                 :   } else {
      76                 : 
      77               0 :     switch (ArgCountForType(type)) {
      78                 :     case 0:
      79               0 :       aValue = typeAsChar;
      80               0 :       break;
      81                 : 
      82                 :     case 1:
      83               0 :       nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g").get(),
      84               0 :                                 typeAsChar, aSeg[1]);
      85               0 :       break;
      86                 : 
      87                 :     case 2:
      88               0 :       nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g").get(),
      89               0 :                                 typeAsChar, aSeg[1], aSeg[2]);
      90               0 :       break;
      91                 : 
      92                 :     case 4:
      93               0 :       nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g %g,%g").get(),
      94               0 :                                 typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4]);
      95               0 :       break;
      96                 : 
      97                 :     case 6:
      98                 :       nsTextFormatter::ssprintf(aValue,
      99               0 :                                 NS_LITERAL_STRING("%c%g,%g %g,%g %g,%g").get(),
     100               0 :                                 typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4],
     101               0 :                                 aSeg[5], aSeg[6]);
     102               0 :       break;
     103                 : 
     104                 :     default:
     105               0 :       NS_ABORT_IF_FALSE(false, "Unknown segment type");
     106               0 :       aValue = NS_LITERAL_STRING("<unknown-segment-type>").get();
     107               0 :       return;
     108                 :     }
     109                 :   }
     110                 :   
     111                 :   // nsTextFormatter::ssprintf is one of the nsTextFormatter methods that
     112                 :   // randomly appends '\0' to its output string, which means that the length
     113                 :   // of the output string is one too long. We need to manually remove that '\0'
     114                 :   // until nsTextFormatter is fixed.
     115                 :   //
     116               0 :   if (aValue[aValue.Length() - 1] == PRUnichar('\0')) {
     117               0 :     aValue.SetLength(aValue.Length() - 1);
     118                 :   }
     119                 : }
     120                 : 
     121                 : 
     122                 : static float
     123               0 : CalcDistanceBetweenPoints(const gfxPoint& aP1, const gfxPoint& aP2)
     124                 : {
     125               0 :   return NS_hypot(aP2.x - aP1.x, aP2.y - aP1.y);
     126                 : }
     127                 : 
     128                 : 
     129                 : static void
     130               0 : SplitQuadraticBezier(const gfxPoint* aCurve, gfxPoint* aLeft, gfxPoint* aRight)
     131                 : {
     132               0 :   aLeft[0].x = aCurve[0].x;
     133               0 :   aLeft[0].y = aCurve[0].y;
     134               0 :   aRight[2].x = aCurve[2].x;
     135               0 :   aRight[2].y = aCurve[2].y;
     136               0 :   aLeft[1].x = (aCurve[0].x + aCurve[1].x) / 2;
     137               0 :   aLeft[1].y = (aCurve[0].y + aCurve[1].y) / 2;
     138               0 :   aRight[1].x = (aCurve[1].x + aCurve[2].x) / 2;
     139               0 :   aRight[1].y = (aCurve[1].y + aCurve[2].y) / 2;
     140               0 :   aLeft[2].x = aRight[0].x = (aLeft[1].x + aRight[1].x) / 2;
     141               0 :   aLeft[2].y = aRight[0].y = (aLeft[1].y + aRight[1].y) / 2;
     142               0 : }
     143                 : 
     144                 : static void
     145               0 : SplitCubicBezier(const gfxPoint* aCurve, gfxPoint* aLeft, gfxPoint* aRight)
     146                 : {
     147               0 :   gfxPoint tmp;
     148               0 :   tmp.x = (aCurve[1].x + aCurve[2].x) / 4;
     149               0 :   tmp.y = (aCurve[1].y + aCurve[2].y) / 4;
     150               0 :   aLeft[0].x = aCurve[0].x;
     151               0 :   aLeft[0].y = aCurve[0].y;
     152               0 :   aRight[3].x = aCurve[3].x;
     153               0 :   aRight[3].y = aCurve[3].y;
     154               0 :   aLeft[1].x = (aCurve[0].x + aCurve[1].x) / 2;
     155               0 :   aLeft[1].y = (aCurve[0].y + aCurve[1].y) / 2;
     156               0 :   aRight[2].x = (aCurve[2].x + aCurve[3].x) / 2;
     157               0 :   aRight[2].y = (aCurve[2].y + aCurve[3].y) / 2;
     158               0 :   aLeft[2].x = aLeft[1].x / 2 + tmp.x;
     159               0 :   aLeft[2].y = aLeft[1].y / 2 + tmp.y;
     160               0 :   aRight[1].x = aRight[2].x / 2 + tmp.x;
     161               0 :   aRight[1].y = aRight[2].y / 2 + tmp.y;
     162               0 :   aLeft[3].x = aRight[0].x = (aLeft[2].x + aRight[1].x) / 2;
     163               0 :   aLeft[3].y = aRight[0].y = (aLeft[2].y + aRight[1].y) / 2;
     164               0 : }
     165                 : 
     166                 : static gfxFloat
     167               0 : CalcBezLengthHelper(gfxPoint* aCurve, PRUint32 aNumPts,
     168                 :                     PRUint32 aRecursionCount,
     169                 :                     void (*aSplit)(const gfxPoint*, gfxPoint*, gfxPoint*))
     170                 : {
     171               0 :   gfxPoint left[4];
     172               0 :   gfxPoint right[4];
     173               0 :   gfxFloat length = 0, dist;
     174               0 :   for (PRUint32 i = 0; i < aNumPts - 1; i++) {
     175               0 :     length += CalcDistanceBetweenPoints(aCurve[i], aCurve[i+1]);
     176                 :   }
     177               0 :   dist = CalcDistanceBetweenPoints(aCurve[0], aCurve[aNumPts - 1]);
     178               0 :   if (length - dist > PATH_SEG_LENGTH_TOLERANCE &&
     179                 :       aRecursionCount < MAX_RECURSION) {
     180               0 :     aSplit(aCurve, left, right);
     181               0 :     ++aRecursionCount;
     182               0 :     return CalcBezLengthHelper(left, aNumPts, aRecursionCount, aSplit) +
     183               0 :            CalcBezLengthHelper(right, aNumPts, aRecursionCount, aSplit);
     184                 :   }
     185               0 :   return length;
     186                 : }
     187                 : 
     188                 : static inline gfxFloat
     189               0 : CalcLengthOfCubicBezier(const gfxPoint& aPos, const gfxPoint &aCP1,
     190                 :                         const gfxPoint& aCP2, const gfxPoint &aTo)
     191                 : {
     192               0 :   gfxPoint curve[4] = { aPos, aCP1, aCP2, aTo };
     193               0 :   return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier);
     194                 : }
     195                 : 
     196                 : static inline gfxFloat
     197               0 : CalcLengthOfQuadraticBezier(const gfxPoint& aPos, const gfxPoint& aCP,
     198                 :                             const gfxPoint& aTo)
     199                 : {
     200               0 :   gfxPoint curve[3] = { aPos, aCP, aTo };
     201               0 :   return CalcBezLengthHelper(curve, 3, 0, SplitQuadraticBezier);
     202                 : }
     203                 : 
     204                 : 
     205                 : static void
     206               0 : TraverseClosePath(const float* aArgs, SVGPathTraversalState& aState)
     207                 : {
     208               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     209               0 :     aState.length += CalcDistanceBetweenPoints(aState.pos, aState.start);
     210               0 :     aState.cp1 = aState.cp2 = aState.start;
     211                 :   }
     212               0 :   aState.pos = aState.start;
     213               0 : }
     214                 : 
     215                 : static void
     216               0 : TraverseMovetoAbs(const float* aArgs, SVGPathTraversalState& aState)
     217                 : {
     218               0 :   aState.start = aState.pos = gfxPoint(aArgs[0], aArgs[1]);
     219               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     220                 :     // aState.length is unchanged, since move commands don't affect path length.
     221               0 :     aState.cp1 = aState.cp2 = aState.start;
     222                 :   }
     223               0 : }
     224                 : 
     225                 : static void
     226               0 : TraverseMovetoRel(const float* aArgs, SVGPathTraversalState& aState)
     227                 : {
     228               0 :   aState.start = aState.pos += gfxPoint(aArgs[0], aArgs[1]);
     229               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     230                 :     // aState.length is unchanged, since move commands don't affect path length.
     231               0 :     aState.cp1 = aState.cp2 = aState.start;
     232                 :   }
     233               0 : }
     234                 : 
     235                 : static void
     236               0 : TraverseLinetoAbs(const float* aArgs, SVGPathTraversalState& aState)
     237                 : {
     238               0 :   gfxPoint to(aArgs[0], aArgs[1]);
     239               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     240               0 :     aState.length += CalcDistanceBetweenPoints(aState.pos, to);
     241               0 :     aState.cp1 = aState.cp2 = to;
     242                 :   }
     243               0 :   aState.pos = to;
     244               0 : }
     245                 : 
     246                 : static void
     247               0 : TraverseLinetoRel(const float* aArgs, SVGPathTraversalState& aState)
     248                 : {
     249               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
     250               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     251               0 :     aState.length += CalcDistanceBetweenPoints(aState.pos, to);
     252               0 :     aState.cp1 = aState.cp2 = to;
     253                 :   }
     254               0 :   aState.pos = to;
     255               0 : }
     256                 : 
     257                 : static void
     258               0 : TraverseLinetoHorizontalAbs(const float* aArgs, SVGPathTraversalState& aState)
     259                 : {
     260               0 :   gfxPoint to(aArgs[0], aState.pos.y);
     261               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     262               0 :     aState.length += fabs(to.x - aState.pos.x);
     263               0 :     aState.cp1 = aState.cp2 = to;
     264                 :   }
     265               0 :   aState.pos = to;
     266               0 : }
     267                 : 
     268                 : static void
     269               0 : TraverseLinetoHorizontalRel(const float* aArgs, SVGPathTraversalState& aState)
     270                 : {
     271               0 :   aState.pos.x += aArgs[0];
     272               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     273               0 :     aState.length += fabs(aArgs[0]);
     274               0 :     aState.cp1 = aState.cp2 = aState.pos;
     275                 :   }
     276               0 : }
     277                 : 
     278                 : static void
     279               0 : TraverseLinetoVerticalAbs(const float* aArgs, SVGPathTraversalState& aState)
     280                 : {
     281               0 :   gfxPoint to(aState.pos.x, aArgs[0]);
     282               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     283               0 :     aState.length += fabs(to.y - aState.pos.y);
     284               0 :     aState.cp1 = aState.cp2 = to;
     285                 :   }
     286               0 :   aState.pos = to;
     287               0 : }
     288                 : 
     289                 : static void
     290               0 : TraverseLinetoVerticalRel(const float* aArgs, SVGPathTraversalState& aState)
     291                 : {
     292               0 :   aState.pos.y += aArgs[0];
     293               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     294               0 :     aState.length += fabs(aArgs[0]);
     295               0 :     aState.cp1 = aState.cp2 = aState.pos;
     296                 :   }
     297               0 : }
     298                 : 
     299                 : static void
     300               0 : TraverseCurvetoCubicAbs(const float* aArgs, SVGPathTraversalState& aState)
     301                 : {
     302               0 :   gfxPoint to(aArgs[4], aArgs[5]);
     303               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     304               0 :     gfxPoint cp1(aArgs[0], aArgs[1]);
     305               0 :     gfxPoint cp2(aArgs[2], aArgs[3]);
     306               0 :     aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
     307               0 :     aState.cp2 = cp2;
     308               0 :     aState.cp1 = to;
     309                 :   }
     310               0 :   aState.pos = to;
     311               0 : }
     312                 : 
     313                 : static void
     314               0 : TraverseCurvetoCubicSmoothAbs(const float* aArgs, SVGPathTraversalState& aState)
     315                 : {
     316               0 :   gfxPoint to(aArgs[2], aArgs[3]);
     317               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     318               0 :     gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
     319               0 :     gfxPoint cp2(aArgs[0], aArgs[1]);
     320               0 :     aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
     321               0 :     aState.cp2 = cp2;
     322               0 :     aState.cp1 = to;
     323                 :   }
     324               0 :   aState.pos = to;
     325               0 : }
     326                 : 
     327                 : static void
     328               0 : TraverseCurvetoCubicRel(const float* aArgs, SVGPathTraversalState& aState)
     329                 : {
     330               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[4], aArgs[5]);
     331               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     332               0 :     gfxPoint cp1 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
     333               0 :     gfxPoint cp2 = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
     334               0 :     aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
     335               0 :     aState.cp2 = cp2;
     336               0 :     aState.cp1 = to;
     337                 :   }
     338               0 :   aState.pos = to;
     339               0 : }
     340                 : 
     341                 : static void
     342               0 : TraverseCurvetoCubicSmoothRel(const float* aArgs, SVGPathTraversalState& aState)
     343                 : {
     344               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
     345               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     346               0 :     gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
     347               0 :     gfxPoint cp2 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
     348               0 :     aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
     349               0 :     aState.cp2 = cp2;
     350               0 :     aState.cp1 = to;
     351                 :   }
     352               0 :   aState.pos = to;
     353               0 : }
     354                 : 
     355                 : static void
     356               0 : TraverseCurvetoQuadraticAbs(const float* aArgs, SVGPathTraversalState& aState)
     357                 : {
     358               0 :   gfxPoint to(aArgs[2], aArgs[3]);
     359               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     360               0 :     gfxPoint cp(aArgs[0], aArgs[1]);
     361               0 :     aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
     362               0 :     aState.cp1 = cp;
     363               0 :     aState.cp2 = to;
     364                 :   }
     365               0 :   aState.pos = to;
     366               0 : }
     367                 : 
     368                 : static void
     369               0 : TraverseCurvetoQuadraticSmoothAbs(const float* aArgs,
     370                 :                                   SVGPathTraversalState& aState)
     371                 : {
     372               0 :   gfxPoint to(aArgs[0], aArgs[1]);
     373               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     374               0 :     gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
     375               0 :     aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
     376               0 :     aState.cp1 = cp;
     377               0 :     aState.cp2 = to;
     378                 :   }
     379               0 :   aState.pos = to;
     380               0 : }
     381                 : 
     382                 : static void
     383               0 : TraverseCurvetoQuadraticRel(const float* aArgs, SVGPathTraversalState& aState)
     384                 : {
     385               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
     386               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     387               0 :     gfxPoint cp = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
     388               0 :     aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
     389               0 :     aState.cp1 = cp;
     390               0 :     aState.cp2 = to;
     391                 :   }
     392               0 :   aState.pos = to;
     393               0 : }
     394                 : 
     395                 : static void
     396               0 : TraverseCurvetoQuadraticSmoothRel(const float* aArgs,
     397                 :                                   SVGPathTraversalState& aState)
     398                 : {
     399               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
     400               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     401               0 :     gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
     402               0 :     aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
     403               0 :     aState.cp1 = cp;
     404               0 :     aState.cp2 = to;
     405                 :   }
     406               0 :   aState.pos = to;
     407               0 : }
     408                 : 
     409                 : static void
     410               0 : TraverseArcAbs(const float* aArgs, SVGPathTraversalState& aState)
     411                 : {
     412               0 :   gfxPoint to(aArgs[5], aArgs[6]);
     413               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     414               0 :     float dist = 0;
     415               0 :     gfxPoint radii(aArgs[0], aArgs[1]);
     416                 :     gfxPoint bez[4] = { aState.pos, gfxPoint(0, 0),
     417               0 :                         gfxPoint(0, 0), gfxPoint(0, 0) };
     418               0 :     nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
     419               0 :                                 aArgs[3] != 0, aArgs[4] != 0);
     420               0 :     while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3])) {
     421               0 :       dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
     422               0 :       bez[0] = bez[3];
     423                 :     }
     424               0 :     aState.length += dist;
     425               0 :     aState.cp1 = aState.cp2 = to;
     426                 :   }
     427               0 :   aState.pos = to;
     428               0 : }
     429                 : 
     430                 : static void
     431               0 : TraverseArcRel(const float* aArgs, SVGPathTraversalState& aState)
     432                 : {
     433               0 :   gfxPoint to = aState.pos + gfxPoint(aArgs[5], aArgs[6]);
     434               0 :   if (aState.ShouldUpdateLengthAndControlPoints()) {
     435               0 :     float dist = 0;
     436               0 :     gfxPoint radii(aArgs[0], aArgs[1]);
     437                 :     gfxPoint bez[4] = { aState.pos, gfxPoint(0, 0),
     438               0 :                         gfxPoint(0, 0), gfxPoint(0, 0) };
     439               0 :     nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
     440               0 :                                 aArgs[3] != 0, aArgs[4] != 0);
     441               0 :     while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3])) {
     442               0 :       dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
     443               0 :       bez[0] = bez[3];
     444                 :     }
     445               0 :     aState.length += dist;
     446               0 :     aState.cp1 = aState.cp2 = to;
     447                 :   }
     448               0 :   aState.pos = to;
     449               0 : }
     450                 : 
     451                 : 
     452                 : typedef void (*TraverseFunc)(const float*, SVGPathTraversalState&);
     453                 : 
     454                 : static TraverseFunc gTraverseFuncTable[NS_SVG_PATH_SEG_TYPE_COUNT] = {
     455                 :   nsnull, //  0 == PATHSEG_UNKNOWN
     456                 :   TraverseClosePath,
     457                 :   TraverseMovetoAbs,
     458                 :   TraverseMovetoRel,
     459                 :   TraverseLinetoAbs,
     460                 :   TraverseLinetoRel,
     461                 :   TraverseCurvetoCubicAbs,
     462                 :   TraverseCurvetoCubicRel,
     463                 :   TraverseCurvetoQuadraticAbs,
     464                 :   TraverseCurvetoQuadraticRel,
     465                 :   TraverseArcAbs,
     466                 :   TraverseArcRel,
     467                 :   TraverseLinetoHorizontalAbs,
     468                 :   TraverseLinetoHorizontalRel,
     469                 :   TraverseLinetoVerticalAbs,
     470                 :   TraverseLinetoVerticalRel,
     471                 :   TraverseCurvetoCubicSmoothAbs,
     472                 :   TraverseCurvetoCubicSmoothRel,
     473                 :   TraverseCurvetoQuadraticSmoothAbs,
     474                 :   TraverseCurvetoQuadraticSmoothRel
     475                 : };
     476                 : 
     477                 : /* static */ void
     478               0 : SVGPathSegUtils::TraversePathSegment(const float* aData,
     479                 :                                      SVGPathTraversalState& aState)
     480                 : {
     481                 :   PR_STATIC_ASSERT(NS_ARRAY_LENGTH(gTraverseFuncTable) ==
     482                 :                      NS_SVG_PATH_SEG_TYPE_COUNT);
     483               0 :   PRUint32 type = DecodeType(aData[0]);
     484               0 :   gTraverseFuncTable[type](aData + 1, aState);
     485               0 : }

Generated by: LCOV version 1.7