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

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