001/* 002 * SVG Salamander 003 * Copyright (c) 2004, Mark McKay 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or 007 * without modification, are permitted provided that the following 008 * conditions are met: 009 * 010 * - Redistributions of source code must retain the above 011 * copyright notice, this list of conditions and the following 012 * disclaimer. 013 * - Redistributions in binary form must reproduce the above 014 * copyright notice, this list of conditions and the following 015 * disclaimer in the documentation and/or other materials 016 * provided with the distribution. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 029 * OF THE POSSIBILITY OF SUCH DAMAGE. 030 * 031 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other 032 * projects can be found at http://www.kitfox.com 033 * 034 * Created on February 18, 2004, 5:09 PM 035 */ 036 037package com.kitfox.svg; 038 039 040import java.util.*; 041import java.net.*; 042import org.xml.sax.*; 043import org.xml.sax.helpers.DefaultHandler; 044 045import com.kitfox.svg.animation.*; 046import java.util.logging.Level; 047import java.util.logging.Logger; 048 049/** 050 * @author Mark McKay 051 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a> 052 */ 053public class SVGLoader extends DefaultHandler 054{ 055 final HashMap nodeClasses = new HashMap(); 056 //final HashMap attribClasses = new HashMap(); 057 final LinkedList buildStack = new LinkedList(); 058 059 final HashSet ignoreClasses = new HashSet(); 060 061 final SVGLoaderHelper helper; 062 063 /** 064 * The diagram that represents the base of this SVG document we're loading. 065 * Will be augmented to include node indexing info and other useful stuff. 066 */ 067 final SVGDiagram diagram; 068 069// SVGElement loadRoot; 070 071 //Used to keep track of document elements that are not part of the SVG namespace 072 int skipNonSVGTagDepth = 0; 073 int indent = 0; 074 075 final boolean verbose; 076 077 /** Creates a new instance of SVGLoader */ 078 public SVGLoader(URI xmlBase, SVGUniverse universe) 079 { 080 this(xmlBase, universe, false); 081 } 082 083 public SVGLoader(URI xmlBase, SVGUniverse universe, boolean verbose) 084 { 085 this.verbose = verbose; 086 087 diagram = new SVGDiagram(xmlBase, universe); 088 089 //Compile a list of important builder classes 090 nodeClasses.put("a", A.class); 091 nodeClasses.put("animate", Animate.class); 092 nodeClasses.put("animatecolor", AnimateColor.class); 093 nodeClasses.put("animatemotion", AnimateMotion.class); 094 nodeClasses.put("animatetransform", AnimateTransform.class); 095 nodeClasses.put("circle", Circle.class); 096 nodeClasses.put("clippath", ClipPath.class); 097 nodeClasses.put("defs", Defs.class); 098 nodeClasses.put("desc", Desc.class); 099 nodeClasses.put("ellipse", Ellipse.class); 100 nodeClasses.put("filter", Filter.class); 101 nodeClasses.put("font", Font.class); 102 nodeClasses.put("font-face", FontFace.class); 103 nodeClasses.put("g", Group.class); 104 nodeClasses.put("glyph", Glyph.class); 105 nodeClasses.put("hkern", Hkern.class); 106 nodeClasses.put("image", ImageSVG.class); 107 nodeClasses.put("line", Line.class); 108 nodeClasses.put("lineargradient", LinearGradient.class); 109 nodeClasses.put("marker", Marker.class); 110 nodeClasses.put("metadata", Metadata.class); 111 nodeClasses.put("missing-glyph", MissingGlyph.class); 112 nodeClasses.put("path", Path.class); 113 nodeClasses.put("pattern", PatternSVG.class); 114 nodeClasses.put("polygon", Polygon.class); 115 nodeClasses.put("polyline", Polyline.class); 116 nodeClasses.put("radialgradient", RadialGradient.class); 117 nodeClasses.put("rect", Rect.class); 118 nodeClasses.put("set", SetSmil.class); 119 nodeClasses.put("shape", ShapeElement.class); 120 nodeClasses.put("stop", Stop.class); 121 nodeClasses.put("style", Style.class); 122 nodeClasses.put("svg", SVGRoot.class); 123 nodeClasses.put("symbol", Symbol.class); 124 nodeClasses.put("text", Text.class); 125 nodeClasses.put("title", Title.class); 126 nodeClasses.put("tspan", Tspan.class); 127 nodeClasses.put("use", Use.class); 128 129 ignoreClasses.add("midpointstop"); 130 131 //attribClasses.put("clip-path", StyleUrl.class); 132 //attribClasses.put("color", StyleColor.class); 133 134 helper = new SVGLoaderHelper(xmlBase, universe, diagram); 135 } 136 137 private String printIndent(int indent, String indentStrn) 138 { 139 StringBuffer sb = new StringBuffer(); 140 for (int i = 0; i < indent; i++) 141 { 142 sb.append(indentStrn); 143 } 144 return sb.toString(); 145 } 146 147 public void startDocument() throws SAXException 148 { 149// System.err.println("Start doc"); 150 151// buildStack.clear(); 152 } 153 154 public void endDocument() throws SAXException 155 { 156// System.err.println("End doc"); 157 } 158 159 public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) throws SAXException 160 { 161 if (verbose) 162 { 163 System.err.println(printIndent(indent, " ") + "Starting parse of tag " + sName+ ": " + namespaceURI); 164 } 165 indent++; 166 167 if (skipNonSVGTagDepth != 0 || (!namespaceURI.equals("") && !namespaceURI.equals(SVGElement.SVG_NS))) 168 { 169 skipNonSVGTagDepth++; 170 return; 171 } 172 173 sName = sName.toLowerCase(); 174 175//javax.swing.JOptionPane.showMessageDialog(null, sName); 176 177 Object obj = nodeClasses.get(sName); 178 if (obj == null) 179 { 180 if (!ignoreClasses.contains(sName)) 181 { 182 if (verbose) 183 { 184 System.err.println("SVGLoader: Could not identify tag '" + sName + "'"); 185 } 186 } 187 return; 188 } 189 190//Debug info tag depth 191//for (int i = 0; i < buildStack.size(); i++) System.err.print(" "); 192//System.err.println("+" + sName); 193 194 try { 195 Class cls = (Class)obj; 196 SVGElement svgEle = (SVGElement)cls.newInstance(); 197 198 SVGElement parent = null; 199 if (buildStack.size() != 0) parent = (SVGElement)buildStack.getLast(); 200 svgEle.loaderStartElement(helper, attrs, parent); 201 202 buildStack.addLast(svgEle); 203 } 204 catch (Exception e) 205 { 206 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, 207 "Could not load", e); 208 throw new SAXException(e); 209 } 210 211 } 212 213 public void endElement(String namespaceURI, String sName, String qName) 214 throws SAXException 215 { 216 indent--; 217 if (verbose) 218 { 219 System.err.println(printIndent(indent, " ") + "Ending parse of tag " + sName+ ": " + namespaceURI); 220 } 221 222 if (skipNonSVGTagDepth != 0) 223 { 224 skipNonSVGTagDepth--; 225 return; 226 } 227 228 sName = sName.toLowerCase(); 229 230 Object obj = nodeClasses.get(sName); 231 if (obj == null) return; 232 233//Debug info tag depth 234//for (int i = 0; i < buildStack.size(); i++) System.err.print(" "); 235//System.err.println("-" + sName); 236 237 try { 238 SVGElement svgEle = (SVGElement)buildStack.removeLast(); 239 240 svgEle.loaderEndElement(helper); 241 242 SVGElement parent = null; 243 if (buildStack.size() != 0) 244 { 245 parent = (SVGElement)buildStack.getLast(); 246 } 247 //else loadRoot = (SVGElement)svgEle; 248 249 if (parent != null) 250 { 251 parent.loaderAddChild(helper, svgEle); 252 } 253 else 254 { 255 diagram.setRoot((SVGRoot)svgEle); 256 } 257 258 } 259 catch (Exception e) 260 { 261 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, 262 "Could not parse", e); 263 throw new SAXException(e); 264 } 265 } 266 267 public void characters(char buf[], int offset, int len) 268 throws SAXException 269 { 270 if (skipNonSVGTagDepth != 0) 271 { 272 return; 273 } 274 275 if (buildStack.size() != 0) 276 { 277 SVGElement parent = (SVGElement)buildStack.getLast(); 278 String s = new String(buf, offset, len); 279 parent.loaderAddText(helper, s); 280 } 281 } 282 283 public void processingInstruction(String target, String data) 284 throws SAXException 285 { 286 //Check for external style sheet 287 } 288 289// public SVGElement getLoadRoot() { return loadRoot; } 290 public SVGDiagram getLoadedDiagram() { return diagram; } 291}