1 /* This file is part of the KDE project
2 Copyright (C) 2002, 2003 The Karbon Developers
3 2006 Alexander Kellett <lypanov@kde.org>
4 2006, 2007 Rob Buis <buis@kde.org>
5 2007 Apple, Inc. All rights reserved.
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.
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.
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.
24 #include "wtf/Platform.h"
26 #include "xml/Document.h"
27 #include "SVGParserUtilities.h"
29 #include "ExceptionCode.h"
30 #include "FloatConversion.h"
31 #include "FloatPoint.h"
33 #include "PlatformString.h"
34 #include "SVGPathSegList.h"
35 #include "SVGPathSegArc.h"
36 #include "SVGPathSegClosePath.h"
37 #include "SVGPathSegCurvetoCubic.h"
38 #include "SVGPathSegCurvetoCubicSmooth.h"
39 #include "SVGPathSegCurvetoQuadratic.h"
40 #include "SVGPathSegCurvetoQuadraticSmooth.h"
41 #include "SVGPathSegLineto.h"
42 #include "SVGPathSegLinetoHorizontal.h"
43 #include "SVGPathSegLinetoVertical.h"
44 #include "SVGPathSegList.h"
45 #include "SVGPathSegMoveto.h"
46 #include "SVGPointList.h"
47 #include "SVGPathElement.h"
49 #include <wtf/MathExtras.h>
53 /* We use this generic _parseNumber function to allow the Path parsing code to work
54 * at a higher precision internally, without any unnecessary runtime cost or code
57 template <typename FloatType
> static bool _parseNumber(const UChar
*& ptr
, const UChar
* end
, FloatType
& number
, bool skip
)
59 int integer
, exponent
;
60 FloatType decimal
, frac
;
62 const UChar
* start
= ptr
;
72 if (ptr
< end
&& *ptr
== '+')
74 else if (ptr
< end
&& *ptr
== '-') {
79 if (ptr
== end
|| ((*ptr
< '0' || *ptr
> '9') && *ptr
!= '.'))
80 // The first character of a number must be one of [0-9+-.]
83 // read the integer part
84 while (ptr
< end
&& *ptr
>= '0' && *ptr
<= '9')
85 integer
= (integer
* 10) + (ptr
++)->unicode() - '0';
87 if (ptr
< end
&& *ptr
== '.') { // read the decimals
90 // There must be a least one digit following the .
91 if (ptr
>= end
|| *ptr
< '0' || *ptr
> '9')
94 while (ptr
< end
&& *ptr
>= '0' && *ptr
<= '9')
95 decimal
+= ((ptr
++)->unicode() - '0') * (frac
*= static_cast<FloatType
>(0.1));
98 // read the exponent part
99 if (ptr
!= start
&& ptr
+ 1 < end
&& (*ptr
== 'e' || *ptr
== 'E')
100 && (ptr
[1] != 'x' && ptr
[1] != 'm')) {
103 // read the sign of the exponent
106 else if (*ptr
== '-') {
111 // There must be an exponent
112 if (ptr
>= end
|| *ptr
< '0' || *ptr
> '9')
115 while (ptr
< end
&& *ptr
>= '0' && *ptr
<= '9') {
117 exponent
+= ptr
->unicode() - '0';
122 number
= integer
+ decimal
;
123 number
*= sign
* static_cast<FloatType
>(pow(10.0, expsign
* exponent
));
129 skipOptionalSpacesOrDelimiter(ptr
, end
);
134 bool parseNumber(const UChar
*& ptr
, const UChar
* end
, float& number
, bool skip
)
136 return _parseNumber(ptr
, end
, number
, skip
);
139 // Only used for parsing Paths
140 static bool parseNumber(const UChar
*& ptr
, const UChar
* end
, double& number
, bool skip
= true)
142 return _parseNumber(ptr
, end
, number
, skip
);
145 bool parseNumberOptionalNumber(const String
& s
, float& x
, float& y
)
149 const UChar
* cur
= s
.characters();
150 const UChar
* end
= cur
+ s
.length();
152 if (!parseNumber(cur
, end
, x
))
157 else if (!parseNumber(cur
, end
, y
, false))
163 bool pointsListFromSVGData(SVGPointList
* pointsList
, const String
& points
)
165 if (points
.isEmpty())
167 const UChar
* cur
= points
.characters();
168 const UChar
* end
= cur
+ points
.length();
170 skipOptionalSpaces(cur
, end
);
172 bool delimParsed
= false;
176 if (!parseNumber(cur
, end
, xPos
))
180 if (!parseNumber(cur
, end
, yPos
, false))
183 skipOptionalSpaces(cur
, end
);
185 if (cur
< end
&& *cur
== ',') {
189 skipOptionalSpaces(cur
, end
);
191 ExceptionCode ec
= 0;
192 pointsList
->appendItem(FloatPoint(xPos
, yPos
), ec
);
194 return cur
== end
&& !delimParsed
;
198 * Parser for svg path data, contained in the d attribute.
200 * The parser delivers encountered commands and parameters by calling
201 * methods that correspond to those commands. Clients have to derive
202 * from this class and implement the abstract command methods.
204 * There are two operating modes. By default the parser just delivers unaltered
205 * svg path data commands and parameters. In the second mode, it will convert all
206 * relative coordinates to absolute ones, and convert all curves to cubic beziers.
211 virtual ~SVGPathParser() { }
212 bool parseSVG(const String
& d
, bool process
= false);
215 virtual void svgMoveTo(double x1
, double y1
, bool closed
, bool abs
= true) = 0;
216 virtual void svgLineTo(double x1
, double y1
, bool abs
= true) = 0;
217 virtual void svgLineToHorizontal(double x
, bool abs
= true) {}
218 virtual void svgLineToVertical(double y
, bool abs
= true) {}
219 virtual void svgCurveToCubic(double x1
, double y1
, double x2
, double y2
, double x
, double y
, bool abs
= true) = 0;
220 virtual void svgCurveToCubicSmooth(double x
, double y
, double x2
, double y2
, bool abs
= true) {}
221 virtual void svgCurveToQuadratic(double x
, double y
, double x1
, double y1
, bool abs
= true) {}
222 virtual void svgCurveToQuadraticSmooth(double x
, double y
, bool abs
= true) {}
223 virtual void svgArcTo(double x
, double y
, double r1
, double r2
, double angle
, bool largeArcFlag
, bool sweepFlag
, bool abs
= true) {}
224 virtual void svgClosePath() = 0;
226 void calculateArc(bool relative
, double& curx
, double& cury
, double angle
, double x
, double y
, double r1
, double r2
, bool largeArcFlag
, bool sweepFlag
);
229 bool SVGPathParser::parseSVG(const String
& s
, bool process
)
234 const UChar
* ptr
= s
.characters();
235 const UChar
* end
= ptr
+ s
.length();
237 double contrlx
, contrly
, curx
, cury
, subpathx
, subpathy
, tox
, toy
, x1
, y1
, x2
, y2
, xc
, yc
;
238 double px1
, py1
, px2
, py2
, px3
, py3
;
241 if (!skipOptionalSpaces(ptr
, end
)) // skip any leading spaces
244 char command
= (ptr
++)->unicode(), lastCommand
= ' ';// or toLatin1() instead of unicode()???
245 if (command
!= 'm' && command
!= 'M') // path must start with moveto
248 subpathx
= subpathy
= curx
= cury
= contrlx
= contrly
= 0.0;
250 skipOptionalSpaces(ptr
, end
); // skip spaces between command and first coord
252 bool relative
= false;
260 if (!parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
264 subpathx
= curx
= relative
? curx
+ tox
: tox
;
265 subpathy
= cury
= relative
? cury
+ toy
: toy
;
267 svgMoveTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
), closed
);
269 svgMoveTo(narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), closed
, !relative
);
277 if (!parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
281 curx
= relative
? curx
+ tox
: tox
;
282 cury
= relative
? cury
+ toy
: toy
;
284 svgLineTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
));
287 svgLineTo(narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), !relative
);
292 if (!parseNumber(ptr
, end
, tox
))
296 svgLineTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
));
299 svgLineToHorizontal(narrowPrecisionToFloat(tox
), false);
304 if (!parseNumber(ptr
, end
, tox
))
308 svgLineTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
));
311 svgLineToHorizontal(narrowPrecisionToFloat(tox
));
316 if (!parseNumber(ptr
, end
, toy
))
320 svgLineTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
));
323 svgLineToVertical(narrowPrecisionToFloat(toy
), false);
328 if (!parseNumber(ptr
, end
, toy
))
332 svgLineTo(narrowPrecisionToFloat(curx
), narrowPrecisionToFloat(cury
));
335 svgLineToVertical(narrowPrecisionToFloat(toy
));
341 // reset curx, cury for next path
354 if (!parseNumber(ptr
, end
, x1
) || !parseNumber(ptr
, end
, y1
) ||
355 !parseNumber(ptr
, end
, x2
) || !parseNumber(ptr
, end
, y2
) ||
356 !parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
360 px1
= relative
? curx
+ x1
: x1
;
361 py1
= relative
? cury
+ y1
: y1
;
362 px2
= relative
? curx
+ x2
: x2
;
363 py2
= relative
? cury
+ y2
: y2
;
364 px3
= relative
? curx
+ tox
: tox
;
365 py3
= relative
? cury
+ toy
: toy
;
367 svgCurveToCubic(narrowPrecisionToFloat(px1
), narrowPrecisionToFloat(py1
), narrowPrecisionToFloat(px2
),
368 narrowPrecisionToFloat(py2
), narrowPrecisionToFloat(px3
), narrowPrecisionToFloat(py3
));
370 contrlx
= relative
? curx
+ x2
: x2
;
371 contrly
= relative
? cury
+ y2
: y2
;
372 curx
= relative
? curx
+ tox
: tox
;
373 cury
= relative
? cury
+ toy
: toy
;
376 svgCurveToCubic(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
), narrowPrecisionToFloat(x2
),
377 narrowPrecisionToFloat(y2
), narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), !relative
);
385 if (!parseNumber(ptr
, end
, x2
) || !parseNumber(ptr
, end
, y2
) ||
386 !parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
389 if (!(lastCommand
== 'c' || lastCommand
== 'C' ||
390 lastCommand
== 's' || lastCommand
== 'S')) {
396 px1
= 2 * curx
- contrlx
;
397 py1
= 2 * cury
- contrly
;
398 px2
= relative
? curx
+ x2
: x2
;
399 py2
= relative
? cury
+ y2
: y2
;
400 px3
= relative
? curx
+ tox
: tox
;
401 py3
= relative
? cury
+ toy
: toy
;
403 svgCurveToCubic(narrowPrecisionToFloat(px1
), narrowPrecisionToFloat(py1
), narrowPrecisionToFloat(px2
),
404 narrowPrecisionToFloat(py2
), narrowPrecisionToFloat(px3
), narrowPrecisionToFloat(py3
));
406 contrlx
= relative
? curx
+ x2
: x2
;
407 contrly
= relative
? cury
+ y2
: y2
;
408 curx
= relative
? curx
+ tox
: tox
;
409 cury
= relative
? cury
+ toy
: toy
;
412 svgCurveToCubicSmooth(narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
),
413 narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), !relative
);
420 if (!parseNumber(ptr
, end
, x1
) || !parseNumber(ptr
, end
, y1
) ||
421 !parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
425 px1
= relative
? (curx
+ 2 * (x1
+ curx
)) * (1.0 / 3.0) : (curx
+ 2 * x1
) * (1.0 / 3.0);
426 py1
= relative
? (cury
+ 2 * (y1
+ cury
)) * (1.0 / 3.0) : (cury
+ 2 * y1
) * (1.0 / 3.0);
427 px2
= relative
? ((curx
+ tox
) + 2 * (x1
+ curx
)) * (1.0 / 3.0) : (tox
+ 2 * x1
) * (1.0 / 3.0);
428 py2
= relative
? ((cury
+ toy
) + 2 * (y1
+ cury
)) * (1.0 / 3.0) : (toy
+ 2 * y1
) * (1.0 / 3.0);
429 px3
= relative
? curx
+ tox
: tox
;
430 py3
= relative
? cury
+ toy
: toy
;
432 svgCurveToCubic(narrowPrecisionToFloat(px1
), narrowPrecisionToFloat(py1
), narrowPrecisionToFloat(px2
),
433 narrowPrecisionToFloat(py2
), narrowPrecisionToFloat(px3
), narrowPrecisionToFloat(py3
));
435 contrlx
= relative
? curx
+ x1
: x1
;
436 contrly
= relative
? cury
+ y1
: y1
;
437 curx
= relative
? curx
+ tox
: tox
;
438 cury
= relative
? cury
+ toy
: toy
;
441 svgCurveToQuadratic(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
),
442 narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), !relative
);
449 if (!parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
451 if (!(lastCommand
== 'q' || lastCommand
== 'Q' ||
452 lastCommand
== 't' || lastCommand
== 'T')) {
458 xc
= 2 * curx
- contrlx
;
459 yc
= 2 * cury
- contrly
;
461 px1
= relative
? (curx
+ 2 * xc
) * (1.0 / 3.0) : (curx
+ 2 * xc
) * (1.0 / 3.0);
462 py1
= relative
? (cury
+ 2 * yc
) * (1.0 / 3.0) : (cury
+ 2 * yc
) * (1.0 / 3.0);
463 px2
= relative
? ((curx
+ tox
) + 2 * xc
) * (1.0 / 3.0) : (tox
+ 2 * xc
) * (1.0 / 3.0);
464 py2
= relative
? ((cury
+ toy
) + 2 * yc
) * (1.0 / 3.0) : (toy
+ 2 * yc
) * (1.0 / 3.0);
465 px3
= relative
? curx
+ tox
: tox
;
466 py3
= relative
? cury
+ toy
: toy
;
468 svgCurveToCubic(narrowPrecisionToFloat(px1
), narrowPrecisionToFloat(py1
), narrowPrecisionToFloat(px2
),
469 narrowPrecisionToFloat(py2
), narrowPrecisionToFloat(px3
), narrowPrecisionToFloat(py3
));
473 curx
= relative
? curx
+ tox
: tox
;
474 cury
= relative
? cury
+ toy
: toy
;
477 svgCurveToQuadraticSmooth(narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), !relative
);
484 bool largeArc
, sweep
;
485 double angle
, rx
, ry
;
486 if (!parseNumber(ptr
, end
, rx
) || !parseNumber(ptr
, end
, ry
) ||
487 !parseNumber(ptr
, end
, angle
) || !parseNumber(ptr
, end
, tox
))
490 if (!parseNumber(ptr
, end
, tox
))
493 if (!parseNumber(ptr
, end
, tox
) || !parseNumber(ptr
, end
, toy
))
496 // Spec: radii are nonnegative numbers
501 calculateArc(relative
, curx
, cury
, angle
, tox
, toy
, rx
, ry
, largeArc
, sweep
);
503 svgArcTo(narrowPrecisionToFloat(tox
), narrowPrecisionToFloat(toy
), narrowPrecisionToFloat(rx
), narrowPrecisionToFloat(ry
),
504 narrowPrecisionToFloat(angle
), largeArc
, sweep
, !relative
);
508 // FIXME: An error should go to the JavaScript console, or the like.
511 lastCommand
= command
;
516 // Check for remaining coordinates in the current command.
517 if ((*ptr
== '+' || *ptr
== '-' || (*ptr
>= '0' && *ptr
<= '9')) &&
518 (command
!= 'z' && command
!= 'Z')) {
521 else if (command
== 'm')
524 command
= (ptr
++)->unicode(); // or toLatin1() instead of unicode()???
526 if (lastCommand
!= 'C' && lastCommand
!= 'c' &&
527 lastCommand
!= 'S' && lastCommand
!= 's' &&
528 lastCommand
!= 'Q' && lastCommand
!= 'q' &&
529 lastCommand
!= 'T' && lastCommand
!= 't') {
538 // This works by converting the SVG arc to "simple" beziers.
539 // For each bezier found a svgToCurve call is done.
540 // Adapted from Niko's code in kdelibs/kdecore/svgicons.
541 // Maybe this can serve in some shared lib? (Rob)
542 void SVGPathParser::calculateArc(bool relative
, double& curx
, double& cury
, double angle
, double x
, double y
, double r1
, double r2
, bool largeArcFlag
, bool sweepFlag
)
544 double sin_th
, cos_th
;
545 double a00
, a01
, a10
, a11
;
546 double x0
, y0
, x1
, y1
, xc
, yc
;
547 double d
, sfactor
, sfactor_sq
;
548 double th0
, th1
, th_arc
;
551 sin_th
= sin(angle
* (piDouble
/ 180.0));
552 cos_th
= cos(angle
* (piDouble
/ 180.0));
557 dx
= (curx
- x
) / 2.0;
564 dy
= (cury
- y
) / 2.0;
568 double _x1
= cos_th
* dx
+ sin_th
* dy
;
569 double _y1
= -sin_th
* dx
+ cos_th
* dy
;
570 double Pr1
= r1
* r1
;
571 double Pr2
= r2
* r2
;
572 double Px
= _x1
* _x1
;
573 double Py
= _y1
* _y1
;
575 // Spec : check if radii are large enough
576 double check
= Px
/ Pr1
+ Py
/ Pr2
;
578 r1
= r1
* sqrt(check
);
579 r2
= r2
* sqrt(check
);
587 x0
= a00
* curx
+ a01
* cury
;
588 y0
= a10
* curx
+ a11
* cury
;
591 x1
= a00
* x
+ a01
* y
;
593 x1
= a00
* (curx
+ x
) + a01
* (cury
+ y
);
596 y1
= a10
* x
+ a11
* y
;
598 y1
= a10
* (curx
+ x
) + a11
* (cury
+ y
);
600 /* (x0, y0) is current point in transformed coordinate space.
601 (x1, y1) is new point in transformed coordinate space.
603 The arc fits a unit-radius circle in this space.
606 d
= (x1
- x0
) * (x1
- x0
) + (y1
- y0
) * (y1
- y0
);
608 sfactor_sq
= 1.0 / d
- 0.25;
613 sfactor
= sqrt(sfactor_sq
);
615 if (sweepFlag
== largeArcFlag
)
618 xc
= 0.5 * (x0
+ x1
) - sfactor
* (y1
- y0
);
619 yc
= 0.5 * (y0
+ y1
) + sfactor
* (x1
- x0
);
621 /* (xc, yc) is center of the circle. */
622 th0
= atan2(y0
- yc
, x0
- xc
);
623 th1
= atan2(y1
- yc
, x1
- xc
);
626 if (th_arc
< 0 && sweepFlag
)
627 th_arc
+= 2 * piDouble
;
628 else if (th_arc
> 0 && !sweepFlag
)
629 th_arc
-= 2 * piDouble
;
631 n_segs
= (int) (int) ceil(fabs(th_arc
/ (piDouble
* 0.5 + 0.001)));
633 for(i
= 0; i
< n_segs
; i
++) {
634 double sin_th
, cos_th
;
635 double a00
, a01
, a10
, a11
;
636 double x1
, y1
, x2
, y2
, x3
, y3
;
640 double _th0
= th0
+ i
* th_arc
/ n_segs
;
641 double _th1
= th0
+ (i
+ 1) * th_arc
/ n_segs
;
643 sin_th
= sin(angle
* (piDouble
/ 180.0));
644 cos_th
= cos(angle
* (piDouble
/ 180.0));
646 /* inverse transform compared with rsvg_path_arc */
652 th_half
= 0.5 * (_th1
- _th0
);
653 t
= (8.0 / 3.0) * sin(th_half
* 0.5) * sin(th_half
* 0.5) / sin(th_half
);
654 x1
= xc
+ cos(_th0
) - t
* sin(_th0
);
655 y1
= yc
+ sin(_th0
) + t
* cos(_th0
);
658 x2
= x3
+ t
* sin(_th1
);
659 y2
= y3
- t
* cos(_th1
);
661 svgCurveToCubic(narrowPrecisionToFloat(a00
* x1
+ a01
* y1
), narrowPrecisionToFloat(a10
* x1
+ a11
* y1
),
662 narrowPrecisionToFloat(a00
* x2
+ a01
* y2
), narrowPrecisionToFloat(a10
* x2
+ a11
* y2
),
663 narrowPrecisionToFloat(a00
* x3
+ a01
* y3
), narrowPrecisionToFloat(a10
* x3
+ a11
* y3
));
677 class PathBuilder
: public SVGPathParser
680 bool build(Path
* path
, const String
& d
)
683 return parseSVG(d
, true);
687 virtual void svgMoveTo(double x1
, double y1
, bool closed
, bool abs
= true)
689 current
.setX(narrowPrecisionToFloat(abs
? x1
: current
.x() + x1
));
690 current
.setY(narrowPrecisionToFloat(abs
? y1
: current
.y() + y1
));
692 m_path
->closeSubpath();
693 m_path
->moveTo(current
);
695 virtual void svgLineTo(double x1
, double y1
, bool abs
= true)
697 current
.setX(narrowPrecisionToFloat(abs
? x1
: current
.x() + x1
));
698 current
.setY(narrowPrecisionToFloat(abs
? y1
: current
.y() + y1
));
699 m_path
->addLineTo(current
);
701 virtual void svgCurveToCubic(double x1
, double y1
, double x2
, double y2
, double x
, double y
, bool abs
= true)
709 current
.setX(narrowPrecisionToFloat(abs
? x
: current
.x() + x
));
710 current
.setY(narrowPrecisionToFloat(abs
? y
: current
.y() + y
));
711 m_path
->addBezierCurveTo(FloatPoint::narrowPrecision(x1
, y1
), FloatPoint::narrowPrecision(x2
, y2
), current
);
713 virtual void svgClosePath()
715 m_path
->closeSubpath();
721 bool pathFromSVGData(Path
& path
, const String
& d
)
724 return builder
.build(&path
, d
);
727 class SVGPathSegListBuilder
: public SVGPathParser
730 bool build(SVGPathSegList
* segList
, const String
& d
, bool process
)
732 m_pathSegList
= segList
;
733 return parseSVG(d
, process
);
737 virtual void svgMoveTo(double x1
, double y1
, bool, bool abs
= true)
739 ExceptionCode ec
= 0;
742 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegMovetoAbs(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
)), ec
);
744 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegMovetoRel(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
)), ec
);
746 virtual void svgLineTo(double x1
, double y1
, bool abs
= true)
748 ExceptionCode ec
= 0;
751 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoAbs(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
)), ec
);
753 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoRel(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
)), ec
);
755 virtual void svgLineToHorizontal(double x
, bool abs
)
757 ExceptionCode ec
= 0;
760 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalAbs(narrowPrecisionToFloat(x
)), ec
);
762 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalRel(narrowPrecisionToFloat(x
)), ec
);
764 virtual void svgLineToVertical(double y
, bool abs
)
766 ExceptionCode ec
= 0;
769 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalAbs(narrowPrecisionToFloat(y
)), ec
);
771 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalRel(narrowPrecisionToFloat(y
)), ec
);
773 virtual void svgCurveToCubic(double x1
, double y1
, double x2
, double y2
, double x
, double y
, bool abs
= true)
775 ExceptionCode ec
= 0;
778 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicAbs(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
),
779 narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
),
780 narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
)), ec
);
782 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicRel(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
),
783 narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
),
784 narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
)), ec
);
786 virtual void svgCurveToCubicSmooth(double x
, double y
, double x2
, double y2
, bool abs
)
788 ExceptionCode ec
= 0;
791 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
),
792 narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
794 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
),
795 narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
797 virtual void svgCurveToQuadratic(double x
, double y
, double x1
, double y1
, bool abs
)
799 ExceptionCode ec
= 0;
802 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
),
803 narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
805 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticRel(narrowPrecisionToFloat(x1
), narrowPrecisionToFloat(y1
),
806 narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
808 virtual void svgCurveToQuadraticSmooth(double x
, double y
, bool abs
)
810 ExceptionCode ec
= 0;
813 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
815 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
)), ec
);
817 virtual void svgArcTo(double x
, double y
, double r1
, double r2
, double angle
, bool largeArcFlag
, bool sweepFlag
, bool abs
)
819 ExceptionCode ec
= 0;
822 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegArcAbs(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
),
823 narrowPrecisionToFloat(r1
), narrowPrecisionToFloat(r2
),
824 narrowPrecisionToFloat(angle
), largeArcFlag
, sweepFlag
), ec
);
826 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegArcRel(narrowPrecisionToFloat(x
), narrowPrecisionToFloat(y
),
827 narrowPrecisionToFloat(r1
), narrowPrecisionToFloat(r2
),
828 narrowPrecisionToFloat(angle
), largeArcFlag
, sweepFlag
), ec
);
830 virtual void svgClosePath()
832 ExceptionCode ec
= 0;
833 m_pathSegList
->appendItem(SVGPathElement::createSVGPathSegClosePath(), ec
);
835 SVGPathSegList
* m_pathSegList
;
838 bool pathSegListFromSVGData(SVGPathSegList
* path
, const String
& d
, bool process
)
840 SVGPathSegListBuilder builder
;
841 return builder
.build(path
, d
, process
);
844 Vector
<String
> parseDelimitedString(const String
& input
, const char seperator
)
846 Vector
<String
> values
;
848 const UChar
* ptr
= input
.characters();
849 const UChar
* end
= ptr
+ input
.length();
850 skipOptionalSpaces(ptr
, end
);
853 // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
854 const UChar
* inputStart
= ptr
;
855 while (ptr
< end
&& *ptr
!= seperator
) // careful not to ignore whitespace inside inputs
858 if (ptr
== inputStart
)
861 // walk backwards from the ; to ignore any whitespace
862 const UChar
* inputEnd
= ptr
- 1;
863 while (inputStart
< inputEnd
&& isWhitespace(*inputEnd
))
866 values
.append(String(inputStart
, inputEnd
- inputStart
+ 1));
867 skipOptionalSpacesOrDelimiter(ptr
, end
, seperator
);
875 #endif // ENABLE(SVG)