don't discard iframe children.
[kdelibs.git] / khtml / svg / SVGParserUtilities.cpp
blob2ca9893e9b135999812d49694d50a3bacc2a5113
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.
23 #include "config.h"
24 #include "wtf/Platform.h"
25 #if ENABLE(SVG)
26 #include "xml/Document.h"
27 #include "SVGParserUtilities.h"
29 #include "ExceptionCode.h"
30 #include "FloatConversion.h"
31 #include "FloatPoint.h"
32 #include "Path.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"
48 #include <math.h>
49 #include <wtf/MathExtras.h>
51 namespace WebCore {
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
55 * complexity
56 */
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;
61 int sign, expsign;
62 const UChar* start = ptr;
64 exponent = 0;
65 integer = 0;
66 frac = 1;
67 decimal = 0;
68 sign = 1;
69 expsign = 1;
71 // read the sign
72 if (ptr < end && *ptr == '+')
73 ptr++;
74 else if (ptr < end && *ptr == '-') {
75 ptr++;
76 sign = -1;
79 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
80 // The first character of a number must be one of [0-9+-.]
81 return false;
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
88 ptr++;
90 // There must be a least one digit following the .
91 if (ptr >= end || *ptr < '0' || *ptr > '9')
92 return false;
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')) {
101 ptr++;
103 // read the sign of the exponent
104 if (*ptr == '+')
105 ptr++;
106 else if (*ptr == '-') {
107 ptr++;
108 expsign = -1;
111 // There must be an exponent
112 if (ptr >= end || *ptr < '0' || *ptr > '9')
113 return false;
115 while (ptr < end && *ptr >= '0' && *ptr <= '9') {
116 exponent *= 10;
117 exponent += ptr->unicode() - '0';
118 ptr++;
122 number = integer + decimal;
123 number *= sign * static_cast<FloatType>(pow(10.0, expsign * exponent));
125 if (start == ptr)
126 return false;
128 if (skip)
129 skipOptionalSpacesOrDelimiter(ptr, end);
131 return true;
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)
147 if (s.isEmpty())
148 return false;
149 const UChar* cur = s.characters();
150 const UChar* end = cur + s.length();
152 if (!parseNumber(cur, end, x))
153 return false;
155 if (cur == end)
156 y = x;
157 else if (!parseNumber(cur, end, y, false))
158 return false;
160 return cur == end;
163 bool pointsListFromSVGData(SVGPointList* pointsList, const String& points)
165 if (points.isEmpty())
166 return true;
167 const UChar* cur = points.characters();
168 const UChar* end = cur + points.length();
170 skipOptionalSpaces(cur, end);
172 bool delimParsed = false;
173 while (cur < end) {
174 delimParsed = false;
175 float xPos = 0.0f;
176 if (!parseNumber(cur, end, xPos))
177 return false;
179 float yPos = 0.0f;
180 if (!parseNumber(cur, end, yPos, false))
181 return false;
183 skipOptionalSpaces(cur, end);
185 if (cur < end && *cur == ',') {
186 delimParsed = true;
187 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.
208 class SVGPathParser
210 public:
211 virtual ~SVGPathParser() { }
212 bool parseSVG(const String& d, bool process = false);
214 protected:
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;
225 private:
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)
231 if (s.isEmpty())
232 return false;
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;
239 bool closed = true;
241 if (!skipOptionalSpaces(ptr, end)) // skip any leading spaces
242 return false;
244 char command = (ptr++)->unicode(), lastCommand = ' ';// or toLatin1() instead of unicode()???
245 if (command != 'm' && command != 'M') // path must start with moveto
246 return false;
248 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
249 while (1) {
250 skipOptionalSpaces(ptr, end); // skip spaces between command and first coord
252 bool relative = false;
254 switch(command)
256 case 'm':
257 relative = true;
258 case 'M':
260 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
261 return false;
263 if (process) {
264 subpathx = curx = relative ? curx + tox : tox;
265 subpathy = cury = relative ? cury + toy : toy;
267 svgMoveTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury), closed);
268 } else
269 svgMoveTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), closed, !relative);
270 closed = false;
271 break;
273 case 'l':
274 relative = true;
275 case 'L':
277 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
278 return false;
280 if (process) {
281 curx = relative ? curx + tox : tox;
282 cury = relative ? cury + toy : toy;
284 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
286 else
287 svgLineTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
288 break;
290 case 'h':
292 if (!parseNumber(ptr, end, tox))
293 return false;
294 if (process) {
295 curx = curx + tox;
296 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
298 else
299 svgLineToHorizontal(narrowPrecisionToFloat(tox), false);
300 break;
302 case 'H':
304 if (!parseNumber(ptr, end, tox))
305 return false;
306 if (process) {
307 curx = tox;
308 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
310 else
311 svgLineToHorizontal(narrowPrecisionToFloat(tox));
312 break;
314 case 'v':
316 if (!parseNumber(ptr, end, toy))
317 return false;
318 if (process) {
319 cury = cury + toy;
320 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
322 else
323 svgLineToVertical(narrowPrecisionToFloat(toy), false);
324 break;
326 case 'V':
328 if (!parseNumber(ptr, end, toy))
329 return false;
330 if (process) {
331 cury = toy;
332 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury));
334 else
335 svgLineToVertical(narrowPrecisionToFloat(toy));
336 break;
338 case 'z':
339 case 'Z':
341 // reset curx, cury for next path
342 if (process) {
343 curx = subpathx;
344 cury = subpathy;
346 closed = true;
347 svgClosePath();
348 break;
350 case 'c':
351 relative = true;
352 case 'C':
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))
357 return false;
359 if (process) {
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;
375 else
376 svgCurveToCubic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), narrowPrecisionToFloat(x2),
377 narrowPrecisionToFloat(y2), narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
379 break;
381 case 's':
382 relative = true;
383 case 'S':
385 if (!parseNumber(ptr, end, x2) || !parseNumber(ptr, end, y2) ||
386 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
387 return false;
389 if (!(lastCommand == 'c' || lastCommand == 'C' ||
390 lastCommand == 's' || lastCommand == 'S')) {
391 contrlx = curx;
392 contrly = cury;
395 if (process) {
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;
411 else
412 svgCurveToCubicSmooth(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2),
413 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
414 break;
416 case 'q':
417 relative = true;
418 case 'Q':
420 if (!parseNumber(ptr, end, x1) || !parseNumber(ptr, end, y1) ||
421 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
422 return false;
424 if (process) {
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;
440 else
441 svgCurveToQuadratic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
442 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
443 break;
445 case 't':
446 relative = true;
447 case 'T':
449 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
450 return false;
451 if (!(lastCommand == 'q' || lastCommand == 'Q' ||
452 lastCommand == 't' || lastCommand == 'T')) {
453 contrlx = curx;
454 contrly = cury;
457 if (process) {
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));
471 contrlx = xc;
472 contrly = yc;
473 curx = relative ? curx + tox : tox;
474 cury = relative ? cury + toy : toy;
476 else
477 svgCurveToQuadraticSmooth(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative);
478 break;
480 case 'a':
481 relative = true;
482 case 'A':
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))
488 return false;
489 largeArc = tox == 1;
490 if (!parseNumber(ptr, end, tox))
491 return false;
492 sweep = tox == 1;
493 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy))
494 return false;
496 // Spec: radii are nonnegative numbers
497 rx = fabs(rx);
498 ry = fabs(ry);
500 if (process)
501 calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
502 else
503 svgArcTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), narrowPrecisionToFloat(rx), narrowPrecisionToFloat(ry),
504 narrowPrecisionToFloat(angle), largeArc, sweep, !relative);
505 break;
507 default:
508 // FIXME: An error should go to the JavaScript console, or the like.
509 return false;
511 lastCommand = command;
513 if (ptr >= end)
514 return true;
516 // Check for remaining coordinates in the current command.
517 if ((*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) &&
518 (command != 'z' && command != 'Z')) {
519 if (command == 'M')
520 command = 'L';
521 else if (command == 'm')
522 command = 'l';
523 } else
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') {
530 contrlx = curx;
531 contrly = cury;
535 return false;
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;
549 int i, n_segs;
551 sin_th = sin(angle * (piDouble / 180.0));
552 cos_th = cos(angle * (piDouble / 180.0));
554 double dx;
556 if (!relative)
557 dx = (curx - x) / 2.0;
558 else
559 dx = -x / 2.0;
561 double dy;
563 if (!relative)
564 dy = (cury - y) / 2.0;
565 else
566 dy = -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;
577 if (check > 1) {
578 r1 = r1 * sqrt(check);
579 r2 = r2 * sqrt(check);
582 a00 = cos_th / r1;
583 a01 = sin_th / r1;
584 a10 = -sin_th / r2;
585 a11 = cos_th / r2;
587 x0 = a00 * curx + a01 * cury;
588 y0 = a10 * curx + a11 * cury;
590 if (!relative)
591 x1 = a00 * x + a01 * y;
592 else
593 x1 = a00 * (curx + x) + a01 * (cury + y);
595 if (!relative)
596 y1 = a10 * x + a11 * y;
597 else
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;
610 if (sfactor_sq < 0)
611 sfactor_sq = 0;
613 sfactor = sqrt(sfactor_sq);
615 if (sweepFlag == largeArcFlag)
616 sfactor = -sfactor;
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);
625 th_arc = th1 - th0;
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;
637 double t;
638 double th_half;
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 */
647 a00 = cos_th * r1;
648 a01 = -sin_th * r2;
649 a10 = sin_th * r1;
650 a11 = cos_th * r2;
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);
656 x3 = xc + cos(_th1);
657 y3 = yc + sin(_th1);
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));
666 if (!relative)
667 curx = x;
668 else
669 curx += x;
671 if (!relative)
672 cury = y;
673 else
674 cury += y;
677 class PathBuilder : public SVGPathParser
679 public:
680 bool build(Path* path, const String& d)
682 m_path = path;
683 return parseSVG(d, true);
686 private:
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));
691 if (closed)
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)
703 if (!abs) {
704 x1 += current.x();
705 y1 += current.y();
706 x2 += current.x();
707 y2 += current.y();
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();
717 Path* m_path;
718 FloatPoint current;
721 bool pathFromSVGData(Path& path, const String& d)
723 PathBuilder builder;
724 return builder.build(&path, d);
727 class SVGPathSegListBuilder : public SVGPathParser
729 public:
730 bool build(SVGPathSegList* segList, const String& d, bool process)
732 m_pathSegList = segList;
733 return parseSVG(d, process);
736 private:
737 virtual void svgMoveTo(double x1, double y1, bool, bool abs = true)
739 ExceptionCode ec = 0;
741 if (abs)
742 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegMovetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec);
743 else
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;
750 if (abs)
751 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec);
752 else
753 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec);
755 virtual void svgLineToHorizontal(double x, bool abs)
757 ExceptionCode ec = 0;
759 if (abs)
760 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalAbs(narrowPrecisionToFloat(x)), ec);
761 else
762 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalRel(narrowPrecisionToFloat(x)), ec);
764 virtual void svgLineToVertical(double y, bool abs)
766 ExceptionCode ec = 0;
768 if (abs)
769 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalAbs(narrowPrecisionToFloat(y)), ec);
770 else
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;
777 if (abs)
778 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
779 narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
780 narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)), ec);
781 else
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;
790 if (abs)
791 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2),
792 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec);
793 else
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;
801 if (abs)
802 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1),
803 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec);
804 else
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;
812 if (abs)
813 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec);
814 else
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;
821 if (abs)
822 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegArcAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y),
823 narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2),
824 narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag), ec);
825 else
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);
852 while (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
856 ptr++;
858 if (ptr == inputStart)
859 break;
861 // walk backwards from the ; to ignore any whitespace
862 const UChar* inputEnd = ptr - 1;
863 while (inputStart < inputEnd && isWhitespace(*inputEnd))
864 inputEnd--;
866 values.append(String(inputStart, inputEnd - inputStart + 1));
867 skipOptionalSpacesOrDelimiter(ptr, end, seperator);
870 return values;
875 #endif // ENABLE(SVG)