pdfbox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jahew...@apache.org
Subject svn commit: r1687878 [1/2] - in /pdfbox/trunk: fontbox/src/main/java/org/apache/fontbox/ fontbox/src/main/java/org/apache/fontbox/cff/ fontbox/src/main/java/org/apache/fontbox/ttf/ fontbox/src/main/java/org/apache/fontbox/type1/ pdfbox/ pdfbox/src/main...
Date Sat, 27 Jun 2015 00:18:22 GMT
Author: jahewson
Date: Sat Jun 27 00:18:21 2015
New Revision: 1687878

URL: http://svn.apache.org/r1687878
Log:
PDFBOX-2842: Overhaul font substitution

Added:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/EncodedFont.java   (with props)
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/FontBoxFont.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java
      - copied, changed from r1687667, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDVectorFont.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/BuiltInEncoding.java   (with props)
Removed:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/Type1Equivalent.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Equivalent.java
    pdfbox/trunk/pdfbox/src/main/resources/org/apache/pdfbox/resources/otf/AdobeBlank.otf
Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/IndexData.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java
    pdfbox/trunk/pdfbox/pom.xml
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
    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/PDCIDSystemInfo.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.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/PDType3Font.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/CIDType0Glyph2D.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
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type1FontValidator.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/Type1DescriptorHelper.java

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/EncodedFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/EncodedFont.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/EncodedFont.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/EncodedFont.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,34 @@
+/*
+ * 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.fontbox;
+
+import java.io.IOException;
+import org.apache.fontbox.encoding.Encoding;
+
+/**
+ * A PostScript font which uses an encoding vector.
+ *
+ * @author John Hewson
+ */
+public interface EncodedFont
+{
+    /**
+     * Returns the PostScript Encoding vector for the font.
+     */
+    Encoding getEncoding() throws IOException;
+}

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

Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/FontBoxFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/FontBoxFont.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/FontBoxFont.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/FontBoxFont.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,69 @@
+/*
+ * 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.fontbox;
+
+import java.awt.geom.GeneralPath;
+import java.io.IOException;
+import java.util.List;
+import org.apache.fontbox.util.BoundingBox;
+
+/**
+ * Common interface for all FontBox fonts.
+ *
+ * @author John Hewson
+ */
+public interface FontBoxFont
+{
+    /**
+     * The PostScript name of the font.
+     */
+    String getName() throws IOException;
+    
+    /**
+     * Returns the font's bounding box in PostScript units.
+     */
+    BoundingBox getFontBBox() throws IOException;
+
+    /**
+     * Returns the FontMatrix in PostScript units.
+     */
+    List<Number> getFontMatrix() throws IOException;
+
+    /**
+     * Returns the path for the character with the given name.
+     *
+     * @return glyph path
+     * @throws IOException if the path could not be read
+     */
+    GeneralPath getPath(String name) throws IOException;
+
+    /**
+     * Returns the advance width for the character with the given name.
+     *
+     * @return glyph advance width
+     * @throws IOException if the path could not be read
+     */
+    float getWidth(String name) throws IOException;
+
+    /**
+     * Returns true if the font contains the given glyph.
+     * 
+     * @param name PostScript glyph name
+     */
+    boolean hasGlyph(String name) throws IOException;
+}

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

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFCIDFont.java Sat Jun 27 00:18:21 2015
@@ -17,13 +17,13 @@
 
 package org.apache.fontbox.cff;
 
-import org.apache.fontbox.type1.Type1CharStringReader;
-
+import java.awt.geom.GeneralPath;
 import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import org.apache.fontbox.type1.Type1CharStringReader;
 
 /**
  * A Type 0 CIDFont represented in a CFF file. Thread safe.
@@ -247,6 +247,39 @@ public class CFFCIDFont extends CFFFont
         return (List<Number>)topDict.get("FontMatrix");
     }
 
+    @Override
+    public GeneralPath getPath(String selector) throws IOException
+    {
+        int cid = selectorToCID(selector);
+        return getType2CharString(cid).getPath();
+    }
+
+    @Override
+    public float getWidth(String selector) throws IOException
+    {
+        int cid = selectorToCID(selector);
+        return getType2CharString(cid).getWidth();
+    }
+
+    @Override
+    public boolean hasGlyph(String selector) throws IOException
+    {
+        int cid = selectorToCID(selector);
+        return cid != 0;
+    }
+
+    /**
+     * Parses a CID selector of the form \ddddd.
+     */
+    private int selectorToCID(String selector)
+    {
+        if (!selector.startsWith("\\"))
+        {
+            throw new IllegalArgumentException("Invalid selector");
+        }
+        return Integer.parseInt(selector.substring(1));
+    }
+
     /**
      * Private implementation of Type1CharStringReader, because only CFFType1Font can
      * expose this publicly, as CIDFonts only support this for legacy 'seac' commands.

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java Sat Jun 27 00:18:21 2015
@@ -16,11 +16,13 @@
  */
 package org.apache.fontbox.cff;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.fontbox.FontBoxFont;
 import org.apache.fontbox.util.BoundingBox;
 
 /**
@@ -29,7 +31,7 @@ import org.apache.fontbox.util.BoundingB
  * @author Villu Ruusmann
  * @author John Hewson
  */
-public abstract class CFFFont
+public abstract class CFFFont implements FontBoxFont
 {
     protected String fontName;
     protected final Map<String, Object> topDict = new LinkedHashMap<String, Object>();
@@ -174,6 +176,14 @@ public abstract class CFFFont
         return globalSubrIndex;
     }
 
+    /**
+     * Returns the Type 2 charstring for the given CID.
+     *
+     * @param cidOrGid CID for CIFFont, or GID for Type 1 font
+     * @throws IOException if the charstring could not be read
+     */
+    public abstract Type2CharString getType2CharString(int cidOrGid) throws IOException;
+
     @Override
     public String toString()
     {

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFType1Font.java Sat Jun 27 00:18:21 2015
@@ -16,15 +16,14 @@
  */
 package org.apache.fontbox.cff;
 
-import org.apache.fontbox.ttf.Type1Equivalent;
-import org.apache.fontbox.type1.Type1CharStringReader;
-
 import java.awt.geom.GeneralPath;
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import org.apache.fontbox.EncodedFont;
+import org.apache.fontbox.type1.Type1CharStringReader;
 
 /**
  * A Type 1-equivalent font program represented in a CFF file. Thread safe.
@@ -32,7 +31,7 @@ import java.util.concurrent.ConcurrentHa
  * @author Villu Ruusmann
  * @author John Hewson
  */
-public class CFFType1Font extends CFFFont implements Type1Equivalent
+public class CFFType1Font extends CFFFont implements EncodedFont
 {
     private final Map<String, Object> privateDict = new LinkedHashMap<String, Object>();
     private CFFEncoding encoding;

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/IndexData.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/IndexData.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/IndexData.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/IndexData.java Sat Jun 27 00:18:21 2015
@@ -104,4 +104,4 @@ public class IndexData
     {
         data[index] = value;
     }
-}
\ No newline at end of file
+}

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java Sat Jun 27 00:18:21 2015
@@ -17,6 +17,7 @@
 
 package org.apache.fontbox.ttf;
 
+import java.awt.geom.GeneralPath;
 import java.io.IOException;
 
 /**
@@ -33,7 +34,6 @@ public class OpenTypeFont extends TrueTy
     {
         super(fontData);
     }
-
     /**
      * Get the "cmap" table for this TTF.
      *
@@ -41,12 +41,25 @@ public class OpenTypeFont extends TrueTy
      */
     public synchronized CFFTable getCFF() throws IOException
     {
-        CFFTable cmap = (CFFTable)tables.get(CFFTable.TAG);
-        if (cmap != null && !cmap.getInitialized())
+        CFFTable cff = (CFFTable)tables.get(CFFTable.TAG);
+        if (cff != null && !cff.getInitialized())
         {
-            readTable(cmap);
+            readTable(cff);
         }
-        return cmap;
+        return cff;
+    }
+
+    @Override
+    public synchronized GlyphTable getGlyph() throws IOException
+    {
+        throw new UnsupportedOperationException("OTF fonts do not have a glyf table");
+    }
+
+    @Override
+    public GeneralPath getPath(String name) throws IOException
+    {
+        int gid = nameToGID(name);
+        return getCFF().getFont().getType2CharString(gid).getPath();
     }
 
     /**

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java Sat Jun 27 00:18:21 2015
@@ -19,13 +19,14 @@ package org.apache.fontbox.ttf;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.fontbox.encoding.Encoding;
+import org.apache.fontbox.FontBoxFont;
 import org.apache.fontbox.util.BoundingBox;
 
 /**
@@ -33,7 +34,7 @@ import org.apache.fontbox.util.BoundingB
  * 
  * @author Ben Litchfield
  */
-public class TrueTypeFont implements Type1Equivalent, Closeable
+public class TrueTypeFont implements FontBoxFont, Closeable
 {
     private float version;
     private int numberOfGlyphs = -1;
@@ -644,12 +645,6 @@ public class TrueTypeFont implements Typ
     }
 
     @Override
-    public Encoding getEncoding()
-    {
-        return null;
-    }
-
-    @Override
     public BoundingBox getFontBBox() throws IOException
     {
         short xMin = getHeader().getXMin();
@@ -661,6 +656,13 @@ public class TrueTypeFont implements Typ
     }
 
     @Override
+    public List<Number> getFontMatrix() throws IOException
+    {
+        float scale = 1000f / getUnitsPerEm();
+        return Arrays.<Number>asList(0.001f * scale, 0, 0, 0.001f * scale, 0, 0);
+    }
+
+    @Override
     public String toString()
     {
         try

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/type1/Type1Font.java Sat Jun 27 00:18:21 2015
@@ -17,13 +17,6 @@
 
 package org.apache.fontbox.type1;
 
-import org.apache.fontbox.cff.Type1CharString;
-import org.apache.fontbox.cff.Type1CharStringParser;
-import org.apache.fontbox.encoding.Encoding;
-import org.apache.fontbox.pfb.PfbParser;
-import org.apache.fontbox.ttf.Type1Equivalent;
-import org.apache.fontbox.util.BoundingBox;
-
 import java.awt.geom.GeneralPath;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,13 +26,20 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import org.apache.fontbox.FontBoxFont;
+import org.apache.fontbox.EncodedFont;
+import org.apache.fontbox.cff.Type1CharString;
+import org.apache.fontbox.cff.Type1CharStringParser;
+import org.apache.fontbox.encoding.Encoding;
+import org.apache.fontbox.pfb.PfbParser;
+import org.apache.fontbox.util.BoundingBox;
 
 /**
  * Represents an Adobe Type 1 (.pfb) font. Thread safe.
  *
  * @author John Hewson
  */
-public final class Type1Font implements Type1CharStringReader, Type1Equivalent
+public final class Type1Font implements Type1CharStringReader, EncodedFont, FontBoxFont
 {
     /**
      * Constructs a new Type1Font object from a .pfb stream.

Modified: pdfbox/trunk/pdfbox/pom.xml
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/pom.xml?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/pom.xml (original)
+++ pdfbox/trunk/pdfbox/pom.xml Sat Jun 27 00:18:21 2015
@@ -97,7 +97,7 @@
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
-                    <argLine>-Xmx128m</argLine>
+                    <argLine>-Xmx768m</argLine>
                     <excludes>
                         <exclude>org/apache/pdfbox/TestAll.java</exclude>
                         <exclude>org/apache/pdfbox/rendering/TestPDFToImage.java</exclude>

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Sat Jun 27 00:18:21 2015
@@ -453,7 +453,6 @@ public final class COSName extends COSBa
     public static final COSName SOFT_LIGHT = new COSName("SoftLight");
     public static final COSName SS = new COSName("SS");
     public static final COSName ST = new COSName("St");
-    public static final COSName STYLE = new COSName("Style");
     public static final COSName STANDARD_ENCODING = new COSName("StandardEncoding");
     public static final COSName STATE = new COSName("State");
     public static final COSName STATE_MODEL = new COSName("StateModel");
@@ -466,6 +465,7 @@ public final class COSName extends COSBa
     public static final COSName STRUCT_PARENT = new COSName("StructParent");
     public static final COSName STRUCT_PARENTS = new COSName("StructParents");
     public static final COSName STRUCT_TREE_ROOT = new COSName("StructTreeRoot");
+    public static final COSName STYLE = new COSName("Style");
     public static final COSName SUB_FILTER = new COSName("SubFilter");
     public static final COSName SUBJ = new COSName("Subj");
     public static final COSName SUBJECT = new COSName("Subject");

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,54 @@
+/*
+ * 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.pdmodel.font;
+
+import org.apache.fontbox.FontBoxFont;
+import org.apache.fontbox.ttf.OpenTypeFont;
+
+/**
+ * A CIDFontMapping is a kind of FontMapping which allows for an additional TrueTypeFont substitute
+ * to be provided if a CID font is not available.
+ *
+ * @author John Hewson
+ */
+public final class CIDFontMapping extends FontMapping<OpenTypeFont>
+{
+    private final FontBoxFont ttf;
+    
+    CIDFontMapping(OpenTypeFont font, FontBoxFont fontBoxFont, boolean isFallback)
+    {
+        super(font, isFallback);
+        this.ttf = fontBoxFont;
+    }
+
+    /**
+     * Returns a TrueType font when isCIDFont() is true, otherwise null.
+     */
+    public FontBoxFont getTrueTypeFont()
+    {
+        return ttf;
+    }
+
+    /**
+     * Returns true if this is a CID font.
+     */
+    public boolean isCIDFont()
+    {
+        return getFont() != null;
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDFontMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java Sat Jun 27 00:18:21 2015
@@ -16,12 +16,21 @@
  */
 package org.apache.pdfbox.pdmodel.font;
 
-import java.util.Set;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.FontBoxFont;
+import org.apache.fontbox.cff.CFFCIDFont;
 import org.apache.fontbox.cff.CFFFont;
-import org.apache.fontbox.cff.CFFParser;
 import org.apache.fontbox.ttf.NamingTable;
+import org.apache.fontbox.ttf.OTFParser;
+import org.apache.fontbox.ttf.OpenTypeFont;
 import org.apache.fontbox.ttf.TTFParser;
 import org.apache.fontbox.ttf.TrueTypeCollection;
 import org.apache.fontbox.ttf.TrueTypeFont;
@@ -29,78 +38,132 @@ import org.apache.fontbox.type1.Type1Fon
 import org.apache.fontbox.util.autodetect.FontFileFinder;
 import org.apache.pdfbox.io.IOUtils;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
- * External font provider which searches for fonts on the local filesystem.
+ * A FontProvider which searches for fonts on the local filesystem.
  *
  * @author John Hewson
  */
 final class FileSystemFontProvider extends FontProvider
 {
     private static final Log LOG = LogFactory.getLog(FileSystemFontProvider.class);
+    
+    private final List<FSFontInfo> fontInfoList = new ArrayList<FSFontInfo>();
+    private final FontCache cache;
+
+    private class FSFontInfo extends FontInfo
+    {
+        private final String postScriptName;
+        private final FontFormat format;
+        private final PDCIDSystemInfo cidSystemInfo;
+        private final File file;
 
-    // cache of font files on the system (populated in constructor)
-    private final Map<String, File> ttfFontFiles = new HashMap<String, File>();
-    private final Map<String, File> cffFontFiles = new HashMap<String, File>();
-    private final Map<String, File> type1FontFiles =  new HashMap<String, File>();
-
-    // cache of loaded fonts which are in use (populated on-the-fly)
-    private final Map<String, TrueTypeFont> ttfFonts = new HashMap<String, TrueTypeFont>();
-    private final Map<String, CFFFont> cffFonts = new HashMap<String, CFFFont>();
-    private final Map<String, Type1Font> type1Fonts = new HashMap<String, Type1Font>();
+        private FSFontInfo(File file, FontFormat format, String postScriptName,
+                           PDCIDSystemInfo cidSystemInfo)
+        {
+            this.file = file;
+            this.format = format;
+            this.postScriptName = postScriptName;
+            this.cidSystemInfo = cidSystemInfo;
+        }
+
+        @Override
+        public String getPostScriptName()
+        {
+            return postScriptName;
+        }
+
+        @Override
+        public FontFormat getFormat()
+        {
+            return format;
+        }
+
+        @Override
+        public PDCIDSystemInfo getCIDSystemInfo()
+        {
+            return cidSystemInfo;
+        }
+
+        @Override
+        public FontBoxFont getFont()
+        {
+            FontBoxFont cached = cache.getFont(this);
+            if (cached != null)
+            {
+                return cached;
+            }
+            else
+            {
+                FontBoxFont font;
+                switch (format)
+                {
+                    case PFB: font = getType1Font(postScriptName, file); break;
+                    case TTF: font = getTrueTypeFont(postScriptName, file); break;
+                    case OTF: font = getOTFFont(postScriptName, file); break;
+                    default: throw new RuntimeException("can't happen");
+                }
+                cache.addFont(this, font);
+                return font;
+            }
+        }
+
+        @Override
+        public String toString()
+        {
+            return super.toString() + " " + file;
+        }
+    }
 
     /**
      * Constructor.
      */
-    FileSystemFontProvider()
+    FileSystemFontProvider(FontCache cache)
     {
+        this.cache = cache;
+
         if (LOG.isTraceEnabled())
         {
             LOG.trace("Will search the local system for fonts");
         }
 
-        int count = 0;
+        List<File> files = new ArrayList<File>();
         FontFileFinder fontFileFinder = new FontFileFinder();
         List<URI> fonts = fontFileFinder.find();
         for (URI font : fonts)
         {
-            count++;
-            File fontFile = new File(font);
+            files.add(new File(font));
+        }
+
+        if (LOG.isTraceEnabled())
+        {
+            LOG.trace("Found " + files.size() + " fonts on the local system");
+        }
+        
+        // todo: loading all of these fonts is slow, can we cache this?
+        for (File file : files)
+        {
             try
             {
-                if (fontFile.getPath().toLowerCase().endsWith(".ttf") ||
-                    fontFile.getPath().toLowerCase().endsWith(".otf"))
+                if (file.getPath().toLowerCase().endsWith(".ttf") ||
+                    file.getPath().toLowerCase().endsWith(".otf"))
                 {
-                    addTrueTypeFont(fontFile);
+                    addTrueTypeFont(file);
                 }
-                else if (fontFile.getPath().toLowerCase().endsWith(".ttc") ||
-                         fontFile.getPath().toLowerCase().endsWith(".otc"))
+                else if (file.getPath().toLowerCase().endsWith(".ttc") ||
+                         file.getPath().toLowerCase().endsWith(".otc"))
                 {
-                    addTrueTypeCollection(fontFile);
+                    addTrueTypeCollection(file);
                 }
-                else if (fontFile.getPath().toLowerCase().endsWith(".pfb"))
+                else if (file.getPath().toLowerCase().endsWith(".pfb"))
                 {
-                    addType1Font(fontFile);
+                    addType1Font(file);
                 }
             }
             catch (IOException e)
             {
-                LOG.error("Error parsing font " + fontFile.getPath(), e);
+                LOG.error("Error parsing font " + file.getPath(), e);
             }
         }
-
-        if (LOG.isTraceEnabled())
-        {
-            LOG.trace("Found " + count + " fonts on the local system");
-        }
     }
 
     /**
@@ -133,17 +196,26 @@ final class FileSystemFontProvider exten
             }
         }
     }
-    
+
     /**
      * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font is not cached.
      */
     private void addTrueTypeFont(File ttfFile) throws IOException
     {
-        TTFParser ttfParser = new TTFParser(false, true);
         try
         {
-            TrueTypeFont ttf = ttfParser.parse(ttfFile);
-            addTrueTypeFontImpl(ttf, ttfFile);
+            if (ttfFile.getPath().endsWith(".otf"))
+            {
+                OTFParser parser = new OTFParser(false, true);
+                OpenTypeFont otf = parser.parse(ttfFile);
+                addTrueTypeFontImpl(otf, ttfFile);
+            }
+            else
+            {
+                TTFParser parser = new TTFParser(false, true);
+                TrueTypeFont ttf = parser.parse(ttfFile);
+                addTrueTypeFontImpl(ttf, ttfFile);
+            }
         }
         catch (NullPointerException e) // TTF parser is buggy
         {
@@ -154,7 +226,7 @@ final class FileSystemFontProvider exten
             LOG.error("Could not load font file: " + ttfFile, e);
         }
     }
-    
+
     /**
      * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font is not cached.
      */
@@ -168,9 +240,10 @@ final class FileSystemFontProvider exten
             // ttf could still be null
             if (ttf != null)
             {
+                // todo: this is a performance bottleneck, we don't actually need to read this table
                 nameTable = ttf.getNaming();
             }
-            
+
             if (nameTable == null)
             {
                 LOG.warn("Missing 'name' table in font " + file);
@@ -178,26 +251,35 @@ final class FileSystemFontProvider exten
             else
             {
                 // read PostScript name, if any
-                if (nameTable.getPostScriptName() != null)
+                if (ttf.getName() != null)
                 {
-                    String psName = nameTable.getPostScriptName();
-
                     String format;
-                    if (ttf.getTableMap().get("CFF ") != null)
+                    if (ttf instanceof OpenTypeFont)
                     {
                         format = "OTF";
-                        cffFontFiles.putAll(toMap(getNames(ttf), file));
+                        CFFFont cff = ((OpenTypeFont)ttf).getCFF().getFont();
+                        PDCIDSystemInfo ros = null;
+                        if (cff instanceof CFFCIDFont)
+                        {
+                            CFFCIDFont cidFont = (CFFCIDFont)cff;
+                            String registry = cidFont.getRegistry();
+                            String ordering = cidFont.getOrdering();
+                            int supplement = cidFont.getSupplement();
+                            ros = new PDCIDSystemInfo(registry, ordering, supplement);
+                        }
+                        fontInfoList.add(new FSFontInfo(file, FontFormat.OTF, ttf.getName(), ros));
                     }
                     else
                     {
                         format = "TTF";
-                        ttfFontFiles.putAll(toMap(getNames(ttf), file));
+                        fontInfoList.add(new FSFontInfo(file, FontFormat.TTF, ttf.getName(), null));
                     }
 
                     if (LOG.isTraceEnabled())
                     {
-                        LOG.trace(format +": '" + psName + "' / '" + nameTable.getFontFamily() +
-                                "' / '" + nameTable.getFontSubFamily() + "'");
+                        LOG.trace(format +": '" + ttf.getName() + "' / '" +
+                                nameTable.getFontFamily() + "' / '" +
+                                nameTable.getFontSubFamily() + "'");
                     }
                 }
                 else
@@ -206,6 +288,10 @@ final class FileSystemFontProvider exten
                 }
             }
         }
+        catch (IOException e)
+        {
+            LOG.error("Could not load font file: " + file, e);
+        }
         finally
         {
             if (ttf != null)
@@ -224,56 +310,43 @@ final class FileSystemFontProvider exten
         try
         {
             Type1Font type1 = Type1Font.createWithPFB(input);
-
-            String psName = type1.getFontName();
-            type1FontFiles.putAll(toMap(getNames(type1), pfbFile));
+            fontInfoList.add(new FSFontInfo(pfbFile, FontFormat.PFB, type1.getName(), null));
 
             if (LOG.isTraceEnabled())
             {
-                LOG.trace("PFB: '" + psName + "' / '" + type1.getFamilyName() + "' / '" +
+                LOG.trace("PFB: '" + type1.getName() + "' / '" + type1.getFamilyName() + "' / '" +
                         type1.getWeight() + "'");
             }
         }
+        catch (IOException e)
+        {
+            LOG.error("Could not load font file: " + pfbFile, e);
+        }
         finally
         {
             input.close();
         }
     }
-    
-    @Override
-    public synchronized TrueTypeFont getTrueTypeFont(String postScriptName)
-    {
-        TrueTypeFont ttf = ttfFonts.get(postScriptName);
-        if (ttf != null)
-        {
-            return ttf;
-        }
 
-        File file = ttfFontFiles.get(postScriptName);
-        if (file != null)
+    private TrueTypeFont getTrueTypeFont(String postScriptName, File file)
+    {
+        try
         {
-            try
-            {
-                ttf = readTrueTypeFont(postScriptName, file);
+            TrueTypeFont ttf = readTrueTypeFont(postScriptName, file);
 
-                for (String name : getNames(ttf))
-                {
-                    ttfFonts.put(name, ttf);
-                }
-                if (LOG.isDebugEnabled())
-                {
-                    LOG.debug("Loaded " + postScriptName + " from " + file);
-                }
-                return ttf;
-            }
-            catch (NullPointerException e) // TTF parser is buggy
+            if (LOG.isDebugEnabled())
             {
-                LOG.error("Could not load font file: " + file, e);
-            }
-            catch (IOException e)
-            {
-                LOG.error("Could not load font file: " + file, e);
+                LOG.debug("Loaded " + postScriptName + " from " + file);
             }
+            return ttf;
+        }
+        catch (NullPointerException e) // TTF parser is buggy
+        {
+            LOG.error("Could not load font file: " + file, e);
+        }
+        catch (IOException e)
+        {
+            LOG.error("Could not load font file: " + file, e);
         }
         return null;
     }
@@ -298,129 +371,72 @@ final class FileSystemFontProvider exten
             return ttfParser.parse(file);
         }
     }
-    
-    @Override
-    public synchronized CFFFont getCFFFont(String postScriptName)
+
+    private OpenTypeFont getOTFFont(String postScriptName, File file)
     {
-        CFFFont cff = cffFonts.get(postScriptName);
-        if (cff != null)
+        try
         {
-            return cff;
-        }
+            // todo JH: we don't yet support loading CFF fonts from OTC collections

+            OTFParser parser = new OTFParser(false, true);
+            OpenTypeFont otf = parser.parse(file);
 
-        File file = cffFontFiles.get(postScriptName);
-        if (file != null)
-        {
-            InputStream input = null;
-            try
+            if (LOG.isDebugEnabled())
             {
-                // todo JH: we don't yet support loading CFF fonts from OTC collections

-                input = new FileInputStream(file);
-                byte[] bytes = IOUtils.toByteArray(input);
-                CFFParser cffParser = new CFFParser();
-                cff = cffParser.parse(bytes).get(0);
-                for (String name : getNames(cff))
-                {
-                    cffFonts.put(name, cff);
-                }
-                if (LOG.isDebugEnabled())
-                {
-                    LOG.debug("Loaded " + postScriptName + " from " + file);
-                }
-                return cff;
-            }
-            catch (IOException e)
-            {
-                LOG.error("Could not load font file: " + file, e);
-            }
-            finally
-            {
-                IOUtils.closeQuietly(input);
+                LOG.debug("Loaded " + postScriptName + " from " + file);
             }
+            return otf;
+        }
+        catch (IOException e)
+        {
+            LOG.error("Could not load font file: " + file, e);
         }
         return null;
     }
 
-    @Override
-    public synchronized Type1Font getType1Font(String postScriptName)
+    private Type1Font getType1Font(String postScriptName, File file)
     {
-        Type1Font type1 = type1Fonts.get(postScriptName);
-        if (type1 != null)
+        InputStream input = null;
+        try
         {
-            return type1;
-        }
+            input = new FileInputStream(file);
+            Type1Font type1 = Type1Font.createWithPFB(input);
 
-        File file = type1FontFiles.get(postScriptName);
-        if (file != null)
-        {
-            InputStream input = null;
-            try
+            if (LOG.isDebugEnabled())
             {
-                input = new FileInputStream(file);
-                type1 = Type1Font.createWithPFB(input);
-                for (String name : getNames(type1))
-                {
-                    type1Fonts.put(name, type1);
-                }
-                if (LOG.isDebugEnabled())
-                {
-                    LOG.debug("Loaded " + postScriptName + " from " + file);
-                }
-                return type1;
-            }
-            catch (IOException e)
-            {
-                LOG.error("Could not load font file: " + file, e);
-            }
-            finally
-            {
-                IOUtils.closeQuietly(input);
+                LOG.debug("Loaded " + postScriptName + " from " + file);
             }
+            return type1;
         }
-        return null;
-    }
-
-    /**
-     * Returns a map containing the given file for each string key.
-     */
-    private Map<String, File> toMap(Set<String> names, File file)
-    {
-        Map<String, File> map = new HashMap<String, File>();
-        for (String name : names)
+        catch (IOException e)
+        {
+            LOG.error("Could not load font file: " + file, e);
+        }
+        finally
         {
-            map.put(name, file);
+            IOUtils.closeQuietly(input);
         }
-        return map;
+        return null;
     }
 
     @Override
     public String toDebugString()
     {
         StringBuilder sb = new StringBuilder();
-        for (Map.Entry<String, File> entry : ttfFontFiles.entrySet())
+        for (FSFontInfo info : fontInfoList)
         {
-            sb.append("TTF: ");
-            sb.append(entry.getKey());
+            sb.append(info.getFormat());
             sb.append(": ");
-            sb.append(entry.getValue().getPath());
-            sb.append('\n');
-        }
-        for (Map.Entry<String, File> entry : cffFontFiles.entrySet())
-        {
-            sb.append("OTF: ");
-            sb.append(entry.getKey());
-            sb.append(": ");
-            sb.append(entry.getValue().getPath());
-            sb.append('\n');
-        }
-        for (Map.Entry<String, File> entry : type1FontFiles.entrySet())
-        {
-            sb.append("PFB: ");
-            sb.append(entry.getKey());
+            sb.append(info.getPostScriptName());
             sb.append(": ");
-            sb.append(entry.getValue().getPath());
+            sb.append(info.file.getPath());
             sb.append('\n');
         }
         return sb.toString();
     }
+
+    @Override
+    public List<? extends FontInfo> getFontInfo()
+    {
+        return fontInfoList;
+    }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,49 @@
+/*
+ * 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.pdmodel.font;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.fontbox.FontBoxFont;
+
+/**
+ * A cache for system fonts. This allows PDFBox to manage caching for a {@link FontProvider}.
+ * PDFBox is free to purge this cache at will.
+ *
+ * @author John Hewson
+ */
+public final class FontCache
+{
+    private final Map<FontInfo, FontBoxFont> cache = new ConcurrentHashMap<FontInfo, FontBoxFont>();
+
+    /**
+     * Adds the given FontBox font to the cache.
+     */
+    public void addFont(FontInfo info, FontBoxFont font)
+    {
+        cache.put(info, font);
+    }
+
+    /**
+     * Returns the FontBox font associated with the given FontInfo.
+     */
+    public FontBoxFont getFont(FontInfo info)
+    {
+        return cache.get(info);
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,41 @@
+/*
+ * 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.pdmodel.font;
+
+/**
+ * Font file format.
+ *
+ * @author John Hewson
+ */
+public enum FontFormat
+{
+    /**
+     * TrueType font.
+     */
+    TTF,
+
+    /**
+     * OpenType font.
+     */
+    OTF,
+
+    /**
+     * Type 1 (binary) font.
+     */
+    PFB
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontFormat.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,55 @@
+/*
+ * 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.pdmodel.font;
+
+import org.apache.fontbox.FontBoxFont;
+
+/**
+ * Information about a font on the system.
+ *
+ * @author John Hewson
+ */
+public abstract class FontInfo
+{
+    /**
+     * Returns the PostScript name of the font.
+     */
+    public abstract String getPostScriptName();
+
+    /**
+     * Returns the font's format.
+     */
+    public abstract FontFormat getFormat();
+
+    /**
+     * Returns the CIDSystemInfo associated with the font, if any.
+     */
+    public abstract PDCIDSystemInfo getCIDSystemInfo();
+
+    /**
+     * Returns a new FontBox font instance for the font. Implementors of this method must not
+     * cache the return value of this method unless doing so via the current {@link FontCache}.
+     */
+    public abstract FontBoxFont getFont();
+    
+    @Override
+    public String toString()
+    {
+        return getPostScriptName() + " (" + getFormat() + ")";
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java (from r1687667, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java)
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java?p2=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java&p1=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java&r1=1687667&r2=1687878&rev=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java Sat Jun 27 00:18:21 2015
@@ -23,68 +23,48 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.fontbox.cff.CFFCIDFont;
+import org.apache.fontbox.FontBoxFont;
 import org.apache.fontbox.cff.CFFFont;
-import org.apache.fontbox.cff.CFFParser;
 import org.apache.fontbox.cff.CFFType1Font;
+import org.apache.fontbox.ttf.OpenTypeFont;
 import org.apache.fontbox.ttf.TTFParser;
-import org.apache.fontbox.ttf.Type1Equivalent;
 import org.apache.fontbox.ttf.TrueTypeFont;
 import org.apache.fontbox.type1.Type1Font;
-import org.apache.pdfbox.io.IOUtils;
 
 /**
- * External font service, locates non-embedded fonts via a pluggable FontProvider.
+ * Font mapper, locates non-embedded fonts via a pluggable FontProvider.
  *
  * @author John Hewson
  */
-public final class ExternalFonts
+public final class FontMapper
 {
-    private ExternalFonts() {}
-
-    // lazy thread safe singleton
-    private static class DefaultFontProvider
-    {
-        private static final FontProvider INSTANCE = new FileSystemFontProvider();
-    }
+    private FontMapper() {}
 
-    private static final Log log = LogFactory.getLog(ExternalFonts.class);
+    private static final FontCache fontCache = new FontCache(); // todo: static cache isn't ideal
+    private static final Log log = LogFactory.getLog(FontMapper.class);
     private static FontProvider fontProvider;
+    private static Map<String, FontInfo> fontInfoByName;
 
     /** fallback fonts, used as as a last resort */
-    private static final TrueTypeFont ttfFallbackFont;
-    private static final CFFCIDFont cidFallbackFont;
+    private static final TrueTypeFont lastResortFont;
     static
     {
         try
         {
-            // ttf
             String ttfName = "org/apache/pdfbox/resources/ttf/LiberationSans-Regular.ttf";
-            URL url = ExternalFonts.class.getClassLoader().getResource(ttfName);
+            URL url = FontMapper.class.getClassLoader().getResource(ttfName);
             if (url == null)
             {
                 throw new IOException("Error loading resource: " + ttfName);
             }
             InputStream ttfStream = url.openStream();
             TTFParser ttfParser = new TTFParser();
-            ttfFallbackFont = ttfParser.parse(ttfStream);
-
-            // cff
-            String cffName = "org/apache/pdfbox/resources/otf/AdobeBlank.otf";
-            url = ExternalFonts.class.getClassLoader().getResource(cffName);
-            if (url == null)
-            {
-                throw new IOException("Error loading resource: " + ttfName);
-            }
-            InputStream cffStream = url.openStream();
-            byte[] bytes = IOUtils.toByteArray(cffStream);
-            CFFParser cffParser = new CFFParser();
-            cidFallbackFont = (CFFCIDFont)cffParser.parse(bytes).get(0);
+            lastResortFont = ttfParser.parse(ttfStream);
         }
         catch (IOException e)
         {
@@ -92,26 +72,52 @@ public final class ExternalFonts
         }
     }
 
+    // lazy thread safe singleton
+    private static class DefaultFontProvider
+    {
+        private static final FontProvider INSTANCE = new FileSystemFontProvider(fontCache);
+    }
+
     /**
      * Sets the font service provider.
      */
-    public static void setProvider(FontProvider fontProvider)
+    public synchronized static void setProvider(FontProvider fontProvider)
     {
-        ExternalFonts.fontProvider = fontProvider;
+        FontMapper.fontProvider = fontProvider;
+        fontInfoByName = createFontInfoByName(fontProvider.getFontInfo());
     }
 
     /**
      * Returns the font service provider. Defaults to using FileSystemFontProvider.
      */
-    public static FontProvider getProvider()
+    public synchronized static FontProvider getProvider()
     {
         if (fontProvider == null)
         {
-            fontProvider = DefaultFontProvider.INSTANCE;
+            setProvider(DefaultFontProvider.INSTANCE);
         }
         return fontProvider;
     }
 
+    /**
+     * Returns the font cache associated with this FontMapper. This method is needed by
+     * FontProvider subclasses.
+     */
+    public static FontCache getFontCache()
+    {
+        return fontCache;
+    }
+    
+    private static Map<String, FontInfo> createFontInfoByName(List<? extends FontInfo> fontInfoList)
+    {
+        Map<String, FontInfo> map = new LinkedHashMap<String, FontInfo>();
+        for (FontInfo info : fontInfoList)
+        {
+            map.put(info.getPostScriptName(), info);
+        }
+        return map;
+    }
+
     /** Map of PostScript name substitutes, in priority order. */
     private static final Map<String, List<String>> substitutes = new HashMap<String, List<String>>();
     static
@@ -156,13 +162,7 @@ public final class ExternalFonts
                              "NimbusRomNo9L-MediItal"));
         substitutes.put("Symbol", Arrays.asList("Symbol", "SymbolMT", "StandardSymL"));
         substitutes.put("ZapfDingbats", Arrays.asList("ZapfDingbatsITC", "Dingbats", "MS-Gothic"));
-
-        // extra substitute mechanism for CJK CIDFonts when all we know is the ROS
-        substitutes.put("$Adobe-CNS1", Arrays.asList("AdobeMingStd-Light"));
-        substitutes.put("$Adobe-Japan1", Arrays.asList("KozMinPr6N-Regular"));
-        substitutes.put("$Adobe-Korea1", Arrays.asList("AdobeGothicStd-Bold"));
-        substitutes.put("$Adobe-GB1", Arrays.asList("AdobeHeitiStd-Regular"));
-
+        
         // Acrobat also uses alternative names for Standard 14 fonts, which we map to those above
         // these include names such as "Arial" and "TimesNewRoman"
         for (String baseName : Standard14Fonts.getNames())
@@ -215,73 +215,6 @@ public final class ExternalFonts
     }
 
     /**
-     * Windows name (ArialNarrow,Bold) to PostScript name (ArialNarrow-Bold)
-     */
-    private static String windowsToPs(String windowsName)
-    {
-        return windowsName.replaceAll(",", "-");
-    }
-
-    /**
-     * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null.
-     *
-     * @param registryOrdering the CID system registry and ordering e.g. "Adobe-Japan1", if any
-     * @param fontDescriptor the font descriptor, if any
-     */
-    public static CFFCIDFont getCFFCIDFontFallback(String registryOrdering,
-                                                   PDFontDescriptor fontDescriptor)
-    {
-        // try ROS substitutes
-        // todo: this is a fairly primitive mechanism and could be improved
-        if (registryOrdering != null)
-        {
-            for (String substituteName : getSubstitutes("$" + registryOrdering))
-            {
-                CFFFont cff = getProvider().getCFFFont(substituteName);
-                if (cff instanceof CFFCIDFont)
-                {
-                    return (CFFCIDFont) cff;
-                }
-            }
-        }
-        return cidFallbackFont;
-    }
-
-    /**
-     * Returns the fallback font, used for rendering when no other fonts are available,
-     * we attempt to find a good fallback based on the font descriptor.
-     */
-    public static Type1Equivalent getType1FallbackFont(PDFontDescriptor fontDescriptor)
-    {
-        String fontName = getFallbackFontName(fontDescriptor);
-        Type1Equivalent type1Equivalent = getType1EquivalentFont(fontName);
-        if (type1Equivalent == null)
-        {
-            // only systems with no fonts should reach this point, so we return a basic fallback
-            log.error("No fallback font for '" + fontName + "'");
-            return ttfFallbackFont;
-        }
-        return type1Equivalent;
-    }
-
-    /**
-     * Returns the fallback font, used for rendering when no other fonts are available,
-     * we attempt to find a good fallback based on the font descriptor.
-     */
-    public static TrueTypeFont getTrueTypeFallbackFont(PDFontDescriptor fontDescriptor)
-    {
-        String fontName = getFallbackFontName(fontDescriptor);
-        TrueTypeFont ttf = getTrueTypeFont(fontName);
-        if (ttf == null)
-        {
-            // we have to return something here as TTFs aren't strictly required on the system
-            log.error("No TTF fallback font for '" + fontName + "'");
-            return ttfFallbackFont;
-        }
-        return ttf;
-    }
-
-    /**
      * Attempts to find a good fallback based on the font descriptor.
      */
     private static String getFallbackFontName(PDFontDescriptor fontDescriptor)
@@ -365,138 +298,203 @@ public final class ExternalFonts
     /**
      * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null.
      *
-     * @param postScriptName PostScript font name
+     * @param fontDescriptor FontDescriptor
      */
-    public static TrueTypeFont getTrueTypeFont(String postScriptName)
+    public static FontMapping<TrueTypeFont> getTrueTypeFont(PDFontDescriptor fontDescriptor)
     {
-        // first ask the font provider for the font
-        TrueTypeFont ttf = getProvider().getTrueTypeFont(postScriptName);
-        if (ttf == null)
+        TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, fontDescriptor.getFontName());
+        if (ttf != null)
+        {
+            return new FontMapping<TrueTypeFont>(ttf, false);
+        }
+        else
         {
-            // then try substitutes
-            for (String substituteName : getSubstitutes(postScriptName))
+            // fallback - todo: i.e. fuzzy match
+            String fontName = getFallbackFontName(fontDescriptor);
+            ttf = (TrueTypeFont) findFont(FontFormat.TTF, fontName);
+            if (ttf == null)
             {
-                ttf = getProvider().getTrueTypeFont(substituteName);
-                if (ttf != null)
-                {
-                    return ttf;
-                }
+                // we have to return something here as TTFs aren't strictly required on the system
+                log.error("Using last-resort fallback for TTF font '" + fontName + "'");
+                ttf = lastResortFont;
             }
-            // then Windows name
-            ttf = getProvider().getTrueTypeFont(windowsToPs(postScriptName));
+            return new FontMapping<TrueTypeFont>(ttf, true);
         }
-        return ttf;
     }
 
     /**
-     * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null.
+     * Finds a font with the given PostScript name, or a suitable substitute, or null. This allows
+     * any font to be substituted with a PFB, TTF or OTF.
      *
-     * @param postScriptName PostScript font name
+     * @param fontDescriptor the FontDescriptor of the font to find
      */
-    public static Type1Font getType1Font(String postScriptName)
+    public static FontMapping<FontBoxFont> getFontBoxFont(PDFontDescriptor fontDescriptor)
     {
-        // first ask the font provider for the font
-        Type1Font t1 = getProvider().getType1Font(postScriptName);
-        if (t1 == null)
+        FontBoxFont font = findFontBoxFont(fontDescriptor.getFontName());
+        if (font != null)
         {
-            // then try substitutes
-            for (String substituteName : getSubstitutes(postScriptName))
+            return new FontMapping<FontBoxFont>(font, false);
+        }
+        else
+        {
+            // fallback - todo: i.e. fuzzy match
+            String fontName = getFallbackFontName(fontDescriptor);
+            font = findFontBoxFont(fontName);
+            if (font == null)
             {
-                t1 = getProvider().getType1Font(substituteName);
-                if (t1 != null)
-                {
-                    return t1;
-                }
+                // we have to return something here as TTFs aren't strictly required on the system
+                log.error("Using last-resort fallback for font '" + fontName + "'");
+                font = lastResortFont;
             }
-            // then Windows name
-            t1 = getProvider().getType1Font(windowsToPs(postScriptName));
+            return new FontMapping<FontBoxFont>(font, true);
         }
-        return t1;
     }
 
     /**
-     * Finds a CFF Type 1 font with the given PostScript name, or a suitable substitute, or null.
+     * Finds a font with the given PostScript name, or a suitable substitute, or null.
      *
      * @param postScriptName PostScript font name
      */
-    public static CFFType1Font getCFFType1Font(String postScriptName)
+    private static FontBoxFont findFontBoxFont(String postScriptName)
     {
-        CFFFont cff = getCFFFont(postScriptName);
+        Type1Font t1 = (Type1Font)findFont(FontFormat.PFB, postScriptName);
+        if (t1 != null)
+        {
+            return t1;
+        }
+
+        CFFFont cff = (CFFFont)findFont(FontFormat.OTF, postScriptName);
         if (cff instanceof CFFType1Font)
         {
-            return (CFFType1Font)cff;
+            return cff;
+        }
+
+        TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, postScriptName);
+        if (ttf != null)
+        {
+            return ttf;
         }
+
         return null;
     }
 
     /**
-     * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null.
+     * Finds a font with the given PostScript name, or a suitable substitute, or null.
      *
      * @param postScriptName PostScript font name
      */
-    public static CFFCIDFont getCFFCIDFont(String postScriptName)
+    private static FontBoxFont findFont(FontFormat format, String postScriptName)
     {
-        CFFFont cff = getCFFFont(postScriptName);
-        if (cff instanceof CFFCIDFont)
+        // make sure the font provider is initialized
+        if (fontProvider == null)
+        {
+            getProvider();
+        }
+
+        // first try to match the PostScript name
+        FontInfo info = getFont(format, postScriptName);
+        if (info != null)
+        {
+            return info.getFont();
+        }
+
+        // remove hyphens (e.g. Arial-Black -> ArialBlack)
+        info = getFont(format, postScriptName.replaceAll("-", ""));
+        if (info != null)
+        {
+            return info.getFont();
+        }
+
+        // then try named substitutes
+        for (String substituteName : getSubstitutes(postScriptName))
         {
-            return (CFFCIDFont)cff;
+            info = getFont(format, substituteName);
+            if (info != null)
+            {
+                return info.getFont();
+            }
+        }
+
+        // then try converting Windows names e.g. (ArialNarrow,Bold) -> (ArialNarrow-Bold)
+        info = getFont(format, postScriptName.replaceAll(",", "-"));
+        if (info != null)
+        {
+            return info.getFont();
         }
+
+        // no matches
         return null;
     }
 
     /**
-     * Finds a CFF font with the given PostScript name, or a suitable substitute, or null.
-     *
-     * @param postScriptName PostScript font name
+     * Finds the named font with the given format.
      */
-    private static CFFFont getCFFFont(String postScriptName)
+    private static FontInfo getFont(FontFormat format, String postScriptName)
     {
-        // first ask the font provider for the font
-        CFFFont cff = getProvider().getCFFFont(postScriptName);
-        if (cff == null)
+        // strip subset tag (happens when we substitute a corrupt embedded font, see PDFBOX-2642)
+        if (postScriptName.contains("+"))
         {
-            // then try substitutes
-            for (String substituteName : getSubstitutes(postScriptName))
-            {
-                cff = getProvider().getCFFFont(substituteName);
-                if (cff != null)
-                {
-                    return cff;
-                }
-            }
-
-            // then Windows name
-            cff = getProvider().getCFFFont(windowsToPs(postScriptName));
+            postScriptName = postScriptName.substring(postScriptName.indexOf("+") + 1);
+        }
+        
+        // look up the PostScript name
+        FontInfo info = fontInfoByName.get(postScriptName);
+        if (info != null && info.getFormat() == format)
+        {
+            return info;
         }
-        return cff;
+        return null;
     }
-
+    
     /**
-     * Finds a Type 1-equivalent font with the given PostScript name, or a suitable substitute,
-     * or null. This allows a Type 1 font to be substituted with a PFB, TTF or OTF.
-     *
-     * @param postScriptName PostScript font name
+     * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null.
+     * This method can also map CJK fonts via their CIDSystemInfo (ROS).
+     * 
+     * @param fontDescriptor FontDescriptor
+     * @param cidSystemInfo the CID system info, e.g. "Adobe-Japan1", if any.
      */
-    public static Type1Equivalent getType1EquivalentFont(String postScriptName)
+    public static CIDFontMapping getCIDFont(PDFontDescriptor fontDescriptor,
+                                            PDCIDSystemInfo cidSystemInfo)
     {
-        Type1Font t1 = getType1Font(postScriptName);
-        if (t1 != null)
+        // try name match or substitute with OTF
+        OpenTypeFont otf1 = (OpenTypeFont)findFont(FontFormat.OTF, fontDescriptor.getFontName());
+        if (otf1 != null)
         {
-            return t1;
+            return new CIDFontMapping(otf1, null, false);
         }
 
-        CFFType1Font cff = getCFFType1Font(postScriptName);
-        if (cff != null)
+        // try name match or substitute with TTF
+        TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, fontDescriptor.getFontName());
+        if (ttf != null)
         {
-            return cff;
+            return new CIDFontMapping(null, ttf, false);
         }
 
-        TrueTypeFont ttf = getTrueTypeFont(postScriptName);
-        if (ttf != null)
+        if (cidSystemInfo != null)
         {
-            return ttf;
+            // "In Acrobat 3.0.1 and later, Type 0 fonts that use a CMap whose CIDSystemInfo
+            // dictionary defines the Adobe-GB1, Adobe-CNS1 Adobe-Japan1, or Adobe-Korea1 character
+            // collection can also be substituted." - Adobe Supplement to the ISO 32000
+
+            String collection = cidSystemInfo.getRegistry() + "-" + cidSystemInfo.getOrdering();
+            
+            if (collection.equals("Adobe-GB1") || collection.equals("Adobe-CNS1") ||
+                collection.equals("Adobe-Japan1") ||  collection.equals("Adobe-Korea1"))
+            {
+                // try automatic substitutes via character collection
+                for (FontInfo info : fontInfoByName.values())
+                {
+                    if (info.getCIDSystemInfo() != null &&
+                        info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) &&
+                        info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering()))
+                    {
+                        return new CIDFontMapping((OpenTypeFont)info.getFont(), null, true);
+                    }
+                }
+            }
         }
 
-        return null;
+        // last-resort fallback
+        return new CIDFontMapping(null, lastResortFont, true);
     }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java?rev=1687878&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java Sat Jun 27 00:18:21 2015
@@ -0,0 +1,54 @@
+/*
+ * 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.pdmodel.font;
+
+import org.apache.fontbox.FontBoxFont;
+
+/**
+ * A font mapping from a PDF font to a FontBox font.
+ *
+ * @author John Hewson
+ */
+public class FontMapping<T extends FontBoxFont>
+{
+    private final T font;
+    private final boolean isFallback;
+    
+    FontMapping(T font, boolean isFallback)
+    {
+        this.font = font;
+        this.isFallback = isFallback;
+    }
+
+    /**
+     * Returns the mapped, FontBox font. This is never null.
+     */
+    public T getFont()
+    {
+        return font;
+    }
+
+    /**
+     * Returns true if the mapped font is a fallback, i.e. a substitute based on basic font style,
+     * such as bold/italic, rather than font name.
+     */
+    public boolean isFallback()
+    {
+        return isFallback;
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java Sat Jun 27 00:18:21 2015
@@ -16,93 +16,23 @@
  */
 package org.apache.pdfbox.pdmodel.font;
 
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.fontbox.cff.CFFFont;
-import org.apache.fontbox.ttf.TrueTypeFont;
-import org.apache.fontbox.type1.Type1Font;
+import java.util.List;
 
 /**
- * External font service provider interface. Implementations are expected to be thread safe.
+ * External font service provider interface.
  *
  * @author John Hewson
  */
 public abstract class FontProvider
 {
     /**
-     * Returns a TrueType which corresponds to the given PostScript name. If there is no
-     * suitable font, then this method will return null.
-     *
-     * @param postScriptName PostScript font name
-     */
-    public abstract TrueTypeFont getTrueTypeFont(String postScriptName);
-
-    /**
-     * Returns a CFF font which corresponds to the given PostScript name. If there is no
-     * suitable font, then this method will return null.
-     *
-     * @param postScriptName PostScript font name
-     */
-    public abstract CFFFont getCFFFont(String postScriptName);
-
-    /**
-     * Returns a Type 1 which corresponds to the given PostScript name. If there is no
-     * suitable font, then this method will return null.
-     *
-     * @param postScriptName PostScript font name
-     */
-    public abstract Type1Font getType1Font(String postScriptName);
-
-    /**
      * Returns a string containing debugging information. This will be written to the log if no
      * suitable fonts are found and no fallback fonts are available. May be null.
      */
     public abstract String toDebugString();
 
     /**
-     * Returns the font names for a given font. This allows substitution based on the PostScript
-     * name of the external font, instead of just the BaseName in the PDF.
+     * Returns a list of information about fonts on the system.
      */
-    protected final Set<String> getNames(TrueTypeFont font) throws IOException
-    {
-        return getPostScriptNames(font.getName());
-        // could add format-specific names here if needed
-    }
-
-    /**
-     * Returns the font names for a given font. This allows substitution based on the PostScript
-     * name of the external font, instead of just the BaseName in the PDF.
-     */
-    protected final Set<String> getNames(Type1Font font) throws IOException
-    {
-        return getPostScriptNames(font.getName());
-        // could add format-specific names here if needed
-    }
-
-    /**
-     * Returns the font names for a given font. This allows substitution based on the PostScript
-     * name of the external font, instead of just the BaseName in the PDF.
-     */
-    protected final Set<String> getNames(CFFFont font) throws IOException
-    {
-        return getPostScriptNames(font.getName());
-        // could add format-specific names here if needed
-    }
-
-    /**
-     * Returns a list of alternative names for the given PostScript name.
-     */
-    private Set<String> getPostScriptNames(String postScriptName) throws IOException
-    {
-        Set<String> names = new HashSet<String>();
-
-        // built-in PostScript name
-        names.add(postScriptName);
-
-        // remove hyphens (e.g. Arial-Black -> ArialBlack)
-        names.add(postScriptName.replaceAll("-", ""));
-
-        return names;
-    }
+    public abstract List<? extends FontInfo> getFontInfo();
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java?rev=1687878&r1=1687877&r2=1687878&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java Sat Jun 27 00:18:21 2015
@@ -38,7 +38,7 @@ import org.apache.pdfbox.util.Vector;
  *
  * @author Ben Litchfield
  */
-public abstract class PDCIDFont implements COSObjectable, PDFontLike
+public abstract class PDCIDFont implements COSObjectable, PDFontLike, PDVectorFont
 {
     protected final PDType0Font parent;
 

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=1687878&r1=1687877&r2=1687878&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 Sat Jun 27 00:18:21 2015
@@ -17,6 +17,7 @@
 package org.apache.pdfbox.pdmodel.font;
 
 import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
 import java.io.IOException;
 import java.util.HashMap;
@@ -24,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.FontBoxFont;
 import org.apache.fontbox.cff.CFFCIDFont;
 import org.apache.fontbox.cff.CFFFont;
 import org.apache.fontbox.cff.CFFParser;
@@ -31,7 +33,6 @@ import org.apache.fontbox.cff.CFFType1Fo
 import org.apache.fontbox.cff.Type2CharString;
 import org.apache.fontbox.util.BoundingBox;
 import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.io.IOUtils;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.util.Matrix;
@@ -47,7 +48,7 @@ public class PDCIDFontType0 extends PDCI
     private static final Log LOG = LogFactory.getLog(PDCIDFontType0.class);
 
     private final CFFCIDFont cidFont;  // Top DICT that uses CIDFont operators
-    private final CFFType1Font t1Font; // Top DICT that does not use CIDFont operators
+    private final FontBoxFont t1Font; // Top DICT that does not use CIDFont operators
     
     private final Map<Integer, Float> glyphHeights = new HashMap<Integer, Float>();
     private final boolean isEmbedded;
@@ -81,8 +82,8 @@ public class PDCIDFontType0 extends PDCI
         CFFFont cffFont = null;
         if (bytes != null && bytes.length > 0 && (bytes[0] & 0xff) == '%')
         {
-            // todo: PDFBOX-2642 contains a Type1 PFB font in a CIDFont, but we can't handle it yet
-            LOG.error("Unsupported: Type1 font instead of CFF in " + fd.getFontName());
+            // PDFBOX-2642 contains a corrupt PFB font instead of a CFF
+            LOG.warn("Found PFB but expected embedded CFF font " + fd.getFontName());
             fontIsDamaged = true;
         }
         else if (bytes != null)
@@ -110,53 +111,30 @@ public class PDCIDFontType0 extends PDCI
             else
             {
                 cidFont = null;
-                t1Font = (CFFType1Font)cffFont;
+                t1Font = cffFont;
             }
             isEmbedded = true;
             isDamaged = false;
         }
         else
         {
-            // substitute
-            CFFCIDFont cidSub = ExternalFonts.getCFFCIDFont(getBaseFont());
-            if (cidSub != null)
+            // find font or substitute
+            CIDFontMapping mapping = FontMapper.getCIDFont(getFontDescriptor(), getCIDSystemInfo());
+
+            if (mapping.isCIDFont())
             {
-                cidFont = cidSub;
+                cidFont = (CFFCIDFont)mapping.getFont().getCFF().getFont();
                 t1Font = null;
             }
             else
             {
-                COSDictionary cidSystemInfo = (COSDictionary)
-                        dict.getDictionaryObject(COSName.CIDSYSTEMINFO);
-
-                String registryOrdering = null;
-                if (cidSystemInfo != null)
-                {
-                    String registry = cidSystemInfo.getNameAsString(COSName.REGISTRY);
-                    String ordering = cidSystemInfo.getNameAsString(COSName.ORDERING);
-                    if (registry != null && ordering != null)
-                    {
-                        registryOrdering = registry + "-" + ordering;
-                    }
-                }
-
-                cidSub = ExternalFonts.getCFFCIDFontFallback(registryOrdering, getFontDescriptor());
-                cidFont = cidSub;
-                t1Font = null;
+                cidFont = null;
+                t1Font = mapping.getTrueTypeFont();
+            }
 
-                if (cidSub.getName().equals("AdobeBlank"))
-                {
-                    // this error often indicates that the user needs to install the Adobe Reader
-                    // Asian and Extended Language Pack
-                    if (!fontIsDamaged)
-                    {
-                        LOG.error("Missing CID-keyed font " + getBaseFont());
-                    }
-                }
-                else
-                {
-                    LOG.warn("Using fallback for CID-keyed font " + getBaseFont());
-                }
+            if (mapping.isFallback())
+            {
+                LOG.warn("Using fallback for CID-keyed font " + getBaseFont());
             }
             isEmbedded = false;
             isDamaged = fontIsDamaged;
@@ -164,7 +142,7 @@ public class PDCIDFontType0 extends PDCI
         fontMatrixTransform = getFontMatrix().createAffineTransform();
         fontMatrixTransform.scale(1000, 1000);
     }
-
+    
     @Override
     public Matrix getFontMatrix()
     {
@@ -177,7 +155,14 @@ public class PDCIDFontType0 extends PDCI
             }
             else
             {
-                numbers = t1Font.getFontMatrix();
+                try
+                {
+                    numbers = t1Font.getFontMatrix();
+                }
+                catch (IOException e)
+                {
+                    return new Matrix(0.001f, 0, 0, 0.001f, 0, 0);
+                }
             }
 
             if (numbers != null && numbers.size() == 6)
@@ -203,12 +188,19 @@ public class PDCIDFontType0 extends PDCI
         }
         else
         {
-            return t1Font.getFontBBox();
+            try
+            {
+                return t1Font.getFontBBox();
+            }
+            catch (IOException e)
+            {
+                return new BoundingBox();
+            }
         }
     }
 
     /**
-     * Returns the embedded CFF CIDFont.
+     * Returns the embedded CFF CIDFont, or null if the substitute is not a CFF font.
      */
     public CFFFont getCFFFont()
     {
@@ -216,14 +208,19 @@ public class PDCIDFontType0 extends PDCI
         {
             return cidFont;
         }
+        else if (t1Font instanceof CFFType1Font)
+        {
+            return (CFFType1Font)t1Font;
+        }
         else
         {
-            return t1Font;
+            return null;
         }
     }
 
     /**
-     * Returns the Type 2 charstring for the given CID.
+     * Returns the Type 2 charstring for the given CID, or null if the substituted font does not
+     * contain Type 2 charstrings.
      *
      * @param cid CID
      * @throws IOException if the charstring could not be read
@@ -234,9 +231,65 @@ public class PDCIDFontType0 extends PDCI
         {
             return cidFont.getType2CharString(cid);
         }
+        else if (t1Font instanceof CFFType1Font)
+        {
+            return ((CFFType1Font)t1Font).getType2CharString(cid);
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the name of the glyph with the given character code. This is done by looking up the
+     * code in the parent font's ToUnicode map and generating a glyph name from that.
+     */
+    private String getGlyphName(int code) throws IOException
+    {
+        String unicodes = parent.toUnicode(code);
+        if (unicodes == null)
+        {
+            return ".notdef";
+        }
+        return String.format("uni%04X", unicodes.codePointAt(0));
+    }
+
+    @Override
+    public GeneralPath getPath(int code) throws IOException
+    {
+        int cid = codeToCID(code);
+        Type2CharString charstring = getType2CharString(cid);
+        if (charstring != null)
+        {
+            return charstring.getPath();
+        }
+        else if (isEmbedded && t1Font instanceof CFFType1Font)
+        {
+            return ((CFFType1Font)t1Font).getType2CharString(cid).getPath();
+        }
         else
         {
-            return t1Font.getType2CharString(cid);
+            return t1Font.getPath(getGlyphName(code));
+        }
+    }
+
+    @Override
+    public boolean hasGlyph(int code) throws IOException
+    {
+        int cid = codeToCID(code);
+        Type2CharString charstring = getType2CharString(cid);
+        if (charstring != null)
+        {
+            return charstring.getGID() != 0;
+        }
+        else if (isEmbedded && t1Font instanceof CFFType1Font)
+        {
+            return ((CFFType1Font)t1Font).getType2CharString(cid).getGID() != 0;
+        }
+        else
+        {
+            return t1Font.hasGlyph(getGlyphName(code));
         }
     }
 
@@ -281,8 +334,20 @@ public class PDCIDFontType0 extends PDCI
     public float getWidthFromFont(int code) throws IOException
     {
         int cid = codeToCID(code);
-        int width = getType2CharString(cid).getWidth();
-
+        float width;
+        if (cidFont != null)
+        {
+            width = getType2CharString(cid).getWidth();
+        }
+        else if (isEmbedded && t1Font instanceof CFFType1Font)
+        {
+            width = ((CFFType1Font)t1Font).getType2CharString(cid).getWidth();
+        }
+        else
+        {
+            width = t1Font.getWidth(getGlyphName(code));
+        }
+        
         Point2D p = new Point2D.Float(width, 0);
         fontMatrixTransform.transform(p, p);
         return (float)p.getX();



Mime
View raw message