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 be...@apache.org on 2001/08/03 06:21:54 UTC

cvs commit: xml-batik/sources/org/apache/batik/svggen SVGFont.java SVGFontDescriptor.java SVGGraphicContextConverter.java SVGGraphics2D.java SVGGraphics2DUnitTester.java SVGSyntax.java

bella       01/08/02 21:21:54

  Modified:    sources/org/apache/batik/svggen SVGFont.java
                        SVGFontDescriptor.java
                        SVGGraphicContextConverter.java SVGGraphics2D.java
                        SVGGraphics2DUnitTester.java SVGSyntax.java
  Log:
  SVGGraphics2D now generates SVG fonts
  
  Revision  Changes    Path
  1.13      +233 -5    xml-batik/sources/org/apache/batik/svggen/SVGFont.java
  
  Index: SVGFont.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGFont.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- SVGFont.java	2001/04/26 14:17:19	1.12
  +++ SVGFont.java	2001/08/03 04:21:53	1.13
  @@ -12,6 +12,16 @@
   import java.util.HashMap;
   import java.util.Map;
   import java.awt.font.TextAttribute;
  +import java.awt.font.GlyphVector;
  +import java.awt.font.GlyphMetrics;
  +import java.awt.font.LineMetrics;
  +import java.awt.font.FontRenderContext;
  +import java.awt.geom.AffineTransform;
  +import java.awt.Shape;
  +
  +import org.w3c.dom.Document;
  +import org.w3c.dom.Element;
  +import org.w3c.dom.NodeList;
   
   import org.apache.batik.ext.awt.g2d.GraphicContext;
   
  @@ -21,7 +31,7 @@
    *
    * @author <a href="mailto:cjolif@ilog.fr">Christophe Jolif</a>
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGFont.java,v 1.12 2001/04/26 14:17:19 cjolif Exp $
  + * @version $Id: SVGFont.java,v 1.13 2001/08/03 04:21:53 bella Exp $
    */
   public class SVGFont extends AbstractSVGConverter {
       public static final float EXTRA_LIGHT =
  @@ -120,6 +130,61 @@
       }
   
       /**
  +     * The common font size to use when generating all SVG fonts.
  +     */
  +    static final int COMMON_FONT_SIZE = 100;
  +
  +    /**
  +     * Used to keep track of which characters have been rendered by each font
  +     * used.
  +     */
  +    static Map fontStringMap = new HashMap();
  +
  +    /**
  +     * @param generatorContext used to build Elements
  +     */
  +    public SVGFont(SVGGeneratorContext generatorContext) {
  +        super(generatorContext);
  +        fontStringMap = new HashMap();
  +    }
  +
  +    /**
  +     * Records that the specified font has been used to draw the text string.
  +     * This is so we can keep track of which glyphs are required for each
  +     * SVG font that is generated.
  +     */
  +    public static void recordFontUsage(String string, Font font) {
  +
  +        Font commonSizeFont = createCommonSizeFont(font);
  +        String fontKey = commonSizeFont.getFamily() + commonSizeFont.getStyle();
  +        String textUsingFont = (String)fontStringMap.get(fontKey);
  +        if (textUsingFont == null) {
  +            // font has not been used before
  +            textUsingFont = "";
  +        }
  +        // append any new characters to textUsingFont
  +        char ch;
  +        for (int i = 0; i < string.length(); i++) {
  +            ch = string.charAt(i);
  +            if (textUsingFont.indexOf(ch) == -1) {
  +                textUsingFont += ch;
  +            }
  +        }
  +        fontStringMap.put(fontKey, textUsingFont);
  +    }
  +
  +    /**
  +     * Creates a new Font that is of the common font size used for generating
  +     * SVG fonts. The new Font will be the same as the specified font, with
  +     * only its size attribute modified.
  +     */
  +    private static Font createCommonSizeFont(Font font) {
  +        HashMap attributes = new HashMap(font.getAttributes());
  +        attributes.put(TextAttribute.SIZE, new Float(COMMON_FONT_SIZE));
  +        return new Font(attributes);
  +    }
  +
  +    /**
        * Converts part or all of the input GraphicContext into
        * a set of attribute/value pairs and related definitions
        *
  @@ -130,21 +195,184 @@
        * @see org.apache.batik.svggen.SVGDescriptor
        */
       public SVGDescriptor toSVG(GraphicContext gc) {
  -        return toSVG(gc.getFont());
  +        return toSVG(gc.getFont(), gc.getFontRenderContext());
       }
   
       /**
        * @param font Font object which should be converted to a set
        *        of SVG attributes
  +     * @param frc The FontRenderContext which will be used to generate glyph
  +     * elements for the SVGFont definition element
        * @return description of attribute values that describe the font
        */
  -    public static SVGFontDescriptor toSVG(Font font) {
  +    public SVGFontDescriptor toSVG(Font font, FontRenderContext frc) {
  +
           String fontSize = "" + font.getSize();
           String fontWeight = weightToSVG(font);
           String fontStyle = styleToSVG(font);
           String fontFamilyStr = familyToSVG(font);
  -        return new SVGFontDescriptor(fontSize, fontWeight,
  -                                     fontStyle, fontFamilyStr);
  +
  +        Font commonSizeFont = createCommonSizeFont(font);
  +        String fontKey = commonSizeFont.getFamily() + commonSizeFont.getStyle();
  +
  +        String textUsingFont = (String)fontStringMap.get(fontKey);
  +
  +        if (textUsingFont == null) {
  +            // this font hasn't been used by any text yet,
  +            // so don't create an SVG Font element for it
  +            return new SVGFontDescriptor(fontSize, fontWeight,
  +                                         fontStyle, fontFamilyStr,
  +                                         null);
  +        }
  +
  +        Document domFactory = generatorContext.domFactory;
  +
  +        // see if a description already exists for this font
  +        SVGFontDescriptor fontDesc =
  +            (SVGFontDescriptor)descMap.get(fontKey);
  +
  +        Element fontDef;
  +
  +        if (fontDesc != null) {
  +
  +            // use the SVG Font element that has already been created
  +            fontDef = fontDesc.getDef();
  +
  +        } else {
  +
  +            // create a new SVG Font element
  +            fontDef = domFactory.createElementNS(SVG_NAMESPACE_URI,
  +                                                 SVG_FONT_TAG);
  +
  +            //
  +            // create the font-face element
  +            //
  +            Element fontFace = domFactory.createElementNS(SVG_NAMESPACE_URI,
  +                                                          SVG_FONT_FACE_TAG);
  +            String svgFontFamilyString = fontFamilyStr;
  +            if (fontFamilyStr.startsWith("'") && fontFamilyStr.endsWith("'")) {
  +                // get rid of the quotes
  +                svgFontFamilyString
  +                    = fontFamilyStr.substring(1, fontFamilyStr.length()-1);
  +            }
  +            fontFace.setAttributeNS(null, SVG_FONT_FAMILY_ATTRIBUTE,
  +                                    svgFontFamilyString);
  +            fontFace.setAttributeNS(null, SVG_FONT_WEIGHT_ATTRIBUTE,
  +                                    fontWeight);
  +            fontFace.setAttributeNS(null, SVG_FONT_STYLE_ATTRIBUTE,
  +                                    fontStyle);
  +            fontFace.setAttributeNS(null, SVG_UNITS_PER_EM_ATTRIBUTE,
  +                                    ""+COMMON_FONT_SIZE);
  +            fontDef.appendChild(fontFace);
  +
  +            //
  +            // create missing glyph element
  +            //
  +            Element missingGlyphElement
  +                = domFactory.createElementNS(SVG_NAMESPACE_URI,
  +                                             SVG_MISSING_GLYPH_TAG);
  +
  +            int missingGlyphCode[] = new int[1];
  +            missingGlyphCode[0] = commonSizeFont.getMissingGlyphCode();
  +            GlyphVector gv = commonSizeFont.createGlyphVector(frc, missingGlyphCode);
  +            Shape missingGlyphShape = gv.getGlyphOutline(0);
  +            GlyphMetrics gm = gv.getGlyphMetrics(0);
  +
  +            // need to turn the missing glyph upside down to be in the font
  +            // coordinate system (i.e Y axis up)
  +            AffineTransform at = AffineTransform.getScaleInstance(1, -1);
  +            missingGlyphShape = at.createTransformedShape(missingGlyphShape);
  +
  +            missingGlyphElement.setAttributeNS(null, SVG_D_ATTRIBUTE,
  +                                    SVGPath.toSVGPathData(missingGlyphShape));
  +            missingGlyphElement.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE,
  +                                               "" + gm.getAdvance());
  +            fontDef.appendChild(missingGlyphElement);
  +
  +            // set the font's default horizontal advance to be the same as
  +            // the missing glyph
  +            fontDef.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE,  "" + gm.getAdvance());
  +
  +            // set the ascent and descent attributes
  +            LineMetrics lm = commonSizeFont.getLineMetrics("By", frc);
  +            fontFace.setAttributeNS(null, SVG_ASCENT_ATTRIBUTE, "" + lm.getAscent());
  +            fontFace.setAttributeNS(null, SVG_DESCENT_ATTRIBUTE, "" + lm.getDescent());
  +
  +            //
  +            // Font ID
  +            //
  +            fontDef.setAttributeNS(null, ATTR_ID,
  +                                   generatorContext.idGenerator.
  +                                   generateID(ID_PREFIX_FONT));
  +        }
  +
  +        //
  +        // add any new glyphs to the fontDef here
  +        //
  +
  +        // process the characters in textUsingFont backwards since the new chars
  +        // are at the end, can stop when find a char that already has a glyph
  +        for (int i = textUsingFont.length()-1; i >= 0; i--) {
  +            char c = textUsingFont.charAt(i);
  +            boolean foundGlyph = false;
  +            NodeList fontChildren = fontDef.getChildNodes();
  +            for (int j = 0; j < fontChildren.getLength(); j++) {
  +                if (fontChildren.item(j) instanceof Element) {
  +                    Element childElement = (Element)fontChildren.item(j);
  +                    if (childElement.getAttributeNS(null,
  +                            SVG_UNICODE_ATTRIBUTE).equals(""+c)) {
  +                        foundGlyph = true;
  +                        break;
  +                    }
  +                }
  +            }
  +            if (!foundGlyph) {
  +                // need to create one
  +                Element glyphElement
  +                    = domFactory.createElementNS(SVG_NAMESPACE_URI,
  +                                                 SVG_GLYPH_TAG);
  +
  +                GlyphVector gv = commonSizeFont.createGlyphVector(frc, ""+c);
  +                Shape glyphShape = gv.getGlyphOutline(0);
  +                GlyphMetrics gm = gv.getGlyphMetrics(0);
  +
  +                // need to turn the glyph upside down to be in the font
  +                // coordinate system (i.e Y axis up)
  +                AffineTransform at = AffineTransform.getScaleInstance(1, -1);
  +                glyphShape = at.createTransformedShape(glyphShape);
  +
  +                glyphElement.setAttributeNS(null, SVG_D_ATTRIBUTE,
  +                                            SVGPath.toSVGPathData(glyphShape));
  +                glyphElement.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE,
  +                                            "" + gm.getAdvance());
  +                glyphElement.setAttributeNS(null, SVG_UNICODE_ATTRIBUTE,
  +                                            "" + c);
  +
  +                fontDef.appendChild(glyphElement);
  +            } else {
  +                // have reached the chars in textUsingFont that already
  +                // have glyphs, don't need to process any further
  +                break;
  +            }
  +        }
  +
  +        //
  +        // create a new font description for this instance of the font usage
  +        //
  +        SVGFontDescriptor newFontDesc
  +            = new SVGFontDescriptor(fontSize, fontWeight,
  +                                    fontStyle, fontFamilyStr,
  +                                    fontDef);
  +
  +        //
  +        // Update maps so that the font def can be reused if needed
  +        //
  +        if (fontDesc == null) {
  +            descMap.put(fontKey, newFontDesc);
  +            defSet.add(fontDef);
  +        }
  +
  +        return newFontDesc;
       }
   
       /**
  
  
  
  1.4       +14 -2     xml-batik/sources/org/apache/batik/svggen/SVGFontDescriptor.java
  
  Index: SVGFontDescriptor.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGFontDescriptor.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SVGFontDescriptor.java	2001/04/26 14:17:19	1.3
  +++ SVGFontDescriptor.java	2001/08/03 04:21:53	1.4
  @@ -16,10 +16,13 @@
    * Describes an SVG font
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGFontDescriptor.java,v 1.3 2001/04/26 14:17:19 cjolif Exp $
  + * @version $Id: SVGFontDescriptor.java,v 1.4 2001/08/03 04:21:53 bella Exp $
    * @see             org.apache.batik.svggen.SVGFont
    */
   public class SVGFontDescriptor implements SVGDescriptor, SVGSyntax {
  +
  +    private Element def;
  +
       private String fontSize;
       private String fontWeight;
       private String fontStyle;
  @@ -31,7 +34,8 @@
       public SVGFontDescriptor(String fontSize,
                                String fontWeight,
                                String fontStyle,
  -                             String fontFamily){
  +                             String fontFamily,
  +                             Element def){
           if (fontSize == null ||
               fontWeight == null ||
               fontStyle == null ||
  @@ -42,6 +46,7 @@
           this.fontWeight = fontWeight;
           this.fontStyle = fontStyle;
           this.fontFamily = fontFamily;
  +        this.def = def;
       }
   
       public Map getAttributeMap(Map attrMap){
  @@ -56,9 +61,16 @@
           return attrMap;
       }
   
  +    public Element getDef(){
  +        return def;
  +    }
  +
       public List getDefinitionSet(List defSet){
           if (defSet == null)
               defSet = new LinkedList();
  +
  +        if(def != null && !defSet.contains(def))
  +            defSet.add(def);
   
           return defSet;
       }
  
  
  
  1.10      +2 -2      xml-batik/sources/org/apache/batik/svggen/SVGGraphicContextConverter.java
  
  Index: SVGGraphicContextConverter.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGGraphicContextConverter.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- SVGGraphicContextConverter.java	2001/04/26 14:17:21	1.9
  +++ SVGGraphicContextConverter.java	2001/08/03 04:21:53	1.10
  @@ -22,7 +22,7 @@
    * SVG attributes.
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGGraphicContextConverter.java,v 1.9 2001/04/26 14:17:21 cjolif Exp $
  + * @version $Id: SVGGraphicContextConverter.java,v 1.10 2001/08/03 04:21:53 bella Exp $
    */
   public class SVGGraphicContextConverter {
       private static final int GRAPHIC_CONTEXT_CONVERTER_COUNT = 6;
  @@ -59,7 +59,7 @@
           compositeConverter = new SVGComposite(generatorContext);
           clipConverter = new SVGClip(generatorContext);
           hintsConverter = new SVGRenderingHints();
  -        fontConverter = new SVGFont();
  +        fontConverter = new SVGFont(generatorContext);
   
           int i=0;
           converters[i++] = paintConverter;
  
  
  
  1.20      +7 -1      xml-batik/sources/org/apache/batik/svggen/SVGGraphics2D.java
  
  Index: SVGGraphics2D.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGGraphics2D.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- SVGGraphics2D.java	2001/06/21 07:54:30	1.19
  +++ SVGGraphics2D.java	2001/08/03 04:21:53	1.20
  @@ -44,7 +44,7 @@
    *
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGGraphics2D.java,v 1.19 2001/06/21 07:54:30 cjolif Exp $
  + * @version $Id: SVGGraphics2D.java,v 1.20 2001/08/03 04:21:53 bella Exp $
    * @see                org.apache.batik.ext.awt.g2d.GraphicContext
    * @see                org.apache.batik.svggen.DOMTreeManager
    * @see                org.apache.batik.svggen.DOMGroupManager
  @@ -968,6 +968,12 @@
        */
       public void drawString(String s, float x, float y) {
           if (!textAsShapes) {
  +
  +            // record that the font is being used to draw this string, this is
  +            // so that the SVG Font element will only create glyphs for the
  +            // characters that are needed
  +            SVGFont.recordFontUsage(s, getFont());
  +
               Element text =
                   getDOMFactory().createElementNS(SVG_NAMESPACE_URI, SVG_TEXT_TAG);
               text.setAttributeNS(null, SVG_X_ATTRIBUTE,
  
  
  
  1.7       +4 -3      xml-batik/sources/org/apache/batik/svggen/SVGGraphics2DUnitTester.java
  
  Index: SVGGraphics2DUnitTester.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGGraphics2DUnitTester.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SVGGraphics2DUnitTester.java	2001/06/21 07:54:31	1.6
  +++ SVGGraphics2DUnitTester.java	2001/08/03 04:21:53	1.7
  @@ -31,7 +31,7 @@
    *
    * @author <a href="mailto:cjolif@ilog.fr">Christophe Jolif</a>
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGGraphics2DUnitTester.java,v 1.6 2001/06/21 07:54:31 cjolif Exp $
  + * @version $Id: SVGGraphics2DUnitTester.java,v 1.7 2001/08/03 04:21:53 bella Exp $
    */
   public class SVGGraphics2DUnitTester implements SVGConstants {
       private String[] args;
  @@ -818,11 +818,12 @@
           throws Exception {
           Document domFactory = getDocumentPrototype();
           Element group = domFactory.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
  -        SVGFont converter = new SVGFont();
  +        SVGFont converter = new SVGFont(getContext(domFactory));
  +        GraphicContext gc = new GraphicContext(new AffineTransform());
   
           for(int i=0; i<fonts.length; i++){
               Font font = fonts[i];
  -            Map attrMap = converter.toSVG(font).getAttributeMap(null);
  +            Map attrMap = converter.toSVG(font, gc.getFontRenderContext()).getAttributeMap(null);
               Element textElement = domFactory.createElementNS(SVG_NAMESPACE_URI, SVG_TEXT_TAG);
               Iterator iter = attrMap.keySet().iterator();
               while(iter.hasNext()){
  
  
  
  1.5       +2 -1      xml-batik/sources/org/apache/batik/svggen/SVGSyntax.java
  
  Index: SVGSyntax.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/svggen/SVGSyntax.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- SVGSyntax.java	2001/03/26 09:45:16	1.4
  +++ SVGSyntax.java	2001/08/03 04:21:53	1.5
  @@ -14,7 +14,7 @@
    * Contains the definition of the SVG tags and attribute names.
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGSyntax.java,v 1.4 2001/03/26 09:45:16 tkormann Exp $
  + * @version $Id: SVGSyntax.java,v 1.5 2001/08/03 04:21:53 bella Exp $
    */
   public interface SVGSyntax extends SVGConstants{
       /**
  @@ -47,6 +47,7 @@
       public static final String ID_PREFIX_FE_GAUSSIAN_BLUR = "feGaussianBlur";
       public static final String ID_PREFIX_FE_LIGHTING_FILTER = "feLightingFilter";
       public static final String ID_PREFIX_FE_SPECULAR_LIGHTING = "feSpecularLighting";
  +    public static final String ID_PREFIX_FONT = "font";
       public static final String ID_PREFIX_GENERIC_DEFS = "genericDefs";
       public static final String ID_PREFIX_LINEAR_GRADIENT = "linearGradient";
       public static final String ID_PREFIX_MASK = "mask";
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org