source: josm/trunk/patches/10trim_svgsalamander.patch @ 7287

Last change on this file since 7287 was 5284, checked in by bastiK, 9 years ago

reverse patches, so they are easier to use in quilt

File size: 200.6 KB
RevLine 
[4256]1Patch against rev 98 of https://svn.java.net/svn/svgsalamander~svn/trunk. It strips some classes, that aren't needed (basically animation and gui) and removes dependencies. The only purpose of this patch is to reduce binary download size for JOSM users.
[5284]2Index: core/src/com/kitfox/svg/animation/Animate.java
[4256]3===================================================================
[5284]4--- /dev/null   1970-01-01 00:00:00.000000000 +0000
5+++ core/src/com/kitfox/svg/animation/Animate.java      2012-06-17 23:56:57.664545050 +0200
6@@ -0,0 +1,419 @@
7+/*
8+ * Animate.java
9+ *
10+ *  The Salamander Project - 2D and 3D graphics libraries in Java
11+ *  Copyright (C) 2004 Mark McKay
12+ *
13+ *  This library is free software; you can redistribute it and/or
14+ *  modify it under the terms of the GNU Lesser General Public
15+ *  License as published by the Free Software Foundation; either
16+ *  version 2.1 of the License, or (at your option) any later version.
17+ *
18+ *  This library is distributed in the hope that it will be useful,
19+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+ *  Lesser General Public License for more details.
22+ *
23+ *  You should have received a copy of the GNU Lesser General Public
24+ *  License along with this library; if not, write to the Free Software
25+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26+ *
27+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
28+ *  projects can be found at http://www.kitfox.com
29+ *
30+ * Created on August 15, 2004, 2:51 AM
31+ */
32+
33+package com.kitfox.svg.animation;
34+
35+import com.kitfox.svg.SVGElement;
36+import com.kitfox.svg.SVGException;
37+import com.kitfox.svg.SVGLoaderHelper;
38+import com.kitfox.svg.animation.parser.AnimTimeParser;
39+import com.kitfox.svg.xml.ColorTable;
40+import com.kitfox.svg.xml.StyleAttribute;
41+import com.kitfox.svg.xml.XMLParseUtil;
42+import java.awt.Color;
43+import java.awt.geom.AffineTransform;
44+import java.awt.geom.GeneralPath;
45+import java.awt.geom.PathIterator;
46+import org.xml.sax.Attributes;
47+import org.xml.sax.SAXException;
48+
49+
50+/**
51+ * Animate is a really annoying morphic tag that could represent a real value,
52+ * a color or a path
53+ *
54+ * @author Mark McKay
55+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
56+ */
57+public class Animate extends AnimateBase implements AnimateColorIface
58+{
59+//    StyleAttribute retAttrib = new StyleAttribute
60+    public static final int DT_REAL = 0;
61+    public static final int DT_COLOR = 1;
62+    public static final int DT_PATH = 2;
63+    int dataType = DT_REAL;
64+   
65+    protected double fromValue = Double.NaN;
66+    protected double toValue = Double.NaN;
67+    protected double byValue = Double.NaN;
68+    protected double[] valuesValue;
69+   
70+    protected Color fromColor = null;
71+    protected Color toColor = null;
72+
73+    protected GeneralPath fromPath = null;
74+    protected GeneralPath toPath = null;
75+
76+    /** Creates a new instance of Animate */
77+    public Animate()
78+    {
79+    }
80+   
81+    public int getDataType()
82+    {
83+        return dataType;
84+    }
85+   
86+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
87+    {
88+               //Load style string
89+        super.loaderStartElement(helper, attrs, parent);
90+
91+        String strn = attrs.getValue("from");
92+        if (strn != null)
93+        {
94+            if (XMLParseUtil.isDouble(strn))
95+            {
96+                fromValue = XMLParseUtil.parseDouble(strn);
97+            }
98+//            else if (attrs.getValue("attributeName").equals("d"))
99+//            {
100+//                fromPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
101+//                dataType = DT_PATH;
102+//            }
103+            else
104+            {
105+                fromColor = ColorTable.parseColor(strn);
106+                if (fromColor == null)
107+                {
108+                    //Try path
109+                    fromPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
110+                    dataType = DT_PATH;
111+                }
112+                else dataType = DT_COLOR;
113+            }
114+        }
115+
116+        strn = attrs.getValue("to");
117+        if (strn != null)
118+        {
119+            if (XMLParseUtil.isDouble(strn))
120+            {
121+                toValue = XMLParseUtil.parseDouble(strn);
122+            }
123+            else
124+            {
125+                toColor = ColorTable.parseColor(strn);
126+                if (toColor == null)
127+                {
128+                    //Try path
129+                    toPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
130+                    dataType = DT_PATH;
131+                }
132+                else dataType = DT_COLOR;
133+            }
134+        }
135+
136+        strn = attrs.getValue("by");
137+        try
138+        {
139+            if (strn != null) byValue = XMLParseUtil.parseDouble(strn);
140+        } catch (Exception e) {}
141+
142+        strn = attrs.getValue("values");
143+        try
144+        {
145+            if (strn != null) valuesValue = XMLParseUtil.parseDoubleList(strn);
146+        } catch (Exception e) {}
147+    }
148+   
149+    /**
150+     * Evaluates this animation element for the passed interpolation time.  Interp
151+     * must be on [0..1].
152+     */
153+    public double eval(double interp)
154+    {
155+        boolean fromExists = !Double.isNaN(fromValue);
156+        boolean toExists = !Double.isNaN(toValue);
157+        boolean byExists = !Double.isNaN(byValue);
158+        boolean valuesExists = valuesValue != null;
159+       
160+        if (valuesExists)
161+        {
162+            double sp = interp * valuesValue.length;
163+            int ip = (int)sp;
164+            double fp = sp - ip;
165+           
166+            int i0 = ip;
167+            int i1 = ip + 1;
168+           
169+            if (i0 < 0) return valuesValue[0];
170+            if (i1 >= valuesValue.length) return valuesValue[valuesValue.length - 1];
171+            return valuesValue[i0] * (1 - fp) + valuesValue[i1] * fp;
172+        }
173+        else if (fromExists && toExists)
174+        {
175+            return toValue * interp + fromValue * (1.0 - interp);
176+        }
177+        else if (fromExists && byExists)
178+        {
179+            return fromValue + byValue * interp;
180+        }
181+        else if (toExists && byExists)
182+        {
183+            return toValue - byValue * (1.0 - interp);
184+        }
185+        else if (byExists)
186+        {
187+            return byValue * interp;
188+        }
189
190+        //Should not reach this line
191+        throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
192+    }
193+
194+    public Color evalColor(double interp)
195+    {
196+        if (fromColor == null && toColor != null)
197+        {
198+            float[] toCol = new float[3];
199+            toColor.getColorComponents(toCol);
200+            return new Color(toCol[0] * (float)interp,
201+                toCol[1] * (float)interp,
202+                toCol[2] * (float)interp);
203+        }
204+        else if (fromColor != null && toColor != null)
205+        {
206+            float nInterp = 1 - (float)interp;
207+           
208+            float[] fromCol = new float[3];
209+            float[] toCol = new float[3];
210+            fromColor.getColorComponents(fromCol);
211+            toColor.getColorComponents(toCol);
212+            return new Color(fromCol[0] * nInterp + toCol[0] * (float)interp,
213+                fromCol[1] * nInterp + toCol[1] * (float)interp,
214+                fromCol[2] * nInterp + toCol[2] * (float)interp);
215+        }
216+       
217+        throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
218+    }
219+
220+    public GeneralPath evalPath(double interp)
221+    {
222+        if (fromPath == null && toPath != null)
223+        {
224+            PathIterator itTo = toPath.getPathIterator(new AffineTransform());
225+           
226+            GeneralPath midPath = new GeneralPath();
227+            float[] coordsTo = new float[6];
228+           
229+            for (; !itTo.isDone(); itTo.next())
230+            {
231+                int segTo = itTo.currentSegment(coordsTo);
232+               
233+                switch (segTo)
234+                {
235+                    case PathIterator.SEG_CLOSE:
236+                        midPath.closePath();
237+                        break;
238+                    case PathIterator.SEG_CUBICTO:
239+                        midPath.curveTo(
240+                                (float)(coordsTo[0] * interp),
241+                                (float)(coordsTo[1] * interp),
242+                                (float)(coordsTo[2] * interp),
243+                                (float)(coordsTo[3] * interp),
244+                                (float)(coordsTo[4] * interp),
245+                                (float)(coordsTo[5] * interp)
246+                                );
247+                        break;
248+                    case PathIterator.SEG_LINETO:
249+                        midPath.lineTo(
250+                                (float)(coordsTo[0] * interp),
251+                                (float)(coordsTo[1] * interp)
252+                                );
253+                        break;
254+                    case PathIterator.SEG_MOVETO:
255+                        midPath.moveTo(
256+                                (float)(coordsTo[0] * interp),
257+                                (float)(coordsTo[1] * interp)
258+                                );
259+                        break;
260+                    case PathIterator.SEG_QUADTO:
261+                        midPath.quadTo(
262+                                (float)(coordsTo[0] * interp),
263+                                (float)(coordsTo[1] * interp),
264+                                (float)(coordsTo[2] * interp),
265+                                (float)(coordsTo[3] * interp)
266+                                );
267+                        break;
268+                }
269+            }
270+           
271+            return midPath;
272+        }
273+        else if (toPath != null)
274+        {
275+            PathIterator itFrom = fromPath.getPathIterator(new AffineTransform());
276+            PathIterator itTo = toPath.getPathIterator(new AffineTransform());
277+           
278+            GeneralPath midPath = new GeneralPath();
279+            float[] coordsFrom = new float[6];
280+            float[] coordsTo = new float[6];
281+           
282+            for (; !itFrom.isDone(); itFrom.next())
283+            {
284+                int segFrom = itFrom.currentSegment(coordsFrom);
285+                int segTo = itTo.currentSegment(coordsTo);
286+               
287+                if (segFrom != segTo)
288+                {
289+                    throw new RuntimeException("Path shape mismatch");
290+                }
291+               
292+                switch (segFrom)
293+                {
294+                    case PathIterator.SEG_CLOSE:
295+                        midPath.closePath();
296+                        break;
297+                    case PathIterator.SEG_CUBICTO:
298+                        midPath.curveTo(
299+                                (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
300+                                (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp),
301+                                (float)(coordsFrom[2] * (1 - interp) + coordsTo[2] * interp),
302+                                (float)(coordsFrom[3] * (1 - interp) + coordsTo[3] * interp),
303+                                (float)(coordsFrom[4] * (1 - interp) + coordsTo[4] * interp),
304+                                (float)(coordsFrom[5] * (1 - interp) + coordsTo[5] * interp)
305+                                );
306+                        break;
307+                    case PathIterator.SEG_LINETO:
308+                        midPath.lineTo(
309+                                (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
310+                                (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp)
311+                                );
312+                        break;
313+                    case PathIterator.SEG_MOVETO:
314+                        midPath.moveTo(
315+                                (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
316+                                (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp)
317+                                );
318+                        break;
319+                    case PathIterator.SEG_QUADTO:
320+                        midPath.quadTo(
321+                                (float)(coordsFrom[0] * (1 - interp) + coordsTo[0] * interp),
322+                                (float)(coordsFrom[1] * (1 - interp) + coordsTo[1] * interp),
323+                                (float)(coordsFrom[2] * (1 - interp) + coordsTo[2] * interp),
324+                                (float)(coordsFrom[3] * (1 - interp) + coordsTo[3] * interp)
325+                                );
326+                        break;
327+                }
328+            }
329+           
330+            return midPath;
331+        }
332+       
333+        throw new RuntimeException("Animate tag could not be evalutated - insufficient arguements");
334+    }
335+   
336+    /**
337+     * If this element is being accumulated, detemine the delta to accumulate by
338+     */
339+    public double repeatSkipSize(int reps)
340+    {
341+        boolean fromExists = !Double.isNaN(fromValue);
342+        boolean toExists = !Double.isNaN(toValue);
343+        boolean byExists = !Double.isNaN(byValue);
344+       
345+        if (fromExists && toExists)
346+        {
347+            return (toValue - fromValue) * reps;
348+        }
349+        else if (fromExists && byExists)
350+        {
351+            return (fromValue + byValue) * reps;
352+        }
353+        else if (toExists && byExists)
354+        {
355+            return toValue * reps;
356+        }
357+        else if (byExists)
358+        {
359+            return byValue * reps;
360+        }
361+
362+        //Should not reach this line
363+        return 0;
364+    }
365+
366+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
367+    {
368+        super.rebuild(animTimeParser);
369+
370+        StyleAttribute sty = new StyleAttribute();
371+
372+        if (getPres(sty.setName("from")))
373+        {
374+            String strn = sty.getStringValue();
375+            if (XMLParseUtil.isDouble(strn))
376+            {
377+                fromValue = XMLParseUtil.parseDouble(strn);
378+            }
379+            else
380+            {
381+                fromColor = ColorTable.parseColor(strn);
382+                if (fromColor == null)
383+                {
384+                    //Try path
385+                    fromPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
386+                    dataType = DT_PATH;
387+                }
388+                else dataType = DT_COLOR;
389+            }
390+        }
391+
392+        if (getPres(sty.setName("to")))
393+        {
394+            String strn = sty.getStringValue();
395+            if (XMLParseUtil.isDouble(strn))
396+            {
397+                toValue = XMLParseUtil.parseDouble(strn);
398+            }
399+            else
400+            {
401+                toColor = ColorTable.parseColor(strn);
402+                if (toColor == null)
403+                {
404+                    //Try path
405+                    toPath = this.buildPath(strn, GeneralPath.WIND_EVEN_ODD);
406+                    dataType = DT_PATH;
407+                }
408+                else dataType = DT_COLOR;
409+            }
410+        }
411+
412+        if (getPres(sty.setName("by")))
413+        {
414+            String strn = sty.getStringValue();
415+            if (strn != null) byValue = XMLParseUtil.parseDouble(strn);
416+        }
417+
418+        if (getPres(sty.setName("values")))
419+        {
420+            String strn = sty.getStringValue();
421+            if (strn != null) valuesValue = XMLParseUtil.parseDoubleList(strn);
422+        }
423+    }
424+   
425+}
426Index: core/src/com/kitfox/svg/animation/AnimateBase.java
[4256]427===================================================================
[5284]428--- /dev/null   1970-01-01 00:00:00.000000000 +0000
429+++ core/src/com/kitfox/svg/animation/AnimateBase.java  2012-06-17 23:56:57.664545050 +0200
430@@ -0,0 +1,133 @@
431+/*
432+ * Animate.java
433+ *
434+ *  The Salamander Project - 2D and 3D graphics libraries in Java
435+ *  Copyright (C) 2004 Mark McKay
436+ *
437+ *  This library is free software; you can redistribute it and/or
438+ *  modify it under the terms of the GNU Lesser General Public
439+ *  License as published by the Free Software Foundation; either
440+ *  version 2.1 of the License, or (at your option) any later version.
441+ *
442+ *  This library is distributed in the hope that it will be useful,
443+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
444+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
445+ *  Lesser General Public License for more details.
446+ *
447+ *  You should have received a copy of the GNU Lesser General Public
448+ *  License along with this library; if not, write to the Free Software
449+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
450+ *
451+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
452+ *  projects can be found at http://www.kitfox.com
453+ *
454+ * Created on August 15, 2004, 2:51 AM
455+ */
456+
457+package com.kitfox.svg.animation;
458+
459+import com.kitfox.svg.SVGElement;
460+import com.kitfox.svg.SVGException;
461+import com.kitfox.svg.SVGLoaderHelper;
462+import com.kitfox.svg.animation.parser.AnimTimeParser;
463+import com.kitfox.svg.animation.parser.ParseException;
464+import com.kitfox.svg.xml.StyleAttribute;
465+import java.io.StringReader;
466+import org.xml.sax.Attributes;
467+import org.xml.sax.SAXException;
468+
469+/**
470+ * @author Mark McKay
471+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
472+ */
473+abstract public class AnimateBase extends AnimationElement
474+{
475+    protected double repeatCount = Double.NaN;
476+    protected TimeBase repeatDur;
477+   
478+    /** Creates a new instance of Animate */
479+    public AnimateBase()
480+    {
481+    }
482+   
483+    public void evalParametric(AnimationTimeEval state, double curTime)
484+    {
485+        evalParametric(state, curTime, repeatCount, repeatDur == null ? Double.NaN : repeatDur.evalTime());
486+    }
487+   
488+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
489+    {
490+               //Load style string
491+        super.loaderStartElement(helper, attrs, parent);
492+
493+        String repeatDurTime = attrs.getValue("repeatDur");
494+
495+        try
496+        {
497+            if (repeatDurTime != null)
498+            {
499+                helper.animTimeParser.ReInit(new StringReader(repeatDurTime));
500+                this.repeatDur = helper.animTimeParser.Expr();
501+                this.repeatDur.setParentElement(this);
502+            }
503+        }
504+        catch (Exception e)
505+        {
506+            throw new SAXException(e);
507+        }
508+       
509+        String strn = attrs.getValue("repeatCount");
510+        if (strn == null)
511+        {
512+            repeatCount = 1;
513+        }
514+        else if ("indefinite".equals(strn))
515+        {
516+            repeatCount = Double.POSITIVE_INFINITY;
517+        }
518+        else
519+        {
520+            try { repeatCount = Double.parseDouble(strn); }
521+            catch (Exception e) { repeatCount = Double.NaN; }
522+        }
523+    }
524+
525+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
526+    {
527+        super.rebuild(animTimeParser);
528+
529+        StyleAttribute sty = new StyleAttribute();
530+
531+        if (getPres(sty.setName("repeatDur")))
532+        {
533+            String strn = sty.getStringValue();
534+            if (strn != null)
535+            {
536+                animTimeParser.ReInit(new StringReader(strn));
537+                try {
538+                    this.repeatDur = animTimeParser.Expr();
539+                } catch (ParseException ex) {
540+                    ex.printStackTrace();
541+                }
542+            }
543+        }
544+
545+        if (getPres(sty.setName("repeatCount")))
546+        {
547+            String strn = sty.getStringValue();
548+            if (strn == null)
549+            {
550+                repeatCount = 1;
551+            }
552+            else if ("indefinite".equals(strn))
553+            {
554+                repeatCount = Double.POSITIVE_INFINITY;
555+            }
556+            else
557+            {
558+                try { repeatCount = Double.parseDouble(strn); }
559+                catch (Exception e) { repeatCount = Double.NaN; }
560+            }
561+        }
562+    }
563+}
564Index: core/src/com/kitfox/svg/animation/AnimateColor.java
[4256]565===================================================================
[5284]566--- /dev/null   1970-01-01 00:00:00.000000000 +0000
567+++ core/src/com/kitfox/svg/animation/AnimateColor.java 2012-06-17 23:56:57.672545050 +0200
568@@ -0,0 +1,105 @@
569+/*
570+ * Animate.java
571+ *
572+ *  The Salamander Project - 2D and 3D graphics libraries in Java
573+ *  Copyright (C) 2004 Mark McKay
574+ *
575+ *  This library is free software; you can redistribute it and/or
576+ *  modify it under the terms of the GNU Lesser General Public
577+ *  License as published by the Free Software Foundation; either
578+ *  version 2.1 of the License, or (at your option) any later version.
579+ *
580+ *  This library is distributed in the hope that it will be useful,
581+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
582+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
583+ *  Lesser General Public License for more details.
584+ *
585+ *  You should have received a copy of the GNU Lesser General Public
586+ *  License along with this library; if not, write to the Free Software
587+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
588+ *
589+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
590+ *  projects can be found at http://www.kitfox.com
591+ *
592+ * Created on August 15, 2004, 2:51 AM
593+ */
594+
595+package com.kitfox.svg.animation;
596+
597+import com.kitfox.svg.SVGElement;
598+import com.kitfox.svg.SVGException;
599+import com.kitfox.svg.SVGLoaderHelper;
600+import com.kitfox.svg.animation.parser.AnimTimeParser;
601+import com.kitfox.svg.xml.ColorTable;
602+import com.kitfox.svg.xml.StyleAttribute;
603+import java.awt.Color;
604+import org.xml.sax.Attributes;
605+import org.xml.sax.SAXException;
606+
607+
608+/**
609+ * @author Mark McKay
610+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
611+ */
612+public class AnimateColor extends AnimateBase implements AnimateColorIface
613+{
614+   
615+    protected Color fromValue;
616+    protected Color toValue;
617+   
618+    /** Creates a new instance of Animate */
619+    public AnimateColor()
620+    {
621+    }
622+   
623+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
624+    {
625+               //Load style string
626+        super.loaderStartElement(helper, attrs, parent);
627+
628+        String strn = attrs.getValue("from");
629+        fromValue = ColorTable.parseColor(strn);
630+
631+        strn = attrs.getValue("to");
632+        toValue = ColorTable.parseColor(strn);
633+    }
634+
635+   
636+    /**
637+     * Evaluates this animation element for the passed interpolation time.  Interp
638+     * must be on [0..1].
639+     */
640+    public Color evalColor(double interp)
641+    {
642+        int r1 = fromValue.getRed();
643+        int g1 = fromValue.getGreen();
644+        int b1 = fromValue.getBlue();
645+        int r2 = toValue.getRed();
646+        int g2 = toValue.getGreen();
647+        int b2 = toValue.getBlue();
648+        double invInterp = 1.0 - interp;
649+       
650+        return new Color((int)(r1 * invInterp + r2 * interp),
651+            (int)(g1 * invInterp + g2 * interp),
652+            (int)(b1 * invInterp + b2 * interp));
653+    }
654+
655+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
656+    {
657+        super.rebuild(animTimeParser);
658+
659+        StyleAttribute sty = new StyleAttribute();
660+
661+        if (getPres(sty.setName("from")))
662+        {
663+            String strn = sty.getStringValue();
664+            fromValue = ColorTable.parseColor(strn);
665+        }
666+
667+        if (getPres(sty.setName("to")))
668+        {
669+            String strn = sty.getStringValue();
670+            toValue = ColorTable.parseColor(strn);
671+        }
672+    }
673+}
674Index: core/src/com/kitfox/svg/animation/AnimateColorIface.java
[4256]675===================================================================
[5284]676--- /dev/null   1970-01-01 00:00:00.000000000 +0000
677+++ core/src/com/kitfox/svg/animation/AnimateColorIface.java    2012-06-17 23:56:57.672545050 +0200
678@@ -0,0 +1,38 @@
679+/*
680+ * AnimateColorIface.java
681+ *
682+ *  The Salamander Project - 2D and 3D graphics libraries in Java
683+ *  Copyright (C) 2004 Mark McKay
684+ *
685+ *  This library is free software; you can redistribute it and/or
686+ *  modify it under the terms of the GNU Lesser General Public
687+ *  License as published by the Free Software Foundation; either
688+ *  version 2.1 of the License, or (at your option) any later version.
689+ *
690+ *  This library is distributed in the hope that it will be useful,
691+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
692+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
693+ *  Lesser General Public License for more details.
694+ *
695+ *  You should have received a copy of the GNU Lesser General Public
696+ *  License along with this library; if not, write to the Free Software
697+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
698+ *
699+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
700+ *  projects can be found at http://www.kitfox.com
701+ *
702+ * Created on January 16, 2005, 6:24 AM
703+ */
704+
705+package com.kitfox.svg.animation;
706+
707+import java.awt.*;
708+
709+/**
710+ *
711+ * @author kitfox
712+ */
713+public interface AnimateColorIface
714+{
715+    public Color evalColor(double interp);
716+}
717Index: core/src/com/kitfox/svg/animation/AnimateMotion.java
[4256]718===================================================================
[5284]719--- /dev/null   1970-01-01 00:00:00.000000000 +0000
720+++ core/src/com/kitfox/svg/animation/AnimateMotion.java        2012-06-17 23:56:57.672545050 +0200
721@@ -0,0 +1,282 @@
722+/*
723+ * Animate.java
724+ *
725+ *  The Salamander Project - 2D and 3D graphics libraries in Java
726+ *  Copyright (C) 2004 Mark McKay
727+ *
728+ *  This library is free software; you can redistribute it and/or
729+ *  modify it under the terms of the GNU Lesser General Public
730+ *  License as published by the Free Software Foundation; either
731+ *  version 2.1 of the License, or (at your option) any later version.
732+ *
733+ *  This library is distributed in the hope that it will be useful,
734+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
735+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
736+ *  Lesser General Public License for more details.
737+ *
738+ *  You should have received a copy of the GNU Lesser General Public
739+ *  License along with this library; if not, write to the Free Software
740+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
741+ *
742+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
743+ *  projects can be found at http://www.kitfox.com
744+ *
745+ * Created on August 15, 2004, 2:51 AM
746+ */
747+
748+package com.kitfox.svg.animation;
749+
750+import com.kitfox.svg.SVGElement;
751+import com.kitfox.svg.SVGException;
752+import com.kitfox.svg.SVGLoaderHelper;
753+import com.kitfox.svg.animation.parser.AnimTimeParser;
754+import com.kitfox.svg.xml.StyleAttribute;
755+import java.awt.geom.AffineTransform;
756+import java.awt.geom.GeneralPath;
757+import java.awt.geom.PathIterator;
758+import java.awt.geom.Point2D;
759+import java.util.ArrayList;
760+import java.util.Iterator;
761+import java.util.regex.Matcher;
762+import java.util.regex.Pattern;
763+import org.xml.sax.Attributes;
764+import org.xml.sax.SAXException;
765+
766+
767+/**
768+ * @author Mark McKay
769+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
770+ */
771+public class AnimateMotion extends AnimateXform
772+{
773+    static final Matcher matchPoint = Pattern.compile("\\s*(\\d+)[^\\d]+(\\d+)\\s*").matcher("");
774+   
775+//    protected double fromValue;
776+//    protected double toValue;
777+    GeneralPath path;
778+    int rotateType = RT_ANGLE;
779+    double rotate;  //Static angle to rotate by
780+   
781+    public static final int RT_ANGLE = 0;  //Rotate by constant 'rotate' degrees
782+    public static final int RT_AUTO = 1;  //Rotate to reflect tangent of position on path
783+   
784+    final ArrayList bezierSegs = new ArrayList();
785+    double curveLength;
786+   
787+    /** Creates a new instance of Animate */
788+    public AnimateMotion()
789+    {
790+    }
791+   
792+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
793+    {
794+               //Load style string
795+        super.loaderStartElement(helper, attrs, parent);
796+       
797+        //Motion element implies animating the transform element
798+        if (attribName == null)
799+        {
800+            attribName = "transform";
801+            attribType = AT_AUTO;
802+            additiveType = AD_SUM;
803+        }
804+       
805+
806+        String path = attrs.getValue("path");
807+        if (path != null)
808+        {
809+            this.path = buildPath(path, GeneralPath.WIND_NON_ZERO);
810+        }
811+       
812+        //Now parse rotation style
813+        String rotate = attrs.getValue("rotate");
814+        if (rotate != null)
815+        {
816+            if (rotate.equals("auto"))
817+            {
818+                this.rotateType = RT_AUTO;
819+            }
820+            else
821+            {
822+                try { this.rotate = Math.toRadians(Float.parseFloat(rotate)); } catch (Exception e) {}
823+            }
824+        }
825+
826+        //Determine path
827+        String from = attrs.getValue("from");
828+        String to = attrs.getValue("to");
829+
830+        buildPath(from, to);
831+    }
832+   
833+    protected static void setPoint(Point2D.Float pt, String x, String y)
834+    {
835+        try { pt.x = Float.parseFloat(x); } catch (Exception e) {};
836+       
837+        try { pt.y = Float.parseFloat(y); } catch (Exception e) {};
838+    }
839+
840+    private void buildPath(String from, String to)
841+    {
842+        if (from != null && to != null)
843+        {
844+            Point2D.Float ptFrom = new Point2D.Float(), ptTo = new Point2D.Float();
845+
846+            matchPoint.reset(from);
847+            if (matchPoint.matches())
848+            {
849+                setPoint(ptFrom, matchPoint.group(1), matchPoint.group(2));
850+            }
851+
852+            matchPoint.reset(to);
853+            if (matchPoint.matches())
854+            {
855+                setPoint(ptFrom, matchPoint.group(1), matchPoint.group(2));
856+            }
857+
858+            if (ptFrom != null && ptTo != null)
859+            {
860+                path = new GeneralPath();
861+                path.moveTo(ptFrom.x, ptFrom.y);
862+                path.lineTo(ptTo.x, ptTo.y);
863+            }
864+        }
865+
866+        paramaterizePath();
867+    }
868+   
869+    private void paramaterizePath()
870+    {
871+        bezierSegs.clear();
872+        curveLength = 0;
873+       
874+        double[] coords = new double[6];
875+        double sx = 0, sy = 0;
876+       
877+        for (PathIterator pathIt = path.getPathIterator(new AffineTransform()); !pathIt.isDone(); pathIt.next())
878+        {
879+            Bezier bezier = null;
880+                   
881+            int segType = pathIt.currentSegment(coords);
882+           
883+            switch (segType)
884+            {
885+                case PathIterator.SEG_LINETO:
886+                {
887+                    bezier = new Bezier(sx, sy, coords, 1);
888+                    sx = coords[0];
889+                    sy = coords[1];
890+                    break;
891+                }
892+                case PathIterator.SEG_QUADTO:
893+                {
894+                    bezier = new Bezier(sx, sy, coords, 2);
895+                    sx = coords[2];
896+                    sy = coords[3];
897+                    break;
898+                }
899+                case PathIterator.SEG_CUBICTO:
900+                {
901+                    bezier = new Bezier(sx, sy, coords, 3);
902+                    sx = coords[4];
903+                    sy = coords[5];
904+                    break;
905+                }
906+                case PathIterator.SEG_MOVETO:
907+                {
908+                    sx = coords[0];
909+                    sy = coords[1];
910+                    break;
911+                }
912+                case PathIterator.SEG_CLOSE:
913+                    //Do nothing
914+                    break;
915+               
916+            }
917+
918+            if (bezier != null)
919+            {
920+                bezierSegs.add(bezier);
921+                curveLength += bezier.getLength();
922+            }
923+        }
924+    }
925+   
926+    /**
927+     * Evaluates this animation element for the passed interpolation time.  Interp
928+     * must be on [0..1].
929+     */
930+    public AffineTransform eval(AffineTransform xform, double interp)
931+    {
932+        Point2D.Double point = new Point2D.Double();
933+       
934+        if (interp >= 1)
935+        {
936+            Bezier last = (Bezier)bezierSegs.get(bezierSegs.size() - 1);
937+            last.getFinalPoint(point);
938+            xform.setToTranslation(point.x, point.y);
939+            return xform;
940+        }
941+       
942+        double curLength = curveLength * interp;
943+        for (Iterator it = bezierSegs.iterator(); it.hasNext();)
944+        {
945+            Bezier bez = (Bezier)it.next();
946+           
947+            double bezLength = bez.getLength();
948+            if (curLength < bezLength)
949+            {
950+                double param = curLength / bezLength;
951+                bez.eval(param, point);
952+                break;
953+            }
954+           
955+            curLength -= bezLength;
956+        }
957+       
958+        xform.setToTranslation(point.x, point.y);
959+       
960+        return xform;
961+    }
962+   
963+
964+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
965+    {
966+        super.rebuild(animTimeParser);
967+
968+        StyleAttribute sty = new StyleAttribute();
969+
970+        if (getPres(sty.setName("path")))
971+        {
972+            String strn = sty.getStringValue();
973+            this.path = buildPath(strn, GeneralPath.WIND_NON_ZERO);
974+        }
975+
976+        if (getPres(sty.setName("rotate")))
977+        {
978+            String strn = sty.getStringValue();
979+            if (strn.equals("auto"))
980+            {
981+                this.rotateType = RT_AUTO;
982+            }
983+            else
984+            {
985+                try { this.rotate = Math.toRadians(Float.parseFloat(strn)); } catch (Exception e) {}
986+            }
987+        }
988+
989+        String from = null;
990+        if (getPres(sty.setName("from")))
991+        {
992+            from = sty.getStringValue();
993+        }
994+
995+        String to = null;
996+        if (getPres(sty.setName("to")))
997+        {
998+            to = sty.getStringValue();
999+        }
1000+       
1001+        buildPath(from, to);
1002+    }
1003+}
1004Index: core/src/com/kitfox/svg/animation/AnimateTransform.java
[4256]1005===================================================================
[5284]1006--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1007+++ core/src/com/kitfox/svg/animation/AnimateTransform.java     2012-06-17 23:56:57.676545050 +0200
1008@@ -0,0 +1,302 @@
1009+/*
1010+ * Animate.java
1011+ *
1012+ *  The Salamander Project - 2D and 3D graphics libraries in Java
1013+ *  Copyright (C) 2004 Mark McKay
1014+ *
1015+ *  This library is free software; you can redistribute it and/or
1016+ *  modify it under the terms of the GNU Lesser General Public
1017+ *  License as published by the Free Software Foundation; either
1018+ *  version 2.1 of the License, or (at your option) any later version.
1019+ *
1020+ *  This library is distributed in the hope that it will be useful,
1021+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1022+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1023+ *  Lesser General Public License for more details.
1024+ *
1025+ *  You should have received a copy of the GNU Lesser General Public
1026+ *  License along with this library; if not, write to the Free Software
1027+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1028+ *
1029+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
1030+ *  projects can be found at http://www.kitfox.com
1031+ *
1032+ * Created on August 15, 2004, 2:51 AM
1033+ */
1034+
1035+package com.kitfox.svg.animation;
1036+
1037+import com.kitfox.svg.SVGElement;
1038+import com.kitfox.svg.SVGException;
1039+import com.kitfox.svg.SVGLoaderHelper;
1040+import com.kitfox.svg.animation.parser.AnimTimeParser;
1041+import com.kitfox.svg.xml.StyleAttribute;
1042+import com.kitfox.svg.xml.XMLParseUtil;
1043+import java.awt.geom.AffineTransform;
1044+import java.util.regex.Pattern;
1045+import org.xml.sax.Attributes;
1046+import org.xml.sax.SAXException;
1047+
1048+
1049+/**
1050+ * @author Mark McKay
1051+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
1052+ */
1053+public class AnimateTransform extends AnimateXform
1054+{
1055+//    protected AffineTransform fromValue;
1056+//    protected AffineTransform toValue;
1057+//    protected double[] fromValue;  //Transform parameters
1058+//    protected double[] toValue;
1059+    protected double[][] values;
1060+    protected double[] keyTimes;
1061+
1062+    public static final int AT_REPLACE = 0;
1063+    public static final int AT_SUM = 1;
1064+
1065+    protected int additive = AT_REPLACE;
1066+
1067+    public static final int TR_TRANSLATE = 0;
1068+    public static final int TR_ROTATE = 1;
1069+    public static final int TR_SCALE = 2;
1070+    public static final int TR_SKEWY = 3;
1071+    public static final int TR_SKEWX = 4;
1072+    public static final int TR_INVALID = 5;
1073+
1074+    protected int xformType = TR_INVALID;
1075+
1076+    /** Creates a new instance of Animate */
1077+    public AnimateTransform()
1078+    {
1079+    }
1080+
1081+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
1082+    {
1083+               //Load style string
1084+        super.loaderStartElement(helper, attrs, parent);
1085+
1086+        //Type of matrix of transform.  Should be one of the known names used to
1087+        // define matrix transforms
1088+        // valid types: translate, scale, rotate, skewX, skewY
1089+        // 'matrix' not valid for animation
1090+        String type = attrs.getValue("type").toLowerCase();
1091+        if (type.equals("translate")) xformType = TR_TRANSLATE;
1092+        if (type.equals("rotate")) xformType = TR_ROTATE;
1093+        if (type.equals("scale")) xformType = TR_SCALE;
1094+        if (type.equals("skewx")) xformType = TR_SKEWX;
1095+        if (type.equals("skewy")) xformType = TR_SKEWY;
1096+
1097+        String fromStrn = attrs.getValue("from");
1098+        String toStrn = attrs.getValue("to");
1099+        if (fromStrn != null && toStrn != null)
1100+        {
1101+            //fromValue = parseSingleTransform(type + "(" + strn + ")");
1102+            double[] fromValue = XMLParseUtil.parseDoubleList(fromStrn);
1103+            fromValue = validate(fromValue);
1104+
1105+    //        toValue = parseSingleTransform(type + "(" + strn + ")");
1106+            double[] toValue = XMLParseUtil.parseDoubleList(toStrn);
1107+            toValue = validate(toValue);
1108+           
1109+            values = new double[][]{fromValue, toValue};
1110+            keyTimes = new double[]{0, 1};
1111+        }
1112+
1113+        String keyTimeStrn = attrs.getValue("keyTimes");
1114+        String valuesStrn = attrs.getValue("values");
1115+        if (keyTimeStrn != null && valuesStrn != null)
1116+        {
1117+            keyTimes = XMLParseUtil.parseDoubleList(keyTimeStrn);
1118+           
1119+            String[] valueList = Pattern.compile(";").split(valuesStrn);
1120+            values = new double[valueList.length][];
1121+            for (int i = 0; i < valueList.length; i++)
1122+            {
1123+                double[] list = XMLParseUtil.parseDoubleList(valueList[i]);
1124+                values[i] = validate(list);
1125+            }
1126+        }
1127+       
1128+        //Check our additive state
1129+        String additive = attrs.getValue("additive");
1130+        if (additive != null)
1131+        {
1132+            if (additive.equals("sum")) this.additive = AT_SUM;
1133+        }
1134+    }
1135+
1136+    /**
1137+     * Check list size against current xform type and ensure list
1138+     * is expanded to a standard list size
1139+     */
1140+    private double[] validate(double[] paramList)
1141+    {
1142+        switch (xformType)
1143+        {
1144+            case TR_SCALE:
1145+            {
1146+                if (paramList == null)
1147+                {
1148+                    paramList = new double[]{1, 1};
1149+                }
1150+                else if (paramList.length == 1)
1151+                {
1152+                    paramList = new double[]{paramList[0], paramList[0]};
1153+                   
1154+//                    double[] tmp = paramList;
1155+//                    paramList = new double[2];
1156+//                    paramList[0] = paramList[1] = tmp[0];
1157+                }
1158+            }
1159+        }
1160+
1161+        return paramList;
1162+    }
1163+
1164+    /**
1165+     * Evaluates this animation element for the passed interpolation time.  Interp
1166+     * must be on [0..1].
1167+     */
1168+    public AffineTransform eval(AffineTransform xform, double interp)
1169+    {
1170+        int idx = 0;
1171+        for (; idx < keyTimes.length - 1; idx++)
1172+        {
1173+            if (interp >= keyTimes[idx])
1174+            {
1175+                idx--;
1176+                if (idx < 0) idx = 0;
1177+                break;
1178+            }
1179+        }
1180+       
1181+        double spanStartTime = keyTimes[idx];
1182+        double spanEndTime = keyTimes[idx + 1];
1183+//        double span = spanStartTime - spanEndTime;
1184+       
1185+        interp = (interp - spanStartTime) / (spanEndTime - spanStartTime);
1186+        double[] fromValue = values[idx];
1187+        double[] toValue = values[idx + 1];
1188+       
1189+        switch (xformType)
1190+        {
1191+            case TR_TRANSLATE:
1192+            {
1193+                double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
1194+                double y = (1.0 - interp) * fromValue[1] + interp * toValue[1];
1195+                xform.setToTranslation(x, y);
1196+                break;
1197+            }
1198+            case TR_ROTATE:
1199+            {
1200+                double x1 = fromValue.length == 3 ? fromValue[1] : 0;
1201+                double y1 = fromValue.length == 3 ? fromValue[2] : 0;
1202+                double x2 = toValue.length == 3 ? toValue[1] : 0;
1203+                double y2 = toValue.length == 3 ? toValue[2] : 0;
1204+               
1205+                double theta = (1.0 - interp) * fromValue[0] + interp * toValue[0];
1206+                double x = (1.0 - interp) * x1 + interp * x2;
1207+                double y = (1.0 - interp) * y1 + interp * y2;
1208+                xform.setToRotation(Math.toRadians(theta), x, y);
1209+                break;
1210+            }
1211+            case TR_SCALE:
1212+            {
1213+                double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
1214+                double y = (1.0 - interp) * fromValue[1] + interp * toValue[1];
1215+                xform.setToScale(x, y);
1216+                break;
1217+            }
1218+            case TR_SKEWX:
1219+            {
1220+                double x = (1.0 - interp) * fromValue[0] + interp * toValue[0];
1221+                xform.setToShear(Math.toRadians(x), 0.0);
1222+                break;
1223+            }
1224+            case TR_SKEWY:
1225+            {
1226+                double y = (1.0 - interp) * fromValue[0] + interp * toValue[0];
1227+                xform.setToShear(0.0, Math.toRadians(y));
1228+                break;
1229+            }
1230+            default:
1231+                xform.setToIdentity();
1232+                break;
1233+        }
1234+
1235+        return xform;
1236+    }
1237+
1238+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
1239+    {
1240+        super.rebuild(animTimeParser);
1241+
1242+        StyleAttribute sty = new StyleAttribute();
1243+
1244+        if (getPres(sty.setName("type")))
1245+        {
1246+            String strn = sty.getStringValue().toLowerCase();
1247+            if (strn.equals("translate")) xformType = TR_TRANSLATE;
1248+            if (strn.equals("rotate")) xformType = TR_ROTATE;
1249+            if (strn.equals("scale")) xformType = TR_SCALE;
1250+            if (strn.equals("skewx")) xformType = TR_SKEWX;
1251+            if (strn.equals("skewy")) xformType = TR_SKEWY;
1252+        }
1253+
1254+        String fromStrn = null;
1255+        if (getPres(sty.setName("from")))
1256+        {
1257+            fromStrn = sty.getStringValue();
1258+        }
1259+
1260+        String toStrn = null;
1261+        if (getPres(sty.setName("to")))
1262+        {
1263+            toStrn = sty.getStringValue();
1264+        }
1265+
1266+        if (fromStrn != null && toStrn != null)
1267+        {
1268+            double[] fromValue = XMLParseUtil.parseDoubleList(fromStrn);
1269+            fromValue = validate(fromValue);
1270+
1271+            double[] toValue = XMLParseUtil.parseDoubleList(toStrn);
1272+            toValue = validate(toValue);
1273+
1274+            values = new double[][]{fromValue, toValue};
1275+        }
1276+
1277+        String keyTimeStrn = null;
1278+        if (getPres(sty.setName("keyTimes")))
1279+        {
1280+            keyTimeStrn = sty.getStringValue();
1281+        }
1282+
1283+        String valuesStrn = null;
1284+        if (getPres(sty.setName("values")))
1285+        {
1286+            valuesStrn = sty.getStringValue();
1287+        }
1288+
1289+        if (keyTimeStrn != null && valuesStrn != null)
1290+        {
1291+            keyTimes = XMLParseUtil.parseDoubleList(keyTimeStrn);
1292+
1293+            String[] valueList = Pattern.compile(";").split(valuesStrn);
1294+            values = new double[valueList.length][];
1295+            for (int i = 0; i < valueList.length; i++)
1296+            {
1297+                double[] list = XMLParseUtil.parseDoubleList(valueList[i]);
1298+                values[i] = validate(list);
1299+            }
1300+        }
1301+
1302+        //Check our additive state
1303+
1304+        if (getPres(sty.setName("additive")))
1305+        {
1306+            String strn = sty.getStringValue().toLowerCase();
1307+            if (strn.equals("sum")) this.additive = AT_SUM;
1308+        }
1309+    }
1310+}
1311Index: core/src/com/kitfox/svg/animation/AnimateXform.java
[4256]1312===================================================================
[5284]1313--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1314+++ core/src/com/kitfox/svg/animation/AnimateXform.java 2012-06-17 23:56:57.676545050 +0200
1315@@ -0,0 +1,54 @@
1316+/*
1317+ * AnimateXform.java
1318+ *
1319+ *  The Salamander Project - 2D and 3D graphics libraries in Java
1320+ *  Copyright (C) 2004 Mark McKay
1321+ *
1322+ *  This library is free software; you can redistribute it and/or
1323+ *  modify it under the terms of the GNU Lesser General Public
1324+ *  License as published by the Free Software Foundation; either
1325+ *  version 2.1 of the License, or (at your option) any later version.
1326+ *
1327+ *  This library is distributed in the hope that it will be useful,
1328+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1329+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1330+ *  Lesser General Public License for more details.
1331+ *
1332+ *  You should have received a copy of the GNU Lesser General Public
1333+ *  License along with this library; if not, write to the Free Software
1334+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1335+ *
1336+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
1337+ *  projects can be found at http://www.kitfox.com
1338+ *
1339+ * Created on January 14, 2005, 6:46 AM
1340+ */
1341+
1342+package com.kitfox.svg.animation;
1343+
1344+import com.kitfox.svg.SVGElement;
1345+import com.kitfox.svg.SVGLoaderHelper;
1346+import java.awt.geom.AffineTransform;
1347+import org.xml.sax.Attributes;
1348+import org.xml.sax.SAXException;
1349+
1350+
1351+
1352+/**
1353+ *
1354+ * @author kitfox
1355+ */
1356+abstract public class AnimateXform extends AnimateBase
1357+{
1358+    public AnimateXform()
1359+    {
1360+    }
1361+   
1362+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
1363+    {
1364+        super.loaderStartElement(helper, attrs, parent);
1365+    }
1366+   
1367+    abstract public AffineTransform eval(AffineTransform xform, double interp);
1368+   
1369+}
1370Index: core/src/com/kitfox/svg/animation/AnimationElement.java
[4256]1371===================================================================
[5284]1372--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1373+++ core/src/com/kitfox/svg/animation/AnimationElement.java     2012-06-17 23:56:57.676545050 +0200
1374@@ -0,0 +1,414 @@
1375+/*
1376+ * AnimateEle.java
1377+ *
1378+ *  The Salamander Project - 2D and 3D graphics libraries in Java
1379+ *  Copyright (C) 2004 Mark McKay
1380+ *
1381+ *  This library is free software; you can redistribute it and/or
1382+ *  modify it under the terms of the GNU Lesser General Public
1383+ *  License as published by the Free Software Foundation; either
1384+ *  version 2.1 of the License, or (at your option) any later version.
1385+ *
1386+ *  This library is distributed in the hope that it will be useful,
1387+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1388+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1389+ *  Lesser General Public License for more details.
1390+ *
1391+ *  You should have received a copy of the GNU Lesser General Public
1392+ *  License along with this library; if not, write to the Free Software
1393+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1394+ *
1395+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
1396+ *  projects can be found at http://www.kitfox.com
1397+ *
1398+ * Created on August 15, 2004, 2:52 AM
1399+ */
1400+
1401+package com.kitfox.svg.animation;
1402+
1403+import com.kitfox.svg.SVGElement;
1404+import com.kitfox.svg.SVGException;
1405+import com.kitfox.svg.SVGLoaderHelper;
1406+import com.kitfox.svg.animation.parser.AnimTimeParser;
1407+import com.kitfox.svg.animation.parser.ParseException;
1408+import com.kitfox.svg.xml.StyleAttribute;
1409+import java.io.StringReader;
1410+import org.xml.sax.Attributes;
1411+import org.xml.sax.SAXException;
1412+
1413+
1414+/**
1415+ * @author Mark McKay
1416+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
1417+ */
1418+public abstract class AnimationElement extends SVGElement
1419+{
1420+    protected String attribName;
1421+//    protected String attribType;
1422+    protected int attribType = AT_AUTO;
1423+
1424+    public static final int AT_CSS = 0;
1425+    public static final int AT_XML = 1;
1426+    public static final int AT_AUTO = 2;  //Check CSS first, then XML
1427+
1428+    protected TimeBase beginTime;
1429+    protected TimeBase durTime;
1430+    protected TimeBase endTime;
1431+    protected int fillType = FT_AUTO;
1432+
1433+    /** <a href="http://www.w3.org/TR/smil20/smil-timing.html#adef-fill">More about the <b>fill</b> attribute</a> */
1434+    public static final int FT_REMOVE = 0;
1435+    public static final int FT_FREEZE = 1;
1436+    public static final int FT_HOLD = 2;
1437+    public static final int FT_TRANSITION = 3;
1438+    public static final int FT_AUTO = 4;
1439+    public static final int FT_DEFAULT = 5;
1440+
1441+    /** Additive state of track */
1442+    public static final int AD_REPLACE = 0;
1443+    public static final int AD_SUM = 1;
1444+
1445+    int additiveType = AD_REPLACE;
1446+   
1447+    /** Accumlative state */
1448+    public static final int AC_REPLACE = 0;
1449+    public static final int AC_SUM = 1;
1450+
1451+    int accumulateType = AC_REPLACE;
1452+
1453+    /** Creates a new instance of AnimateEle */
1454+    public AnimationElement()
1455+    {
1456+    }
1457+
1458+    public static String animationElementToString(int attrValue)
1459+    {
1460+        switch (attrValue)
1461+        {
1462+            case AT_CSS:
1463+                return "CSS";
1464+            case AT_XML:
1465+                return "XML";
1466+            case AT_AUTO:
1467+                return "AUTO";
1468+            default:
1469+                throw new RuntimeException("Unknown element type");
1470+        }
1471+    }
1472+   
1473+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
1474+    {
1475+               //Load style string
1476+        super.loaderStartElement(helper, attrs, parent);
1477+
1478+        attribName = attrs.getValue("attributeName");
1479+        String attribType = attrs.getValue("attributeType");
1480+        if (attribType != null)
1481+        {
1482+            attribType = attribType.toLowerCase();
1483+            if (attribType.equals("css")) this.attribType = AT_CSS;
1484+            else if (attribType.equals("xml")) this.attribType = AT_XML;
1485+        }
1486+
1487+        String beginTime = attrs.getValue("begin");
1488+        String durTime = attrs.getValue("dur");
1489+        String endTime = attrs.getValue("end");
1490+
1491+        try
1492+        {
1493+            if (beginTime != null)
1494+            {
1495+                helper.animTimeParser.ReInit(new StringReader(beginTime));
1496+                this.beginTime = helper.animTimeParser.Expr();
1497+                this.beginTime.setParentElement(this);
1498+            }
1499+
1500+            if (durTime != null)
1501+            {
1502+                helper.animTimeParser.ReInit(new StringReader(durTime));
1503+                this.durTime = helper.animTimeParser.Expr();
1504+                this.durTime.setParentElement(this);
1505+            }
1506+
1507+            if (endTime != null)
1508+            {
1509+                helper.animTimeParser.ReInit(new StringReader(endTime));
1510+                this.endTime = helper.animTimeParser.Expr();
1511+                this.endTime.setParentElement(this);
1512+            }
1513+        }
1514+        catch (Exception e)
1515+        {
1516+            throw new SAXException(e);
1517+        }
1518+       
1519+//        this.beginTime = TimeBase.parseTime(beginTime);
1520+//        this.durTime = TimeBase.parseTime(durTime);
1521+//        this.endTime = TimeBase.parseTime(endTime);
1522+
1523+        String fill = attrs.getValue("fill");
1524+
1525+        if (fill != null)
1526+        {
1527+            if (fill.equals("remove")) this.fillType = FT_REMOVE;
1528+            if (fill.equals("freeze")) this.fillType = FT_FREEZE;
1529+            if (fill.equals("hold")) this.fillType = FT_HOLD;
1530+            if (fill.equals("transiton")) this.fillType = FT_TRANSITION;
1531+            if (fill.equals("auto")) this.fillType = FT_AUTO;
1532+            if (fill.equals("default")) this.fillType = FT_DEFAULT;
1533+        }
1534+       
1535+        String additiveStrn = attrs.getValue("additive");
1536+       
1537+        if (additiveStrn != null)
1538+        {
1539+            if (additiveStrn.equals("replace")) this.additiveType = AD_REPLACE;
1540+            if (additiveStrn.equals("sum")) this.additiveType = AD_SUM;
1541+        }
1542+       
1543+        String accumulateStrn = attrs.getValue("accumulate");
1544+       
1545+        if (accumulateStrn != null)
1546+        {
1547+            if (accumulateStrn.equals("replace")) this.accumulateType = AC_REPLACE;
1548+            if (accumulateStrn.equals("sum")) this.accumulateType = AC_SUM;
1549+        }
1550+    }
1551+
1552+    public String getAttribName() { return attribName; }
1553+    public int getAttribType() { return attribType; }
1554+    public int getAdditiveType() { return additiveType; }
1555+    public int getAccumulateType() { return accumulateType; }
1556+
1557+    public void evalParametric(AnimationTimeEval state, double curTime)
1558+    {
1559+        evalParametric(state, curTime, Double.NaN, Double.NaN);
1560+    }
1561+
1562+    /**
1563+     * Compares current time to start and end times and determines what degree
1564+     * of time interpolation this track currently represents.  Returns
1565+     * Float.NaN if this track cannot be evaluated at the passed time (ie,
1566+     * it is before or past the end of the track, or it depends upon
1567+     * an unknown event)
1568+     * @param state - A structure that will be filled with information
1569+     * regarding the applicability of this animatoin element at the passed
1570+     * time.
1571+     * @param curTime - Current time in seconds
1572+     * @param repeatCount - Optional number of repetitions of length 'dur' to
1573+     * do.  Set to Double.NaN to not consider this in the calculation.
1574+     * @param repeatDur - Optional amoun tof time to repeat the animaiton.
1575+     * Set to Double.NaN to not consider this in the calculation.
1576+     */
1577+    protected void evalParametric(AnimationTimeEval state, double curTime, double repeatCount, double repeatDur)
1578+    {
1579+        double begin = (beginTime == null) ? 0 : beginTime.evalTime();
1580+        if (Double.isNaN(begin) || begin > curTime)
1581+        {
1582+            state.set(Double.NaN, 0);
1583+            return;
1584+        }
1585+
1586+        double dur = (durTime == null) ? Double.NaN : durTime.evalTime();
1587+        if (Double.isNaN(dur))
1588+        {
1589+            state.set(Double.NaN, 0);
1590+            return;
1591+        }
1592+
1593+        //Determine end point of this animation
1594+        double end = (endTime == null) ? Double.NaN : endTime.evalTime();
1595+        double repeat;
1596+//        if (Double.isNaN(repeatDur))
1597+//        {
1598+//            repeatDur = dur;
1599+//        }
1600+        if (Double.isNaN(repeatCount) && Double.isNaN(repeatDur))
1601+        {
1602+            repeat = Double.NaN;
1603+        }
1604+        else
1605+        {
1606+            repeat = Math.min(
1607+                Double.isNaN(repeatCount) ? Double.POSITIVE_INFINITY : dur * repeatCount,
1608+                Double.isNaN(repeatDur) ? Double.POSITIVE_INFINITY : repeatDur);
1609+        }
1610+        if (Double.isNaN(repeat) && Double.isNaN(end))
1611+        {
1612+            //If neither and end point nor a repeat is specified, end point is
1613+            // implied by duration.
1614+            end = begin + dur;
1615+        }
1616+
1617+        double finishTime;
1618+        if (Double.isNaN(end))
1619+        {
1620+            finishTime = begin + repeat;
1621+        }
1622+        else if (Double.isNaN(repeat))
1623+        {
1624+            finishTime = end;
1625+        }
1626+        else
1627+        {
1628+            finishTime = Math.min(end, repeat);
1629+        }
1630+       
1631+        double evalTime = Math.min(curTime, finishTime);
1632+//        if (curTime > finishTime) evalTime = finishTime;
1633+       
1634+       
1635+//        double evalTime = curTime;
1636+
1637+//        boolean pastEnd = curTime > evalTime;
1638+       
1639+//        if (!Double.isNaN(end) && curTime > end) { pastEnd = true; evalTime = Math.min(evalTime, end); }
1640+//        if (!Double.isNaN(repeat) && curTime > repeat) { pastEnd = true; evalTime = Math.min(evalTime, repeat); }
1641+       
1642+        double ratio = (evalTime - begin) / dur;
1643+        int rep = (int)ratio;
1644+        double interp = ratio - rep;
1645+       
1646+        //Adjust for roundoff
1647+        if (interp < 0.00001) interp = 0;
1648+
1649+//        state.set(interp, rep);
1650+//        if (!pastEnd)
1651+//        {
1652+//            state.set(interp, rep, false);
1653+//            return;
1654+//        }
1655+
1656+        //If we are still within the clip, return value
1657+        if (curTime == evalTime)
1658+        {
1659+            state.set(interp, rep);
1660+            return;
1661+        }
1662+       
1663+        //We are past end of clip.  Determine to clamp or ignore.
1664+        switch (fillType)
1665+        {
1666+            default:
1667+            case FT_REMOVE:
1668+            case FT_AUTO:
1669+            case FT_DEFAULT:
1670+                state.set(Double.NaN, rep);
1671+                return;
1672+            case FT_FREEZE:
1673+            case FT_HOLD:
1674+            case FT_TRANSITION:
1675+                state.set(interp == 0 ? 1 : interp, rep);
1676+                return;
1677+        }
1678+
1679+    }
1680+
1681+    double evalStartTime()
1682+    {
1683+        return beginTime == null ? Double.NaN : beginTime.evalTime();
1684+    }
1685+
1686+    double evalDurTime()
1687+    {
1688+        return durTime == null ? Double.NaN : durTime.evalTime();
1689+    }
1690+
1691+    /**
1692+     * Evaluates the ending time of this element.  Returns 0 if not specified.
1693+     *
1694+     * @see hasEndTime
1695+     */
1696+    double evalEndTime()
1697+    {
1698+        return endTime == null ? Double.NaN : endTime.evalTime();
1699+    }
1700+
1701+    /**
1702+     * Checks to see if an end time has been specified for this element.
1703+     */
1704+    boolean hasEndTime() { return endTime != null; }
1705+
1706+    /**
1707+     * Updates all attributes in this diagram associated with a time event.
1708+     * Ie, all attributes with track information.
1709+     * @return - true if this node has changed state as a result of the time
1710+     * update
1711+     */
1712+    public boolean updateTime(double curTime)
1713+    {
1714+        //Animation elements to not change with time
1715+        return false;
1716+    }
1717+
1718+    public void rebuild() throws SVGException
1719+    {
1720+        AnimTimeParser animTimeParser = new AnimTimeParser(new StringReader(""));
1721+
1722+        rebuild(animTimeParser);
1723+    }
1724+
1725+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
1726+    {
1727+        StyleAttribute sty = new StyleAttribute();
1728+
1729+        if (getPres(sty.setName("begin")))
1730+        {
1731+            String newVal = sty.getStringValue();
1732+            animTimeParser.ReInit(new StringReader(newVal));
1733+            try {
1734+                this.beginTime = animTimeParser.Expr();
1735+            } catch (ParseException ex) {
1736+                ex.printStackTrace();
1737+            }
1738+        }
1739+
1740+        if (getPres(sty.setName("dur")))
1741+        {
1742+            String newVal = sty.getStringValue();
1743+            animTimeParser.ReInit(new StringReader(newVal));
1744+            try {
1745+                this.durTime = animTimeParser.Expr();
1746+            } catch (ParseException ex) {
1747+                ex.printStackTrace();
1748+            }
1749+        }
1750+
1751+        if (getPres(sty.setName("end")))
1752+        {
1753+            String newVal = sty.getStringValue();
1754+            animTimeParser.ReInit(new StringReader(newVal));
1755+            try {
1756+                this.endTime = animTimeParser.Expr();
1757+            } catch (ParseException ex) {
1758+                ex.printStackTrace();
1759+            }
1760+        }
1761+
1762+        if (getPres(sty.setName("fill")))
1763+        {
1764+            String newVal = sty.getStringValue();
1765+            if (newVal.equals("remove")) this.fillType = FT_REMOVE;
1766+            if (newVal.equals("freeze")) this.fillType = FT_FREEZE;
1767+            if (newVal.equals("hold")) this.fillType = FT_HOLD;
1768+            if (newVal.equals("transiton")) this.fillType = FT_TRANSITION;
1769+            if (newVal.equals("auto")) this.fillType = FT_AUTO;
1770+            if (newVal.equals("default")) this.fillType = FT_DEFAULT;
1771+        }
1772+
1773+        if (getPres(sty.setName("additive")))
1774+        {
1775+            String newVal = sty.getStringValue();
1776+            if (newVal.equals("replace")) this.additiveType = AD_REPLACE;
1777+            if (newVal.equals("sum")) this.additiveType = AD_SUM;
1778+        }
1779+
1780+        if (getPres(sty.setName("accumulate")))
1781+        {
1782+            String newVal = sty.getStringValue();
1783+            if (newVal.equals("replace")) this.accumulateType = AC_REPLACE;
1784+            if (newVal.equals("sum")) this.accumulateType = AC_SUM;
1785+        }
1786+
1787+    }
1788+}
1789Index: core/src/com/kitfox/svg/animation/AnimationTimeEval.java
[4256]1790===================================================================
[5284]1791--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1792+++ core/src/com/kitfox/svg/animation/AnimationTimeEval.java    2012-06-17 23:56:57.676545050 +0200
1793@@ -0,0 +1,65 @@
1794+/*
1795+ * AnimateTimeEval.java
1796+ *
1797+ *  The Salamander Project - 2D and 3D graphics libraries in Java
1798+ *  Copyright (C) 2004 Mark McKay
1799+ *
1800+ *  This library is free software; you can redistribute it and/or
1801+ *  modify it under the terms of the GNU Lesser General Public
1802+ *  License as published by the Free Software Foundation; either
1803+ *  version 2.1 of the License, or (at your option) any later version.
1804+ *
1805+ *  This library is distributed in the hope that it will be useful,
1806+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1807+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1808+ *  Lesser General Public License for more details.
1809+ *
1810+ *  You should have received a copy of the GNU Lesser General Public
1811+ *  License along with this library; if not, write to the Free Software
1812+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1813+ *
1814+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
1815+ *  projects can be found at http://www.kitfox.com
1816+ *
1817+ *
1818+ * Created on September 21, 2004, 1:31 PM
1819+ */
1820+
1821+package com.kitfox.svg.animation;
1822+
1823+/**
1824+ *
1825+ * @author  kitfox
1826+ */
1827+public class AnimationTimeEval
1828+{
1829+    /**
1830+     * Value on [0..1] representing the interpolation value of queried animation
1831+     * element, or Double.NaN if element does not provide a valid evalutaion
1832+     */
1833+    public double interp;
1834+   
1835+    /**
1836+     * Number of completed repetitions
1837+     */
1838+    public int rep;
1839+   
1840+    /**
1841+     * True if this evaluation is in a frozen state; ie, past the end of the
1842+     * track and held in the "freeze" state.
1843+     */
1844+//    public boolean pastEnd;
1845+   
1846+    /** Creates a new instance of AnimateTimeEval */
1847+    public AnimationTimeEval()
1848+    {
1849+    }
1850+   
1851+//    public void set(double interp, int rep, boolean pastEnd)
1852+    public void set(double interp, int rep)
1853+    {
1854+        this.interp = interp;
1855+        this.rep = rep;
1856+//        this.pastEnd = pastEnd;
1857+    }
1858+}
1859Index: core/src/com/kitfox/svg/animation/Bezier.java
[4256]1860===================================================================
[5284]1861--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1862+++ core/src/com/kitfox/svg/animation/Bezier.java       2012-06-17 23:56:57.680545050 +0200
1863@@ -0,0 +1,201 @@
1864+/*
1865+ * Bezier.java
1866+ *
1867+
1868+ *  The Salamander Project - 2D and 3D graphics libraries in Java
1869+ *  Copyright (C) 2004 Mark McKay
1870+ *
1871+ *  This library is free software; you can redistribute it and/or
1872+ *  modify it under the terms of the GNU Lesser General Public
1873+ *  License as published by the Free Software Foundation; either
1874+ *  version 2.1 of the License, or (at your option) any later version.
1875+ *
1876+ *  This library is distributed in the hope that it will be useful,
1877+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1878+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1879+ *  Lesser General Public License for more details.
1880+ *
1881+ *  You should have received a copy of the GNU Lesser General Public
1882+ *  License along with this library; if not, write to the Free Software
1883+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1884+ *
1885+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
1886+ *  projects can be found at http://www.kitfox.com
1887+ *
1888+ * Created on January 14, 2005, 4:08 AM
1889+ */
1890+
1891+package com.kitfox.svg.animation;
1892+
1893+import java.awt.geom.*;
1894+
1895+/**
1896+ * http://mathworld.wolfram.com/BezierCurve.html
1897+ * @author kitfox
1898+ */
1899+public class Bezier
1900+{
1901+    double length;
1902+    double[] coord;
1903+
1904+    public Bezier(double sx, double sy, double[] coords, int numCoords)
1905+    {
1906+        setCoords(sx, sy, coords, numCoords);
1907+    }
1908+   
1909+    public void setCoords(double sx, double sy, double[] coords, int numCoords)
1910+    {
1911+        coord = new double[numCoords * 2 + 2];
1912+        coord[0] = sx;
1913+        coord[1] = sy;
1914+        for (int i = 0; i < numCoords; i++)
1915+        {
1916+            coord[i * 2 + 2] = coords[i * 2];
1917+            coord[i * 2 + 3] = coords[i * 2 + 1];
1918+        }
1919+       
1920+        calcLength();       
1921+    }
1922+   
1923+    /**
1924+     * Retuns aproximation of the length of the bezier
1925+     */
1926+    public double getLength()
1927+    {
1928+        return length;
1929+    }
1930+   
1931+    private void calcLength()
1932+    {
1933+        length = 0;
1934+        for (int i = 2; i < coord.length; i += 2)
1935+        {
1936+            length += lineLength(coord[i - 2], coord[i - 1], coord[i], coord[i + 1]);
1937+        }
1938+    }
1939+   
1940+    private double lineLength(double x1, double y1, double x2, double y2)
1941+    {
1942+        double dx = x2 - x1, dy = y2 - y1;
1943+        return Math.sqrt(dx * dx + dy * dy);
1944+    }
1945+   
1946+    public Point2D.Double getFinalPoint(Point2D.Double point)
1947+    {
1948+        point.x = coord[coord.length - 2];
1949+        point.y = coord[coord.length - 1];
1950+        return point;
1951+    }
1952+   
1953+    public Point2D.Double eval(double param, Point2D.Double point)
1954+    {
1955+        point.x = 0;
1956+        point.y = 0;
1957+        int numKnots = coord.length / 2;
1958+       
1959+        for (int i = 0; i < numKnots; i++)
1960+        {
1961+            double scale = bernstein(numKnots - 1, i, param);
1962+            point.x += coord[i * 2] * scale;
1963+            point.y += coord[i * 2 + 1] * scale;
1964+        }
1965+       
1966+        return point;
1967+    }
1968+   
1969+    /**
1970+     * Calculates the bernstein polynomial for evaluating parametric bezier
1971+     * @param numKnots - one less than number of knots in this curve hull
1972+     * @param knotNo - knot we are evaluating Bernstein for
1973+     * @param param - Parametric value we are evaluating at
1974+     */
1975+    private double bernstein(int numKnots, int knotNo, double param)
1976+    {
1977+        double iParam = 1 - param;
1978+        //Faster evaluation for easy cases:
1979+        switch (numKnots)
1980+        {
1981+            case 0:
1982+                return 1;
1983+            case 1:
1984+            {
1985+                switch (knotNo)
1986+                {
1987+                    case 0:
1988+                        return iParam;
1989+                    case 1:
1990+                        return param;
1991+                }
1992+                break;
1993+            }
1994+            case 2:
1995+            {
1996+                switch (knotNo)
1997+                {
1998+                    case 0:
1999+                        return iParam * iParam;
2000+                    case 1:
2001+                        return 2 * iParam * param;
2002+                    case 2:
2003+                        return param * param;
2004+                }
2005+                break;
2006+            }
2007+            case 3:
2008+            {
2009+                switch (knotNo)
2010+                {
2011+                    case 0:
2012+                        return iParam * iParam * iParam;
2013+                    case 1:
2014+                        return 3 * iParam * iParam * param;
2015+                    case 2:
2016+                        return 3 * iParam * param * param;
2017+                    case 3:
2018+                        return param * param * param;
2019+                }
2020+                break;
2021+            }
2022+        }
2023+       
2024+        //If this bezier has more than four points, calculate bernstein the hard way
2025+        double retVal = 1;
2026+        for (int i = 0; i < knotNo; i++)
2027+        {
2028+            retVal *= param;
2029+        }
2030+        for (int i = 0; i < numKnots - knotNo; i++)
2031+        {
2032+            retVal *= iParam;
2033+        }
2034+        retVal *= choose(numKnots, knotNo);
2035+       
2036+        return retVal;
2037+    }
2038+   
2039+   
2040+   
2041+    private int choose(int num, int denom)
2042+    {
2043+        int denom2 = num - denom;
2044+        if (denom < denom2)
2045+        {
2046+            int tmp = denom;
2047+            denom = denom2;
2048+            denom2 = tmp;
2049+        }
2050+       
2051+        int prod = 1;
2052+        for (int i = num; i > denom; i--)
2053+        {
2054+            prod *= num;
2055+        }
2056+       
2057+        for (int i = 2; i <= denom2; i++)
2058+        {
2059+            prod /= i;
2060+        }
2061+       
2062+        return prod;
2063+    }
2064+}
2065Index: core/src/com/kitfox/svg/animation/SetSmil.java
[4256]2066===================================================================
[5284]2067--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2068+++ core/src/com/kitfox/svg/animation/SetSmil.java      2012-06-17 23:56:57.680545050 +0200
2069@@ -0,0 +1,73 @@
2070+/*
2071+ * Set.java
2072+ *
2073+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2074+ *  Copyright (C) 2004 Mark McKay
2075+ *
2076+ *  This library is free software; you can redistribute it and/or
2077+ *  modify it under the terms of the GNU Lesser General Public
2078+ *  License as published by the Free Software Foundation; either
2079+ *  version 2.1 of the License, or (at your option) any later version.
2080+ *
2081+ *  This library is distributed in the hope that it will be useful,
2082+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2083+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2084+ *  Lesser General Public License for more details.
2085+ *
2086+ *  You should have received a copy of the GNU Lesser General Public
2087+ *  License along with this library; if not, write to the Free Software
2088+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2089+ *
2090+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2091+ *  projects can be found at http://www.kitfox.com
2092+ *
2093+ * Created on August 15, 2004, 2:51 AM
2094+ */
2095+
2096+package com.kitfox.svg.animation;
2097+
2098+import com.kitfox.svg.SVGElement;
2099+import com.kitfox.svg.SVGException;
2100+import com.kitfox.svg.SVGLoaderHelper;
2101+import com.kitfox.svg.animation.parser.AnimTimeParser;
2102+import com.kitfox.svg.xml.StyleAttribute;
2103+import org.xml.sax.Attributes;
2104+import org.xml.sax.SAXException;
2105+
2106+
2107+/**
2108+ * Set is used to set a textual value; most likely for a style element.
2109+ *
2110+ * @author Mark McKay
2111+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2112+ */
2113+public class SetSmil extends AnimationElement
2114+{
2115+    String toValue;
2116+   
2117+    /** Creates a new instance of Set */
2118+    public SetSmil()
2119+    {
2120+    }
2121+   
2122+    public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
2123+    {
2124+               //Load style string
2125+        super.loaderStartElement(helper, attrs, parent);
2126+
2127+        toValue = attrs.getValue("to");
2128+    }
2129+
2130+    protected void rebuild(AnimTimeParser animTimeParser) throws SVGException
2131+    {
2132+        super.rebuild(animTimeParser);
2133+
2134+        StyleAttribute sty = new StyleAttribute();
2135+
2136+        if (getPres(sty.setName("to")))
2137+        {
2138+            String newVal = sty.getStringValue();
2139+            toValue = newVal;
2140+        }
2141+    }
2142+}
2143Index: core/src/com/kitfox/svg/animation/TimeBase.java
[4256]2144===================================================================
[5284]2145--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2146+++ core/src/com/kitfox/svg/animation/TimeBase.java     2012-06-17 23:56:57.680545050 +0200
2147@@ -0,0 +1,99 @@
2148+/*
2149+ * TimeBase.java
2150+ *
2151+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2152+ *  Copyright (C) 2004 Mark McKay
2153+ *
2154+ *  This library is free software; you can redistribute it and/or
2155+ *  modify it under the terms of the GNU Lesser General Public
2156+ *  License as published by the Free Software Foundation; either
2157+ *  version 2.1 of the License, or (at your option) any later version.
2158+ *
2159+ *  This library is distributed in the hope that it will be useful,
2160+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2161+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2162+ *  Lesser General Public License for more details.
2163+ *
2164+ *  You should have received a copy of the GNU Lesser General Public
2165+ *  License along with this library; if not, write to the Free Software
2166+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2167+ *
2168+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2169+ *  projects can be found at http://www.kitfox.com
2170+ *
2171+ * Created on August 15, 2004, 3:31 AM
2172+ */
2173+
2174+package com.kitfox.svg.animation;
2175+
2176+import java.util.regex.*;
2177+
2178+/**
2179+ * SVG has a complicated way of specifying time.  Potentially, a time could
2180+ * be represened as a summation of discrete times and times of other animation
2181+ * events.  This provides a root for the many elements we will need to define
2182+ * time.
2183+ *
2184+ * @author Mark McKay
2185+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2186+ */
2187+abstract public class TimeBase
2188+{
2189+    static final Matcher matchIndefinite = Pattern.compile("\\s*indefinite\\s*").matcher("");
2190+    static final Matcher matchUnitTime = Pattern.compile("\\s*([-+]?((\\d*\\.\\d+)|(\\d+))([-+]?[eE]\\d+)?)\\s*(h|min|s|ms)?\\s*").matcher("");
2191+   
2192+    /*
2193+    public static TimeBase parseTime(String text)
2194+    {
2195+        if (text == null) return null;
2196+       
2197+        if (text.indexOf('+') == -1)
2198+        {
2199+            return parseTimeComponent(text);
2200+        }
2201+       
2202+        return new TimeCompound(text);
2203+    }
2204+     */
2205+   
2206+    protected static TimeBase parseTimeComponent(String text)
2207+    {
2208+        matchIndefinite.reset(text);
2209+        if (matchIndefinite.matches()) return new TimeIndefinite();
2210+       
2211+        matchUnitTime.reset(text);
2212+        if (matchUnitTime.matches())
2213+        {
2214+            String val = matchUnitTime.group(1);
2215+            String units = matchUnitTime.group(6);
2216+           
2217+            double time = 0;
2218+            try { time = Double.parseDouble(val); }
2219+            catch (Exception e) {}
2220+           
2221+            if (units.equals("ms")) time *= .001;
2222+            else if (units.equals("min")) time *= 60;
2223+            else if (units.equals("h")) time *= 3600;
2224+           
2225+            return new TimeDiscrete(time);
2226+        }
2227+       
2228+        return null;
2229+    }
2230+   
2231+    /**
2232+     * Calculates the (greater than or equal to 0) time in seconds this
2233+     * time represents.  If the time cannot be determined, returns
2234+     * Double.NaN.  If this represents an infinte amount of time, returns
2235+     * Double.POSITIVE_INFINITY.
2236+     */
2237+    abstract public double evalTime();
2238+   
2239+    /**
2240+     * Some time elements need to refer to the animation element that contains
2241+     * them to evaluate correctly
2242+     */
2243+    public void setParentElement(AnimationElement ele)
2244+    {
2245+    }
2246+}
2247Index: core/src/com/kitfox/svg/animation/TimeCompound.java
[4256]2248===================================================================
[5284]2249--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2250+++ core/src/com/kitfox/svg/animation/TimeCompound.java 2012-06-17 23:56:57.680545050 +0200
2251@@ -0,0 +1,84 @@
2252+/*
2253+ * TimeDiscrete.java
2254+ *
2255+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2256+ *  Copyright (C) 2004 Mark McKay
2257+ *
2258+ *  This library is free software; you can redistribute it and/or
2259+ *  modify it under the terms of the GNU Lesser General Public
2260+ *  License as published by the Free Software Foundation; either
2261+ *  version 2.1 of the License, or (at your option) any later version.
2262+ *
2263+ *  This library is distributed in the hope that it will be useful,
2264+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2265+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2266+ *  Lesser General Public License for more details.
2267+ *
2268+ *  You should have received a copy of the GNU Lesser General Public
2269+ *  License along with this library; if not, write to the Free Software
2270+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2271+ *
2272+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2273+ *  projects can be found at http://www.kitfox.com
2274+ *
2275+ * Created on August 15, 2004, 3:33 AM
2276+ */
2277+
2278+package com.kitfox.svg.animation;
2279+
2280+import java.util.Collections;
2281+import java.util.Iterator;
2282+import java.util.List;
2283+import java.util.regex.Pattern;
2284+
2285+
2286+/**
2287+ * This represents a summation of other time elements.  It is used for complex
2288+ * timing events with offsets.
2289+ *
2290+ * @author Mark McKay
2291+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2292+ */
2293+public class TimeCompound extends TimeBase
2294+{
2295+    static final Pattern patPlus = Pattern.compile("\\+");
2296+   
2297+    /**
2298+     * This is a list of times.  This element's time is calculated as the greatest
2299+     * member that is less than the current time.
2300+    */
2301+    final List componentTimes;
2302+
2303+    private AnimationElement parent;
2304+   
2305+    /** Creates a new instance of TimeDiscrete */
2306+    public TimeCompound(List timeBases)
2307+    {
2308+        componentTimes = Collections.unmodifiableList(timeBases);
2309+    }
2310+   
2311+    public double evalTime()
2312+    {
2313+        double agg = 0.0;
2314+       
2315+        for (Iterator it = componentTimes.iterator(); it.hasNext();)
2316+        {
2317+            TimeBase timeEle = (TimeBase)it.next();
2318+            double time = timeEle.evalTime();
2319+            agg += time;
2320+        }
2321+       
2322+        return agg;
2323+    }
2324+   
2325+    public void setParentElement(AnimationElement ele)
2326+    {
2327+        this.parent = ele;
2328+       
2329+        for (Iterator it = componentTimes.iterator(); it.hasNext();)
2330+        {
2331+            TimeBase timeEle = (TimeBase)it.next();
2332+            timeEle.setParentElement(ele);
2333+        }
2334+    }
2335+}
2336Index: core/src/com/kitfox/svg/animation/TimeDiscrete.java
[4256]2337===================================================================
[5284]2338--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2339+++ core/src/com/kitfox/svg/animation/TimeDiscrete.java 2012-06-17 23:56:57.680545050 +0200
2340@@ -0,0 +1,51 @@
2341+/*
2342+ * TimeDiscrete.java
2343+ *
2344+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2345+ *  Copyright (C) 2004 Mark McKay
2346+ *
2347+ *  This library is free software; you can redistribute it and/or
2348+ *  modify it under the terms of the GNU Lesser General Public
2349+ *  License as published by the Free Software Foundation; either
2350+ *  version 2.1 of the License, or (at your option) any later version.
2351+ *
2352+ *  This library is distributed in the hope that it will be useful,
2353+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2354+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2355+ *  Lesser General Public License for more details.
2356+ *
2357+ *  You should have received a copy of the GNU Lesser General Public
2358+ *  License along with this library; if not, write to the Free Software
2359+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2360+ *
2361+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2362+ *  projects can be found at http://www.kitfox.com
2363+ *
2364+ * Created on August 15, 2004, 3:33 AM
2365+ */
2366+
2367+package com.kitfox.svg.animation;
2368+
2369+/**
2370+ * This is a time that represents a specific number of milliseconds
2371+ *
2372+ * @author Mark McKay
2373+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2374+ */
2375+public class TimeDiscrete extends TimeBase
2376+{
2377+    //Milliseconds of delay
2378+    double secs;
2379+   
2380+    /** Creates a new instance of TimeDiscrete */
2381+    public TimeDiscrete(double secs)
2382+    {
2383+        this.secs = secs;
2384+    }
2385+   
2386+    public double evalTime()
2387+    {
2388+        return secs;
2389+    }
2390+   
2391+}
2392Index: core/src/com/kitfox/svg/animation/TimeIndefinite.java
[4256]2393===================================================================
[5284]2394--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2395+++ core/src/com/kitfox/svg/animation/TimeIndefinite.java       2012-06-17 23:56:57.680545050 +0200
2396@@ -0,0 +1,48 @@
2397+/*
2398+ * TimeDiscrete.java
2399+ *
2400+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2401+ *  Copyright (C) 2004 Mark McKay
2402+ *
2403+ *  This library is free software; you can redistribute it and/or
2404+ *  modify it under the terms of the GNU Lesser General Public
2405+ *  License as published by the Free Software Foundation; either
2406+ *  version 2.1 of the License, or (at your option) any later version.
2407+ *
2408+ *  This library is distributed in the hope that it will be useful,
2409+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2410+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2411+ *  Lesser General Public License for more details.
2412+ *
2413+ *  You should have received a copy of the GNU Lesser General Public
2414+ *  License along with this library; if not, write to the Free Software
2415+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2416+ *
2417+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2418+ *  projects can be found at http://www.kitfox.com
2419+ *
2420+ * Created on August 15, 2004, 3:33 AM
2421+ */
2422+
2423+package com.kitfox.svg.animation;
2424+
2425+/**
2426+ * This represents the indefinite (infinite) amount of time.
2427+ *
2428+ * @author Mark McKay
2429+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2430+ */
2431+public class TimeIndefinite extends TimeBase
2432+{
2433+   
2434+    /** Creates a new instance of TimeDiscrete */
2435+    public TimeIndefinite()
2436+    {
2437+    }
2438+   
2439+    public double evalTime()
2440+    {
2441+        return Double.POSITIVE_INFINITY;
2442+    }
2443+   
2444+}
2445Index: core/src/com/kitfox/svg/animation/TimeLookup.java
[4256]2446===================================================================
[5284]2447--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2448+++ core/src/com/kitfox/svg/animation/TimeLookup.java   2012-06-17 23:56:57.684545050 +0200
2449@@ -0,0 +1,75 @@
2450+/*
2451+ * TimeDiscrete.java
2452+ *
2453+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2454+ *  Copyright (C) 2004 Mark McKay
2455+ *
2456+ *  This library is free software; you can redistribute it and/or
2457+ *  modify it under the terms of the GNU Lesser General Public
2458+ *  License as published by the Free Software Foundation; either
2459+ *  version 2.1 of the License, or (at your option) any later version.
2460+ *
2461+ *  This library is distributed in the hope that it will be useful,
2462+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2463+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2464+ *  Lesser General Public License for more details.
2465+ *
2466+ *  You should have received a copy of the GNU Lesser General Public
2467+ *  License along with this library; if not, write to the Free Software
2468+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2469+ *
2470+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2471+ *  projects can be found at http://www.kitfox.com
2472+ *
2473+ * Created on August 15, 2004, 3:33 AM
2474+ */
2475+
2476+package com.kitfox.svg.animation;
2477+
2478+/**
2479+ * This is a time that represents a specific number of milliseconds
2480+ *
2481+ * @author Mark McKay
2482+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2483+ */
2484+public class TimeLookup extends TimeBase
2485+{
2486+    /**
2487+     * This time can only be resolved in relation to it's parent
2488+     */
2489+    private AnimationElement parent;
2490+   
2491+    /**
2492+     * Node this lookup acts upon
2493+     */
2494+    String node;
2495+   
2496+    /**
2497+     * Event to evalutae on this node
2498+     */
2499+    String event;
2500+   
2501+    /**
2502+     * Optional parameter used by some events
2503+     */
2504+    String paramList;
2505+   
2506+    /** Creates a new instance of TimeDiscrete */
2507+    public TimeLookup(AnimationElement parent, String node, String event, String paramList)
2508+    {
2509+        this.parent = parent;
2510+        this.node = node;
2511+        this.event = event;
2512+        this.paramList = paramList;
2513+    }
2514+   
2515+    public double evalTime()
2516+    {
2517+        return 0.0;
2518+    }
2519+   
2520+    public void setParentElement(AnimationElement ele)
2521+    {
2522+        parent = ele;
2523+    }
2524+}
2525Index: core/src/com/kitfox/svg/animation/TimeSum.java
[4256]2526===================================================================
[5284]2527--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2528+++ core/src/com/kitfox/svg/animation/TimeSum.java      2012-06-17 23:56:57.684545050 +0200
2529@@ -0,0 +1,60 @@
2530+/*
2531+ * TimeDiscrete.java
2532+ *
2533+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2534+ *  Copyright (C) 2004 Mark McKay
2535+ *
2536+ *  This library is free software; you can redistribute it and/or
2537+ *  modify it under the terms of the GNU Lesser General Public
2538+ *  License as published by the Free Software Foundation; either
2539+ *  version 2.1 of the License, or (at your option) any later version.
2540+ *
2541+ *  This library is distributed in the hope that it will be useful,
2542+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2543+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2544+ *  Lesser General Public License for more details.
2545+ *
2546+ *  You should have received a copy of the GNU Lesser General Public
2547+ *  License along with this library; if not, write to the Free Software
2548+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2549+ *
2550+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2551+ *  projects can be found at http://www.kitfox.com
2552+ *
2553+ * Created on August 15, 2004, 3:33 AM
2554+ */
2555+
2556+package com.kitfox.svg.animation;
2557+
2558+/**
2559+ * This is a time that represents a specific number of milliseconds
2560+ *
2561+ * @author Mark McKay
2562+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2563+ */
2564+public class TimeSum extends TimeBase
2565+{
2566+    //Milliseconds of delay
2567+    TimeBase t1;
2568+    TimeBase t2;
2569+    boolean add;
2570+   
2571+    /** Creates a new instance of TimeDiscrete */
2572+    public TimeSum(TimeBase t1, TimeBase t2, boolean add)
2573+    {
2574+        this.t1 = t1;
2575+        this.t2 = t2;
2576+        this.add = add;
2577+    }
2578+   
2579+    public double evalTime()
2580+    {
2581+        return add ? t1.evalTime() + t2.evalTime() : t1.evalTime() - t2.evalTime();
2582+    }
2583+   
2584+    public void setParentElement(AnimationElement ele)
2585+    {
2586+        t1.setParentElement(ele);
2587+        t2.setParentElement(ele);
2588+    }
2589+}
2590Index: core/src/com/kitfox/svg/animation/TrackBase.java
[4256]2591===================================================================
[5284]2592--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2593+++ core/src/com/kitfox/svg/animation/TrackBase.java    2012-06-17 23:56:57.684545050 +0200
2594@@ -0,0 +1,103 @@
2595+/*
2596+ * TrackManager.java
2597+ *
2598+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2599+ *  Copyright (C) 2004 Mark McKay
2600+ *
2601+ *  This library is free software; you can redistribute it and/or
2602+ *  modify it under the terms of the GNU Lesser General Public
2603+ *  License as published by the Free Software Foundation; either
2604+ *  version 2.1 of the License, or (at your option) any later version.
2605+ *
2606+ *  This library is distributed in the hope that it will be useful,
2607+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2608+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2609+ *  Lesser General Public License for more details.
2610+ *
2611+ *  You should have received a copy of the GNU Lesser General Public
2612+ *  License along with this library; if not, write to the Free Software
2613+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2614+ *
2615+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2616+ *  projects can be found at http://www.kitfox.com
2617+ *
2618+ * Created on August 15, 2004, 11:34 PM
2619+ */
2620+
2621+package com.kitfox.svg.animation;
2622+
2623+import java.util.*;
2624+
2625+import com.kitfox.svg.xml.*;
2626+import com.kitfox.svg.*;
2627+
2628+/**
2629+ * A track holds the animation events for a single parameter of a single SVG
2630+ * element.  It also contains the default value for the element, should the
2631+ * user want to see the 'unanimated' value.
2632+ *
2633+ * @author Mark McKay
2634+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2635+ */
2636+abstract public class TrackBase
2637+{
2638+    protected final String attribName;
2639+    protected final int attribType;  //AnimationElement.AT_*
2640+
2641+    /** Element we're animating */
2642+    protected final SVGElement parent;
2643+   
2644+    //It doesn't make sense to sort this, since some events will depend on
2645+    // other events - in many cases, there will be no meaningful sorted order.
2646+    final ArrayList animEvents = new ArrayList();
2647+   
2648+    /** Creates a new instance of TrackManager */
2649+//    public TrackBase(SVGElement parent)
2650+//    {
2651+//        this(parent, "", AnimationElement.AT_AUTO);
2652+//    }
2653+   
2654+    /**
2655+     * Creates a track that would be valid for the name and type of element
2656+     * passed in.  Does not actually add this elemnt to the track.
2657+     */
2658+    public TrackBase(SVGElement parent, AnimationElement ele) throws SVGElementException
2659+    {
2660+        this(parent, ele.getAttribName(), ele.getAttribType());
2661+    }
2662+   
2663+    public TrackBase(SVGElement parent, String attribName, int attribType) throws SVGElementException
2664+    {
2665+        this.parent = parent;
2666+        this.attribName = attribName;
2667+        this.attribType = attribType;
2668+       
2669+        //Make sure parent has an attribute we will write to
2670+        if (attribType == AnimationElement.AT_AUTO
2671+            && !parent.hasAttribute(attribName, AnimationElement.AT_CSS)
2672+            && !parent.hasAttribute(attribName, AnimationElement.AT_XML))
2673+        {
2674+            parent.addAttribute(attribName, AnimationElement.AT_CSS, "");
2675+        }
2676+        else if (!parent.hasAttribute(attribName, attribType))
2677+        {
2678+            parent.addAttribute(attribName, attribType, "");
2679+        }
2680+    }
2681+   
2682+    public String getAttribName() { return attribName; }
2683+    public int getAttribType() { return attribType; }
2684+   
2685+    public void addElement(AnimationElement ele)
2686+    {
2687+        animEvents.add(ele);
2688+    }
2689+   
2690+    /**
2691+     * Returns a StyleAttribute representing the value of this track at the
2692+     * passed time.  If this track does not apply, returns null.
2693+     * @return - True if successful, false if a value could not be obtained
2694+     */
2695+    abstract public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException;
2696+   
2697+}
2698Index: core/src/com/kitfox/svg/animation/TrackColor.java
[4256]2699===================================================================
[5284]2700--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2701+++ core/src/com/kitfox/svg/animation/TrackColor.java   2012-06-17 23:56:57.684545050 +0200
2702@@ -0,0 +1,95 @@
2703+/*
2704+ * TrackManager.java
2705+ *
2706+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2707+ *  Copyright (C) 2004 Mark McKay
2708+ *
2709+ *  This library is free software; you can redistribute it and/or
2710+ *  modify it under the terms of the GNU Lesser General Public
2711+ *  License as published by the Free Software Foundation; either
2712+ *  version 2.1 of the License, or (at your option) any later version.
2713+ *
2714+ *  This library is distributed in the hope that it will be useful,
2715+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2716+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2717+ *  Lesser General Public License for more details.
2718+ *
2719+ *  You should have received a copy of the GNU Lesser General Public
2720+ *  License along with this library; if not, write to the Free Software
2721+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2722+ *
2723+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2724+ *  projects can be found at http://www.kitfox.com
2725+ *
2726+ * Created on September 21, 2004, 11:34 PM
2727+ */
2728+
2729+package com.kitfox.svg.animation;
2730+
2731+import com.kitfox.svg.xml.StyleAttribute;
2732+import java.awt.*;
2733+import java.util.*;
2734+
2735+import com.kitfox.svg.*;
2736+import com.kitfox.svg.xml.*;
2737+
2738+/**
2739+ * A track holds the animation events for a single parameter of a single SVG
2740+ * element.  It also contains the default value for the element, should the
2741+ * user want to see the 'unanimated' value.
2742+ *
2743+ * @author Mark McKay
2744+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2745+ */
2746+public class TrackColor extends TrackBase
2747+{
2748+
2749+    public TrackColor(AnimationElement ele) throws SVGElementException
2750+    {
2751+        super(ele.getParent(), ele);
2752+    }
2753+
2754+    public boolean getValue(StyleAttribute attrib, double curTime)
2755+    {
2756+        Color col = getValue(curTime);
2757+        if (col == null) return false;
2758+
2759+        attrib.setStringValue("#" + Integer.toHexString(col.getRGB()));
2760+        return true;
2761+    }
2762+
2763+    public Color getValue(double curTime)
2764+    {
2765+        Color retVal = null;
2766+        AnimationTimeEval state = new AnimationTimeEval();
2767+
2768+        for (Iterator it = animEvents.iterator(); it.hasNext();)
2769+        {
2770+            AnimateBase ele = (AnimateBase)it.next();
2771+            AnimateColorIface eleColor = (AnimateColorIface)ele;
2772+            ele.evalParametric(state, curTime);
2773+
2774+            //Reject value if it is in the invalid state
2775+            if (Double.isNaN(state.interp)) continue;
2776+
2777+            if (retVal == null)
2778+            {
2779+                retVal = eleColor.evalColor(state.interp);
2780+                continue;
2781+            }
2782+           
2783+            Color curCol = eleColor.evalColor(state.interp);
2784+            switch (ele.getAdditiveType())
2785+            {
2786+                case AnimationElement.AD_REPLACE:
2787+                    retVal = curCol;
2788+                    break;
2789+                case AnimationElement.AD_SUM:
2790+                    retVal = new Color(curCol.getRed() + retVal.getRed(), curCol.getGreen() + retVal.getGreen(), curCol.getBlue() + retVal.getBlue());
2791+                    break;
2792+            }
2793+        }
2794+
2795+        return retVal;
2796+    }
2797+}
2798Index: core/src/com/kitfox/svg/animation/TrackDouble.java
[4256]2799===================================================================
[5284]2800--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2801+++ core/src/com/kitfox/svg/animation/TrackDouble.java  2012-06-17 23:56:57.684545050 +0200
2802@@ -0,0 +1,119 @@
2803+/*
2804+ * TrackManager.java
2805+ *
2806+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2807+ *  Copyright (C) 2004 Mark McKay
2808+ *
2809+ *  This library is free software; you can redistribute it and/or
2810+ *  modify it under the terms of the GNU Lesser General Public
2811+ *  License as published by the Free Software Foundation; either
2812+ *  version 2.1 of the License, or (at your option) any later version.
2813+ *
2814+ *  This library is distributed in the hope that it will be useful,
2815+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2816+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2817+ *  Lesser General Public License for more details.
2818+ *
2819+ *  You should have received a copy of the GNU Lesser General Public
2820+ *  License along with this library; if not, write to the Free Software
2821+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2822+ *
2823+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2824+ *  projects can be found at http://www.kitfox.com
2825+ *
2826+ * Created on August 15, 2004, 11:34 PM
2827+ */
2828+
2829+package com.kitfox.svg.animation;
2830+
2831+import com.kitfox.svg.xml.StyleAttribute;
2832+import java.util.*;
2833+
2834+import com.kitfox.svg.*;
2835+import com.kitfox.svg.xml.*;
2836+
2837+/**
2838+ * A track holds the animation events for a single parameter of a single SVG
2839+ * element.  It also contains the default value for the element, should the
2840+ * user want to see the 'unanimated' value.
2841+ *
2842+ * @author Mark McKay
2843+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2844+ */
2845+public class TrackDouble extends TrackBase
2846+{
2847+    public TrackDouble(AnimationElement ele) throws SVGElementException
2848+    {
2849+        super(ele.getParent(), ele);
2850+    }
2851+
2852+    public boolean getValue(StyleAttribute attrib, double curTime)
2853+    {
2854+        double val = getValue(curTime);
2855+        if (Double.isNaN(val)) return false;
2856+
2857+        attrib.setStringValue("" + val);
2858+        return true;
2859+    }
2860+
2861+    public double getValue(double curTime)
2862+    {
2863+        double retVal = Double.NaN;
2864+       
2865+        StyleAttribute attr = null;
2866+        switch (attribType)
2867+        {
2868+            case AnimationElement.AT_CSS:
2869+                attr = parent.getStyleAbsolute(attribName);
2870+                retVal = attr.getDoubleValue();
2871+                break;
2872+            case AnimationElement.AT_XML:
2873+                attr = parent.getPresAbsolute(attribName);
2874+                retVal = attr.getDoubleValue();
2875+                break;
2876+            case AnimationElement.AT_AUTO:
2877+                attr = parent.getStyleAbsolute(attribName);
2878+                if (attr == null) attr = parent.getPresAbsolute(attribName);
2879+                retVal = attr.getDoubleValue();
2880+                break;
2881+        }
2882+       
2883+       
2884+       
2885+        AnimationTimeEval state = new AnimationTimeEval();
2886+//        boolean pastEnd = true;
2887+
2888+        for (Iterator it = animEvents.iterator(); it.hasNext();)
2889+        {
2890+            Animate ele = (Animate)it.next();
2891+            ele.evalParametric(state, curTime);
2892+
2893+            //Go to next element if this one does not affect processing
2894+            if (Double.isNaN(state.interp)) continue;
2895+
2896+            switch (ele.getAdditiveType())
2897+            {
2898+                case AnimationElement.AD_SUM:
2899+                    retVal += ele.eval(state.interp);
2900+                    break;
2901+                case AnimationElement.AD_REPLACE:
2902+                    retVal = ele.eval(state.interp);
2903+                    break;
2904+            }
2905+           
2906+            //Evalutae accumulation if applicable
2907+            if (state.rep > 0)
2908+            {
2909+                switch (ele.getAccumulateType())
2910+                {
2911+                    case AnimationElement.AC_SUM:
2912+                        retVal += ele.repeatSkipSize(state.rep);
2913+                        break;
2914+                }
2915+               
2916+            }
2917+        }
2918+
2919+        return retVal;
2920+    }
2921+}
2922Index: core/src/com/kitfox/svg/animation/TrackManager.java
[4256]2923===================================================================
[5284]2924--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2925+++ core/src/com/kitfox/svg/animation/TrackManager.java 2012-06-17 23:56:57.684545050 +0200
2926@@ -0,0 +1,153 @@
2927+/*
2928+ * TrackManager.java
2929+ *
2930+ *  The Salamander Project - 2D and 3D graphics libraries in Java
2931+ *  Copyright (C) 2004 Mark McKay
2932+ *
2933+ *  This library is free software; you can redistribute it and/or
2934+ *  modify it under the terms of the GNU Lesser General Public
2935+ *  License as published by the Free Software Foundation; either
2936+ *  version 2.1 of the License, or (at your option) any later version.
2937+ *
2938+ *  This library is distributed in the hope that it will be useful,
2939+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2940+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2941+ *  Lesser General Public License for more details.
2942+ *
2943+ *  You should have received a copy of the GNU Lesser General Public
2944+ *  License along with this library; if not, write to the Free Software
2945+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2946+ *
2947+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
2948+ *  projects can be found at http://www.kitfox.com
2949+ *
2950+ * Created on August 15, 2004, 11:34 PM
2951+ */
2952+
2953+package com.kitfox.svg.animation;
2954+
2955+import java.util.*;
2956+
2957+import com.kitfox.svg.*;
2958+import java.io.Serializable;
2959+
2960+/**
2961+ * Every element contains tracks, which manage the animation.  There is one track
2962+ * for every parameter with animation, and each track in turn is composed of
2963+ * many events.
2964+ *
2965+ * @author Mark McKay
2966+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
2967+ */
2968+public class TrackManager implements Serializable
2969+{
2970+    public static final long serialVersionUID = 0;
2971+   
2972+    static class TrackKey
2973+    {
2974+        String name;
2975+        int type;
2976+       
2977+        TrackKey(AnimationElement base)
2978+        {
2979+            this(base.getAttribName(), base.getAttribType());
2980+        }
2981+       
2982+        TrackKey(String name, int type)
2983+        {
2984+            this.name = name;
2985+            this.type = type;
2986+        }
2987+       
2988+        public int hashCode() { return name.hashCode() ^ type; }
2989+        public boolean equals(Object obj)
2990+        {
2991+            if (!(obj instanceof TrackKey)) return false;
2992+            TrackKey key = (TrackKey)obj;
2993+            return key.type == type && key.name.equals(name);
2994+        }
2995+    }
2996+   
2997+    HashMap tracks = new HashMap();
2998+   
2999+    /** Creates a new instance of TrackManager */
3000+    public TrackManager()
3001+    {
3002+    }
3003+   
3004+    /**
3005+     * Adds a new animation element to this track
3006+     */
3007+    public void addTrackElement(AnimationElement element) throws SVGElementException
3008+    {
3009+        TrackKey key = new TrackKey(element);
3010+       
3011+        TrackBase track = (TrackBase)tracks.get(key);
3012+       
3013+        if (track == null)
3014+        {
3015+            //Create a track for this element
3016+            if (element instanceof Animate)
3017+            {
3018+                switch (((Animate)element).getDataType())
3019+                {
3020+                    case Animate.DT_REAL:
3021+                        track = new TrackDouble(element);
3022+                        break;
3023+                    case Animate.DT_COLOR:
3024+                        track = new TrackColor(element);
3025+                        break;
3026+                    case Animate.DT_PATH:
3027+                        track = new TrackPath(element);
3028+                        break;
3029+                    default:
3030+                        throw new RuntimeException("");
3031+                }
3032+            }
3033+            else if (element instanceof AnimateColor)
3034+            {
3035+                track = new TrackColor(element);
3036+            }
3037+            else if (element instanceof AnimateTransform || element instanceof AnimateMotion)
3038+            {
3039+                track = new TrackTransform(element);
3040+            }
3041+           
3042+            tracks.put(key, track);
3043+        }
3044
3045+        track.addElement(element);
3046+    }
3047+   
3048+    public TrackBase getTrack(String name, int type)
3049+    {
3050+        //Handle AUTO, which will match either CSS or XML (in that order)
3051+        if (type == AnimationElement.AT_AUTO)
3052+        {
3053+            TrackBase t = getTrack(name, AnimationElement.AT_CSS);
3054+            if (t != null) return t;
3055+            t = getTrack(name, AnimationElement.AT_XML);
3056+            if (t != null) return t;
3057+            return null;
3058+        }
3059+       
3060+        //Get requested attribute
3061+        TrackKey key = new TrackKey(name, type);
3062+        TrackBase t = (TrackBase)tracks.get(key);
3063+        if (t != null) return t;
3064+       
3065+        //If that didn't exist, see if one exists of type AUTO
3066+        key = new TrackKey(name, AnimationElement.AT_AUTO);
3067+        return (TrackBase)tracks.get(key);
3068+    }
3069+   
3070+    public int getNumTracks()
3071+    {
3072+        return tracks.size();
3073+    }
3074+   
3075+    public Iterator iterator()
3076+    {
3077+        return tracks.values().iterator();
3078+    }
3079+}
3080Index: core/src/com/kitfox/svg/animation/TrackMotion.java
[4256]3081===================================================================
[5284]3082--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3083+++ core/src/com/kitfox/svg/animation/TrackMotion.java  2012-06-17 23:56:57.684545050 +0200
3084@@ -0,0 +1,128 @@
3085+/*
3086+ * TrackManager.java
3087+ *
3088+ *  The Salamander Project - 2D and 3D graphics libraries in Java
3089+ *  Copyright (C) 2004 Mark McKay
3090+ *
3091+ *  This library is free software; you can redistribute it and/or
3092+ *  modify it under the terms of the GNU Lesser General Public
3093+ *  License as published by the Free Software Foundation; either
3094+ *  version 2.1 of the License, or (at your option) any later version.
3095+ *
3096+ *  This library is distributed in the hope that it will be useful,
3097+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3098+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3099+ *  Lesser General Public License for more details.
3100+ *
3101+ *  You should have received a copy of the GNU Lesser General Public
3102+ *  License along with this library; if not, write to the Free Software
3103+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3104+ *
3105+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
3106+ *  projects can be found at http://www.kitfox.com
3107+ *
3108+ * Created on September 21, 2004, 11:34 PM
3109+ */
3110+
3111+package com.kitfox.svg.animation;
3112+
3113+import com.kitfox.svg.xml.StyleAttribute;
3114+import java.awt.geom.*;
3115+import java.util.*;
3116+
3117+import com.kitfox.svg.*;
3118+import com.kitfox.svg.xml.*;
3119+
3120+/**
3121+ * A track holds the animation events for a single parameter of a single SVG
3122+ * element.  It also contains the default value for the element, should the
3123+ * user want to see the 'unanimated' value.
3124+ *
3125+ * @author Mark McKay
3126+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
3127+ */
3128+public class TrackMotion extends TrackBase
3129+{
3130+    public TrackMotion(AnimationElement ele) throws SVGElementException
3131+    {
3132+        //The motion element implies a CSS attribute of transform
3133+//        super(ele.getParent(), "transform", AnimationElement.AT_CSS);
3134+        super(ele.getParent(), ele);
3135+    }
3136+
3137+    public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException
3138+    {
3139+        AffineTransform retVal = new AffineTransform();
3140+        retVal = getValue(retVal, curTime);
3141+//        AffineTransform val = getValue(curTime);
3142+//        if (val == null) return false;
3143+
3144+        double[] mat = new double[6];
3145+        retVal.getMatrix(mat);
3146+        attrib.setStringValue("matrix(" + mat[0] + " " + mat[1] + " " + mat[2] + " " + mat[3] + " " + mat[4] + " " + mat[5] + ")");
3147+        return true;
3148+    }
3149+
3150+    public AffineTransform getValue(AffineTransform retVal, double curTime) throws SVGException
3151+    {
3152+        //Init transform with default state
3153+        StyleAttribute attr = null;
3154+        switch (attribType)
3155+        {
3156+            case AnimationElement.AT_CSS:
3157+                attr = parent.getStyleAbsolute(attribName);
3158+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3159+                break;
3160+            case AnimationElement.AT_XML:
3161+                attr = parent.getPresAbsolute(attribName);
3162+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3163+                break;
3164+            case AnimationElement.AT_AUTO:
3165+                attr = parent.getStyleAbsolute(attribName);
3166+                if (attr == null) attr = parent.getPresAbsolute(attribName);
3167+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3168+                break;
3169+        }
3170+
3171+
3172+        //Update transform with time based information
3173+        AnimationTimeEval state = new AnimationTimeEval();
3174+        AffineTransform xform = new AffineTransform();
3175+//        boolean pastEnd = true;
3176+
3177+        for (Iterator it = animEvents.iterator(); it.hasNext();)
3178+        {
3179+            AnimateMotion ele = (AnimateMotion)it.next();
3180+            ele.evalParametric(state, curTime);
3181+
3182+            //Go to next element if this one does not affect processing
3183+            if (Double.isNaN(state.interp)) continue;
3184+
3185+            switch (ele.getAdditiveType())
3186+            {
3187+                case AnimationElement.AD_SUM:
3188+                    retVal.concatenate(ele.eval(xform, state.interp));
3189+                    break;
3190+                case AnimationElement.AD_REPLACE:
3191+                    retVal.setTransform(ele.eval(xform, state.interp));
3192+                    break;
3193+            }
3194+
3195+            //Evaluate accumulation if applicable
3196+/*
3197+            if (state.rep > 0)
3198+            {
3199+                switch (ele.getAccumulateType())
3200+                {
3201+                    case AnimationElement.AC_SUM:
3202+                        retVal += ele.repeatSkipSize(state.rep);
3203+                        break;
3204+                }
3205+
3206+            }
3207+*/
3208+        }
3209+
3210+        return retVal;
3211+    }
3212+}
3213Index: core/src/com/kitfox/svg/animation/TrackPath.java
[4256]3214===================================================================
[5284]3215--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3216+++ core/src/com/kitfox/svg/animation/TrackPath.java    2012-06-17 23:56:57.684545050 +0200
3217@@ -0,0 +1,100 @@
3218+/*
3219+ * TrackManager.java
3220+ *
3221+ *  The Salamander Project - 2D and 3D graphics libraries in Java
3222+ *  Copyright (C) 2004 Mark McKay
3223+ *
3224+ *  This library is free software; you can redistribute it and/or
3225+ *  modify it under the terms of the GNU Lesser General Public
3226+ *  License as published by the Free Software Foundation; either
3227+ *  version 2.1 of the License, or (at your option) any later version.
3228+ *
3229+ *  This library is distributed in the hope that it will be useful,
3230+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3231+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3232+ *  Lesser General Public License for more details.
3233+ *
3234+ *  You should have received a copy of the GNU Lesser General Public
3235+ *  License along with this library; if not, write to the Free Software
3236+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3237+ *
3238+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
3239+ *  projects can be found at http://www.kitfox.com
3240+ *
3241+ * Created on September 21, 2004, 11:34 PM
3242+ */
3243+
3244+package com.kitfox.svg.animation;
3245+
3246+import com.kitfox.svg.xml.StyleAttribute;
3247+import java.awt.*;
3248+import java.awt.geom.*;
3249+import java.util.*;
3250+
3251+import com.kitfox.svg.pathcmd.*;
3252+import com.kitfox.svg.*;
3253+import com.kitfox.svg.xml.*;
3254+
3255+/**
3256+ * A track holds the animation events for a single parameter of a single SVG
3257+ * element.  It also contains the default value for the element, should the
3258+ * user want to see the 'unanimated' value.
3259+ *
3260+ * @author Mark McKay
3261+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
3262+ */
3263+public class TrackPath extends TrackBase
3264+{
3265+
3266+    public TrackPath(AnimationElement ele) throws SVGElementException
3267+    {
3268+        super(ele.getParent(), ele);
3269+    }
3270+
3271+    public boolean getValue(StyleAttribute attrib, double curTime)
3272+    {
3273+        GeneralPath path = getValue(curTime);
3274+        if (path == null) return false;
3275+
3276+        attrib.setStringValue(PathUtil.buildPathString(path));
3277+        return true;
3278+    }
3279+
3280+    public GeneralPath getValue(double curTime)
3281+    {
3282+        GeneralPath retVal = null;
3283+        AnimationTimeEval state = new AnimationTimeEval();
3284+
3285+        for (Iterator it = animEvents.iterator(); it.hasNext();)
3286+        {
3287+            AnimateBase ele = (AnimateBase)it.next();
3288+            Animate eleAnim = (Animate)ele;
3289+            ele.evalParametric(state, curTime);
3290+
3291+            //Reject value if it is in the invalid state
3292+            if (Double.isNaN(state.interp)) continue;
3293+
3294+            if (retVal == null)
3295+            {
3296+                retVal = eleAnim.evalPath(state.interp);
3297+                continue;
3298+            }
3299+           
3300+            GeneralPath curPath = eleAnim.evalPath(state.interp);
3301+            switch (ele.getAdditiveType())
3302+            {
3303+                case AnimationElement.AD_REPLACE:
3304+                    retVal = curPath;
3305+                    break;
3306+                case AnimationElement.AD_SUM:
3307+                    throw new RuntimeException("Not implemented");
3308+//                    retVal = new Color(curCol.getRed() + retVal.getRed(), curCol.getGreen() + retVal.getGreen(), curCol.getBlue() + retVal.getBlue());
3309+//                    break;
3310+                default:
3311+                    throw new RuntimeException();
3312+            }
3313+        }
3314+
3315+        return retVal;
3316+    }
3317+}
3318Index: core/src/com/kitfox/svg/animation/TrackTransform.java
[4256]3319===================================================================
[5284]3320--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3321+++ core/src/com/kitfox/svg/animation/TrackTransform.java       2012-06-17 23:56:57.684545050 +0200
3322@@ -0,0 +1,112 @@
3323+/*
3324+ * TrackManager.java
3325+ *
3326+ *  The Salamander Project - 2D and 3D graphics libraries in Java
3327+ *  Copyright (C) 2004 Mark McKay
3328+ *
3329+ *  This library is free software; you can redistribute it and/or
3330+ *  modify it under the terms of the GNU Lesser General Public
3331+ *  License as published by the Free Software Foundation; either
3332+ *  version 2.1 of the License, or (at your option) any later version.
3333+ *
3334+ *  This library is distributed in the hope that it will be useful,
3335+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3336+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3337+ *  Lesser General Public License for more details.
3338+ *
3339+ *  You should have received a copy of the GNU Lesser General Public
3340+ *  License along with this library; if not, write to the Free Software
3341+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3342+ *
3343+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
3344+ *  projects can be found at http://www.kitfox.com
3345+ *
3346+ * Created on September 21, 2004, 11:34 PM
3347+ */
3348+
3349+package com.kitfox.svg.animation;
3350+
3351+import com.kitfox.svg.xml.StyleAttribute;
3352+import java.awt.geom.*;
3353+import java.util.*;
3354+
3355+import com.kitfox.svg.*;
3356+import com.kitfox.svg.xml.*;
3357+
3358+/**
3359+ * A track holds the animation events for a single parameter of a single SVG
3360+ * element.  It also contains the default value for the element, should the
3361+ * user want to see the 'unanimated' value.
3362+ *
3363+ * @author Mark McKay
3364+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
3365+ */
3366+public class TrackTransform extends TrackBase
3367+{
3368+    public TrackTransform(AnimationElement ele) throws SVGElementException
3369+    {
3370+        super(ele.getParent(), ele);
3371+    }
3372+
3373+    public boolean getValue(StyleAttribute attrib, double curTime) throws SVGException
3374+    {
3375+        AffineTransform retVal = new AffineTransform();
3376+        retVal = getValue(retVal, curTime);
3377+//        AffineTransform val = getValue(curTime);
3378+//        if (val == null) return false;
3379+
3380+        double[] mat = new double[6];
3381+        retVal.getMatrix(mat);
3382+        attrib.setStringValue("matrix(" + mat[0] + " " + mat[1] + " " + mat[2] + " " + mat[3] + " " + mat[4] + " " + mat[5] + ")");
3383+        return true;
3384+    }
3385+
3386+    public AffineTransform getValue(AffineTransform retVal, double curTime) throws SVGException
3387+    {
3388+        //Init transform with default state
3389+        StyleAttribute attr = null;
3390+        switch (attribType)
3391+        {
3392+            case AnimationElement.AT_CSS:
3393+                attr = parent.getStyleAbsolute(attribName);
3394+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3395+                break;
3396+            case AnimationElement.AT_XML:
3397+                attr = parent.getPresAbsolute(attribName);
3398+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3399+                break;
3400+            case AnimationElement.AT_AUTO:
3401+                attr = parent.getStyleAbsolute(attribName);
3402+                if (attr == null) attr = parent.getPresAbsolute(attribName);
3403+                retVal.setTransform(SVGElement.parseSingleTransform(attr.getStringValue()));
3404+                break;
3405+        }
3406+
3407+
3408+        //Update transform with time based information
3409+        AnimationTimeEval state = new AnimationTimeEval();
3410+        AffineTransform xform = new AffineTransform();
3411+
3412+        for (Iterator it = animEvents.iterator(); it.hasNext();)
3413+        {
3414+            AnimateXform ele = (AnimateXform)it.next();
3415+            ele.evalParametric(state, curTime);
3416+
3417+            //Go to next element if this one does not affect processing
3418+            if (Double.isNaN(state.interp)) continue;
3419+
3420+            switch (ele.getAdditiveType())
3421+            {
3422+                case AnimationElement.AD_SUM:
3423+                    retVal.concatenate(ele.eval(xform, state.interp));
3424+                    break;
3425+                case AnimationElement.AD_REPLACE:
3426+                    retVal.setTransform(ele.eval(xform, state.interp));
3427+                    break;
3428+            }
3429+
3430+        }
3431+
3432+        return retVal;
3433+    }
3434+}
3435Index: core/src/com/kitfox/svg/SVGElement.java
[4256]3436===================================================================
[5284]3437--- core.orig/src/com/kitfox/svg/SVGElement.java        2012-05-11 17:03:52.404311564 +0200
3438+++ core/src/com/kitfox/svg/SVGElement.java     2012-06-17 23:56:57.732545052 +0200
3439@@ -33,6 +33,7 @@
[4256]3440 import java.awt.geom.*;
3441 
3442 import org.xml.sax.*;
[5284]3443+import com.kitfox.svg.animation.*;
[4256]3444 import com.kitfox.svg.pathcmd.*;
3445 import com.kitfox.svg.xml.*;
3446 import java.io.Serializable;
[5284]3447@@ -100,6 +101,8 @@
[4256]3448      */
3449 //    protected SVGUniverse universe;
3450     
[5284]3451+    protected final TrackManager trackManager = new TrackManager();
3452+
[4256]3453     boolean dirty = true;
3454 
3455 //    public static final Matcher adobeId = Pattern.compile("(.*)_1_").matcher("");
[5284]3456@@ -265,6 +268,46 @@
[4256]3457         }
3458     }
3459     
[5284]3460+    public void addAttribute(String name, int attribType, String value) throws SVGElementException
3461+    {
3462+        if (hasAttribute(name, attribType)) throw new SVGElementException(this, "Attribute " + name + "(" + AnimationElement.animationElementToString(attribType) + ") already exists");
3463+       
3464+        //Alter layout for id attribute
3465+        if ("id".equals(name) && diagram != null)
3466+        {
3467+            diagram.removeElement(this.id);
3468+            this.id = name;
3469+            diagram.setElement(this.id, this);
3470+        }
3471+       
3472+        switch (attribType)
3473+        {
3474+            case AnimationElement.AT_CSS:
3475+                inlineStyles.put(name, new StyleAttribute(name, value));
3476+                return;
3477+            case AnimationElement.AT_XML:
3478+                presAttribs.put(name, new StyleAttribute(name, value));
3479+                return;
3480+        }
3481+       
3482+        throw new SVGElementException(this, "Invalid attribute type " + attribType);
3483+    }
3484+   
3485+    public boolean hasAttribute(String name, int attribType) throws SVGElementException
3486+    {
3487+        switch (attribType)
3488+        {
3489+            case AnimationElement.AT_CSS:
3490+                return inlineStyles.containsKey(name);
3491+            case AnimationElement.AT_XML:
3492+                return presAttribs.containsKey(name);
3493+            case AnimationElement.AT_AUTO:
3494+                return inlineStyles.containsKey(name) || presAttribs.containsKey(name);
3495+        }
3496+       
3497+        throw new SVGElementException(this, "Invalid attribute type " + attribType);
3498+    }
3499+   
[4256]3500     /**
3501      * @return a set of Strings that corespond to CSS attributes on this element
3502      */
[5284]3503@@ -290,6 +333,12 @@
[4256]3504         children.add(child);
3505         child.parent = this;
3506         child.setDiagram(diagram);
[5284]3507+       
3508+        //Add info to track if we've scanned animation element
3509+        if (child instanceof AnimationElement)
3510+        {
3511+            trackManager.addTrackElement((AnimationElement)child);
3512+        }
[4256]3513     }
3514     
3515     private void setDiagram(SVGDiagram diagram)
[5284]3516@@ -408,6 +457,54 @@
[4256]3517         return getStyle(attrib, true);
3518     }
3519     
[5284]3520+   
3521+    public void setAttribute(String name, int attribType, String value) throws SVGElementException
3522+    {
3523+        StyleAttribute styAttr;
3524+       
3525+       
3526+        switch (attribType)
3527+        {
3528+            case AnimationElement.AT_CSS:
3529+            {
3530+                styAttr = (StyleAttribute)inlineStyles.get(name);
3531+                break;
3532+            }
3533+            case AnimationElement.AT_XML:
3534+            {
3535+                styAttr = (StyleAttribute)presAttribs.get(name);
3536+                break;
3537+            }
3538+            case AnimationElement.AT_AUTO:
3539+            {
3540+                styAttr = (StyleAttribute)inlineStyles.get(name);
3541+               
3542+                if (styAttr == null)
3543+                {
3544+                    styAttr = (StyleAttribute)presAttribs.get(name);
3545+                }
3546+                break;
3547+            }
3548+            default:
3549+                throw new SVGElementException(this, "Invalid attribute type " + attribType);
3550+        }
3551+       
3552+        if (styAttr == null)
3553+        {
3554+            throw new SVGElementException(this, "Could not find attribute " + name + "(" + AnimationElement.animationElementToString(attribType) + ").  Make sure to create attribute before setting it.");
3555+        }
3556+       
3557+        //Alter layout for relevant attributes
3558+        if ("id".equals(styAttr.getName()))
3559+        {
3560+            diagram.removeElement(this.id);
3561+            this.id = name;
3562+            diagram.setElement(this.id, this);
3563+        }
3564+       
3565+        styAttr.setStringValue(value);
3566+    }
3567+   
[4256]3568     /**
3569      * Copies the current style into the passed style attribute.  Checks for
3570      * inline styles first, then internal and extranal style sheets, and
[5284]3571@@ -427,6 +524,14 @@
[4256]3572         
3573         attrib.setStringValue(styAttr == null ? "" : styAttr.getStringValue());
3574         
[5284]3575+        //Evalutate coresponding track, if one exists
3576+        TrackBase track = trackManager.getTrack(styName, AnimationElement.AT_CSS);
3577+        if (track != null)
3578+        {
3579+            track.getValue(attrib, diagram.getUniverse().getCurTime());
3580+            return true;
3581+        }
3582+       
[4256]3583         //Return if we've found a non animated style
3584         if (styAttr != null) return true;
3585         
[5284]3586@@ -439,6 +544,14 @@
[4256]3587         
3588         attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
3589         
[5284]3590+        //Evalutate coresponding track, if one exists
3591+        track = trackManager.getTrack(styName, AnimationElement.AT_XML);
3592+        if (track != null)
3593+        {
3594+            track.getValue(attrib, diagram.getUniverse().getCurTime());
3595+            return true;
3596+        }
3597+       
[4256]3598         //Return if we've found a presentation attribute instead
3599         if (presAttr != null) return true;
3600         
[5284]3601@@ -480,6 +593,14 @@
[4256]3602         //Copy presentation value directly
3603         attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
3604         
[5284]3605+        //Evalutate coresponding track, if one exists
3606+        TrackBase track = trackManager.getTrack(presName, AnimationElement.AT_XML);
3607+        if (track != null)
3608+        {
3609+            track.getValue(attrib, diagram.getUniverse().getCurTime());
3610+            return true;
3611+        }
3612+       
[4256]3613         //Return if we found presentation attribute
3614         if (presAttr != null) return true;
3615         
[5284]3616Index: core/src/com/kitfox/svg/SVGLoader.java
[4256]3617===================================================================
[5284]3618--- core.orig/src/com/kitfox/svg/SVGLoader.java 2012-05-11 17:03:52.404311564 +0200
3619+++ core/src/com/kitfox/svg/SVGLoader.java      2012-06-17 23:56:57.732545052 +0200
3620@@ -33,6 +33,8 @@
[4256]3621 import org.xml.sax.*;
3622 import org.xml.sax.helpers.DefaultHandler;
3623 
[5284]3624+import com.kitfox.svg.animation.*;
3625+
[4256]3626 /**
3627  * @author Mark McKay
3628  * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
[5284]3629@@ -75,6 +77,10 @@
[4256]3630 
3631         //Compile a list of important builder classes
3632         nodeClasses.put("a", A.class);
[5284]3633+        nodeClasses.put("animate", Animate.class);
3634+        nodeClasses.put("animatecolor", AnimateColor.class);
3635+        nodeClasses.put("animatemotion", AnimateMotion.class);
3636+        nodeClasses.put("animatetransform", AnimateTransform.class);
[4256]3637         nodeClasses.put("circle", Circle.class);
3638         nodeClasses.put("clippath", ClipPath.class);
3639         nodeClasses.put("defs", Defs.class);
[5284]3640@@ -98,6 +104,7 @@
[4256]3641         nodeClasses.put("polyline", Polyline.class);
3642         nodeClasses.put("radialgradient", RadialGradient.class);
3643         nodeClasses.put("rect", Rect.class);
[5284]3644+        nodeClasses.put("set", SetSmil.class);
[4256]3645         nodeClasses.put("shape", ShapeElement.class);
3646         nodeClasses.put("stop", Stop.class);
3647         nodeClasses.put("style", Style.class);
[5284]3648Index: core/src/com/kitfox/svg/SVGLoaderHelper.java
[4256]3649===================================================================
[5284]3650--- core.orig/src/com/kitfox/svg/SVGLoaderHelper.java   2012-05-11 17:03:52.404311564 +0200
3651+++ core/src/com/kitfox/svg/SVGLoaderHelper.java        2012-06-17 23:56:57.740545051 +0200
3652@@ -28,6 +28,9 @@
[4256]3653 package com.kitfox.svg;
3654 
3655 import java.net.*;
[5284]3656+import java.io.*;
3657+
3658+import com.kitfox.svg.animation.parser.*;
[4256]3659 
3660 /**
3661  * @author Mark McKay
[5284]3662@@ -47,6 +50,11 @@
[4256]3663 
3664     public final URI xmlBase;
3665 
[5284]3666+    /**
3667+     * Animate nodes use this to parse their time strings
3668+     */
3669+    public final AnimTimeParser animTimeParser = new AnimTimeParser(new StringReader(""));
3670+   
[4256]3671     /** Creates a new instance of SVGLoaderHelper */
3672     public SVGLoaderHelper(URI xmlBase, SVGUniverse universe, SVGDiagram diagram)
3673     {
[5284]3674Index: core/src/com/kitfox/svg/app/MainFrame.java
[4256]3675===================================================================
[5284]3676--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3677+++ core/src/com/kitfox/svg/app/MainFrame.java  2012-06-17 23:56:57.748545052 +0200
3678@@ -0,0 +1,134 @@
3679+/*
3680+ * MainFrame.java
3681+ *
3682+ * Created on September 6, 2004, 1:19 AM
3683+ */
3684+
3685+package com.kitfox.svg.app;
3686+
3687+/**
3688+ *
3689+ * @author  kitfox
3690+ */
3691+public class MainFrame extends javax.swing.JFrame
3692+{
3693+    public static final long serialVersionUID = 1;
3694+   
3695+    /** Creates new form MainFrame */
3696+    public MainFrame()
3697+    {
3698+        initComponents();
3699+    }
3700+   
3701+    /** This method is called from within the constructor to
3702+     * initialize the form.
3703+     * WARNING: Do NOT modify this code. The content of this method is
3704+     * always regenerated by the Form Editor.
3705+     */
3706+    private void initComponents()//GEN-BEGIN:initComponents
3707+    {
3708+        jPanel1 = new javax.swing.JPanel();
3709+        bn_svgViewer = new javax.swing.JButton();
3710+        bn_svgViewer1 = new javax.swing.JButton();
3711+        jPanel2 = new javax.swing.JPanel();
3712+        bn_quit = new javax.swing.JButton();
3713+
3714+        setTitle("SVG Salamander - Application Launcher");
3715+        addWindowListener(new java.awt.event.WindowAdapter()
3716+        {
3717+            public void windowClosing(java.awt.event.WindowEvent evt)
3718+            {
3719+                exitForm(evt);
3720+            }
3721+        });
3722+
3723+        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.Y_AXIS));
3724+
3725+        bn_svgViewer.setText("SVG Viewer (No animation)");
3726+        bn_svgViewer.addActionListener(new java.awt.event.ActionListener()
3727+        {
3728+            public void actionPerformed(java.awt.event.ActionEvent evt)
3729+            {
3730+                bn_svgViewerActionPerformed(evt);
3731+            }
3732+        });
3733+
3734+        jPanel1.add(bn_svgViewer);
3735+
3736+        bn_svgViewer1.setText("SVG Player (Animation)");
3737+        bn_svgViewer1.addActionListener(new java.awt.event.ActionListener()
3738+        {
3739+            public void actionPerformed(java.awt.event.ActionEvent evt)
3740+            {
3741+                bn_svgViewer1ActionPerformed(evt);
3742+            }
3743+        });
3744+
3745+        jPanel1.add(bn_svgViewer1);
3746+
3747+        getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
3748+
3749+        bn_quit.setText("Quit");
3750+        bn_quit.addActionListener(new java.awt.event.ActionListener()
3751+        {
3752+            public void actionPerformed(java.awt.event.ActionEvent evt)
3753+            {
3754+                bn_quitActionPerformed(evt);
3755+            }
3756+        });
3757+
3758+        jPanel2.add(bn_quit);
3759+
3760+        getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
3761+
3762+        pack();
3763+    }//GEN-END:initComponents
3764+
3765+    private void bn_svgViewer1ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_svgViewer1ActionPerformed
3766+    {//GEN-HEADEREND:event_bn_svgViewer1ActionPerformed
3767+        SVGPlayer.main(null);
3768+
3769+        close();
3770+    }//GEN-LAST:event_bn_svgViewer1ActionPerformed
3771+
3772+    private void bn_svgViewerActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_svgViewerActionPerformed
3773+    {//GEN-HEADEREND:event_bn_svgViewerActionPerformed
3774+        SVGViewer.main(null);
3775+
3776+        close();
3777+    }//GEN-LAST:event_bn_svgViewerActionPerformed
3778+
3779+    private void bn_quitActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_quitActionPerformed
3780+    {//GEN-HEADEREND:event_bn_quitActionPerformed
3781+        exitForm(null);
3782+    }//GEN-LAST:event_bn_quitActionPerformed
3783+   
3784+    /** Exit the Application */
3785+    private void exitForm(java.awt.event.WindowEvent evt)//GEN-FIRST:event_exitForm
3786+    {
3787+        System.exit(0);
3788+    }//GEN-LAST:event_exitForm
3789+   
3790+    private void close()
3791+    {
3792+        this.setVisible(false);
3793+        this.dispose();
3794+    }
3795+   
3796+    /**
3797+     * @param args the command line arguments
3798+     */
3799+    public static void main(String args[])
3800+    {
3801+        new MainFrame().setVisible(true);
3802+    }
3803+   
3804+    // Variables declaration - do not modify//GEN-BEGIN:variables
3805+    private javax.swing.JButton bn_quit;
3806+    private javax.swing.JButton bn_svgViewer;
3807+    private javax.swing.JButton bn_svgViewer1;
3808+    private javax.swing.JPanel jPanel1;
3809+    private javax.swing.JPanel jPanel2;
3810+    // End of variables declaration//GEN-END:variables
3811+   
3812+}
3813Index: core/src/com/kitfox/svg/app/PlayerDialog.java
[4256]3814===================================================================
[5284]3815--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3816+++ core/src/com/kitfox/svg/app/PlayerDialog.java       2012-06-17 23:56:57.748545052 +0200
3817@@ -0,0 +1,289 @@
3818+/*
3819+ * PlayerDialog.java
3820+ *
3821+ *
3822+ *  The Salamander Project - 2D and 3D graphics libraries in Java
3823+ *  Copyright (C) 2004 Mark McKay
3824+ *
3825+ *  This library is free software; you can redistribute it and/or
3826+ *  modify it under the terms of the GNU Lesser General Public
3827+ *  License as published by the Free Software Foundation; either
3828+ *  version 2.1 of the License, or (at your option) any later version.
3829+ *
3830+ *  This library is distributed in the hope that it will be useful,
3831+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
3832+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3833+ *  Lesser General Public License for more details.
3834+ *
3835+ *  You should have received a copy of the GNU Lesser General Public
3836+ *  License along with this library; if not, write to the Free Software
3837+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3838+ *
3839+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
3840+ *  projects can be found at http://www.kitfox.com
3841+ *
3842+ * Created on September 28, 2004, 9:56 PM
3843+ */
3844+
3845+package com.kitfox.svg.app;
3846+
3847+/**
3848+ *
3849+ * @author  kitfox
3850+ */
3851+public class PlayerDialog extends javax.swing.JDialog implements PlayerThreadListener
3852+{
3853+    public static final long serialVersionUID = 1;
3854+   
3855+    PlayerThread thread;
3856+   
3857+    final SVGPlayer parent;
3858+   
3859+    /** Creates new form PlayerDialog */
3860+    public PlayerDialog(SVGPlayer parent)
3861+    {
3862+        super(parent, false);
3863+        initComponents();
3864+       
3865+        this.parent = parent;
3866+       
3867+        thread = new PlayerThread();
3868+        thread.addListener(this);
3869+       
3870+        text_timeStepActionPerformed(null);
3871+    }
3872+   
3873+    public void updateTime(double curTime, double timeStep, int playState)
3874+    {
3875+        if (playState == PlayerThread.PS_STOP) return;
3876+       
3877+        text_curTime.setText("" + (float)curTime);
3878+        parent.updateTime(curTime);
3879+//        text_timeStep.setText("" + (int)(1.0 / timeStep));
3880+    }
3881+   
3882+    /** This method is called from within the constructor to
3883+     * initialize the form.
3884+     * WARNING: Do NOT modify this code. The content of this method is
3885+     * always regenerated by the Form Editor.
3886+     */
3887+    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
3888+    private void initComponents()
3889+    {
3890+        jPanel1 = new javax.swing.JPanel();
3891+        bn_playBack = new javax.swing.JButton();
3892+        bn_stop = new javax.swing.JButton();
3893+        bn_playFwd = new javax.swing.JButton();
3894+        jPanel2 = new javax.swing.JPanel();
3895+        jPanel3 = new javax.swing.JPanel();
3896+        jLabel1 = new javax.swing.JLabel();
3897+        text_curTime = new javax.swing.JTextField();
3898+        bn_time0 = new javax.swing.JButton();
3899+        jPanel4 = new javax.swing.JPanel();
3900+        jLabel2 = new javax.swing.JLabel();
3901+        text_timeStep = new javax.swing.JTextField();
3902+
3903+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
3904+        setTitle("Player");
3905+        addWindowListener(new java.awt.event.WindowAdapter()
3906+        {
3907+            public void windowClosed(java.awt.event.WindowEvent evt)
3908+            {
3909+                formWindowClosed(evt);
3910+            }
3911+        });
3912+
3913+        bn_playBack.setText("<");
3914+        bn_playBack.setToolTipText("Play backwards");
3915+        bn_playBack.addActionListener(new java.awt.event.ActionListener()
3916+        {
3917+            public void actionPerformed(java.awt.event.ActionEvent evt)
3918+            {
3919+                bn_playBackActionPerformed(evt);
3920+            }
3921+        });
3922+
3923+        jPanel1.add(bn_playBack);
3924+
3925+        bn_stop.setText("||");
3926+        bn_stop.setToolTipText("Stop playback");
3927+        bn_stop.addActionListener(new java.awt.event.ActionListener()
3928+        {
3929+            public void actionPerformed(java.awt.event.ActionEvent evt)
3930+            {
3931+                bn_stopActionPerformed(evt);
3932+            }
3933+        });
3934+
3935+        jPanel1.add(bn_stop);
3936+
3937+        bn_playFwd.setText(">");
3938+        bn_playFwd.setToolTipText("Play Forwards");
3939+        bn_playFwd.addActionListener(new java.awt.event.ActionListener()
3940+        {
3941+            public void actionPerformed(java.awt.event.ActionEvent evt)
3942+            {
3943+                bn_playFwdActionPerformed(evt);
3944+            }
3945+        });
3946+
3947+        jPanel1.add(bn_playFwd);
3948+
3949+        getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);
3950+
3951+        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
3952+
3953+        jLabel1.setText("Cur Time");
3954+        jPanel3.add(jLabel1);
3955+
3956+        text_curTime.setHorizontalAlignment(javax.swing.JTextField.LEFT);
3957+        text_curTime.setText("0");
3958+        text_curTime.setPreferredSize(new java.awt.Dimension(100, 21));
3959+        text_curTime.addActionListener(new java.awt.event.ActionListener()
3960+        {
3961+            public void actionPerformed(java.awt.event.ActionEvent evt)
3962+            {
3963+                text_curTimeActionPerformed(evt);
3964+            }
3965+        });
3966+        text_curTime.addFocusListener(new java.awt.event.FocusAdapter()
3967+        {
3968+            public void focusLost(java.awt.event.FocusEvent evt)
3969+            {
3970+                text_curTimeFocusLost(evt);
3971+            }
3972+        });
3973+
3974+        jPanel3.add(text_curTime);
3975+
3976+        bn_time0.setText("Time 0");
3977+        bn_time0.setToolTipText("Reset time to first frame");
3978+        bn_time0.addActionListener(new java.awt.event.ActionListener()
3979+        {
3980+            public void actionPerformed(java.awt.event.ActionEvent evt)
3981+            {
3982+                bn_time0ActionPerformed(evt);
3983+            }
3984+        });
3985+
3986+        jPanel3.add(bn_time0);
3987+
3988+        jPanel2.add(jPanel3);
3989+
3990+        jLabel2.setText("Frames Per Second");
3991+        jPanel4.add(jLabel2);
3992+
3993+        text_timeStep.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
3994+        text_timeStep.setText("60");
3995+        text_timeStep.setPreferredSize(new java.awt.Dimension(100, 21));
3996+        text_timeStep.addActionListener(new java.awt.event.ActionListener()
3997+        {
3998+            public void actionPerformed(java.awt.event.ActionEvent evt)
3999+            {
4000+                text_timeStepActionPerformed(evt);
4001+            }
4002+        });
4003+        text_timeStep.addFocusListener(new java.awt.event.FocusAdapter()
4004+        {
4005+            public void focusLost(java.awt.event.FocusEvent evt)
4006+            {
4007+                text_timeStepFocusLost(evt);
4008+            }
4009+        });
4010+
4011+        jPanel4.add(text_timeStep);
4012+
4013+        jPanel2.add(jPanel4);
4014+
4015+        getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);
4016+
4017+        pack();
4018+    }// </editor-fold>//GEN-END:initComponents
4019+
4020+    private void bn_time0ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_time0ActionPerformed
4021+    {//GEN-HEADEREND:event_bn_time0ActionPerformed
4022+        thread.setCurTime(0);
4023+    }//GEN-LAST:event_bn_time0ActionPerformed
4024+
4025+    private void bn_playFwdActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_playFwdActionPerformed
4026+    {//GEN-HEADEREND:event_bn_playFwdActionPerformed
4027+        thread.setPlayState(PlayerThread.PS_PLAY_FWD);
4028+    }//GEN-LAST:event_bn_playFwdActionPerformed
4029+
4030+    private void bn_stopActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_stopActionPerformed
4031+    {//GEN-HEADEREND:event_bn_stopActionPerformed
4032+        thread.setPlayState(PlayerThread.PS_STOP);
4033+    }//GEN-LAST:event_bn_stopActionPerformed
4034+
4035+    private void bn_playBackActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_playBackActionPerformed
4036+    {//GEN-HEADEREND:event_bn_playBackActionPerformed
4037+        thread.setPlayState(PlayerThread.PS_PLAY_BACK);
4038+    }//GEN-LAST:event_bn_playBackActionPerformed
4039+
4040+    private void formWindowClosed(java.awt.event.WindowEvent evt)//GEN-FIRST:event_formWindowClosed
4041+    {//GEN-HEADEREND:event_formWindowClosed
4042+//        thread.exit();
4043+    }//GEN-LAST:event_formWindowClosed
4044+
4045+    private void text_timeStepFocusLost(java.awt.event.FocusEvent evt)//GEN-FIRST:event_text_timeStepFocusLost
4046+    {//GEN-HEADEREND:event_text_timeStepFocusLost
4047+        text_timeStepActionPerformed(null);
4048+    }//GEN-LAST:event_text_timeStepFocusLost
4049+
4050+    private void text_timeStepActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_text_timeStepActionPerformed
4051+    {//GEN-HEADEREND:event_text_timeStepActionPerformed
4052+        try
4053+        {
4054+            int val = Integer.parseInt(text_timeStep.getText());
4055+            thread.setTimeStep(1.0 / val);
4056+        }
4057+        catch (Exception e)
4058+        {
4059+        }
4060+       
4061+        double d = thread.getTimeStep();
4062+        String newStrn = "" + (int)(1f / d);
4063+        if (newStrn.equals(text_timeStep.getText())) return;
4064+        text_timeStep.setText(newStrn);
4065+       
4066+//        text_timeStepActionPerformed(null);
4067+    }//GEN-LAST:event_text_timeStepActionPerformed
4068+
4069+    private void text_curTimeActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_text_curTimeActionPerformed
4070+    {//GEN-HEADEREND:event_text_curTimeActionPerformed
4071+        try
4072+        {
4073+            double val = Double.parseDouble(text_curTime.getText());
4074+            thread.setCurTime(val);
4075+        }
4076+        catch (Exception e)
4077+        {
4078+        }
4079+       
4080+        double d = thread.getCurTime();
4081+        text_curTime.setText("" + (float)d);
4082+       
4083+        text_timeStepActionPerformed(null);
4084+    }//GEN-LAST:event_text_curTimeActionPerformed
4085+
4086+    private void text_curTimeFocusLost(java.awt.event.FocusEvent evt)//GEN-FIRST:event_text_curTimeFocusLost
4087+    {//GEN-HEADEREND:event_text_curTimeFocusLost
4088+        text_curTimeActionPerformed(null);
4089+    }//GEN-LAST:event_text_curTimeFocusLost
4090+   
4091+    // Variables declaration - do not modify//GEN-BEGIN:variables
4092+    private javax.swing.JButton bn_playBack;
4093+    private javax.swing.JButton bn_playFwd;
4094+    private javax.swing.JButton bn_stop;
4095+    private javax.swing.JButton bn_time0;
4096+    private javax.swing.JLabel jLabel1;
4097+    private javax.swing.JLabel jLabel2;
4098+    private javax.swing.JPanel jPanel1;
4099+    private javax.swing.JPanel jPanel2;
4100+    private javax.swing.JPanel jPanel3;
4101+    private javax.swing.JPanel jPanel4;
4102+    private javax.swing.JTextField text_curTime;
4103+    private javax.swing.JTextField text_timeStep;
4104+    // End of variables declaration//GEN-END:variables
4105+   
4106+}
4107Index: core/src/com/kitfox/svg/app/PlayerThread.java
[4256]4108===================================================================
[5284]4109--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4110+++ core/src/com/kitfox/svg/app/PlayerThread.java       2012-06-17 23:56:57.748545052 +0200
4111@@ -0,0 +1,129 @@
4112+/*
4113+ * PlayerThread.java
4114+ *
4115+ *
4116+ *  The Salamander Project - 2D and 3D graphics libraries in Java
4117+ *  Copyright (C) 2004 Mark McKay
4118+ *
4119+ *  This library is free software; you can redistribute it and/or
4120+ *  modify it under the terms of the GNU Lesser General Public
4121+ *  License as published by the Free Software Foundation; either
4122+ *  version 2.1 of the License, or (at your option) any later version.
4123+ *
4124+ *  This library is distributed in the hope that it will be useful,
4125+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4126+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4127+ *  Lesser General Public License for more details.
4128+ *
4129+ *  You should have received a copy of the GNU Lesser General Public
4130+ *  License along with this library; if not, write to the Free Software
4131+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4132+ *
4133+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
4134+ *  projects can be found at http://www.kitfox.com
4135+ *
4136+ * Created on September 28, 2004, 10:07 PM
4137+ */
4138+
4139+
4140+package com.kitfox.svg.app;
4141+
4142+import java.util.*;
4143+
4144+/**
4145+ *
4146+ * @author  kitfox
4147+ */
4148+public class PlayerThread implements Runnable
4149+{
4150+    HashSet listeners = new HashSet();
4151+   
4152+    double curTime = 0;
4153+    double timeStep = .2;
4154+   
4155+    public static final int PS_STOP = 0;
4156+    public static final int PS_PLAY_FWD = 1;
4157+    public static final int PS_PLAY_BACK = 2;
4158+   
4159+    int playState = PS_STOP;
4160+   
4161+    Thread thread;
4162+   
4163+    /** Creates a new instance of PlayerThread */
4164+    public PlayerThread()
4165+    {
4166+        thread = new Thread(this);
4167+        thread.start();
4168+    }
4169+   
4170+    public void run()
4171+    {
4172+        while (thread != null)
4173+        {
4174+            synchronized (this)
4175+            {
4176+                switch (playState)
4177+                {
4178+                    case PS_PLAY_FWD:
4179+                        curTime += timeStep;
4180+                        break;
4181+                    case PS_PLAY_BACK:
4182+                        curTime -= timeStep;
4183+                        if (curTime < 0) curTime = 0;
4184+                        break;
4185+                    default:
4186+                    case PS_STOP:
4187+                        break;
4188+                }
4189+               
4190+                fireTimeUpdateEvent();
4191+            }
4192+           
4193+            try
4194+            {
4195+                Thread.sleep((long)(timeStep * 1000));
4196+            }
4197+            catch (Exception e)
4198+            {
4199+                throw new RuntimeException(e);
4200+            }
4201+        }
4202+    }
4203+   
4204+    public void exit() { thread = null; }
4205+    public synchronized void addListener(PlayerThreadListener listener)
4206+    {
4207+        listeners.add(listener);
4208+    }
4209+   
4210+    public synchronized double getCurTime() { return curTime; }
4211+   
4212+    public synchronized void setCurTime(double time)
4213+    {
4214+        curTime = time;
4215+    }
4216+   
4217+    public synchronized double getTimeStep() { return timeStep; }
4218+   
4219+    public synchronized void setTimeStep(double time)
4220+    {
4221+        timeStep = time;
4222+        if (timeStep < .01) timeStep = .01;
4223+    }
4224+   
4225+    public synchronized int getPlayState() { return playState; }
4226+   
4227+    public synchronized void setPlayState(int playState)
4228+    {
4229+        this.playState = playState;
4230+    }
4231+   
4232+    private void fireTimeUpdateEvent()
4233+    {
4234+        for (Iterator it = listeners.iterator(); it.hasNext();)
4235+        {
4236+            PlayerThreadListener listener = (PlayerThreadListener)it.next();
4237+            listener.updateTime(curTime, timeStep, playState);
4238+        }
4239+    }
4240+}
4241Index: core/src/com/kitfox/svg/app/PlayerThreadListener.java
[4256]4242===================================================================
[5284]4243--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4244+++ core/src/com/kitfox/svg/app/PlayerThreadListener.java       2012-06-17 23:56:57.748545052 +0200
4245@@ -0,0 +1,37 @@
4246+/*
4247+ * PlayerThreadListener.java
4248+ *
4249+ *
4250+ *  The Salamander Project - 2D and 3D graphics libraries in Java
4251+ *  Copyright (C) 2004 Mark McKay
4252+ *
4253+ *  This library is free software; you can redistribute it and/or
4254+ *  modify it under the terms of the GNU Lesser General Public
4255+ *  License as published by the Free Software Foundation; either
4256+ *  version 2.1 of the License, or (at your option) any later version.
4257+ *
4258+ *  This library is distributed in the hope that it will be useful,
4259+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4260+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4261+ *  Lesser General Public License for more details.
4262+ *
4263+ *  You should have received a copy of the GNU Lesser General Public
4264+ *  License along with this library; if not, write to the Free Software
4265+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4266+ *
4267+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
4268+ *  projects can be found at http://www.kitfox.com
4269+ *
4270+ * Created on September 28, 2004, 10:15 PM
4271+ */
4272+
4273+package com.kitfox.svg.app;
4274+
4275+/**
4276+ *
4277+ * @author  kitfox
4278+ */
4279+public interface PlayerThreadListener
4280+{
4281+    public void updateTime(double curTime, double timeStep, int playState);
4282+}
4283Index: core/src/com/kitfox/svg/app/SVGPlayer.java
[4256]4284===================================================================
[5284]4285--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4286+++ core/src/com/kitfox/svg/app/SVGPlayer.java  2012-06-17 23:56:57.748545052 +0200
4287@@ -0,0 +1,436 @@
4288+/*
4289+ * SVGViewer.java
4290+ *
4291+ *
4292+ *  The Salamander Project - 2D and 3D graphics libraries in Java
4293+ *  Copyright (C) 2004 Mark McKay
4294+ *
4295+ *  This library is free software; you can redistribute it and/or
4296+ *  modify it under the terms of the GNU Lesser General Public
4297+ *  License as published by the Free Software Foundation; either
4298+ *  version 2.1 of the License, or (at your option) any later version.
4299+ *
4300+ *  This library is distributed in the hope that it will be useful,
4301+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4302+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4303+ *  Lesser General Public License for more details.
4304+ *
4305+ *  You should have received a copy of the GNU Lesser General Public
4306+ *  License along with this library; if not, write to the Free Software
4307+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4308+ *
4309+ *  Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
4310+ *  projects can be found at http://www.kitfox.com
4311+ *
4312+ * Created on April 3, 2004, 5:28 PM
4313+ */
4314+
4315+package com.kitfox.svg.app;
4316+
4317+
4318+import com.kitfox.svg.SVGDiagram;
4319+import com.kitfox.svg.SVGDisplayPanel;
4320+import com.kitfox.svg.SVGElement;
4321+import com.kitfox.svg.SVGException;
4322+import com.kitfox.svg.SVGUniverse;
4323+import java.awt.Color;
4324+import java.awt.event.MouseAdapter;
4325+import java.awt.event.MouseEvent;
4326+import java.awt.geom.Point2D;
4327+import java.io.File;
4328+import java.io.InputStream;
4329+import java.net.URI;
4330+import java.net.URL;
4331+import java.net.URLEncoder;
4332+import java.security.AccessControlException;
4333+import java.util.ArrayList;
4334+import java.util.List;
4335+import java.util.Vector;
4336+import java.util.regex.Matcher;
4337+import java.util.regex.Pattern;
4338+import javax.swing.JFileChooser;
4339+import javax.swing.JOptionPane;
4340+
4341+/**
4342+ * @author Mark McKay
4343+ * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
4344+ */
4345+public class SVGPlayer extends javax.swing.JFrame
4346+{
4347+    public static final long serialVersionUID = 1;
4348+
4349+    SVGDisplayPanel svgDisplayPanel = new SVGDisplayPanel();
4350+
4351+    final PlayerDialog playerDialog;
4352+   
4353+    SVGUniverse universe;
4354+   
4355+    /** FileChooser for running in trusted environments */
4356+    final JFileChooser fileChooser;
4357+    {
4358+//        fileChooser = new JFileChooser(new File("."));
4359+        JFileChooser fc = null;
4360+        try
4361+        {
4362+            fc = new JFileChooser();
4363+            fc.setFileFilter(
4364+                new javax.swing.filechooser.FileFilter() {
4365+                    final Matcher matchLevelFile = Pattern.compile(".*\\.svg[z]?").matcher("");
4366+
4367+                    public boolean accept(File file)
4368+                    {
4369+                        if (file.isDirectory()) return true;
4370+
4371+                        matchLevelFile.reset(file.getName());
4372+                        return matchLevelFile.matches();
4373+                    }
4374+
4375+                    public String getDescription() { return "SVG file (*.svg, *.svgz)"; }
4376+                }
4377+            );
4378+        }
4379+        catch (AccessControlException ex)
4380+        {
4381+            //Do not create file chooser if webstart refuses permissions
4382+        }
4383+        fileChooser = fc;
4384+    }
4385+
4386+    /** Backup file service for opening files in WebStart situations */
4387+    /*
4388+    final FileOpenService fileOpenService;
4389+    {
4390+        try
4391+        {
4392+            fileOpenService = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService");
4393+        }
4394+        catch (UnavailableServiceException e)
4395+        {
4396+            fileOpenService = null;
4397+        }
4398+    }
4399+     */
4400+   
4401+    /** Creates new form SVGViewer */
4402+    public SVGPlayer() {
4403+        initComponents();
4404+
4405+        setSize(800, 600);
4406+
4407+        svgDisplayPanel.setBgColor(Color.white);
4408+        svgDisplayPanel.addMouseListener(new MouseAdapter()
4409+        {
4410+            public void mouseClicked(MouseEvent evt)
4411+            {
4412+                SVGDiagram diagram = svgDisplayPanel.getDiagram();
4413+                if (diagram == null) return;
4414+               
4415+                System.out.println("Picking at cursor (" + evt.getX() + ", " + evt.getY() + ")");
4416+                try
4417+                {
4418+                    List paths = diagram.pick(new Point2D.Float(evt.getX(), evt.getY()), null);
4419+                    for (int i = 0; i < paths.size(); i++)
4420+                    {
4421+                        ArrayList path = (ArrayList)paths.get(i);
4422+                        System.out.println(pathToString(path));
4423+                    }
4424+                }
4425+                catch (SVGException ex)
4426+                {
4427+                    ex.printStackTrace();
4428+                }
4429+            }
4430+        }
4431+        );
4432+       
4433+        svgDisplayPanel.setPreferredSize(getSize());
4434+        scrollPane_svgArea.setViewportView(svgDisplayPanel);
4435+       
4436+        playerDialog = new PlayerDialog(this);
4437+    }
4438+   
4439+    private String pathToString(List path)
4440+    {
4441+        if (path.size() == 0) return "";
4442+       
4443+        StringBuffer sb = new StringBuffer();
4444+        sb.append(path.get(0));
4445+        for (int i = 1; i < path.size(); i++)
4446+        {
4447+            sb.append("/");
4448+            sb.append(((SVGElement)path.get(i)).getId());
4449+        }
4450+        return sb.toString();
4451+    }
4452+   
4453+    public void updateTime(double curTime)
4454+    {
4455+        try
4456+        {
4457+            if (universe != null)
4458+            {
4459+                universe.setCurTime(curTime);
4460+                universe.updateTime();
4461+    //            svgDisplayPanel.updateTime(curTime);
4462+                repaint();
4463+            }
4464+        }
4465+        catch (Exception e)
4466+        {
4467+            e.printStackTrace();
4468+        }
4469+    }
4470+
4471+    private void loadURL(URL url)
4472+    {
4473+        boolean verbose = cmCheck_verbose.isSelected();
4474+
4475+        universe = new SVGUniverse();
4476+        universe.setVerbose(verbose);
4477+        SVGDiagram diagram = null;
4478+
4479+        if (!CheckBoxMenuItem_anonInputStream.isSelected())
4480+        {
4481+            //Load from a disk with a valid URL
4482+            URI uri = universe.loadSVG(url);
4483+
4484+            if (verbose) System.err.println(uri.toString());
4485+
4486+            diagram = universe.getDiagram(uri);
4487+        }
4488+        else
4489+        {
4490+            //Load from a stream with no particular valid URL
4491+            try
4492+            {
4493+                InputStream is = url.openStream();
4494+                URI uri = universe.loadSVG(is, "defaultName");
4495+
4496+                if (verbose) System.err.println(uri.toString());
4497+
4498+                diagram = universe.getDiagram(uri);
4499+            }
4500+            catch (Exception e)
4501+            {
4502+                e.printStackTrace();
4503+            }
4504+        }
4505+
4506+        svgDisplayPanel.setDiagram(diagram);
4507+        repaint();
4508+    }
4509+   
4510+    /** This method is called from within the constructor to
4511+     * initialize the form.
4512+     * WARNING: Do NOT modify this code. The content of this method is
4513+     * always regenerated by the Form Editor.
4514+     */
4515+    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
4516+    private void initComponents()
4517+    {
4518+        scrollPane_svgArea = new javax.swing.JScrollPane();
4519+        jMenuBar1 = new javax.swing.JMenuBar();
4520+        menu_file = new javax.swing.JMenu();
4521+        cm_loadFile = new javax.swing.JMenuItem();
4522+        cm_loadUrl = new javax.swing.JMenuItem();
4523+        menu_window = new javax.swing.JMenu();
4524+        cm_player = new javax.swing.JMenuItem();
4525+        jSeparator2 = new javax.swing.JSeparator();
4526+        cm_800x600 = new javax.swing.JMenuItem();
4527+        CheckBoxMenuItem_anonInputStream = new javax.swing.JCheckBoxMenuItem();
4528+        cmCheck_verbose = new javax.swing.JCheckBoxMenuItem();
4529+        menu_help = new javax.swing.JMenu();
4530+        cm_about = new javax.swing.JMenuItem();
4531+
4532+        setTitle("SVG Player - Salamander Project");
4533+        addWindowListener(new java.awt.event.WindowAdapter()
4534+        {
4535+            public void windowClosing(java.awt.event.WindowEvent evt)
4536+            {
4537+                exitForm(evt);
4538+            }
4539+        });
4540+
4541+        getContentPane().add(scrollPane_svgArea, java.awt.BorderLayout.CENTER);
4542+
4543+        menu_file.setMnemonic('f');
4544+        menu_file.setText("File");
4545+        cm_loadFile.setMnemonic('l');
4546+        cm_loadFile.setText("Load File...");
4547+        cm_loadFile.addActionListener(new java.awt.event.ActionListener()
4548+        {
4549+            public void actionPerformed(java.awt.event.ActionEvent evt)
4550+            {
4551+                cm_loadFileActionPerformed(evt);
4552+            }
4553+        });
4554+
4555+        menu_file.add(cm_loadFile);
4556+
4557+        cm_loadUrl.setText("Load URL...");
4558+        cm_loadUrl.addActionListener(new java.awt.event.ActionListener()
4559+        {
4560+            public void actionPerformed(java.awt.event.ActionEvent evt)
4561+            {
4562+                cm_loadUrlActionPerformed(evt);
4563+            }
4564+        });
4565+
4566+        menu_file.add(cm_loadUrl);
4567+
4568+        jMenuBar1.add(menu_file);
4569+
4570+        menu_window.setText("Window");
4571+        cm_player.setText("Player");
4572+        cm_player.addActionListener(new java.awt.event.ActionListener()
4573+        {
4574+            public void actionPerformed(java.awt.event.ActionEvent evt)
4575+            {
4576+                cm_playerActionPerformed(evt);
4577+            }
4578+        });
4579+
4580+        menu_window.add(cm_player);
4581+
4582+        menu_window.add(jSeparator2);
4583+
4584+        cm_800x600.setText("800 x 600");
4585+        cm_800x600.addActionListener(new java.awt.event.ActionListener()
4586+        {
4587+            public void actionPerformed(java.awt.event.ActionEvent evt)
4588+            {
4589+                cm_800x600ActionPerformed(evt);
4590+            }
4591+        });
4592+
4593+        menu_window.add(cm_800x600);
4594+
4595+        CheckBoxMenuItem_anonInputStream.setText("Anonymous Input Stream");
4596+        menu_window.add(CheckBoxMenuItem_anonInputStream);
4597+
4598+        cmCheck_verbose.setText("Verbose");
4599+        cmCheck_verbose.addActionListener(new java.awt.event.ActionListener()
4600+        {
4601+            public void actionPerformed(java.awt.event.ActionEvent evt)
4602+            {
4603+                cmCheck_verboseActionPerformed(evt);
4604+            }
4605+        });
4606+
4607+        menu_window.add(cmCheck_verbose);
4608+
4609+        jMenuBar1.add(menu_window);
4610+
4611+        menu_help.setText("Help");
4612+        cm_about.setText("About...");
4613+        cm_about.addActionListener(new java.awt.event.ActionListener()
4614+        {
4615+            public void actionPerformed(java.awt.event.ActionEvent evt)
4616+            {
4617+                cm_aboutActionPerformed(evt);
4618+            }
4619+        });
4620+
4621+        menu_help.add(cm_about);
4622+
4623+        jMenuBar1.add(menu_help);
4624+
4625+        setJMenuBar(jMenuBar1);
4626+
4627+        pack();
4628+    }// </editor-fold>//GEN-END:initComponents
4629+
4630+    private void cm_loadUrlActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadUrlActionPerformed
4631+    {//GEN-HEADEREND:event_cm_loadUrlActionPerformed
4632+        String urlStrn = JOptionPane.showInputDialog(this, "Enter URL of SVG file");
4633+        if (urlStrn == null) return;
4634+       
4635+        try
4636+        {
4637+            URL url = new URL(URLEncoder.encode(urlStrn, "UTF-8"));
4638+            loadURL(url);
4639+        }
4640+        catch (Exception e)
4641+        {
4642+            e.printStackTrace();
4643+        }
4644+
4645+    }//GEN-LAST:event_cm_loadUrlActionPerformed
4646+
4647+    private void cmCheck_verboseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cmCheck_verboseActionPerformed
4648+    {//GEN-HEADEREND:event_cmCheck_verboseActionPerformed
4649+// TODO add your handling code here:
4650+    }//GEN-LAST:event_cmCheck_verboseActionPerformed
4651+
4652+    private void cm_playerActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_playerActionPerformed
4653+    {//GEN-HEADEREND:event_cm_playerActionPerformed
4654+        playerDialog.setVisible(true);
4655+    }//GEN-LAST:event_cm_playerActionPerformed
4656+
4657+    private void cm_aboutActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_aboutActio