/* Traverse the whole DOM and process each node in three ways 1. Save XML doc as a nested object tree to be saved out 2. Parse graphics into ofPaths 3. Save reference to current processed path node in a lookup flatlist info belongs to ofxSVG node is the current object in the tree being parsed, preserving nesting cnl is the childlist from original DOM state is tinysvg control parse value */ svgtiny_code processChildren(svgInfo &info, ofPtr<svgNode> node, Poco::XML::ChildNodesList *cnl, struct svgtiny_parse_state state){ svgtiny_code code = svgtiny_OK; int i = 0, l = cnl->length(); while( i < l ){ Element *child = (Poco::XML::Element *) cnl->item(i); ofPtr<svgNode> childnode(new svgNode()); // I think this can't happen? if (child->nodeType() == Poco::XML::Element::ELEMENT_NODE) { const char *name = (const char *) child->localName().c_str(); if (strcmp(name, "svg") == 0){ ofLog()<<"processing a nested svg (not root)"<<endl; //this svg is within root svg svgDef svgDef; svgDef.width = ofToString(child->getAttribute("width").c_str()); svgDef.height = ofToString(child->getAttribute("height").c_str()); svgDef.x = ofToString(child->getAttribute("x").c_str()); svgDef.y = ofToString(child->getAttribute("y").c_str()); svgDef.viewbox = ofToString(child->getAttribute("viewbox").c_str()); /*recursive call for any nodes inside svg Poco::XML::ChildNodesList *cnl = ( Poco::XML::ChildNodesList *) child->childNodes(); int ii = 0, ll = cnl->length(); while( ii < ll ) { ofLog()<<"recursive svg call"<<ii<<endl; Poco::XML::Element * grandchild = (Poco::XML::Element *) cnl->item(ii); svgNode childnode; svgtiny_code code = processChildren(info,childnode,grandchild,state); svgDef.nodes.push_back(childnode); if (code != svgtiny_OK) return code; ii++; }*/ childnode->svg = svgDef; childnode->type =SVG_TAG_TYPE_SVG; node->children.push_back(childnode); //recursive call...it seeems svg and groups are treated the same code = svgtiny_parse_svg(info,child, state,childnode); }else if (strcmp(name, "g") == 0){ /// ofLog()<<"processing group"<<endl; svgGroupDef gDef; gDef.transform = ofToString(child->getAttribute("transform").c_str()); gDef.fill = ofToString(child->getAttribute("fill").c_str()); gDef.stroke = ofToString(child->getAttribute("stroke").c_str()); gDef.stroke_width = ofToString(child->getAttribute("stroke-width").c_str()); gDef.stroke_miterlimit = ofToString(child->getAttribute("stroke-miterlimit").c_str()); gDef.fill_opacity = ofToString(child->getAttribute("fill-opacity").c_str()); gDef.stroke_opacity = ofToString(child->getAttribute("stroke-opacity").c_str()); //recursive call for any nodes inside svg /*Poco::XML::ChildNodesList *cnl = ( Poco::XML::ChildNodesList *) child->childNodes(); int ii = 0, ll = cnl->length(); while( ii < ll ) { ofLog()<<"recursive grop call"<<ii<<endl; Poco::XML::Element * grandchild = (Poco::XML::Element *) cnl->item(ii); svgNode childnode; svgtiny_code code = processChildren(info,childnode,grandchild,state); gDef.nodes.push_back(childnode); if (code != svgtiny_OK) return code; ii++; } */ childnode->group = gDef; childnode->type =SVG_TAG_TYPE_GROUP; node->children.push_back(childnode); //recursive call...it seeems svg and groups are treated the same code = svgtiny_parse_svg(info,child, state,childnode); }else if (strcmp(name, "a") == 0){ //a node?! who cares code = svgtiny_parse_svg(info,child, state,childnode); }else if (strcmp(name, "path") == 0){ //ofLog()<<"-------- "<<child->getAttribute("d").c_str()<<endl; //<path fill="#D14E8F" stroke="#0C0404" stroke-miterlimit="10" d="M2802.998,4477.002c-2.002-30-2.002-31.001,7.998-8.003c5,13.999,6.006,28.003,1.006,33.003 C2807.998,4506.001,2802.998,4495,2802.998,4477.002z"/> //info.paths.push_back(child->getAttribute("d").c_str()); //info.paths.push_back("<"+ofToString(child->nodeName().c_str())+"/>"); //"<path fill='#000000' stroke='#000000' stroke-width='1' stroke-miterlimit='10' d='M590 35 c0 -19 5 -35 11 -35 7 0 9 10 4 28 -4 17 -3 24 3 17 6 -5 12 -19 15 -30 4 -16 5 -16 6 5 1 15 -7 30 -19 38 -19 11 -20 10 -20 -23z' />" svgPathDef pDef; pDef.d = ofToString(child->getAttribute("d").c_str()); pDef.fill = ofToString(child->getAttribute("fill").c_str()); pDef.stroke = ofToString(child->getAttribute("stroke").c_str()); pDef.stroke_width = ofToString(child->getAttribute("stroke-width").c_str()); pDef.stroke_miterlimit = ofToString(child->getAttribute("stroke-miterlimit").c_str()); //info.paths.push_back(pDef); pDef.fill_opacity = ofToString(child->getAttribute("fill-opacity").c_str()); pDef.stroke_opacity = ofToString(child->getAttribute("stroke-opacity").c_str()); childnode->path = pDef; childnode->type = SVG_TAG_TYPE_PATH; node->children.push_back(childnode); // ofLog()<<"defining currNode"<<endl; state.currNode = childnode; /* if(info.svgs.size()>0){ //this path is within a nested svg info.svgs[info.svgs.size()-1]->groups[info.svgs[info.svgs.size()-1]->groups.size()-1]->paths.push_back(pDef); }else{ //this path belongs within group in root svg info.groups[info.groups.size()-1]->paths.push_back(pDef); } */ code = svgtiny_parse_path(child, state); } else if (strcmp(name, "rect") == 0){ svgRectDef pDef; pDef.fill = ofToString(child->getAttribute("fill").c_str()); pDef.stroke = ofToString(child->getAttribute("stroke").c_str()); pDef.stroke_width = ofToString(child->getAttribute("stroke-width").c_str()); pDef.stroke_miterlimit = ofToString(child->getAttribute("stroke-miterlimit").c_str()); //info.paths.push_back(pDef); pDef.fill_opacity = ofToString(child->getAttribute("fill-opacity").c_str()); pDef.stroke_opacity = ofToString(child->getAttribute("stroke-opacity").c_str()); pDef.x = ofToString(child->getAttribute("x").c_str()); pDef.y = ofToString(child->getAttribute("y").c_str()); pDef.width = ofToString(child->getAttribute("width").c_str()); pDef.height = ofToString(child->getAttribute("height").c_str()); childnode->rect = pDef; childnode->type = SVG_TAG_TYPE_RECT; node->children.push_back(childnode); // ofLog()<<"defining currNode"<<endl; state.currNode = childnode; code = svgtiny_parse_rect(child, state); }else if (strcmp(name, "circle") == 0){ code = svgtiny_parse_circle(child, state); }else if (strcmp(name, "ellipse") == 0){ code = svgtiny_parse_ellipse(child, state); }else if (strcmp(name, "line") == 0){ code = svgtiny_parse_line(child, state); } else if (strcmp(name, "polyline") == 0){ code = svgtiny_parse_poly(child, state, false); }else if (strcmp(name, "polygon") == 0){ code = svgtiny_parse_poly(child, state, true); } else if (strcmp(name, "text") == 0){ code = svgtiny_parse_text(child, state); } // not sure about this } else if (child->nodeType() == Poco::XML::Element::TEXT_NODE) { const char *name = (const char *) child->localName().c_str(); if (strcmp(name, "text") == 0) code = svgtiny_parse_text(child, state); } //pNode = it.nextNode(); if (code != svgtiny_OK){ return code; } i++; } return code; };
svgtiny_code svgtiny_parse_svg(xmlNode *svg, struct svgtiny_parse_state state) { float x, y, width, height; xmlAttr *view_box; xmlNode *child; svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(svg, &state); svgtiny_parse_font_attributes(svg, &state); /* parse viewBox */ view_box = xmlHasProp(svg, (const xmlChar *) "viewBox"); if (view_box) { const char *s = (const char *) view_box->children->content; float min_x, min_y, vwidth, vheight; if (sscanf(s, "%f,%f,%f,%f", &min_x, &min_y, &vwidth, &vheight) == 4 || sscanf(s, "%f %f %f %f", &min_x, &min_y, &vwidth, &vheight) == 4) { state.ctm.a = (float) state.viewport_width / vwidth; state.ctm.d = (float) state.viewport_height / vheight; state.ctm.e += -min_x * state.ctm.a; state.ctm.f += -min_y * state.ctm.d; } } svgtiny_parse_transform_attributes(svg, &state); for (child = svg->children; child; child = child->next) { svgtiny_code code = svgtiny_OK; if (child->type == XML_ELEMENT_NODE) { const char *name = (const char *) child->name; if (strcmp(name, "svg") == 0) code = svgtiny_parse_svg(child, state); else if (strcmp(name, "g") == 0) code = svgtiny_parse_svg(child, state); else if (strcmp(name, "a") == 0) code = svgtiny_parse_svg(child, state); else if (strcmp(name, "path") == 0) code = svgtiny_parse_path(child, state); else if (strcmp(name, "rect") == 0) code = svgtiny_parse_rect(child, state); else if (strcmp(name, "circle") == 0) code = svgtiny_parse_circle(child, state); else if (strcmp(name, "ellipse") == 0) code = svgtiny_parse_ellipse(child, state); else if (strcmp(name, "line") == 0) code = svgtiny_parse_line(child, state); else if (strcmp(name, "polyline") == 0) code = svgtiny_parse_poly(child, state, false); else if (strcmp(name, "polygon") == 0) code = svgtiny_parse_poly(child, state, true); else if (strcmp(name, "text") == 0) code = svgtiny_parse_text(child, state); } if (code != svgtiny_OK) return code; } return svgtiny_OK; }
svgtiny_code svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state) { float x, y, width, height; dom_string *view_box; dom_element *child; dom_exception exc; svgtiny_setup_state_local(&state); svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(svg, &state); svgtiny_parse_font_attributes(svg, &state); exc = dom_element_get_attribute(svg, state.interned_viewBox, &view_box); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (view_box) { char *s = strndup(dom_string_data(view_box), dom_string_byte_length(view_box)); float min_x, min_y, vwidth, vheight; if (sscanf(s, "%f,%f,%f,%f", &min_x, &min_y, &vwidth, &vheight) == 4 || sscanf(s, "%f %f %f %f", &min_x, &min_y, &vwidth, &vheight) == 4) { state.ctm.a = (float) state.viewport_width / vwidth; state.ctm.d = (float) state.viewport_height / vheight; state.ctm.e += -min_x * state.ctm.a; state.ctm.f += -min_y * state.ctm.d; } free(s); dom_string_unref(view_box); } svgtiny_parse_transform_attributes(svg, &state); exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } while (child != NULL) { dom_element *next; dom_node_type nodetype; svgtiny_code code = svgtiny_OK; exc = dom_node_get_node_type(child, &nodetype); if (exc != DOM_NO_ERR) { dom_node_unref(child); return svgtiny_LIBDOM_ERROR; } if (nodetype == DOM_ELEMENT_NODE) { dom_string *nodename; exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(state.interned_svg, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_g, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_a, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_path, nodename)) code = svgtiny_parse_path(child, state); else if (dom_string_caseless_isequal(state.interned_rect, nodename)) code = svgtiny_parse_rect(child, state); else if (dom_string_caseless_isequal(state.interned_circle, nodename)) code = svgtiny_parse_circle(child, state); else if (dom_string_caseless_isequal(state.interned_ellipse, nodename)) code = svgtiny_parse_ellipse(child, state); else if (dom_string_caseless_isequal(state.interned_line, nodename)) code = svgtiny_parse_line(child, state); else if (dom_string_caseless_isequal(state.interned_polyline, nodename)) code = svgtiny_parse_poly(child, state, false); else if (dom_string_caseless_isequal(state.interned_polygon, nodename)) code = svgtiny_parse_poly(child, state, true); else if (dom_string_caseless_isequal(state.interned_text, nodename)) code = svgtiny_parse_text(child, state); dom_string_unref(nodename); } if (code != svgtiny_OK) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, (dom_node **) (void *) &next); dom_node_unref(child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } child = next; } svgtiny_cleanup_state_local(&state); return svgtiny_OK; }