From 091a1e0179cb264cc2cab6e3b11ea31045c8536d Mon Sep 17 00:00:00 2001 From: kitfox Date: Tue, 29 May 2007 23:33:23 +0000 Subject: Restoring SVG Salamander to it's original code base, and updating build scripts. git-svn-id: https://svn.java.net/svn/svgsalamander~svn/trunk/svg-core@36 7dc7fa77-23fb-e6ad-8e2e-c86bd48ed22b --- src/main/java/com/kitfox/svg/Text.java | 539 +++++++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 src/main/java/com/kitfox/svg/Text.java (limited to 'src/main/java/com/kitfox/svg/Text.java') diff --git a/src/main/java/com/kitfox/svg/Text.java b/src/main/java/com/kitfox/svg/Text.java new file mode 100644 index 0000000..1256419 --- /dev/null +++ b/src/main/java/com/kitfox/svg/Text.java @@ -0,0 +1,539 @@ +/* + * Stop.java + * + * + * The Salamander Project - 2D and 3D graphics libraries in Java + * Copyright (C) 2004 Mark McKay + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Mark McKay can be contacted at mark@kitfox.com. 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.xml.StyleAttribute; +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.util.*; +import java.util.regex.*; + +//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public class Text extends ShapeElement +{ + + float x = 0; + float y = 0; + AffineTransform transform = null; + + String fontFamily; + float fontSize; + + //List of strings and tspans containing the content of this node + LinkedList content = new LinkedList(); + + Shape textShape; + + public static final int TXAN_START = 0; + public static final int TXAN_MIDDLE = 1; + public static final int TXAN_END = 2; + int textAnchor = TXAN_START; + + public static final int TXST_NORMAL = 0; + public static final int TXST_ITALIC = 1; + public static final int TXST_OBLIQUE = 2; + int fontStyle; + + public static final int TXWE_NORMAL = 0; + public static final int TXWE_BOLD = 1; + public static final int TXWE_BOLDER = 2; + public static final int TXWE_LIGHTER = 3; + public static final int TXWE_100 = 4; + public static final int TXWE_200 = 5; + public static final int TXWE_300 = 6; + public static final int TXWE_400 = 7; + public static final int TXWE_500 = 8; + public static final int TXWE_600 = 9; + public static final int TXWE_700 = 10; + public static final int TXWE_800 = 11; + public static final int TXWE_900 = 12; + int fontWeight; + + /** Creates a new instance of Stop */ + public Text() + { + } + + public void appendText(String text) + { + content.addLast(text); + } + + public void appendTspan(Tspan tspan) throws SVGElementException + { + super.loaderAddChild(null, tspan); + content.addLast(tspan); +// tspan.setParent(this); + } + + /** + * Discard cached information + */ + public void rebuild() throws SVGException + { + build(); + } + + public java.util.List getContent() + { + return content; + } +/* + 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 transform = attrs.getValue("transform"); + + this.x = XMLParseUtil.parseFloat(x); + this.y = XMLParseUtil.parseFloat(y); + } + */ + /** + * Called after the start element but before the end element to indicate + * each child tag that has been processed + */ + public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException + { + super.loaderAddChild(helper, child); + + content.addLast(child); + } + + /** + * Called during load process to add text scanned within a tag + */ + public void loaderAddText(SVGLoaderHelper helper, String text) + { + Matcher matchWs = Pattern.compile("\\s*").matcher(text); + if (!matchWs.matches()) content.addLast(text); + } + + public void build() throws SVGException + { + super.build(); + + StyleAttribute sty = new StyleAttribute(); + + if (getPres(sty.setName("x"))) x = sty.getFloatValueWithUnits(); + + if (getPres(sty.setName("y"))) y = sty.getFloatValueWithUnits(); + + if (getStyle(sty.setName("font-family"))) fontFamily = sty.getStringValue(); + else fontFamily = "Sans Serif"; + + if (getStyle(sty.setName("font-size"))) fontSize = sty.getFloatValueWithUnits(); + else fontSize = 12f; + + if (getStyle(sty.setName("font-style"))) + { + String s = sty.getStringValue(); + if ("normal".equals(s)) + { + fontStyle = TXST_NORMAL; + } + else if ("italic".equals(s)) + { + fontStyle = TXST_ITALIC; + } + else if ("oblique".equals(s)) + { + fontStyle = TXST_OBLIQUE; + } + } + else fontStyle = TXST_NORMAL; + + if (getStyle(sty.setName("font-weight"))) + { + String s = sty.getStringValue(); + if ("normal".equals(s)) + { + fontWeight = TXWE_NORMAL; + } + else if ("bold".equals(s)) + { + fontWeight = TXWE_BOLD; + } + } + else fontWeight = TXWE_BOLD; + + if (getStyle(sty.setName("text-anchor"))) + { + String s = sty.getStringValue(); + if (s.equals("middle")) textAnchor = TXAN_MIDDLE; + else if (s.equals("end")) textAnchor = TXAN_END; + else textAnchor = TXAN_START; + } + else textAnchor = TXAN_START; + + //text anchor + //text-decoration + //text-rendering + + buildFont(); + } + + protected void buildFont() throws SVGException + { + int style; + switch (fontStyle) + { + case TXST_ITALIC: + style = java.awt.Font.ITALIC; + break; + default: + style = java.awt.Font.PLAIN; + break; + } + + int weight; + switch (fontWeight) + { + case TXWE_BOLD: + case TXWE_BOLDER: + weight = java.awt.Font.BOLD; + break; + default: + weight = java.awt.Font.PLAIN; + break; + } + + //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, style | weight, (int)fontSize); + buildSysFont(sysFont); + return; + } + +// font = new java.awt.Font(font.getFamily(), style | weight, font.getSize()); + +// Area textArea = new Area(); + GeneralPath textPath = new GeneralPath(); + textShape = textPath; + + float cursorX = x, cursorY = y; + + FontFace fontFace = font.getFontFace(); + //int unitsPerEm = fontFace.getUnitsPerEm(); + int ascent = fontFace.getAscent(); + float fontScale = fontSize / (float)ascent; + +// AffineTransform oldXform = g.getTransform(); + AffineTransform xform = new AffineTransform(); + + for (Iterator it = content.iterator(); it.hasNext();) + { + Object obj = it.next(); + + if (obj instanceof String) + { + String text = (String)obj; + + strokeWidthScalar = 1f / fontScale; + + for (int i = 0; i < text.length(); i++) + { + xform.setToIdentity(); + 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) + { + path = xform.createTransformedShape(path); + textPath.append(path, false); + } +// else glyph.render(g); + + cursorX += fontScale * glyph.getHorizAdvX(); + +// g.setTransform(oldXform); + } + + strokeWidthScalar = 1f; + } + else if (obj instanceof Tspan) + { + Tspan tspan = (Tspan)obj; + + xform.setToIdentity(); + xform.setToTranslation(cursorX, cursorY); + xform.scale(fontScale, fontScale); +// tspan.setCursorX(cursorX); +// tspan.setCursorY(cursorY); + + Shape tspanShape = tspan.getShape(); + tspanShape = xform.createTransformedShape(tspanShape); + textPath.append(tspanShape, false); +// tspan.render(g); +// cursorX = tspan.getCursorX(); +// cursorY = tspan.getCursorY(); + } + + } + + switch (textAnchor) + { + case TXAN_MIDDLE: + { + AffineTransform at = new AffineTransform(); + at.translate(-textPath.getBounds2D().getWidth() / 2, 0); + textPath.transform(at); + break; + } + case TXAN_END: + { + AffineTransform at = new AffineTransform(); + at.translate(-textPath.getBounds2D().getWidth(), 0); + textPath.transform(at); + break; + } + } + } + + private void buildSysFont(java.awt.Font font) throws SVGException + { + GeneralPath textPath = new GeneralPath(); + textShape = textPath; + + float cursorX = x, cursorY = y; + +// FontMetrics fm = g.getFontMetrics(font); + FontRenderContext frc = new FontRenderContext(null, true, true); + +// FontFace fontFace = font.getFontFace(); + //int unitsPerEm = fontFace.getUnitsPerEm(); +// int ascent = fm.getAscent(); +// float fontScale = fontSize / (float)ascent; + +// AffineTransform oldXform = g.getTransform(); + AffineTransform xform = new AffineTransform(); + + for (Iterator it = content.iterator(); it.hasNext();) + { + Object obj = it.next(); + + if (obj instanceof String) + { + String text = (String)obj; + + Shape textShape = font.createGlyphVector(frc, text).getOutline(cursorX, cursorY); + textPath.append(textShape, false); +// renderShape(g, textShape); +// g.drawString(text, cursorX, cursorY); + + Rectangle2D rect = font.getStringBounds(text, frc); + cursorX += (float)rect.getWidth(); + } + else if (obj instanceof Tspan) + { + /* + Tspan tspan = (Tspan)obj; + + xform.setToIdentity(); + xform.setToTranslation(cursorX, cursorY); + + Shape tspanShape = tspan.getShape(); + tspanShape = xform.createTransformedShape(tspanShape); + textArea.add(new Area(tspanShape)); + + cursorX += tspanShape.getBounds2D().getWidth(); + */ + + + Tspan tspan = (Tspan)obj; + tspan.setCursorX(cursorX); + tspan.setCursorY(cursorY); + tspan.addShape(textPath); + cursorX = tspan.getCursorX(); + cursorY = tspan.getCursorY(); + + } + } + + switch (textAnchor) + { + case TXAN_MIDDLE: + { + AffineTransform at = new AffineTransform(); + at.translate(-textPath.getBounds2D().getWidth() / 2, 0); + textPath.transform(at); + break; + } + case TXAN_END: + { + AffineTransform at = new AffineTransform(); + at.translate(-textPath.getBounds2D().getWidth(), 0); + textPath.transform(at); + break; + } + } + } + + + public void render(Graphics2D g) throws SVGException + { + beginLayer(g); + renderShape(g, textShape); + finishLayer(g); + } + + public Shape getShape() + { + return shapeToParent(textShape); + } + + public Rectangle2D getBoundingBox() throws SVGException + { + return boundsToParent(includeStrokeInBounds(textShape.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 + */ + public boolean updateTime(double curTime) throws SVGException + { +// if (trackManager.getNumTracks() == 0) return false; + boolean changeState = super.updateTime(curTime); + + //Get current values for parameters + StyleAttribute sty = new StyleAttribute(); + boolean shapeChange = false; + + if (getPres(sty.setName("x"))) + { + float newVal = sty.getFloatValueWithUnits(); + if (newVal != x) + { + x = newVal; + shapeChange = true; + } + } + + if (getPres(sty.setName("y"))) + { + float newVal = sty.getFloatValueWithUnits(); + if (newVal != y) + { + y = newVal; + shapeChange = true; + } + } + + if (getPres(sty.setName("font-family"))) + { + String newVal = sty.getStringValue(); + if (!newVal.equals(fontFamily)) + { + fontFamily = newVal; + shapeChange = true; + } + } + + if (getPres(sty.setName("font-size"))) + { + float newVal = sty.getFloatValueWithUnits(); + if (newVal != fontSize) + { + fontSize = newVal; + shapeChange = true; + } + } + + + if (getStyle(sty.setName("font-style"))) + { + String s = sty.getStringValue(); + int newVal = fontStyle; + if ("normal".equals(s)) + { + newVal = TXST_NORMAL; + } + else if ("italic".equals(s)) + { + newVal = TXST_ITALIC; + } + else if ("oblique".equals(s)) + { + newVal = TXST_OBLIQUE; + } + if (newVal != fontStyle) + { + fontStyle = newVal; + shapeChange = true; + } + } + + if (getStyle(sty.setName("font-weight"))) + { + String s = sty.getStringValue(); + int newVal = fontWeight; + if ("normal".equals(s)) + { + newVal = TXWE_NORMAL; + } + else if ("bold".equals(s)) + { + newVal = TXWE_BOLD; + } + if (newVal != fontWeight) + { + fontWeight = newVal; + shapeChange = true; + } + } + + if (shapeChange) + { + buildFont(); + return true; + } + + return changeState; + } +} -- cgit v1.2.3-55-g7522