void SVGPathParser::parseSVG( const DeprecatedString &s, bool process ) { if(!s.isEmpty()) { DeprecatedString d = s; d = d.replace(',', ' '); d = d.simplifyWhiteSpace(); const char *ptr = d.latin1(); const char *end = d.latin1() + d.length() + 1; double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; double px1, py1, px2, py2, px3, py3; bool relative, closed = true; char command = *(ptr++), lastCommand = ' '; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while( ptr < end ) { if( *ptr == ' ' ) ptr++; relative = false; //std::cout << "Command : " << command << std::endl; switch( command ) { case 'm': relative = true; case 'M': { ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo( curx, cury, closed ); } else svgMoveTo( tox, toy, closed, !relative ); closed = false; break; } case 'l': relative = true; case 'L': { ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo( curx, cury ); } else svgLineTo( tox, toy, !relative ); break; } case 'h': { ptr = parseCoord( ptr, tox ); if( process ) { curx = curx + tox; svgLineTo( curx, cury ); } else svgLineToHorizontal( tox, false ); break; } case 'H': { ptr = parseCoord( ptr, tox ); if( process ) { curx = tox; svgLineTo( curx, cury ); } else svgLineToHorizontal( tox ); break; } case 'v': { ptr = parseCoord( ptr, toy ); if( process ) { cury = cury + toy; svgLineTo( curx, cury ); } else svgLineToVertical( toy, false ); break; } case 'V': { ptr = parseCoord( ptr, toy ); if( process ) { cury = toy; svgLineTo( curx, cury ); } else svgLineToVertical( toy ); break; } case 'z': case 'Z': { // reset curx, cury for next path if( process ) { curx = subpathx; cury = subpathy; } closed = true; svgClosePath(); break; } case 'c': relative = true; case 'C': { ptr = parseCoord( ptr, x1 ); ptr = parseCoord( ptr, y1 ); ptr = parseCoord( ptr, x2 ); ptr = parseCoord( ptr, y2 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { px1 = relative ? curx + x1 : x1; py1 = relative ? cury + y1 : y1; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubic( x1, y1, x2, y2, tox, toy, !relative ); break; } case 's': relative = true; case 'S': { ptr = parseCoord( ptr, x2 ); ptr = parseCoord( ptr, y2 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if(!(lastCommand == 'c' || lastCommand == 'C' || lastCommand == 's' || lastCommand == 'S')) { contrlx = curx; contrly = cury; } if( process ) { px1 = 2 * curx - contrlx; py1 = 2 * cury - contrly; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubicSmooth( x2, y2, tox, toy, !relative ); break; } case 'q': relative = true; case 'Q': { ptr = parseCoord( ptr, x1 ); ptr = parseCoord( ptr, y1 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x1 : x1; contrly = relative ? cury + y1 : y1; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadratic( x1, y1, tox, toy, !relative ); break; } case 't': relative = true; case 'T': { ptr = parseCoord(ptr, tox); ptr = parseCoord(ptr, toy); if(!(lastCommand == 'q' || lastCommand == 'Q' || lastCommand == 't' || lastCommand == 'T')) { contrlx = curx; contrly = cury; } if( process ) { xc = 2 * curx - contrlx; yc = 2 * cury - contrly; px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = xc; contrly = yc; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadraticSmooth( tox, toy, !relative ); break; } case 'a': relative = true; case 'A': { bool largeArc, sweep; double angle, rx, ry; ptr = parseCoord( ptr, rx ); ptr = parseCoord( ptr, ry ); ptr = parseCoord( ptr, angle ); ptr = parseCoord( ptr, tox ); largeArc = tox == 1; ptr = parseCoord( ptr, tox ); sweep = tox == 1; ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); // Spec: radii are nonnegative numbers rx = fabs(rx); ry = fabs(ry); if( process ) calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep ); else svgArcTo( tox, toy, rx, ry, angle, largeArc, sweep, !relative ); break; } default: // FIXME: An error should go to the JavaScript console, or the like. return; } lastCommand = command; if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { // there are still coords in this command if(command == 'M') command = 'L'; else if(command == 'm') command = 'l'; } else command = *(ptr++); if( lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's' && lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't' ) { contrlx = curx; contrly = cury; } } } }
void KoPathShapeLoaderPrivate::parseSvg(const QString &s, bool process) { if (!s.isEmpty()) { QString d = s; d = d.replace(',', ' '); d = d.simplified(); const QByteArray buffer = d.toLatin1(); const char *ptr = buffer.constData(); const char *end = buffer.constData() + buffer.length() + 1; qreal curx = 0.0; qreal cury = 0.0; qreal contrlx, contrly, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; qreal px1, py1, px2, py2, px3, py3; bool relative; char command = *(ptr++), lastCommand = ' '; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while (ptr < end) { if (*ptr == ' ') ++ptr; relative = false; switch (command) { case 'm': relative = true; case 'M': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo(curx, cury); } else svgMoveTo(tox, toy, !relative); break; } case 'l': relative = true; case 'L': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo(curx, cury); } else svgLineTo(tox, toy, !relative); break; } case 'h': { ptr = getCoord(ptr, tox); if (process) { curx = curx + tox; svgLineTo(curx, cury); } else svgLineToHorizontal(tox, false); break; } case 'H': { ptr = getCoord(ptr, tox); if (process) { curx = tox; svgLineTo(curx, cury); } else svgLineToHorizontal(tox); break; } case 'v': { ptr = getCoord(ptr, toy); if (process) { cury = cury + toy; svgLineTo(curx, cury); } else svgLineToVertical(toy, false); break; } case 'V': { ptr = getCoord(ptr, toy); if (process) { cury = toy; svgLineTo(curx, cury); } else svgLineToVertical(toy); break; } case 'z': case 'Z': { // reset curx, cury for next path if (process) { // The "closepath" (Z or z) ends the current subpath and causes an automatic // straight line to be drawn from the current point to the initial point of the // current subpath. If a "closepath" is followed immediately by a "moveto", then // the "moveto" identifies the start point of the next subpath. If a "closepath" // is followed immediately by any other command, then the next subpath starts at // the same initial point as the current subpath. if (*ptr != 'm' && *ptr != 'M') { curx = subpathx; cury = subpathy; } } svgClosePath(); break; } case 'c': relative = true; case 'C': { ptr = getCoord(ptr, x1); ptr = getCoord(ptr, y1); ptr = getCoord(ptr, x2); ptr = getCoord(ptr, y2); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { px1 = relative ? curx + x1 : x1; py1 = relative ? cury + y1 : y1; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubic(x1, y1, x2, y2, tox, toy, !relative); break; } case 's': relative = true; case 'S': { ptr = getCoord(ptr, x2); ptr = getCoord(ptr, y2); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (!(lastCommand == 'c' || lastCommand == 'C' || lastCommand == 's' || lastCommand == 'S')) { contrlx = curx; contrly = cury; } if (process) { px1 = 2 * curx - contrlx; py1 = 2 * cury - contrly; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubicSmooth(x2, y2, tox, toy, !relative); break; } case 'q': relative = true; case 'Q': { ptr = getCoord(ptr, x1); ptr = getCoord(ptr, y1); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x1 : x1; contrly = relative ? cury + y1 : y1; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadratic(x1, y1, tox, toy, !relative); break; } case 't': relative = true; case 'T': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (!(lastCommand == 'q' || lastCommand == 'Q' || lastCommand == 't' || lastCommand == 'T')) { contrlx = curx; contrly = cury; } if (process) { xc = 2 * curx - contrlx; yc = 2 * cury - contrly; px1 = (curx + 2 * xc) * (1.0 / 3.0); py1 = (cury + 2 * yc) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = xc; contrly = yc; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadraticSmooth(tox, toy, !relative); break; } case 'a': relative = true; case 'A': { bool largeArc, sweep; qreal angle, rx, ry; ptr = getCoord(ptr, rx); ptr = getCoord(ptr, ry); ptr = getCoord(ptr, angle); ptr = getCoord(ptr, tox); largeArc = tox == 1; ptr = getCoord(ptr, tox); sweep = tox == 1; ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); // Spec: radii are nonnegative numbers rx = fabs(rx); ry = fabs(ry); if (process) calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); else svgArcTo(tox, toy, rx, ry, angle, largeArc, sweep, !relative); break; } default: { // when svg parser is used for a parsing an odf path an unknown command // can be encountered, so we stop parsing here kDebug(30006) << "KoSvgPathParser::parseSVG(): unknown command \"" << command << "\""; return; } } lastCommand = command; if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { // there are still coords in this command if (command == 'M') command = 'L'; else if (command == 'm') command = 'l'; } else command = *(ptr++); if (lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's' && lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't') { contrlx = curx; contrly = cury; } } } }