1 /* 2 Copyright (C) 2002, 2003 The Karbon Developers 3 2006 Alexander Kellett <lypanov (at) kde.org> 4 2006, 2007 Rob Buis <buis (at) 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 */ 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 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 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 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 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: 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; 214 virtual void svgLineToHorizontal(double, bool /*abs*/ = 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; 217 virtual void svgCurveToCubicSmooth(double /*x*/, double /*y*/, double /*x2*/, double /*y2*/, bool /*abs*/ = true) { } 218 virtual void svgCurveToQuadratic(double /*x*/, double /*y*/, double /*x1*/, double /*y1*/, bool /*abs*/ = true) { } 219 virtual void svgCurveToQuadraticSmooth(double /*x*/, double /*y*/, bool /*abs*/ = 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 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 == '.' || (*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) 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: 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: 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 } 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 } 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 } 711 virtual void svgClosePath() 712 { 713 m_path->closeSubpath(); 714 } 715 716 Path* m_path; 717 FloatPoint current; 718 }; 719 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: 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: 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 817 virtual void svgClosePath() 818 { 819 m_vector.append(SVGPathElement::createSVGPathSegClosePath()); 820 } 821 822 Vector<RefPtr<SVGPathSeg> > m_vector; 823 }; 824 825 bool pathSegListFromSVGData(SVGPathSegList* path, const String& d, bool process) 826 { 827 SVGPathSegListBuilder builder; 828 return builder.build(path, d, process); 829 } 830 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