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

Last change on this file since 9171 was 8084, checked in by bastiK, 9 years ago

add svn:eol-style=native for svgsalamander

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