• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2    Copyright (C) 2002, 2003 The Karbon Developers
3                  2006       Alexander Kellett <lypanov@kde.org>
4                  2006, 2007 Rob Buis <buis@kde.org>
5    Copyrigth (C) 2007, 2009 Apple, Inc.  All rights reserved.
6 
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Library General Public
9    License as published by the Free Software Foundation; either
10    version 2 of the License, or (at your option) any later version.
11 
12    This library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Library General Public License for more details.
16 
17    You should have received a copy of the GNU Library General Public License
18    along with this library; see the file COPYING.LIB.  If not, write to
19    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.
21 */
22 
23 #include "config.h"
24 #if ENABLE(SVG)
25 #include "SVGParserUtilities.h"
26 
27 #include "ExceptionCode.h"
28 #include "FloatConversion.h"
29 #include "FloatPoint.h"
30 #include "Path.h"
31 #include "PlatformString.h"
32 #include "SVGPathSegList.h"
33 #include "SVGPathSegArc.h"
34 #include "SVGPathSegClosePath.h"
35 #include "SVGPathSegCurvetoCubic.h"
36 #include "SVGPathSegCurvetoCubicSmooth.h"
37 #include "SVGPathSegCurvetoQuadratic.h"
38 #include "SVGPathSegCurvetoQuadraticSmooth.h"
39 #include "SVGPathSegLineto.h"
40 #include "SVGPathSegLinetoHorizontal.h"
41 #include "SVGPathSegLinetoVertical.h"
42 #include "SVGPathSegList.h"
43 #include "SVGPathSegMoveto.h"
44 #include "SVGPointList.h"
45 #include "SVGPathElement.h"
46 #include <math.h>
47 #include <wtf/MathExtras.h>
48 
49 namespace WebCore {
50 
51 /* We use this generic _parseNumber function to allow the Path parsing code to work
52  * at a higher precision internally, without any unnecessary runtime cost or code
53  * complexity
54  */
_parseNumber(const UChar * & ptr,const UChar * end,FloatType & number,bool skip)55 template <typename FloatType> static bool _parseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip)
56 {
57     int integer, exponent;
58     FloatType decimal, frac;
59     int sign, expsign;
60     const UChar* start = ptr;
61 
62     exponent = 0;
63     integer = 0;
64     frac = 1;
65     decimal = 0;
66     sign = 1;
67     expsign = 1;
68 
69     // read the sign
70     if (ptr < end && *ptr == '+')
71         ptr++;
72     else if (ptr < end && *ptr == '-') {
73         ptr++;
74         sign = -1;
75     }
76 
77     if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
78         // The first character of a number must be one of [0-9+-.]
79         return false;
80 
81     // read the integer part
82     while (ptr < end && *ptr >= '0' && *ptr <= '9')
83         integer = (integer * 10) + *(ptr++) - '0';
84 
85     if (ptr < end && *ptr == '.') { // read the decimals
86         ptr++;
87 
88         // There must be a least one digit following the .
89         if (ptr >= end || *ptr < '0' || *ptr > '9')
90             return false;
91 
92         while (ptr < end && *ptr >= '0' && *ptr <= '9')
93             decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
94     }
95 
96     // read the exponent part
97     if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E')
98         && (ptr[1] != 'x' && ptr[1] != 'm')) {
99         ptr++;
100 
101         // read the sign of the exponent
102         if (*ptr == '+')
103             ptr++;
104         else if (*ptr == '-') {
105             ptr++;
106             expsign = -1;
107         }
108 
109         // There must be an exponent
110         if (ptr >= end || *ptr < '0' || *ptr > '9')
111             return false;
112 
113         while (ptr < end && *ptr >= '0' && *ptr <= '9') {
114             exponent *= 10;
115             exponent += *ptr - '0';
116             ptr++;
117         }
118     }
119 
120     number = integer + decimal;
121     number *= sign * static_cast<FloatType>(pow(10.0, expsign * exponent));
122 
123     if (start == ptr)
124         return false;
125 
126     if (skip)
127         skipOptionalSpacesOrDelimiter(ptr, end);
128 
129     return true;
130 }
131 
parseNumber(const UChar * & ptr,const UChar * end,float & number,bool skip)132 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip)
133 {
134     return _parseNumber(ptr, end, number, skip);
135 }
136 
137 // Only used for parsing Paths
parseNumber(const UChar * & ptr,const UChar * end,double & number,bool skip=true)138 static bool parseNumber(const UChar*& ptr, const UChar* end, double& number, bool skip = true)
139 {
140     return _parseNumber(ptr, end, number, skip);
141 }
142 
parseNumberOptionalNumber(const String & s,float & x,float & y)143 bool parseNumberOptionalNumber(const String& s, float& x, float& y)
144 {
145     if (s.isEmpty())
146         return false;
147     const UChar* cur = s.characters();
148     const UChar* end = cur + s.length();
149 
150     if (!parseNumber(cur, end, x))
151         return false;
152 
153     if (cur == end)
154         y = x;
155     else if (!parseNumber(cur, end, y, false))
156         return false;
157 
158     return cur == end;
159 }
160 
pointsListFromSVGData(SVGPointList * pointsList,const String & points)161 bool pointsListFromSVGData(SVGPointList* pointsList, const String& points)
162 {
163     if (points.isEmpty())
164         return true;
165     const UChar* cur = points.characters();
166     const UChar* end = cur + points.length();
167 
168     skipOptionalSpaces(cur, end);
169 
170     bool delimParsed = false;
171     while (cur < end) {
172         delimParsed = false;
173         float xPos = 0.0f;
174         if (!parseNumber(cur, end, xPos))
175            return false;
176 
177         float yPos = 0.0f;
178         if (!parseNumber(cur, end, yPos, false))
179             return false;
180 
181         skipOptionalSpaces(cur, end);
182 
183         if (cur < end && *cur == ',') {
184             delimParsed = true;
185             cur++;
186         }
187         skipOptionalSpaces(cur, end);
188 
189         ExceptionCode ec = 0;
190         pointsList->appendItem(FloatPoint(xPos, yPos), ec);
191     }
192     return cur == end && !delimParsed;
193 }
194 
195     /**
196      * Parser for svg path data, contained in the d attribute.
197      *
198      * The parser delivers encountered commands and parameters by calling
199      * methods that correspond to those commands. Clients have to derive
200      * from this class and implement the abstract command methods.
201      *
202      * There are two operating modes. By default the parser just delivers unaltered
203      * svg path data commands and parameters. In the second mode, it will convert all
204      * relative coordinates to absolute ones, and convert all curves to cubic beziers.
205      */
206     class SVGPathParser {
207     public:
~SVGPathParser()208         virtual ~SVGPathParser() { }
209         bool parseSVG(const String& d, bool process = false);
210 
211     protected:
212         virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true) = 0;
213         virtual void svgLineTo(double x1, double y1, bool abs = true) = 0;
svgLineToHorizontal(double,bool=true)214         virtual void svgLineToHorizontal(double, bool /*abs*/ = true) { }
svgLineToVertical(double,bool=true)215         virtual void svgLineToVertical(double /*y*/, bool /*abs*/ = true) { }
216         virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) = 0;
svgCurveToCubicSmooth(double,double,double,double,bool=true)217         virtual void svgCurveToCubicSmooth(double /*x*/, double /*y*/, double /*x2*/, double /*y2*/, bool /*abs*/ = true) { }
svgCurveToQuadratic(double,double,double,double,bool=true)218         virtual void svgCurveToQuadratic(double /*x*/, double /*y*/, double /*x1*/, double /*y1*/, bool /*abs*/ = true) { }
svgCurveToQuadraticSmooth(double,double,bool=true)219         virtual void svgCurveToQuadraticSmooth(double /*x*/, double /*y*/, bool /*abs*/ = true) { }
svgArcTo(double,double,double,double,double,bool,bool,bool=true)220         virtual void svgArcTo(double /*x*/, double /*y*/, double /*r1*/, double /*r2*/, double /*angle*/, bool /*largeArcFlag*/, bool /*sweepFlag*/, bool /*abs*/ = true) { }
221         virtual void svgClosePath() = 0;
222 
223     private:
224         void calculateArc(bool relative, double& curx, double& cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag);
225     };
226 
parseSVG(const String & s,bool process)227 bool SVGPathParser::parseSVG(const String& s, bool process)
228 {
229     const UChar* ptr = s.characters();
230     const UChar* end = ptr + s.length();
231 
232     double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
233     double px1, py1, px2, py2, px3, py3;
234     bool closed = true;
235 
236     if (!skipOptionalSpaces(ptr, end)) // skip any leading spaces
237         return false;
238 
239     char command = *(ptr++), lastCommand = ' ';
240     if (command != 'm' && command != 'M') // path must start with moveto
241         return false;
242 
243     subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
244     while (1) {
245         skipOptionalSpaces(ptr, end); // skip spaces between command and first coord
246 
247         bool relative = false;
248 
249         switch(command)
250         {
251             case 'm':
252                 relative = true;
253             case 'M':
254             {
255                 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
256                     return false;
257 
258                 if (process) {
259                     subpathx = curx = relative ? curx + tox : tox;
260                     subpathy = cury = relative ? cury + toy : toy;
261 
262                     svgMoveTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury), closed);
263                 } else
264                     svgMoveTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), closed, !relative);
265                 closed = false;
266                 break;
267             }
268             case 'l':
269                 relative = true;
270             case 'L':
271             {
272                 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
273                     return false;
274 
275                 if (process) {
276                     curx = relative ? curx + tox : tox;
277                     cury = relative ? cury + toy : toy;
278 
279                     svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
280                 }
281                 else
282                     svgLineTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
283                 break;
284             }
285             case 'h':
286             {
287                 if (!parseNumber(ptr, end, tox))
288                     return false;
289                 if (process) {
290                     curx = curx + tox;
291                     svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
292                 }
293                 else
294                     svgLineToHorizontal(narrowPrecisionToFloat(tox), false);
295                 break;
296             }
297             case 'H':
298             {
299                 if (!parseNumber(ptr, end, tox))
300                     return false;
301                 if (process) {
302                     curx = tox;
303                     svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
304                 }
305                 else
306                     svgLineToHorizontal(narrowPrecisionToFloat(tox));
307                 break;
308             }
309             case 'v':
310             {
311                 if (!parseNumber(ptr, end, toy))
312                     return false;
313                 if (process) {
314                     cury = cury + toy;
315                     svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
316                 }
317                 else
318                     svgLineToVertical(narrowPrecisionToFloat(toy), false);
319                 break;
320             }
321             case 'V':
322             {
323                 if (!parseNumber(ptr, end, toy))
324                     return false;
325                 if (process) {
326                     cury = toy;
327                     svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
328                 }
329                 else
330                     svgLineToVertical(narrowPrecisionToFloat(toy));
331                 break;
332             }
333             case 'z':
334             case 'Z':
335             {
336                 // reset curx, cury for next path
337                 if (process) {
338                     curx = subpathx;
339                     cury = subpathy;
340                 }
341                 closed = true;
342                 svgClosePath();
343                 break;
344             }
345             case 'c':
346                 relative = true;
347             case 'C':
348             {
349                 if (!parseNumber(ptr, end, x1)  || !parseNumber(ptr, end, y1) ||
350                     !parseNumber(ptr, end, x2)  || !parseNumber(ptr, end, y2) ||
351                     !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
352                     return false;
353 
354                 if (process) {
355                     px1 = relative ? curx + x1 : x1;
356                     py1 = relative ? cury + y1 : y1;
357                     px2 = relative ? curx + x2 : x2;
358                     py2 = relative ? cury + y2 : y2;
359                     px3 = relative ? curx + tox : tox;
360                     py3 = relative ? cury + toy : toy;
361 
362                     svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2),
363                                     narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3));
364 
365                     contrlx = relative ? curx + x2 : x2;
366                     contrly = relative ? cury + y2 : y2;
367                     curx = relative ? curx + tox : tox;
368                     cury = relative ? cury + toy : toy;
369                 }
370                 else
371                     svgCurveToCubic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), narrowPrecisionToFloat(x2),
372                                     narrowPrecisionToFloat(y2), narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
373 
374                 break;
375             }
376             case 's':
377                 relative = true;
378             case 'S':
379             {
380                 if (!parseNumber(ptr, end, x2)  || !parseNumber(ptr, end, y2) ||
381                     !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
382                     return false;
383 
384                 if (!(lastCommand == 'c' || lastCommand == 'C' ||
385                      lastCommand == 's' || lastCommand == 'S')) {
386                     contrlx = curx;
387                     contrly = cury;
388                 }
389 
390                 if (process) {
391                     px1 = 2 * curx - contrlx;
392                     py1 = 2 * cury - contrly;
393                     px2 = relative ? curx + x2 : x2;
394                     py2 = relative ? cury + y2 : y2;
395                     px3 = relative ? curx + tox : tox;
396                     py3 = relative ? cury + toy : toy;
397 
398                     svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2),
399                                     narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3));
400 
401                     contrlx = relative ? curx + x2 : x2;
402                     contrly = relative ? cury + y2 : y2;
403                     curx = relative ? curx + tox : tox;
404                     cury = relative ? cury + toy : toy;
405                 }
406                 else
407                     svgCurveToCubicSmooth(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2),
408                                           narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
409                 break;
410             }
411             case 'q':
412                 relative = true;
413             case 'Q':
414             {
415                 if (!parseNumber(ptr, end, x1)  || !parseNumber(ptr, end, y1) ||
416                     !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
417                     return false;
418 
419                 if (process) {
420                     px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
421                     py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
422                     px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
423                     py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
424                     px3 = relative ? curx + tox : tox;
425                     py3 = relative ? cury + toy : toy;
426 
427                     svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2),
428                                     narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3));
429 
430                     contrlx = relative ? curx + x1 : x1;
431                     contrly = relative ? cury + y1 : y1;
432                     curx = relative ? curx + tox : tox;
433                     cury = relative ? cury + toy : toy;
434                 }
435                 else
436                     svgCurveToQuadratic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
437                                         narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
438                 break;
439             }
440             case 't':
441                 relative = true;
442             case 'T':
443             {
444                 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
445                     return false;
446                 if (!(lastCommand == 'q' || lastCommand == 'Q' ||
447                      lastCommand == 't' || lastCommand == 'T')) {
448                     contrlx = curx;
449                     contrly = cury;
450                 }
451 
452                 if (process) {
453                     xc = 2 * curx - contrlx;
454                     yc = 2 * cury - contrly;
455 
456                     px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
457                     py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
458                     px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
459                     py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
460                     px3 = relative ? curx + tox : tox;
461                     py3 = relative ? cury + toy : toy;
462 
463                     svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2),
464                                     narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3));
465 
466                     contrlx = xc;
467                     contrly = yc;
468                     curx = relative ? curx + tox : tox;
469                     cury = relative ? cury + toy : toy;
470                 }
471                 else
472                     svgCurveToQuadraticSmooth(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
473                 break;
474             }
475             case 'a':
476                 relative = true;
477             case 'A':
478             {
479                 bool largeArc, sweep;
480                 double angle, rx, ry;
481                 if (!parseNumber(ptr, end, rx)    || !parseNumber(ptr, end, ry) ||
482                     !parseNumber(ptr, end, angle) || !parseNumber(ptr, end, tox))
483                     return false;
484                 largeArc = tox == 1;
485                 if (!parseNumber(ptr, end, tox))
486                     return false;
487                 sweep = tox == 1;
488                 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
489                     return false;
490 
491                 // Spec: radii are nonnegative numbers
492                 rx = fabs(rx);
493                 ry = fabs(ry);
494 
495                 if (process)
496                     calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
497                 else
498                     svgArcTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), narrowPrecisionToFloat(rx), narrowPrecisionToFloat(ry),
499                              narrowPrecisionToFloat(angle), largeArc, sweep, !relative);
500                 break;
501             }
502             default:
503                 // FIXME: An error should go to the JavaScript console, or the like.
504                 return false;
505         }
506         lastCommand = command;
507 
508         if (ptr >= end)
509             return true;
510 
511         // Check for remaining coordinates in the current command.
512         if ((*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) &&
513             (command != 'z' && command != 'Z')) {
514             if (command == 'M')
515                 command = 'L';
516             else if (command == 'm')
517                 command = 'l';
518         } else
519             command = *(ptr++);
520 
521         if (lastCommand != 'C' && lastCommand != 'c' &&
522             lastCommand != 'S' && lastCommand != 's' &&
523             lastCommand != 'Q' && lastCommand != 'q' &&
524             lastCommand != 'T' && lastCommand != 't') {
525             contrlx = curx;
526             contrly = cury;
527         }
528     }
529 
530     return false;
531 }
532 
533 // This works by converting the SVG arc to "simple" beziers.
534 // For each bezier found a svgToCurve call is done.
535 // Adapted from Niko's code in kdelibs/kdecore/svgicons.
536 // Maybe this can serve in some shared lib? (Rob)
calculateArc(bool relative,double & curx,double & cury,double angle,double x,double y,double r1,double r2,bool largeArcFlag,bool sweepFlag)537 void SVGPathParser::calculateArc(bool relative, double& curx, double& cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
538 {
539     double sin_th, cos_th;
540     double a00, a01, a10, a11;
541     double x0, y0, x1, y1, xc, yc;
542     double d, sfactor, sfactor_sq;
543     double th0, th1, th_arc;
544     int i, n_segs;
545 
546     sin_th = sin(angle * (piDouble / 180.0));
547     cos_th = cos(angle * (piDouble / 180.0));
548 
549     double dx;
550 
551     if (!relative)
552         dx = (curx - x) / 2.0;
553     else
554         dx = -x / 2.0;
555 
556     double dy;
557 
558     if (!relative)
559         dy = (cury - y) / 2.0;
560     else
561         dy = -y / 2.0;
562 
563     double _x1 =  cos_th * dx + sin_th * dy;
564     double _y1 = -sin_th * dx + cos_th * dy;
565     double Pr1 = r1 * r1;
566     double Pr2 = r2 * r2;
567     double Px = _x1 * _x1;
568     double Py = _y1 * _y1;
569 
570     // Spec : check if radii are large enough
571     double check = Px / Pr1 + Py / Pr2;
572     if (check > 1) {
573         r1 = r1 * sqrt(check);
574         r2 = r2 * sqrt(check);
575     }
576 
577     a00 = cos_th / r1;
578     a01 = sin_th / r1;
579     a10 = -sin_th / r2;
580     a11 = cos_th / r2;
581 
582     x0 = a00 * curx + a01 * cury;
583     y0 = a10 * curx + a11 * cury;
584 
585     if (!relative)
586         x1 = a00 * x + a01 * y;
587     else
588         x1 = a00 * (curx + x) + a01 * (cury + y);
589 
590     if (!relative)
591         y1 = a10 * x + a11 * y;
592     else
593         y1 = a10 * (curx + x) + a11 * (cury + y);
594 
595     /* (x0, y0) is current point in transformed coordinate space.
596        (x1, y1) is new point in transformed coordinate space.
597 
598        The arc fits a unit-radius circle in this space.
599     */
600 
601     d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
602 
603     sfactor_sq = 1.0 / d - 0.25;
604 
605     if (sfactor_sq < 0)
606         sfactor_sq = 0;
607 
608     sfactor = sqrt(sfactor_sq);
609 
610     if (sweepFlag == largeArcFlag)
611         sfactor = -sfactor;
612 
613     xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
614     yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
615 
616     /* (xc, yc) is center of the circle. */
617     th0 = atan2(y0 - yc, x0 - xc);
618     th1 = atan2(y1 - yc, x1 - xc);
619 
620     th_arc = th1 - th0;
621     if (th_arc < 0 && sweepFlag)
622         th_arc += 2 * piDouble;
623     else if (th_arc > 0 && !sweepFlag)
624         th_arc -= 2 * piDouble;
625 
626     n_segs = (int) (int) ceil(fabs(th_arc / (piDouble * 0.5 + 0.001)));
627 
628     for(i = 0; i < n_segs; i++) {
629         double sin_th, cos_th;
630         double a00, a01, a10, a11;
631         double x1, y1, x2, y2, x3, y3;
632         double t;
633         double th_half;
634 
635         double _th0 = th0 + i * th_arc / n_segs;
636         double _th1 = th0 + (i + 1) * th_arc / n_segs;
637 
638         sin_th = sin(angle * (piDouble / 180.0));
639         cos_th = cos(angle * (piDouble / 180.0));
640 
641         /* inverse transform compared with rsvg_path_arc */
642         a00 = cos_th * r1;
643         a01 = -sin_th * r2;
644         a10 = sin_th * r1;
645         a11 = cos_th * r2;
646 
647         th_half = 0.5 * (_th1 - _th0);
648         t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
649         x1 = xc + cos(_th0) - t * sin(_th0);
650         y1 = yc + sin(_th0) + t * cos(_th0);
651         x3 = xc + cos(_th1);
652         y3 = yc + sin(_th1);
653         x2 = x3 + t * sin(_th1);
654         y2 = y3 - t * cos(_th1);
655 
656         svgCurveToCubic(narrowPrecisionToFloat(a00 * x1 + a01 * y1), narrowPrecisionToFloat(a10 * x1 + a11 * y1),
657                         narrowPrecisionToFloat(a00 * x2 + a01 * y2), narrowPrecisionToFloat(a10 * x2 + a11 * y2),
658                         narrowPrecisionToFloat(a00 * x3 + a01 * y3), narrowPrecisionToFloat(a10 * x3 + a11 * y3));
659     }
660 
661     if (!relative)
662         curx = x;
663     else
664         curx += x;
665 
666     if (!relative)
667         cury = y;
668     else
669         cury += y;
670 }
671 
672 class PathBuilder : private SVGPathParser {
673 public:
build(Path * path,const String & d)674     bool build(Path* path, const String& d)
675     {
676         Path temporaryPath;
677         m_path = &temporaryPath;
678         if (!parseSVG(d, true))
679             return false;
680         temporaryPath.swap(*path);
681         return true;
682     }
683 
684 private:
svgMoveTo(double x1,double y1,bool closed,bool abs=true)685     virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true)
686     {
687         current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1));
688         current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1));
689         if (closed)
690             m_path->closeSubpath();
691         m_path->moveTo(current);
692     }
svgLineTo(double x1,double y1,bool abs=true)693     virtual void svgLineTo(double x1, double y1, bool abs = true)
694     {
695         current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1));
696         current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1));
697         m_path->addLineTo(current);
698     }
svgCurveToCubic(double x1,double y1,double x2,double y2,double x,double y,bool abs=true)699     virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true)
700     {
701         if (!abs) {
702             x1 += current.x();
703             y1 += current.y();
704             x2 += current.x();
705             y2 += current.y();
706         }
707         current.setX(narrowPrecisionToFloat(abs ? x : current.x() + x));
708         current.setY(narrowPrecisionToFloat(abs ? y : current.y() + y));
709         m_path->addBezierCurveTo(FloatPoint::narrowPrecision(x1, y1), FloatPoint::narrowPrecision(x2, y2), current);
710     }
svgClosePath()711     virtual void svgClosePath()
712     {
713         m_path->closeSubpath();
714     }
715 
716     Path* m_path;
717     FloatPoint current;
718 };
719 
pathFromSVGData(Path & path,const String & d)720 bool pathFromSVGData(Path& path, const String& d)
721 {
722     PathBuilder builder;
723     return builder.build(&path, d);
724 }
725 
726 class SVGPathSegListBuilder : private SVGPathParser {
727 public:
build(SVGPathSegList * segList,const String & d,bool process)728     bool build(SVGPathSegList* segList, const String& d, bool process)
729     {
730         if (!parseSVG(d, process))
731             return false;
732         size_t size = m_vector.size();
733         for (size_t i = 0; i < size; ++i) {
734             ExceptionCode ec;
735             segList->appendItem(m_vector[i].release(), ec);
736         }
737         m_vector.clear();
738         return true;
739     }
740 
741 private:
svgMoveTo(double x1,double y1,bool,bool abs=true)742     virtual void svgMoveTo(double x1, double y1, bool, bool abs = true)
743     {
744         if (abs)
745             m_vector.append(SVGPathElement::createSVGPathSegMovetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)));
746         else
747             m_vector.append(SVGPathElement::createSVGPathSegMovetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)));
748     }
svgLineTo(double x1,double y1,bool abs=true)749     virtual void svgLineTo(double x1, double y1, bool abs = true)
750     {
751         if (abs)
752             m_vector.append(SVGPathElement::createSVGPathSegLinetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)));
753         else
754             m_vector.append(SVGPathElement::createSVGPathSegLinetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)));
755     }
svgLineToHorizontal(double x,bool abs)756     virtual void svgLineToHorizontal(double x, bool abs)
757     {
758         if (abs)
759             m_vector.append(SVGPathElement::createSVGPathSegLinetoHorizontalAbs(narrowPrecisionToFloat(x)));
760         else
761             m_vector.append(SVGPathElement::createSVGPathSegLinetoHorizontalRel(narrowPrecisionToFloat(x)));
762     }
svgLineToVertical(double y,bool abs)763     virtual void svgLineToVertical(double y, bool abs)
764     {
765         if (abs)
766             m_vector.append(SVGPathElement::createSVGPathSegLinetoVerticalAbs(narrowPrecisionToFloat(y)));
767         else
768             m_vector.append(SVGPathElement::createSVGPathSegLinetoVerticalRel(narrowPrecisionToFloat(y)));
769     }
svgCurveToCubic(double x1,double y1,double x2,double y2,double x,double y,bool abs=true)770     virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true)
771     {
772         if (abs)
773             m_vector.append(SVGPathElement::createSVGPathSegCurvetoCubicAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
774                                                                                       narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
775                                                                                       narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)));
776         else
777             m_vector.append(SVGPathElement::createSVGPathSegCurvetoCubicRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
778                                                                                       narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
779                                                                                       narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)));
780     }
svgCurveToCubicSmooth(double x,double y,double x2,double y2,bool abs)781     virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs)
782     {
783         if (abs)
784             m_vector.append(SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2),
785                                                                                             narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
786         else
787             m_vector.append(SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2),
788                                                                                             narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
789     }
svgCurveToQuadratic(double x,double y,double x1,double y1,bool abs)790     virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs)
791     {
792         if (abs)
793             m_vector.append(SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
794                                                                                           narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
795         else
796             m_vector.append(SVGPathElement::createSVGPathSegCurvetoQuadraticRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
797                                                                                           narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
798     }
svgCurveToQuadraticSmooth(double x,double y,bool abs)799     virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs)
800     {
801         if (abs)
802             m_vector.append(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
803         else
804             m_vector.append(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)));
805     }
svgArcTo(double x,double y,double r1,double r2,double angle,bool largeArcFlag,bool sweepFlag,bool abs)806     virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs)
807     {
808         if (abs)
809             m_vector.append(SVGPathElement::createSVGPathSegArcAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
810                                                                              narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2),
811                                                                              narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag));
812         else
813             m_vector.append(SVGPathElement::createSVGPathSegArcRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
814                                                                              narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2),
815                                                                              narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag));
816     }
svgClosePath()817     virtual void svgClosePath()
818     {
819         m_vector.append(SVGPathElement::createSVGPathSegClosePath());
820     }
821 
822     Vector<RefPtr<SVGPathSeg> > m_vector;
823 };
824 
pathSegListFromSVGData(SVGPathSegList * path,const String & d,bool process)825 bool pathSegListFromSVGData(SVGPathSegList* path, const String& d, bool process)
826 {
827     SVGPathSegListBuilder builder;
828     return builder.build(path, d, process);
829 }
830 
parseDelimitedString(const String & input,const char seperator)831 Vector<String> parseDelimitedString(const String& input, const char seperator)
832 {
833     Vector<String> values;
834 
835     const UChar* ptr = input.characters();
836     const UChar* end = ptr + input.length();
837     skipOptionalSpaces(ptr, end);
838 
839     while (ptr < end) {
840         // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
841         const UChar* inputStart = ptr;
842         while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
843             ptr++;
844 
845         if (ptr == inputStart)
846             break;
847 
848         // walk backwards from the ; to ignore any whitespace
849         const UChar* inputEnd = ptr - 1;
850         while (inputStart < inputEnd && isWhitespace(*inputEnd))
851             inputEnd--;
852 
853         values.append(String(inputStart, inputEnd - inputStart + 1));
854         skipOptionalSpacesOrDelimiter(ptr, end, seperator);
855     }
856 
857     return values;
858 }
859 
860 }
861 
862 #endif // ENABLE(SVG)
863