KHTML
SVGParserUtilities.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2002, 2003 The Karbon Developers 00003 2006 Alexander Kellett <lypanov@kde.org> 00004 2006, 2007 Rob Buis <buis@kde.org> 00005 2007 Apple, Inc. All rights reserved. 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "config.h" 00024 #include "wtf/Platform.h" 00025 #if ENABLE(SVG) 00026 #include "xml/Document.h" 00027 #include "SVGParserUtilities.h" 00028 00029 #include "ExceptionCode.h" 00030 #include "FloatConversion.h" 00031 #include "FloatPoint.h" 00032 #include "Path.h" 00033 #include "PlatformString.h" 00034 #include "SVGPathSegList.h" 00035 #include "SVGPathSegArc.h" 00036 #include "SVGPathSegClosePath.h" 00037 #include "SVGPathSegCurvetoCubic.h" 00038 #include "SVGPathSegCurvetoCubicSmooth.h" 00039 #include "SVGPathSegCurvetoQuadratic.h" 00040 #include "SVGPathSegCurvetoQuadraticSmooth.h" 00041 #include "SVGPathSegLineto.h" 00042 #include "SVGPathSegLinetoHorizontal.h" 00043 #include "SVGPathSegLinetoVertical.h" 00044 #include "SVGPathSegList.h" 00045 #include "SVGPathSegMoveto.h" 00046 #include "SVGPointList.h" 00047 #include "SVGPathElement.h" 00048 #include <math.h> 00049 #include <wtf/MathExtras.h> 00050 00051 namespace WebCore { 00052 00053 /* We use this generic _parseNumber function to allow the Path parsing code to work 00054 * at a higher precision internally, without any unnecessary runtime cost or code 00055 * complexity 00056 */ 00057 template <typename FloatType> static bool _parseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip) 00058 { 00059 int integer, exponent; 00060 FloatType decimal, frac; 00061 int sign, expsign; 00062 const UChar* start = ptr; 00063 00064 exponent = 0; 00065 integer = 0; 00066 frac = 1; 00067 decimal = 0; 00068 sign = 1; 00069 expsign = 1; 00070 00071 // read the sign 00072 if (ptr < end && *ptr == '+') 00073 ptr++; 00074 else if (ptr < end && *ptr == '-') { 00075 ptr++; 00076 sign = -1; 00077 } 00078 00079 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) 00080 // The first character of a number must be one of [0-9+-.] 00081 return false; 00082 00083 // read the integer part 00084 while (ptr < end && *ptr >= '0' && *ptr <= '9') 00085 integer = (integer * 10) + (ptr++)->unicode() - '0'; 00086 00087 if (ptr < end && *ptr == '.') { // read the decimals 00088 ptr++; 00089 00090 // There must be a least one digit following the . 00091 if (ptr >= end || *ptr < '0' || *ptr > '9') 00092 return false; 00093 00094 while (ptr < end && *ptr >= '0' && *ptr <= '9') 00095 decimal += ((ptr++)->unicode() - '0') * (frac *= static_cast<FloatType>(0.1)); 00096 } 00097 00098 // read the exponent part 00099 if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') 00100 && (ptr[1] != 'x' && ptr[1] != 'm')) { 00101 ptr++; 00102 00103 // read the sign of the exponent 00104 if (*ptr == '+') 00105 ptr++; 00106 else if (*ptr == '-') { 00107 ptr++; 00108 expsign = -1; 00109 } 00110 00111 // There must be an exponent 00112 if (ptr >= end || *ptr < '0' || *ptr > '9') 00113 return false; 00114 00115 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 00116 exponent *= 10; 00117 exponent += ptr->unicode() - '0'; 00118 ptr++; 00119 } 00120 } 00121 00122 number = integer + decimal; 00123 number *= sign * static_cast<FloatType>(pow(10.0, expsign * exponent)); 00124 00125 if (start == ptr) 00126 return false; 00127 00128 if (skip) 00129 skipOptionalSpacesOrDelimiter(ptr, end); 00130 00131 return true; 00132 } 00133 00134 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) 00135 { 00136 return _parseNumber(ptr, end, number, skip); 00137 } 00138 00139 // Only used for parsing Paths 00140 static bool parseNumber(const UChar*& ptr, const UChar* end, double& number, bool skip = true) 00141 { 00142 return _parseNumber(ptr, end, number, skip); 00143 } 00144 00145 bool parseNumberOptionalNumber(const String& s, float& x, float& y) 00146 { 00147 if (s.isEmpty()) 00148 return false; 00149 const UChar* cur = s.characters(); 00150 const UChar* end = cur + s.length(); 00151 00152 if (!parseNumber(cur, end, x)) 00153 return false; 00154 00155 if (cur == end) 00156 y = x; 00157 else if (!parseNumber(cur, end, y, false)) 00158 return false; 00159 00160 return cur == end; 00161 } 00162 00163 bool pointsListFromSVGData(SVGPointList* pointsList, const String& points) 00164 { 00165 if (points.isEmpty()) 00166 return true; 00167 const UChar* cur = points.characters(); 00168 const UChar* end = cur + points.length(); 00169 00170 skipOptionalSpaces(cur, end); 00171 00172 bool delimParsed = false; 00173 while (cur < end) { 00174 delimParsed = false; 00175 float xPos = 0.0f; 00176 if (!parseNumber(cur, end, xPos)) 00177 return false; 00178 00179 float yPos = 0.0f; 00180 if (!parseNumber(cur, end, yPos, false)) 00181 return false; 00182 00183 skipOptionalSpaces(cur, end); 00184 00185 if (cur < end && *cur == ',') { 00186 delimParsed = true; 00187 cur++; 00188 } 00189 skipOptionalSpaces(cur, end); 00190 00191 ExceptionCode ec = 0; 00192 pointsList->appendItem(FloatPoint(xPos, yPos), ec); 00193 } 00194 return cur == end && !delimParsed; 00195 } 00196 00208 class SVGPathParser 00209 { 00210 public: 00211 virtual ~SVGPathParser() { } 00212 bool parseSVG(const String& d, bool process = false); 00213 00214 protected: 00215 virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true) = 0; 00216 virtual void svgLineTo(double x1, double y1, bool abs = true) = 0; 00217 virtual void svgLineToHorizontal(double x, bool abs = true) { Q_UNUSED(x); Q_UNUSED(abs); } 00218 virtual void svgLineToVertical(double y, bool abs = true) { Q_UNUSED(y); Q_UNUSED(abs); } 00219 virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) = 0; 00220 virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs = true) { Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(x2); Q_UNUSED(y2); Q_UNUSED(abs); } 00221 virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs = true) { Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(x1); Q_UNUSED(y1); Q_UNUSED(abs); } 00222 virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs = true) {Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(abs);} 00223 virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true) { Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(r1); Q_UNUSED(r2); Q_UNUSED(angle); Q_UNUSED(largeArcFlag); Q_UNUSED(sweepFlag); Q_UNUSED(abs);} 00224 virtual void svgClosePath() = 0; 00225 private: 00226 void calculateArc(bool relative, double& curx, double& cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag); 00227 }; 00228 00229 bool SVGPathParser::parseSVG(const String& s, bool process) 00230 { 00231 if (s.isEmpty()) 00232 return false; 00233 00234 const UChar* ptr = s.characters(); 00235 const UChar* end = ptr + s.length(); 00236 00237 double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; 00238 double px1, py1, px2, py2, px3, py3; 00239 bool closed = true; 00240 00241 if (!skipOptionalSpaces(ptr, end)) // skip any leading spaces 00242 return false; 00243 00244 char command = (ptr++)->unicode(), lastCommand = ' ';// or toLatin1() instead of unicode()??? 00245 if (command != 'm' && command != 'M') // path must start with moveto 00246 return false; 00247 00248 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; 00249 while (1) { 00250 skipOptionalSpaces(ptr, end); // skip spaces between command and first coord 00251 00252 bool relative = false; 00253 00254 switch(command) 00255 { 00256 case 'm': 00257 relative = true; 00258 case 'M': 00259 { 00260 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00261 return false; 00262 00263 if (process) { 00264 subpathx = curx = relative ? curx + tox : tox; 00265 subpathy = cury = relative ? cury + toy : toy; 00266 00267 svgMoveTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury), closed); 00268 } else 00269 svgMoveTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), closed, !relative); 00270 closed = false; 00271 break; 00272 } 00273 case 'l': 00274 relative = true; 00275 case 'L': 00276 { 00277 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00278 return false; 00279 00280 if (process) { 00281 curx = relative ? curx + tox : tox; 00282 cury = relative ? cury + toy : toy; 00283 00284 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 00285 } 00286 else 00287 svgLineTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 00288 break; 00289 } 00290 case 'h': 00291 { 00292 if (!parseNumber(ptr, end, tox)) 00293 return false; 00294 if (process) { 00295 curx = curx + tox; 00296 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 00297 } 00298 else 00299 svgLineToHorizontal(narrowPrecisionToFloat(tox), false); 00300 break; 00301 } 00302 case 'H': 00303 { 00304 if (!parseNumber(ptr, end, tox)) 00305 return false; 00306 if (process) { 00307 curx = tox; 00308 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 00309 } 00310 else 00311 svgLineToHorizontal(narrowPrecisionToFloat(tox)); 00312 break; 00313 } 00314 case 'v': 00315 { 00316 if (!parseNumber(ptr, end, toy)) 00317 return false; 00318 if (process) { 00319 cury = cury + toy; 00320 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 00321 } 00322 else 00323 svgLineToVertical(narrowPrecisionToFloat(toy), false); 00324 break; 00325 } 00326 case 'V': 00327 { 00328 if (!parseNumber(ptr, end, toy)) 00329 return false; 00330 if (process) { 00331 cury = toy; 00332 svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); 00333 } 00334 else 00335 svgLineToVertical(narrowPrecisionToFloat(toy)); 00336 break; 00337 } 00338 case 'z': 00339 case 'Z': 00340 { 00341 // reset curx, cury for next path 00342 if (process) { 00343 curx = subpathx; 00344 cury = subpathy; 00345 } 00346 closed = true; 00347 svgClosePath(); 00348 break; 00349 } 00350 case 'c': 00351 relative = true; 00352 case 'C': 00353 { 00354 if (!parseNumber(ptr, end, x1) || !parseNumber(ptr, end, y1) || 00355 !parseNumber(ptr, end, x2) || !parseNumber(ptr, end, y2) || 00356 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00357 return false; 00358 00359 if (process) { 00360 px1 = relative ? curx + x1 : x1; 00361 py1 = relative ? cury + y1 : y1; 00362 px2 = relative ? curx + x2 : x2; 00363 py2 = relative ? cury + y2 : y2; 00364 px3 = relative ? curx + tox : tox; 00365 py3 = relative ? cury + toy : toy; 00366 00367 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 00368 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 00369 00370 contrlx = relative ? curx + x2 : x2; 00371 contrly = relative ? cury + y2 : y2; 00372 curx = relative ? curx + tox : tox; 00373 cury = relative ? cury + toy : toy; 00374 } 00375 else 00376 svgCurveToCubic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), narrowPrecisionToFloat(x2), 00377 narrowPrecisionToFloat(y2), narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 00378 00379 break; 00380 } 00381 case 's': 00382 relative = true; 00383 case 'S': 00384 { 00385 if (!parseNumber(ptr, end, x2) || !parseNumber(ptr, end, y2) || 00386 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00387 return false; 00388 00389 if (!(lastCommand == 'c' || lastCommand == 'C' || 00390 lastCommand == 's' || lastCommand == 'S')) { 00391 contrlx = curx; 00392 contrly = cury; 00393 } 00394 00395 if (process) { 00396 px1 = 2 * curx - contrlx; 00397 py1 = 2 * cury - contrly; 00398 px2 = relative ? curx + x2 : x2; 00399 py2 = relative ? cury + y2 : y2; 00400 px3 = relative ? curx + tox : tox; 00401 py3 = relative ? cury + toy : toy; 00402 00403 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 00404 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 00405 00406 contrlx = relative ? curx + x2 : x2; 00407 contrly = relative ? cury + y2 : y2; 00408 curx = relative ? curx + tox : tox; 00409 cury = relative ? cury + toy : toy; 00410 } 00411 else 00412 svgCurveToCubicSmooth(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 00413 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 00414 break; 00415 } 00416 case 'q': 00417 relative = true; 00418 case 'Q': 00419 { 00420 if (!parseNumber(ptr, end, x1) || !parseNumber(ptr, end, y1) || 00421 !parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00422 return false; 00423 00424 if (process) { 00425 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); 00426 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); 00427 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); 00428 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); 00429 px3 = relative ? curx + tox : tox; 00430 py3 = relative ? cury + toy : toy; 00431 00432 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 00433 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 00434 00435 contrlx = relative ? curx + x1 : x1; 00436 contrly = relative ? cury + y1 : y1; 00437 curx = relative ? curx + tox : tox; 00438 cury = relative ? cury + toy : toy; 00439 } 00440 else 00441 svgCurveToQuadratic(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 00442 narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 00443 break; 00444 } 00445 case 't': 00446 relative = true; 00447 case 'T': 00448 { 00449 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00450 return false; 00451 if (!(lastCommand == 'q' || lastCommand == 'Q' || 00452 lastCommand == 't' || lastCommand == 'T')) { 00453 contrlx = curx; 00454 contrly = cury; 00455 } 00456 00457 if (process) { 00458 xc = 2 * curx - contrlx; 00459 yc = 2 * cury - contrly; 00460 00461 px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); 00462 py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); 00463 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); 00464 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); 00465 px3 = relative ? curx + tox : tox; 00466 py3 = relative ? cury + toy : toy; 00467 00468 svgCurveToCubic(narrowPrecisionToFloat(px1), narrowPrecisionToFloat(py1), narrowPrecisionToFloat(px2), 00469 narrowPrecisionToFloat(py2), narrowPrecisionToFloat(px3), narrowPrecisionToFloat(py3)); 00470 00471 contrlx = xc; 00472 contrly = yc; 00473 curx = relative ? curx + tox : tox; 00474 cury = relative ? cury + toy : toy; 00475 } 00476 else 00477 svgCurveToQuadraticSmooth(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); 00478 break; 00479 } 00480 case 'a': 00481 relative = true; 00482 case 'A': 00483 { 00484 bool largeArc, sweep; 00485 double angle, rx, ry; 00486 if (!parseNumber(ptr, end, rx) || !parseNumber(ptr, end, ry) || 00487 !parseNumber(ptr, end, angle) || !parseNumber(ptr, end, tox)) 00488 return false; 00489 largeArc = tox == 1; 00490 if (!parseNumber(ptr, end, tox)) 00491 return false; 00492 sweep = tox == 1; 00493 if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) 00494 return false; 00495 00496 // Spec: radii are nonnegative numbers 00497 rx = fabs(rx); 00498 ry = fabs(ry); 00499 00500 if (process) 00501 calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 00502 else 00503 svgArcTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), narrowPrecisionToFloat(rx), narrowPrecisionToFloat(ry), 00504 narrowPrecisionToFloat(angle), largeArc, sweep, !relative); 00505 break; 00506 } 00507 default: 00508 // FIXME: An error should go to the JavaScript console, or the like. 00509 return false; 00510 } 00511 lastCommand = command; 00512 00513 if (ptr >= end) 00514 return true; 00515 00516 // Check for remaining coordinates in the current command. 00517 if ((*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) && 00518 (command != 'z' && command != 'Z')) { 00519 if (command == 'M') 00520 command = 'L'; 00521 else if (command == 'm') 00522 command = 'l'; 00523 } else 00524 command = (ptr++)->unicode(); // or toLatin1() instead of unicode()??? 00525 00526 if (lastCommand != 'C' && lastCommand != 'c' && 00527 lastCommand != 'S' && lastCommand != 's' && 00528 lastCommand != 'Q' && lastCommand != 'q' && 00529 lastCommand != 'T' && lastCommand != 't') { 00530 contrlx = curx; 00531 contrly = cury; 00532 } 00533 } 00534 00535 return false; 00536 } 00537 00538 // This works by converting the SVG arc to "simple" beziers. 00539 // For each bezier found a svgToCurve call is done. 00540 // Adapted from Niko's code in kdelibs/kdecore/svgicons. 00541 // Maybe this can serve in some shared lib? (Rob) 00542 void SVGPathParser::calculateArc(bool relative, double& curx, double& cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) 00543 { 00544 double sin_th, cos_th; 00545 double a00, a01, a10, a11; 00546 double x0, y0, x1, y1, xc, yc; 00547 double d, sfactor, sfactor_sq; 00548 double th0, th1, th_arc; 00549 int i, n_segs; 00550 00551 sin_th = sin(angle * (piDouble / 180.0)); 00552 cos_th = cos(angle * (piDouble / 180.0)); 00553 00554 double dx; 00555 00556 if (!relative) 00557 dx = (curx - x) / 2.0; 00558 else 00559 dx = -x / 2.0; 00560 00561 double dy; 00562 00563 if (!relative) 00564 dy = (cury - y) / 2.0; 00565 else 00566 dy = -y / 2.0; 00567 00568 double _x1 = cos_th * dx + sin_th * dy; 00569 double _y1 = -sin_th * dx + cos_th * dy; 00570 double Pr1 = r1 * r1; 00571 double Pr2 = r2 * r2; 00572 double Px = _x1 * _x1; 00573 double Py = _y1 * _y1; 00574 00575 // Spec : check if radii are large enough 00576 double check = Px / Pr1 + Py / Pr2; 00577 if (check > 1) { 00578 r1 = r1 * sqrt(check); 00579 r2 = r2 * sqrt(check); 00580 } 00581 00582 a00 = cos_th / r1; 00583 a01 = sin_th / r1; 00584 a10 = -sin_th / r2; 00585 a11 = cos_th / r2; 00586 00587 x0 = a00 * curx + a01 * cury; 00588 y0 = a10 * curx + a11 * cury; 00589 00590 if (!relative) 00591 x1 = a00 * x + a01 * y; 00592 else 00593 x1 = a00 * (curx + x) + a01 * (cury + y); 00594 00595 if (!relative) 00596 y1 = a10 * x + a11 * y; 00597 else 00598 y1 = a10 * (curx + x) + a11 * (cury + y); 00599 00600 /* (x0, y0) is current point in transformed coordinate space. 00601 (x1, y1) is new point in transformed coordinate space. 00602 00603 The arc fits a unit-radius circle in this space. 00604 */ 00605 00606 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); 00607 00608 sfactor_sq = 1.0 / d - 0.25; 00609 00610 if (sfactor_sq < 0) 00611 sfactor_sq = 0; 00612 00613 sfactor = sqrt(sfactor_sq); 00614 00615 if (sweepFlag == largeArcFlag) 00616 sfactor = -sfactor; 00617 00618 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); 00619 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); 00620 00621 /* (xc, yc) is center of the circle. */ 00622 th0 = atan2(y0 - yc, x0 - xc); 00623 th1 = atan2(y1 - yc, x1 - xc); 00624 00625 th_arc = th1 - th0; 00626 if (th_arc < 0 && sweepFlag) 00627 th_arc += 2 * piDouble; 00628 else if (th_arc > 0 && !sweepFlag) 00629 th_arc -= 2 * piDouble; 00630 00631 n_segs = (int) (int) ceil(fabs(th_arc / (piDouble * 0.5 + 0.001))); 00632 00633 for(i = 0; i < n_segs; i++) { 00634 double sin_th, cos_th; 00635 double a00, a01, a10, a11; 00636 double x1, y1, x2, y2, x3, y3; 00637 double t; 00638 double th_half; 00639 00640 double _th0 = th0 + i * th_arc / n_segs; 00641 double _th1 = th0 + (i + 1) * th_arc / n_segs; 00642 00643 sin_th = sin(angle * (piDouble / 180.0)); 00644 cos_th = cos(angle * (piDouble / 180.0)); 00645 00646 /* inverse transform compared with rsvg_path_arc */ 00647 a00 = cos_th * r1; 00648 a01 = -sin_th * r2; 00649 a10 = sin_th * r1; 00650 a11 = cos_th * r2; 00651 00652 th_half = 0.5 * (_th1 - _th0); 00653 t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); 00654 x1 = xc + cos(_th0) - t * sin(_th0); 00655 y1 = yc + sin(_th0) + t * cos(_th0); 00656 x3 = xc + cos(_th1); 00657 y3 = yc + sin(_th1); 00658 x2 = x3 + t * sin(_th1); 00659 y2 = y3 - t * cos(_th1); 00660 00661 svgCurveToCubic(narrowPrecisionToFloat(a00 * x1 + a01 * y1), narrowPrecisionToFloat(a10 * x1 + a11 * y1), 00662 narrowPrecisionToFloat(a00 * x2 + a01 * y2), narrowPrecisionToFloat(a10 * x2 + a11 * y2), 00663 narrowPrecisionToFloat(a00 * x3 + a01 * y3), narrowPrecisionToFloat(a10 * x3 + a11 * y3)); 00664 } 00665 00666 if (!relative) 00667 curx = x; 00668 else 00669 curx += x; 00670 00671 if (!relative) 00672 cury = y; 00673 else 00674 cury += y; 00675 } 00676 00677 class PathBuilder : public SVGPathParser 00678 { 00679 public: 00680 bool build(Path* path, const String& d) 00681 { 00682 m_path = path; 00683 return parseSVG(d, true); 00684 } 00685 00686 private: 00687 virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true) 00688 { 00689 current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1)); 00690 current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1)); 00691 if (closed) 00692 m_path->closeSubpath(); 00693 m_path->moveTo(current); 00694 } 00695 virtual void svgLineTo(double x1, double y1, bool abs = true) 00696 { 00697 current.setX(narrowPrecisionToFloat(abs ? x1 : current.x() + x1)); 00698 current.setY(narrowPrecisionToFloat(abs ? y1 : current.y() + y1)); 00699 m_path->addLineTo(current); 00700 } 00701 virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) 00702 { 00703 if (!abs) { 00704 x1 += current.x(); 00705 y1 += current.y(); 00706 x2 += current.x(); 00707 y2 += current.y(); 00708 } 00709 current.setX(narrowPrecisionToFloat(abs ? x : current.x() + x)); 00710 current.setY(narrowPrecisionToFloat(abs ? y : current.y() + y)); 00711 m_path->addBezierCurveTo(FloatPoint::narrowPrecision(x1, y1), FloatPoint::narrowPrecision(x2, y2), current); 00712 } 00713 virtual void svgClosePath() 00714 { 00715 m_path->closeSubpath(); 00716 } 00717 Path* m_path; 00718 FloatPoint current; 00719 }; 00720 00721 bool pathFromSVGData(Path& path, const String& d) 00722 { 00723 PathBuilder builder; 00724 return builder.build(&path, d); 00725 } 00726 00727 class SVGPathSegListBuilder : public SVGPathParser 00728 { 00729 public: 00730 bool build(SVGPathSegList* segList, const String& d, bool process) 00731 { 00732 m_pathSegList = segList; 00733 return parseSVG(d, process); 00734 } 00735 00736 private: 00737 virtual void svgMoveTo(double x1, double y1, bool, bool abs = true) 00738 { 00739 ExceptionCode ec = 0; 00740 00741 if (abs) 00742 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegMovetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 00743 else 00744 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegMovetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 00745 } 00746 virtual void svgLineTo(double x1, double y1, bool abs = true) 00747 { 00748 ExceptionCode ec = 0; 00749 00750 if (abs) 00751 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 00752 else 00753 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1)), ec); 00754 } 00755 virtual void svgLineToHorizontal(double x, bool abs) 00756 { 00757 ExceptionCode ec = 0; 00758 00759 if (abs) 00760 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalAbs(narrowPrecisionToFloat(x)), ec); 00761 else 00762 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoHorizontalRel(narrowPrecisionToFloat(x)), ec); 00763 } 00764 virtual void svgLineToVertical(double y, bool abs) 00765 { 00766 ExceptionCode ec = 0; 00767 00768 if (abs) 00769 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalAbs(narrowPrecisionToFloat(y)), ec); 00770 else 00771 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegLinetoVerticalRel(narrowPrecisionToFloat(y)), ec); 00772 } 00773 virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) 00774 { 00775 ExceptionCode ec = 0; 00776 00777 if (abs) 00778 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 00779 narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 00780 narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)), ec); 00781 else 00782 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 00783 narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 00784 narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)), ec); 00785 } 00786 virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs) 00787 { 00788 ExceptionCode ec = 0; 00789 00790 if (abs) 00791 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 00792 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00793 else 00794 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2), 00795 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00796 } 00797 virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs) 00798 { 00799 ExceptionCode ec = 0; 00800 00801 if (abs) 00802 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 00803 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00804 else 00805 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticRel(narrowPrecisionToFloat(x1), narrowPrecisionToFloat(y1), 00806 narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00807 } 00808 virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs) 00809 { 00810 ExceptionCode ec = 0; 00811 00812 if (abs) 00813 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00814 else 00815 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)), ec); 00816 } 00817 virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs) 00818 { 00819 ExceptionCode ec = 0; 00820 00821 if (abs) 00822 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegArcAbs(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 00823 narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2), 00824 narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag), ec); 00825 else 00826 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegArcRel(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), 00827 narrowPrecisionToFloat(r1), narrowPrecisionToFloat(r2), 00828 narrowPrecisionToFloat(angle), largeArcFlag, sweepFlag), ec); 00829 } 00830 virtual void svgClosePath() 00831 { 00832 ExceptionCode ec = 0; 00833 m_pathSegList->appendItem(SVGPathElement::createSVGPathSegClosePath(), ec); 00834 } 00835 SVGPathSegList* m_pathSegList; 00836 }; 00837 00838 bool pathSegListFromSVGData(SVGPathSegList* path , const String& d, bool process) 00839 { 00840 SVGPathSegListBuilder builder; 00841 return builder.build(path, d, process); 00842 } 00843 00844 Vector<String> parseDelimitedString(const String& input, const char separator) 00845 { 00846 Vector<String> values; 00847 00848 const UChar* ptr = input.characters(); 00849 const UChar* end = ptr + input.length(); 00850 skipOptionalSpaces(ptr, end); 00851 00852 while (ptr < end) { 00853 // Leading and trailing white space, and white space before and after semicolon separators, will be ignored. 00854 const UChar* inputStart = ptr; 00855 while (ptr < end && *ptr != separator) // careful not to ignore whitespace inside inputs 00856 ptr++; 00857 00858 if (ptr == inputStart) 00859 break; 00860 00861 // walk backwards from the ; to ignore any whitespace 00862 const UChar* inputEnd = ptr - 1; 00863 while (inputStart < inputEnd && isWhitespace(*inputEnd)) 00864 inputEnd--; 00865 00866 values.append(String(inputStart, inputEnd - inputStart + 1)); 00867 skipOptionalSpacesOrDelimiter(ptr, end, separator); 00868 } 00869 00870 return values; 00871 } 00872 00873 } 00874 00875 #endif // ENABLE(SVG)
KDE 4.6 API Reference