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

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

see #14319, see #16838 - fix regressions introduced in svgSalamander 1.1.2

see https://github.com/blackears/svgSalamander/issues/29

  • Property svn:eol-style set to native
File size: 13.4 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 = FontSystem.createFont(fontFamily, fontStyle, fontWeight, (int)fontSize);
234 }
235
236 if (font == null)
237 {
238 font = FontSystem.createFont("Serif", fontStyle, fontWeight, fontStyle);
239 }
240
241 AffineTransform xform = new AffineTransform();
242
243 float cursorX = (float)cursor.getX();
244 float cursorY = (float)cursor.getY();
245
246 String drawText = this.text;
247 drawText = drawText.trim();
248 for (int i = 0; i < drawText.length(); i++)
249 {
250 if (x != null && i < x.length)
251 {
252 cursorX = x[i];
253 } else if (dx != null && i < dx.length)
254 {
255 cursorX += dx[i];
256 }
257
258 if (y != null && i < y.length)
259 {
260 cursorY = y[i];
261 } else if (dy != null && i < dy.length)
262 {
263 cursorY += dy[i];
264 }
265
266 xform.setToIdentity();
267 xform.setToTranslation(cursorX, cursorY);
268 if (rotate != null)
269 {
270 xform.rotate(rotate[i]);
271 }
272
273 String unicode = drawText.substring(i, i + 1);
274 MissingGlyph glyph = font.getGlyph(unicode);
275
276 Shape path = glyph.getPath();
277 if (path != null)
278 {
279 path = xform.createTransformedShape(path);
280 addShape.append(path, false);
281 }
282
283 cursorX += glyph.getHorizAdvX() + letterSpacing;
284 }
285
286 //Save final draw point so calling method knows where to begin next
287 // text draw
288 cursor.setLocation(cursorX, cursorY);
289 strokeWidthScalar = 1f;
290 }
291
292// private void addShapeSysFont(GeneralPath addShape, Font font,
293// String fontFamily, float fontSize, float letterSpacing, Point2D cursor)
294// {
295//
296// java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
297//
298// FontRenderContext frc = new FontRenderContext(null, true, true);
299// String renderText = this.text.trim();
300//
301// AffineTransform xform = new AffineTransform();
302//
303// float cursorX = (float)cursor.getX();
304// float cursorY = (float)cursor.getY();
305//// int i = 0;
306// for (int i = 0; i < renderText.length(); i++)
307// {
308// if (x != null && i < x.length)
309// {
310// cursorX = x[i];
311// } else if (dx != null && i < dx.length)
312// {
313// cursorX += dx[i];
314// }
315//
316// if (y != null && i < y.length)
317// {
318// cursorY = y[i];
319// } else if (dy != null && i < dy.length)
320// {
321// cursorY += dy[i];
322// }
323//// i++;
324//
325// xform.setToIdentity();
326// xform.setToTranslation(cursorX, cursorY);
327// if (rotate != null)
328// {
329// xform.rotate(rotate[Math.min(i, rotate.length - 1)]);
330// }
331//
332//// String unicode = renderText.substring(i, i + 1);
333// GlyphVector textVector = sysFont.createGlyphVector(frc, renderText.substring(i, i + 1));
334// Shape glyphOutline = textVector.getGlyphOutline(0);
335// GlyphMetrics glyphMetrics = textVector.getGlyphMetrics(0);
336//
337// glyphOutline = xform.createTransformedShape(glyphOutline);
338// addShape.append(glyphOutline, false);
339//
340//
341//// cursorX += fontScale * glyph.getHorizAdvX() + letterSpacing;
342// cursorX += glyphMetrics.getAdvance() + letterSpacing;
343// }
344//
345// cursor.setLocation(cursorX, cursorY);
346// }
347
348 @Override
349 public void render(Graphics2D g) throws SVGException
350 {
351 float cursorX = 0;
352 float cursorY = 0;
353
354 if (x != null)
355 {
356 cursorX = x[0];
357 cursorY = y[0];
358 } else if (dx != null)
359 {
360 cursorX += dx[0];
361 cursorY += dy[0];
362 }
363
364 StyleAttribute sty = new StyleAttribute();
365
366 String fontFamily = null;
367 if (getPres(sty.setName("font-family")))
368 {
369 fontFamily = sty.getStringValue();
370 }
371
372
373 float fontSize = 12f;
374 if (getPres(sty.setName("font-size")))
375 {
376 fontSize = sty.getFloatValueWithUnits();
377 }
378
379 //Get font
380 Font font = diagram.getUniverse().getFont(fontFamily);
381 if (font == null)
382 {
383 System.err.println("Could not load font");
384 java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
385 renderSysFont(g, sysFont);
386 return;
387 }
388
389
390 FontFace fontFace = font.getFontFace();
391 int ascent = fontFace.getAscent();
392 float fontScale = fontSize / (float) ascent;
393
394 AffineTransform oldXform = g.getTransform();
395 AffineTransform xform = new AffineTransform();
396
397 strokeWidthScalar = 1f / fontScale;
398
399 int posPtr = 1;
400
401 for (int i = 0; i < text.length(); i++)
402 {
403 xform.setToTranslation(cursorX, cursorY);
404 xform.scale(fontScale, fontScale);
405 g.transform(xform);
406
407 String unicode = text.substring(i, i + 1);
408 MissingGlyph glyph = font.getGlyph(unicode);
409
410 Shape path = glyph.getPath();
411 if (path != null)
412 {
413 renderShape(g, path);
414 } else
415 {
416 glyph.render(g);
417 }
418
419 if (x != null && posPtr < x.length)
420 {
421 cursorX = x[posPtr];
422 cursorY = y[posPtr++];
423 } else if (dx != null && posPtr < dx.length)
424 {
425 cursorX += dx[posPtr];
426 cursorY += dy[posPtr++];
427 }
428
429 cursorX += fontScale * glyph.getHorizAdvX();
430
431 g.setTransform(oldXform);
432 }
433
434 strokeWidthScalar = 1f;
435 }
436
437 protected void renderSysFont(Graphics2D g, java.awt.Font font) throws SVGException
438 {
439 float cursorX = 0;
440 float cursorY = 0;
441
442 FontRenderContext frc = g.getFontRenderContext();
443
444 Shape textShape = font.createGlyphVector(frc, text).getOutline(cursorX, cursorY);
445 renderShape(g, textShape);
446 Rectangle2D rect = font.getStringBounds(text, frc);
447 cursorX += (float) rect.getWidth();
448 }
449
450 @Override
451 public Shape getShape()
452 {
453 return null;
454 //return shapeToParent(tspanShape);
455 }
456
457 @Override
458 public Rectangle2D getBoundingBox()
459 {
460 return null;
461 //return boundsToParent(tspanShape.getBounds2D());
462 }
463
464 /**
465 * Updates all attributes in this diagram associated with a time event. Ie,
466 * all attributes with track information.
467 *
468 * @return - true if this node has changed state as a result of the time
469 * update
470 */
471 @Override
472 public boolean updateTime(double curTime) throws SVGException
473 {
474 //Tspan does not change
475 return false;
476 }
477
478 public String getText()
479 {
480 return text;
481 }
482
483 public void setText(String text)
484 {
485 this.text = text;
486 }
487}
Note: See TracBrowser for help on using the repository browser.