#include "swft.h" #include "SVGPathParser.h" #include "SVGTransformParser.h" #include "SVGAttributeParser.h" #include "SVGPointsParser.h" #include "SVGStyle.h" #include <libxml/xpathInternals.h> #include <libxslt/xsltutils.h> #include <libxslt/extensions.h> using namespace SWF; /* Create a complete DefineShape3 element. syntax: swft:path( <node> , <shapeid> , <movie-version> ) */ void swft_path(xmlXPathParserContextPtr ctx, int nargs) { xmlChar *styleString, *idString, *pathString; xmlDocPtr doc; xmlNodePtr node; xmlNodeSetPtr nodeSet; double movieVersion; if(nargs != 3) { xmlXPathSetArityError(ctx); return; } movieVersion = xmlXPathPopNumber(ctx); idString = xmlXPathPopString(ctx); nodeSet = xmlXPathPopNodeSet(ctx); if(nodeSet == NULL || nodeSet->nodeNr != 1) { xmlXPathSetTypeError(ctx); return; } node = nodeSet->nodeTab[0]; swft_ctx *c = (swft_ctx*)xsltGetExtData(xsltXPathGetTransformContext(ctx), SWFT_NAMESPACE); SVGStyle style; if(c->styles.size() > 0) { style = c->styles.top(); } style.parseNode(node, c->gradients); if(!style.hasStyle()) { style.setFillColor("#000"); } Shape shape; int xOffset = 0, yOffset = 0; ShapeMaker shaper(shape.getedges(), 20, 20, xOffset, yOffset); shaper.setStyle(style.hasFill() ? 1 : -1, -1, style.hasStroke() ? 1 : -1); AttributeParser attribs; attribs.parseNode(node); if(!xmlStrcmp(node->name, (const xmlChar *)"path")) { const char* pathString = attribs["d"]; if(pathString) { PathParser parser(&shaper); parser.parse(pathString); } } else if(!xmlStrcmp(node->name, (const xmlChar *)"rect")) { double w = attribs.getDouble("width"); double h = attribs.getDouble("height"); if(w > 0 && h > 0) { double rx = attribs.getDouble("rx"); double ry = attribs.getDouble("ry"); if(attribs["rx"] == NULL && attribs["ry"] == NULL) { rx = ry = 0; } else if(attribs["rx"] == NULL && attribs["ry"] != NULL) { rx = ry; } else if(attribs["rx"] != NULL && attribs["ry"] == NULL) { ry = rx; } if(rx > w / 2) rx = w / 2; if(ry > h / 2) ry = h / 2; shaper.rect( attribs.getDouble("x"), attribs.getDouble("y"), w, h, rx, ry); } } else if(!xmlStrcmp(node->name, (const xmlChar *)"circle")) { double r = attribs.getDouble("r"); if(r > 0) shaper.ellipse(attribs.getDouble("cx"), attribs.getDouble("cy"), r, r); } else if(!xmlStrcmp(node->name, (const xmlChar *)"ellipse")) { double rx = attribs.getDouble("rx"); double ry = attribs.getDouble("ry"); if(rx > 0 && ry > 0) shaper.ellipse(attribs.getDouble("cx"), attribs.getDouble("cy"), rx, ry); } else if(!xmlStrcmp(node->name, (const xmlChar *)"line")) { shaper.setup(attribs.getDouble("x1"), attribs.getDouble("y1")); shaper.lineTo(attribs.getDouble("x2"), attribs.getDouble("y2")); } else if(!xmlStrcmp(node->name, (const xmlChar *)"polyline") || !xmlStrcmp(node->name, (const xmlChar *)"polygon")) { PointsParser parser; parser.parse(attribs["points"]); if(parser.getPointCount() >= 2) { Point point, firstPoint; firstPoint = parser.getPoint(); shaper.setup(firstPoint.x, firstPoint.y); int pointCount = parser.getPointCount(); for(int i = 0; i < pointCount; i++) { point = parser.getPoint(); shaper.lineTo(point.x, point.y); } if(!xmlStrcmp(node->name, (const xmlChar *)"polyline")) { shaper.close(false); } else { shaper.close(true); } } } xmlNodePtr shapeNode, styleNode; // make the shape xml doc = xmlNewDoc( (const xmlChar *)"1.0"); if(movieVersion > 7) { node = shapeNode = doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"DefineShape5", NULL ); } else { node = shapeNode = doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"DefineShape3", NULL ); } xmlSetProp( node, (const xmlChar*)"objectID", idString ); // bounds shaper.boundsWriteXML(shapeNode, (style.hasStroke() ? style.getStrokeWidth() / 2 : 0)); // stroke bounds if(movieVersion > 7) shaper.boundsWriteXML(shapeNode); // styles node = xmlNewChild(shapeNode, NULL, (const xmlChar *)"styles", NULL); style.setBounds(shaper.getBounds()); style.writeXML(node, movieVersion); // the shape itself shaper.finish(); node = xmlNewChild(shapeNode, NULL, (const xmlChar *)"shapes", NULL); Context swfctx; shape.writeXML( node, &swfctx ); valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) ); return; } void swft_transform( xmlXPathParserContextPtr ctx, int nargs ) { if(nargs != 1) { xmlXPathSetArityError(ctx); return; } xmlChar *transform = xmlXPathPopString(ctx); if(xmlXPathCheckError(ctx) || (transform == NULL)) { return; } TransformParser transformParser; transformParser.parse((char *)transform); xmlDocPtr doc; doc = xmlNewDoc( (const xmlChar *)"1.0"); doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"Transform", NULL ); transformParser.getMatrix().setXMLProps(doc->xmlRootNode); valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) ); }