source: josm/trunk/src/com/kitfox/svg/Tspan.java@ 7497

Last change on this file since 7497 was 6002, checked in by Don-vip, 11 years ago

fix #8742 - update svgsalamander to release 0.1.18+patch (fix bug SVGSALAMANDER-26) -> allow to open more SVG files

File size: 12.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 January 26, 2004, 1:56 AM
35 */
36package com.kitfox.svg;
37
38import com.kitfox.svg.xml.StyleAttribute;
39import java.awt.Graphics2D;
40import java.awt.Shape;
41import java.awt.font.FontRenderContext;
42import java.awt.font.GlyphMetrics;
43import java.awt.font.GlyphVector;
44import java.awt.geom.AffineTransform;
45import java.awt.geom.GeneralPath;
46import java.awt.geom.Rectangle2D;
47
48/**
49 * @author Mark McKay
50 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
51 */
52public class Tspan extends ShapeElement
53{
54
55 public static final String TAG_NAME = "tspan";
56 float[] x = null;
57 float[] y = null;
58 float[] dx = null;
59 float[] dy = null;
60 float[] rotate = null;
61 private String text = "";
62 float cursorX;
63 float cursorY;
64
65// Shape tspanShape;
66 /**
67 * Creates a new instance of Stop
68 */
69 public Tspan()
70 {
71 }
72
73 public String getTagName()
74 {
75 return TAG_NAME;
76 }
77
78 public float getCursorX()
79 {
80 return cursorX;
81 }
82
83 public float getCursorY()
84 {
85 return cursorY;
86 }
87
88 public void setCursorX(float cursorX)
89 {
90 this.cursorX = cursorX;
91 }
92
93 public void setCursorY(float cursorY)
94 {
95 this.cursorY = cursorY;
96 }
97 /*
98 public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
99 {
100 //Load style string
101 super.loaderStartElement(helper, attrs, parent);
102
103 String x = attrs.getValue("x");
104 String y = attrs.getValue("y");
105 String dx = attrs.getValue("dx");
106 String dy = attrs.getValue("dy");
107 String rotate = attrs.getValue("rotate");
108
109 if (x != null) this.x = XMLParseUtil.parseFloatList(x);
110 if (y != null) this.y = XMLParseUtil.parseFloatList(y);
111 if (dx != null) this.dx = XMLParseUtil.parseFloatList(dx);
112 if (dy != null) this.dy = XMLParseUtil.parseFloatList(dy);
113 if (rotate != null)
114 {
115 this.rotate = XMLParseUtil.parseFloatList(rotate);
116 for (int i = 0; i < this.rotate.length; i++)
117 this.rotate[i] = (float)Math.toRadians(this.rotate[i]);
118 }
119 }
120 */
121
122 /**
123 * Called during load process to add text scanned within a tag
124 */
125 public void loaderAddText(SVGLoaderHelper helper, String text)
126 {
127 this.text += text;
128 }
129
130 protected void build() throws SVGException
131 {
132 super.build();
133
134 StyleAttribute sty = new StyleAttribute();
135
136 if (getPres(sty.setName("x")))
137 {
138 x = sty.getFloatList();
139 }
140
141 if (getPres(sty.setName("y")))
142 {
143 y = sty.getFloatList();
144 }
145
146 if (getPres(sty.setName("dx")))
147 {
148 dx = sty.getFloatList();
149 }
150
151 if (getPres(sty.setName("dy")))
152 {
153 dy = sty.getFloatList();
154 }
155
156 if (getPres(sty.setName("rotate")))
157 {
158 rotate = sty.getFloatList();
159 for (int i = 0; i < this.rotate.length; i++)
160 {
161 rotate[i] = (float) Math.toRadians(this.rotate[i]);
162 }
163
164 }
165 }
166
167 public void addShape(GeneralPath addShape) throws SVGException
168 {
169 if (x != null)
170 {
171 cursorX = x[0];
172 } else if (dx != null)
173 {
174 cursorX += dx[0];
175 }
176
177 if (y != null)
178 {
179 cursorY = y[0];
180 } else if (dy != null)
181 {
182 cursorY += dy[0];
183 }
184
185 StyleAttribute sty = new StyleAttribute();
186
187 String fontFamily = null;
188 if (getStyle(sty.setName("font-family")))
189 {
190 fontFamily = sty.getStringValue();
191 }
192
193
194 float fontSize = 12f;
195 if (getStyle(sty.setName("font-size")))
196 {
197 fontSize = sty.getFloatValueWithUnits();
198 }
199
200 float letterSpacing = 0;
201 if (getStyle(sty.setName("letter-spacing")))
202 {
203 letterSpacing = sty.getFloatValueWithUnits();
204 }
205
206
207 //Get font
208 Font font = diagram.getUniverse().getFont(fontFamily);
209 if (font == null)
210 {
211 addShapeSysFont(addShape, font, fontFamily, fontSize, letterSpacing);
212 return;
213 }
214
215 FontFace fontFace = font.getFontFace();
216 int ascent = fontFace.getAscent();
217 float fontScale = fontSize / (float) ascent;
218
219 AffineTransform xform = new AffineTransform();
220
221 strokeWidthScalar = 1f / fontScale;
222
223 int posPtr = 1;
224
225 for (int i = 0; i < text.length(); i++)
226 {
227 xform.setToIdentity();
228 xform.setToTranslation(cursorX, cursorY);
229 xform.scale(fontScale, fontScale);
230 if (rotate != null)
231 {
232 xform.rotate(rotate[posPtr]);
233 }
234
235 String unicode = text.substring(i, i + 1);
236 MissingGlyph glyph = font.getGlyph(unicode);
237
238 Shape path = glyph.getPath();
239 if (path != null)
240 {
241 path = xform.createTransformedShape(path);
242 addShape.append(path, false);
243 }
244
245 if (x != null && posPtr < x.length)
246 {
247 cursorX = x[posPtr];
248 cursorY = y[posPtr++];
249 } else if (dx != null && posPtr < dx.length)
250 {
251 cursorX += dx[posPtr];
252 cursorY += dy[posPtr++];
253 }
254
255 cursorX += fontScale * glyph.getHorizAdvX() + letterSpacing;
256 }
257
258 strokeWidthScalar = 1f;
259 }
260
261 private void addShapeSysFont(GeneralPath addShape, Font font,
262 String fontFamily, float fontSize, float letterSpacing)
263 {
264 java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
265
266 FontRenderContext frc = new FontRenderContext(null, true, true);
267 GlyphVector textVector = sysFont.createGlyphVector(frc, text);
268
269 AffineTransform xform = new AffineTransform();
270
271 int posPtr = 1;
272 for (int i = 0; i < text.length(); i++)
273 {
274 xform.setToIdentity();
275 xform.setToTranslation(cursorX + i * letterSpacing, cursorY);
276 if (rotate != null)
277 {
278 xform.rotate(rotate[Math.min(i, rotate.length - 1)]);
279 }
280
281 String unicode = text.substring(i, i + 1);
282 Shape glyphOutline = textVector.getGlyphOutline(i);
283 GlyphMetrics glyphMetrics = textVector.getGlyphMetrics(i);
284
285 glyphOutline = xform.createTransformedShape(glyphOutline);
286 addShape.append(glyphOutline, false);
287
288 if (x != null && posPtr < x.length)
289 {
290 cursorX = x[posPtr];
291 cursorY = y[posPtr++];
292 } else if (dx != null && posPtr < dx.length)
293 {
294 cursorX += dx[posPtr];
295 cursorY += dy[posPtr++];
296 }
297 }
298 }
299
300 public void render(Graphics2D g) throws SVGException
301 {
302 if (x != null)
303 {
304 cursorX = x[0];
305 cursorY = y[0];
306 } else if (dx != null)
307 {
308 cursorX += dx[0];
309 cursorY += dy[0];
310 }
311
312 StyleAttribute sty = new StyleAttribute();
313
314 String fontFamily = null;
315 if (getPres(sty.setName("font-family")))
316 {
317 fontFamily = sty.getStringValue();
318 }
319
320
321 float fontSize = 12f;
322 if (getPres(sty.setName("font-size")))
323 {
324 fontSize = sty.getFloatValueWithUnits();
325 }
326
327 //Get font
328 Font font = diagram.getUniverse().getFont(fontFamily);
329 if (font == null)
330 {
331 System.err.println("Could not load font");
332 java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
333 renderSysFont(g, sysFont);
334 return;
335 }
336
337
338 FontFace fontFace = font.getFontFace();
339 int ascent = fontFace.getAscent();
340 float fontScale = fontSize / (float) ascent;
341
342 AffineTransform oldXform = g.getTransform();
343 AffineTransform xform = new AffineTransform();
344
345 strokeWidthScalar = 1f / fontScale;
346
347 int posPtr = 1;
348
349 for (int i = 0; i < text.length(); i++)
350 {
351 xform.setToTranslation(cursorX, cursorY);
352 xform.scale(fontScale, fontScale);
353 g.transform(xform);
354
355 String unicode = text.substring(i, i + 1);
356 MissingGlyph glyph = font.getGlyph(unicode);
357
358 Shape path = glyph.getPath();
359 if (path != null)
360 {
361 renderShape(g, path);
362 } else
363 {
364 glyph.render(g);
365 }
366
367 if (x != null && posPtr < x.length)
368 {
369 cursorX = x[posPtr];
370 cursorY = y[posPtr++];
371 } else if (dx != null && posPtr < dx.length)
372 {
373 cursorX += dx[posPtr];
374 cursorY += dy[posPtr++];
375 }
376
377 cursorX += fontScale * glyph.getHorizAdvX();
378
379 g.setTransform(oldXform);
380 }
381
382 strokeWidthScalar = 1f;
383 }
384
385 protected void renderSysFont(Graphics2D g, java.awt.Font font) throws SVGException
386 {
387 int posPtr = 1;
388 FontRenderContext frc = g.getFontRenderContext();
389
390 Shape textShape = font.createGlyphVector(frc, text).getOutline(cursorX, cursorY);
391 renderShape(g, textShape);
392 Rectangle2D rect = font.getStringBounds(text, frc);
393 cursorX += (float) rect.getWidth();
394 }
395
396 public Shape getShape()
397 {
398 return null;
399 //return shapeToParent(tspanShape);
400 }
401
402 public Rectangle2D getBoundingBox()
403 {
404 return null;
405 //return boundsToParent(tspanShape.getBounds2D());
406 }
407
408 /**
409 * Updates all attributes in this diagram associated with a time event. Ie,
410 * all attributes with track information.
411 *
412 * @return - true if this node has changed state as a result of the time
413 * update
414 */
415 public boolean updateTime(double curTime) throws SVGException
416 {
417 //Tspan does not change
418 return false;
419 }
420
421 public String getText()
422 {
423 return text;
424 }
425
426 public void setText(String text)
427 {
428 this.text = text;
429 }
430}
Note: See TracBrowser for help on using the repository browser.