package org.apache.batik.bridge;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.StringTokenizer;
import java.util.List;
import java.util.ArrayList;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.font.GVTFontFace;
import org.apache.batik.gvt.font.Glyph;
import org.apache.batik.gvt.text.TextPaintInfo;
import org.apache.batik.parser.AWTPathProducer;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.PathParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SVGGlyphElementBridge extends AbstractSVGBridge
implements ErrorConstants {
protected SVGGlyphElementBridge() {}
public String getLocalName() {
return SVG_GLYPH_TAG;
}
public Glyph createGlyph(BridgeContext ctx,
Element glyphElement,
Element textElement,
int glyphCode,
float fontSize,
GVTFontFace fontFace,
TextPaintInfo tpi) {
float fontHeight = fontFace.getUnitsPerEm();
float scale = fontSize/fontHeight;
AffineTransform scaleTransform
= AffineTransform.getScaleInstance(scale, -scale);
String d = glyphElement.getAttributeNS(null, SVG_D_ATTRIBUTE);
Shape dShape = null;
if (d.length() != 0) {
AWTPathProducer app = new AWTPathProducer();
app.setWindingRule(CSSUtilities.convertFillRule(textElement));
try {
PathParser pathParser = new PathParser();
pathParser.setPathHandler(app);
pathParser.parse(d);
} catch (ParseException pEx) {
throw new BridgeException(ctx, glyphElement,
pEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_D_ATTRIBUTE});
} finally {
Shape shape = app.getShape();
Shape transformedShape
= scaleTransform.createTransformedShape(shape);
dShape = transformedShape;
}
}
NodeList glyphChildren = glyphElement.getChildNodes();
int numChildren = glyphChildren.getLength();
int numGlyphChildren = 0;
for (int i = 0; i < numChildren; i++) {
Node childNode = glyphChildren.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
numGlyphChildren++;
}
}
CompositeGraphicsNode glyphContentNode = null;
if (numGlyphChildren > 0) {
GVTBuilder builder = ctx.getGVTBuilder();
glyphContentNode = new CompositeGraphicsNode();
Element fontElementClone
= (Element)glyphElement.getParentNode().cloneNode(false);
NamedNodeMap fontAttributes
= glyphElement.getParentNode().getAttributes();
int numAttributes = fontAttributes.getLength();
for (int i = 0; i < numAttributes; i++) {
fontElementClone.setAttributeNode((Attr)fontAttributes.item(i));
}
Element clonedGlyphElement = (Element)glyphElement.cloneNode(true);
fontElementClone.appendChild(clonedGlyphElement);
textElement.appendChild(fontElementClone);
CompositeGraphicsNode glyphChildrenNode
= new CompositeGraphicsNode();
glyphChildrenNode.setTransform(scaleTransform);
NodeList clonedGlyphChildren = clonedGlyphElement.getChildNodes();
int numClonedChildren = clonedGlyphChildren.getLength();
for (int i = 0; i < numClonedChildren; i++) {
Node childNode = clonedGlyphChildren.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element)childNode;
GraphicsNode childGraphicsNode =
builder.build(ctx, childElement);
glyphChildrenNode.add(childGraphicsNode);
}
}
glyphContentNode.add(glyphChildrenNode);
textElement.removeChild(fontElementClone);
}
String unicode
= glyphElement.getAttributeNS(null, SVG_UNICODE_ATTRIBUTE);
String nameList
= glyphElement.getAttributeNS(null, SVG_GLYPH_NAME_ATTRIBUTE);
List names = new ArrayList();
StringTokenizer st = new StringTokenizer(nameList, " ,");
while (st.hasMoreTokens()) {
names.add(st.nextToken());
}
String orientation
= glyphElement.getAttributeNS(null, SVG_ORIENTATION_ATTRIBUTE);
String arabicForm
= glyphElement.getAttributeNS(null, SVG_ARABIC_FORM_ATTRIBUTE);
String lang = glyphElement.getAttributeNS(null, SVG_LANG_ATTRIBUTE);
Element parentFontElement = (Element)glyphElement.getParentNode();
String s = glyphElement.getAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE);
if (s.length() == 0) {
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE);
if (s.length() == 0) {
throw new BridgeException
(ctx, parentFontElement, ERR_ATTRIBUTE_MISSING,
new Object[] {SVG_HORIZ_ADV_X_ATTRIBUTE});
}
}
float horizAdvX;
try {
horizAdvX = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, glyphElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_HORIZ_ADV_X_ATTRIBUTE, s});
}
s = glyphElement.getAttributeNS(null, SVG_VERT_ADV_Y_ATTRIBUTE);
if (s.length() == 0) {
s = parentFontElement.getAttributeNS(null, SVG_VERT_ADV_Y_ATTRIBUTE);
if (s.length() == 0) {
s = String.valueOf(fontFace.getUnitsPerEm());
}
}
float vertAdvY;
try {
vertAdvY = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, glyphElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_VERT_ADV_Y_ATTRIBUTE, s});
}
s = glyphElement.getAttributeNS(null, SVG_VERT_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
s = parentFontElement.getAttributeNS(null, SVG_VERT_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
s = Float.toString(horizAdvX/2);
}
}
float vertOriginX;
try {
vertOriginX = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, glyphElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_VERT_ORIGIN_X_ATTRIBUTE, s});
}
s = glyphElement.getAttributeNS(null, SVG_VERT_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
s = parentFontElement.getAttributeNS(null, SVG_VERT_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
s = String.valueOf(fontFace.getAscent());
}
}
float vertOriginY;
try {
vertOriginY = SVGUtilities.convertSVGNumber(s) * -scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, glyphElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_VERT_ORIGIN_Y_ATTRIBUTE, s});
}
Point2D vertOrigin = new Point2D.Float(vertOriginX, vertOriginY);
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
s = SVG_HORIZ_ORIGIN_X_DEFAULT_VALUE;
}
float horizOriginX;
try {
horizOriginX = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, parentFontElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_HORIZ_ORIGIN_X_ATTRIBUTE, s});
}
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
s = SVG_HORIZ_ORIGIN_Y_DEFAULT_VALUE;
}
float horizOriginY;
try {
horizOriginY = SVGUtilities.convertSVGNumber(s) * -scale;
} catch (NumberFormatException nfEx ) {
throw new BridgeException
(ctx, glyphElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_HORIZ_ORIGIN_Y_ATTRIBUTE, s});
}
Point2D horizOrigin = new Point2D.Float(horizOriginX, horizOriginY);
return new Glyph(unicode, names, orientation,
arabicForm, lang, horizOrigin, vertOrigin,
horizAdvX, vertAdvY, glyphCode,
tpi, dShape, glyphContentNode);
}
}