root/src/swft/SVGPathParser.cpp

/* [<][>][^][v][top][bottom][index][help] */
#include "SVGPathParser.h"

using namespace std;

namespace SWF {

PathParser::PathParser(ShapeMaker *shapeMaker) {
        shaper = shapeMaker;
}

void PathParser::parse(const char *path) {
        char currentChar, currentCmd = 0;
        CharType charType;
        bool repeated = false;

        //use <= strlen() to make sure the last parameter is parsed correctly 
        for(size_t i = 0; i <= strlen(path); i++) {
                currentChar = path[i];
                charType = getCharType(currentChar);

                if(charType != OTHER) {
                        if(params.size() != 0 && params.size() == getParameterCount(currentCmd)) {
                                executeCommand(currentCmd, repeated);
                                params.clear();

                                repeated = true;
                        }

                        if(charType == COMMAND_ABSOLUTE || charType == COMMAND_RELATIVE) {
                                if(params.size() > 0) {
                                        cerr << "WARNING: too much parameters in SVG path" << endl;
                                        params.clear();
                                }
                                
                                currentCmd = currentChar;

                                if(getParameterCount(currentCmd) == 0) {
                                        executeCommand(currentCmd, repeated);
                                }

                                repeated = false;
                        }
                } else {
                        char *str = (char*)path + i;
                        char *tailPtr;
                        
                        params.push_back(strtod(str, &tailPtr));
                        i += tailPtr - str - 1;
                }
                
        }
        if(params.size() > 0) {
                cerr << "WARNING: too much parameters in SVG path" << endl;
                params.clear();
        }
        shaper->close(false);
        shaper->finish();
}

void PathParser::executeCommand(char command, bool repeated) {
        switch(command) {
                case 'Q':
                        shaper->curveTo(params[0], params[1], params[2], params[3]);
                        break;

                case 'q':
                        shaper->curveToR(params[0], params[1], params[2], params[3]);
                        break;

                case 'T':
                        shaper->smoothCurveTo(params[0], params[1]);
                        break;

                case 't':
                        shaper->smoothCurveToR(params[0], params[1]);
                        break;

                case 'C':
                        shaper->cubicTo(params[0], params[1], params[2], params[3], params[4], params[5]);
                        break;

                case 'c':
                        shaper->cubicToR(params[0], params[1], params[2], params[3], params[4], params[5]);
                        break;

                case 'S':
                        shaper->smoothCubicTo(params[0], params[1], params[2], params[3]);
                        break;

                case 's':
                        shaper->smoothCubicToR(params[0], params[1], params[2], params[3]);
                        break;

                case 'L':
                        shaper->lineTo(params[0], params[1]);
                        break;

                case 'l':
                        shaper->lineToR(params[0], params[1]);
                        break;

                case 'M':
                        if(repeated) {
                                shaper->lineTo(params[0], params[1]);
                        } else {
                                shaper->close(false);
                                shaper->setup(params[0], params[1]);
                        }
                        break;

                case 'm':
                        if(repeated) {
                                shaper->lineToR(params[0], params[1]);
                        } else {
                                shaper->close(false);
                                shaper->setupR(params[0], params[1]);
                        }
                        break;

                case 'H':
                        shaper->lineTo(params[0], shaper->getLastY());
                        break;

                case 'h':
                        shaper->lineToR(params[0], 0);
                        break;
                        
                case 'V':
                        shaper->lineTo(shaper->getLastX(), params[0]);
                        break;

                case 'v':
                        shaper->lineToR(0, params[0]);
                        break;

                case 'A':
                        shaper->arcTo(params[0], params[1], params[2], (params[3] == 1), (params[4] == 1), params[5], params[6]);
                        break;

                case 'a':
                        shaper->arcToR(params[0], params[1], params[2], (params[3] == 1), (params[4] == 1), params[5], params[6]);
                        break;

                case 'Z':
                case 'z':
                        shaper->close();
                        break;
                
                default:
                        cerr << "WARNING: SVG path command not implemented (" << command << ")" << endl;
                        break;
        }
}

}

/* [<][>][^][v][top][bottom][index][help] */