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

Last change on this file since 7676 was 7676, checked in by stoecker, 11 years ago

update SVG code to current SVN (fix line endings), see #10479

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