You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2013/07/29 23:45:23 UTC

svn commit: r1508208 [8/10] - in /xmlgraphics/fop/branches/Temp_FopFontsForSVG: ./ lib/ src/codegen/fonts/ src/java/org/apache/fop/afp/ src/java/org/apache/fop/afp/fonts/ src/java/org/apache/fop/afp/goca/ src/java/org/apache/fop/afp/svg/ src/java/org/a...

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java Mon Jul 29 21:45:20 2013
@@ -223,6 +223,26 @@ public class Java2DFontMetrics {
         return xHeight * 1000;
     }
 
+    public int getUnderlinePosition(String family, int style, int size) {
+        setFont(family, style, size);
+        return -Math.round(lineMetrics.getUnderlineOffset());
+    }
+
+    public int getUnderlineThickness(String family, int style, int size) {
+        setFont(family, style, size);
+        return Math.round(lineMetrics.getUnderlineThickness());
+    }
+
+    public int getStrikeoutPosition(String family, int style, int size) {
+        setFont(family, style, size);
+        return -Math.round(lineMetrics.getStrikethroughOffset());
+    }
+
+    public int getStrikeoutThickness(String family, int style, int size) {
+        setFont(family, style, size);
+        return Math.round(lineMetrics.getStrikethroughThickness());
+    }
+
     /**
      * Returns width (in 1/1000ths of point size) of character at
      * code point i

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java Mon Jul 29 21:45:20 2013
@@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFac
 import org.apache.batik.bridge.BridgeContext;
 import org.apache.batik.bridge.GVTBuilder;
 import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.font.DefaultFontFamilyResolver;
 
 import org.apache.fop.image.loader.batik.BatikUtil;
 import org.apache.fop.render.AbstractGenericSVGHandler;
@@ -128,8 +129,8 @@ public class Java2DSVGHandler extends Ab
 
         int x = info.currentXPosition;
         int y = info.currentYPosition;
-
-        SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
+        SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(), DefaultFontFamilyResolver.SINGLETON,
+                new AffineTransform());
 
         BridgeContext ctx = new BridgeContext(ua);
 

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java Mon Jul 29 21:45:20 2013
@@ -20,6 +20,7 @@
 package org.apache.fop.render.java2d;
 
 // Java
+import java.awt.Rectangle;
 import java.util.Map;
 import java.util.Set;
 
@@ -133,6 +134,22 @@ public class SystemFontMetricsMapper ext
         return java2DFontMetrics.getXHeight(family, style, size);
     }
 
+    public int getUnderlinePosition(int size) {
+        return java2DFontMetrics.getUnderlinePosition(family, style, size);
+    }
+
+    public int getUnderlineThickness(int size) {
+        return java2DFontMetrics.getUnderlineThickness(family, style, size);
+    }
+
+    public int getStrikeoutPosition(int size) {
+        return java2DFontMetrics.getStrikeoutPosition(family, style, size);
+    }
+
+    public int getStrikeoutThickness(int size) {
+        return java2DFontMetrics.getStrikeoutThickness(family, style, size);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -148,6 +165,10 @@ public class SystemFontMetricsMapper ext
         return java2DFontMetrics.getWidths(family, style, Java2DFontMetrics.FONT_SIZE);
     }
 
+    public Rectangle getBoundingBox(int glyphIndex, int size) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
     /**
      * {@inheritDoc}
      */

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java Mon Jul 29 21:45:20 2013
@@ -52,6 +52,7 @@ import org.apache.fop.svg.PDFBridgeConte
 import org.apache.fop.svg.PDFGraphics2D;
 import org.apache.fop.svg.SVGEventProducer;
 import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
 
 /**
  * Image Handler implementation which handles SVG images.
@@ -76,7 +77,8 @@ public class PDFImageHandlerSVG implemen
         }
 
         final float uaResolution = userAgent.getSourceResolution();
-        SVGUserAgent ua = new SVGUserAgent(userAgent, new AffineTransform());
+        SVGUserAgent ua = new SVGUserAgent(userAgent, new FOPFontFamilyResolverImpl(pdfContext.getFontInfo()),
+                new AffineTransform());
 
         GVTBuilder builder = new GVTBuilder();
 

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java Mon Jul 29 21:45:20 2013
@@ -40,6 +40,7 @@ import org.apache.fop.apps.FOPException;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.svg.AbstractFOPTranscoder;
 import org.apache.fop.svg.PDFDocumentGraphics2DConfigurator;
+import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
 
 /**
  * <p>This class enables to transcode an input to a PostScript document.</p>
@@ -115,6 +116,8 @@ public abstract class AbstractPSTranscod
                 this.fontInfo = PDFDocumentGraphics2DConfigurator.createFontInfo(
                         getEffectiveConfiguration(), useComplexScriptFeatures);
                 graphics.setCustomTextHandler(new NativeTextHandler(graphics, fontInfo));
+                ((FOPTranscoderUserAgent) userAgent).setFontFamilyResolver(
+                        new FOPFontFamilyResolverImpl(fontInfo));
             } catch (FOPException fe) {
                 throw new TranscoderException(fe);
             }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java Mon Jul 29 21:45:20 2013
@@ -41,6 +41,7 @@ import org.apache.fop.render.ImageHandle
 import org.apache.fop.render.RenderingContext;
 import org.apache.fop.svg.SVGEventProducer;
 import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
 
 /**
  * Image handler implementation which handles SVG images for PostScript output.
@@ -62,8 +63,8 @@ public class PSImageHandlerSVG implement
         boolean strokeText = false;
         //TODO Configure text stroking
 
-        SVGUserAgent ua
-             = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
+        SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(),
+                new FOPFontFamilyResolverImpl(psContext.getFontInfo()), new AffineTransform());
 
         PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
         graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSSVGHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSSVGHandler.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSSVGHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSSVGHandler.java Mon Jul 29 21:45:20 2013
@@ -249,8 +249,7 @@ public class PSSVGHandler extends Abstra
             strokeText = cfg.getChild("stroke-text", true).getValueAsBoolean(strokeText);
         }
 
-        SVGUserAgent ua
-             = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
+        SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(), null /* TODO */, new AffineTransform());
 
         PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
         graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSTextPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSTextPainter.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSTextPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/ps/PSTextPainter.java Mon Jul 29 21:45:20 2013
@@ -19,25 +19,21 @@
 
 package org.apache.fop.render.ps;
 
-import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.Paint;
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
+import java.awt.geom.Point2D.Double;
 import java.io.IOException;
-import java.text.AttributedCharacterIterator;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 
-import org.apache.batik.gvt.font.GVTGlyphVector;
 import org.apache.batik.gvt.text.TextPaintInfo;
-import org.apache.batik.gvt.text.TextSpanLayout;
 
 import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
 import org.apache.xmlgraphics.ps.PSGenerator;
@@ -48,7 +44,6 @@ import org.apache.fop.fonts.FontMetrics;
 import org.apache.fop.fonts.LazyFont;
 import org.apache.fop.fonts.MultiByteFont;
 import org.apache.fop.svg.NativeTextPainter;
-import org.apache.fop.util.CharUtilities;
 import org.apache.fop.util.HexEncoder;
 
 /**
@@ -62,10 +57,20 @@ import org.apache.fop.util.HexEncoder;
  */
 public class PSTextPainter extends NativeTextPainter {
 
-    private static final boolean DEBUG = false;
-
     private FontResourceCache fontResources;
 
+    private PSGraphics2D ps;
+
+    private PSGenerator gen;
+
+    private TextUtil textUtil;
+
+    private boolean flushCurrentRun;
+
+    private PSTextRun psRun;
+
+    private Double relPos;
+
     private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
 
     /**
@@ -82,165 +87,26 @@ public class PSTextPainter extends Nativ
         return g2d instanceof PSGraphics2D;
     }
 
-    /** {@inheritDoc} */
-    protected void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException {
-        AttributedCharacterIterator runaci = textRun.getACI();
-        runaci.first();
-
-        TextPaintInfo tpi = (TextPaintInfo)runaci.getAttribute(PAINT_INFO);
-        if (tpi == null || !tpi.visible) {
-            return;
-        }
-        if ((tpi != null) && (tpi.composite != null)) {
-            g2d.setComposite(tpi.composite);
-        }
-
-        //------------------------------------
-        TextSpanLayout layout = textRun.getLayout();
-        logTextRun(runaci, layout);
-        CharSequence chars = collectCharacters(runaci);
-        runaci.first(); //Reset ACI
-
-        final PSGraphics2D ps = (PSGraphics2D)g2d;
-        final PSGenerator gen = ps.getPSGenerator();
+    @Override
+    protected void preparePainting(Graphics2D g2d) {
+        ps = (PSGraphics2D) g2d;
+        gen = ps.getPSGenerator();
         ps.preparePainting();
+    }
 
-        if (DEBUG) {
-            log.debug("Text: " + chars);
-            gen.commentln("%Text: " + chars);
-        }
-
-        GeneralPath debugShapes = null;
-        if (DEBUG) {
-            debugShapes = new GeneralPath();
-        }
-
-        TextUtil textUtil = new TextUtil(gen);
-        textUtil.setupFonts(runaci);
-        if (!textUtil.hasFonts()) {
-            //Draw using Java2D when no native fonts are available
-            textRun.getLayout().draw(g2d);
-            return;
-        }
-
+    @Override
+    protected void saveGraphicsState() throws IOException {
         gen.saveGraphicsState();
-        gen.concatMatrix(g2d.getTransform());
-        Shape imclip = g2d.getClip();
-        clip(ps, imclip);
-
-        gen.writeln("BT"); //beginTextObject()
-
-        AffineTransform localTransform = new AffineTransform();
-        Point2D prevPos = null;
-        GVTGlyphVector gv = layout.getGlyphVector();
-        PSTextRun psRun = new PSTextRun(); //Used to split a text run into smaller runs
-        for (int index = 0, c = gv.getNumGlyphs(); index < c; index++) {
-            char ch = chars.charAt(index);
-            boolean visibleChar = gv.isGlyphVisible(index)
-                || (CharUtilities.isAnySpace(ch) && !CharUtilities.isZeroWidthSpace(ch));
-            logCharacter(ch, layout, index, visibleChar);
-            if (!visibleChar) {
-                continue;
-            }
-            Point2D glyphPos = gv.getGlyphPosition(index);
-
-            AffineTransform glyphTransform = gv.getGlyphTransform(index);
-            if (log.isTraceEnabled()) {
-                log.trace("pos " + glyphPos + ", transform " + glyphTransform);
-            }
-            if (DEBUG) {
-                Shape sh = gv.getGlyphLogicalBounds(index);
-                if (sh == null) {
-                    sh = new Ellipse2D.Double(glyphPos.getX(), glyphPos.getY(), 2, 2);
-                }
-                debugShapes.append(sh, false);
-            }
-
-            //Exact position of the glyph
-            localTransform.setToIdentity();
-            localTransform.translate(glyphPos.getX(), glyphPos.getY());
-            if (glyphTransform != null) {
-                localTransform.concatenate(glyphTransform);
-            }
-            localTransform.scale(1, -1);
-
-            boolean flushCurrentRun = false;
-            //Try to optimize by combining characters using the same font and on the same line.
-            if (glyphTransform != null) {
-                //Happens for text-on-a-path
-                flushCurrentRun = true;
-            }
-            if (psRun.getRunLength() >= 128) {
-                //Don't let a run get too long
-                flushCurrentRun = true;
-            }
-
-            //Note the position of the glyph relative to the previous one
-            Point2D relPos;
-            if (prevPos == null) {
-                relPos = new Point2D.Double(0, 0);
-            } else {
-                relPos = new Point2D.Double(
-                        glyphPos.getX() - prevPos.getX(),
-                        glyphPos.getY() - prevPos.getY());
-            }
-            if (psRun.vertChanges == 0
-                    && psRun.getHorizRunLength() > 2
-                    && relPos.getY() != 0) {
-                //new line
-                flushCurrentRun = true;
-            }
-
-            //Select the actual character to paint
-            char paintChar = (CharUtilities.isAnySpace(ch) ? ' ' : ch);
-
-            //Select (sub)font for character
-            Font f = textUtil.selectFontForChar(paintChar);
-            char mapped = f.mapChar(ch);
-            boolean fontChanging = textUtil.isFontChanging(f, mapped);
-            if (fontChanging) {
-                flushCurrentRun = true;
-            }
-
-            if (flushCurrentRun) {
-                //Paint the current run and reset for the next run
-                psRun.paint(ps, textUtil, tpi);
-                psRun.reset();
-            }
-
-            //Track current run
-            psRun.addCharacter(paintChar, relPos);
-            psRun.noteStartingTransformation(localTransform);
-
-            //Change font if necessary
-            if (fontChanging) {
-                textUtil.setCurrentFont(f, mapped);
-            }
+    }
 
-            //Update last position
-            prevPos = glyphPos;
-        }
-        psRun.paint(ps, textUtil, tpi);
-        gen.writeln("ET"); //endTextObject()
+    @Override
+    protected void restoreGraphicsState() throws IOException {
         gen.restoreGraphicsState();
-
-        if (DEBUG) {
-            //Paint debug shapes
-            g2d.setStroke(new BasicStroke(0));
-            g2d.setColor(Color.LIGHT_GRAY);
-            g2d.draw(debugShapes);
-        }
     }
 
-    private void applyColor(Paint paint, final PSGenerator gen) throws IOException {
-        if (paint == null) {
-            return;
-        } else if (paint instanceof Color) {
-            Color col = (Color)paint;
-            gen.useColor(col);
-        } else {
-            log.warn("Paint not supported: " + paint.toString());
-        }
+    @Override
+    protected void setInitialTransform(AffineTransform transform) throws IOException {
+        gen.concatMatrix(transform);
     }
 
     private PSFontResource getResourceForFont(Font f, String postfix) {
@@ -248,7 +114,8 @@ public class PSTextPainter extends Nativ
         return this.fontResources.getFontResourceForFontKey(key);
     }
 
-    private void clip(PSGraphics2D ps, Shape shape) throws IOException {
+    @Override
+    protected void clip(Shape shape) throws IOException {
         if (shape == null) {
             return;
         }
@@ -258,17 +125,76 @@ public class PSTextPainter extends Nativ
         ps.getPSGenerator().writeln("clip");
     }
 
+    @Override
+    protected void beginTextObject() throws IOException {
+        gen.writeln("BT");
+        textUtil = new TextUtil();
+        psRun = new PSTextRun(); //Used to split a text run into smaller runs
+    }
+
+    @Override
+    protected void endTextObject() throws IOException {
+        psRun.paint(ps, textUtil, tpi);
+        gen.writeln("ET");
+    }
+
+    @Override
+    protected void positionGlyph(Point2D prevPos, Point2D glyphPos, boolean reposition) {
+        flushCurrentRun = false;
+        //Try to optimize by combining characters using the same font and on the same line.
+        if (reposition) {
+            //Happens for text-on-a-path
+            flushCurrentRun = true;
+        }
+        if (psRun.getRunLength() >= 128) {
+            //Don't let a run get too long
+            flushCurrentRun = true;
+        }
+
+        //Note the position of the glyph relative to the previous one
+        if (prevPos == null) {
+            relPos = new Point2D.Double(0, 0);
+        } else {
+            relPos = new Point2D.Double(
+                    glyphPos.getX() - prevPos.getX(),
+                    glyphPos.getY() - prevPos.getY());
+        }
+        if (psRun.vertChanges == 0
+                && psRun.getHorizRunLength() > 2
+                && relPos.getY() != 0) {
+            //new line
+            flushCurrentRun = true;
+        }
+    }
+
+    @Override
+    protected void writeGlyph(char glyph, AffineTransform localTransform) throws IOException {
+        boolean fontChanging = textUtil.isFontChanging(font, glyph);
+        if (fontChanging) {
+            flushCurrentRun = true;
+        }
+
+        if (flushCurrentRun) {
+            //Paint the current run and reset for the next run
+            psRun.paint(ps, textUtil, tpi);
+            psRun.reset();
+        }
+
+        //Track current run
+        psRun.addGlyph(glyph, relPos);
+        psRun.noteStartingTransformation(localTransform);
+
+        //Change font if necessary
+        if (fontChanging) {
+            textUtil.setCurrentFont(font, glyph);
+        }
+    }
+
     private class TextUtil {
 
-        private PSGenerator gen;
-        private Font[] fonts;
         private Font currentFont;
         private int currentEncoding = -1;
 
-        public TextUtil(PSGenerator gen) {
-            this.gen = gen;
-        }
-
         public boolean isMultiByte(Font f) {
             FontMetrics metrics = f.getFontMetrics();
             boolean multiByte = metrics instanceof MultiByteFont || metrics instanceof LazyFont
@@ -276,15 +202,6 @@ public class PSTextPainter extends Nativ
             return multiByte;
         }
 
-        public Font selectFontForChar(char ch) {
-            for (int i = 0, c = fonts.length; i < c; i++) {
-                if (fonts[i].hasChar(ch)) {
-                    return fonts[i];
-                }
-            }
-            return fonts[0]; //TODO Maybe fall back to painting with shapes
-        }
-
         public void writeTextMatrix(AffineTransform transform) throws IOException {
             double[] matrix = new double[6];
             transform.getMatrix(matrix);
@@ -335,27 +252,19 @@ public class PSTextPainter extends Nativ
             setCurrentFont(font, encoding);
         }
 
-        public void setupFonts(AttributedCharacterIterator runaci) {
-            this.fonts = findFonts(runaci);
-        }
-
-        public boolean hasFonts() {
-            return (fonts != null) && (fonts.length > 0);
-        }
-
     }
 
     private class PSTextRun {
 
         private AffineTransform textTransform;
-        private List relativePositions = new java.util.LinkedList();
-        private StringBuffer currentChars = new StringBuffer();
+        private List<Point2D> relativePositions = new LinkedList<Point2D>();
+        private StringBuffer currentGlyphs = new StringBuffer();
         private int horizChanges = 0;
         private int vertChanges = 0;
 
         public void reset() {
             textTransform = null;
-            currentChars.setLength(0);
+            currentGlyphs.setLength(0);
             horizChanges = 0;
             vertChanges = 0;
             relativePositions.clear();
@@ -369,9 +278,9 @@ public class PSTextPainter extends Nativ
             return 0;
         }
 
-        public void addCharacter(char paintChar, Point2D relPos) {
+        public void addGlyph(char glyph, Point2D relPos) {
             addRelativePosition(relPos);
-            currentChars.append(paintChar);
+            currentGlyphs.append(glyph);
         }
 
         private void addRelativePosition(Point2D relPos) {
@@ -393,7 +302,7 @@ public class PSTextPainter extends Nativ
         }
 
         public int getRunLength() {
-            return currentChars.length();
+            return currentGlyphs.length();
         }
 
         private boolean isXShow() {
@@ -407,9 +316,6 @@ public class PSTextPainter extends Nativ
         public void paint(PSGraphics2D g2d, TextUtil textUtil, TextPaintInfo tpi)
                     throws IOException {
             if (getRunLength() > 0) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Text run: " + currentChars);
-                }
                 textUtil.writeTextMatrix(this.textTransform);
                 if (isXShow()) {
                     log.debug("Horizontal text: xshow");
@@ -431,25 +337,20 @@ public class PSTextPainter extends Nativ
 
         private void paintXYShow(PSGraphics2D g2d, TextUtil textUtil, Paint paint,
                 boolean x, boolean y) throws IOException {
-            PSGenerator gen = textUtil.gen;
-            char firstChar = this.currentChars.charAt(0);
-            //Font only has to be setup up before the first character
-            Font f = textUtil.selectFontForChar(firstChar);
-            char mapped = f.mapChar(firstChar);
-            textUtil.selectFont(f, mapped);
-            textUtil.setCurrentFont(f, mapped);
-            applyColor(paint, gen);
+            char glyph = currentGlyphs.charAt(0);
+            textUtil.selectFont(font, glyph);
+            textUtil.setCurrentFont(font, glyph);
+            applyColor(paint);
 
-            boolean multiByte = textUtil.isMultiByte(f);
+            boolean multiByte = textUtil.isMultiByte(font);
             StringBuffer sb = new StringBuffer();
             sb.append(multiByte ? '<' : '(');
-            for (int i = 0, c = this.currentChars.length(); i < c; i++) {
-                char ch = this.currentChars.charAt(i);
-                mapped = f.mapChar(ch);
+            for (int i = 0, c = this.currentGlyphs.length(); i < c; i++) {
+                glyph = this.currentGlyphs.charAt(i);
                 if (multiByte) {
-                    sb.append(HexEncoder.encode(mapped));
+                    sb.append(HexEncoder.encode(glyph));
                 } else {
-                    char codepoint = (char) (mapped % 256);
+                    char codepoint = (char) (glyph % 256);
                     PSGenerator.escapeChar(codepoint, sb);
                 }
             }
@@ -457,9 +358,9 @@ public class PSTextPainter extends Nativ
             if (x || y) {
                 sb.append("\n[");
                 int idx = 0;
-                Iterator iter = this.relativePositions.iterator();
+                Iterator<Point2D> iter = this.relativePositions.iterator();
                 while (iter.hasNext()) {
-                    Point2D pt = (Point2D)iter.next();
+                    Point2D pt = iter.next();
                     if (idx > 0) {
                         if (x) {
                             sb.append(format(gen, pt.getX()));
@@ -500,6 +401,17 @@ public class PSTextPainter extends Nativ
             gen.writeln(sb.toString());
         }
 
+        private void applyColor(Paint paint) throws IOException {
+            if (paint == null) {
+                return;
+            } else if (paint instanceof Color) {
+                Color col = (Color) paint;
+                gen.useColor(col);
+            } else {
+                log.warn("Paint not supported: " + paint.toString());
+            }
+        }
+
         private String format(PSGenerator gen, double coord) {
             if (Math.abs(coord) < 0.00001) {
                 return "0";
@@ -510,30 +422,21 @@ public class PSTextPainter extends Nativ
 
         private void paintStrokedGlyphs(PSGraphics2D g2d, TextUtil textUtil,
                 Paint strokePaint, Stroke stroke) throws IOException {
-            PSGenerator gen = textUtil.gen;
-
-            applyColor(strokePaint, gen);
+            applyColor(strokePaint);
             PSGraphics2D.applyStroke(stroke, gen);
 
-            Font f = null;
-            Iterator iter = this.relativePositions.iterator();
+            Iterator<Point2D> iter = this.relativePositions.iterator();
             iter.next();
             Point2D pos = new Point2D.Double(0, 0);
             gen.writeln("0 0 M");
-            for (int i = 0, c = this.currentChars.length(); i < c; i++) {
-                char ch = this.currentChars.charAt(0);
-                if (i == 0) {
-                    //Font only has to be setup up before the first character
-                    f = textUtil.selectFontForChar(ch);
-                }
-                char mapped = f.mapChar(ch);
+            for (int i = 0, c = this.currentGlyphs.length(); i < c; i++) {
+                char mapped = this.currentGlyphs.charAt(i);
                 if (i == 0) {
-                    textUtil.selectFont(f, mapped);
-                    textUtil.setCurrentFont(f, mapped);
+                    textUtil.selectFont(font, mapped);
+                    textUtil.setCurrentFont(font, mapped);
                 }
                 //add glyph outlines to current path
-                mapped = f.mapChar(this.currentChars.charAt(i));
-                FontMetrics metrics = f.getFontMetrics();
+                FontMetrics metrics = font.getFontMetrics();
                 boolean multiByte = metrics instanceof MultiByteFont
                         || metrics instanceof LazyFont
                                 && ((LazyFont) metrics).getRealFont() instanceof MultiByteFont;
@@ -542,14 +445,14 @@ public class PSTextPainter extends Nativ
                     gen.write(HexEncoder.encode(mapped));
                     gen.write(">");
                 } else {
-                    char codepoint = (char)(mapped % 256);
+                    char codepoint = (char) (mapped % 256);
                     gen.write("(" + codepoint + ")");
                 }
                 gen.writeln(" false charpath");
 
                 if (iter.hasNext()) {
                     //Position for the next character
-                    Point2D pt = (Point2D)iter.next();
+                    Point2D pt = iter.next();
                     pos.setLocation(pos.getX() + pt.getX(), pos.getY() - pt.getY());
                     gen.writeln(gen.formatDouble5(pos.getX()) + " "
                             + gen.formatDouble5(pos.getY()) + " M");

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/ACIUtils.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/ACIUtils.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/ACIUtils.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/ACIUtils.java Mon Jul 29 21:45:20 2013
@@ -38,7 +38,8 @@ import org.apache.batik.gvt.text.GVTAttr
 
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.svg.font.FOPGVTFont;
+import org.apache.fop.svg.font.FOPGVTFontFamily;
 
 /**
  * Utilities for java.text.AttributedCharacterIterator.
@@ -64,57 +65,43 @@ public final class ACIUtils {
         @SuppressWarnings("unchecked")
         List<GVTFontFamily> gvtFonts = (List<GVTFontFamily>) aci.getAttribute(
                 GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
-        Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
-        Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
-        Float fontSize = (Float) aci.getAttribute(TextAttribute.SIZE);
-
-        String style = toStyle(posture);
-        int weight = toCSSWeight(taWeight);
-        int fsize = (int)(fontSize.floatValue() * 1000);
+        String style = toStyle((Float) aci.getAttribute(TextAttribute.POSTURE));
+        int weight = toCSSWeight((Float) aci.getAttribute(TextAttribute.WEIGHT));
+        float fontSize = ((Float) aci.getAttribute(TextAttribute.SIZE)).floatValue();
 
         String firstFontFamily = null;
-
         //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES
         //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set
-        /* The following code section is not available until Batik 1.7 is released. */
-        GVTFont gvtFont = (GVTFont)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
+        GVTFont gvtFont = (GVTFont) aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
         if (gvtFont != null) {
             String gvtFontFamily = gvtFont.getFamilyName();
-            if (fontInfo.hasFont(gvtFontFamily, style, weight)) {
-                FontTriplet triplet = fontInfo.fontLookup(gvtFontFamily, style,
-                                                          weight);
-                Font f = fontInfo.getFontInstance(triplet, fsize);
+            if (gvtFont instanceof FOPGVTFont) {
+                Font font = ((FOPGVTFont) gvtFont).getFont();
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Found a font that matches the GVT font: "
                               + gvtFontFamily + ", " + weight + ", " + style
-                              + " -> " + f);
+                              + " -> " + font);
                 }
-                fonts.add(f);
+                fonts.add(font);
             }
             firstFontFamily = gvtFontFamily;
         }
 
         if (gvtFonts != null) {
             boolean haveInstanceOfSVGFontFamily = false;
-            for (GVTFontFamily fam : gvtFonts) {
-                if (fam instanceof SVGFontFamily) {
+            for (GVTFontFamily fontFamily : gvtFonts) {
+                if (fontFamily instanceof SVGFontFamily) {
                     haveInstanceOfSVGFontFamily = true;
-                }
-                String fontFamily = fam.getFamilyName();
-                if (fontInfo.hasFont(fontFamily, style, weight)) {
-                    FontTriplet triplet = fontInfo.fontLookup(fontFamily, style,
-                                                       weight);
-                    Font f = fontInfo.getFontInstance(triplet, fsize);
+                } else if (fontFamily instanceof FOPGVTFontFamily) {
+                    Font font = ((FOPGVTFontFamily) fontFamily).deriveFont(fontSize, aci).getFont();
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("Found a font that matches the GVT font family: "
-                                + fontFamily + ", " + weight + ", " + style
-                                + " -> " + f);
+                                + fontFamily.getFamilyName() + ", " + weight + ", " + style + " -> " + font);
                     }
-                    fonts.add(f);
+                    fonts.add(font);
                 }
                 if (firstFontFamily == null) {
-                    firstFontFamily = fontFamily;
+                    firstFontFamily = fontFamily.getFamilyName();
                 }
             }
             // SVG fonts are embedded fonts in the SVG document and are rarely used; however if they
@@ -126,25 +113,10 @@ public final class ACIUtils {
                 return null; // Let Batik paint this text!
             }
         }
-        if (fonts.isEmpty()) {
-            if (firstFontFamily == null) {
-                //This will probably never happen. Just to be on the safe side.
-                firstFontFamily = "any";
-            }
-            //lookup with fallback possibility (incl. substitution notification)
-            FontTriplet triplet = fontInfo.fontLookup(firstFontFamily, style, weight);
-            Font f = fontInfo.getFontInstance(triplet, fsize);
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("Falling back to adjustable font lookup up for: "
-                        + firstFontFamily + ", " + weight + ", " + style
-                        + " -> " + f);
-            }
-            fonts.add(f);
-        }
-        return fonts.toArray(new Font[fonts.size()]);
+        return fonts.isEmpty() ? null : fonts.toArray(new Font[fonts.size()]);
     }
 
-    private static int toCSSWeight(Float weight) {
+    public static int toCSSWeight(Float weight) {
         if (weight == null) {
             return 400;
         } else if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
@@ -170,7 +142,7 @@ public final class ACIUtils {
         }
     }
 
-    private static String toStyle(Float posture) {
+    public static String toStyle(Float posture) {
         return ((posture != null) && (posture.floatValue() > 0.0))
                        ? Font.STYLE_ITALIC
                        : Font.STYLE_NORMAL;

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java Mon Jul 29 21:45:20 2013
@@ -23,20 +23,15 @@ import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.Paint;
 import java.awt.Shape;
-import java.awt.font.TextAttribute;
-import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.text.AttributedCharacterIterator;
 import java.text.CharacterIterator;
-import java.util.Iterator;
-import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import org.apache.batik.dom.svg.SVGOMTextElement;
 import org.apache.batik.gvt.TextNode;
 import org.apache.batik.gvt.TextPainter;
 import org.apache.batik.gvt.renderer.StrokingTextPainter;
@@ -66,15 +61,15 @@ public abstract class AbstractFOPTextPai
      * Use the stroking text painter to get the bounds and shape.
      * Also used as a fallback to draw the string with strokes.
      */
-    protected static final TextPainter
-        PROXY_PAINTER = StrokingTextPainter.getInstance();
+    private final TextPainter proxyTextPainter;
 
     /**
      * Create a new PS text painter with the given font information.
      * @param nativeTextHandler the NativeTextHandler instance used for text painting
      */
-    public AbstractFOPTextPainter(FOPTextHandler nativeTextHandler) {
+    public AbstractFOPTextPainter(FOPTextHandler nativeTextHandler, TextPainter proxyTextPainter) {
         this.nativeTextHandler = nativeTextHandler;
+        this.proxyTextPainter = proxyTextPainter;
     }
 
     /**
@@ -85,19 +80,10 @@ public abstract class AbstractFOPTextPai
      * @param g2d the Graphics2D to use
      */
     public void paint(TextNode node, Graphics2D g2d) {
-        Point2D loc = node.getLocation();
-        if (!isSupportedGraphics2D(g2d) || hasUnsupportedAttributes(node)) {
-            if (log.isDebugEnabled()) {
-                log.debug("painting text node " + node
-                    + " by stroking due to unsupported attributes or an incompatible Graphics2D");
-            }
-            PROXY_PAINTER.paint(node, g2d);
-        } else {
-            if (log.isDebugEnabled()) {
-                log.debug("painting text node " + node + " normally.");
-            }
-            paintTextRuns(node.getTextRuns(), g2d, loc);
+        if (isSupportedGraphics2D(g2d)) {
+            new TextRunPainter().paintTextRuns(node.getTextRuns(), g2d, node.getLocation());
         }
+        proxyTextPainter.paint(node, g2d);
     }
 
     /**
@@ -109,190 +95,99 @@ public abstract class AbstractFOPTextPai
      */
     protected abstract boolean isSupportedGraphics2D(Graphics2D g2d);
 
-    private boolean hasUnsupportedAttributes(TextNode node) {
-        Iterator iter = node.getTextRuns().iterator();
-        while (iter.hasNext()) {
-            StrokingTextPainter.TextRun
-                    run = (StrokingTextPainter.TextRun)iter.next();
-            AttributedCharacterIterator aci = run.getACI();
-            boolean hasUnsupported = hasUnsupportedAttributes(aci);
-            if (hasUnsupported) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
-        boolean hasUnsupported = false;
+    private class TextRunPainter {
 
-        Font font = getFont(aci);
-        String text = getText(aci);
-        if (hasUnsupportedGlyphs(text, font)) {
-            log.trace("-> Unsupported glyphs found");
-            hasUnsupported = true;
-        }
+        private Point2D currentLocation;
 
-        TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
-            GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
-        if ((tpi != null)
-                && ((tpi.strokeStroke != null && tpi.strokePaint != null)
-                    || (tpi.strikethroughStroke != null)
-                    || (tpi.underlineStroke != null)
-                    || (tpi.overlineStroke != null))) {
-                        log.trace("-> under/overlines etc. found");
-            hasUnsupported = true;
-        }
-
-        //Alpha is not supported
-        Paint foreground = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
-        if (foreground instanceof Color) {
-            Color col = (Color)foreground;
-            if (col.getAlpha() != 255) {
-                log.trace("-> transparency found");
-                hasUnsupported = true;
+        public void paintTextRuns(Iterable<StrokingTextPainter.TextRun> textRuns, Graphics2D g2d,
+                Point2D nodeLocation) {
+            currentLocation = new Point2D.Double(nodeLocation.getX(), nodeLocation.getY());
+            for (StrokingTextPainter.TextRun run : textRuns) {
+                paintTextRun(run, g2d);
             }
         }
 
-        Object letSpace = aci.getAttribute(
-                            GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
-        if (letSpace != null) {
-            log.trace("-> letter spacing found");
-            hasUnsupported = true;
-        }
-
-        Object wordSpace = aci.getAttribute(
-                             GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
-        if (wordSpace != null) {
-            log.trace("-> word spacing found");
-            hasUnsupported = true;
-        }
-
-        Object lengthAdjust = aci.getAttribute(
-                            GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST);
-        if (lengthAdjust != null) {
-            log.trace("-> length adjustments found");
-            hasUnsupported = true;
-        }
-
-        Object writeMod = aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE);
-        if (writeMod != null
-            && !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
-                  writeMod)) {
-            log.trace("-> Unsupported writing modes found");
-            hasUnsupported = true;
-        }
-
-        Object vertOr = aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
-        if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
-                  vertOr)) {
-            log.trace("-> vertical orientation found");
-            hasUnsupported = true;
-        }
-
-        Object rcDel = aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
-        //Batik 1.6 returns null here which makes it impossible to determine whether this can
-        //be painted or not, i.e. fall back to stroking. :-(
-        if (rcDel != null && !(rcDel instanceof SVGOMTextElement)) {
-            log.trace("-> spans found");
-            hasUnsupported = true; //Filter spans
-        }
-
-        if (hasUnsupported) {
-            log.trace("Unsupported attributes found in ACI, using StrokingTextPainter");
-        }
-        return hasUnsupported;
-    }
-
-    /**
-     * Paint a list of text runs on the Graphics2D at a given location.
-     * @param textRuns the list of text runs
-     * @param g2d the Graphics2D to paint to
-     * @param loc the current location of the "cursor"
-     */
-    protected void paintTextRuns(List textRuns, Graphics2D g2d, Point2D loc) {
-        Point2D currentloc = loc;
-        Iterator i = textRuns.iterator();
-        while (i.hasNext()) {
-            StrokingTextPainter.TextRun
-                    run = (StrokingTextPainter.TextRun)i.next();
-            currentloc = paintTextRun(run, g2d, currentloc);
-        }
-    }
-
-    /**
-     * Paint a single text run on the Graphics2D at a given location.
-     * @param run the text run to paint
-     * @param g2d the Graphics2D to paint to
-     * @param loc the current location of the "cursor"
-     * @return the new location of the "cursor" after painting the text run
-     */
-    protected Point2D paintTextRun(StrokingTextPainter.TextRun run, Graphics2D g2d, Point2D loc) {
-        AttributedCharacterIterator aci = run.getACI();
-        aci.first();
-
-        updateLocationFromACI(aci, loc);
-        AffineTransform at = g2d.getTransform();
-        loc = at.transform(loc, null);
-
-        // font
-        Font font = getFont(aci);
-        if (font != null) {
-            nativeTextHandler.setOverrideFont(font);
-        }
-
-        // color
-        TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
-        if (tpi == null) {
-            return loc;
-        }
-        Paint foreground = tpi.fillPaint;
-        if (foreground instanceof Color) {
-            Color col = (Color)foreground;
-            g2d.setColor(col);
-        }
-        g2d.setPaint(foreground);
-
-        // text anchor
-        TextNode.Anchor anchor = (TextNode.Anchor)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
-
-        // text
-        String txt = getText(aci);
-        float advance = getStringWidth(txt, font);
-        float tx = 0;
-        if (anchor != null) {
-            switch (anchor.getType()) {
-            case TextNode.Anchor.ANCHOR_MIDDLE:
-                tx = -advance / 2;
-                break;
-            case TextNode.Anchor.ANCHOR_END:
-                tx = -advance;
-                break;
-            default: //nop
+        private void paintTextRun(StrokingTextPainter.TextRun run, Graphics2D g2d) {
+            AttributedCharacterIterator aci = run.getACI();
+            aci.first();
+            updateLocationFromACI(aci, currentLocation);
+            // font
+            Font font = getFont(aci);
+            if (font != null) {
+                nativeTextHandler.setOverrideFont(font);
             }
-        }
-
-        // draw string
-        double x = loc.getX();
-        double y = loc.getY();
-        try {
+            // color
+            TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
+            if (tpi == null) {
+                return;
+            }
+            Paint foreground = tpi.fillPaint;
+            if (foreground instanceof Color) {
+                Color col = (Color) foreground;
+                g2d.setColor(col);
+            }
+            g2d.setPaint(foreground);
+            // text anchor
+            TextNode.Anchor anchor = (TextNode.Anchor) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+            // text
+            String txt = getText(aci);
+            double advance = font == null ? run.getLayout().getAdvance2D().getX() : getStringWidth(txt, font);
+            double tx = 0;
+            if (anchor != null) {
+                switch (anchor.getType()) {
+                case TextNode.Anchor.ANCHOR_MIDDLE:
+                    tx = -advance / 2;
+                    break;
+                case TextNode.Anchor.ANCHOR_END:
+                    tx = -advance;
+                    break;
+                default: //nop
+                }
+            }
+            // draw string
+            Point2D outputLocation = g2d.getTransform().transform(currentLocation, null);
+            double x = outputLocation.getX();
+            double y = outputLocation.getY();
             try {
-                nativeTextHandler.drawString(g2d, txt, (float)x + tx, (float)y);
-            } catch (IOException ioe) {
-                if (g2d instanceof AFPGraphics2D) {
-                    ((AFPGraphics2D)g2d).handleIOException(ioe);
+                try {
+                    //TODO draw underline and overline if set
+                    nativeTextHandler.drawString(g2d, txt, (float) (x + tx), (float) y);
+                    //TODO draw strikethrough if set
+                } catch (IOException ioe) {
+                    if (g2d instanceof AFPGraphics2D) {
+                        ((AFPGraphics2D) g2d).handleIOException(ioe);
+                    }
                 }
+            } finally {
+                nativeTextHandler.setOverrideFont(null);
+            }
+            currentLocation.setLocation(currentLocation.getX() + advance, currentLocation.getY());
+        }
+        private void updateLocationFromACI(AttributedCharacterIterator aci, Point2D loc) {
+            //Adjust position of span
+            Float xpos = (Float) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.X);
+            Float ypos = (Float) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.Y);
+            Float dxpos = (Float) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.DX);
+            Float dypos = (Float) aci.getAttribute(
+                    GVTAttributedCharacterIterator.TextAttribute.DY);
+            if (xpos != null) {
+                loc.setLocation(xpos.doubleValue(), loc.getY());
+            }
+            if (ypos != null) {
+                loc.setLocation(loc.getX(), ypos.doubleValue());
+            }
+            if (dxpos != null) {
+                loc.setLocation(loc.getX() + dxpos.doubleValue(), loc.getY());
+            }
+            if (dypos != null) {
+                loc.setLocation(loc.getX(), loc.getY() + dypos.doubleValue());
             }
-        } finally {
-            nativeTextHandler.setOverrideFont(null);
         }
-        loc.setLocation(loc.getX() + advance, loc.getY());
-        return loc;
     }
 
     /**
@@ -305,36 +200,9 @@ public abstract class AbstractFOPTextPai
         for (char c = aci.first(); c != CharacterIterator.DONE; c = aci.next()) {
             sb.append(c);
         }
-        aci.first();
         return sb.toString();
     }
 
-    private void updateLocationFromACI(
-                AttributedCharacterIterator aci,
-                Point2D loc) {
-        //Adjust position of span
-        Float xpos = (Float)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.X);
-        Float ypos = (Float)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.Y);
-        Float dxpos = (Float)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.DX);
-        Float dypos = (Float)aci.getAttribute(
-                GVTAttributedCharacterIterator.TextAttribute.DY);
-        if (xpos != null) {
-            loc.setLocation(xpos.doubleValue(), loc.getY());
-        }
-        if (ypos != null) {
-            loc.setLocation(loc.getX(), ypos.doubleValue());
-        }
-        if (dxpos != null) {
-            loc.setLocation(loc.getX() + dxpos.doubleValue(), loc.getY());
-        }
-        if (dypos != null) {
-            loc.setLocation(loc.getX(), loc.getY() + dypos.doubleValue());
-        }
-    }
-
     private Font getFont(AttributedCharacterIterator aci) {
         Font[] fonts = ACIUtils.findFontsForBatikACI(aci, nativeTextHandler.getFontInfo());
         return fonts == null ? null : fonts[0];
@@ -360,21 +228,6 @@ public abstract class AbstractFOPTextPai
         return wordWidth / 1000f;
     }
 
-    private boolean hasUnsupportedGlyphs(String str, Font font) {
-         if (font == null) {
-            return true;
-         }
-        for (int i = 0; i < str.length(); i++) {
-            char c = str.charAt(i);
-            if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
-                if (!font.hasChar(c)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Get the outline shape of the text characters.
      * This uses the StrokingTextPainter to get the outline
@@ -384,7 +237,7 @@ public abstract class AbstractFOPTextPai
      * @return the outline shape of the text characters
      */
     public Shape getOutline(TextNode node) {
-        return PROXY_PAINTER.getOutline(node);
+        return proxyTextPainter.getOutline(node);
     }
 
     /**
@@ -399,7 +252,7 @@ public abstract class AbstractFOPTextPai
         /* (todo) getBounds2D() is too slow
          * because it uses the StrokingTextPainter. We should implement this
          * method ourselves. */
-        return PROXY_PAINTER.getBounds2D(node);
+        return proxyTextPainter.getBounds2D(node);
     }
 
     /**
@@ -411,7 +264,7 @@ public abstract class AbstractFOPTextPai
      * @return the bounds of the text
      */
     public Rectangle2D getGeometryBounds(TextNode node) {
-        return PROXY_PAINTER.getGeometryBounds(node);
+        return proxyTextPainter.getGeometryBounds(node);
     }
 
     // Methods that have no purpose for PS

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java Mon Jul 29 21:45:20 2013
@@ -36,9 +36,9 @@ import org.apache.avalon.framework.confi
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.impl.SimpleLog;
 
-import org.apache.batik.bridge.UserAgent;
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.dom.util.DocumentFactory;
+import org.apache.batik.gvt.font.FontFamilyResolver;
 import org.apache.batik.transcoder.ErrorHandler;
 import org.apache.batik.transcoder.SVGAbstractTranscoder;
 import org.apache.batik.transcoder.TranscoderException;
@@ -56,6 +56,8 @@ import org.apache.xmlgraphics.image.load
 import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
 import org.apache.xmlgraphics.util.UnitConv;
 
+import org.apache.fop.svg.font.FOPFontFamilyResolver;
+
 /**
  * This is the common base class of all of FOP's transcoders.
  */
@@ -86,11 +88,6 @@ public abstract class AbstractFOPTransco
     /** The value to turn off text stroking. */
     public static final Boolean VALUE_FORMAT_OFF = Boolean.FALSE;
 
-    /**
-     * The user agent dedicated to this Transcoder.
-     */
-    protected UserAgent userAgent = createUserAgent();
-
     private Log logger;
     private EntityResolver resolver;
     private Configuration cfg = null;
@@ -113,7 +110,7 @@ public abstract class AbstractFOPTransco
      * this method if you need non-default behaviour.
      * @return UserAgent the newly created user agent
      */
-    protected UserAgent createUserAgent() {
+    protected FOPTranscoderUserAgent createUserAgent() {
         return new FOPTranscoderUserAgent();
     }
 
@@ -331,6 +328,8 @@ public abstract class AbstractFOPTransco
      */
     protected class FOPTranscoderUserAgent extends SVGAbstractTranscoderUserAgent {
 
+        private FOPFontFamilyResolver fontFamilyResolver;
+
         /**
          * Displays the specified error message using the {@link ErrorHandler}.
          * @param message the message to display
@@ -386,6 +385,15 @@ public abstract class AbstractFOPTransco
             return "print";
         }
 
+        public void setFontFamilyResolver(FOPFontFamilyResolver resolver) {
+            fontFamilyResolver = resolver;
+        }
+
+        @Override
+        public FontFamilyResolver getFontFamilyResolver() {
+            return fontFamilyResolver;
+        }
+
     }
 
 }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/NativeTextPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/NativeTextPainter.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/NativeTextPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/NativeTextPainter.java Mon Jul 29 21:45:20 2013
@@ -19,7 +19,14 @@
 
 package org.apache.fop.svg;
 
+import java.awt.BasicStroke;
+import java.awt.Color;
 import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
 import java.io.IOException;
 import java.text.AttributedCharacterIterator;
 import java.util.List;
@@ -27,11 +34,17 @@ import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.batik.bridge.SVGGVTFont;
+import org.apache.batik.gvt.font.FontFamilyResolver;
+import org.apache.batik.gvt.font.GVTGlyphVector;
 import org.apache.batik.gvt.renderer.StrokingTextPainter;
+import org.apache.batik.gvt.text.TextPaintInfo;
 import org.apache.batik.gvt.text.TextSpanLayout;
 
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
+import org.apache.fop.svg.font.FOPGVTFont;
 import org.apache.fop.util.CharUtilities;
 
 /**
@@ -41,17 +54,26 @@ import org.apache.fop.util.CharUtilities
 public abstract class NativeTextPainter extends StrokingTextPainter {
 
     /** the logger for this class */
-    protected Log log = LogFactory.getLog(NativeTextPainter.class);
+    protected static final Log log = LogFactory.getLog(NativeTextPainter.class);
+
+    private static final boolean DEBUG = false;
 
     /** the font collection */
     protected final FontInfo fontInfo;
 
+    protected final FontFamilyResolver fontFamilyResolver;
+
+    protected Font font;
+
+    protected TextPaintInfo tpi;
+
     /**
      * Creates a new instance.
      * @param fontInfo the font collection
      */
     public NativeTextPainter(FontInfo fontInfo) {
         this.fontInfo = fontInfo;
+        this.fontFamilyResolver = new FOPFontFamilyResolverImpl(fontInfo);
     }
 
     /**
@@ -68,11 +90,93 @@ public abstract class NativeTextPainter 
      * @param g2d the target Graphics2D instance
      * @throws IOException if an I/O error occurs while rendering the text
      */
-    protected abstract void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException;
+    protected final void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException {
+        AttributedCharacterIterator runaci = textRun.getACI();
+        runaci.first();
+
+        tpi = (TextPaintInfo) runaci.getAttribute(PAINT_INFO);
+        if (tpi == null || !tpi.visible) {
+            return;
+        }
+        if (tpi.composite != null) {
+            g2d.setComposite(tpi.composite);
+        }
+
+        //------------------------------------
+        TextSpanLayout layout = textRun.getLayout();
+        logTextRun(runaci, layout);
+        runaci.first(); //Reset ACI
+
+        GeneralPath debugShapes = null;
+        if (DEBUG) {
+            debugShapes = new GeneralPath();
+        }
+
+        preparePainting(g2d);
+
+        GVTGlyphVector gv = layout.getGlyphVector();
+        if (!(gv.getFont() instanceof FOPGVTFont)) {
+            assert gv.getFont() == null || gv.getFont() instanceof SVGGVTFont;
+            //Draw using Java2D when no native fonts are available
+            textRun.getLayout().draw(g2d);
+            return;
+        }
+        font = ((FOPGVTFont) gv.getFont()).getFont();
+
+        saveGraphicsState();
+        setInitialTransform(g2d.getTransform());
+        clip(g2d.getClip());
+        beginTextObject();
+
+        AffineTransform localTransform = new AffineTransform();
+        Point2D prevPos = null;
+        AffineTransform prevGlyphTransform = null;
+        for (int index = 0, c = gv.getNumGlyphs(); index < c; index++) {
+            if (!gv.isGlyphVisible(index)) {
+                continue;
+            }
+            Point2D glyphPos = gv.getGlyphPosition(index);
+
+            AffineTransform glyphTransform = gv.getGlyphTransform(index);
+            if (log.isTraceEnabled()) {
+                log.trace("pos " + glyphPos + ", transform " + glyphTransform);
+            }
+            if (DEBUG) {
+                Shape sh = gv.getGlyphLogicalBounds(index);
+                if (sh == null) {
+                    sh = new Ellipse2D.Double(glyphPos.getX(), glyphPos.getY(), 2, 2);
+                }
+                debugShapes.append(sh, false);
+            }
+
+            //Exact position of the glyph
+            localTransform.setToIdentity();
+            localTransform.translate(glyphPos.getX(), glyphPos.getY());
+            if (glyphTransform != null) {
+                localTransform.concatenate(glyphTransform);
+            }
+            localTransform.scale(1, -1);
+
+            positionGlyph(prevPos, glyphPos, glyphTransform != null || prevGlyphTransform != null);
+            char glyph = (char) gv.getGlyphCode(index);
+            //Update last position
+            prevPos = glyphPos;
+            prevGlyphTransform = glyphTransform;
+
+            writeGlyph(glyph, localTransform);
+        }
+        endTextObject();
+        restoreGraphicsState();
+        if (DEBUG) {
+            //Paint debug shapes
+            g2d.setStroke(new BasicStroke(0));
+            g2d.setColor(Color.LIGHT_GRAY);
+            g2d.draw(debugShapes);
+        }
+    }
 
-    /** {@inheritDoc} */
     @Override
-    protected void paintTextRuns(List textRuns, Graphics2D g2d) {
+    protected void paintTextRuns(@SuppressWarnings("rawtypes") List textRuns, Graphics2D g2d) {
         if (log.isTraceEnabled()) {
             log.trace("paintTextRuns: count = " + textRuns.size());
         }
@@ -81,7 +185,7 @@ public abstract class NativeTextPainter 
             return;
         }
         for (int i = 0; i < textRuns.size(); i++) {
-            TextRun textRun = (TextRun)textRuns.get(i);
+            TextRun textRun = (TextRun) textRuns.get(i);
             try {
                 paintTextRun(textRun, g2d);
             } catch (IOException ioe) {
@@ -92,16 +196,6 @@ public abstract class NativeTextPainter 
     }
 
     /**
-     * Finds an array of suitable fonts for a given AttributedCharacterIterator.
-     * @param aci the character iterator
-     * @return the array of fonts
-     */
-    protected Font[] findFonts(AttributedCharacterIterator aci) {
-        Font[] fonts = ACIUtils.findFontsForBatikACI(aci, fontInfo);
-        return fonts;
-    }
-
-    /**
      * Collects all characters from an {@link AttributedCharacterIterator}.
      * @param runaci the character iterator
      * @return the characters
@@ -115,6 +209,25 @@ public abstract class NativeTextPainter 
         return chars;
     }
 
+    protected abstract void preparePainting(Graphics2D g2d);
+
+    protected abstract void saveGraphicsState() throws IOException;
+
+    protected abstract void restoreGraphicsState() throws IOException;
+
+    protected abstract void setInitialTransform(AffineTransform transform) throws IOException;
+
+    protected abstract void clip(Shape clip) throws IOException;
+
+    protected abstract void beginTextObject() throws IOException;
+
+    protected abstract void endTextObject() throws IOException;
+
+    protected abstract void positionGlyph(Point2D prevPos, Point2D glyphPos, boolean reposition);
+
+    protected abstract void writeGlyph(char glyph, AffineTransform transform) throws IOException;
+
+
     /**
      * @param runaci an attributed character iterator
      * @param layout a text span layout
@@ -155,5 +268,9 @@ public abstract class NativeTextPainter 
         }
     }
 
+    @Override
+    protected FontFamilyResolver getFontFamilyResolver() {
+        return this.fontFamilyResolver;
+    }
 
 }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextPainter.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextPainter.java Mon Jul 29 21:45:20 2013
@@ -19,25 +19,17 @@
 
 package org.apache.fop.svg;
 
-import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.Paint;
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
-import java.text.AttributedCharacterIterator;
 
-import org.apache.batik.gvt.font.GVTGlyphVector;
 import org.apache.batik.gvt.text.TextPaintInfo;
-import org.apache.batik.gvt.text.TextSpanLayout;
 
-import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.util.CharUtilities;
 
 /**
  * Renders the attributed character iterator of a {@link org.apache.batik.gvt.TextNode}.
@@ -51,11 +43,19 @@ import org.apache.fop.util.CharUtilities
  */
 class PDFTextPainter extends NativeTextPainter {
 
-    private static final boolean DEBUG = false;
+    private PDFGraphics2D pdf;
+
+    private PDFTextUtil textUtil;
+
+    private double prevVisibleGlyphWidth;
+
+    private boolean repositionNextGlyph;
 
     /**
      * Create a new PDF text painter with the given font information.
+     *
      * @param fi the font info
+     * @param fontFamilyResolver the Font Family Resolver
      */
     public PDFTextPainter(FontInfo fi) {
         super(fi);
@@ -67,29 +67,29 @@ class PDFTextPainter extends NativeTextP
         return g2d instanceof PDFGraphics2D;
     }
 
-    /** {@inheritDoc} */
     @Override
-    protected void paintTextRun(TextRun textRun, Graphics2D g2d) {
-        AttributedCharacterIterator runaci = textRun.getACI();
-        runaci.first();
+    protected void preparePainting(Graphics2D g2d) {
+        pdf = (PDFGraphics2D) g2d;
+    }
 
-        TextPaintInfo tpi = (TextPaintInfo)runaci.getAttribute(PAINT_INFO);
-        if (tpi == null || !tpi.visible) {
-            return;
-        }
-        if ((tpi != null) && (tpi.composite != null)) {
-            g2d.setComposite(tpi.composite);
-        }
+    @Override
+    protected void saveGraphicsState() {
+        pdf.saveGraphicsState();
+    }
 
-        //------------------------------------
-        TextSpanLayout layout = textRun.getLayout();
-        logTextRun(runaci, layout);
-        CharSequence chars = collectCharacters(runaci);
-        runaci.first(); //Reset ACI
+    @Override
+    protected void restoreGraphicsState() {
+        pdf.restoreGraphicsState();
+    }
 
-        final PDFGraphics2D pdf = (PDFGraphics2D)g2d;
+    @Override
+    protected void setInitialTransform(AffineTransform transform) {
+        createTextUtil();
+        textUtil.concatMatrix(transform);
+    }
 
-        PDFTextUtil textUtil = new PDFTextUtil(pdf.fontInfo) {
+    private void createTextUtil() {
+        textUtil = new PDFTextUtil(pdf.fontInfo) {
             protected void write(String code) {
                 pdf.currentStream.write(code);
             }
@@ -97,142 +97,39 @@ class PDFTextPainter extends NativeTextP
                 pdf.currentStream.append(code);
             }
         };
+    }
 
-        if (DEBUG) {
-            log.debug("Text: " + chars);
-            pdf.currentStream.write("%Text: " + chars + "\n");
-        }
-
-        GeneralPath debugShapes = null;
-        if (DEBUG) {
-            debugShapes = new GeneralPath();
-        }
-
-        Font[] fonts = findFonts(runaci);
-        if (fonts == null || fonts.length == 0) {
-            //Draw using Java2D when no native fonts are available
-            textRun.getLayout().draw(g2d);
-            return;
-        }
-
-        pdf.saveGraphicsState();
-        textUtil.concatMatrix(g2d.getTransform());
-        Shape imclip = g2d.getClip();
-        pdf.writeClip(imclip);
-
-        applyColorAndPaint(tpi, pdf);
+    @Override
+    protected void clip(Shape clip) {
+        pdf.writeClip(clip);
+    }
 
+    @Override
+    protected void beginTextObject() {
+        applyColorAndPaint(tpi);
         textUtil.beginTextObject();
-        textUtil.setFonts(fonts);
-        boolean stroke = (tpi.strokePaint != null)
-            && (tpi.strokeStroke != null);
+        boolean stroke = (tpi.strokePaint != null) && (tpi.strokeStroke != null);
         textUtil.setTextRenderingMode(tpi.fillPaint != null, stroke, false);
+    }
 
-        AffineTransform localTransform = new AffineTransform();
-        Point2D prevPos = null;
-        double prevVisibleCharWidth = 0.0;
-        GVTGlyphVector gv = layout.getGlyphVector();
-        for (int index = 0, c = gv.getNumGlyphs(); index < c; index++) {
-            char ch = chars.charAt(index);
-            boolean visibleChar = gv.isGlyphVisible(index)
-                || (CharUtilities.isAnySpace(ch) && !CharUtilities.isZeroWidthSpace(ch));
-            logCharacter(ch, layout, index, visibleChar);
-            if (!visibleChar) {
-                continue;
-            }
-            Point2D glyphPos = gv.getGlyphPosition(index);
-
-            AffineTransform glyphTransform = gv.getGlyphTransform(index);
-            //TODO Glyph transforms could be refined so not every char has to be painted
-            //with its own TJ command (stretch/squeeze case could be optimized)
-            if (log.isTraceEnabled()) {
-                log.trace("pos " + glyphPos + ", transform " + glyphTransform);
-            }
-            if (DEBUG) {
-                Shape sh = gv.getGlyphLogicalBounds(index);
-                if (sh == null) {
-                    sh = new Ellipse2D.Double(glyphPos.getX(), glyphPos.getY(), 2, 2);
-                }
-                debugShapes.append(sh, false);
-            }
-
-            //Exact position of the glyph
-            localTransform.setToIdentity();
-            localTransform.translate(glyphPos.getX(), glyphPos.getY());
-            if (glyphTransform != null) {
-                localTransform.concatenate(glyphTransform);
-            }
-            localTransform.scale(1, -1);
-
-            boolean yPosChanged = (prevPos == null
-                    || prevPos.getY() != glyphPos.getY()
-                    || glyphTransform != null);
-            if (yPosChanged) {
-                if (index > 0) {
-                    textUtil.writeTJ();
-                    textUtil.writeTextMatrix(localTransform);
-                }
-            } else {
-                double xdiff = glyphPos.getX() - prevPos.getX();
-                //Width of previous character
-                Font font = textUtil.getCurrentFont();
-                double cw = prevVisibleCharWidth;
-                double effxdiff = (1000 * xdiff) - cw;
-                if (effxdiff != 0) {
-                    double adjust = (-effxdiff / font.getFontSize());
-                    textUtil.adjustGlyphTJ(adjust * 1000);
-                }
-                if (log.isTraceEnabled()) {
-                    log.trace("==> x diff: " + xdiff + ", " + effxdiff
-                            + ", charWidth: " + cw);
-                }
-            }
-            Font f = textUtil.selectFontForChar(ch);
-            char paintChar = (CharUtilities.isAnySpace(ch) ? ' ' : ch);
-            char mappedChar = f.mapChar(paintChar);
-            boolean encodingChanging = false; // used for single byte
-            if (!textUtil.isMultiByteFont(f.getFontName())) {
-                int encoding = mappedChar / 256;
-                mappedChar = (char) (mappedChar % 256);
-                if (textUtil.getCurrentEncoding() != encoding) {
-                    textUtil.setCurrentEncoding(encoding);
-                    encodingChanging = true;
-                }
-            }
-            if (f != textUtil.getCurrentFont() || encodingChanging) {
-                textUtil.writeTJ();
-                textUtil.setCurrentFont(f);
-                textUtil.writeTf(f);
-                textUtil.writeTextMatrix(localTransform);
-            }
-            textUtil.writeTJMappedChar(mappedChar);
-
-            //Update last position
-            prevPos = glyphPos;
-            prevVisibleCharWidth = textUtil.getCurrentFont().getCharWidth(chars.charAt(index));
-        }
+    @Override
+    protected void endTextObject() {
         textUtil.writeTJ();
         textUtil.endTextObject();
-        pdf.restoreGraphicsState();
-        if (DEBUG) {
-            g2d.setStroke(new BasicStroke(0));
-            g2d.setColor(Color.LIGHT_GRAY);
-            g2d.draw(debugShapes);
-        }
     }
 
-    private void applyColorAndPaint(TextPaintInfo tpi, PDFGraphics2D pdf) {
+    private void applyColorAndPaint(TextPaintInfo tpi) {
         Paint fillPaint = tpi.fillPaint;
         Paint strokePaint = tpi.strokePaint;
         Stroke stroke = tpi.strokeStroke;
         int fillAlpha = PDFGraphics2D.OPAQUE;
         if (fillPaint instanceof Color) {
-            Color col = (Color)fillPaint;
+            Color col = (Color) fillPaint;
             pdf.applyColor(col, true);
             fillAlpha = col.getAlpha();
         }
         if (strokePaint instanceof Color) {
-            Color col = (Color)strokePaint;
+            Color col = (Color) strokePaint;
             pdf.applyColor(col, false);
         }
         pdf.applyPaint(fillPaint, true);
@@ -243,4 +140,46 @@ class PDFTextPainter extends NativeTextP
         pdf.applyAlpha(fillAlpha, PDFGraphics2D.OPAQUE);
     }
 
+    @Override
+    protected void positionGlyph(Point2D prevPos, Point2D glyphPos, boolean reposition) {
+        // TODO Glyph transforms could be refined so not every char has to be painted
+        // with its own TJ command (stretch/squeeze case could be optimized)
+        repositionNextGlyph = (prevPos == null
+                || prevPos.getY() != glyphPos.getY()
+                || reposition);
+        if (!repositionNextGlyph) {
+            double xdiff = glyphPos.getX() - prevPos.getX();
+            //Width of previous character
+            double cw = prevVisibleGlyphWidth;
+            double effxdiff = (1000 * xdiff) - cw;
+            if (effxdiff != 0) {
+                double adjust = (-effxdiff / font.getFontSize());
+                textUtil.adjustGlyphTJ(adjust * 1000);
+            }
+        }
+    }
+
+    @Override
+    protected void writeGlyph(char glyph, AffineTransform transform) {
+        prevVisibleGlyphWidth = font.getWidth(glyph);
+        boolean encodingChanging = false; // used for single byte
+        if (!textUtil.isMultiByteFont(font.getFontName())) {
+            int encoding = glyph / 256;
+            glyph = (char) (glyph % 256);
+            if (textUtil.getCurrentEncoding() != encoding) {
+                textUtil.setCurrentEncoding(encoding);
+                encodingChanging = true;
+            }
+        }
+        if (repositionNextGlyph || encodingChanging) {
+            textUtil.writeTJ();
+            if (font != textUtil.getCurrentFont() || encodingChanging) {
+                textUtil.setCurrentFont(font);
+                textUtil.writeTf(font);
+            }
+            textUtil.writeTextMatrix(transform);
+        }
+        textUtil.writeTJMappedChar(glyph);
+    }
+
 }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextUtil.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextUtil.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTextUtil.java Mon Jul 29 21:45:20 2013
@@ -30,7 +30,6 @@ import org.apache.fop.fonts.Typeface;
 public abstract class PDFTextUtil extends org.apache.fop.pdf.PDFTextUtil {
 
     private FontInfo fontInfo;
-    private Font[] fonts;
     private Font font;
     private int encoding;
 
@@ -50,23 +49,6 @@ public abstract class PDFTextUtil extend
     }
 
     /**
-     * Sets the current fonts for the text object. For every character, the suitable font will
-     * be selected.
-     * @param fonts the new fonts
-     */
-    public void setFonts(Font[] fonts) {
-        this.fonts = fonts;
-    }
-
-    /**
-     * Sets the current font for the text object.
-     * @param font the new font
-     */
-    public void setFont(Font font) {
-        setFonts(new Font[] {font});
-    }
-
-    /**
      * Returns the current font in use.
      * @return the current font or null if no font is currently active.
      */
@@ -123,27 +105,4 @@ public abstract class PDFTextUtil extend
         }
     }
 
-    /**
-     * Selects a font from the font list suitable to display the given character.
-     * @param ch the character
-     * @return the recommended Font to use
-     */
-    public Font selectFontForChar(char ch) {
-        for (int i = 0, c = fonts.length; i < c; i++) {
-            if (fonts[i].hasChar(ch)) {
-                return fonts[i];
-            }
-        }
-        return fonts[0]; //TODO Maybe fall back to painting with shapes
-    }
-
-    /**
-     * Writes a char to the "TJ-Buffer".
-     * @param ch the unmapped character
-     */
-    public void writeTJChar(char ch) {
-        char mappedChar = font.mapChar(ch);
-        writeTJMappedChar(mappedChar);
-    }
-
 }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTranscoder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTranscoder.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTranscoder.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/PDFTranscoder.java Mon Jul 29 21:45:20 2013
@@ -31,7 +31,6 @@ import org.apache.avalon.framework.confi
 
 import org.apache.batik.bridge.BridgeContext;
 import org.apache.batik.bridge.UnitProcessor;
-import org.apache.batik.bridge.UserAgent;
 import org.apache.batik.ext.awt.RenderingHintsKeyExt;
 import org.apache.batik.transcoder.TranscoderException;
 import org.apache.batik.transcoder.TranscoderOutput;
@@ -39,6 +38,7 @@ import org.apache.batik.transcoder.image
 
 import org.apache.fop.Version;
 import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.svg.font.FOPFontFamilyResolverImpl;
 
 /**
  * <p>This class enables to transcode an input to a PDF document.</p>
@@ -88,7 +88,7 @@ public class PDFTranscoder extends Abstr
     /**
      * {@inheritDoc}
      */
-    protected UserAgent createUserAgent() {
+    protected FOPTranscoderUserAgent createUserAgent() {
         return new AbstractFOPTranscoder.FOPTranscoderUserAgent() {
             // The PDF stuff wants everything at 72dpi
             public float getPixelUnitToMillimeter() {
@@ -131,6 +131,8 @@ public class PDFTranscoder extends Abstr
             } else {
                 graphics.setupDefaultFontInfo();
             }
+            ((FOPTranscoderUserAgent) userAgent).setFontFamilyResolver(
+                    new FOPFontFamilyResolverImpl(graphics.getFontInfo()));
         } catch (Exception e) {
             throw new TranscoderException(
                     "Error while setting up PDFDocumentGraphics2D", e);

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SVGUserAgent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SVGUserAgent.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SVGUserAgent.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SVGUserAgent.java Mon Jul 29 21:45:20 2013
@@ -21,6 +21,8 @@ package org.apache.fop.svg;
 
 import java.awt.geom.AffineTransform;
 
+import org.apache.batik.gvt.font.FontFamilyResolver;
+
 import org.apache.fop.apps.FOUserAgent;
 
 /**
@@ -34,10 +36,11 @@ public class SVGUserAgent extends Simple
     /**
      * Creates a new SVGUserAgent.
      * @param foUserAgent the FO user agent to associate with this SVG user agent
+     * @param fontFamilyResolver the font family resolver
      * @param at the current transform
      */
-    public SVGUserAgent(FOUserAgent foUserAgent, AffineTransform at) {
-        super(foUserAgent.getSourcePixelUnitToMillimeter(), at);
+    public SVGUserAgent(FOUserAgent foUserAgent, FontFamilyResolver fontFamilyResolver, AffineTransform at) {
+        super(foUserAgent.getSourcePixelUnitToMillimeter(), at, fontFamilyResolver);
         this.eventProducer = SVGEventProducer.Provider.get(foUserAgent.getEventBroadcaster());
     }
 
@@ -45,8 +48,8 @@ public class SVGUserAgent extends Simple
      * Creates a new SVGUserAgent.
      * @param foUserAgent the FO user agent to associate with this SVG user agent
      */
-    public SVGUserAgent(FOUserAgent foUserAgent) {
-        this(foUserAgent, new AffineTransform());
+    public SVGUserAgent(FOUserAgent foUserAgent, FontFamilyResolver fontFamilyResolver) {
+        this(foUserAgent, fontFamilyResolver,  new AffineTransform());
     }
 
     /**

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SimpleSVGUserAgent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SimpleSVGUserAgent.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SimpleSVGUserAgent.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/SimpleSVGUserAgent.java Mon Jul 29 21:45:20 2013
@@ -26,6 +26,7 @@ import java.awt.geom.Dimension2D;
 import javax.xml.parsers.SAXParserFactory;
 
 import org.apache.batik.bridge.UserAgentAdapter;
+import org.apache.batik.gvt.font.FontFamilyResolver;
 
 /**
  * A simple SVG user agent.
@@ -35,14 +36,18 @@ import org.apache.batik.bridge.UserAgent
 public class SimpleSVGUserAgent extends UserAgentAdapter {
 
     private AffineTransform currentTransform = null;
+
     private float pixelUnitToMillimeter = 0.0f;
 
+    private final FontFamilyResolver fontFamilyResolver;
+
     /**
      * Creates a new user agent.
      * @param pixelUnitToMM the pixel to millimeter conversion factor currently in effect
      * @param at the current transform
      */
-    public SimpleSVGUserAgent(float pixelUnitToMM, AffineTransform at) {
+    public SimpleSVGUserAgent(float pixelUnitToMM, AffineTransform at, FontFamilyResolver fontFamilyResolver) {
+        this.fontFamilyResolver = fontFamilyResolver;
         pixelUnitToMillimeter = pixelUnitToMM;
         currentTransform = at;
     }
@@ -122,5 +127,10 @@ public class SimpleSVGUserAgent extends 
         return new Dimension(100, 100);
     }
 
+    @Override
+    public FontFamilyResolver getFontFamilyResolver() {
+        return fontFamilyResolver;
+    }
+
 }
 

Added: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java?rev=1508208&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java (added)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java Mon Jul 29 21:45:20 2013
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.batik.gvt.font.FontFamilyResolver;
+import org.apache.batik.gvt.font.GVTFontFamily;
+
+public class AggregatingFontFamilyResolver implements FontFamilyResolver {
+
+    private final List<FontFamilyResolver> resolvers;
+
+    public AggregatingFontFamilyResolver(FontFamilyResolver... resolvers) {
+        this.resolvers = Arrays.<FontFamilyResolver>asList(resolvers);
+    }
+
+    public String lookup(String familyName) {
+        for (FontFamilyResolver resolver : resolvers) {
+            String lookup = resolver.lookup(familyName);
+            if (lookup != null) {
+                return lookup;
+            }
+        }
+        return null;
+    }
+
+    public GVTFontFamily resolve(String familyName) {
+        for (FontFamilyResolver resolver : resolvers) {
+            GVTFontFamily family = resolver.resolve(familyName);
+            if (family != null) {
+                return family;
+            }
+        }
+        return null;
+    }
+
+    public GVTFontFamily getDefault() {
+        return resolve("any");
+    }
+
+    public GVTFontFamily getFamilyThatCanDisplay(char c) {
+        for (FontFamilyResolver resolver : resolvers) {
+            GVTFontFamily family = resolver.getFamilyThatCanDisplay(c);
+            if (family != null) {
+                return family;
+            }
+        }
+        return null;
+    }
+
+}

Propchange: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java
------------------------------------------------------------------------------
    svn:keywords = Revision Id



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org