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 &lt;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 &lt;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 &lt;altGlyph> element.
       */
      public SVGAltGlyphElementBridge() {
      }
  
      /**
       * Constructs an array of Glyphs that represents the specified
       * &lt;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 &lt;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 &lt;font> element.
       */
      public SVGFontElementBridge() {
      }
  
      /**
       * Constructs a new SVGGVTFont that represents the specified &lt;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 &lt;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 &lt;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 &lt;font-face> element.
       */
      public SVGFontFaceElementBridge() {
      }
  
      /**
       * Creates an SVGFontFace that repesents the specified &lt;font-face> element.
       *
       * @param ctx The current bridge context.
       * @param fontFaceElement The &lt;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 &lt;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 &lt;glyph> element.
       */
      protected SVGGlyphElementBridge() {}
  
      /**
       * Constructs a new Glyph that represents the specified &lt;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 &lt;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