/** * Phoebe DOM Implementation. * * This is a C++ approximation of the W3C DOM model, which follows * fairly closely the specifications in the various .idl files, copies of * which are provided for reference. Most important is this one: * * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html * * Authors: * Bob Jamison * * Copyright (C) 2005-2008 Bob Jamison * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * ======================================================================= * NOTES * * */ #include "svgreader.h" #include "dom/cssreader.h" #include "dom/ucd.h" #include "xmlreader.h" #include #define SVG_NAMESPACE "http://www.w3.org/2000/svg" namespace org { namespace w3c { namespace dom { namespace svg { //######################################################################### //# M E S S A G E S //######################################################################### /** * */ void SVGReader::error(char const *fmt, ...) { va_list args; fprintf(stderr, "SVGReader:error: "); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args) ; fprintf(stderr, "\n"); } /** * */ void SVGReader::trace(char const *fmt, ...) { va_list args; fprintf(stdout, "SVGReader: "); va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args) ; fprintf(stdout, "\n"); } //######################################################################### //# P A R S I N G //######################################################################### /** * Get the character at the position and record the fact */ XMLCh SVGReader::get(int p) { if (p >= parselen) return 0; XMLCh ch = parsebuf[p]; //printf("%c", ch); lastPosition = p; return ch; } /** * Test if the given substring exists at the given position * in parsebuf. Use get() in case of out-of-bounds */ bool SVGReader::match(int pos, char const *str) { while (*str) { if (get(pos++) != (XMLCh) *str++) return false; } return true; } /** * */ int SVGReader::skipwhite(int p) { while (p < parselen) { //# XML COMMENT if (match(p, "")) { p+=3; done=true; break; } p++; } lastPosition = p; if (!done) { error("unterminated comment"); return -1; } } //# C comment else if (match(p, "/*")) { p+=2; bool done=false; while (p'9') break; str.push_back(ch); p++; } if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9') { p++; str.push_back('.'); while (p < parselen) { XMLCh ch = get(p); if (ch<'0' || ch>'9') break; str.push_back(ch); p++; } } if (p>p0) { char *start = (char *)str.c_str(); char *end = NULL; double val = strtod(start, &end); if (end > start) { result = val; return p; } } //not a number return p0; } #endif /** * get a word from the buffer */ int SVGReader::getNumber(int p0, double &result) { int p=p0; char buf[64]; int i; for (i=0 ; i<63 && p start) { result = val; int count = (int)(end - start); p = p0 + count; return p; } //not a number return p0; } bool SVGReader::parseTransform(const DOMString &str) { parsebuf = str; parselen = str.size(); //printf("transform:%s\n", str.c_str()); SVGTransformList transformList; int p = 0; while (p < parselen) { p = skipwhite(p); DOMString name; int p2 = getWord(p, name); if (p2<0) return false; if (p2<=p) { error("transform: need transform name"); //return false; break; } p = p2; //printf("transform name:%s\n", name.c_str()); //######### MATRIX if (name == "matrix") { p = skipwhite(p); if (get(p++) != '(') { error("matrix transform needs opening '('"); return false; } int nrVals = 0; double vals[6]; bool seenBrace = false; while (p < parselen && nrVals < 6) { p = skipwhite(p); double val = 0.0; p2 = getNumber(p, val); if (p2<0) return false; if (p2<=p) { error("matrix() expected number"); return false; } vals[nrVals++] = val; p = skipwhite(p2); XMLCh ch = get(p); if (ch == ',') { p++; p = skipwhite(p); ch = get(p); } if (ch == ')') { seenBrace = true; p++; break; } } if (!seenBrace) { error("matrix() needs closing brace"); return false; } if (nrVals != 6) { error("matrix() requires exactly 6 arguments"); return false; } //We got our arguments //printf("translate: %f %f %f %f %f %f\n", // vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]); SVGMatrix matrix(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]); SVGTransform transform; transform.setMatrix(matrix); transformList.appendItem(transform); } //######### TRANSLATE else if (name == "translate") { p = skipwhite(p); if (get(p++) != '(') { error("matrix transform needs opening '('"); return false; } p = skipwhite(p); double x = 0.0; p2 = getNumber(p, x); if (p2<0) return false; if (p2<=p) { error("translate() expected 'x' value"); return false; } p = skipwhite(p2); if (get(p) == ',') { p++; p = skipwhite(p); } double y = 0.0; p2 = getNumber(p, y); if (p2<0) return false; if (p2<=p) //no y specified. use default y = 0.0; p = skipwhite(p2); if (get(p++) != ')') { error("translate() needs closing ')'"); return false; } //printf("translate: %f %f\n", x, y); SVGTransform transform; transform.setTranslate(x, y); transformList.appendItem(transform); } //######### SCALE else if (name == "scale") { p = skipwhite(p); if (get(p++) != '(') { error("scale transform needs opening '('"); return false; } p = skipwhite(p); double x = 0.0; p2 = getNumber(p, x); if (p2<0) return false; if (p2<=p) { error("scale() expected 'x' value"); return false; } p = skipwhite(p2); if (get(p) == ',') { p++; p = skipwhite(p); } double y = 0.0; p2 = getNumber(p, y); if (p2<0) return false; if (p2<=p) //no y specified. use default y = x; // y is same as x. uniform scaling p = skipwhite(p2); if (get(p++) != ')') { error("scale() needs closing ')'"); return false; } //printf("scale: %f %f\n", x, y); SVGTransform transform; transform.setScale(x, y); transformList.appendItem(transform); } //######### ROTATE else if (name == "rotate") { p = skipwhite(p); if (get(p++) != '(') { error("rotate transform needs opening '('"); return false; } p = skipwhite(p); double angle = 0.0; p2 = getNumber(p, angle); if (p2<0) return false; if (p2<=p) { error("rotate() expected 'angle' value"); return false; } p = skipwhite(p2); if (get(p) == ',') { p++; p = skipwhite(p); } double cx = 0.0; double cy = 0.0; p2 = getNumber(p, cx); if (p2>p) { p = skipwhite(p2); if (get(p) == ',') { p++; p = skipwhite(p); } p2 = getNumber(p, cy); if (p2<0) return false; if (p2<=p) { error("rotate() arguments should be either rotate(angle) or rotate(angle, cx, cy)"); return false; } p = skipwhite(p2); } if (get(p++) != ')') { error("rotate() needs closing ')'"); return false; } //printf("rotate: %f %f %f\n", angle, cx, cy); SVGTransform transform; transform.setRotate(angle, cx, cy); transformList.appendItem(transform); } //######### SKEWX else if (name == "skewX") { p = skipwhite(p); if (get(p++) != '(') { error("skewX transform needs opening '('"); return false; } p = skipwhite(p); double x = 0.0; p2 = getNumber(p, x); if (p2<0) return false; if (p2<=p) { error("skewX() expected 'x' value"); return false; } p = skipwhite(p2); if (get(p++) != ')') { error("skewX() needs closing ')'"); return false; } //printf("skewX: %f\n", x); SVGTransform transform; transform.setSkewX(x); transformList.appendItem(transform); } //######### SKEWY else if (name == "skewY") { p = skipwhite(p); if (get(p++) != '(') { error("skewY transform needs opening '('"); return false; } p = skipwhite(p); double y = 0.0; p2 = getNumber(p, y); if (p2<0) return false; if (p2<=p) { error("skewY() expected 'y' value"); return false; } p = skipwhite(p2); if (get(p++) != ')') { error("skewY() needs closing ')'"); return false; } //printf("skewY: %f\n", y); SVGTransform transform; transform.setSkewY(y); transformList.appendItem(transform); } //### NONE OF THE ABOVE else { error("unknown transform type:'%s'", name.c_str()); } p = skipwhite(p); XMLCh ch = get(p); if (ch == ',') { p++; p = skipwhite(p); } }//WHILE pgetNamespaceURI(); //printf("namespaceURI:%s\n", namespaceURI.c_str()); DOMString tagName = sourceElem->getTagName(); printf("tag name:%s\n", tagName.c_str()); ElementImplPtr newElement = NULL; if (namespaceURI != SVG_NAMESPACE) { newElement = new SVGSVGElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else //## SVG!! { //#################################################### //## ATTRIBUTES //#################################################### DOMString style = sourceElem->getAttribute("style"); if (style.size() > 0) { css::CssReader parser; style.insert(0, "{"); style.append("}"); //printf("CSS:%s\n", style.c_str()); if (!parser.parse(style)) { error("parsing style attribute"); } else { //printf("##parsed!\n"); } } DOMString transform = sourceElem->getAttribute("transform"); if (transform.size() > 0) { if (!parseTransform(transform)) { error("parsing transform attribute"); } else { //printf("##parsed!\n"); } } //#################################################### //## ELEMENT - SPECIFIC //#################################################### if (tagName == "svg") { newElement = new SVGSVGElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "title") { newElement = new SVGTitleElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "desc") { newElement = new SVGDescElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "defs") { newElement = new SVGDefsElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "style") { newElement = new SVGStyleElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "g") { newElement = new SVGGElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } else if (tagName == "path") { newElement = new SVGPathElementImpl(); newElement->assign(*sourceElem); parent->appendChild(newElement); } } NodeList children = sourceElem->getChildNodes(); int nodeCount = children.getLength(); for (int i=0 ; igetNodeType(); if (typ == Node::TEXT_NODE) { NodePtr newNode = doc->createTextNode(child->getNodeValue()); parent->appendChild(newNode); } else if (typ == Node::CDATA_SECTION_NODE) { NodePtr newNode = doc->createCDATASection(child->getNodeValue()); parent->appendChild(newNode); } else if (newElement.get() && typ == Node::ELEMENT_NODE) { //ElementImplPtr childElement = dynamic_cast(child.get()); //parseElement(newElement, childElement); } } return true; } /** * */ SVGDocumentPtr SVGReader::parse(const DocumentPtr src) { if (!src) { error("NULL source document"); return NULL; } DOMImplementationImpl impl; doc = new SVGDocumentImpl(&impl, SVG_NAMESPACE, "svg" , NULL); SVGElementImplPtr destElem = dynamic_pointer_cast(doc->getRootElement()); ElementImplPtr srcElem = dynamic_pointer_cast(src->getDocumentElement()); if (!parseElement(destElem, srcElem)) { return NULL; } return doc; } /** * */ SVGDocumentPtr SVGReader::parse(const DOMString &buf) { /* remember, smartptrs are null-testable*/ SVGDocumentPtr svgdoc; XmlReader parser; DocumentPtr doc = parser.parse(buf); if (!doc) { return svgdoc; } svgdoc = parse(doc); return svgdoc; } /** * */ SVGDocumentPtr SVGReader::parseFile(const DOMString &fileName) { /* remember, smartptrs are null-testable*/ SVGDocumentPtr svgdoc; XmlReader parser; DocumentPtr doc = parser.parseFile(fileName); if (!doc) { error("Could not load xml doc"); return svgdoc; } svgdoc = parse(doc); return svgdoc; } } //namespace svg } //namespace dom } //namespace w3c } //namespace org /*######################################################################### ## E N D O F F I L E #########################################################################*/