File indexing completed on 2024-04-28 15:24:38
0001 /* This file is part of the KDE project 0002 Copyright (C) 2002, 2003 The Karbon Developers 0003 2006 Alexander Kellett <lypanov@kde.org> 0004 2006, 2007 Rob Buis <buis@kde.org> 0005 2007 Apple, Inc. All rights reserved. 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "wtf/Platform.h" 0024 #if ENABLE(SVG) 0025 #include "xml/Document.h" 0026 #include "SVGParserUtilities.h" 0027 0028 #include "ExceptionCode.h" 0029 #include "FloatConversion.h" 0030 #include "FloatPoint.h" 0031 #include "Path.h" 0032 #include "PlatformString.h" 0033 #include "SVGPathSegList.h" 0034 #include "SVGPathSegArc.h" 0035 #include "SVGPathSegClosePath.h" 0036 #include "SVGPathSegCurvetoCubic.h" 0037 #include "SVGPathSegCurvetoCubicSmooth.h" 0038 #include "SVGPathSegCurvetoQuadratic.h" 0039 #include "SVGPathSegCurvetoQuadraticSmooth.h" 0040 #include "SVGPathSegLineto.h" 0041 #include "SVGPathSegLinetoHorizontal.h" 0042 #include "SVGPathSegLinetoVertical.h" 0043 #include "SVGPathSegList.h" 0044 #include "SVGPathSegMoveto.h" 0045 #include "SVGPointList.h" 0046 #include "SVGPathElement.h" 0047 #include <math.h> 0048 #include <wtf/MathExtras.h> 0049 0050 namespace WebCore 0051 { 0052 0053 /* We use this generic _parseNumber function to allow the Path parsing code to work 0054 * at a higher precision internally, without any unnecessary runtime cost or code 0055 * complexity 0056 */ 0057 template <typename FloatType> static bool _parseNumber(const UChar *&ptr, const UChar *end, FloatType &number, bool skip) 0058 { 0059 int integer, exponent; 0060 FloatType decimal, frac; 0061 int sign, expsign; 0062 const UChar *start = ptr; 0063 0064 exponent = 0; 0065 integer = 0; 0066 frac = 1; 0067 decimal = 0; 0068 sign = 1; 0069 expsign = 1; 0070 0071 // read the sign 0072 if (ptr < end && *ptr == '+') { 0073 ptr++; 0074 } else if (ptr < end && *ptr == '-') { 0075 ptr++; 0076 sign = -1; 0077 } 0078 0079 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) 0080 // The first character of a number must be one of [0-9+-.] 0081 { 0082 return false; 0083 } 0084 0085 // read the integer part 0086 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 0087 integer = (integer * 10) + (ptr++)->unicode() - '0'; 0088 } 0089 0090 if (ptr < end && *ptr == '.') { // read the decimals 0091 ptr++; 0092 0093 // There must be a least one digit following the . 0094 if (ptr >= end || *ptr < '0' || *ptr > '9') { 0095 return false; 0096 } 0097 0098 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 0099 decimal += ((ptr++)->unicode() - '0') * (frac *= static_cast<FloatType>(0.1)); 0100 } 0101 } 0102 0103 // read the exponent part 0104 if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') 0105 && (ptr[1] != 'x' && ptr[1] != 'm')) { 0106 ptr++; 0107 0108 // read the sign of the exponent 0109 if (*ptr == '+') { 0110 ptr++; 0111 } else if (*ptr == '-') { 0112 ptr++; 0113 expsign = -1; 0114 } 0115 0116 // There must be an exponent 0117 if (ptr >= end || *ptr < '0' || *ptr > '9') { 0118 return false; 0119 } 0120 0121 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 0122 exponent *= 10; 0123 exponent += ptr->unicode() - '0'; 0124 ptr++; 0125 } 0126 } 0127 0128 number = integer + decimal; 0129 number *= sign * static_cast<FloatType>(pow(10.0, expsign * exponent)); 0130 0131 if (start == ptr) { 0132 return false; 0133 } 0134 0135 if (skip) { 0136 skipOptionalSpacesOrDelimiter(ptr, end); 0137 } 0138 0139 return true; 0140 } 0141 0142 bool parseNumber(const UChar *&ptr, const UChar *end, float &number, bool skip) 0143 { 0144 return _parseNumber(ptr, end, number, skip); 0145 } 0146 0147 // Only used for parsing Paths 0148 static bool parseNumber(const UChar *&ptr, const UChar *end, double &number, bool skip = true) 0149 { 0150 return _parseNumber(ptr, end, number, skip); 0151 } 0152 0153 bool parseNumberOptionalNumber(const String &s, float &x, float &y) 0154 { 0155 if (s.isEmpty()) { 0156 return false; 0157 } 0158 const UChar *cur = s.characters(); 0159 const UChar *end = cur + s.length(); 0160 0161 if (!parseNumber(cur, end, x)) { 0162 return false; 0163 } 0164 0165 if (cur == end) { 0166 y = x; 0167 } else if (!parseNumber(cur, end, y, false)) { 0168 return false; 0169 } 0170 0171 return cur == end; 0172 } 0173 0174 bool pointsListFromSVGData(SVGPointList *pointsList, const String &points) 0175 { 0176 if (points.isEmpty()) { 0177 return true; 0178 } 0179 const UChar *cur = points.characters(); 0180 const UChar *end = cur + points.length(); 0181 0182 skipOptionalSpaces(cur, end); 0183 0184 bool delimParsed = false; 0185 while (cur < end) { 0186 delimParsed = false; 0187 float xPos = 0.0f; 0188 if (!parseNumber(cur, end, xPos)) { 0189 return false; 0190 } 0191 0192 float yPos = 0.0f; 0193 if (!parseNumber(cur, end, yPos, false)) { 0194 return false; 0195 } 0196 0197 skipOptionalSpaces(cur, end); 0198 0199 if (cur < end && *cur == ',') { 0200 delimParsed = true; 0201 cur++; 0202 } 0203 skipOptionalSpaces(cur, end); 0204 0205 ExceptionCode ec = 0; 0206 pointsList->appendItem(FloatPoint(xPos, yPos), ec); 0207 } 0208 return cur == end && !delimParsed; 0209 } 0210 0211 /** 0212 * Parser for svg path data, contained in the d attribute. 0213 * 0214 * The parser delivers encountered commands and parameters by calling 0215 * methods that correspond to those commands. Clients have to derive 0216 * from this class and implement the abstract command methods. 0217 * 0218 * There are two operating modes. By default the parser just delivers unaltered 0219 * svg path data commands and parameters. In the second mode, it will convert all 0220 * relative coordinates to absolute ones, and convert all curves to cubic beziers. 0221 */ 0222 class SVGPathParser 0223 { 0224 public: 0225 virtual ~SVGPathParser() { } 0226 bool parseSVG(const String &d, bool process = false); 0227 0228 protected: 0229 virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true) = 0; 0230 virtual void svgLineTo(double x1, double y1, bool abs = true) = 0; 0231 virtual void svgLineToHorizontal(double x, bool abs = true) 0232 { 0233 Q_UNUSED(x); 0234 Q_UNUSED(abs); 0235 } 0236 virtual void svgLineToVertical(double y, bool abs = true) 0237 { 0238 Q_UNUSED(y); 0239 Q_UNUSED(abs); 0240 } 0241 virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) = 0; 0242 virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs = true) 0243 { 0244 Q_UNUSED(x); 0245 Q_UNUSED(y); 0246 Q_UNUSED(x2); 0247 Q_UNUSED(y2); 0248 Q_UNUSED(abs); 0249 } 0250 virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs = true) 0251 { 0252 Q_UNUSED(x); 0253 Q_UNUSED(y); 0254 Q_UNUSED(x1); 0255 Q_UNUSED(y1); 0256 Q_UNUSED(abs); 0257 } 0258 virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs = true) 0259 { 0260 Q_UNUSED(x); 0261 Q_UNUSED(y); 0262 Q_UNUSED(abs); 0263 } 0264 virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true) 0265 { 0266 Q_UNUSED(x); 0267 Q_UNUSED(y); 0268 Q_UNUSED(r1); 0269 Q_UNUSED(r2); 0270 Q_UNUSED(angle); 0271 Q_UNUSED(largeArcFlag); 0272 Q_UNUSED(sweepFlag); 0273 Q_UNUSED(abs); 0274 } 0275 virtual void svgClosePath() = 0; 0276 private: 0277 void calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag); 0278 }; 0279 0280 bool SVGPathParser::parseSVG(const String &s, bool process) 0281 { 0282 if (s.isEmpty()) { 0283 return false; 0284 } 0285 0286 const UChar *ptr = s.characters(); 0287 const UChar *end = ptr + s.length(); 0288 0289 double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; 0290 double px1, py1, px2, py2, px3, py3; 0291 bool closed = true; 0292 0293 if (!skipOptionalSpaces(ptr, end)) { // skip any leading spaces 0294 return false; 0295 } 0296 0297 char command = (ptr++)->unicode(), lastCommand = ' ';// or toLatin1() instead of unicode()??? 0298 if (command != 'm' && command != 'M') { // path must start with moveto 0299 return false; 0300 } 0301 0302 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; 0303 while (1) { 0304 skipOptionalSpaces(ptr, end); // skip spaces between command and first coord 0305 0306 bool relative = false; 0307 0308 switch (command) { 0309 case 'm': 0310 relative = true; 0311 case 'M': { 0312 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0313 return false; 0314 } 0315 0316 if (process) { 0317 subpathx = curx = relative ? curx + tox : tox; 0318 subpathy = cury = relative ? cury + toy : toy; 0319 0320 svgMoveTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury), closed); 0321 } else { 0322 svgMoveTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), closed, !relative); 0323 } 0324 closed = false; 0325 break; 0326 } 0327 case 'l': 0328 relative = true; 0329 case 'L': { 0330 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0331 return false; 0332 } 0333 0334 if (process) { 0335 curx = relative ? curx + tox : tox; 0336 cury = relative ? cury + toy : toy; 0337 0338 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 0339 } else { 0340 svgLineTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 0341 } 0342 break; 0343 } 0344 case 'h': { 0345 if (!parseNumber(ptr, end, tox)) { 0346 return false; 0347 } 0348 if (process) { 0349 curx = curx + tox; 0350 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 0351 } else { 0352 svgLineToHorizontal(narrowPrecisionToFloat(tox), false); 0353 } 0354 break; 0355 } 0356 case 'H': { 0357 if (!parseNumber(ptr, end, tox)) { 0358 return false; 0359 } 0360 if (process) { 0361 curx = tox; 0362 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 0363 } else { 0364 svgLineToHorizontal(narrowPrecisionToFloat(tox)); 0365 } 0366 break; 0367 } 0368 case 'v': { 0369 if (!parseNumber(ptr, end, toy)) { 0370 return false; 0371 } 0372 if (process) { 0373 cury = cury + toy; 0374 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 0375 } else { 0376 svgLineToVertical(narrowPrecisionToFloat(toy), false); 0377 } 0378 break; 0379 } 0380 case 'V': { 0381 if (!parseNumber(ptr, end, toy)) { 0382 return false; 0383 } 0384 if (process) { 0385 cury = toy; 0386 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 0387 } else { 0388 svgLineToVertical(narrowPrecisionToFloat(toy)); 0389 } 0390 break; 0391 } 0392 case 'z': 0393 case 'Z': { 0394 // reset curx, cury for next path 0395 if (process) { 0396 curx = subpathx; 0397 cury = subpathy; 0398 } 0399 closed = true; 0400 svgClosePath(); 0401 break; 0402 } 0403 case 'c': 0404 relative = true; 0405 case 'C': { 0406 if (!parseNumber(ptr, end, x1) || !parseNumber(ptr, end, y1) || 0407 !parseNumber(ptr, end, x2) || !parseNumber(ptr, end, y2) || 0408 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0409 return false; 0410 } 0411 0412 if (process) { 0413 px1 = relative ? curx + x1 : x1; 0414 py1 = relative ? cury + y1 : y1; 0415 px2 = relative ? curx + x2 : x2; 0416 py2 = relative ? cury + y2 : y2; 0417 px3 = relative ? curx + tox : tox; 0418 py3 = relative ? cury + toy : toy; 0419 0420 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 0421 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 0422 0423 contrlx = relative ? curx + x2 : x2; 0424 contrly = relative ? cury + y2 : y2; 0425 curx = relative ? curx + tox : tox; 0426 cury = relative ? cury + toy : toy; 0427 } else 0428 svgCurveToCubic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), narrowPrecisionToFloat(x2), 0429 narrowPrecisionToFloat(y2), narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 0430 0431 break; 0432 } 0433 case 's': 0434 relative = true; 0435 case 'S': { 0436 if (!parseNumber(ptr, end, x2) || !parseNumber(ptr, end, y2) || 0437 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0438 return false; 0439 } 0440 0441 if (!(lastCommand == 'c' || lastCommand == 'C' || 0442 lastCommand == 's' || lastCommand == 'S')) { 0443 contrlx = curx; 0444 contrly = cury; 0445 } 0446 0447 if (process) { 0448 px1 = 2 * curx - contrlx; 0449 py1 = 2 * cury - contrly; 0450 px2 = relative ? curx + x2 : x2; 0451 py2 = relative ? cury + y2 : y2; 0452 px3 = relative ? curx + tox : tox; 0453 py3 = relative ? cury + toy : toy; 0454 0455 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 0456 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 0457 0458 contrlx = relative ? curx + x2 : x2; 0459 contrly = relative ? cury + y2 : y2; 0460 curx = relative ? curx + tox : tox; 0461 cury = relative ? cury + toy : toy; 0462 } else 0463 svgCurveToCubicSmooth(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 0464 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 0465 break; 0466 } 0467 case 'q': 0468 relative = true; 0469 case 'Q': { 0470 if (!parseNumber(ptr, end, x1) || !parseNumber(ptr, end, y1) || 0471 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0472 return false; 0473 } 0474 0475 if (process) { 0476 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); 0477 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); 0478 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); 0479 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); 0480 px3 = relative ? curx + tox : tox; 0481 py3 = relative ? cury + toy : toy; 0482 0483 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 0484 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 0485 0486 contrlx = relative ? curx + x1 : x1; 0487 contrly = relative ? cury + y1 : y1; 0488 curx = relative ? curx + tox : tox; 0489 cury = relative ? cury + toy : toy; 0490 } else 0491 svgCurveToQuadratic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 0492 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 0493 break; 0494 } 0495 case 't': 0496 relative = true; 0497 case 'T': { 0498 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0499 return false; 0500 } 0501 if (!(lastCommand == 'q' || lastCommand == 'Q' || 0502 lastCommand == 't' || lastCommand == 'T')) { 0503 contrlx = curx; 0504 contrly = cury; 0505 } 0506 0507 if (process) { 0508 xc = 2 * curx - contrlx; 0509 yc = 2 * cury - contrly; 0510 0511 px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); 0512 py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); 0513 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); 0514 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); 0515 px3 = relative ? curx + tox : tox; 0516 py3 = relative ? cury + toy : toy; 0517 0518 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 0519 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 0520 0521 contrlx = xc; 0522 contrly = yc; 0523 curx = relative ? curx + tox : tox; 0524 cury = relative ? cury + toy : toy; 0525 } else { 0526 svgCurveToQuadraticSmooth(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 0527 } 0528 break; 0529 } 0530 case 'a': 0531 relative = true; 0532 case 'A': { 0533 bool largeArc, sweep; 0534 double angle, rx, ry; 0535 if (!parseNumber(ptr, end, rx) || !parseNumber(ptr, end, ry) || 0536 !parseNumber(ptr, end, angle) || !parseNumber(ptr, end, tox)) { 0537 return false; 0538 } 0539 largeArc = tox == 1; 0540 if (!parseNumber(ptr, end, tox)) { 0541 return false; 0542 } 0543 sweep = tox == 1; 0544 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) { 0545 return false; 0546 } 0547 0548 // Spec: radii are nonnegative numbers 0549 rx = fabs(rx); 0550 ry = fabs(ry); 0551 0552 if (process) { 0553 calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 0554 } else 0555 svgArcTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), narrowPrecisionToFloat(rx), narrowPrecisionToFloat(ry), 0556 narrowPrecisionToFloat(angle), largeArc, sweep, !relative); 0557 break; 0558 } 0559 default: 0560 // FIXME: An error should go to the JavaScript console, or the like. 0561 return false; 0562 } 0563 lastCommand = command; 0564 0565 if (ptr >= end) { 0566 return true; 0567 } 0568 0569 // Check for remaining coordinates in the current command. 0570 if ((*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) && 0571 (command != 'z' && command != 'Z')) { 0572 if (command == 'M') { 0573 command = 'L'; 0574 } else if (command == 'm') { 0575 command = 'l'; 0576 } 0577 } else { 0578 command = (ptr++)->unicode(); // or toLatin1() instead of unicode()??? 0579 } 0580 0581 if (lastCommand != 'C' && lastCommand != 'c' && 0582 lastCommand != 'S' && lastCommand != 's' && 0583 lastCommand != 'Q' && lastCommand != 'q' && 0584 lastCommand != 'T' && lastCommand != 't') { 0585 contrlx = curx; 0586 contrly = cury; 0587 } 0588 } 0589 0590 return false; 0591 } 0592 0593 // This works by converting the SVG arc to "simple" beziers. 0594 // For each bezier found a svgToCurve call is done. 0595 // Adapted from Niko's code in kdelibs/kdecore/svgicons. 0596 // Maybe this can serve in some shared lib? (Rob) 0597 void SVGPathParser::calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) 0598 { 0599 double sin_th, cos_th; 0600 double a00, a01, a10, a11; 0601 double x0, y0, x1, y1, xc, yc; 0602 double d, sfactor, sfactor_sq; 0603 double th0, th1, th_arc; 0604 int i, n_segs; 0605 0606 sin_th = sin(angle * (piDouble / 180.0)); 0607 cos_th = cos(angle * (piDouble / 180.0)); 0608 0609 double dx; 0610 0611 if (!relative) { 0612 dx = (curx - x) / 2.0; 0613 } else { 0614 dx = -x / 2.0; 0615 } 0616 0617 double dy; 0618 0619 if (!relative) { 0620 dy = (cury - y) / 2.0; 0621 } else { 0622 dy = -y / 2.0; 0623 } 0624 0625 double _x1 = cos_th * dx + sin_th * dy; 0626 double _y1 = -sin_th * dx + cos_th * dy; 0627 double Pr1 = r1 * r1; 0628 double Pr2 = r2 * r2; 0629 double Px = _x1 * _x1; 0630 double Py = _y1 * _y1; 0631 0632 // Spec : check if radii are large enough 0633 double check = Px / Pr1 + Py / Pr2; 0634 if (check > 1) { 0635 r1 = r1 * sqrt(check); 0636 r2 = r2 * sqrt(check); 0637 } 0638 0639 a00 = cos_th / r1; 0640 a01 = sin_th / r1; 0641 a10 = -sin_th / r2; 0642 a11 = cos_th / r2; 0643 0644 x0 = a00 * curx + a01 * cury; 0645 y0 = a10 * curx + a11 * cury; 0646 0647 if (!relative) { 0648 x1 = a00 * x + a01 * y; 0649 } else { 0650 x1 = a00 * (curx + x) + a01 * (cury + y); 0651 } 0652 0653 if (!relative) { 0654 y1 = a10 * x + a11 * y; 0655 } else { 0656 y1 = a10 * (curx + x) + a11 * (cury + y); 0657 } 0658 0659 /* (x0, y0) is current point in transformed coordinate space. 0660 (x1, y1) is new point in transformed coordinate space. 0661 0662 The arc fits a unit-radius circle in this space. 0663 */ 0664 0665 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); 0666 0667 sfactor_sq = 1.0 / d - 0.25; 0668 0669 if (sfactor_sq < 0) { 0670 sfactor_sq = 0; 0671 } 0672 0673 sfactor = sqrt(sfactor_sq); 0674 0675 if (sweepFlag == largeArcFlag) { 0676 sfactor = -sfactor; 0677 } 0678 0679 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); 0680 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); 0681 0682 /* (xc, yc) is center of the circle. */ 0683 th0 = atan2(y0 - yc, x0 - xc); 0684 th1 = atan2(y1 - yc, x1 - xc); 0685 0686 th_arc = th1 - th0; 0687 if (th_arc < 0 && sweepFlag) { 0688 th_arc += 2 * piDouble; 0689 } else if (th_arc > 0 && !sweepFlag) { 0690 th_arc -= 2 * piDouble; 0691 } 0692 0693 n_segs = (int)(int) ceil(fabs(th_arc / (piDouble * 0.5 + 0.001))); 0694 0695 for (i = 0; i < n_segs; i++) { 0696 double sin_th, cos_th; 0697 double a00, a01, a10, a11; 0698 double x1, y1, x2, y2, x3, y3; 0699 double t; 0700 double th_half; 0701 0702 double _th0 = th0 + i * th_arc / n_segs; 0703 double _th1 = th0 + (i + 1) * th_arc / n_segs; 0704 0705 sin_th = sin(angle * (piDouble / 180.0)); 0706 cos_th = cos(angle * (piDouble / 180.0)); 0707 0708 /* inverse transform compared with rsvg_path_arc */ 0709 a00 = cos_th * r1; 0710 a01 = -sin_th * r2; 0711 a10 = sin_th * r1; 0712 a11 = cos_th * r2; 0713 0714 th_half = 0.5 * (_th1 - _th0); 0715 t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); 0716 x1 = xc + cos(_th0) - t * sin(_th0); 0717 y1 = yc + sin(_th0) + t * cos(_th0); 0718 x3 = xc + cos(_th1); 0719 y3 = yc + sin(_th1); 0720 x2 = x3 + t * sin(_th1); 0721 y2 = y3 - t * cos(_th1); 0722 0723 svgCurveToCubic(narrowPrecisionToFloat(a00 * x1 + a01 * y1), narrowPrecisionToFloat(a10 * x1 + a11 * y1), 0724 narrowPrecisionToFloat(a00 * x2 + a01 * y2), narrowPrecisionToFloat(a10 * x2 + a11 * y2), 0725 narrowPrecisionToFloat(a00 * x3 + a01 * y3), narrowPrecisionToFloat(a10 * x3 + a11 * y3)); 0726 } 0727 0728 if (!relative) { 0729 curx = x; 0730 } else { 0731 curx += x; 0732 } 0733 0734 if (!relative) { 0735 cury = y; 0736 } else { 0737 cury += y; 0738 } 0739 } 0740 0741 class PathBuilder : public SVGPathParser 0742 { 0743 public: 0744 bool build(Path *path, const String &d) 0745 { 0746 m_path = path; 0747 return parseSVG(d, true); 0748 } 0749 0750 private: 0751 void svgMoveTo(double x1, double y1, bool closed, bool abs = true) override 0752 { 0753 current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1)); 0754 current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1)); 0755 if (closed) { 0756 m_path->closeSubpath(); 0757 } 0758 m_path->moveTo(current); 0759 } 0760 void svgLineTo(double x1, double y1, bool abs = true) override 0761 { 0762 current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1)); 0763 current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1)); 0764 m_path->addLineTo(current); 0765 } 0766 void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) override 0767 { 0768 if (!abs) { 0769 x1 += current.x(); 0770 y1 += current.y(); 0771 x2 += current.x(); 0772 y2 += current.y(); 0773 } 0774 current.setX(narrowPrecisionToFloat(abs ? x : current.x() + x)); 0775 current.setY(narrowPrecisionToFloat(abs ? y : current.y() + y)); 0776 m_path->addBezierCurveTo(FloatPoint::narrowPrecision(x1, y1), FloatPoint::narrowPrecision(x2, y2), current); 0777 } 0778 void svgClosePath() override 0779 { 0780 m_path->closeSubpath(); 0781 } 0782 Path *m_path; 0783 FloatPoint current; 0784 }; 0785 0786 bool pathFromSVGData(Path &path, const String &d) 0787 { 0788 PathBuilder builder; 0789 return builder.build(&path, d); 0790 } 0791 0792 class SVGPathSegListBuilder : public SVGPathParser 0793 { 0794 public: 0795 bool build(SVGPathSegList *segList, const String &d, bool process) 0796 { 0797 m_pathSegList = segList; 0798 return parseSVG(d, process); 0799 } 0800 0801 private: 0802 void svgMoveTo(double x1, double y1, bool, bool abs = true) override 0803 { 0804 ExceptionCode ec = 0; 0805 0806 if (abs) { 0807 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegMovetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 0808 } else { 0809 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegMovetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 0810 } 0811 } 0812 void svgLineTo(double x1, double y1, bool abs = true) override 0813 { 0814 ExceptionCode ec = 0; 0815 0816 if (abs) { 0817 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 0818 } else { 0819 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 0820 } 0821 } 0822 void svgLineToHorizontal(double x, bool abs) override 0823 { 0824 ExceptionCode ec = 0; 0825 0826 if (abs) { 0827 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalAbs(narrowPrecisionToFloat(x)), ec); 0828 } else { 0829 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalRel(narrowPrecisionToFloat(x)), ec); 0830 } 0831 } 0832 void svgLineToVertical(double y, bool abs) override 0833 { 0834 ExceptionCode ec = 0; 0835 0836 if (abs) { 0837 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalAbs(narrowPrecisionToFloat(y)), ec); 0838 } else { 0839 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalRel(narrowPrecisionToFloat(y)), ec); 0840 } 0841 } 0842 void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) override 0843 { 0844 ExceptionCode ec = 0; 0845 0846 if (abs) 0847 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 0848 narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 0849 narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)), ec); 0850 else 0851 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 0852 narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 0853 narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)), ec); 0854 } 0855 void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs) override 0856 { 0857 ExceptionCode ec = 0; 0858 0859 if (abs) 0860 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 0861 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0862 else 0863 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 0864 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0865 } 0866 void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs) override 0867 { 0868 ExceptionCode ec = 0; 0869 0870 if (abs) 0871 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 0872 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0873 else 0874 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 0875 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0876 } 0877 void svgCurveToQuadraticSmooth(double x, double y, bool abs) override 0878 { 0879 ExceptionCode ec = 0; 0880 0881 if (abs) { 0882 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0883 } else { 0884 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 0885 } 0886 } 0887 void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs) override 0888 { 0889 ExceptionCode ec = 0; 0890 0891 if (abs) 0892 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegArcAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 0893 narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2), 0894 narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag), ec); 0895 else 0896 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegArcRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 0897 narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2), 0898 narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag), ec); 0899 } 0900 void svgClosePath() override 0901 { 0902 ExceptionCode ec = 0; 0903 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegClosePath(), ec); 0904 } 0905 SVGPathSegList *m_pathSegList; 0906 }; 0907 0908 bool pathSegListFromSVGData(SVGPathSegList *path, const String &d, bool process) 0909 { 0910 SVGPathSegListBuilder builder; 0911 return builder.build(path, d, process); 0912 } 0913 0914 Vector<String> parseDelimitedString(const String &input, const char separator) 0915 { 0916 Vector<String> values; 0917 0918 const UChar *ptr = input.characters(); 0919 const UChar *end = ptr + input.length(); 0920 skipOptionalSpaces(ptr, end); 0921 0922 while (ptr < end) { 0923 // Leading and trailing white space, and white space before and after semicolon separators, will be ignored. 0924 const UChar *inputStart = ptr; 0925 while (ptr < end && *ptr != separator) { // careful not to ignore whitespace inside inputs 0926 ptr++; 0927 } 0928 0929 if (ptr == inputStart) { 0930 break; 0931 } 0932 0933 // walk backwards from the ; to ignore any whitespace 0934 const UChar *inputEnd = ptr - 1; 0935 while (inputStart < inputEnd && isWhitespace(*inputEnd)) { 0936 inputEnd--; 0937 } 0938 0939 values.append(String(inputStart, inputEnd - inputStart + 1)); 0940 skipOptionalSpacesOrDelimiter(ptr, end, separator); 0941 } 0942 0943 return values; 0944 } 0945 0946 } 0947 0948 #endif // ENABLE(SVG)