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

Last change on this file since 14331 was 14331, checked in by Don-vip, 5 months 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.