• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

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) {}
00218         virtual void svgLineToVertical(double y, bool abs = true) {}
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) {}
00221         virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs = true) {}
00222         virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs = true) {}
00223         virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true) {}
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)

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal