Example #1
0
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;
            }
        }
    }
}