File indexing completed on 2024-05-12 15:56:44
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KoPathShapeLoader.h" 0008 #include "KoPathShape.h" 0009 #include <math.h> 0010 #include <FlakeDebug.h> 0011 #include <kis_algebra_2d.h> 0012 0013 class KoPathShapeLoaderPrivate 0014 { 0015 public: 0016 KoPathShapeLoaderPrivate(KoPathShape * p) : path(p) { 0017 Q_ASSERT(path); 0018 path->clear(); 0019 } 0020 0021 void parseSvg(const QString &svgInputData, bool process = false); 0022 0023 void svgMoveTo(qreal x1, qreal y1, bool abs = true); 0024 void svgLineTo(qreal x1, qreal y1, bool abs = true); 0025 void svgLineToHorizontal(qreal x, bool abs = true); 0026 void svgLineToVertical(qreal y, bool abs = true); 0027 void svgCurveToCubic(qreal x1, qreal y1, qreal x2, qreal y2, qreal x, qreal y, bool abs = true); 0028 void svgCurveToCubicSmooth(qreal x, qreal y, qreal x2, qreal y2, bool abs = true); 0029 void svgCurveToQuadratic(qreal x, qreal y, qreal x1, qreal y1, bool abs = true); 0030 void svgCurveToQuadraticSmooth(qreal x, qreal y, bool abs = true); 0031 void svgArcTo(qreal x, qreal y, qreal r1, qreal r2, qreal angle, bool largeArcFlag, bool sweepFlag, bool abs = true); 0032 void svgClosePath(); 0033 0034 const char *getCoord(const char *, qreal &); 0035 const char *getFlag(const char *ptr, bool &flag); 0036 void calculateArc(bool relative, qreal &curx, qreal &cury, qreal angle, qreal x, qreal y, qreal r1, qreal r2, bool largeArcFlag, bool sweepFlag); 0037 0038 KoPathShape * path; ///< the path shape to work on 0039 QPointF lastPoint; 0040 }; 0041 0042 void KoPathShapeLoaderPrivate::parseSvg(const QString &s, bool process) 0043 { 0044 if (!s.isEmpty()) { 0045 QString d = s; 0046 d.replace(',', ' '); 0047 d = d.simplified(); 0048 0049 const QByteArray buffer = d.toLatin1(); 0050 const char *ptr = buffer.constData(); 0051 const char *end = buffer.constData() + buffer.length() + 1; 0052 0053 qreal curx = 0.0; 0054 qreal cury = 0.0; 0055 qreal contrlx, contrly, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; 0056 qreal px1, py1, px2, py2, px3, py3; 0057 bool relative; 0058 char command = *(ptr++), lastCommand = ' '; 0059 0060 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; 0061 while (ptr < end) { 0062 if (*ptr == ' ') 0063 ++ptr; 0064 0065 relative = false; 0066 0067 switch (command) { 0068 case 'm': 0069 relative = true; 0070 Q_FALLTHROUGH(); 0071 case 'M': { 0072 ptr = getCoord(ptr, tox); 0073 ptr = getCoord(ptr, toy); 0074 0075 if (process) { 0076 subpathx = curx = relative ? curx + tox : tox; 0077 subpathy = cury = relative ? cury + toy : toy; 0078 0079 svgMoveTo(curx, cury); 0080 } else 0081 svgMoveTo(tox, toy, !relative); 0082 break; 0083 } 0084 case 'l': 0085 relative = true; 0086 Q_FALLTHROUGH(); 0087 case 'L': { 0088 ptr = getCoord(ptr, tox); 0089 ptr = getCoord(ptr, toy); 0090 0091 if (process) { 0092 curx = relative ? curx + tox : tox; 0093 cury = relative ? cury + toy : toy; 0094 0095 svgLineTo(curx, cury); 0096 } else 0097 svgLineTo(tox, toy, !relative); 0098 break; 0099 } 0100 case 'h': { 0101 ptr = getCoord(ptr, tox); 0102 if (process) { 0103 curx = curx + tox; 0104 svgLineTo(curx, cury); 0105 } else 0106 svgLineToHorizontal(tox, false); 0107 break; 0108 } 0109 case 'H': { 0110 ptr = getCoord(ptr, tox); 0111 if (process) { 0112 curx = tox; 0113 svgLineTo(curx, cury); 0114 } else 0115 svgLineToHorizontal(tox); 0116 break; 0117 } 0118 case 'v': { 0119 ptr = getCoord(ptr, toy); 0120 if (process) { 0121 cury = cury + toy; 0122 svgLineTo(curx, cury); 0123 } else 0124 svgLineToVertical(toy, false); 0125 break; 0126 } 0127 case 'V': { 0128 ptr = getCoord(ptr, toy); 0129 if (process) { 0130 cury = toy; 0131 svgLineTo(curx, cury); 0132 } else 0133 svgLineToVertical(toy); 0134 break; 0135 } 0136 case 'z': 0137 Q_FALLTHROUGH(); 0138 case 'Z': { 0139 // reset curx, cury for next path 0140 if (process) { 0141 curx = subpathx; 0142 cury = subpathy; 0143 } 0144 svgClosePath(); 0145 break; 0146 } 0147 case 'c': 0148 relative = true; 0149 Q_FALLTHROUGH(); 0150 case 'C': { 0151 ptr = getCoord(ptr, x1); 0152 ptr = getCoord(ptr, y1); 0153 ptr = getCoord(ptr, x2); 0154 ptr = getCoord(ptr, y2); 0155 ptr = getCoord(ptr, tox); 0156 ptr = getCoord(ptr, toy); 0157 0158 if (process) { 0159 px1 = relative ? curx + x1 : x1; 0160 py1 = relative ? cury + y1 : y1; 0161 px2 = relative ? curx + x2 : x2; 0162 py2 = relative ? cury + y2 : y2; 0163 px3 = relative ? curx + tox : tox; 0164 py3 = relative ? cury + toy : toy; 0165 0166 svgCurveToCubic(px1, py1, px2, py2, px3, py3); 0167 0168 contrlx = relative ? curx + x2 : x2; 0169 contrly = relative ? cury + y2 : y2; 0170 curx = relative ? curx + tox : tox; 0171 cury = relative ? cury + toy : toy; 0172 } else 0173 svgCurveToCubic(x1, y1, x2, y2, tox, toy, !relative); 0174 0175 break; 0176 } 0177 case 's': 0178 relative = true; 0179 Q_FALLTHROUGH(); 0180 case 'S': { 0181 ptr = getCoord(ptr, x2); 0182 ptr = getCoord(ptr, y2); 0183 ptr = getCoord(ptr, tox); 0184 ptr = getCoord(ptr, toy); 0185 if (!(lastCommand == 'c' || lastCommand == 'C' || 0186 lastCommand == 's' || lastCommand == 'S')) { 0187 contrlx = curx; 0188 contrly = cury; 0189 } 0190 0191 if (process) { 0192 px1 = 2 * curx - contrlx; 0193 py1 = 2 * cury - contrly; 0194 px2 = relative ? curx + x2 : x2; 0195 py2 = relative ? cury + y2 : y2; 0196 px3 = relative ? curx + tox : tox; 0197 py3 = relative ? cury + toy : toy; 0198 0199 svgCurveToCubic(px1, py1, px2, py2, px3, py3); 0200 0201 contrlx = relative ? curx + x2 : x2; 0202 contrly = relative ? cury + y2 : y2; 0203 curx = relative ? curx + tox : tox; 0204 cury = relative ? cury + toy : toy; 0205 } else 0206 svgCurveToCubicSmooth(x2, y2, tox, toy, !relative); 0207 break; 0208 } 0209 case 'q': 0210 relative = true; 0211 Q_FALLTHROUGH(); 0212 case 'Q': { 0213 ptr = getCoord(ptr, x1); 0214 ptr = getCoord(ptr, y1); 0215 ptr = getCoord(ptr, tox); 0216 ptr = getCoord(ptr, toy); 0217 0218 if (process) { 0219 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); 0220 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); 0221 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); 0222 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); 0223 px3 = relative ? curx + tox : tox; 0224 py3 = relative ? cury + toy : toy; 0225 0226 svgCurveToCubic(px1, py1, px2, py2, px3, py3); 0227 0228 contrlx = relative ? curx + x1 : x1; 0229 contrly = relative ? cury + y1 : y1; 0230 curx = relative ? curx + tox : tox; 0231 cury = relative ? cury + toy : toy; 0232 } else 0233 svgCurveToQuadratic(x1, y1, tox, toy, !relative); 0234 break; 0235 } 0236 case 't': 0237 relative = true; 0238 Q_FALLTHROUGH(); 0239 case 'T': { 0240 ptr = getCoord(ptr, tox); 0241 ptr = getCoord(ptr, toy); 0242 if (!(lastCommand == 'q' || lastCommand == 'Q' || 0243 lastCommand == 't' || lastCommand == 'T')) { 0244 contrlx = curx; 0245 contrly = cury; 0246 } 0247 0248 if (process) { 0249 xc = 2 * curx - contrlx; 0250 yc = 2 * cury - contrly; 0251 0252 px1 = (curx + 2 * xc) * (1.0 / 3.0); 0253 py1 = (cury + 2 * yc) * (1.0 / 3.0); 0254 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); 0255 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); 0256 px3 = relative ? curx + tox : tox; 0257 py3 = relative ? cury + toy : toy; 0258 0259 svgCurveToCubic(px1, py1, px2, py2, px3, py3); 0260 0261 contrlx = xc; 0262 contrly = yc; 0263 curx = relative ? curx + tox : tox; 0264 cury = relative ? cury + toy : toy; 0265 } else 0266 svgCurveToQuadraticSmooth(tox, toy, !relative); 0267 break; 0268 } 0269 case 'a': 0270 relative = true; 0271 Q_FALLTHROUGH(); 0272 case 'A': { 0273 bool largeArc = false; 0274 bool sweep = false; 0275 qreal angle, rx, ry; 0276 ptr = getCoord(ptr, rx); 0277 ptr = getCoord(ptr, ry); 0278 ptr = getCoord(ptr, angle); 0279 ptr = getFlag(ptr, largeArc); 0280 ptr = getFlag(ptr, sweep); 0281 ptr = getCoord(ptr, tox); 0282 ptr = getCoord(ptr, toy); 0283 0284 // Spec: radii are nonnegative numbers 0285 rx = fabs(rx); 0286 ry = fabs(ry); 0287 0288 if (process) 0289 calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 0290 else 0291 svgArcTo(tox, toy, rx, ry, angle, largeArc, sweep, !relative); 0292 break; 0293 } 0294 default: { 0295 // when svg parser is used for a parsing an odf path an unknown command 0296 // can be encountered, so we stop parsing here 0297 debugFlake << "KoSvgPathParser::parseSVG(): unknown command \"" << command << "\""; 0298 return; 0299 } 0300 } 0301 0302 lastCommand = command; 0303 0304 if (*ptr == '+' || *ptr == '-' || *ptr == '.' || (*ptr >= '0' && *ptr <= '9')) { 0305 // there are still coords in this command 0306 if (command == 'M') 0307 command = 'L'; 0308 else if (command == 'm') 0309 command = 'l'; 0310 } else 0311 command = *(ptr++); 0312 0313 if (lastCommand != 'C' && lastCommand != 'c' && 0314 lastCommand != 'S' && lastCommand != 's' && 0315 lastCommand != 'Q' && lastCommand != 'q' && 0316 lastCommand != 'T' && lastCommand != 't') { 0317 contrlx = curx; 0318 contrly = cury; 0319 } 0320 } 0321 } 0322 } 0323 0324 // parses the coord into number and forwards to the next token 0325 const char * KoPathShapeLoaderPrivate::getCoord(const char *ptr, qreal &number) 0326 { 0327 int integer, exponent; 0328 qreal decimal, frac; 0329 int sign, expsign; 0330 0331 exponent = 0; 0332 integer = 0; 0333 frac = 1.0; 0334 decimal = 0; 0335 sign = 1; 0336 expsign = 1; 0337 0338 // read the sign 0339 if (*ptr == '+') 0340 ++ptr; 0341 else if (*ptr == '-') { 0342 ++ptr; 0343 sign = -1; 0344 } 0345 0346 // read the integer part 0347 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 0348 integer = (integer * 10) + *(ptr++) - '0'; 0349 if (*ptr == '.') { // read the decimals 0350 ++ptr; 0351 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 0352 decimal += (*(ptr++) - '0') * (frac *= 0.1); 0353 } 0354 0355 if (*ptr == 'e' || *ptr == 'E') { // read the exponent part 0356 ++ptr; 0357 0358 // read the sign of the exponent 0359 if (*ptr == '+') 0360 ++ptr; 0361 else if (*ptr == '-') { 0362 ++ptr; 0363 expsign = -1; 0364 } 0365 0366 exponent = 0; 0367 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9') { 0368 exponent *= 10; 0369 exponent += *ptr - '0'; 0370 ++ptr; 0371 } 0372 } 0373 number = integer + decimal; 0374 number *= sign * pow((qreal)10, qreal(expsign * exponent)); 0375 0376 // skip the following space 0377 if (*ptr == ' ') 0378 ++ptr; 0379 0380 return ptr; 0381 } 0382 0383 const char *KoPathShapeLoaderPrivate::getFlag(const char *ptr, bool &flag) 0384 { 0385 // check for '0' or '1' 0386 if (*ptr != '0' && *ptr != '1') { 0387 return ptr; 0388 } 0389 flag = (*ptr == '1'); 0390 ++ptr; 0391 0392 if (*ptr == ' ') { 0393 ++ptr; 0394 } 0395 return ptr; 0396 } 0397 0398 // This works by converting the SVG arc to "simple" beziers. 0399 // For each bezier found a svgToCurve call is done. 0400 void KoPathShapeLoaderPrivate::calculateArc(bool relative, qreal &curx, qreal &cury, qreal angle, qreal x, qreal y, qreal rx, qreal ry, bool largeArcFlag, bool sweepFlag) 0401 { 0402 // if radii are zero or the endpoints of ellipse are same as its start point, then use lineTo/don't do 0403 // anything. 0404 if (qFuzzyCompare(rx, 0.0) || qFuzzyCompare(ry, 0.0) 0405 || (!relative && qFuzzyCompare(curx - x, 0) && qFuzzyCompare(cury - y, 0)) 0406 || (relative && qFuzzyCompare(x, 0) && qFuzzyCompare(y, 0))) { 0407 qreal x2 = x; 0408 qreal y2 = y; 0409 0410 if (relative) { 0411 x2 += curx; 0412 y2 += cury; 0413 } 0414 svgLineTo(x2, y2); 0415 return; 0416 } 0417 0418 const qreal angleRadians = angle * (M_PI / 180.0); 0419 const qreal sin_th = sin(angleRadians); 0420 const qreal cos_th = cos(angleRadians); 0421 0422 qreal dx; 0423 qreal x2 = x; 0424 if (!relative) { 0425 dx = (curx - x) / 2.0; 0426 } else { 0427 dx = -(x / 2.0); 0428 x2 = curx + x; 0429 } 0430 0431 qreal dy; 0432 qreal y2 = y; 0433 if (!relative) { 0434 dy = (cury - y) / 2.0; 0435 } else { 0436 dy = -(y / 2.0); 0437 y2 = cury + y; 0438 } 0439 0440 // From SVG spec 0441 0442 // Step 1: Compute (x1_prime, y1_prime) 0443 const qreal x1Prime = cos_th * dx + sin_th * dy; 0444 const qreal y1Prime = -sin_th * dx + cos_th * dy; 0445 0446 // eq. 5.1 0447 const qreal x1PrimeSq = x1Prime * x1Prime; 0448 const qreal y1PrimeSq = y1Prime * y1Prime; 0449 0450 // Step 2: Compute (c_x_prime, c_y_prime) 0451 qreal rxSq = rx * rx; 0452 qreal rySq = ry * ry; 0453 0454 // Spec : check if radii are large enough 0455 // eq. 6.2 0456 const qreal check = x1PrimeSq / rxSq + y1PrimeSq / rySq; 0457 if (check > 1) { 0458 // eq. 6.3 0459 rx = rx * sqrt(check); 0460 ry = ry * sqrt(check); 0461 0462 rxSq = rx * rx; 0463 rySq = ry * ry; 0464 } 0465 0466 // Step 2: Compute (c_x_prime, c_y_prime) 0467 const qreal radiiSq = rxSq * rySq; 0468 const qreal ellipseValue = rxSq * y1PrimeSq + rySq * x1PrimeSq; 0469 0470 qreal coef = sqrt(std::fabs((radiiSq - ellipseValue) / ellipseValue)); 0471 if (sweepFlag == largeArcFlag) { 0472 coef = -coef; 0473 } 0474 // eq. 5.2 0475 const qreal cxPrime = coef * (rx * y1Prime) / ry; 0476 const qreal cyPrime = coef * -(ry * x1Prime) / rx; 0477 0478 // Step 3: Compute (c_x, c_y) from (c_x_prime, c_y_prime) 0479 // eq. 5.3 0480 const qreal cx = cos_th * cxPrime - sin_th * cyPrime + (curx + x2) * 0.5; 0481 const qreal cy = sin_th * cxPrime + cos_th * cyPrime + (cury + y2) * 0.5; 0482 0483 // Step 4: Compute angle and delta 0484 const QPointF v = {(x1Prime - cxPrime) / rx, (y1Prime - cyPrime) / ry}; 0485 // eq. 5.5 0486 const qreal theta = KisAlgebra2D::angleBetweenVectors({1.0, 0.0}, v); 0487 // eq. 5.6 0488 qreal delta = std::fmod( 0489 KisAlgebra2D::angleBetweenVectors(v, {(-x1Prime - cxPrime) / rx, (-y1Prime - cyPrime) / ry}), 0490 M_PI * 2); 0491 0492 if (sweepFlag && delta < 0) { 0493 delta += (M_PI * 2); 0494 } else if (!sweepFlag && delta > 0) { 0495 delta -= (M_PI * 2); 0496 } 0497 0498 int n_segs = (int)ceil(fabs(delta / (M_PI * 0.25))); 0499 0500 // From: http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf 0501 for (int i = 0; i < n_segs; ++i) { 0502 const qreal eta1 = theta + i * delta / n_segs; 0503 const qreal eta2 = theta + (i + 1) * delta / n_segs; 0504 0505 const qreal etaHalf = 0.5 * (eta2 - eta1); 0506 0507 const qreal cosAngle = cos(angleRadians); 0508 const qreal sinAngle = sin(angleRadians); 0509 0510 auto ellipseArcToPoint = [sinAngle, cosAngle](qreal cx, qreal cy, qreal eta, qreal rx, qreal ry) { 0511 qreal x = cx + (rx * cosAngle * cos(eta)) - (ry * sinAngle * sin(eta)); 0512 qreal y = cy + (rx * sinAngle * cos(eta)) + (ry * cosAngle * sin(eta)); 0513 return QPointF(x, y); 0514 }; 0515 auto ellipseDerivativeArcToPoint = [sinAngle, cosAngle](qreal eta, qreal rx, qreal ry) { 0516 qreal x = -(rx * cosAngle * sin(eta)) - (ry * sinAngle * cos(eta)); 0517 qreal y = -(rx * sinAngle * sin(eta)) + (ry * cosAngle * cos(eta)); 0518 return QPointF(x, y); 0519 }; 0520 0521 // bezier control points 0522 const QPointF p1 = ellipseArcToPoint(cx, cy, eta1, rx, ry); 0523 const QPointF p2 = ellipseArcToPoint(cx, cy, eta2, rx, ry); 0524 0525 const qreal alpha = sin(eta2 - eta1) * (sqrt(4 + 3 * tan(etaHalf) * tan(etaHalf)) - 1) / 3; 0526 0527 const QPointF q1 = p1 + alpha * ellipseDerivativeArcToPoint(eta1, rx, ry); 0528 const QPointF q2 = p2 - alpha * ellipseDerivativeArcToPoint(eta2, rx, ry); 0529 0530 svgCurveToCubic(q1.x(), q1.y(), q2.x(), q2.y(), p2.x(), p2.y()); 0531 } 0532 0533 if (!relative) 0534 curx = x; 0535 else 0536 curx += x; 0537 0538 if (!relative) 0539 cury = y; 0540 else 0541 cury += y; 0542 } 0543 0544 void KoPathShapeLoaderPrivate::svgMoveTo(qreal x1, qreal y1, bool abs) 0545 { 0546 if (abs) 0547 lastPoint = QPointF(x1, y1); 0548 else 0549 lastPoint += QPointF(x1, y1); 0550 path->moveTo(lastPoint); 0551 } 0552 0553 void KoPathShapeLoaderPrivate::svgLineTo(qreal x1, qreal y1, bool abs) 0554 { 0555 if (abs) 0556 lastPoint = QPointF(x1, y1); 0557 else 0558 lastPoint += QPointF(x1, y1); 0559 0560 path->lineTo(lastPoint); 0561 } 0562 0563 void KoPathShapeLoaderPrivate::svgLineToHorizontal(qreal x, bool abs) 0564 { 0565 if (abs) 0566 lastPoint.setX(x); 0567 else 0568 lastPoint.rx() += x; 0569 0570 path->lineTo(lastPoint); 0571 } 0572 0573 void KoPathShapeLoaderPrivate::svgLineToVertical(qreal y, bool abs) 0574 { 0575 if (abs) 0576 lastPoint.setY(y); 0577 else 0578 lastPoint.ry() += y; 0579 0580 path->lineTo(lastPoint); 0581 } 0582 0583 void KoPathShapeLoaderPrivate::svgCurveToCubic(qreal x1, qreal y1, qreal x2, qreal y2, qreal x, qreal y, bool abs) 0584 { 0585 QPointF p1, p2; 0586 if (abs) { 0587 p1 = QPointF(x1, y1); 0588 p2 = QPointF(x2, y2); 0589 lastPoint = QPointF(x, y); 0590 } else { 0591 p1 = lastPoint + QPointF(x1, y1); 0592 p2 = lastPoint + QPointF(x2, y2); 0593 lastPoint += QPointF(x, y); 0594 } 0595 0596 path->curveTo(p1, p2, lastPoint); 0597 } 0598 0599 void KoPathShapeLoaderPrivate::svgCurveToCubicSmooth(qreal x, qreal y, qreal x2, qreal y2, bool abs) 0600 { 0601 Q_UNUSED(x); 0602 Q_UNUSED(y); 0603 Q_UNUSED(x2); 0604 Q_UNUSED(y2); 0605 Q_UNUSED(abs); 0606 // TODO implement 0607 } 0608 0609 void KoPathShapeLoaderPrivate::svgCurveToQuadratic(qreal x, qreal y, qreal x1, qreal y1, bool abs) 0610 { 0611 Q_UNUSED(x); 0612 Q_UNUSED(y); 0613 Q_UNUSED(x1); 0614 Q_UNUSED(y1); 0615 Q_UNUSED(abs); 0616 // TODO implement 0617 } 0618 0619 void KoPathShapeLoaderPrivate::svgCurveToQuadraticSmooth(qreal x, qreal y, bool abs) 0620 { 0621 Q_UNUSED(x); 0622 Q_UNUSED(y); 0623 Q_UNUSED(abs); 0624 // TODO implement 0625 } 0626 0627 void KoPathShapeLoaderPrivate::svgArcTo(qreal x, qreal y, qreal r1, qreal r2, qreal angle, bool largeArcFlag, bool sweepFlag, bool abs) 0628 { 0629 Q_UNUSED(x); 0630 Q_UNUSED(y); 0631 Q_UNUSED(r1); 0632 Q_UNUSED(r2); 0633 Q_UNUSED(angle); 0634 Q_UNUSED(largeArcFlag); 0635 Q_UNUSED(sweepFlag); 0636 Q_UNUSED(abs); 0637 // TODO implement 0638 } 0639 0640 void KoPathShapeLoaderPrivate::svgClosePath() 0641 { 0642 path->closeMerge(); 0643 } 0644 0645 KoPathShapeLoader::KoPathShapeLoader(KoPathShape *path) 0646 : d(new KoPathShapeLoaderPrivate(path)) 0647 { 0648 } 0649 0650 KoPathShapeLoader::~KoPathShapeLoader() 0651 { 0652 delete d; 0653 } 0654 0655 void KoPathShapeLoader::parseSvg(const QString &s, bool process) 0656 { 0657 d->parseSvg(s, process); 0658 }