/src/org/mt4j/util/xml/svg/SVGLoader.java

http://mt4j.googlecode.com/ · Java · 2589 lines · 1581 code · 318 blank · 690 comment · 297 complexity · a0e5b4b9ced62d905339e4e815e4d032 MD5 · raw file

Large files are truncated click here to view the full file

  1. /***********************************************************************
  2. * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. ***********************************************************************/
  18. package org.mt4j.util.xml.svg;
  19. import java.awt.BasicStroke;
  20. import java.awt.Color;
  21. import java.awt.Graphics;
  22. import java.awt.Graphics2D;
  23. import java.awt.MultipleGradientPaint.CycleMethod;
  24. import java.awt.RadialGradientPaint;
  25. import java.awt.Rectangle;
  26. import java.awt.Stroke;
  27. import java.awt.geom.AffineTransform;
  28. import java.awt.geom.Point2D;
  29. import java.awt.geom.Rectangle2D;
  30. import java.io.File;
  31. import java.io.InputStream;
  32. import java.net.URI;
  33. import java.text.AttributedCharacterIterator;
  34. import java.text.AttributedCharacterIterator.Attribute;
  35. import java.util.ArrayList;
  36. import java.util.Iterator;
  37. import java.util.LinkedList;
  38. import java.util.List;
  39. import java.util.Map;
  40. import java.util.Set;
  41. import java.util.Stack;
  42. import javax.media.opengl.GL;
  43. import javax.media.opengl.glu.GLU;
  44. import javax.swing.JPanel;
  45. import org.apache.batik.bridge.AbstractSVGGradientElementBridge;
  46. import org.apache.batik.bridge.AbstractSVGGradientElementBridge.SVGStopElementBridge;
  47. import org.apache.batik.bridge.AbstractSVGGradientElementBridge.Stop;
  48. import org.apache.batik.bridge.Bridge;
  49. import org.apache.batik.bridge.BridgeContext;
  50. import org.apache.batik.bridge.BridgeException;
  51. import org.apache.batik.bridge.CSSUtilities;
  52. import org.apache.batik.bridge.DocumentLoader;
  53. import org.apache.batik.bridge.GVTBuilder;
  54. import org.apache.batik.bridge.PaintServer;
  55. import org.apache.batik.bridge.SVGTextElementBridge;
  56. import org.apache.batik.bridge.SVGUtilities;
  57. import org.apache.batik.bridge.TextUtilities;
  58. import org.apache.batik.bridge.UnitProcessor;
  59. import org.apache.batik.bridge.UserAgent;
  60. import org.apache.batik.bridge.UserAgentAdapter;
  61. import org.apache.batik.css.engine.SVGCSSEngine;
  62. import org.apache.batik.css.engine.value.ListValue;
  63. import org.apache.batik.css.engine.value.Value;
  64. import org.apache.batik.css.engine.value.svg.ICCColor;
  65. import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
  66. import org.apache.batik.dom.svg.SVGGraphicsElement;
  67. import org.apache.batik.dom.svg.SVGOMCircleElement;
  68. import org.apache.batik.dom.svg.SVGOMClipPathElement;
  69. import org.apache.batik.dom.svg.SVGOMDefsElement;
  70. import org.apache.batik.dom.svg.SVGOMEllipseElement;
  71. import org.apache.batik.dom.svg.SVGOMForeignObjectElement;
  72. import org.apache.batik.dom.svg.SVGOMGElement;
  73. import org.apache.batik.dom.svg.SVGOMLineElement;
  74. import org.apache.batik.dom.svg.SVGOMLinearGradientElement;
  75. import org.apache.batik.dom.svg.SVGOMMaskElement;
  76. import org.apache.batik.dom.svg.SVGOMPathElement;
  77. import org.apache.batik.dom.svg.SVGOMPolygonElement;
  78. import org.apache.batik.dom.svg.SVGOMPolylineElement;
  79. import org.apache.batik.dom.svg.SVGOMRadialGradientElement;
  80. import org.apache.batik.dom.svg.SVGOMRectElement;
  81. import org.apache.batik.dom.svg.SVGOMSVGElement;
  82. import org.apache.batik.dom.svg.SVGOMSwitchElement;
  83. import org.apache.batik.dom.svg.SVGOMTSpanElement;
  84. import org.apache.batik.dom.svg.SVGOMTextElement;
  85. import org.apache.batik.dom.svg.SVGOMToBeImplementedElement;
  86. import org.apache.batik.dom.svg.SVGTextContentSupport;
  87. import org.apache.batik.dom.svg.SVGURIReferenceGraphicsElement;
  88. import org.apache.batik.dom.svg12.BindableElement;
  89. import org.apache.batik.dom.svg12.SVGOMFlowRootElement;
  90. import org.apache.batik.dom.util.XLinkSupport;
  91. import org.apache.batik.ext.awt.MultipleGradientPaint;
  92. import org.apache.batik.ext.awt.MultipleGradientPaint.CycleMethodEnum;
  93. import org.apache.batik.gvt.GraphicsNode;
  94. import org.apache.batik.gvt.TextNode;
  95. import org.apache.batik.gvt.font.AWTGVTFont;
  96. import org.apache.batik.gvt.font.GVTFont;
  97. import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
  98. import org.apache.batik.gvt.text.TextPaintInfo;
  99. import org.apache.batik.parser.PathParser;
  100. import org.apache.batik.parser.TransformListParser;
  101. import org.apache.batik.util.SVGConstants;
  102. import org.apache.batik.util.XMLResourceDescriptor;
  103. import org.mt4j.MTApplication;
  104. import org.mt4j.components.MTComponent;
  105. import org.mt4j.components.TransformSpace;
  106. import org.mt4j.components.bounds.BoundsZPlaneRectangle;
  107. import org.mt4j.components.bounds.IBoundingShape;
  108. import org.mt4j.components.clipping.FillPaint;
  109. import org.mt4j.components.visibleComponents.AbstractVisibleComponent;
  110. import org.mt4j.components.visibleComponents.font.FontManager;
  111. import org.mt4j.components.visibleComponents.font.IFont;
  112. import org.mt4j.components.visibleComponents.shapes.AbstractShape;
  113. import org.mt4j.components.visibleComponents.shapes.GeometryInfo;
  114. import org.mt4j.components.visibleComponents.shapes.MTEllipse;
  115. import org.mt4j.components.visibleComponents.shapes.MTLine;
  116. import org.mt4j.components.visibleComponents.shapes.MTPolygon;
  117. import org.mt4j.components.visibleComponents.shapes.MTRectangle;
  118. import org.mt4j.components.visibleComponents.shapes.MTRectangle.PositionAnchor;
  119. import org.mt4j.components.visibleComponents.shapes.MTRoundRectangle;
  120. import org.mt4j.components.visibleComponents.shapes.MTStencilPolygon;
  121. import org.mt4j.components.visibleComponents.shapes.mesh.MTTriangleMesh;
  122. import org.mt4j.components.visibleComponents.widgets.MTTextArea;
  123. import org.mt4j.input.gestureAction.DefaultDragAction;
  124. import org.mt4j.input.gestureAction.DefaultRotateAction;
  125. import org.mt4j.input.gestureAction.DefaultScaleAction;
  126. import org.mt4j.input.inputProcessors.IGestureEventListener;
  127. import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
  128. import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
  129. import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
  130. import org.mt4j.util.HelperMethods;
  131. import org.mt4j.util.MT4jSettings;
  132. import org.mt4j.util.MTColor;
  133. import org.mt4j.util.SwingTextureRenderer;
  134. import org.mt4j.util.logging.ILogger;
  135. import org.mt4j.util.logging.MTLoggerFactory;
  136. import org.mt4j.util.math.ConvexityUtil;
  137. import org.mt4j.util.math.Matrix;
  138. import org.mt4j.util.math.ToolsGeometry;
  139. import org.mt4j.util.math.Vector3D;
  140. import org.mt4j.util.math.Vertex;
  141. import org.mt4j.util.opengl.GLTexture;
  142. import org.mt4j.util.opengl.GluTrianglulator;
  143. import org.w3c.dom.Document;
  144. import org.w3c.dom.Element;
  145. import org.w3c.dom.NamedNodeMap;
  146. import org.w3c.dom.Node;
  147. import org.w3c.dom.NodeList;
  148. import org.w3c.dom.css.CSSPrimitiveValue;
  149. import org.w3c.dom.css.CSSStyleDeclaration;
  150. import org.w3c.dom.css.CSSValue;
  151. import org.w3c.dom.svg.SVGAnimatedLength;
  152. import org.w3c.dom.svg.SVGDocument;
  153. import org.w3c.dom.svg.SVGElement;
  154. import org.w3c.dom.svg.SVGLength;
  155. import org.w3c.dom.svg.SVGLengthList;
  156. import org.w3c.dom.svg.SVGMatrix;
  157. import org.w3c.dom.svg.SVGPoint;
  158. import org.w3c.dom.svg.SVGPointList;
  159. import org.w3c.dom.svg.SVGSVGElement;
  160. import processing.core.PApplet;
  161. import processing.opengl.PGraphicsOpenGL;
  162. /**
  163. * This class can be used to load and display scalable vector graphics (svg) files.
  164. *
  165. * @author Christopher Ruff
  166. */
  167. public class SVGLoader implements SVGConstants{
  168. private static final ILogger logger = MTLoggerFactory.getLogger(SVGLoader.class.getName());
  169. static{
  170. logger.setLevel(ILogger.ERROR);
  171. }
  172. /** The svg doc. */
  173. private SVGDocument svgDoc;
  174. /** The user agent. */
  175. private UserAgent userAgent;
  176. /** The loader. */
  177. private DocumentLoader loader;
  178. /** The ctx. */
  179. private BridgeContext ctx;
  180. /** The builder. */
  181. private GVTBuilder builder;
  182. /** The root gn. */
  183. private GraphicsNode rootGN;
  184. /** The css engine. */
  185. protected SVGCSSEngine cssEngine;
  186. /** The pa. */
  187. private PApplet pa;
  188. /** The opacity stack. */
  189. private Stack<Float> opacityStack;
  190. /** The default drag action. */
  191. private IGestureEventListener defaultDragAction;
  192. /** The default rotate action. */
  193. private IGestureEventListener defaultRotateAction;
  194. /** The default scale action. */
  195. private IGestureEventListener defaultScaleAction;
  196. /** The current local transform matrix. */
  197. private Matrix currentLocalTransformMatrix;
  198. /**
  199. * Instantiates a new batik svg parser.
  200. *
  201. * @param pa the pa
  202. */
  203. public SVGLoader(PApplet pa){
  204. this.pa = pa;
  205. opacityStack = new Stack<Float>();
  206. currentLocalTransformMatrix = new Matrix();
  207. defaultDragAction = new DefaultDragAction();
  208. defaultRotateAction = new DefaultRotateAction();
  209. defaultScaleAction = new DefaultScaleAction();
  210. }
  211. /**
  212. * Loads a "*.svg" file, parses it, creates drawable components and returns the
  213. * toplevel component.
  214. *
  215. * @param filedescr the absolute path of the svg file as a string
  216. *
  217. * @return the MT base component
  218. *
  219. * the created top level component of the svg
  220. */
  221. public MTComponent loadSvg(String filedescr){
  222. return this.getCreatedSvgComponents(this.parseSvg(filedescr));
  223. }
  224. /**
  225. * Uses the batik parser to genererate an svg document from an svg file.
  226. * To create the components in that svg document, call <code>getCreatedSvgComponents(SVGDocument doc)</code>
  227. *
  228. * @param filedescr the filedescr
  229. *
  230. * @return the SVG document
  231. */
  232. public SVGDocument parseSvg(String filedescr){
  233. Document doc;
  234. try {
  235. String parser = XMLResourceDescriptor.getXMLParserClassName();
  236. SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
  237. File file = new File(filedescr);
  238. if (file.exists()){
  239. URI localFileAsUri = file.toURI();
  240. String uri = localFileAsUri.toASCIIString();
  241. doc = f.createDocument(uri);
  242. }else{
  243. InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filedescr);
  244. if (in == null){
  245. in = pa.getClass().getResourceAsStream(filedescr);
  246. }
  247. doc = f.createDocument(filedescr, in);
  248. /*on it (after casting it to SVGOMDocument) to give it a
  249. URI of some sort. If the document needs to be able to have relative
  250. reference to files on the local file system, give it a URI like
  251. "file:///some/where/file.svg";
  252. */
  253. //FIXME HACK! this seems to help the "org.apache.batik.bridge.BridgeException: Unable to make sense of URL for connection" error
  254. //occuring with windmill.svg if loading from inputstream instead of local file system file
  255. //FIXME but this might create errors when loading external file like images from the relative svg path?
  256. doc.setDocumentURI("") ;
  257. // String sub = filedescr.substring(0, filedescr.lastIndexOf(MTApplication.separator));
  258. // System.out.println("F: " + filedescr + " sub; " + sub);
  259. // svgDoc.setDocumentURI(sub+ MTApplication.separator) ;
  260. }
  261. svgDoc = (SVGDocument)doc;
  262. } catch (Exception ex) {
  263. ex.printStackTrace();
  264. }
  265. //Neccesary? For booting css
  266. try{
  267. userAgent = new UserAgentAdapter();
  268. loader = new DocumentLoader(userAgent);
  269. ctx = new BridgeContext(userAgent, loader);
  270. ctx.setDynamicState(BridgeContext.DYNAMIC); //TODO use static?
  271. builder = new GVTBuilder();
  272. rootGN = builder.build(ctx, svgDoc);
  273. // ctx.getCSSEngineForElement(null).
  274. }catch(Exception e){
  275. e.printStackTrace();
  276. }
  277. return svgDoc;
  278. }
  279. /**
  280. * Creates and returns components of the provided svg document for displaying.
  281. *
  282. * @param svgDoc the svg doc
  283. *
  284. * @return the created svg components
  285. */
  286. public MTComponent getCreatedSvgComponents(SVGDocument svgDoc){
  287. ArrayList<MTComponent> components = new ArrayList<MTComponent>();
  288. opacityStack.push(1.0f);
  289. traverseSVGDoc(svgDoc, components);
  290. opacityStack.pop();
  291. MTComponent[] comps = components.toArray(new MTComponent[components.size()]);
  292. //Only returning the 1st component, since this should be the top-level <svg> element and only 1!?
  293. return comps[0];
  294. }
  295. /**
  296. * Traverse svg doc.
  297. *
  298. * @param node the node
  299. * @param comps the comps
  300. */
  301. private void traverseSVGDoc(Node node, ArrayList<MTComponent> comps){
  302. logger.debug("Traversing: " + node.getNodeName());
  303. //Damit transformationen konsistent sind muss
  304. //jedes tag, da? eine transform attribut hat
  305. //behandelt werden!
  306. //Default
  307. currentLocalTransformMatrix = new Matrix();
  308. //If there is a TRANSFORM attribute parse that and set the
  309. //current transformation matrix to be used with the svg components created after
  310. NamedNodeMap atts = node.getAttributes();
  311. if (atts != null){
  312. for (int i = 0; i < atts.getLength(); i++) {
  313. Node att = atts.item(i);
  314. if (att.getNodeName().equals(SVG_TRANSFORM_ATTRIBUTE)){
  315. CustomTransformHandler transFormHandler = new CustomTransformHandler();
  316. TransformListParser transFormListParser = new TransformListParser();
  317. transFormListParser.setTransformListHandler(transFormHandler);
  318. transFormListParser.parse(att.getNodeValue());
  319. //Overwrite current default matrix if the element has its own
  320. //transform defined, will be used at gfx obj creation
  321. currentLocalTransformMatrix = transFormHandler.getResultMatrix();
  322. }
  323. }
  324. }
  325. // logger.debug("Node: " + node.getNodeName() + " Class: " + node.getClass());
  326. //For opacity inheritance
  327. if (node instanceof SVGGraphicsElement){
  328. SVGGraphicsElement svgGfx = (SVGGraphicsElement)node;
  329. //Handle inherited opacity settings
  330. float opac = queryPrimitiveFloatValue(svgGfx, "opacity", 1f);
  331. opacityStack.push(opac *= opacityStack.peek());
  332. }
  333. // if G (GROUP) element, add all children to this element
  334. if ( node instanceof SVGOMGElement
  335. || node instanceof SVGSVGElement
  336. || node instanceof SVGOMSVGElement
  337. ){
  338. // SVGOMGElement gElem = (SVGOMGElement)node;
  339. SVGElement gElem = (SVGElement)node;
  340. MTComponent group = new MTComponent(pa);
  341. group.setName(gElem.getTagName());
  342. // Element viewPort = gElem.getViewportElement();
  343. // logger.debug("Viewport " + viewPort.getNodeName());
  344. //Set the <g> group to composite, meaning that it will
  345. //be returned at picking, when one of the children gets picked
  346. group.setComposite(true);
  347. group.setLocalMatrix(currentLocalTransformMatrix);
  348. //IF its <svg> element get the transform
  349. //(to honor the viewBox and the width/height attributes
  350. if (node instanceof SVGOMSVGElement ){
  351. SVGOMSVGElement svgGom = ((SVGOMSVGElement)node);
  352. Element viewPort = svgGom.getViewportElement();
  353. if (viewPort != null)
  354. logger.debug("Viewport " + viewPort.getNodeName());
  355. // SVGMatrix mat = svgGom.getScreenCTM();
  356. SVGAnimatedLength widthA = svgGom.getWidth();
  357. SVGAnimatedLength heightA = svgGom.getHeight();
  358. SVGLength w = widthA.getBaseVal();
  359. float width = w.getValue();
  360. SVGLength h = heightA.getBaseVal();
  361. float height = h.getValue();
  362. logger.debug("-> SVG Width: " + width + " Height: " + height);
  363. SVGMatrix mat = svgGom.getCTM();
  364. /*
  365. logger.debug("mat: " + mat.toString());
  366. logger.debug(mat.getA());
  367. logger.debug(mat.getB());
  368. logger.debug(mat.getC());
  369. logger.debug(mat.getD());
  370. logger.debug(mat.getE());
  371. logger.debug(mat.getF());
  372. SVGRect bbox = svgGom.getBBox();
  373. logger.debug("BBOx: X:" + bbox.getX() + " Y:" + bbox.getY() + " Width:" + bbox.getWidth() + " Height:" + bbox.getHeight());
  374. */
  375. //Hack, because if no width/height is specified default of 1.0
  376. //is assumed by batik -> things may get scaled too small
  377. if ( !(width == 1 && height == 1) ){
  378. currentLocalTransformMatrix = new Matrix(mat.getA(), mat.getC(), 0, mat.getE(),
  379. mat.getB(), mat.getD(), 0, mat.getF(),
  380. 0, 0, 1, 0,
  381. 0, 0, 0, 1
  382. );
  383. //logger.debug("Matrix: " + currentLocalTransformMatrix);
  384. group.setLocalMatrix(currentLocalTransformMatrix);
  385. }
  386. }
  387. //Make the group pickable and manipulatable
  388. group.setPickable(true);
  389. group.registerInputProcessor(new DragProcessor(pa));
  390. group.setGestureAllowance(DragProcessor.class, true);
  391. group.addGestureListener(DragProcessor.class, (IGestureEventListener)defaultDragAction);
  392. group.registerInputProcessor(new RotateProcessor(pa));
  393. group.addGestureListener(RotateProcessor.class, defaultRotateAction);
  394. group.registerInputProcessor(new ScaleProcessor(pa));
  395. group.addGestureListener(ScaleProcessor.class, defaultScaleAction);
  396. ArrayList<MTComponent> groupChildren = new ArrayList<MTComponent>();
  397. //Traverse the children and add them to a new arraylist
  398. traverseChildren(gElem, groupChildren);
  399. MTComponent[] childComps = groupChildren.toArray(new MTComponent[groupChildren.size()]);
  400. //Add the children to the group
  401. group.addChildren(childComps);
  402. //Add the group to the arraylist of the parent
  403. comps.add(group);
  404. }else{//If NOT GROUP
  405. if (node instanceof SVGGraphicsElement){
  406. SVGGraphicsElement svgGfxElem = (SVGGraphicsElement)node;
  407. //IF node isnt a group node just add it to the passed in comps arraylist
  408. try{
  409. //Create a component from the graphicsnode and add it to the parents arraylist
  410. MTComponent liveComponent = handleGraphicsNode(svgGfxElem);
  411. if (liveComponent != null){
  412. comps.add(liveComponent);
  413. }
  414. }catch(Exception e){
  415. logger.error("Error handling svg node: " + svgGfxElem.getTagName());
  416. e.printStackTrace();
  417. }
  418. }
  419. //FIXME IMPLEMENT
  420. if (node instanceof SVGOMTSpanElement){
  421. SVGOMTSpanElement tSpanElement = (SVGOMTSpanElement)node;
  422. }
  423. //FIXME TEST
  424. if (node instanceof SVGOMTextElement){
  425. boolean useVectorFont = false;
  426. SVGOMTextElement textElement = (SVGOMTextElement)node;
  427. //Get <text> position values (can be a list)
  428. List<Float> xValues = getSVGLengthListAsFloat(textElement.getX().getBaseVal());
  429. List<Float> yValues = getSVGLengthListAsFloat(textElement.getY().getBaseVal());
  430. // /*//Not used
  431. String textContent = TextUtilities.getElementContent(textElement);
  432. textContent = textContent.replaceAll("\\n","");
  433. textContent = textContent.trim();
  434. // */
  435. /*
  436. //TODO USE?
  437. textElement.getTextLength();
  438. textElement.getRotate();
  439. */
  440. if (textElement.getSVGContext() instanceof SVGTextElementBridge){
  441. SVGTextElementBridge b = (SVGTextElementBridge)textElement.getSVGContext();
  442. GraphicsNode gr = b.createGraphicsNode(ctx, textElement);
  443. TextNode tNode = (TextNode)gr;
  444. b.buildGraphicsNode(ctx, textElement, tNode);
  445. List<?> textRuns = tNode.getTextRuns();
  446. logger.debug("Text runs: " + textRuns);
  447. //Get font size
  448. float fontSize = b.getFontSize();
  449. logger.debug("Text:" + " x:" + xValues.get(0) + " y:" + yValues.get(0) + " FontSize: " + fontSize + " Text: '" + textContent + "'");
  450. //Get font FILL
  451. Value fillOpacValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FILL_OPACITY_INDEX);
  452. float computedfillOpac = PaintServer.convertOpacity(fillOpacValue);
  453. Value fillIndexValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FILL_INDEX);
  454. Object fill = SVGLoader.getFillOrStroke(textElement, fillIndexValue, computedfillOpac, ctx);
  455. MTColor fillColor = new MTColor(150,150,150,255);
  456. if (fill instanceof java.awt.Color) {
  457. java.awt.Color color = (Color) fill;
  458. fillColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
  459. }
  460. //Get STROKE
  461. // Stroke Opacity \\
  462. Value strokeOpacValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.STROKE_OPACITY_INDEX);
  463. float computedStrokeOpacity = PaintServer.convertOpacity(strokeOpacValue);
  464. // Stroke java.awt.Color \\
  465. Value strokeIndexValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.STROKE_INDEX);
  466. Object stroke = SVGLoader.getFillOrStroke(textElement, strokeIndexValue, computedStrokeOpacity, ctx);
  467. MTColor strokeColor = new MTColor(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha());
  468. if (stroke instanceof java.awt.Color) {
  469. java.awt.Color color = (Color) stroke;
  470. strokeColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
  471. }
  472. //Get the font family
  473. Value fontFamilyValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FONT_FAMILY_INDEX);
  474. String fontFamily = "arial"; //DEFAULT
  475. if (fontFamilyValue instanceof ListValue) {
  476. ListValue listValue = (ListValue) fontFamilyValue;
  477. Value firstValue = listValue.item(0); //Can be a List? -> take only the first one..
  478. if (firstValue != null)
  479. fontFamily = firstValue.getStringValue();
  480. }
  481. logger.debug("Font family: " + fontFamily);
  482. IFont font;
  483. if (useVectorFont)
  484. //Vector font
  485. font = FontManager.getInstance().createFont(pa,
  486. "arial.ttf", Math.round(fontSize), fillColor);
  487. else
  488. //Bitmap font
  489. font = FontManager.getInstance().createFont(pa,
  490. // "Arial", Math.round(fontSize),
  491. fontFamily, Math.round(fontSize), fillColor);
  492. // /*
  493. IFont fontToUse = font;
  494. IFont lastUsedFont = fontToUse;
  495. List<MTTextArea> textAreas = new ArrayList<MTTextArea>();
  496. AttributedCharacterIterator iter = tNode.getAttributedCharacterIterator();
  497. if (font != null && iter != null){ //To avoid not loaded fonts or if text ist empty
  498. for (int i = iter.getBeginIndex(); i < iter.getEndIndex(); i++) {
  499. char currentChar = iter.setIndex(i);
  500. Set<Attribute> keys = iter.getAllAttributeKeys();
  501. Map<Attribute, Object> charAtts = iter.getAttributes();
  502. Object baseLineShift = charAtts.get(SVGTextElementBridge.BASELINE_SHIFT);
  503. Object paintInfo = charAtts.get(SVGTextElementBridge.PAINT_INFO);
  504. Object charX = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.X);
  505. Object charY = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.Y);
  506. Object charDX = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.DX);
  507. Object charDY = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.DY);
  508. Object charRotation = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.ROTATION);
  509. Object gvtFont = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
  510. Object gvtFonts = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONTS);
  511. Object gvtFontFamilies = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
  512. Object textCompoundDelimiter = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
  513. Object verticalOrientation = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
  514. logger.debug("Character: " + currentChar + " CharX:" + charX + " CharY: " + charY + " CharDX: " + charDX + " CharDY: " + charDY + " Font: " + gvtFont + " Fonts: " + gvtFonts + " FontFamilies: " + gvtFontFamilies);
  515. AWTGVTFont awtGvtFont = (AWTGVTFont)gvtFont;
  516. if (awtGvtFont != null)
  517. logger.debug("CharfontSize: " + awtGvtFont.getSize());
  518. //FIXME REMOVE, Not working always 0,0
  519. SVGPoint startPosOfChar = SVGTextContentSupport.getStartPositionOfChar(textElement, i);
  520. /////////////////////////////////////
  521. //Get the character information - font, colors
  522. String newFamilyName = fontFamily;
  523. float newFontSize = fontSize;
  524. MTColor newFillColor = new MTColor(fillColor);
  525. MTColor newStrokeColor = new MTColor(strokeColor);
  526. boolean charHasColorInfo = false;
  527. boolean charHasFontInfo = false;
  528. //Get chars paint info
  529. if (paintInfo != null && paintInfo instanceof TextPaintInfo){
  530. charHasColorInfo = true;
  531. TextPaintInfo texInfo = (TextPaintInfo)paintInfo;
  532. if (texInfo.fillPaint instanceof java.awt.Color){
  533. java.awt.Color color = (Color)texInfo.fillPaint;
  534. newFillColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
  535. }
  536. if (texInfo.strokePaint instanceof java.awt.Color){
  537. java.awt.Color color = (Color)texInfo.strokePaint;
  538. newStrokeColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
  539. }
  540. }
  541. //Get the chars font family and size
  542. GVTFont aGvtFont = null;
  543. if (gvtFonts!=null){
  544. if (gvtFonts instanceof List) {
  545. List<?> fonts = (List<?>) gvtFonts;
  546. for (Object o : fonts) {
  547. if (o instanceof GVTFont) {
  548. aGvtFont = (GVTFont) o;
  549. //logger.debug("Char font family: " + aGvtFont.getFamilyName() + " Size:" + aGvtFont.getSize());
  550. }
  551. }
  552. }
  553. }
  554. if (aGvtFont != null){
  555. charHasFontInfo = true;
  556. newFamilyName = aGvtFont.getFamilyName();
  557. newFontSize = aGvtFont.getSize();
  558. }else{
  559. logger.error("Character: " + currentChar + " has no font attached.");
  560. }
  561. if (charHasColorInfo && charHasFontInfo){
  562. logger.debug("Character '" + currentChar + "'-> has font info -> load font!" +
  563. " Family: " + newFamilyName +
  564. " Fontsize: " + Math.round(newFontSize) +
  565. " FillColor: " + newFillColor +
  566. " StrokeColor: " + newStrokeColor);
  567. if (useVectorFont)
  568. fontToUse = FontManager.getInstance().createFont(pa,
  569. "arial.ttf", Math.round(newFontSize), newFillColor);
  570. else
  571. fontToUse = FontManager.getInstance().createFont(pa, //uses cached font if available
  572. // "Arial", Math.round(fontSize),
  573. newFamilyName, Math.round(newFontSize), newFillColor);
  574. if (fontToUse == null){
  575. fontToUse = font;
  576. }
  577. }else{
  578. fontToUse = font;
  579. }
  580. boolean fontChanged = !FontManager.isFontsAreEqual(fontToUse, lastUsedFont);
  581. lastUsedFont = fontToUse;
  582. // //FIXME REMOVE TEST
  583. // fontChanged = true;
  584. ///////////////////////////////////////
  585. boolean textPositionChanged = charX != null || charY != null || charDX != null || charDY != null;
  586. //TODO if we forceAnewTextarea because of font change but ther is NO NEW POSITION, we
  587. //have to set the textareas anchor to the lower left
  588. //TODO problem if we have a tspan centered and a next tspan without new position
  589. //-> the first tspan textarea gets centered on the position
  590. //but we would have to treat them (all in the same line) as 1 textarea when center positioning!
  591. //FIXME there are slight differences because we use a different SPACE character length and no font KERNING!
  592. //FIXME DO WIDHTOUT USERDATA
  593. //FIXME bitmap font has no top border, vector has.. why?
  594. //TODO -> eventuell doch in handleSvgNode machen?
  595. //-> statt graphicsnode /stylable node ?bergeben? - SVGOMTextElement is nicht instanceof graphicsnode..
  596. // we have to check font/color etc at every character, not only at new positon because
  597. //pos doesent change at tspans without new posinfo
  598. //check if equal to last used font and if equal original text font
  599. if ( fontChanged || textPositionChanged
  600. ){ //Make a new textarea if the text position changed or if the font changed at the current character
  601. MTTextArea previousTextArea = null;
  602. if (!textAreas.isEmpty()){
  603. previousTextArea = textAreas.get(textAreas.size()-1);
  604. }
  605. float newXPos = 0;
  606. float newYPos = 0 ;
  607. //If there is a previous text, get its ending coordinates
  608. //for the DX and DY shift info for the next text area
  609. if (previousTextArea != null){
  610. PositionAnchor oldAnchor = previousTextArea.getAnchor();
  611. // previousTextArea.setAnchor(PositionAnchor.LOWER_RIGHT);
  612. previousTextArea.setAnchor(PositionAnchor.UPPER_LEFT);
  613. //Calculate last/current textposition for DX and DY use
  614. //add up the last textareas start position end position(width)
  615. Vector3D lastPos = previousTextArea.getPosition(TransformSpace.LOCAL);
  616. // lastPos.addLocal(new Vector3D(previousTextArea.getWidthXY(TransformSpace.LOCAL) - 1 * previousTextArea.getInnerPaddingLeft(),0));
  617. lastPos.addLocal(new Vector3D(previousTextArea.getWidthXY(TransformSpace.LOCAL) - 2 * previousTextArea.getInnerPaddingLeft(),0));
  618. // newXPos = lastPos.x - previousTextArea.getInnerPaddingLeft();
  619. newXPos = lastPos.x;
  620. newXPos += (Float)previousTextArea.getUserData("XPos");
  621. newYPos = lastPos.y;
  622. // newYPos -= previousTextArea.getInnerPaddingTop();
  623. // newYPos += fontToUse.getFontMaxDescent(); //FIXME WHY NEVESSARY?
  624. newYPos += (Float)previousTextArea.getUserData("YPos");
  625. previousTextArea.setAnchor(oldAnchor);
  626. }
  627. //IF absolute x or y is present overwrite the position values from the last textarea
  628. if (charX != null)
  629. newXPos = (Float)charX;
  630. if (charY != null)
  631. newYPos = (Float)charY;
  632. if (charDX != null)
  633. newXPos += (Float)charDX;
  634. if (charDY != null)
  635. newYPos += (Float)charDY;
  636. // Create the text area \\
  637. MTTextArea t = new MTTextArea(pa, fontToUse);
  638. t.setNoFill(true);
  639. t.setNoStroke(true);
  640. textAreas.add(t);
  641. try{
  642. t.setLocalMatrix(new Matrix(currentLocalTransformMatrix));
  643. }catch(Exception e){
  644. logger.error(e.getMessage());
  645. }
  646. //FIXME TEST
  647. // if (previousTextArea != null && !textPositionChange){
  648. // t.setAnchor(PositionAnchor.LOWER_LEFT);
  649. // t.setUserData("posRelParent", new Vector3D(newXPos , newYPos - fontToUse.getFontMaxDescent() , 0));
  650. // logger.debug("Character '" + currentChar + "' -> Anchor: LOWER_LEFT");
  651. // }else{
  652. Value v = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.TEXT_ANCHOR_INDEX);
  653. //INFO: we have to move the BASELINE of the text to the svg position
  654. //The textarea is usually fontmaxascent+fontmaxdescent+2*innerPadding big!
  655. switch (v.getStringValue().charAt(0)) {
  656. case 'e':
  657. t.setAnchor(PositionAnchor.LOWER_RIGHT);
  658. t.setUserData("posRelParent", new Vector3D((newXPos + t.getInnerPaddingLeft()) , newYPos - fontToUse.getFontMaxDescent() + t.getInnerPaddingTop() , 0));
  659. // t.setPositionRelativeToParent(new Vector3D(newXPos, newYPos - font.getFontMaxDescent() , 0));
  660. logger.debug("Character '" + currentChar + "' -> Anchor: LOWER_RIGHT");
  661. break;
  662. case 'm': //text-anchor="middle"
  663. t.setAnchor(PositionAnchor.CENTER);
  664. // t.setUserData("posRelParent", new Vector3D(newXPos, newYPos - fontToUse.getFontMaxAscent()*0.5f - fontToUse.getFontMaxDescent()*0.5f , 0));
  665. // t.setUserData("posRelParent", new Vector3D(newXPos, newYPos - fontToUse.getFontAbsoluteHeight()*0.5f + t.getInnerPaddingTop() , 0));
  666. // t.setPositionRelativeToParent(new Vector3D(newXPos, newYPos - font.getFontMaxAscent()*0.5f - font.getFontMaxDescent()*0.5f, 0)); //- font.getFontMaxAscent()*0.5f
  667. logger.debug("Character '" + currentChar + "' -> Anchor: CENTER");
  668. t.setUserData("posRelParent", new Vector3D((newXPos), (newYPos - fontToUse.getFontMaxDescent() + t.getInnerPaddingTop()) - t.getHeightXY(TransformSpace.LOCAL)/2f , 0));
  669. break;
  670. default: //text-anchor="start" //default!
  671. t.setAnchor(PositionAnchor.LOWER_LEFT);
  672. // t.setUserData("posRelParent", new Vector3D(newXPos -t.getInnerPaddingLeft(), newYPos - fontToUse.getFontMaxDescent() + t.getInnerPaddingTop() , 0));
  673. t.setUserData("posRelParent", new Vector3D(newXPos -t.getInnerPaddingLeft(), newYPos - fontToUse.getFontMaxDescent() + t.getInnerPaddingTop() , 0));
  674. // t.setAnchor(PositionAnchor.UPPER_LEFT);
  675. // t.setUserData("posRelParent", new Vector3D(newXPos -t.getInnerPaddingLeft(), newYPos, 0));
  676. // t.setPositionRelativeToParent(new Vector3D(newXPos, newYPos - font.getFontMaxDescent() , 0));
  677. logger.debug("Character '" + currentChar + "' -> Anchor: LOWER_LEFT");
  678. }
  679. t.setUserData("XPos", newXPos);
  680. t.setUserData("YPos", newYPos);
  681. // }
  682. }
  683. //Add character to the current textarea in the list
  684. if (!textAreas.isEmpty()){
  685. textAreas.get(textAreas.size()-1).appendCharByUnicode(Character.toString(currentChar));
  686. }
  687. }
  688. //Set the positions of the textareas
  689. for (MTTextArea textArea : textAreas) {
  690. logger.debug("Adding text area at: " + (Vector3D) textArea.getUserData("posRelParent"));
  691. textArea.setPositionRelativeToParent((Vector3D) textArea.getUserData("posRelParent"));
  692. }
  693. comps.addAll(textAreas);
  694. }
  695. /*
  696. //This gets only the text of this hierarchy level
  697. StringBuffer result = new StringBuffer();
  698. for (Node n = textElement.getFirstChild();
  699. n != null;
  700. n = n.getNextSibling()) {
  701. switch (n.getNodeType()) {
  702. case Node.ELEMENT_NODE:
  703. break;
  704. case Node.CDATA_SECTION_NODE:
  705. case Node.TEXT_NODE:
  706. result.append(n.getNodeValue());
  707. }
  708. }
  709. logger.debug("TEXTTTT2: " + result);
  710. */
  711. // */////////////////////
  712. }
  713. }
  714. }
  715. if (node instanceof SVGGraphicsElement){
  716. //Remove inherited opacity attribute from stack
  717. opacityStack.pop();
  718. }
  719. //Traverse the children, not if it was a group element
  720. //because then the children are already
  721. //traversed in the if (group) block above
  722. if ( !(node instanceof SVGOMGElement)
  723. && !(node instanceof SVGSVGElement)
  724. && !(node instanceof SVGOMSVGElement)
  725. ){
  726. traverseChildren(node, comps);
  727. }
  728. }
  729. /**
  730. * Traverse children.
  731. *
  732. * @param node the node
  733. * @param comps the comps
  734. */
  735. private void traverseChildren(Node node, ArrayList<MTComponent> comps){
  736. //Check the children
  737. NodeList nl = node.getChildNodes();
  738. for (int i = 0; i < nl.getLength(); i++) {
  739. Node currentNode = nl.item(i);
  740. traverseSVGDoc(currentNode, comps);
  741. }
  742. }
  743. /**
  744. * Handle graphics node.
  745. *
  746. * @param gfxElem the gfx elem
  747. *
  748. * @return the mT base component
  749. */
  750. private MTComponent handleGraphicsNode(SVGGraphicsElement gfxElem){
  751. MTComponent returnComp = null;
  752. // logger.debug("Handle Element: " + gfxElem.getTagName());
  753. //Print all css properties and values
  754. // logger.debug("Style Css Text: " + style.getCssText());
  755. // SVG Defaults \\
  756. float fillR = 255;
  757. float fillG = 255;
  758. float fillB = 255;
  759. boolean noFill = false;
  760. float strokeR = 0;
  761. float strokeG = 0;
  762. float strokeB = 0;
  763. float strokeWidth = 1.0f;
  764. boolean noStroke = false;
  765. float strokeOpacity = 1;
  766. float fillOpacity = 1;
  767. int windingRule = GLU.GLU_TESS_WINDING_NONZERO;
  768. // SVG Defaults \\
  769. // Opacity, not as a style attribute but a separate
  770. // as group opacity doesnt get computed right, so we
  771. // mannually track it on a stack
  772. float opacity = opacityStack.peek();
  773. //logger.debug("INHERITED OPACITY: " + opacity);
  774. // FILL-RULE \\
  775. Value fillRuleValue = CSSUtilities.getComputedStyle(gfxElem, SVGCSSEngine.FILL_RULE_INDEX);
  776. String fillRule = fillRuleValue.getStringValue();
  777. if (fillRule.equalsIgnoreCase("nonzero")){
  778. windingRule = GLU.GLU_TESS_WINDING_NONZERO;
  779. }else if (fillRule.equalsIgnoreCase("evenodd")){
  780. windingRule = GLU.GLU_TESS_WINDING_ODD;
  781. }else{
  782. windingRule = GLU.GLU_TESS_WINDING_NONZERO;
  783. }
  784. //logger.debug("fillRule: " + fillRule);
  785. // Fill Opacity \\
  786. fillOpacity = PaintServer.convertOpacity(CSSUtilities.getComputedStyle(gfxElem, SVGCSSEngine.FILL_OPACITY_INDEX));
  787. //Multiplicate inherited opacity with this components opacities
  788. fillOpacity *= opacity;
  789. //Save for eventual lineargradient creation later that needs the not interpolated value
  790. float originalFillOpacity = fillOpacity;
  791. //logger.debug("fill opacity unnormalized: " + fillOpacity);
  792. // Fill java.awt.Color \\
  793. Value fillIndexValue = CSSUtilities.getComputedStyle(gfxElem, SVGCSSEngine.FILL_INDEX);
  794. Object fill = SVGLoader.getFillOrStroke(gfxElem, fillIndexValue, fillOpacity, ctx);
  795. SVGOMLinearGradientElement linearGradient = null;
  796. SVGOMRadialGradientElement radialGradient = null;
  797. if (fill instanceof java.awt.Color) {
  798. java.awt.Color color = (Color) fill;
  799. fillR = color.getRed();
  800. fillG = color.getGreen();
  801. fillB = color.getBlue();
  802. fillOpacity = color.getAlpha();
  803. noFill = false;
  804. //logger.debug("Fill: " + color + " a=" + fillOpacity);
  805. }else if (fill instanceof SVGOMLinearGradientElement) {
  806. //TODO cache gradients so dass man nicht immer neu den gleichen
  807. //machen muss!
  808. linearGradient = (SVGOMLinearGradientElement) fill;
  809. noFill = false;
  810. }else if (fill instanceof SVGOMRadialGradientElement) {
  811. //TODO!! //FIXME TEST
  812. radialGradient = (SVGOMRadialGradientElement)fill;
  813. noFill = false;
  814. }else{
  815. noFill = true;
  816. }
  817. // Stroke Opacity \\
  818. strokeOpacity = PaintServer.convertOpacity(CSSUtilities.getComputedStyle(gfxElem, SVGCSSEngine.STROKE_OPACITY_INDEX));
  819. // Multiplicate inherited opacity with this components group opacities
  820. strokeOpacity *= opacity;
  821. // Stroke java.awt.Color \\
  822. Value strokeIndexValue = CSSUtilities.getComputedStyle(gfxElem, SVGCSSEngine.STROKE_INDEX);
  823. Object stroke = SVGLoader.getFillOrStroke(gfxElem, strokeIndexValue, strokeOpacity, ctx);
  824. if (stroke instanceof java.awt.Color) {
  825. java.awt.Color color = (Color) stroke;
  826. strokeR = color.getRed();
  827. strokeG = color.getGreen();
  828. strokeB = color.getBlue();
  829. strokeOpacity = color.getAlpha();
  830. noStroke = false;
  831. }else{
  832. noStroke = true;
  833. strokeR = fillR;
  834. strokeG = fillG;
  835. strokeB = fillB;
  836. }
  837. // Stroke Width \\
  838. Stroke s = PaintServer.convertStroke(gfxElem);
  839. if (s != null){
  840. if (s instanceof BasicStroke) {
  841. BasicStroke basicStroke = (BasicStroke) s;
  842. strokeWidth = basicStroke.getLineWidth();
  843. }
  844. }else{
  845. strokeWidth = 0.0f;
  846. noStroke = true;
  847. }
  848. /*
  849. logger.debug("Fill COL: " + fillR + " " + fillG + " " + fillB + " " fillopacity);
  850. logger.debug("STROKE COL: " + strokeR + " " + strokeG + " " + strokeB + " " strokeOpacity);
  851. */
  852. // CHECK WHAT KIND OF GRAPHICS ELEMENT IT IS AND CREATE IT \\
  853. if (gfxElem instanceof SVGOMPathElement){
  854. SVGOMPathElement pathElem = (SVGOMPathElement)gfxElem;
  855. //FIXME handle clip-paths in the future
  856. if (isUnderClipPath(pathElem)){
  857. logger.error("Discarding clip-path path element. Not implemented.");
  858. return null;
  859. }
  860. //Create the shape
  861. AbstractShape pathComp = getLivePathComponent(pathElem, noFill, windingRule);
  862. try{
  863. pathComp.setLocalMatrix(currentLocalTransformMatrix);
  864. }catch(Exception e){
  865. logger.error(e.getMessage());
  866. }
  867. returnComp = pathComp;
  868. }else if (gfxElem instanceof SVGOMPolygonElement){
  869. SVGOMPolygonElement polygonElem = (SVGOMPolygonElement)gfxElem;
  870. //Create the shape
  871. AbstractShape comp = getLivePolygonComponent(polygonElem, noFill, windingRule);
  872. try{
  873. comp.setLocalMatrix(currentLocalTransformMatrix);
  874. }catch(Exception e){
  875. logger.error(e.getMessage());
  876. }
  877. returnComp = comp;
  878. }else if (gfxElem instanceof SVGOMPolylineElement){
  879. SVGOMPolylineElement polyLineElem = (SVGOMPolylineElement)gfxElem;
  880. //Create Vertex[] from points
  881. SVGPointList pointList = polyLineElem.getPoints();
  882. Vertex[] vertices = new Vertex[pointList.getNumberOfItems()];
  883. for (int i = 0; i < pointList.getNumberOfItems(); i++) {
  884. SVGPoint p = pointList.getItem(i);
  885. vertices[i] = new Vertex(p.getX(), p.getY(),0);
  886. }
  887. //Create the shape
  888. AbstractShape comp = createPoly(vertices);
  889. try{
  890. comp.setLocalMatrix(currentLocalTransformMatrix);
  891. }catch(Exception e){
  892. logger.error(e.getMessage());
  893. }
  894. returnComp = comp;
  895. }else if (gfxElem instanceof SVGOMRectElement){
  896. SVGOMRectElement rectElem = (SVGOMRectElement)gfxElem;
  897. if (isUnderClipPath(rectElem)){
  898. logger.error("discarding clip-path Rect");
  899. return null;
  900. }
  901. float x = rectElem.getX().getBaseVal().getValue();
  902. float y = rectElem.getY().getBaseVal().getValue();
  903. float width = rectElem.getWidth().getBaseVal().getValue();
  904. float height = rectElem.getHeight().getBaseVal().getValue();
  905. float rx = rectElem.getRx().getBaseVal().getValue();
  906. float ry = rectElem.getRy().getBaseVal().getValue();
  907. AbstractShape comp;
  908. //Create a normal rectangle or a round rectangle
  909. if (rx != 0.0f || ry != 0.0f){
  910. if (rx > width/2 )
  911. rx = width/2;
  912. if (ry > height/2 )
  913. ry = height/2;
  914. comp = new MTRoundRectangle(pa,x,y, 0,width,height, rx, ry);
  915. }else{
  916. comp = new MTRectangle(pa,x, y,width, height);
  917. }
  918. try{
  919. comp.setLocalMatrix(currentLocalTransformMatrix);
  920. }catch(Exception e){
  921. logger.error(e.getMessage());
  922. }
  923. returnComp = comp;
  924. }else if (gfxElem instanceof SVGOMEllipseElement){
  925. SVGOMEllipseElement ellipseElem = (SVGOMEllipseElement)gfxElem;
  926. float cx = ellipseElem.getCx().getBaseVal().getValue();
  927. float cy = ellipseElem.getCy().getBaseVal().getValue();
  928. float r = ellipseElem.getRx().getBaseVal().getValue();
  929. float r2 = ellipseElem.getRy().getBaseVal().getValue();
  930. Vertex middlePoint = new Vertex(cx,cy,0);
  931. //Apply transformation, transform centerpoint and the radii
  932. try{
  933. middlePoint.transform(currentLocalTransformMatrix);
  934. }catch(Exception e){
  935. logger.error(e.getMessage());
  936. }
  937. //somehow the circle radii need to be doubled
  938. //or else theyre too small => processing bug?
  939. // r*=2;
  940. // r2*=2;
  941. MTEllipse comp = new MTEllipse(pa, middlePoint, r, r2);
  942. returnComp = comp;
  943. }else if (gfxElem instanceof SVGOMCircleElement){
  944. SVGOMCircleElement circleElem = (SVGOMCircleElement)gfxElem;
  945. float cx = circleElem.getCx().getBaseVal().getValue();
  946. float cy = circleElem.getCy().getBaseVal().getValue();
  947. float r = circleElem.getR().getBaseVal().getValue();
  948. float r2 = circleElem.getR().getBaseVal().getValue();
  949. Vertex middlePoint = new Vertex(cx,cy,0);
  950. //Apply transformation, transform centerpoint and the radii
  951. try{
  952. middlePoint.transform(currentLocalTransformMatrix);
  953. }catch(Exception e){
  954. logger.error(e.getMessage());
  955. }
  956. //somehow the circle radii need to be doubled
  957. //or else theyre too small => processing bug?
  958. // r*=2;
  959. // r2*=2;
  960. MTEllipse comp = new MTEllipse(pa, middlePoint, r, r2);
  961. returnComp = comp;
  962. }else if (gfxElem instanceof SVGOMLineElement){
  963. SVGOMLineElement line = (SVGOMLineElement)gfxElem;
  964. float x1 = line.getX1().getBaseVal().getValue();
  965. float y1 = line.getY1().getBaseVal().getValue();
  966. float x2 = line.getX2().getBaseVal().getValue();
  967. float y2 = line.getY2().getBaseVal().getValue();
  968. //logger.debug("Line x1: " + x1 + ",y1:" + y1 + ",x2:" + x2 + ",y2:" + y2);
  969. MTLine comp = new MTLine(pa, x1,y1 ,x2,y2);
  970. try{
  971. comp.setLocalMatrix(currentLocalTransformMatrix);
  972. }catch(Exception e){
  973. logger.error(e.getMessage());
  974. }
  975. returnComp = comp;
  976. }else if (gfxElem instanceof SVGOMClipPathElement){
  977. }else if (gfxElem instanceof SVGOMDefsElement){
  978. }else if (gfxElem instanceof SVGOMMaskElement){
  979. }else if (gfxElem instanceof SVGOMSwitchElement){
  980. }else if (gfxElem instanceof SVGOMFlowRootElement){
  981. }else if (gfxElem instanceof SVGURIReferenceGraphicsElement){
  982. }else if (gfxElem instanceof BindableElement){
  983. }else if (gfxElem instanceof SVGOMForeignObjectElement){
  984. }else if (gfxElem instanceof SVGOMToBeImplementedElement){
  985. }
  986. //Do the finishing touch of the svg graphics element
  987. if (returnComp != null){
  988. returnComp.setName(gfxElem.getTagName());
  989. //Set style infos
  990. if (returnComp instanceof AbstractVisibleComponent){
  991. AbstractVisibleComponent comp = (AbstractVisibleComponent)returnComp;
  992. //Set Fill
  993. comp.setFillColor(new MTColor(fillR, fillG, fillB, fillOpacity));
  994. comp.setNoFill(noFill);
  995. //Set Stroke
  996. comp.setStrokeColor(new MTColor(strokeR, strokeG, strokeB, strokeOpacity));
  997. //Opengl cant handle big lines well
  998. //So cap at width 3
  999. if (strokeWidth > 2.0f)
  1000. strokeWidth = 2.0f;
  1001. comp.setStrokeWeight(strokeWidth);
  1002. comp.setNoStroke(noStroke);
  1003. //Other
  1004. comp.setDrawSmooth(true);
  1005. comp.setPickable(false);
  1006. //Hack for smoothing non stroked components with a stroke same as fillcolor
  1007. if (comp.isNoStroke()
  1008. && linearGradient == null
  1009. ){
  1010. comp.setStrokeColor(new MTColor(fillR, fillG, fillB, fillOpacity)); //fillOpacity
  1011. comp.setStrokeWeight(0.6f);
  1012. //Ellipse doesent smooth right with 0.1f strokeweight
  1013. if (comp instanceof MTEllipse){
  1014. comp.setStrokeWeight(1.0f);
  1015. }
  1016. comp.setNoStroke(false);
  1017. }
  1018. //Some settings for Geometric shapes (actually should all be)
  1019. if (comp instanceof AbstractShape ){
  1020. AbstractShape shape = (AbstractShape)comp;
  1021. //Set a bounding rectangle to check first at picking
  1022. if (shape.getVerticesLocal().length >= 3){
  1023. shape.setBoundsBehaviour(AbstractShape.BOUNDS_CHECK_THEN_GEOMETRY_CHECK);
  1024. //shape.setBoundingShape(new BoundsZPlaneRectangle(shape)); //already done by override, (ie svgpoly)
  1025. //Create amd apply the linear gradient if existant and if we are in opengl rendering mode
  1026. if (MT4jSettings.getInstance().isOpenGlMode()){
  1027. if (linearGradient != null){
  1028. FillPaint gradient = this.createLinearGradient(linearGradient, gfxElem, originalFillOpacity, shape);
  1029. if (gradient != null){
  1030. shape.setFillPaint(gradient);
  1031. }
  1032. }
  1033. if (radialGradient != null){
  1034. FillPaint gradient = this.createRadialGradient(radialGradient, gfxElem, opacity, shape);
  1035. if (gradient != null){
  1036. shape.setFillPaint(gradient);
  1037. }
  1038. }
  1039. //Per default use direct gl drawing and displaylists in OGL mode
  1040. if (pa instanceof MTApplication) {
  1041. MTApplication app = (MTApplication) pa;