com.kitfox.svg.Tspan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of svgSalamander Show documentation
Show all versions of svgSalamander Show documentation
A tool for displaying and playing SVG content using the Java2D.
/*
* SVG Salamander
* Copyright (c) 2004, Mark McKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Mark McKay can be contacted at [email protected]. Salamander and other
* projects can be found at http://www.kitfox.com
*
* Created on January 26, 2004, 1:56 AM
*/
package com.kitfox.svg;
import com.kitfox.svg.util.FontSystem;
import com.kitfox.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author Mark McKay
*/
public class Tspan extends ShapeElement
{
public static final String TAG_NAME = "tspan";
float[] x = null;
float[] y = null;
float[] dx = null;
float[] dy = null;
float[] rotate = null;
private String text = "";
// float cursorX;
// float cursorY;
// Shape tspanShape;
/**
* Creates a new instance of Stop
*/
public Tspan()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
// public float getCursorX()
// {
// return cursorX;
// }
//
// public float getCursorY()
// {
// return cursorY;
// }
//
// public void setCursorX(float cursorX)
// {
// this.cursorX = cursorX;
// }
//
// public void setCursorY(float cursorY)
// {
// this.cursorY = cursorY;
// }
/*
public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
{
//Load style string
super.loaderStartElement(helper, attrs, parent);
String x = attrs.getValue("x");
String y = attrs.getValue("y");
String dx = attrs.getValue("dx");
String dy = attrs.getValue("dy");
String rotate = attrs.getValue("rotate");
if (x != null) this.x = XMLParseUtil.parseFloatList(x);
if (y != null) this.y = XMLParseUtil.parseFloatList(y);
if (dx != null) this.dx = XMLParseUtil.parseFloatList(dx);
if (dy != null) this.dy = XMLParseUtil.parseFloatList(dy);
if (rotate != null)
{
this.rotate = XMLParseUtil.parseFloatList(rotate);
for (int i = 0; i < this.rotate.length; i++)
this.rotate[i] = (float)Math.toRadians(this.rotate[i]);
}
}
*/
/**
* Called during load process to add text scanned within a tag
*/
@Override
public void loaderAddText(SVGLoaderHelper helper, String text)
{
this.text += text;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getFloatList();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatList();
}
if (getPres(sty.setName("dx")))
{
dx = sty.getFloatList();
}
if (getPres(sty.setName("dy")))
{
dy = sty.getFloatList();
}
if (getPres(sty.setName("rotate")))
{
rotate = sty.getFloatList();
for (int i = 0; i < this.rotate.length; i++)
{
rotate[i] = (float) Math.toRadians(this.rotate[i]);
}
}
}
public void appendToShape(GeneralPath addShape, Point2D cursor) throws SVGException
{
StyleAttribute sty = new StyleAttribute();
String fontFamily = null;
if (getStyle(sty.setName("font-family")))
{
fontFamily = sty.getStringValue();
}
float fontSize = 12f;
if (getStyle(sty.setName("font-size")))
{
fontSize = sty.getFloatValueWithUnits();
}
float letterSpacing = 0;
if (getStyle(sty.setName("letter-spacing")))
{
letterSpacing = sty.getFloatValueWithUnits();
}
int fontStyle = 0;
if (getStyle(sty.setName("font-style")))
{
String s = sty.getStringValue();
if ("normal".equals(s))
{
fontStyle = Text.TXST_NORMAL;
} else if ("italic".equals(s))
{
fontStyle = Text.TXST_ITALIC;
} else if ("oblique".equals(s))
{
fontStyle = Text.TXST_OBLIQUE;
}
} else
{
fontStyle = Text.TXST_NORMAL;
}
int fontWeight = 0;
if (getStyle(sty.setName("font-weight")))
{
String s = sty.getStringValue();
if ("normal".equals(s))
{
fontWeight = Text.TXWE_NORMAL;
} else if ("bold".equals(s))
{
fontWeight = Text.TXWE_BOLD;
}
} else
{
fontWeight = Text.TXWE_NORMAL;
}
//Get font
Font font = diagram.getUniverse().getFont(fontFamily);
if (font == null && fontFamily != null)
{
font = FontSystem.createFont(fontFamily, fontStyle, fontWeight, (int)fontSize);
// addShapeSysFont(addShape, font, fontFamily, fontSize, letterSpacing, cursor);
// return;
}
if (font == null)
{
font = FontSystem.createFont("Serif", fontStyle, fontWeight, fontStyle);
}
// FontFace fontFace = font.getFontFace();
// int ascent = fontFace.getAscent();
// float fontScale = fontSize / (float) ascent;
AffineTransform xform = new AffineTransform();
// strokeWidthScalar = 1f / fontScale;
float cursorX = (float)cursor.getX();
float cursorY = (float)cursor.getY();
// int i = 0;
String drawText = this.text;
drawText = drawText.trim();
for (int i = 0; i < drawText.length(); i++)
{
if (x != null && i < x.length)
{
cursorX = x[i];
} else if (dx != null && i < dx.length)
{
cursorX += dx[i];
}
if (y != null && i < y.length)
{
cursorY = y[i];
} else if (dy != null && i < dy.length)
{
cursorY += dy[i];
}
// i++;
xform.setToIdentity();
xform.setToTranslation(cursorX, cursorY);
// xform.scale(fontScale, fontScale);
if (rotate != null)
{
xform.rotate(rotate[i]);
}
String unicode = drawText.substring(i, i + 1);
MissingGlyph glyph = font.getGlyph(unicode);
Shape path = glyph.getPath();
if (path != null)
{
path = xform.createTransformedShape(path);
addShape.append(path, false);
}
// cursorX += fontScale * glyph.getHorizAdvX() + letterSpacing;
cursorX += glyph.getHorizAdvX() + letterSpacing;
}
//Save final draw point so calling method knows where to begin next
// text draw
cursor.setLocation(cursorX, cursorY);
strokeWidthScalar = 1f;
}
// private void addShapeSysFont(GeneralPath addShape, Font font,
// String fontFamily, float fontSize, float letterSpacing, Point2D cursor)
// {
//
// java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
//
// FontRenderContext frc = new FontRenderContext(null, true, true);
// String renderText = this.text.trim();
//
// AffineTransform xform = new AffineTransform();
//
// float cursorX = (float)cursor.getX();
// float cursorY = (float)cursor.getY();
//// int i = 0;
// for (int i = 0; i < renderText.length(); i++)
// {
// if (x != null && i < x.length)
// {
// cursorX = x[i];
// } else if (dx != null && i < dx.length)
// {
// cursorX += dx[i];
// }
//
// if (y != null && i < y.length)
// {
// cursorY = y[i];
// } else if (dy != null && i < dy.length)
// {
// cursorY += dy[i];
// }
//// i++;
//
// xform.setToIdentity();
// xform.setToTranslation(cursorX, cursorY);
// if (rotate != null)
// {
// xform.rotate(rotate[Math.min(i, rotate.length - 1)]);
// }
//
//// String unicode = renderText.substring(i, i + 1);
// GlyphVector textVector = sysFont.createGlyphVector(frc, renderText.substring(i, i + 1));
// Shape glyphOutline = textVector.getGlyphOutline(0);
// GlyphMetrics glyphMetrics = textVector.getGlyphMetrics(0);
//
// glyphOutline = xform.createTransformedShape(glyphOutline);
// addShape.append(glyphOutline, false);
//
//
//// cursorX += fontScale * glyph.getHorizAdvX() + letterSpacing;
// cursorX += glyphMetrics.getAdvance() + letterSpacing;
// }
//
// cursor.setLocation(cursorX, cursorY);
// }
@Override
public void render(Graphics2D g) throws SVGException
{
float cursorX = 0;
float cursorY = 0;
if (x != null)
{
cursorX = x[0];
cursorY = y[0];
} else if (dx != null)
{
cursorX += dx[0];
cursorY += dy[0];
}
StyleAttribute sty = new StyleAttribute();
String fontFamily = null;
if (getPres(sty.setName("font-family")))
{
fontFamily = sty.getStringValue();
}
float fontSize = 12f;
if (getPres(sty.setName("font-size")))
{
fontSize = sty.getFloatValueWithUnits();
}
//Get font
Font font = diagram.getUniverse().getFont(fontFamily);
if (font == null)
{
System.err.println("Could not load font");
java.awt.Font sysFont = new java.awt.Font(fontFamily, java.awt.Font.PLAIN, (int) fontSize);
renderSysFont(g, sysFont);
return;
}
FontFace fontFace = font.getFontFace();
int ascent = fontFace.getAscent();
float fontScale = fontSize / (float) ascent;
AffineTransform oldXform = g.getTransform();
AffineTransform xform = new AffineTransform();
strokeWidthScalar = 1f / fontScale;
int posPtr = 1;
for (int i = 0; i < text.length(); i++)
{
xform.setToTranslation(cursorX, cursorY);
xform.scale(fontScale, fontScale);
g.transform(xform);
String unicode = text.substring(i, i + 1);
MissingGlyph glyph = font.getGlyph(unicode);
Shape path = glyph.getPath();
if (path != null)
{
renderShape(g, path);
} else
{
glyph.render(g);
}
if (x != null && posPtr < x.length)
{
cursorX = x[posPtr];
cursorY = y[posPtr++];
} else if (dx != null && posPtr < dx.length)
{
cursorX += dx[posPtr];
cursorY += dy[posPtr++];
}
cursorX += fontScale * glyph.getHorizAdvX();
g.setTransform(oldXform);
}
strokeWidthScalar = 1f;
}
protected void renderSysFont(Graphics2D g, java.awt.Font font) throws SVGException
{
float cursorX = 0;
float cursorY = 0;
FontRenderContext frc = g.getFontRenderContext();
Shape textShape = font.createGlyphVector(frc, text).getOutline(cursorX, cursorY);
renderShape(g, textShape);
Rectangle2D rect = font.getStringBounds(text, frc);
cursorX += (float) rect.getWidth();
}
@Override
public Shape getShape()
{
return null;
//return shapeToParent(tspanShape);
}
@Override
public Rectangle2D getBoundingBox()
{
return null;
//return boundsToParent(tspanShape.getBounds2D());
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Tspan does not change
return false;
}
public String getText()
{
return text;
}
public void setText(String text)
{
this.text = text;
}
}