source: josm/trunk/src/com/kitfox/svg/SVGRoot.java@ 14082

Last change on this file since 14082 was 11525, checked in by Don-vip, 7 years ago

see #14319 - update to latest version of svgSalamander (2017-01-07, patched)

  • Property svn:eol-style set to native
File size: 15.0 KB
Line 
1/*
2 * SVG Salamander
3 * Copyright (c) 2004, Mark McKay
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
9 *
10 * - Redistributions of source code must retain the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
32 * projects can be found at http://www.kitfox.com
33 *
34 * Created on February 18, 2004, 5:33 PM
35 */
36
37package com.kitfox.svg;
38
39import com.kitfox.svg.xml.NumberWithUnits;
40import com.kitfox.svg.xml.StyleAttribute;
41import com.kitfox.svg.xml.StyleSheet;
42import java.awt.Graphics2D;
43import java.awt.Rectangle;
44import java.awt.Shape;
45import java.awt.geom.AffineTransform;
46import java.awt.geom.NoninvertibleTransformException;
47import java.awt.geom.Point2D;
48import java.awt.geom.Rectangle2D;
49import java.util.List;
50
51/**
52 * The root element of an SVG tree.
53 *
54 * @author Mark McKay
55 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
56 */
57public class SVGRoot extends Group
58{
59 public static final String TAG_NAME = "svg";
60
61 NumberWithUnits x;
62 NumberWithUnits y;
63 NumberWithUnits width;
64 NumberWithUnits height;
65
66 Rectangle2D.Float viewBox = null;
67
68 public static final int PA_X_NONE = 0;
69 public static final int PA_X_MIN = 1;
70 public static final int PA_X_MID = 2;
71 public static final int PA_X_MAX = 3;
72
73 public static final int PA_Y_NONE = 0;
74 public static final int PA_Y_MIN = 1;
75 public static final int PA_Y_MID = 2;
76 public static final int PA_Y_MAX = 3;
77
78 public static final int PS_MEET = 0;
79 public static final int PS_SLICE = 1;
80
81 int parSpecifier = PS_MEET;
82 int parAlignX = PA_X_MID;
83 int parAlignY = PA_Y_MID;
84
85 final AffineTransform viewXform = new AffineTransform();
86 final Rectangle2D.Float clipRect = new Rectangle2D.Float();
87
88 private StyleSheet styleSheet;
89
90 /** Creates a new instance of SVGRoot */
91 public SVGRoot()
92 {
93 }
94
95 @Override
96 public String getTagName()
97 {
98 return TAG_NAME;
99 }
100
101 @Override
102 public void build() throws SVGException
103 {
104 super.build();
105
106 StyleAttribute sty = new StyleAttribute();
107
108 if (getPres(sty.setName("x")))
109 {
110 x = sty.getNumberWithUnits();
111 }
112
113 if (getPres(sty.setName("y")))
114 {
115 y = sty.getNumberWithUnits();
116 }
117
118 if (getPres(sty.setName("width")))
119 {
120 width = sty.getNumberWithUnits();
121 }
122
123 if (getPres(sty.setName("height")))
124 {
125 height = sty.getNumberWithUnits();
126 }
127
128 if (getPres(sty.setName("viewBox")))
129 {
130 float[] coords = sty.getFloatList();
131 viewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
132 }
133
134 if (getPres(sty.setName("preserveAspectRatio")))
135 {
136 String preserve = sty.getStringValue();
137
138 if (contains(preserve, "none")) { parAlignX = PA_X_NONE; parAlignY = PA_Y_NONE; }
139 else if (contains(preserve, "xMinYMin")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MIN; }
140 else if (contains(preserve, "xMidYMin")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MIN; }
141 else if (contains(preserve, "xMaxYMin")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MIN; }
142 else if (contains(preserve, "xMinYMid")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MID; }
143 else if (contains(preserve, "xMidYMid")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MID; }
144 else if (contains(preserve, "xMaxYMid")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MID; }
145 else if (contains(preserve, "xMinYMax")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MAX; }
146 else if (contains(preserve, "xMidYMax")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MAX; }
147 else if (contains(preserve, "xMaxYMax")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MAX; }
148
149 if (contains(preserve, "meet"))
150 {
151 parSpecifier = PS_MEET;
152 }
153 else if (contains(preserve, "slice"))
154 {
155 parSpecifier = PS_SLICE;
156 }
157 }
158
159 prepareViewport();
160 }
161
162 private boolean contains(String text, String find)
163 {
164 return (text.indexOf(find) != -1);
165 }
166
167 @Override
168 public SVGRoot getRoot()
169 {
170 return this;
171 }
172
173 protected void prepareViewport()
174 {
175 Rectangle deviceViewport = diagram.getDeviceViewport();
176
177 Rectangle2D defaultBounds;
178 try
179 {
180 defaultBounds = getBoundingBox();
181 }
182 catch (SVGException ex)
183 {
184 defaultBounds= new Rectangle2D.Float();
185 }
186
187 //Determine destination rectangle
188 float xx, yy, ww, hh;
189 if (width != null)
190 {
191 xx = (x == null) ? 0 : StyleAttribute.convertUnitsToPixels(x.getUnits(), x.getValue());
192 if (width.getUnits() == NumberWithUnits.UT_PERCENT)
193 {
194 ww = width.getValue() * deviceViewport.width;
195 }
196 else
197 {
198 ww = StyleAttribute.convertUnitsToPixels(width.getUnits(), width.getValue());
199 }
200 }
201 else if (viewBox != null)
202 {
203 xx = (float)viewBox.x;
204 ww = (float)viewBox.width;
205 width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
206 x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
207 }
208 else
209 {
210 //Estimate size from scene bounding box
211 xx = (float)defaultBounds.getX();
212 ww = (float)defaultBounds.getWidth();
213 width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
214 x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
215 }
216
217 if (height != null)
218 {
219 yy = (y == null) ? 0 : StyleAttribute.convertUnitsToPixels(y.getUnits(), y.getValue());
220 if (height.getUnits() == NumberWithUnits.UT_PERCENT)
221 {
222 hh = height.getValue() * deviceViewport.height;
223 }
224 else
225 {
226 hh = StyleAttribute.convertUnitsToPixels(height.getUnits(), height.getValue());
227 }
228 }
229 else if (viewBox != null)
230 {
231 yy = (float)viewBox.y;
232 hh = (float)viewBox.height;
233 height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
234 y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
235 }
236 else
237 {
238 //Estimate size from scene bounding box
239 yy = (float)defaultBounds.getY();
240 hh = (float)defaultBounds.getHeight();
241 height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
242 y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
243 }
244
245 clipRect.setRect(xx, yy, ww, hh);
246
247// if (viewBox == null)
248// {
249// viewXform.setToIdentity();
250// }
251// else
252// {
253// //If viewport window is set, we are drawing to entire viewport
254// clipRect.setRect(deviceViewport);
255//
256// viewXform.setToIdentity();
257// viewXform.setToTranslation(deviceViewport.x, deviceViewport.y);
258// viewXform.scale(deviceViewport.width, deviceViewport.height);
259// viewXform.scale(1 / viewBox.width, 1 / viewBox.height);
260// viewXform.translate(-viewBox.x, -viewBox.y);
261// }
262 }
263
264 public void renderToViewport(Graphics2D g) throws SVGException
265 {
266 prepareViewport();
267
268 Rectangle targetViewport = g.getClipBounds();
269//
270// if (targetViewport == null)
271// {
272// Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
273// targetViewport = new Rectangle(0, 0, size.width, size.height);
274// }
275// clipRect.setRect(targetViewport);
276
277
278 Rectangle deviceViewport = diagram.getDeviceViewport();
279 if (width != null && height != null)
280 {
281 float xx, yy, ww, hh;
282
283 xx = (x == null) ? 0 : StyleAttribute.convertUnitsToPixels(x.getUnits(), x.getValue());
284 if (width.getUnits() == NumberWithUnits.UT_PERCENT)
285 {
286 ww = width.getValue() * deviceViewport.width;
287 }
288 else
289 {
290 ww = StyleAttribute.convertUnitsToPixels(width.getUnits(), width.getValue());
291 }
292
293 yy = (y == null) ? 0 : StyleAttribute.convertUnitsToPixels(y.getUnits(), y.getValue());
294 if (height.getUnits() == NumberWithUnits.UT_PERCENT)
295 {
296 hh = height.getValue() * deviceViewport.height;
297 }
298 else
299 {
300 hh = StyleAttribute.convertUnitsToPixels(height.getUnits(), height.getValue());
301 }
302
303 targetViewport = new Rectangle((int)xx, (int)yy, (int)ww, (int)hh);
304 }
305 else
306 {
307// Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
308// targetViewport = new Rectangle(0, 0, size.width, size.height);
309 targetViewport = new Rectangle(deviceViewport);
310 }
311 clipRect.setRect(targetViewport);
312
313 if (viewBox == null)
314 {
315 viewXform.setToIdentity();
316 }
317 else
318 {
319 viewXform.setToIdentity();
320 viewXform.setToTranslation(targetViewport.x, targetViewport.y);
321 viewXform.scale(targetViewport.width, targetViewport.height);
322 viewXform.scale(1 / viewBox.width, 1 / viewBox.height);
323 viewXform.translate(-viewBox.x, -viewBox.y);
324 }
325
326 AffineTransform cachedXform = g.getTransform();
327 g.transform(viewXform);
328
329 super.render(g);
330
331 g.setTransform(cachedXform);
332 }
333
334 @Override
335 public void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
336 {
337 if (viewXform != null)
338 {
339 ltw = new AffineTransform(ltw);
340 ltw.concatenate(viewXform);
341 }
342
343 super.pick(pickArea, ltw, boundingBox, retVec);
344 }
345
346 @Override
347 public void pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
348 {
349 Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
350 if (viewXform != null)
351 {
352 try
353 {
354 viewXform.inverseTransform(point, xPoint);
355 } catch (NoninvertibleTransformException ex)
356 {
357 throw new SVGException(ex);
358 }
359 }
360
361 super.pick(xPoint, boundingBox, retVec);
362 }
363
364 @Override
365 public Shape getShape()
366 {
367 Shape shape = super.getShape();
368 return viewXform.createTransformedShape(shape);
369 }
370
371 @Override
372 public Rectangle2D getBoundingBox() throws SVGException
373 {
374 Rectangle2D bbox = super.getBoundingBox();
375 return viewXform.createTransformedShape(bbox).getBounds2D();
376 }
377
378 public float getDeviceWidth()
379 {
380 return clipRect.width;
381 }
382
383 public float getDeviceHeight()
384 {
385 return clipRect.height;
386 }
387
388 public Rectangle2D getDeviceRect(Rectangle2D rect)
389 {
390 rect.setRect(clipRect);
391 return rect;
392 }
393
394 /**
395 * Updates all attributes in this diagram associated with a time event.
396 * Ie, all attributes with track information.
397 * @return - true if this node has changed state as a result of the time
398 * update
399 */
400 @Override
401 public boolean updateTime(double curTime) throws SVGException
402 {
403 boolean changeState = super.updateTime(curTime);
404
405 StyleAttribute sty = new StyleAttribute();
406 boolean shapeChange = false;
407
408 if (getPres(sty.setName("x")))
409 {
410 NumberWithUnits newVal = sty.getNumberWithUnits();
411 if (!newVal.equals(x))
412 {
413 x = newVal;
414 shapeChange = true;
415 }
416 }
417
418 if (getPres(sty.setName("y")))
419 {
420 NumberWithUnits newVal = sty.getNumberWithUnits();
421 if (!newVal.equals(y))
422 {
423 y = newVal;
424 shapeChange = true;
425 }
426 }
427
428 if (getPres(sty.setName("width")))
429 {
430 NumberWithUnits newVal = sty.getNumberWithUnits();
431 if (!newVal.equals(width))
432 {
433 width = newVal;
434 shapeChange = true;
435 }
436 }
437
438 if (getPres(sty.setName("height")))
439 {
440 NumberWithUnits newVal = sty.getNumberWithUnits();
441 if (!newVal.equals(height))
442 {
443 height = newVal;
444 shapeChange = true;
445 }
446 }
447
448 if (getPres(sty.setName("viewBox")))
449 {
450 float[] coords = sty.getFloatList();
451 Rectangle2D.Float newViewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
452 if (!newViewBox.equals(viewBox))
453 {
454 viewBox = newViewBox;
455 shapeChange = true;
456 }
457 }
458
459 if (shapeChange)
460 {
461 build();
462 }
463
464 return changeState || shapeChange;
465 }
466
467 /**
468 * @return the styleSheet
469 */
470 public StyleSheet getStyleSheet()
471 {
472 if (styleSheet == null)
473 {
474 for (int i = 0; i < getNumChildren(); ++i)
475 {
476 SVGElement ele = getChild(i);
477 if (ele instanceof Style)
478 {
479 return ((Style)ele).getStyleSheet();
480 }
481 }
482 }
483
484 return styleSheet;
485 }
486
487 /**
488 * @param styleSheet the styleSheet to set
489 */
490 public void setStyleSheet(StyleSheet styleSheet)
491 {
492 this.styleSheet = styleSheet;
493 }
494
495}
Note: See TracBrowser for help on using the repository browser.