You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by di...@apache.org on 2001/04/29 10:23:21 UTC
cvs commit: xml-batik/sources/org/apache/batik/bridge SVGAltGlyphElementBridge.java SVGFontElementBridge.java SVGFontFace.java SVGFontFaceElementBridge.java SVGFontFamily.java SVGFontUtilities.java SVGGVTFont.java SVGGlyphElementBridge.java SVGHKernElementBridge.java BridgeContext.java SVGTextElementBridge.java
dino 01/04/29 01:23:21
Modified: sources/org/apache/batik/bridge BridgeContext.java
SVGTextElementBridge.java
Added: sources/org/apache/batik/bridge
SVGAltGlyphElementBridge.java
SVGFontElementBridge.java SVGFontFace.java
SVGFontFaceElementBridge.java SVGFontFamily.java
SVGFontUtilities.java SVGGVTFont.java
SVGGlyphElementBridge.java
SVGHKernElementBridge.java
Log:
adding first pass at svg fonts
Revision Changes Path
1.19 +27 -1 xml-batik/sources/org/apache/batik/bridge/BridgeContext.java
Index: BridgeContext.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/BridgeContext.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- BridgeContext.java 2001/04/23 12:19:34 1.18
+++ BridgeContext.java 2001/04/29 08:23:19 1.19
@@ -41,7 +41,7 @@
* a SVG DOM tree such as the current viewport or the user agent.
*
* @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
- * @version $Id: BridgeContext.java,v 1.18 2001/04/23 12:19:34 tkormann Exp $
+ * @version $Id: BridgeContext.java,v 1.19 2001/04/29 08:23:19 dino Exp $
*/
public class BridgeContext implements ErrorConstants {
@@ -725,6 +725,10 @@
new SVGGElementBridge());
ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_HKERN_TAG,
+ new SVGHKernElementBridge());
+
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
SVGConstants.SVG_IMAGE_TAG,
new SVGImageElementBridge());
@@ -799,6 +803,28 @@
ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
SVGConstants.SVG_FE_DISTANT_LIGHT_TAG,
new SVGFeAbstractLightingElementBridge.SVGFeDistantLightElementBridge());
+
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_FONT_TAG,
+ new SVGFontElementBridge());
+
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_FONT_FACE_TAG,
+ new SVGFontFaceElementBridge());
+
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_GLYPH_TAG,
+ new SVGGlyphElementBridge());
+
+ // just use the glyph bridge for missing glyph
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_MISSING_GLYPH_TAG,
+ new SVGGlyphElementBridge());
+
+
+ ctx.putBridge(SVGConstants.SVG_NAMESPACE_URI,
+ SVGConstants.SVG_ALT_GLYPH_TAG,
+ new SVGAltGlyphElementBridge());
}
}
1.19 +101 -67 xml-batik/sources/org/apache/batik/bridge/SVGTextElementBridge.java
Index: SVGTextElementBridge.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGTextElementBridge.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- SVGTextElementBridge.java 2001/03/30 11:46:07 1.18
+++ SVGTextElementBridge.java 2001/04/29 08:23:20 1.19
@@ -30,6 +30,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Vector;
import org.apache.batik.css.CSSOMReadOnlyStyleDeclaration;
import org.apache.batik.dom.svg.SVGOMDocument;
@@ -39,6 +40,8 @@
import org.apache.batik.gvt.GraphicsNodeRenderContext;
import org.apache.batik.gvt.TextNode;
import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.gvt.font.UnresolvedFontFamily;
import org.apache.batik.util.CSSConstants;
import org.apache.batik.util.SVGConstants;
@@ -53,7 +56,7 @@
* Bridge class for the <text> element.
*
* @author <a href="bill.haneman@ireland.sun.com>Bill Haneman</a>
- * @version $Id: SVGTextElementBridge.java,v 1.18 2001/03/30 11:46:07 tkormann Exp $
+ * @version $Id: SVGTextElementBridge.java,v 1.19 2001/04/29 08:23:20 dino Exp $
*/
public class SVGTextElementBridge implements GraphicsNodeBridge,
CSSConstants,
@@ -263,7 +266,7 @@
// !!! return two lists
Map m = getAttributeMap(ctx, element, node);
String s = XMLSupport.getXMLSpace(element);
- boolean preserve = s.equals("preserve");
+ boolean preserve = s.equals(SVG_PRESERVE_VALUE);
boolean first = true;
boolean last;
boolean stripFirst = !preserve;
@@ -293,14 +296,17 @@
nodeElement = (Element)n;
- if (n.getLocalName().equals("tspan")
- || n.getLocalName().equals("altGlyph")) {
+ if (n.getLocalName().equals(SVG_TSPAN_TAG)
+ || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) {
+
buildAttributedStrings(ctx,
nodeElement,
node,
false,
result);
- } else if (n.getLocalName().equals("tref")) {
+
+ } else if (n.getLocalName().equals(SVG_TREF_TAG)) {
+
String uriStr = XLinkSupport.getXLinkHref((Element)n);
Element ref = ctx.getReferencedElement((Element)n, uriStr);
s = getElementContent(ref);
@@ -599,26 +605,16 @@
// Font size, in user space units.
float fs = TextUtilities.convertFontSize(element, ctx, cssDecl, uctx);
-
result.put(TextAttribute.SIZE, new Float(fs));
- // Font family
- CSSValueList ff = (CSSValueList)cssDecl.getPropertyCSSValueInternal
- (CSS_FONT_FAMILY_PROPERTY);
- s = null;
- for (int i = 0; s == null && i < ff.getLength(); i++) {
- v = (CSSPrimitiveValue)ff.item(i);
- s = (String)fonts.get(v.getStringValue());
- }
- s = (s == null) ? "SansSerif" : s;
- result.put(TextAttribute.FAMILY, s);
-
// Font weight
// TODO: improve support for relative values
// (e.g. "lighter", "bolder")
v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
(CSS_FONT_WEIGHT_PROPERTY);
+ String fontWeightString;
if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
+ fontWeightString = v.getStringValue();
//System.out.println("CSS Font Weight "+v.getStringValue());
if (v.getStringValue().charAt(0) == 'n') {
result.put(TextAttribute.WEIGHT,
@@ -632,6 +628,7 @@
}
} else {
//System.out.println("CSS Font Weight "+v.getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
+ fontWeightString = "" + v.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
switch ((int)v.getFloatValue(CSSPrimitiveValue.CSS_NUMBER)) {
case 100:
result.put(TextAttribute.WEIGHT,
@@ -674,6 +671,93 @@
}
}
+ // Font style
+ v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
+ (CSS_FONT_STYLE_PROPERTY);
+ String fontStyleString = v.getStringValue();
+ switch (fontStyleString.charAt(0)) {
+ case 'n':
+ result.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_REGULAR);
+ break;
+ case 'o':
+ case 'i':
+ result.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ }
+
+
+ // Font stretch
+ v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
+ (CSS_FONT_STRETCH_PROPERTY);
+ String fontStretchString = v.getStringValue();
+ switch (fontStretchString.charAt(0)) {
+ case 'u':
+ if (fontStretchString.charAt(6) == 'c') {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_CONDENSED);
+ } else {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_EXTENDED);
+ }
+ break;
+ case 'e':
+ if (fontStretchString.charAt(6) == 'c') {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_CONDENSED);
+ } else {
+ if (fontStretchString.length() == 8) {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_SEMI_EXTENDED);
+ } else {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_EXTENDED);
+ }
+ }
+ break;
+ case 's':
+ if (fontStretchString.charAt(6) == 'c') {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_SEMI_CONDENSED);
+ } else {
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_SEMI_EXTENDED);
+ }
+ break;
+ default:
+ result.put(TextAttribute.WIDTH,
+ TextAttribute.WIDTH_REGULAR);
+ }
+
+
+ // Font family
+ CSSValueList ff = (CSSValueList)cssDecl.getPropertyCSSValueInternal
+ (CSS_FONT_FAMILY_PROPERTY);
+
+ //
+ // new code for SVGFonts:
+ //
+
+ // make a list of GVTFontFamily objects
+ Vector fontFamilyList = new Vector();
+ for (int i = 0; i < ff.getLength(); i++) {
+ v = (CSSPrimitiveValue)ff.item(i);
+ String fontFamilyName = v.getStringValue();
+ GVTFontFamily fontFamily
+ = SVGFontUtilities.getFontFamily(element, ctx, fontFamilyName,
+ fontWeightString, fontStyleString);
+ fontFamilyList.add(fontFamily);
+ /* if (fontFamily instanceof SVGFontFamily) {
+ System.out.println(fontFamilyName + " : SVGGVTFontFamily");
+ } else {
+ System.out.println(fontFamilyName + " : UnresolvedFontFamily");
+ }
+*/
+ }
+ result.put(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES,
+ fontFamilyList);
+
+
// Text baseline adjustment.
// TODO: support for <percentage> and <length> values.
v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
@@ -778,20 +862,6 @@
break;
}
- // Font style
- v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
- (CSS_FONT_STYLE_PROPERTY);
- s = v.getStringValue();
- switch (s.charAt(0)) {
- case 'n':
- result.put(TextAttribute.POSTURE,
- TextAttribute.POSTURE_REGULAR);
- break;
- case 'o':
- case 'i':
- result.put(TextAttribute.POSTURE,
- TextAttribute.POSTURE_OBLIQUE);
- }
// Font stretch
v = (CSSPrimitiveValue)cssDecl.getPropertyCSSValueInternal
@@ -987,40 +1057,4 @@
}
- protected final static Map fonts = new HashMap(11);
- static {
- fonts.put("serif", "Serif");
- fonts.put("Times", "Serif");
- fonts.put("Times New Roman", "Serif");
- fonts.put("sans-serif", "SansSerif");
- fonts.put("cursive", "Dialog");
- fonts.put("fantasy", "Symbol");
- fonts.put("monospace", "Monospaced");
- fonts.put("monospaced", "Monospaced");
- fonts.put("Courier", "Monospaced");
-
- //
- // Load all fonts. Work around
- //
- /* Note to maintainer: font init code should not be here!
- * we should not have dependencies in the Bridge
- * on java2d Fonts - they are not relevant to non-rasterizing
- * renderers!
- * We should instead support a list of fonts, in order of preference,
- * as CSS allows, and defer resolving these names to actual
- * implementation-dependent font names until render time.
- *
- * -Bill Haneman
- */
- GraphicsEnvironment env;
- env = GraphicsEnvironment.getLocalGraphicsEnvironment();
- // System.out.println("Initializing fonts .... please wait");
- String fontNames[] = env.getAvailableFontFamilyNames();
- int nFonts = fontNames != null ? fontNames.length : 0;
- // System.out.println("Done initializing " + nFonts + " fonts");
- for(int i=0; i<nFonts; i++){
- fonts.put(fontNames[i], fontNames[i]);
- //System.out.println(fontNames[i]);
- }
- }
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGAltGlyphElementBridge.java
Index: SVGAltGlyphElementBridge.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.gvt.font.Glyph;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.apache.batik.dom.util.XLinkSupport;
import org.apache.batik.dom.svg.SVGOMDocument;
/**
* Bridge class for the <altGlyph> element.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGAltGlyphElementBridge.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGAltGlyphElementBridge implements Bridge, SVGConstants {
/**
* Constructs a new bridge for the <altGlyph> element.
*/
public SVGAltGlyphElementBridge() {
}
/**
* Constructs an array of Glyphs that represents the specified
* <altGlyph> element at the requested size.
*
* @param ctx The current bridge context.
* @param fontElement The altGlyph element to base the SVGGVTGlyphVector
* construction on.
* @param fontSize The font size of the Glyphs to create.
* @param fontFace The font face object that contains the font attributes.
*
* @return The new SVGGVTGlyphVector or null if any of the glyphs are
* unavailable.
*/
public Glyph[] createAltGlyphArray(BridgeContext ctx,
Element altGlyphElement,
float fontSize) {
// get the referenced element
String uri = XLinkSupport.getXLinkHref(altGlyphElement);
Element refElement = ctx.getReferencedElement(altGlyphElement, uri);
if (refElement == null) {
// couldn't find the referenced element
return null;
}
// if the referenced element is a glyph
if (refElement.getTagName().equals(SVG_GLYPH_TAG)) {
Glyph glyph = getGlyph(ctx, uri, altGlyphElement, fontSize);
if (glyph == null) {
// failed to create a glyph for the specified glyph uri
return null;
}
Glyph[] glyphArray = new Glyph[1];
glyphArray[0] = glyph;
return glyphArray;
}
// else should be an altGlyphDef element
if (refElement.getTagName().equals(SVG_ALT_GLYPH_DEF_TAG)) {
// if not local import the referenced altGlyphDef into the current document
SVGOMDocument document
= (SVGOMDocument)altGlyphElement.getOwnerDocument();
SVGOMDocument refDocument
= (SVGOMDocument)refElement.getOwnerDocument();
boolean isLocal = (refDocument == document);
Element localRefElement = (isLocal) ? refElement
: (Element)document.importNode(refElement, true);
if (!isLocal) {
// need to attach the imported element to the document and
// then compute the styles and uris
Element g = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
g.appendChild(localRefElement);
CSSUtilities.computeStyleAndURIs(refElement, localRefElement);
}
// look for glyphRef children
NodeList altGlyphDefChildren = localRefElement.getChildNodes();
boolean containsGlyphRefNodes = false;
int numAltGlyphDefChildren = altGlyphDefChildren.getLength();
for (int i = 0; i < numAltGlyphDefChildren; i++) {
Node altGlyphChild = altGlyphDefChildren.item(i);
if (altGlyphChild.getNodeType() == Node.ELEMENT_NODE) {
if (((Element)altGlyphChild).getTagName().equals(SVG_GLYPH_REF_TAG)) {
containsGlyphRefNodes = true;
break;
}
}
}
if (containsGlyphRefNodes) { // process the glyphRef children
NodeList glyphRefNodes = localRefElement.getElementsByTagName(SVG_GLYPH_REF_TAG);
int numGlyphRefNodes = glyphRefNodes.getLength();
Glyph[] glyphArray = new Glyph[numGlyphRefNodes];
for (int i = 0; i < numGlyphRefNodes; i++) {
// get the referenced glyph element
Element glyphRefElement = (Element)glyphRefNodes.item(i);
String glyphUri = XLinkSupport.getXLinkHref(glyphRefElement);
Glyph glyph = getGlyph(ctx, glyphUri, altGlyphElement, fontSize);
if (glyph == null) {
// failed to create a glyph for the specified glyph uri
return null;
}
glyphArray[i] = glyph;
}
return glyphArray;
} else { // try looking for altGlyphItem children
NodeList altGlyphItemNodes = localRefElement.getElementsByTagName(SVG_ALT_GLYPH_ITEM_TAG);
int numAltGlyphItemNodes = altGlyphItemNodes.getLength();
if (numAltGlyphItemNodes > 0) {
Glyph[] glyphArray = new Glyph[numAltGlyphItemNodes];
for (int i = 0; i < numAltGlyphItemNodes; i++) {
// try to find a resolvable glyphRef
Element altGlyphItemElement = (Element)altGlyphItemNodes.item(i);
NodeList altGlyphRefNodes = altGlyphItemElement.getElementsByTagName(SVG_GLYPH_REF_TAG);
int numAltGlyphRefNodes = altGlyphRefNodes.getLength();
boolean foundMatchingGlyph = false;
for (int j = 0; j < numAltGlyphRefNodes; j++) {
// get the referenced glyph element
Element glyphRefElement = (Element)altGlyphRefNodes.item(j);
String glyphUri = XLinkSupport.getXLinkHref(glyphRefElement);
Glyph glyph = getGlyph(ctx, glyphUri, altGlyphElement, fontSize);
if (glyph != null) {
// found a matching glyph for this altGlyphItem
glyphArray[i] = glyph;
foundMatchingGlyph = true;
break;
}
}
if (!foundMatchingGlyph) {
// couldn't find a matching glyph for this alGlyphItem
// so stop and return null
return null;
}
}
return glyphArray;
}
}
}
// reference is not to a valid element, should throw an exception
return null;
}
private Glyph getGlyph(BridgeContext ctx,
String glyphUri,
Element altGlyphElement,
float fontSize) {
Element refGlyphElement = null;
try {
refGlyphElement = ctx.getReferencedElement(altGlyphElement, glyphUri);
} catch (BridgeException e) {
// this is ok, it is possible that the glyph at the given uri is not available
}
if (refGlyphElement == null || !refGlyphElement.getTagName().equals(SVG_GLYPH_TAG)) {
// couldn't find the referenced glyph element,
// or referenced element not a glyph
return null;
}
// see if the referenced glyph element is local
SVGOMDocument document
= (SVGOMDocument)altGlyphElement.getOwnerDocument();
SVGOMDocument refDocument
= (SVGOMDocument)refGlyphElement.getOwnerDocument();
boolean isLocal = (refDocument == document);
// if not local, import both the glyph and its font-face element
Element localGlyphElement = null;
Element localFontFaceElement = null;
if (isLocal) {
localGlyphElement = refGlyphElement;
Element fontElement = (Element)localGlyphElement.getParentNode();
NodeList fontFaceElements = fontElement.getElementsByTagName(SVG_FONT_FACE_TAG);
if (fontFaceElements.getLength() > 0) {
localFontFaceElement = (Element)fontFaceElements.item(0);
}
} else {
// import the whole font
Element localFontElement = (Element)document.importNode(refGlyphElement.getParentNode(), true);
Element g = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
g.appendChild(localFontElement);
CSSUtilities.computeStyleAndURIs((Element)refGlyphElement.getParentNode(), localFontElement);
// get the local glyph element
String glyphId = refGlyphElement.getAttributeNS(null, SVG_ID_ATTRIBUTE);
NodeList glyphElements = localFontElement.getElementsByTagName(SVG_GLYPH_TAG);
for (int i = 0; i < glyphElements.getLength(); i++) {
Element glyphElem = (Element)glyphElements.item(i);
if (glyphElem.getAttributeNS(null, SVG_ID_ATTRIBUTE).equals(glyphId)) {
localGlyphElement = glyphElem;
break;
}
}
// get the local font-face element
NodeList fontFaceElements = localFontElement.getElementsByTagName(SVG_FONT_FACE_TAG);
if (fontFaceElements.getLength() > 0) {
localFontFaceElement = (Element)fontFaceElements.item(0);
}
}
// if couldn't find the glyph or its font-face return null
if (localGlyphElement == null || localFontFaceElement == null) {
return null;
}
SVGFontFaceElementBridge fontFaceBridge
= (SVGFontFaceElementBridge)ctx.getBridge(localFontFaceElement);
SVGFontFace fontFace = fontFaceBridge.createFontFace(ctx, localFontFaceElement);
SVGGlyphElementBridge glyphBridge = (SVGGlyphElementBridge)ctx.getBridge(localGlyphElement);
return glyphBridge.createGlyph(ctx, localGlyphElement, altGlyphElement, -1, fontSize, fontFace);
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGFontElementBridge.java
Index: SVGFontElementBridge.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Bridge class for the <font> element.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGFontElementBridge.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGFontElementBridge implements Bridge, SVGConstants {
/**
* Constructs a new bridge for the <font> element.
*/
public SVGFontElementBridge() {
}
/**
* Constructs a new SVGGVTFont that represents the specified <font> element
* at the requested size.
*
* @param ctx The current bridge context.
* @param fontElement The font element to base the SVGGVTFont construction on.
* @param textElement The textElement that will use the new font.
* @param size The size of the new font.
* @param fontFace The font face object that contains the font attributes.
*
* @return The new SVGGVTFont.
*/
public SVGGVTFont createFont(BridgeContext ctx,
Element fontElement,
Element textElement,
float size,
SVGFontFace fontFace) {
// construct a list of glyph codes that this font can display and
// a list of the glyph elements
NodeList glyphElements = fontElement.getElementsByTagName(SVG_GLYPH_TAG);
int numGlyphs = glyphElements.getLength();
String[] glyphCodes = new String[numGlyphs];
String[] glyphNames = new String[numGlyphs];
Element[] glyphElementArray = new Element[numGlyphs];
for (int i = 0; i < numGlyphs; i++) {
Element glyphElement = (Element)glyphElements.item(i);
glyphCodes[i] = glyphElement.getAttribute(SVG_UNICODE_ATTRIBUTE);
glyphNames[i] = glyphElement.getAttribute(SVG_GLYPH_NAME_ATTRIBUTE);
glyphElementArray[i] = glyphElement;
}
NodeList missingGlyphElements = fontElement.getElementsByTagName(SVG_MISSING_GLYPH_TAG);
Element missingGlyphElement = null;
if (missingGlyphElements.getLength() > 0) {
missingGlyphElement = (Element)missingGlyphElements.item(0);
}
NodeList hkernElements = fontElement.getElementsByTagName(SVG_HKERN_TAG);
Element[] hkernElementArray = new Element[hkernElements.getLength()];
for (int i = 0; i < hkernElementArray.length; i++) {
Element hkernElement = (Element)hkernElements.item(i);
hkernElementArray[i] = hkernElement;
}
return new SVGGVTFont(size, fontFace, glyphCodes, glyphNames, ctx,
glyphElementArray, missingGlyphElement,
hkernElementArray, textElement);
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGFontFace.java
Index: SVGFontFace.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
/**
* This class represents a <font-face> element.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGFontFace.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGFontFace {
protected String familyName;
protected float unitsPerEm;
protected String fontWeight;
protected String fontStyle;
protected String fontVariant;
protected String fontStretch;
protected float slope;
protected String panose1;
protected float ascent;
protected float descent;
protected float strikethroughPosition;
protected float strikethroughThickness;
protected float underlinePosition;
protected float underlineThickness;
protected float overlinePosition;
protected float overlineThickness;
// TODO: change this list of parameters into a Map of some sort, will be
// too many attributes to pass in individually
/**
* Constructes an SVGFontFace with the specfied font attributes.
*/
public SVGFontFace(String familyName, float unitsPerEm, String fontWeight,
String fontStyle, String fontVariant, String fontStretch,
float slope, String panose1, float ascent, float descent,
float strikethroughPosition, float strikethroughThickness,
float underlinePosition, float underlineThickness,
float overlinePosition, float overlineThickness) {
this.familyName = familyName;
this.unitsPerEm = unitsPerEm;
this.fontWeight = fontWeight;
this.fontStyle = fontStyle;
this.fontVariant = fontVariant;
this.fontStretch = fontStretch;
this.slope = slope;
this.panose1 = panose1;
this.ascent = ascent;
this.strikethroughPosition = strikethroughPosition;
this.strikethroughThickness = strikethroughThickness;
this.underlinePosition = underlinePosition;
this.underlineThickness = underlineThickness;
this.overlinePosition = overlinePosition;
this.overlineThickness = overlineThickness;
}
public String getFamilyName() {
return familyName;
}
public String getFontWeight() {
return fontWeight;
}
public String getFontStyle() {
return fontStyle;
}
public float getUnitsPerEm() {
return unitsPerEm;
}
public float getAscent() {
return ascent;
}
public float getDescent() {
return descent;
}
public float getStrikethroughPosition() {
return strikethroughPosition;
}
public float getStrikethroughThickness() {
return strikethroughThickness;
}
public float getUnderlinePosition() {
return underlinePosition;
}
public float getUnderlineThickness() {
return underlineThickness;
}
public float getOverlinePosition() {
return overlinePosition;
}
public float getOverlineThickness() {
return overlineThickness;
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGFontFaceElementBridge.java
Index: SVGFontFaceElementBridge.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.w3c.dom.Element;
import org.apache.batik.util.SVGConstants;
/**
* Bridge class for the <font-face> element.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGFontFaceElementBridge.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGFontFaceElementBridge implements Bridge, SVGConstants, ErrorConstants {
/**
* Constructs a new bridge for the <font-face> element.
*/
public SVGFontFaceElementBridge() {
}
/**
* Creates an SVGFontFace that repesents the specified <font-face> element.
*
* @param ctx The current bridge context.
* @param fontFaceElement The <font-face> element.
*
* @return A new SVGFontFace.
*/
public SVGFontFace createFontFace(BridgeContext ctx,
Element fontFaceElement) {
// get all the font-face attributes
String familyNames = fontFaceElement.getAttributeNS(null, SVG_FONT_FAMILY_ATTRIBUTE);
// units per em
String unitsPerEmStr = fontFaceElement.getAttributeNS(null, SVG_UNITS_PER_EM_ATTRIBUTE);
if (unitsPerEmStr.length() == 0) {
unitsPerEmStr = SVG_FONT_FACE_UNITS_PER_EM_DEFAULT_VALUE;
}
float unitsPerEm;
try {
unitsPerEm = SVGUtilities.convertSVGNumber(unitsPerEmStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_UNITS_PER_EM_ATTRIBUTE, unitsPerEmStr});
}
// font-weight
String fontWeight = fontFaceElement.getAttributeNS(null, SVG_FONT_WEIGHT_ATTRIBUTE);
if (fontWeight.length() == 0) {
fontWeight = SVG_FONT_FACE_FONT_WEIGHT_DEFAULT_VALUE;
}
// font-style
String fontStyle = fontFaceElement.getAttributeNS(null, SVG_FONT_STYLE_ATTRIBUTE);
if (fontStyle.length() == 0) {
fontStyle = SVG_FONT_FACE_FONT_STYLE_DEFAULT_VALUE;
}
// font-variant
String fontVariant = fontFaceElement.getAttributeNS(null, SVG_FONT_VARIANT_ATTRIBUTE);
if (fontVariant.length() == 0) {
fontVariant = SVG_FONT_FACE_FONT_VARIANT_DEFAULT_VALUE;
}
// font-stretch
String fontStretch = fontFaceElement.getAttributeNS(null, SVG_FONT_STRETCH_ATTRIBUTE);
if (fontStretch.length() == 0) {
fontStretch = SVG_FONT_FACE_FONT_STRETCH_DEFAULT_VALUE;
}
// slopeStr
String slopeStr = fontFaceElement.getAttributeNS(null, SVG_SLOPE_ATTRIBUTE);
if (slopeStr.length() == 0) {
slopeStr = SVG_FONT_FACE_SLOPE_DEFAULT_VALUE;
}
float slope;
try {
slope = SVGUtilities.convertSVGNumber(slopeStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, slopeStr});
}
// panose-1
String panose1 = fontFaceElement.getAttributeNS(null, SVG_PANOSE_1_ATTRIBUTE);
if (panose1.length() == 0) {
panose1 = SVG_FONT_FACE_PANOSE_1_DEFAULT_VALUE;
}
// ascent
String ascentStr = fontFaceElement.getAttributeNS(null, SVG_ASCENT_ATTRIBUTE);
if (ascentStr.length() == 0) {
// set it to be unitsPerEm/2, not sure if this is correct or not
ascentStr = String.valueOf(unitsPerEm/2);
}
float ascent;
try {
ascent = SVGUtilities.convertSVGNumber(ascentStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, ascentStr});
}
// descent
String descentStr = fontFaceElement.getAttributeNS(null, SVG_DESCENT_ATTRIBUTE);
if (descentStr.length() == 0) {
// set it to be unitsPerEm/2, not sure if this is correct or not
descentStr = String.valueOf(unitsPerEm/2);
}
float descent;
try {
descent = SVGUtilities.convertSVGNumber(descentStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, descentStr});
}
// underline-position
String underlinePosStr = fontFaceElement.getAttributeNS(null, SVG_UNDERLINE_POSITION_ATTRIBUTE);
if (underlinePosStr.length() == 0) {
underlinePosStr = "0";
}
float underlinePos;
try {
underlinePos = SVGUtilities.convertSVGNumber(underlinePosStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, underlinePosStr});
}
// underline-thickness
String underlineThicknessStr = fontFaceElement.getAttributeNS(null, SVG_UNDERLINE_THICKNESS_ATTRIBUTE);
if (underlineThicknessStr.length() == 0) {
underlineThicknessStr = String.valueOf(unitsPerEm/20);
}
float underlineThickness;
try {
underlineThickness = SVGUtilities.convertSVGNumber(underlineThicknessStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, underlineThicknessStr});
}
// strikethrough-position
String strikethroughPosStr = fontFaceElement.getAttributeNS(null, SVG_STRIKETHROUGH_POSITION_ATTRIBUTE);
if (strikethroughPosStr.length() == 0) {
strikethroughPosStr = String.valueOf(ascent/3);
}
float strikethroughPos;
try {
strikethroughPos = SVGUtilities.convertSVGNumber(strikethroughPosStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, strikethroughPosStr});
}
// strikethrough-thickness
String strikethroughThicknessStr = fontFaceElement.getAttributeNS(null, SVG_STRIKETHROUGH_THICKNESS_ATTRIBUTE);
if (strikethroughThicknessStr.length() == 0) {
strikethroughThicknessStr = String.valueOf(unitsPerEm/20);
}
float strikethroughThickness;
try {
strikethroughThickness = SVGUtilities.convertSVGNumber(strikethroughThicknessStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, strikethroughThicknessStr});
}
// overline-position
String overlinePosStr = fontFaceElement.getAttributeNS(null, this.SVG_OVERLINE_POSITION_ATTRIBUTE);
if (overlinePosStr.length() == 0) {
overlinePosStr = String.valueOf(ascent);
}
float overlinePos;
try {
overlinePos = SVGUtilities.convertSVGNumber(overlinePosStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, overlinePosStr});
}
// overline-thickness
String overlineThicknessStr = fontFaceElement.getAttributeNS(null, SVG_OVERLINE_THICKNESS_ATTRIBUTE);
if (overlineThicknessStr.length() == 0) {
overlineThicknessStr = String.valueOf(unitsPerEm/20);
}
float overlineThickness;
try {
overlineThickness = SVGUtilities.convertSVGNumber(overlineThicknessStr);
} catch (NumberFormatException ex) {
throw new BridgeException
(fontFaceElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_FONT_FACE_SLOPE_DEFAULT_VALUE, overlineThicknessStr});
}
// TODO: get the rest of the attributes
// should really pass in a HashMap containing the attribute values
return new SVGFontFace(familyNames, unitsPerEm, fontWeight, fontStyle,
fontVariant, fontStretch, slope, panose1, ascent,
descent, strikethroughPos, strikethroughThickness,
underlinePos, underlineThickness,
overlinePos, overlineThickness);
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGFontFamily.java
Index: SVGFontFamily.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.gvt.font.GVTFontFamily;
import org.apache.batik.gvt.font.GVTFont;
import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
import org.w3c.dom.Element;
import java.text.AttributedCharacterIterator;
/**
* A font family class for SVG fonts.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGFontFamily.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGFontFamily implements GVTFontFamily {
protected SVGFontFace fontFace;
protected Element fontElement;
protected BridgeContext ctx;
/**
* Constructs an SVGFontFamily.
*
* @param fontFace The font face object that describes this font family.
* @param fontElement The element that contains the font data for this family.
* @param ctx The bridge context. This is required for lazily loading the
* font data at render time.
*/
public SVGFontFamily(SVGFontFace fontFace,
Element fontElement,
BridgeContext ctx) {
this.fontFace = fontFace;
this.fontElement = fontElement;
this.ctx = ctx;
}
/**
* Returns the family name of this font.
*
* @return The font family name.
*/
public String getFamilyName() {
return fontFace.getFamilyName();
}
/**
* Returns the font-face associated with this font family.
*
* @return The font face.
*/
public SVGFontFace getFontFace() {
return fontFace;
}
/**
* Derives a GVTFont object of the correct size.
*
* @param size The required size of the derived font.
* @param aci The character iterator that will be rendered using the derived
* font.
*/
public GVTFont deriveFont(float size, AttributedCharacterIterator aci) {
SVGFontElementBridge fontBridge
= (SVGFontElementBridge)ctx.getBridge(fontElement);
Element textElement = (Element)aci.getAttributes().get(
GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
return fontBridge.createFont(ctx, fontElement, textElement, size, fontFace);
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGFontUtilities.java
Index: SVGFontUtilities.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.gvt.font.GVTFontFamily;
import org.apache.batik.gvt.font.UnresolvedFontFamily;
import org.apache.batik.dom.util.XLinkSupport;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.svg.SVGDocument;
import java.util.HashMap;
import java.util.Vector;
import java.util.StringTokenizer;
/**
* Utility class for SVG fonts.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGFontUtilities.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public abstract class SVGFontUtilities implements SVGConstants {
/**
* A hash map of all the font families already matched. This is
* to reduce the number of instances of GVTFontFamilies and to
* hopefully reduce the time taken to search for a matching SVG font.
*/
private static HashMap fontFamilyMap;
/**
* Keeps track of the currentDocument. This is used to detect when a new
* document has been loaded.
*/
private static Document currentDocument = null;
/**
* Given a font family name tries to find a matching SVG font object.
* If finds one, returns an SVGFontFamily otherwise returns an
* UnresolvedFontFamily.
* TODO: should match against font-variant as well.
*
* @param textElement The text element that the font family will be attached to.
* @param ctx The bridge context, used to search for a matching SVG font element.
* @param fontFamilyName The name of the font family to search for.
* @param fontWeight The weight of the font to use when trying to match an SVG font family.
* @param fontStyle The style of the font to use when trying to match as SVG font family.
*
* @return A GVTFontFamily for the specified font attributes. This will be
* unresolved unless a matching SVG font was found.
*/
public static GVTFontFamily getFontFamily(Element textElement,
BridgeContext ctx,
String fontFamilyName,
String fontWeight,
String fontStyle) {
// if this is a new document reset the fontFamilyMap
if (fontFamilyMap == null || textElement.getOwnerDocument() != currentDocument) {
fontFamilyMap = new HashMap();
currentDocument = textElement.getOwnerDocument();
}
String fontKeyName = fontFamilyName + " " + fontWeight + " " + fontStyle;
// check fontFamilyMap to see if we have already created an FontFamily
// that matches
GVTFontFamily fontFamily = (GVTFontFamily)fontFamilyMap.get(fontKeyName);
if (fontFamily != null) {
return fontFamily;
}
// try to find a matching SVGFontFace element
Document doc = textElement.getOwnerDocument();
NodeList fontFaceElements = doc.getElementsByTagName(SVG_FONT_FACE_TAG);
Vector svgFontFamilies = new Vector();
for (int i = 0; i < fontFaceElements.getLength(); i++) {
Element fontFaceElement = (Element)fontFaceElements.item(i);
String elemFamilyName
= fontFaceElement.getAttribute(SVG_FONT_FAMILY_ATTRIBUTE);
if (elemFamilyName.indexOf(fontFamilyName) == 0) { // found one
// find matching font element
// see if its the parent node
Element fontElement = (Element)fontFaceElement.getParentNode();
if (!fontElement.getTagName().equals(SVG_FONT_TAG)) {
// parent element is not the font element
// need to look at the font-face-src
fontElement = null;
NodeList fontFaceSrcNodes = fontFaceElement.getElementsByTagName(SVG_FONT_FACE_SRC_TAG);
if (fontFaceSrcNodes.getLength() > 0) {
Element fontFaceSrcElement = (Element)fontFaceSrcNodes.item(0);
// see if there is a fontFaceUri child
NodeList fontFaceUriNodes = fontFaceSrcElement.getElementsByTagName(SVG_FONT_FACE_URI_TAG);
if (fontFaceUriNodes.getLength() > 0) {
Element fontFaceUriElement = (Element)fontFaceUriNodes.item(0);
// get the referenced element
String uri = XLinkSupport.getXLinkHref(fontFaceUriElement);
Element refElement = ctx.getReferencedElement(fontFaceUriElement, uri);
// make sure its a font element
if (refElement.getTagName().equals(SVG_FONT_TAG)) {
SVGOMDocument document
= (SVGOMDocument)fontFaceUriElement.getOwnerDocument();
SVGOMDocument refDocument
= (SVGOMDocument)refElement.getOwnerDocument();
boolean isLocal = (refDocument == document);
// import or clone the referenced element in current document
fontElement = (isLocal) ? refElement
: (Element)document.importNode(refElement, true);
if (!isLocal) {
// need to attach the imported element to the document and
// then compute the styles and uris
Element g = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
g.appendChild(fontElement);
CSSUtilities.computeStyleAndURIs(refElement, fontElement);
}
}
}
}
}
if (fontElement != null) {
// create a font face
SVGFontFaceElementBridge fontFaceBridge
= (SVGFontFaceElementBridge)ctx.getBridge(fontFaceElement);
SVGFontFace fontFace = fontFaceBridge.createFontFace(ctx, fontFaceElement);
// see if the font face is ok for the font-weight and style etc
String fontFaceStyle = fontFace.getFontStyle();
if (fontFaceStyle.equals(SVG_ALL_VALUE) || fontFaceStyle.indexOf(fontStyle) != -1) {
// create a new SVGFontFamily
GVTFontFamily gvtFontFamily = new SVGFontFamily(fontFace, fontElement, ctx);
svgFontFamilies.add(gvtFontFamily);
}
}
}
}
if (svgFontFamilies.size() == 1) {
// only found one matching svg font family
fontFamilyMap.put(fontKeyName, svgFontFamilies.elementAt(0));
return (GVTFontFamily)svgFontFamilies.elementAt(0);
} else if (svgFontFamilies.size() > 1) {
// need to find font face that matches the font-weight closest
String fontWeightNumber = getFontWeightNumberString(fontWeight);
// create lists of font weight numbers for each font family
Vector fontFamilyWeights = new Vector();
for (int i = 0; i < svgFontFamilies.size(); i++) {
SVGFontFace fontFace = ((SVGFontFamily)svgFontFamilies.elementAt(i)).getFontFace();
String fontFaceWeight = fontFace.getFontWeight();
fontFaceWeight = getFontWeightNumberString(fontFaceWeight);
fontFamilyWeights.add(fontFaceWeight);
}
// make sure that each possible font-weight has been assigned to a font-face
// if not then need to "fill the holes"
Vector newFontFamilyWeights = (Vector)fontFamilyWeights.clone();
for (int i = 100; i <= 900; i+= 100) {
String weightString = String.valueOf(i);
boolean matched = false;
int minDifference = 1000;
int minDifferenceIndex = 0;
for (int j = 0; j < fontFamilyWeights.size(); j++) {
String fontFamilyWeight = (String)fontFamilyWeights.elementAt(j);
if (fontFamilyWeight.indexOf(weightString) > -1) {
matched = true;
break;
}
StringTokenizer st = new StringTokenizer(fontFamilyWeight, " ,");
while (st.hasMoreTokens()) {
int weightNum = Integer.parseInt(st.nextToken());
int difference = (int)Math.abs(weightNum - i);
if (difference < minDifference) {
minDifference = difference;
minDifferenceIndex = j;
}
}
}
if (!matched) {
String newFontFamilyWeight = newFontFamilyWeights.elementAt(minDifferenceIndex)
+ ", " + weightString;
newFontFamilyWeights.setElementAt(newFontFamilyWeight, minDifferenceIndex);
}
}
// now find matching font weight
for (int i = 0; i < svgFontFamilies.size(); i++) {
String fontFaceWeight = (String)newFontFamilyWeights.elementAt(i);
if (fontFaceWeight.indexOf(fontWeightNumber) > -1) {
fontFamilyMap.put(fontKeyName, svgFontFamilies.elementAt(i));
return (GVTFontFamily)svgFontFamilies.elementAt(i);
}
}
// should not get here, just return the first svg font family
fontFamilyMap.put(fontKeyName, svgFontFamilies.elementAt(0));
return (GVTFontFamily) svgFontFamilies.elementAt(0);
} else {
// couldn't find one so return an UnresolvedFontFamily object
GVTFontFamily gvtFontFamily = new UnresolvedFontFamily(fontFamilyName);
fontFamilyMap.put(fontKeyName, gvtFontFamily);
return gvtFontFamily;
}
}
private static String getFontWeightNumberString(String fontWeight) {
if (fontWeight.equals(SVG_NORMAL_VALUE)) {
return SVG_400_VALUE;
} else if (fontWeight.equals(SVG_BOLD_VALUE)) {
return SVG_700_VALUE;
} else if (fontWeight.equals(SVG_ALL_VALUE)) {
return "100, 200, 300, 400, 500, 600, 700, 800, 900";
}
return fontWeight;
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGGVTFont.java
Index: SVGGVTFont.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.font.GlyphVector;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Vector;
import org.w3c.dom.Element;
import org.apache.batik.gvt.text.AttributedCharacterSpanIterator;
import org.apache.batik.gvt.font.GVTFont;
import org.apache.batik.gvt.font.GVTGlyphVector;
import org.apache.batik.gvt.font.SVGGVTGlyphVector;
import org.apache.batik.gvt.font.GVTLineMetrics;
import org.apache.batik.gvt.font.Glyph;
import org.apache.batik.gvt.font.HKern;
import org.apache.batik.gvt.font.HKernTable;
import org.apache.batik.util.SVGConstants;
/**
* Represents an SVG font.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGGVTFont.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public final class SVGGVTFont implements GVTFont, SVGConstants {
private float fontSize;
private SVGFontFace fontFace;
private String[] glyphUnicodes;
private String[] glyphNames;
private Element[] glyphElements;
private Element[] hkernElements;
private BridgeContext ctx;
private Element textElement;
private Element missingGlyphElement;
private HKernTable kerningTable;
public SVGGVTFont(float fontSize, SVGFontFace fontFace, String[] glyphUnicodes,
String[] glyphNames,
BridgeContext ctx, Element[] glyphElements,
Element missingGlyphElement,
Element[] hkernElements,
Element textElement) {
this.fontFace = fontFace;
this.fontSize = fontSize;
this.glyphUnicodes = glyphUnicodes;
this.glyphNames = glyphNames;
this.ctx = ctx;
this.glyphElements = glyphElements;
this.missingGlyphElement = missingGlyphElement;
this.hkernElements = hkernElements;
this.textElement = textElement;
createKerningTable();
}
/**
* Creates the kerning table for this font
*/
private void createKerningTable() {
HKern[] entries = new HKern[hkernElements.length];
for (int i=0; i < hkernElements.length; i++) {
Element hkernElement = hkernElements[i];
SVGHKernElementBridge hkernBridge = (SVGHKernElementBridge)ctx.getBridge(hkernElement);
HKern hkern = hkernBridge.createHKern(ctx, hkernElement, fontFace, this);
entries[i] = hkern;
}
kerningTable = new HKernTable(entries);
}
/**
* Returns the kerning value of this character pair.
*/
public float getKerning(String unicode1, String unicode2) {
if (unicode1 != null && unicode1.length() > 0 &&
unicode2 != null && unicode2.length() > 0) {
return kerningTable.getKerningValue(unicode1.charAt(0),
unicode2.charAt(0));
} else {
return 0f;
}
}
/**
* Checks if this Font has a glyph for the glyph name.
*
* @param name The glyph-name to look for.
*/
public boolean canDisplayGivenName(String name) {
for (int i = 0; i < glyphNames.length; i++) {
if (glyphNames[i] != null && glyphNames[i].equals(name)) {
return true;
}
}
return false;
}
/**
* Returns the unicode character that corresponds to this glyph.
*
* @param name The glyph-name to look for.
*/
public char unicodeForName(String name) {
for (int i = 0; i < glyphNames.length; i++) {
if (glyphNames[i] != null && glyphNames[i].equals(name)) {
return glyphUnicodes[i].charAt(0);
}
}
return 0;
}
/**
* Checks if this Font has a glyph for the specified character.
*/
public boolean canDisplay(char c) {
for (int i = 0; i < glyphUnicodes.length; i++) {
if (glyphUnicodes[i].indexOf(c) != -1) {
return true;
}
}
return false;
}
/**
* Indicates whether or not this Font can display the characters in the
* specified text starting at start and ending at limit.
* Returns the index of the first character it can't display. Returns -1 if
* it can display the whole string.
*/
public int canDisplayUpTo(char[] text, int start, int limit) {
StringCharacterIterator sci = new StringCharacterIterator(new String(text));
return canDisplayUpTo(sci, start, limit);
}
/**
* Indicates whether or not this Font can display the the characters in
* the specified CharacterIterator starting at start and ending at limit.
* Returns the index of the first character it can't display. Returns -1 if
* it can display the whole string.
*/
public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
char c = iter.setIndex(start);
int currentIndex = start;
while (c != iter.DONE && currentIndex < limit) {
boolean foundMatchingGlyph = false;
for (int i = 0; i < glyphUnicodes.length; i++) {
if (glyphUnicodes[i].indexOf(c) == 0) { // found a possible match
if (glyphUnicodes[i].length() == 0) { // not a ligature
foundMatchingGlyph = true;
break;
} else {
// glyphCodes[i] is a ligature so try and
// match the rest of the glyphCode chars
boolean matched = true;
String ligature = "" + c;
for (int j = 1; j < glyphUnicodes[i].length(); j++) {
c = iter.next();
if (glyphUnicodes[i].charAt(j) != c) {
matched = false;
break;
}
ligature += c;
}
if (matched) { // found a matching ligature!
foundMatchingGlyph = true;
break;
} else {
// did not match ligature, keep looking for another glyph
c = iter.setIndex(currentIndex);
}
}
}
}
if (!foundMatchingGlyph) {
return currentIndex;
}
c = iter.next();
currentIndex = iter.getIndex();
}
return -1;
}
/**
* Indicates whether or not this Font can display a specified String.
* Returns the index of the first character it can't display. Returns -1 if
* it can display the whole string.
*/
public int canDisplayUpTo(String str) {
StringCharacterIterator sci = new StringCharacterIterator(str);
return canDisplayUpTo(sci, 0, str.length());
}
/**
* Returns a new GlyphVector object created with the specified array of
* characters and the specified FontRenderContext.
*/
public GVTGlyphVector createGlyphVector(FontRenderContext frc,
char[] chars) {
StringCharacterIterator sci = new StringCharacterIterator(new String(chars));
return createGlyphVector(frc, sci);
}
/**
* Returns a new GlyphVector object created with the specified
* CharacterIterator and the specified FontRenderContext.
*/
public GVTGlyphVector createGlyphVector(FontRenderContext frc,
CharacterIterator ci) {
/* System.out.print("creating SVGGVTGlyphVector for: ");
for (char c = ci.first(); c != ci.DONE; c = ci.next()) {
System.out.print(c);
}
System.out.println();
*/
// first look to see if we are creating an altGlyph glyph vector
if (textElement.getTagName().equals(SVG_ALT_GLYPH_TAG)) {
SVGAltGlyphElementBridge altGlyphBridge = (SVGAltGlyphElementBridge)ctx.getBridge(textElement);
Glyph[] glyphArray = altGlyphBridge.createAltGlyphArray(ctx, textElement, fontSize);
if (glyphArray != null) {
return new SVGGVTGlyphVector(this, glyphArray, frc);
}
}
// not alt-glyph or alt-glyph could not find referenced glyphs
Vector glyphs = new Vector();
char c = ci.first();
while (c != ci.DONE) {
boolean foundMatchingGlyph = false;
for (int i = 0; i < glyphUnicodes.length; i++) {
if (glyphUnicodes[i].indexOf(c) == 0) { // found a possible match
if (glyphUnicodes[i].length() == 0) { // not a ligature
Element glyphElement = glyphElements[i];
SVGGlyphElementBridge glyphBridge = (SVGGlyphElementBridge)ctx.getBridge(glyphElement);
Glyph glyph = glyphBridge.createGlyph(ctx, glyphElement, textElement, i, fontSize, fontFace);
glyphs.add(glyph);
foundMatchingGlyph = true;
break;
} else {
// glyphCodes[i] is a ligature so try and
// match the rest of the glyphCode chars
int current = ci.getIndex();
boolean matched = true;
for (int j = 1; j < glyphUnicodes[i].length(); j++) {
c = ci.next();
if (glyphUnicodes[i].charAt(j) != c) {
matched = false;
break;
}
}
if (matched) { // found a matching ligature!
Element glyphElement = glyphElements[i];
SVGGlyphElementBridge glyphBridge = (SVGGlyphElementBridge)ctx.getBridge(glyphElement);
Glyph glyph = glyphBridge.createGlyph(ctx, glyphElement, textElement, i, fontSize, fontFace);
glyphs.add(glyph);
foundMatchingGlyph = true;
break;
} else {
// did not match ligature, keep looking for another glyph
c = ci.setIndex(current);
}
}
}
}
if (!foundMatchingGlyph) {
// add the missing glyph
SVGGlyphElementBridge glyphBridge = (SVGGlyphElementBridge)ctx.getBridge(missingGlyphElement);
Glyph glyph = glyphBridge.createGlyph(ctx, missingGlyphElement, textElement, -1, fontSize, fontFace);
glyphs.add(glyph);
}
c = ci.next();
}
// turn the vector of glyphs into an array;
int numGlyphs = glyphs.size();
Glyph[] glyphArray = new Glyph[numGlyphs];
for (int i =0; i < numGlyphs; i++) {
glyphArray[i] = (Glyph)glyphs.get(i);
}
// return a new SVGGVTGlyphVector
return new SVGGVTGlyphVector(this, glyphArray, frc);
}
/**
* Returns a new GlyphVector object created with the specified integer
* array and the specified FontRenderContext.
*/
public GVTGlyphVector createGlyphVector(FontRenderContext frc,
int[] glyphCodes) {
// costruct a string from the glyphCodes
String str = "";
for (int i = 0; i < glyphCodes.length; i++) {
str += glyphUnicodes[glyphCodes[i]];
}
StringCharacterIterator sci = new StringCharacterIterator(str);
return createGlyphVector(frc, sci);
}
/**
* Returns a new GlyphVector object created with the specified String and
* the specified FontRenderContext.
*/
public GVTGlyphVector createGlyphVector(FontRenderContext frc, String str) {
StringCharacterIterator sci = new StringCharacterIterator(str);
return createGlyphVector(frc, sci);
}
/**
* Creates a new Font object by replicating the current Font object and
* applying a new size to it.
*/
public GVTFont deriveFont(float size) {
return new SVGGVTFont(size, fontFace, glyphUnicodes, glyphNames, ctx,
glyphElements, missingGlyphElement, hkernElements, textElement);
}
/**
* Returns a GVTLineMetrics object created with the specified arguments.
*/
public GVTLineMetrics getLineMetrics(char[] chars, int beginIndex, int limit,
FontRenderContext frc) {
StringCharacterIterator sci = new StringCharacterIterator(new String(chars));
return getLineMetrics(sci, beginIndex, limit, frc);
}
/**
* Returns a GVTLineMetrics object created with the specified arguments.
*/
public GVTLineMetrics getLineMetrics(CharacterIterator ci, int beginIndex,
int limit, FontRenderContext frc) {
// first create the character iterator that represents the subset
// from beginIndex to limit
String s = "";
char c = ci.setIndex(beginIndex);
int currentIndex = beginIndex;
while (c != ci.DONE && currentIndex < limit) {
s += c;
currentIndex++;
c = ci.next();
}
StringCharacterIterator sci = new StringCharacterIterator(s);
GVTGlyphVector gv = createGlyphVector(frc, sci);
float fontHeight = fontFace.getUnitsPerEm();
float scale = fontSize/fontHeight;
float ascent = fontFace.getAscent() * scale;
float descent = fontFace.getDescent() * scale;
int numGlyphs = gv.getNumGlyphs();
float[] baselineOffsets = new float[numGlyphs];
for (int i = 0; i < numGlyphs; i++) {
baselineOffsets[i] = (float)( gv.getGlyphMetrics(i).getBounds2D().getMaxY()
- gv.getGlyphPosition(i).getY());
}
float strikethroughOffset = fontFace.getStrikethroughPosition() * -scale;
float strikethroughThickness = fontFace.getStrikethroughThickness() * scale;
float underlineOffset = fontFace.getUnderlinePosition() * scale;
float underlineThickness = fontFace.getUnderlineThickness() * scale;
float overlineOffset = fontFace.getOverlinePosition() * -scale;
float overlineThickness = fontFace.getOverlineThickness() * scale;
return new GVTLineMetrics(ascent, Font.ROMAN_BASELINE, baselineOffsets, descent,
fontHeight, fontHeight, numGlyphs, strikethroughOffset,
strikethroughThickness, underlineOffset,
underlineThickness, overlineOffset, overlineThickness);
}
/**
* Returns a GVTLineMetrics object created with the specified String and
* FontRenderContext.
*/
public GVTLineMetrics getLineMetrics(String str, FontRenderContext frc) {
StringCharacterIterator sci = new StringCharacterIterator(str);
return getLineMetrics(sci, 0, str.length(), frc);
}
/**
* Returns a GVTLineMetrics object created with the specified arguments.
*/
public GVTLineMetrics getLineMetrics(String str, int beginIndex, int limit,
FontRenderContext frc) {
StringCharacterIterator sci = new StringCharacterIterator(str);
return getLineMetrics(sci, beginIndex, limit, frc);
}
public String toString() {
return fontFace.getFamilyName() + " " + fontFace.getFontWeight() + " "
+ fontFace.getFontStyle();
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGGlyphElementBridge.java
Index: SVGGlyphElementBridge.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.gvt.font.Glyph;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.Attr;
import java.util.StringTokenizer;
import java.util.Vector;
import java.awt.geom.Point2D;
import java.awt.geom.AffineTransform;
import java.awt.Shape;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.ShapeNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.parser.AWTPathProducer;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.PathParser;
import java.io.StringReader;
import org.apache.batik.gvt.ShapePainter;
/**
* Bridge class for the <glyph> element.
*
* @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
* @version $Id: SVGGlyphElementBridge.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGGlyphElementBridge implements Bridge, SVGConstants, ErrorConstants {
/**
* Constructs a new bridge for the <glyph> element.
*/
protected SVGGlyphElementBridge() {}
/**
* Constructs a new Glyph that represents the specified <glyph> element
* at the requested size.
*
* @param ctx The current bridge context.
* @param glyphElement The glyph element to base the glyph construction on.
* @param textElement The textElement the glyph will be used for.
* @param glyphCode The unique id to give to the new glyph.
* @param fontSize The font size used to determine the size of the glyph.
* @param fontFace The font face object that contains the font attributes.
*
* @return The new Glyph.
*/
public Glyph createGlyph(BridgeContext ctx, Element glyphElement,
Element textElement, int glyphCode, float fontSize,
SVGFontFace fontFace) {
// build the GVT tree that represents the glyph
GVTBuilder builder = ctx.getGVTBuilder();
CompositeGraphicsNode glyphContentNode
= new CompositeGraphicsNode();
float fontHeight = fontFace.getUnitsPerEm();
float scale = fontSize/fontHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(scale, -scale);
// create a shape node that represents the d attribute
String d = glyphElement.getAttributeNS(null, SVG_D_ATTRIBUTE);
if (d.length() != 0) {
ShapeNode shapeNode = new ShapeNode();
AWTPathProducer app = new AWTPathProducer();
app.setWindingRule(CSSUtilities.convertFillRule(glyphElement));
try {
PathParser pathParser = new PathParser();
pathParser.setPathHandler(app);
pathParser.parse(new StringReader(d));
} catch (ParseException ex) {
throw new BridgeException(glyphElement, 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);
shapeNode.setShape(transformedShape);
// set up the painter for the d part of the glyph
ShapePainter painter = PaintServer.convertFillAndStroke(
textElement, shapeNode, ctx);
shapeNode.setShapePainter(painter);
glyphContentNode.add(shapeNode);
}
}
// 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++;
}
}
if (numGlyphChildren > 0) { // the glyph has child elements
//
// 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);
Vector names = new Vector();
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) {
// not specified on parent either, use one em
s = String.valueOf(fontFace.getUnitsPerEm());
}
}
float horizAdvX;
try {
horizAdvX = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException ex) {
throw new BridgeException
(glyphElement, 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 ex) {
throw new BridgeException
(glyphElement, 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 font.horzAdvX/2
s = parentFontElement.getAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE);
if (s.length() == 0) {
// not specified on parent either, use one em/2
s = String.valueOf(fontFace.getUnitsPerEm()/2);
} else {
// need to divide by 2
s = String.valueOf(Float.parseFloat(s)/2);
}
}
}
float vertOriginX;
try {
vertOriginX = SVGUtilities.convertSVGNumber(s) * scale;
} catch (NumberFormatException ex) {
throw new BridgeException
(glyphElement, 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 ex) {
throw new BridgeException
(glyphElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_VERT_ORIGIN_Y_ATTRIBUTE, s});
}
Point2D vertOrigin = new Point2D.Float(vertOriginX, vertOriginY);
// return a new Glyph
return new Glyph(glyphContentNode, unicode, names,
orientation, arabicForm, lang, vertOrigin,
horizAdvX, vertAdvY, glyphCode, scale);
}
}
1.1 xml-batik/sources/org/apache/batik/bridge/SVGHKernElementBridge.java
Index: SVGHKernElementBridge.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.bridge;
import org.apache.batik.gvt.font.HKern;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
/**
* Bridge class for the <hkern> element.
*
* @author <a href="mailto:dean.jackson@cmis.csiro.au">Dean Jackson</a>
* @version $Id: SVGHKernElementBridge.java,v 1.1 2001/04/29 08:23:20 dino Exp $
*/
public class SVGHKernElementBridge implements Bridge, SVGConstants, ErrorConstants {
protected SVGHKernElementBridge() {}
public HKern createHKern(BridgeContext ctx, Element hkernElement, SVGFontFace fontFace, SVGGVTFont svgGvtFont) {
String g1 = hkernElement.getAttributeNS(null, SVG_G1_ATTRIBUTE);
String g2 = hkernElement.getAttributeNS(null, SVG_G2_ATTRIBUTE);
String k = hkernElement.getAttributeNS(null, SVG_K_ATTRIBUTE);
if (k.length() == 0) {
k = SVG_HKERN_K_DEFAULT_VALUE;
}
char character1 = svgGvtFont.unicodeForName(g1);
char character2 = svgGvtFont.unicodeForName(g2);
float kern = Float.valueOf(k).floatValue();
return new HKern(new char[]{character1}, new char[]{character2}, kern);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org