You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2016/08/10 16:06:07 UTC

svn commit: r1755774 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: pdmodel/font/ rendering/

Author: jahewson
Date: Wed Aug 10 16:06:07 2016
New Revision: 1755774

URL: http://svn.apache.org/viewvc?rev=1755774&view=rev
Log:
PDFBOX-3459: Move Glyph2D functionality into PDFont subclasses

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java   (with props)
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/CIDType0Glyph2D.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/Glyph2D.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TTFGlyph2D.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/Type1Glyph2D.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java Wed Aug 10 16:06:07 2016
@@ -57,10 +57,9 @@ public class PDCIDFontType0 extends PDCI
     private final Map<Integer, Float> glyphHeights = new HashMap<Integer, Float>();
     private final boolean isEmbedded;
     private final boolean isDamaged;
-
+    private final AffineTransform fontMatrixTransform;
     private Float avgWidth = null;
     private Matrix fontMatrix;
-    private final AffineTransform fontMatrixTransform;
     private BoundingBox fontBBox;
 
     /**
@@ -190,16 +189,6 @@ public class PDCIDFontType0 extends PDCI
         return fontMatrix;
     }
     
-    private class ByteSource implements CFFParser.ByteSource
-    {
-        @Override
-        public byte[] getBytes() throws IOException
-        {
-            PDStream ff3Stream = getFontDescriptor().getFontFile3();
-            return IOUtils.toByteArray(ff3Stream.createInputStream());
-        }
-    }
-
     @Override
     public BoundingBox getBoundingBox()
     {
@@ -328,6 +317,12 @@ public class PDCIDFontType0 extends PDCI
     }
 
     @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        return getPath(code);
+    }
+
+    @Override
     public boolean hasGlyph(int code) throws IOException
     {
         int cid = codeToCID(code);
@@ -448,4 +443,14 @@ public class PDCIDFontType0 extends PDCI
         // todo: not implemented, highly suspect
         return 500;
     }
+
+    private class ByteSource implements CFFParser.ByteSource
+    {
+        @Override
+        public byte[] getBytes() throws IOException
+        {
+            PDStream ff3Stream = getFontDescriptor().getFontFile3();
+            return IOUtils.toByteArray(ff3Stream.createInputStream());
+        }
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Wed Aug 10 16:06:07 2016
@@ -16,6 +16,7 @@
  */
 package org.apache.pdfbox.pdmodel.font;
 
+import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.io.IOException;
 import java.io.InputStream;
@@ -447,6 +448,36 @@ public class PDCIDFontType2 extends PDCI
         }
     }
 
+    @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        boolean hasScaling = ttf.getUnitsPerEm() != 1000;
+        float scale = 1000f / ttf.getUnitsPerEm();
+        int gid = codeToGID(code);
+
+        GeneralPath path = getPath(code);
+
+        // Acrobat only draws GID 0 for embedded CIDFonts, see PDFBOX-2372
+        if (gid == 0 && !isEmbedded())
+        {
+            path = null;
+        }
+
+        if (path == null)
+        {
+            // empty glyph (e.g. space, newline)
+            return new GeneralPath();
+        }
+        else
+        {
+            if (hasScaling)
+            {
+                path.transform(AffineTransform.getScaleInstance(scale, scale));
+            }
+            return path;
+        }
+    }
+
     @Override
     public boolean hasGlyph(int code) throws IOException
     {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Wed Aug 10 16:06:07 2016
@@ -16,6 +16,7 @@
  */
 package org.apache.pdfbox.pdmodel.font;
 
+import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.io.File;
 import java.io.FileInputStream;
@@ -75,6 +76,86 @@ public class PDTrueTypeFont extends PDSi
         }
     }
 
+    private final TrueTypeFont ttf;
+    private final boolean isEmbedded;
+    private final boolean isDamaged;
+    private CmapSubtable cmapWinUnicode = null;
+    private CmapSubtable cmapWinSymbol = null;
+    private CmapSubtable cmapMacRoman = null;
+    private boolean cmapInitialized = false;
+    private Map<Integer, Integer> gidToCode; // for embedding
+    private BoundingBox fontBBox;
+
+    /**
+     * Creates a new TrueType font from a Font dictionary.
+     *
+     * @param fontDictionary The font dictionary according to the PDF specification.
+     */
+    public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException
+    {
+        super(fontDictionary);
+
+        TrueTypeFont ttfFont = null;
+        boolean fontIsDamaged = false;
+        if (getFontDescriptor() != null)
+        {
+            PDFontDescriptor fd = super.getFontDescriptor();
+            PDStream ff2Stream = fd.getFontFile2();
+            if (ff2Stream != null)
+            {
+                try
+                {
+                    // embedded
+                    TTFParser ttfParser = new TTFParser(true);
+                    ttfFont = ttfParser.parse(ff2Stream.createInputStream());
+                }
+                catch (NullPointerException e) // TTF parser is buggy
+                {
+                    LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e);
+                    fontIsDamaged = true;
+                }
+                catch (IOException e)
+                {
+                    LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e);
+                    fontIsDamaged = true;
+                }
+            }
+        }
+        isEmbedded = ttfFont != null;
+        isDamaged = fontIsDamaged;
+
+        // substitute
+        if (ttfFont == null)
+        {
+            FontMapping<TrueTypeFont> mapping = FontMappers.instance()
+                                                           .getTrueTypeFont(getBaseFont(),
+                                                                            getFontDescriptor());
+            ttfFont = mapping.getFont();
+
+            if (mapping.isFallback())
+            {
+                LOG.warn("Using fallback font '" + ttfFont + "' for '" + getBaseFont() + "'");
+            }
+        }
+        ttf = ttfFont;
+        readEncoding();
+    }
+    /**
+     * Creates a new TrueType font for embedding.
+     */
+    private PDTrueTypeFont(PDDocument document, InputStream ttfStream, Encoding encoding)
+            throws IOException
+    {
+        PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, dict, ttfStream,
+                                                                     encoding);
+        this.encoding = encoding;
+        ttf = embedder.getTrueTypeFont();
+        setFontDescriptor(embedder.getFontDescriptor());
+        isEmbedded = true;
+        isDamaged = false;
+        glyphList = GlyphList.getAdobeGlyphList();
+    }
+
     /**
      * Loads a TTF to be embedded into a document as a simple font.
      * 
@@ -110,7 +191,7 @@ public class PDTrueTypeFont extends PDSi
     {
         return new PDTrueTypeFont(doc, input, encoding);
     }
-    
+
     /**
      * Loads a TTF to be embedded into a document as a simple font. Only supports WinAnsiEncoding.
      *
@@ -143,72 +224,6 @@ public class PDTrueTypeFont extends PDSi
         return new PDTrueTypeFont(doc, input, WinAnsiEncoding.INSTANCE);
     }
 
-    private CmapSubtable cmapWinUnicode = null;
-    private CmapSubtable cmapWinSymbol = null;
-    private CmapSubtable cmapMacRoman = null;
-    private boolean cmapInitialized = false;
-    private Map<Integer, Integer> gidToCode; // for embedding
-
-    private final TrueTypeFont ttf;
-    private final boolean isEmbedded;
-    private final boolean isDamaged;
-    private BoundingBox fontBBox;
-
-    /**
-     * Creates a new TrueType font from a Font dictionary.
-     *
-     * @param fontDictionary The font dictionary according to the PDF specification.
-     */
-    public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException
-    {
-        super(fontDictionary);
-
-        TrueTypeFont ttfFont = null;
-        boolean fontIsDamaged = false;
-        if (getFontDescriptor() != null)
-        {
-            PDFontDescriptor fd = super.getFontDescriptor();
-            PDStream ff2Stream = fd.getFontFile2();
-            if (ff2Stream != null)
-            {
-                try
-                {
-                    // embedded
-                    TTFParser ttfParser = new TTFParser(true);
-                    ttfFont = ttfParser.parse(ff2Stream.createInputStream());
-                }
-                catch (NullPointerException e) // TTF parser is buggy
-                {
-                    LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e);
-                    fontIsDamaged = true;
-                }
-                catch (IOException e)
-                {
-                    LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e);
-                    fontIsDamaged = true;
-                }
-            }
-        }
-        isEmbedded = ttfFont != null;
-        isDamaged = fontIsDamaged;
-
-        // substitute
-        if (ttfFont == null)
-        {
-            FontMapping<TrueTypeFont> mapping = FontMappers.instance()
-                                                           .getTrueTypeFont(getBaseFont(),
-                                                                            getFontDescriptor());
-            ttfFont = mapping.getFont();
-
-            if (mapping.isFallback())
-            {
-                LOG.warn("Using fallback font '" + ttfFont + "' for '" + getBaseFont() + "'");
-            }
-        }
-        ttf = ttfFont;
-        readEncoding();
-    }
-
     /**
      * Returns the PostScript name of the font.
      */
@@ -271,22 +286,6 @@ public class PDTrueTypeFont extends PDSi
         }
     }
 
-    /**
-     * Creates a new TrueType font for embedding.
-     */
-    private PDTrueTypeFont(PDDocument document, InputStream ttfStream, Encoding encoding)
-            throws IOException
-    {
-        PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, dict, ttfStream,
-                                                                     encoding);
-        this.encoding = encoding;
-        ttf = embedder.getTrueTypeFont();
-        setFontDescriptor(embedder.getFontDescriptor());
-        isEmbedded = true;
-        isDamaged = false;
-        glyphList = GlyphList.getAdobeGlyphList();
-    }
-
     @Override
     public int readCode(InputStream in) throws IOException
     {
@@ -494,10 +493,40 @@ public class PDTrueTypeFont extends PDSi
     }
 
     @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        boolean hasScaling = ttf.getUnitsPerEm() != 1000;
+        float scale = 1000f / ttf.getUnitsPerEm();
+        int gid = codeToGID(code);
+
+        GeneralPath path = getPath(code);
+
+        // Acrobat only draws GID 0 for embedded or "Standard 14" fonts, see PDFBOX-2372
+        if (gid == 0 && !isEmbedded() && !isStandard14())
+        {
+            path = null;
+        }
+
+        if (path == null)
+        {
+            // empty glyph (e.g. space, newline)
+            return new GeneralPath();
+        }
+        else
+        {
+            if (hasScaling)
+            {
+                path.transform(AffineTransform.getScaleInstance(scale, scale));
+            }
+            return path;
+        }
+    }
+
+    @Override
     public boolean hasGlyph(String name) throws IOException
     {
         int gid = ttf.nameToGID(name);
-        return gid != 0;
+        return !(gid == 0 || gid >= ttf.getMaximumProfile().getNumGlyphs());
     }
 
     @Override

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java Wed Aug 10 16:06:07 2016
@@ -46,13 +46,47 @@ public class PDType0Font extends PDFont
     private static final Log LOG = LogFactory.getLog(PDType0Font.class);
 
     private final PDCIDFont descendantFont;
+    private final Set<Integer> noUnicode = new HashSet<Integer>(); 
     private CMap cMap, cMapUCS2;
     private boolean isCMapPredefined;
     private boolean isDescendantCJK;
     private PDCIDFontType2Embedder embedder;
-    private final Set<Integer> noUnicode = new HashSet<Integer>(); 
     
     /**
+     * Constructor for reading a Type0 font from a PDF file.
+     * 
+     * @param fontDictionary The font dictionary according to the PDF specification.
+     * @throws IOException if the descendant font is missing.
+     */
+    public PDType0Font(COSDictionary fontDictionary) throws IOException
+    {
+        super(fontDictionary);
+        COSArray descendantFonts = (COSArray)dict.getDictionaryObject(COSName.DESCENDANT_FONTS);
+        COSDictionary descendantFontDictionary = (COSDictionary) descendantFonts.getObject(0);
+
+        if (descendantFontDictionary == null)
+        {
+            throw new IOException("Missing descendant font dictionary");
+        }
+
+        descendantFont = PDFontFactory.createDescendantFont(descendantFontDictionary, this);
+        readEncoding();
+        fetchCMapUCS2();
+    }
+
+    /**
+    * Private. Creates a new TrueType font for embedding.
+    */
+    private PDType0Font(PDDocument document, TrueTypeFont ttf, boolean embedSubset)
+            throws IOException
+    {
+        embedder = new PDCIDFontType2Embedder(document, dict, ttf, embedSubset, this);
+        descendantFont = embedder.getCIDFont();
+        readEncoding();
+        fetchCMapUCS2();
+    }
+
+    /**
     * Loads a TTF to be embedded into a document as a Type 0 font.
     *
     * @param doc The PDF document that will hold the embedded font.
@@ -108,40 +142,6 @@ public class PDType0Font extends PDFont
         return new PDType0Font(doc, ttf, embedSubset);
     }
 
-    /**
-     * Constructor for reading a Type0 font from a PDF file.
-     * 
-     * @param fontDictionary The font dictionary according to the PDF specification.
-     * @throws IOException if the descendant font is missing.
-     */
-    public PDType0Font(COSDictionary fontDictionary) throws IOException
-    {
-        super(fontDictionary);
-        COSArray descendantFonts = (COSArray)dict.getDictionaryObject(COSName.DESCENDANT_FONTS);
-        COSDictionary descendantFontDictionary = (COSDictionary) descendantFonts.getObject(0);
-
-        if (descendantFontDictionary == null)
-        {
-            throw new IOException("Missing descendant font dictionary");
-        }
-
-        descendantFont = PDFontFactory.createDescendantFont(descendantFontDictionary, this);
-        readEncoding();
-        fetchCMapUCS2();
-    }
-
-    /**
-    * Private. Creates a new TrueType font for embedding.
-    */
-    private PDType0Font(PDDocument document, TrueTypeFont ttf, boolean embedSubset)
-            throws IOException
-    {
-        embedder = new PDCIDFontType2Embedder(document, dict, ttf, embedSubset, this);
-        descendantFont = embedder.getCIDFont();
-        readEncoding();
-        fetchCMapUCS2();
-    }
-
     @Override
     public void addToSubset(int codePoint)
     {
@@ -506,6 +506,13 @@ public class PDType0Font extends PDFont
         return descendantFont.getPath(code);
     }
 
+    
+    @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        return descendantFont.getNormalizedPath(code);
+    }
+    
     @Override
     public boolean hasGlyph(int code) throws IOException
     {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java Wed Aug 10 16:06:07 2016
@@ -51,19 +51,18 @@ import static org.apache.pdfbox.pdmodel.
  * @author Villu Ruusmann
  * @author John Hewson
  */
-public class PDType1CFont extends PDSimpleFont
+public class PDType1CFont extends PDSimpleFont implements PDVectorFont
 {
     private static final Log LOG = LogFactory.getLog(PDType1CFont.class);
 
     private final Map<String, Float> glyphHeights = new HashMap<String, Float>();
-    private Float avgWidth = null;
-    private Matrix fontMatrix;
     private final AffineTransform fontMatrixTransform;
-
     private final CFFType1Font cffFont; // embedded font
     private final FontBoxFont genericFont; // embedded or system font for rendering
     private final boolean isEmbedded;
     private final boolean isDamaged;
+    private Float avgWidth = null;
+    private Matrix fontMatrix;
     private BoundingBox fontBBox;
 
     /**
@@ -133,16 +132,6 @@ public class PDType1CFont extends PDSimp
         fontMatrixTransform.scale(1000, 1000);
     }
     
-    private class ByteSource implements CFFParser.ByteSource
-    {
-        @Override
-        public byte[] getBytes() throws IOException
-        {
-            PDStream ff3Stream = getFontDescriptor().getFontFile3();
-            return IOUtils.toByteArray(ff3Stream.createInputStream());
-        }
-    }
-
     @Override
     public FontBoxFont getFontBoxFont()
     {
@@ -172,6 +161,32 @@ public class PDType1CFont extends PDSimp
     }
 
     @Override
+    public boolean hasGlyph(int code) throws IOException
+    {
+        String name = getEncoding().getName(code);
+        return hasGlyph(name);
+    }
+
+    @Override
+    public GeneralPath getPath(int code) throws IOException
+    {
+        String name = getEncoding().getName(code);
+        return getPath(name);
+    }
+
+    @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        String name = getEncoding().getName(code);
+        GeneralPath path = getPath(name);
+        if (path == null)
+        {
+            return getPath(".notdef");
+        }
+        return path;
+    }
+    
+    @Override
     public boolean hasGlyph(String name) throws IOException
     {
         return genericFont.hasGlyph(name);
@@ -211,7 +226,7 @@ public class PDType1CFont extends PDSimp
     {
         return getEncoding().getName(code);
     }
-    
+
     @Override
     protected Encoding readEncodingFromFont() throws IOException
     {
@@ -234,7 +249,7 @@ public class PDType1CFont extends PDSimp
             }
         }
     }
-
+    
     @Override
     public int readCode(InputStream in) throws IOException
     {
@@ -331,7 +346,7 @@ public class PDType1CFont extends PDSimp
         int code = inverted.get(name);
         return new byte[] { (byte)code };
     }
-    
+
     @Override
     public float getStringWidth(String string) throws IOException
     {
@@ -344,7 +359,7 @@ public class PDType1CFont extends PDSimp
         }
         return width;
     }
-
+    
     @Override
     public float getAverageFontWidth()
     {
@@ -371,7 +386,7 @@ public class PDType1CFont extends PDSimp
         // todo: not implemented, highly suspect
         return 500;
     }
-    
+
     /**
      * Maps a PostScript glyph name to the name in the underlying font, for example when
      * using a TTF font we might map "W" to "uni0057".
@@ -397,4 +412,14 @@ public class PDType1CFont extends PDSimp
         }
         return ".notdef";
     }
+    
+    private class ByteSource implements CFFParser.ByteSource
+    {
+        @Override
+        public byte[] getBytes() throws IOException
+        {
+            PDStream ff3Stream = getFontDescriptor().getFontFile3();
+            return IOUtils.toByteArray(ff3Stream.createInputStream());
+        }
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Wed Aug 10 16:06:07 2016
@@ -42,38 +42,20 @@ import org.apache.pdfbox.pdmodel.common.
 import org.apache.pdfbox.pdmodel.font.encoding.Encoding;
 import org.apache.pdfbox.pdmodel.font.encoding.StandardEncoding;
 import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding;
+import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding;
+import org.apache.pdfbox.pdmodel.font.encoding.ZapfDingbatsEncoding;
 import org.apache.pdfbox.util.Matrix;
 
 
 import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint;
-import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding;
-import org.apache.pdfbox.pdmodel.font.encoding.ZapfDingbatsEncoding;
 
 /**
  * A PostScript Type 1 Font.
  *
  * @author Ben Litchfield
  */
-public class PDType1Font extends PDSimpleFont
+public class PDType1Font extends PDSimpleFont implements PDVectorFont
 {
-    private static final Log LOG = LogFactory.getLog(PDType1Font.class);
-
-    // alternative names for glyphs which are commonly encountered
-    private static final Map<String, String> ALT_NAMES = new HashMap<String, String>();
-    static
-    {
-        ALT_NAMES.put("ff", "f_f");
-        ALT_NAMES.put("ffi", "f_f_i");
-        ALT_NAMES.put("ffl", "f_f_l");
-        ALT_NAMES.put("fi", "f_i");
-        ALT_NAMES.put("fl", "f_l");
-        ALT_NAMES.put("st", "s_t");
-        ALT_NAMES.put("IJ", "I_J");
-        ALT_NAMES.put("ij", "i_j");
-        ALT_NAMES.put("ellipsis", "elipsis"); // misspelled in ArialMT
-    }
-    private static final int PFB_START_MARKER = 0x80;
-
     // todo: replace with enum? or getters?
     public static final PDType1Font TIMES_ROMAN = new PDType1Font("Times-Roman");
     public static final PDType1Font TIMES_BOLD = new PDType1Font("Times-Bold");
@@ -89,6 +71,23 @@ public class PDType1Font extends PDSimpl
     public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font("Courier-BoldOblique");
     public static final PDType1Font SYMBOL = new PDType1Font("Symbol");
     public static final PDType1Font ZAPF_DINGBATS = new PDType1Font("ZapfDingbats");
+    private static final Log LOG = LogFactory.getLog(PDType1Font.class);
+    // alternative names for glyphs which are commonly encountered
+    private static final Map<String, String> ALT_NAMES = new HashMap<String, String>();
+    private static final int PFB_START_MARKER = 0x80;
+
+    static
+    {
+        ALT_NAMES.put("ff", "f_f");
+        ALT_NAMES.put("ffi", "f_f_i");
+        ALT_NAMES.put("ffl", "f_f_l");
+        ALT_NAMES.put("fi", "f_i");
+        ALT_NAMES.put("fl", "f_l");
+        ALT_NAMES.put("st", "s_t");
+        ALT_NAMES.put("IJ", "I_J");
+        ALT_NAMES.put("ij", "i_j");
+        ALT_NAMES.put("ellipsis", "elipsis"); // misspelled in ArialMT
+    }
 
     /**
      * embedded font.
@@ -102,14 +101,13 @@ public class PDType1Font extends PDSimpl
     
     private final boolean isEmbedded;
     private final boolean isDamaged;
-    private Matrix fontMatrix;
     private final AffineTransform fontMatrixTransform;
-    private BoundingBox fontBBox;
-
     /**
      * to improve encoding speed.
      */
     private final Map <Integer,byte[]> codeToBytesMap;
+    private Matrix fontMatrix;
+    private BoundingBox fontBBox;
 
     /**
      * Creates a Type 1 standard 14 font for embedding.
@@ -562,12 +560,37 @@ public class PDType1Font extends PDSimpl
     }
 
     @Override
+    public GeneralPath getPath(int code) throws IOException
+    {
+        String name = getEncoding().getName(code);
+        return getPath(name);
+    }
+
+    @Override
+    public GeneralPath getNormalizedPath(int code) throws IOException
+    {
+        String name = getEncoding().getName(code);
+        GeneralPath path = getPath(name);
+        if (path == null)
+        {
+            return getPath(".notdef");
+        }
+        return path;
+    }
+    
+    @Override
     public boolean hasGlyph(String name) throws IOException
     {
         return genericFont.hasGlyph(getNameInFont(name));
     }
 
     @Override
+    public boolean hasGlyph(int code) throws IOException
+    {
+        return !getEncoding().getName(code).equals(".notdef");
+    }
+
+    @Override
     public final Matrix getFontMatrix()
     {
         if (fontMatrix == null)

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java Wed Aug 10 16:06:07 2016
@@ -34,6 +34,16 @@ public interface PDVectorFont
      * @throws java.io.IOException if the font could not be read
      */
     GeneralPath getPath(int code) throws IOException;
+
+    /**
+     * Returns the normalized glyph path for the given character code. The resulting path is
+     * normalized to  the PostScript 1000 unit square, and fallback glyphs are returned
+     * where appropriate, e.g. for missing glyphs.
+     *  
+     * @param code character code
+     * @throws java.io.IOException if the font could not be read
+     */
+    GeneralPath getNormalizedPath(int code) throws IOException;
     
     /**
      * Returns true if this font contains a glyph for the given character code.

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java?rev=1755774&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java Wed Aug 10 16:06:07 2016
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+package org.apache.pdfbox.rendering;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.font.PDVectorFont;
+
+/**
+ * A simple glyph outline cache.
+ *
+ * @author John Hewson
+ */
+final class GlyphCache
+{
+    private static final Log LOG = LogFactory.getLog(GlyphCache.class);
+    
+    private final PDVectorFont font;
+    private final Map<Integer, GeneralPath> cache = new HashMap<Integer, GeneralPath>();
+
+    public GlyphCache(PDVectorFont font)
+    {
+        this.font = font;
+    }
+
+    public void put(int code, GeneralPath path)
+    {
+        cache.put(code, path);
+    }
+    
+    public GeneralPath getPathForCharacterCode(int code)
+    {
+        GeneralPath path = cache.get(code);
+        if (path != null)
+        {
+            return path;
+        }
+
+        try
+        {
+            if (!font.hasGlyph(code))
+            {
+                String fontName = ((PDFont)font).getName();
+                if (font instanceof PDType0Font)
+                {
+                    int cid = ((PDType0Font) font).codeToCID(code);
+                    String cidHex = String.format("%04x", cid);
+                    LOG.warn("No glyph for " + code + " (CID " + cidHex + ") in font " + fontName);
+                }
+                else
+                {
+                    LOG.warn("No glyph for " + code + " in font " + fontName);
+                }
+            }
+
+            path = font.getNormalizedPath(code);
+            cache.put(code, path);
+            return path;
+        }
+        catch (IOException e)
+        {
+            // todo: escalate this error?
+            LOG.error("Glyph rendering failed", e);
+            return new GeneralPath();
+        }
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/GlyphCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1755774&r1=1755773&r2=1755774&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Wed Aug 10 16:06:07 2016
@@ -47,13 +47,8 @@ import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNumber;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.common.function.PDFunction;
-import org.apache.pdfbox.pdmodel.font.PDCIDFontType0;
-import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
 import org.apache.pdfbox.pdmodel.font.PDFont;
-import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;
-import org.apache.pdfbox.pdmodel.font.PDType0Font;
-import org.apache.pdfbox.pdmodel.font.PDType1CFont;
-import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.apache.pdfbox.pdmodel.font.PDVectorFont;
 import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
 import org.apache.pdfbox.pdmodel.graphics.blend.SoftMaskPaint;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
@@ -92,26 +87,21 @@ public class PageDrawer extends PDFGraph
 
     // parent document renderer - note: this is needed for not-yet-implemented resource caching
     private final PDFRenderer renderer;
-    
+    // glyph caches
+    private final Map<PDFont, GlyphCache> glyphCaches = new HashMap<PDFont, GlyphCache>();
     // the graphics device to draw to, xform is the initial transform of the device (i.e. DPI)
     private Graphics2D graphics;
     private AffineTransform xform;
-
     // the page box to draw (usually the crop box but may be another)
     private PDRectangle pageSize;
-    
     // clipping winding rule used for the clipping path
     private int clipWindingRule = -1;
     private GeneralPath linePath = new GeneralPath();
-
     // last clipping path
     private Area lastClip;
-
     // buffered clipping area for text being drawn
     private Area textClippingArea;
-
-    // glyph cache
-    private final Map<PDFont, Glyph2D> fontGlyph2D = new HashMap<PDFont, Glyph2D>();
+    
     
     /**
      * Constructor.
@@ -330,27 +320,41 @@ public class PageDrawer extends PDFGraph
         AffineTransform at = textRenderingMatrix.createAffineTransform();
         at.concatenate(font.getFontMatrix().createAffineTransform());
 
-        Glyph2D glyph2D = createGlyph2D(font);
-        drawGlyph2D(glyph2D, font, code, displacement, at);
+        // create cache if it does not exist
+        PDVectorFont vectorFont = ((PDVectorFont)font);
+        GlyphCache cache = glyphCaches.get(font);
+        if (cache == null)
+        {
+            cache = new GlyphCache(vectorFont);
+            glyphCaches.put(font, cache);
+        }
+        
+        // cache glyph path if is not already cache
+        GeneralPath path = cache.getPathForCharacterCode(code);
+        if (path == null)
+        {
+            path = vectorFont.getNormalizedPath(code);
+            cache.put(code, path);
+        }
+        
+        drawGlyph(path, font, code, displacement, at);
     }
 
     /**
      * Render the font using the Glyph2D interface.
      * 
-     * @param glyph2D the Glyph2D implementation provided a GeneralPath for each glyph
+     * @param path the Glyph2D implementation provided a GeneralPath for each glyph
      * @param font the font
      * @param code character code
      * @param displacement the glyph's displacement (advance)
      * @param at the transformation
      * @throws IOException if something went wrong
      */
-    private void drawGlyph2D(Glyph2D glyph2D, PDFont font, int code, Vector displacement,
-                             AffineTransform at) throws IOException
+    private void drawGlyph(GeneralPath path, PDFont font, int code, Vector displacement, AffineTransform at) throws IOException
     {
         PDGraphicsState state = getGraphicsState();
         RenderingMode renderingMode = state.getTextState().getRenderingMode();
-
-        GeneralPath path = glyph2D.getPathForCharacterCode(code);
+        
         if (path != null)
         {
             // stretch non-embedded glyph if it does not match the width contained in the PDF
@@ -391,72 +395,7 @@ public class PageDrawer extends PDFGraph
             }
         }
     }
-
-    /**
-     * Provide a Glyph2D for the given font.
-     * 
-     * @param font the font
-     * @return the implementation of the Glyph2D interface for the given font
-     * @throws IOException if something went wrong
-     */
-    private Glyph2D createGlyph2D(PDFont font) throws IOException
-    {
-        Glyph2D glyph2D = fontGlyph2D.get(font);
-        // Is there already a Glyph2D for the given font?
-        if (glyph2D != null)
-        {
-            return glyph2D;
-        }
-
-        if (font instanceof PDTrueTypeFont)
-        {
-            PDTrueTypeFont ttfFont = (PDTrueTypeFont)font;
-            glyph2D = new TTFGlyph2D(ttfFont);  // TTF is never null
-        }
-        else if (font instanceof PDType1Font)
-        {
-            PDType1Font pdType1Font = (PDType1Font)font;
-            glyph2D = new Type1Glyph2D(pdType1Font); // T1 is never null
-        }
-        else if (font instanceof PDType1CFont)
-        {
-            PDType1CFont type1CFont = (PDType1CFont)font;
-            glyph2D = new Type1Glyph2D(type1CFont);
-        }
-        else if (font instanceof PDType0Font)
-        {
-            PDType0Font type0Font = (PDType0Font) font;
-            if (type0Font.getDescendantFont() instanceof PDCIDFontType2)
-            {
-                glyph2D = new TTFGlyph2D(type0Font); // TTF is never null
-            }
-            else if (type0Font.getDescendantFont() instanceof PDCIDFontType0)
-            {
-                // a Type0 CIDFont contains CFF font
-                PDCIDFontType0 cidType0Font = (PDCIDFontType0)type0Font.getDescendantFont();
-                glyph2D = new CIDType0Glyph2D(cidType0Font); // todo: could be null (need incorporate fallback)
-            }
-        }
-        else
-        {
-            throw new IllegalStateException("Bad font type: " + font.getClass().getSimpleName());
-        }
-
-        // cache the Glyph2D instance
-        if (glyph2D != null)
-        {
-            fontGlyph2D.put(font, glyph2D);
-        }
-
-        if (glyph2D == null)
-        {
-            // todo: make sure this never happens
-            throw new UnsupportedOperationException("No font for " + font.getName());
-        }
-
-        return glyph2D;
-    }
-
+    
     @Override
     public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3)
     {
@@ -968,14 +907,6 @@ public class PageDrawer extends PDFGraph
         }
     }
 
-    private static class AnnotationBorder
-    {
-        private float[] dashArray = null;
-        private boolean underline = false;
-        private float width = 0;
-        private PDColor color;
-    }
-    
     // return border info. BorderStyle must be provided as parameter because
     // method is not available in the base class
     private AnnotationBorder getAnnotationBorder(PDAnnotation annotation, 
@@ -1034,7 +965,7 @@ public class PageDrawer extends PDFGraph
         }
         return ab;
     }
-
+    
     private void drawAnnotationLinkBorder(PDAnnotationLink link) throws IOException
     {
         AnnotationBorder ab = getAnnotationBorder(link, link.getBorderStyle());
@@ -1157,6 +1088,14 @@ public class PageDrawer extends PDFGraph
         graphics.setTransform(prev);
     }
 
+    private static class AnnotationBorder
+    {
+        private float[] dashArray = null;
+        private boolean underline = false;
+        private float width = 0;
+        private PDColor color;
+    }
+
     /**
      * Transparency group.
      **/