in batik-bridge/src/main/java/org/apache/batik/bridge/SVGGlyphElementBridge.java [77:327]
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);
// create a shape that represents the d attribute
String d = glyphElement.getAttributeNS(null, SVG_D_ATTRIBUTE);
Shape dShape = null;
if (d.length() != 0) {
AWTPathProducer app = new AWTPathProducer();
// Glyph is supposed to use properties from text element.
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 {
// transform the shape into the correct coord system
Shape shape = app.getShape();
Shape transformedShape
= scaleTransform.createTransformedShape(shape);
dShape = transformedShape;
}
}
// process any glyph children
// first see if there are any, because don't want to do the following
// bit of code if we can avoid it
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) { // the glyph has child elements
// build the GVT tree that represents the glyph children
GVTBuilder builder = ctx.getGVTBuilder();
glyphContentNode = new CompositeGraphicsNode();
//
// need to clone the parent font element and glyph element
// this is so that the glyph doesn't inherit anything past the font element
//
Element fontElementClone
= (Element)glyphElement.getParentNode().cloneNode(false);
// copy all font attributes over
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);
}
// set up glyph attributes
// unicode
String unicode
= glyphElement.getAttributeNS(null, SVG_UNICODE_ATTRIBUTE);
// glyph-name
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());
}
// orientation
String orientation
= glyphElement.getAttributeNS(null, SVG_ORIENTATION_ATTRIBUTE);
// arabicForm
String arabicForm
= glyphElement.getAttributeNS(null, SVG_ARABIC_FORM_ATTRIBUTE);
// lang
String lang = glyphElement.getAttributeNS(null, SVG_LANG_ATTRIBUTE);
Element parentFontElement = (Element)glyphElement.getParentNode();
// horz-adv-x
String s = glyphElement.getAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE);
if (s.length() == 0) {
// look for attribute on parent font element
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE);
if (s.length() == 0) {
// throw an exception since this attribute is required on the font element
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});
}
// vert-adv-y
s = glyphElement.getAttributeNS(null, SVG_VERT_ADV_Y_ATTRIBUTE);
if (s.length() == 0) {
// look for attribute on parent font element
s = parentFontElement.getAttributeNS(null, SVG_VERT_ADV_Y_ATTRIBUTE);
if (s.length() == 0) {
// not specified on parent either, use one em
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});
}
// vert-origin-x
s = glyphElement.getAttributeNS(null, SVG_VERT_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
// look for attribute on parent font element
s = parentFontElement.getAttributeNS(null, SVG_VERT_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
// not specified so use the default value which is horizAdvX/2
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});
}
// vert-origin-y
s = glyphElement.getAttributeNS(null, SVG_VERT_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
// look for attribute on parent font element
s = parentFontElement.getAttributeNS(null, SVG_VERT_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
// not specified so use the default value which is the fonts ascent
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);
// get the horizontal origin from the parent font element
// horiz-origin-x
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ORIGIN_X_ATTRIBUTE);
if (s.length() == 0) {
// not specified so use the default value which is 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});
}
// horiz-origin-y
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ORIGIN_Y_ATTRIBUTE);
if (s.length() == 0) {
// not specified so use the default value which is 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 a new Glyph
return new Glyph(unicode, names, orientation,
arabicForm, lang, horizOrigin, vertOrigin,
horizAdvX, vertAdvY, glyphCode,
tpi, dShape, glyphContentNode);
}