root/src/swft/SVGStyle.cpp

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

#define TMP_STRLEN 0xFF

using namespace std;

namespace SWF {

SVGStyle::SVGStyle() {
        _hasFill = false;
        _hasFillGradient = false;
        _hasStroke = false;
        _hasStrokeGradient = false;
        _hasStyle = false;

        _hasLineCap = false;
        lineCap = CAP_BUTT;

        _hasLineJoin = false;
        lineJoin = JOIN_MITER;
        miterLimit = 4;

        strokeWidth = 1;
}

void SVGStyle::parseNode(xmlNodePtr node, map<string, SVGGradient*> &gradients) {
        AttributeParser parser;
        parser.parseNode(node);

        map<string, string> &attributes = parser.getAttributes();
        for(map<string, string>::iterator iter = attributes.begin(); iter != attributes.end(); iter++) {
                const string &attribute = (*iter).first;
                const string &valueStr = (*iter).second;
                const char *value = valueStr.c_str();
                
                if(attribute == "stroke") {
                        SVGGradient *gradient = getGradient(valueStr, gradients);
                        if(gradient) {
                                        strokeGradient = gradient;
                                        _hasStrokeGradient = true;
                                        _hasStroke = true;
                        } else {
                                setStrokeColor(value);
                        }
                } else if(attribute == "stroke-width") {
                        setStrokeWidth(atof(value));
                } else if(attribute == "stroke-opacity") {
                        setStrokeAlpha(atof(value));
                } else if(attribute == "stroke-linecap") {
                        setLineCap(value);
                } else if(attribute == "stroke-linejoin") {
                        setLineJoin(value);
                } else if(attribute == "stroke-miterlimit") {
                        setMiterLimit(atof(value));
                } else if(attribute == "fill") {
                        SVGGradient *gradient = getGradient(valueStr, gradients);
                        if(gradient) {
                                        fillGradient = gradient;
                                        _hasFillGradient = true;
                                        _hasFill = true;
                        } else {
                                setFillColor(value);
                        }
                } else if(attribute == "fill-opacity") {
                        setFillAlpha(atof(value));
                }
        }
}

SVGGradient *SVGStyle::getGradient(const string &str, map<string, SVGGradient*> &gradients) {
        if(str.substr(0, 4) == "url(" && str.substr(str.length() - 1) == ")") {
                map<string, SVGGradient*>::iterator i;
                i = gradients.find(str.substr(5, str.length() - 6));
                if(i != gradients.end()) {
                        return (*i).second;
                } else {
                        return NULL;
                }
        } else {
                return NULL;
        }
}

void SVGStyle::setLineCap(const char *cap) {
        if(!strcmp(cap, "butt")) {
                lineCap = CAP_BUTT;
                _hasLineCap = true;
                _hasStyle = true;
        } else if(!strcmp(cap, "round")) {
                lineCap = CAP_ROUND;
                _hasLineCap = true;
                _hasStyle = true;
        } else if(!strcmp(cap, "square")) {
                lineCap = CAP_SQUARE;
                _hasLineCap = true;
                _hasStyle = true;
        }
}

void SVGStyle::setLineJoin(const char *join) {
        if(!strcmp(join, "miter")) {
                lineJoin = JOIN_MITER;
                _hasLineJoin = true;
                _hasStyle = true;
        } else if(!strcmp(join, "round")) {
                lineJoin = JOIN_ROUND;
                _hasLineJoin = true;
                _hasStyle = true;
        } else if(!strcmp(join, "bevel")) {
                lineJoin = JOIN_BEVEL;
                _hasLineJoin = true;
                _hasStyle = true;
        }
}

void SVGStyle::writeXML(xmlNodePtr parent, double movieVersion) {
        xmlNodePtr node, styleNode;
        char tmp[TMP_STRLEN];

        styleNode = xmlNewChild(parent, NULL, (const xmlChar *)"StyleList", NULL);

        if(_hasFill) {
                node = xmlNewChild(styleNode, NULL, (const xmlChar *)"fillStyles", NULL);
                if(_hasFillGradient) {
                        fillGradient->writeXML(node, bounds, (movieVersion >= 8));
                } else {
                        node = xmlNewChild(node, NULL, (const xmlChar *)"Solid", NULL);
                        node = xmlNewChild(node, NULL, (const xmlChar *)"color", NULL);
                        fill.writeXML(node);
                }
        }

        if(_hasStroke) {
                node = xmlNewChild(styleNode, NULL, (const xmlChar *)"lineStyles", NULL);

                if(movieVersion >= 8) {
                        node = xmlNewChild(node, NULL, (const xmlChar *)"LineStyle", NULL);
                        snprintf(tmp,TMP_STRLEN,"%f", strokeWidth * 20);
                        xmlSetProp(node, (const xmlChar *)"width", (const xmlChar *)&tmp);
                        snprintf(tmp, TMP_STRLEN, "%i", lineCap);
                        xmlSetProp(node, (const xmlChar *)"startCapStyle", (const xmlChar *)&tmp);
                        snprintf(tmp, TMP_STRLEN, "%i", lineJoin);
                        xmlSetProp(node, (const xmlChar *)"jointStyle", (const xmlChar *)&tmp);
                        xmlSetProp(node, (const xmlChar *)"hasFill", (const xmlChar *)(_hasStrokeGradient ? "1" : "0"));
                        xmlSetProp(node, (const xmlChar *)"noHScale", (const xmlChar *)"0");
                        xmlSetProp(node, (const xmlChar *)"noVScale", (const xmlChar *)"0");
                        xmlSetProp(node, (const xmlChar *)"pixelHinting", (const xmlChar *)"0");
                        xmlSetProp(node, (const xmlChar *)"reserved", (const xmlChar *)"0");
                        xmlSetProp(node, (const xmlChar *)"noClose", (const xmlChar *)"0");
                        snprintf(tmp, TMP_STRLEN, "%i", lineCap);
                        xmlSetProp(node, (const xmlChar *)"endCapStyle", (const xmlChar *)&tmp);

                        if(lineJoin == JOIN_MITER) {
                                snprintf(tmp, TMP_STRLEN, "%f", miterLimit);
                                xmlSetProp(node, (const xmlChar *)"miterLimitFactor", (const xmlChar *)&tmp);
                        }
                        
                        if(_hasStrokeGradient) {
                                node = xmlNewChild(node, NULL, (const xmlChar *)"fillStyles", NULL);
                                strokeGradient->writeXML(node, bounds, (movieVersion >= 8));
                        } else {
                                node = xmlNewChild(node, NULL, (const xmlChar *)"fillColor", NULL);
                                stroke.writeXML(node);
                        }
                } else {
                        node = xmlNewChild(node, NULL, (const xmlChar *)"LineStyle", NULL);
                        snprintf(tmp,TMP_STRLEN,"%f", strokeWidth * 20);
                        xmlSetProp(node, (const xmlChar *)"width", (const xmlChar *)&tmp);
                        node = xmlNewChild(node, NULL, (const xmlChar *)"color", NULL);
                        stroke.writeXML(node);

                        if(_hasLineCap || _hasLineJoin) {
                                cerr << "WARNING: some svg features aren't supported before swf version 8" << endl;
                        }
                }
        }
}

}

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