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 2014/08/17 22:02:20 UTC

svn commit: r1618516 [4/6] - in /pdfbox/no-awt: examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ fontbox/src/main/java/org/apache/fontbox/afm/ fontbox/src/main/java/org/apache/fontbox/cff/ fontbox/src/main/java/org/apache/fontbox/cff/charset/...

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/encoding/Type1Encoding.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/encoding/Type1Encoding.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/encoding/Type1Encoding.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/encoding/Type1Encoding.java Sun Aug 17 20:02:18 2014
@@ -16,28 +16,57 @@
  */
 package org.apache.pdfbox.encoding;
 
+import org.apache.fontbox.afm.CharMetric;
+import org.apache.fontbox.afm.FontMetrics;
 import org.apache.pdfbox.cos.COSBase;
 
+import java.util.Map;
+
 /**
- * This class represents an encoding which was read from a type1 font.
- * 
+ * An encoding for a Type 1 font.
  */
 public class Type1Encoding extends Encoding
 {
+    /**
+     * Creates an empty encoding of the given size (all elements map to .notdef).
+     */
     public Type1Encoding(int size)
     {
-        for (int i=1;i<size;i++)
+        for (int i = 1; i < size; i++)
         {
             addCharacterEncoding(i, NOTDEF);
         }
     }
 
     /**
-     * {@inheritDoc}
+     * Creates an encoding from the given AFM font metrics.
+     *
+     * @param fontMetrics AFM font metrics.
+     */
+    public Type1Encoding(FontMetrics fontMetrics)
+    {
+        for (CharMetric nextMetric : fontMetrics.getCharMetrics())
+        {
+            addCharacterEncoding(nextMetric.getCharacterCode(), nextMetric.getName());
+        }
+    }
+
+    /**
+     * Creates an encoding from the given FontBox encoding.
+     *
+     * @param encoding FontBox encoding
      */
+    public Type1Encoding(org.apache.fontbox.encoding.Encoding encoding)
+    {
+        for (Map.Entry<Integer, String> entry : encoding.getCodeToNameMap().entrySet())
+        {
+            addCharacterEncoding(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
     public COSBase getCOSObject()
     {
         return null;
     }
-
 }

Added: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java?rev=1618516&view=auto
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java (added)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ExternalFonts.java Sun Aug 17 20:02:18 2014
@@ -0,0 +1,309 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.fontbox.cff.CFFCIDFont;
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFType1Font;
+import org.apache.fontbox.ttf.Type1Equivalent;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.fontbox.type1.Type1Font;
+
+/**
+ * External font service, locates non-embedded fonts via a pluggable FontProvider.
+ *
+ * @author John Hewson
+ */
+public final class ExternalFonts
+{
+    private ExternalFonts() {}
+
+    private static FontProvider fontProvider;
+
+    /**
+     * Sets the font service provider.
+     */
+    public static void setProvider(FontProvider fontProvider)
+    {
+        ExternalFonts.fontProvider = fontProvider;
+    }
+
+    /**
+     * Gets the font service provider. Defaults to using FileSystemFontProvider.
+     */
+    private static FontProvider getProvider()
+    {
+        if (fontProvider == null)
+        {
+            fontProvider = new FileSystemFontProvider();
+        }
+        return fontProvider;
+    }
+
+    // todo: we could just rely on the system to provide Times rather than ship our own
+    /** Fallback font, used as as a last resort */
+    private static TrueTypeFont fallbackFont;
+    static
+    {
+        try
+        {
+            String name = "org/apache/pdfbox/resources/ttf/LiberationSans-Regular.ttf";
+            TTFParser ttfParser = new TTFParser();
+            InputStream fontStream = org.apache.fontbox.util.ResourceLoader.loadResource(name);
+            if (fontStream == null)
+            {
+                throw new IOException("Error loading resource: " + name);
+            }
+            fallbackFont = ttfParser.parseTTF(fontStream);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Map of PostScript name substitutes, in priority order. */
+    private final static Map<String, List<String>> substitutes = new HashMap<String, List<String>>();
+    static
+    {
+        // well-known substitutes commonly found on end-user systems
+        substitutes.put("Courier",
+                Arrays.asList("CourierNew", "CourierNewPSMT"));
+        substitutes.put("Courier-Bold",
+                Arrays.asList("CourierNewPS-BoldMT", "CourierNew-Bold"));
+        substitutes.put("Courier-Oblique",
+                Arrays.asList("CourierNewPS-ItalicMT","CourierNew-Italic"));
+        substitutes.put("Helvetica",
+                Arrays.asList("ArialMT", "Arial"));
+        substitutes.put("Helvetica-Bold",
+                Arrays.asList("Arial-BoldMT", "Arial-Bold"));
+        substitutes.put("Helvetica-Oblique",
+                Arrays.asList("Arial-ItalicMT", "Arial-Italic", "Helvetica-Italic"));
+        substitutes.put("Helvetica-BoldOblique",
+                Arrays.asList("Helvetica-BoldItalic"));
+        substitutes.put("Times-Roman",
+                Arrays.asList("TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS"));
+        substitutes.put("Times-Bold",
+                Arrays.asList("TimesNewRomanPS-BoldMT", "TimesNewRomanPS-Bold",
+                              "TimesNewRoman-Bold"));
+        substitutes.put("Times-Italic",
+                Arrays.asList("TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-Italic",
+                              "TimesNewRoman-Italic"));
+        substitutes.put("Times-BoldItalic",
+                Arrays.asList("TimesNewRomanPS-BoldItalicMT", "TimesNewRomanPS-BoldItalic",
+                             "TimesNewRoman-BoldItalic"));
+        substitutes.put("Symbol",Arrays.asList("SymbolMT"));
+        substitutes.put("ZapfDingbats", Arrays.asList("ZapfDingbatsITC"));
+
+        // the Adobe Supplement to the ISO 32000 specifies some alternative names for some
+        // of the standard 14 fonts, so we map these to our fallbacks above
+        substitutes.put("CourierCourierNew", substitutes.get("Courier"));
+        substitutes.put("CourierNew,Italic", substitutes.get("Courier-Oblique"));
+        substitutes.put("CourierNew,Bold", substitutes.get("Courier-Bold"));
+        substitutes.put("CourierNew,BoldItalic", substitutes.get("Courier-BoldOblique"));
+        substitutes.put("Arial", substitutes.get("Helvetica"));
+        substitutes.put("Arial,Italic", substitutes.get("Helvetica-Oblique"));
+        substitutes.put("Arial,Bold", substitutes.get("Helvetica-Bold"));
+        substitutes.put("Arial,BoldItalic", substitutes.get("Helvetica-BoldOblique"));
+        substitutes.put("TimesNewRoman", substitutes.get("Times-Roman"));
+        substitutes.put("TimesNewRoman,Italic", substitutes.get("Times-Italic"));
+        substitutes.put("TimesNewRoman,Bold", substitutes.get("Times-Bold"));
+        substitutes.put("TimesNewRoman,BoldItalic", substitutes.get("Times-BoldItalic"));
+    }
+
+    /**
+     * Adds a top-priority substitute for the given font.
+     *
+     * @param match PostScript name of the font to match
+     * @param replace PostScript name of the font to use as a replacement
+     */
+    public static void addSubstitute(String match, String replace)
+    {
+        if (!substitutes.containsKey(match))
+        {
+            substitutes.put(match, new ArrayList<String>());
+        }
+        substitutes.get(match).add(replace);
+    }
+
+    /**
+     * Returns the substitutes for a given font.
+     */
+    private static List<String> getSubstitutes(String postScriptName)
+    {
+        List<String> subs = substitutes.get(postScriptName);
+        if (subs != null)
+        {
+            return subs;
+        }
+        else
+        {
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * Returns the fallback font, used for rendering when no other fonts are available.
+     */
+    public static TrueTypeFont getFallbackFont()
+    {
+        // todo: add FontDescriptor to the parameters for this method for "smart fallback" to
+        //       standard 14 fonts via the FontProvider
+        return fallbackFont;
+    }
+
+    /**
+     * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null.
+     *
+     * @param postScriptName PostScript font name
+     */
+    public static TrueTypeFont getTrueTypeFont(String postScriptName)
+    {
+        // first ask the font provider for the font
+        TrueTypeFont ttf = getProvider().getTrueTypeFont(postScriptName);
+        if (ttf == null)
+        {
+            // then try substitutes
+            for (String substituteName : getSubstitutes(postScriptName))
+            {
+                ttf = getProvider().getTrueTypeFont(substituteName);
+                if (ttf != null)
+                {
+                    break;
+                }
+            }
+        }
+        return ttf;
+    }
+
+    /**
+     * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null.
+     *
+     * @param postScriptName PostScript font name
+     */
+    public static Type1Font getType1Font(String postScriptName)
+    {
+        // first ask the font provider for the font
+        Type1Font t1 = getProvider().getType1Font(postScriptName);
+        if (t1 == null)
+        {
+            // then try substitutes
+            for (String substituteName : getSubstitutes(postScriptName))
+            {
+                t1 = getProvider().getType1Font(substituteName);
+                if (t1 != null)
+                {
+                    break;
+                }
+            }
+        }
+        return t1;
+    }
+
+    /**
+     * Finds a CFF Type 1 font with the given PostScript name, or a suitable substitute, or null.
+     *
+     * @param postScriptName PostScript font name
+     */
+    public static CFFType1Font getCFFType1Font(String postScriptName)
+    {
+        CFFFont cff = getCFFFont(postScriptName);
+        if (cff instanceof CFFType1Font)
+        {
+            return (CFFType1Font)cff;
+        }
+        return null;
+    }
+
+    /**
+     * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null.
+     *
+     * @param postScriptName PostScript font name
+     */
+    public static CFFCIDFont getCFFCIDFont(String postScriptName)
+    {
+        CFFFont cff = getCFFFont(postScriptName);
+        if (cff instanceof CFFCIDFont)
+        {
+            return (CFFCIDFont)cff;
+        }
+        return null;
+    }
+
+    /**
+     * Finds a CFF font with the given PostScript name, or a suitable substitute, or null.
+     *
+     * @param postScriptName PostScript font name
+     */
+    private static CFFFont getCFFFont(String postScriptName)
+    {
+        // first ask the font provider for the font
+        CFFFont cff = getProvider().getCFFFont(postScriptName);
+        if (cff == null)
+        {
+            // then try substitutes
+            for (String substituteName : getSubstitutes(postScriptName))
+            {
+                cff = getProvider().getCFFFont(substituteName);
+                if (cff != null)
+                {
+                    break;
+                }
+            }
+        }
+        return cff;
+    }
+
+    /**
+     * 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
+     */
+    public static Type1Equivalent getType1EquivalentFont(String postScriptName)
+    {
+        Type1Font t1 = getType1Font(postScriptName);
+        if (t1 != null)
+        {
+            return t1;
+        }
+
+        CFFType1Font cff = getCFFType1Font(postScriptName);
+        if (cff != null)
+        {
+            return cff;
+        }
+
+        TrueTypeFont ttf = getTrueTypeFont(postScriptName);
+        if (ttf != null)
+        {
+            return ttf;
+        }
+
+        return null;
+    }
+}

Added: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java?rev=1618516&view=auto
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java (added)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java Sun Aug 17 20:02:18 2014
@@ -0,0 +1,264 @@
+/*
+ * 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.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFParser;
+import org.apache.fontbox.ttf.NamingTable;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.fontbox.type1.Type1Font;
+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.
+ *
+ * @author John Hewson
+ */
+final class FileSystemFontProvider implements FontProvider
+{
+    private static final Log LOG = LogFactory.getLog(FileSystemFontProvider.class);
+
+    // cache of font files on the system
+    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
+    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>();
+
+    /**
+     * Constructor.
+     */
+    FileSystemFontProvider()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Will search the local system for fonts");
+        }
+
+        int count = 0;
+        FontFileFinder fontFileFinder = new FontFileFinder();
+        List<URI> fonts = fontFileFinder.find();
+        for (URI font : fonts)
+        {
+            count++;
+            File fontFile = new File(font);
+            try
+            {
+                if (fontFile.getPath().toLowerCase().endsWith(".ttf") ||
+                    fontFile.getPath().toLowerCase().endsWith(".otf"))
+                {
+                    addOpenTypeFont(fontFile);
+                }
+                else if (fontFile.getPath().toLowerCase().endsWith(".pfb"))
+                {
+                    addType1Font(fontFile);
+                }
+            }
+            catch (IOException e)
+            {
+                LOG.error("Error parsing font " + fontFile.getPath(), e);
+            }
+        }
+
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Found " + count + " fonts on the local system");
+        }
+    }
+
+    /**
+     * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font is not cached.
+     */
+    private void addOpenTypeFont(File otfFile) throws IOException
+    {
+        TTFParser ttfParser = new TTFParser(false, true);
+        TrueTypeFont ttf = ttfParser.parseTTF(otfFile);
+        try
+        {
+            // check for 'name' table
+            NamingTable nameTable = ttf.getNaming();
+            if (nameTable == null)
+            {
+                throw new IOException("Missing 'name' table");
+            }
+
+            // read PostScript name, if any
+            if (nameTable.getPostScriptName() != null)
+            {
+                String psName = nameTable.getPostScriptName();
+
+                String format;
+                if (ttf.getTableMap().get("CFF ") != null)
+                {
+                    format = "OTF";
+                    cffFontFiles.put(psName, otfFile);
+                }
+                else
+                {
+                    format = "TTF";
+                    ttfFontFiles.put(psName, otfFile);
+                }
+
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug(format +": '" + psName + "' / '" + nameTable.getFontFamily() +
+                            "' / '" + nameTable.getFontSubFamily() + "'");
+                }
+            }
+            else
+            {
+                throw new IOException("Missing 'name' entry for PostScript name");
+            }
+        }
+        finally
+        {
+            ttf.close();
+        }
+    }
+
+    /**
+     * Adds a Type 1 font to the file cache. To reduce memory, the parsed font is not cached.
+     */
+    private void addType1Font(File pfbFile) throws IOException
+    {
+        InputStream input = new FileInputStream(pfbFile);
+        try
+        {
+            Type1Font type1 = Type1Font.createWithPFB(input);
+
+            String psName = type1.getFontName();
+            type1FontFiles.put(psName, pfbFile);
+
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("PFB: '" + psName + "' / '" + type1.getFamilyName() + "' / '" +
+                        type1.getWeight() + "'");
+            }
+        }
+        finally
+        {
+            input.close();
+        }
+    }
+
+    @Override
+    public TrueTypeFont getTrueTypeFont(String postScriptName)
+    {
+        TrueTypeFont ttf = ttfFonts.get(postScriptName);
+        if (ttf != null)
+        {
+            return ttf;
+        }
+
+        File file = ttfFontFiles.get(postScriptName);
+        if (file != null)
+        {
+            TTFParser ttfParser = new TTFParser(false, true);
+            try
+            {
+                ttf = ttfParser.parseTTF(file);
+                ttfFonts.put(postScriptName, ttf);
+                return ttf;
+            }
+            catch (IOException e)
+            {
+                LOG.error("Could not load font file: " + file);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public CFFFont getCFFFont(String postScriptName)
+    {
+        CFFFont cff = cffFonts.get(postScriptName);
+        if (cff != null)
+        {
+            return cff;
+        }
+
+        File file = cffFontFiles.get(postScriptName);
+        if (file != null)
+        {
+            InputStream input = null;
+            try
+            {
+                input = new FileInputStream(file);
+                byte[] bytes = IOUtils.toByteArray(input);
+                CFFParser cffParser = new CFFParser();
+                cff = cffParser.parse(bytes).get(0);
+                cffFonts.put(postScriptName, cff);
+            }
+            catch (IOException e)
+            {
+                LOG.error("Could not load font file: " + file);
+            }
+            finally
+            {
+                IOUtils.closeQuietly(input);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Type1Font getType1Font(String postScriptName)
+    {
+        Type1Font type1 = type1Fonts.get(postScriptName);
+        if (type1 != null)
+        {
+            return type1;
+        }
+
+        File file = type1FontFiles.get(postScriptName);
+        if (file != null)
+        {
+            InputStream input = null;
+            try
+            {
+                input = new FileInputStream(file);
+                type1 = Type1Font.createWithPFB(input);
+                type1Fonts.put(postScriptName, type1);
+            }
+            catch (IOException e)
+            {
+                LOG.error("Could not load font file: " + file);
+            }
+            finally
+            {
+                IOUtils.closeQuietly(input);
+            }
+        }
+        return null;
+    }
+}

Added: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java?rev=1618516&view=auto
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java (added)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontProvider.java Sun Aug 17 20:02:18 2014
@@ -0,0 +1,53 @@
+/*
+ * 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.cff.CFFFont;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.fontbox.type1.Type1Font;
+
+/**
+ * External font service provider interface.
+ *
+ * @author John Hewson
+ */
+public interface 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 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 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 Type1Font getType1Font(String postScriptName);
+}

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java Sun Aug 17 20:02:18 2014
@@ -55,6 +55,7 @@ public abstract class PDCIDFont extends 
         super(fontDictionary);
         this.parent = parent;
         extractWidths();
+        determineEncoding();
     }
 
     /**
@@ -108,10 +109,9 @@ public abstract class PDCIDFont extends 
      * @param offset The offset into the array.
      * @param length The length of the data.
      * @return The width is in 1000 unit of text space, ie 333 or 777
-     * @throws IOException If an error occurs while parsing.
      */
     @Override
-    public float getFontWidth(byte[] c, int offset, int length) throws IOException
+    public float getFontWidth(byte[] c, int offset, int length)
     {
         float retval = getDefaultWidth();
         int code = getCodeFromArray(c, offset, length);
@@ -174,11 +174,9 @@ public abstract class PDCIDFont extends 
      * @param length The length of the data.
      *
      * @return The width is in 1000 unit of text space, ie 333 or 777
-     *
-     * @throws IOException If an error occurs while parsing.
      */
     @Override
-    public float getFontHeight(byte[] c, int offset, int length) throws IOException
+    public float getFontHeight(byte[] c, int offset, int length)
     {
         float retval = 0;
         PDFontDescriptor desc = getFontDescriptor();
@@ -212,11 +210,9 @@ public abstract class PDCIDFont extends 
      * This will get the average font width for all characters.
      *
      * @return The width is in 1000 unit of text space, ie 333 or 777
-     *
-     * @throws IOException If an error occurs while parsing.
      */
     @Override
-    public float getAverageFontWidth() throws IOException
+    public float getAverageFontWidth()
     {
         float totalWidths = 0.0f;
         float characterCount = 0.0f;
@@ -331,7 +327,7 @@ public abstract class PDCIDFont extends 
                 }
                 else
                 {
-                    LOG.debug("'" + cidSystemInfo + "' isn't a predefined CMap, most " +
+                    LOG.warn("'" + cidSystemInfo + "' isn't a predefined CMap, most " +
                               "likely it's embedded in the pdf itself.");
                 }
             }

Copied: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java (from r1615712, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0Font.java)
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java?p2=pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java&p1=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0Font.java&r1=1615712&r2=1618516&rev=1618516&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0Font.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java Sun Aug 17 20:02:18 2014
@@ -17,66 +17,287 @@
 package org.apache.pdfbox.pdmodel.font;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+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.cff.CFFParser;
+import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSFloat;
+import org.apache.pdfbox.io.IOUtils;
+import org.apache.pdfbox.pdmodel.common.PDMatrix;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
 
 /**
- * A Type0 CIDFont (CFF).
+ * Type 0 CIDFont (CFF).
  * 
  * @author Ben Litchfield
+ * @author John Hewson
  */
-public class PDCIDFontType0Font extends PDCIDFont
+public class PDCIDFontType0 extends PDCIDFont
 {
-    private static final Log LOG = LogFactory.getLog(PDCIDFontType0Font.class);
+    private static final Log LOG = LogFactory.getLog(PDCIDFontType0.class);
+    private static final byte[] SPACE_BYTES = { (byte) 32 };
 
-    private PDType1CFont type1CFont;
+    private CFFCIDFont cffFont = null;
+    private String fontname = null;
+    private final Map<Integer, Float> glyphWidths = new HashMap<Integer, Float>();
+    private final Map<Integer, Float> glyphHeights = new HashMap<Integer, Float>();
+    private Float avgWidth = null;
+    private PDRectangle fontBBox = null;
 
     /**
      * Constructor.
      * 
      * @param fontDictionary The font dictionary according to the PDF specification.
      */
-    public PDCIDFontType0Font(COSDictionary fontDictionary, PDType0Font parent)
+    public PDCIDFontType0(COSDictionary fontDictionary, PDType0Font parent) throws IOException
     {
         super(fontDictionary, parent);
+
         PDFontDescriptor fd = getFontDescriptor();
-        if (fd instanceof PDFontDescriptorDictionary)
+        byte[] bytes = null;
+        if (fd != null && fd instanceof PDFontDescriptorDictionary) // <-- todo: must be true
         {
-            PDFontDescriptorDictionary fdd = (PDFontDescriptorDictionary) fd;
-            if (fdd.getFontFile3() != null)
+            PDStream ff3Stream = ((PDFontDescriptorDictionary) fd).getFontFile3();
+            if (ff3Stream != null)
             {
-                try
-                {
-                    type1CFont = new PDType1CFont(dict);
-                }
-                catch (IOException exception)
-                {
-                    LOG.error("Can't create the embedded CFF-font", exception);
-                }
+                bytes = IOUtils.toByteArray(ff3Stream.createInputStream());
+            }
+        }
+
+        if (bytes != null)
+        {
+            // embedded
+            CFFParser cffParser = new CFFParser();
+            cffFont = (CFFCIDFont)cffParser.parse(bytes).get(0);
+        }
+        else
+        {
+            // substitute
+            cffFont = ExternalFonts.getCFFCIDFont(getBaseFont());
+
+            if (cffFont == null)
+            {
+                // todo: log message + substitute? But what would we substitute with?
+                throw new UnsupportedOperationException("not implemented: missing CFF");
             }
         }
+
+        // cache the font name
+        fontname = cffFont.getName();
     }
 
     /**
-     * Returns the embedded Type1CFont.
-     * 
-     * @return the Type1C font
+     * Returns the embedded CFF CIDFont.
+     */
+    public CFFCIDFont getCFFCIDFont()
+    {
+        return cffFont;
+    }
+
+    @Override
+    public String encode(byte[] bytes, int offset, int length) throws IOException
+    {
+        // a CIDFont does not contain an encoding, instead the CMap defines this mapping
+        int code = getCodeFromArray(bytes, offset, length);
+        String character = getCMap().lookupCID(code);
+
+        if (character == null)
+        {
+            LOG.error("No character for code " + (bytes[offset] & 0xff) + " in " + fontname);
+            return null;
+        }
+        return character;
+    }
+
+    @Override
+    public int encodeToCID(byte[] bytes, int offset, int length)
+    {
+        if (length > 2)
+        {
+            return -1;
+        }
+        int code = bytes[offset] & 0xff;
+        if (length == 2)
+        {
+            code = code * 256 + bytes[offset + 1] & 0xff;
+        }
+        return code;
+    }
+
+    @Override
+    public float getFontWidth(byte[] bytes, int offset, int length)
+    {
+        int cid = codeToCID(bytes, offset, length);
+        if (cid == 0 && !Arrays.equals(SPACE_BYTES, bytes))
+        {
+            LOG.error("No name for code " + (bytes[offset] & 0xff) + " in " + fontname);
+            return 0;
+        }
+
+        Float width = glyphWidths.get(cid);
+        if (width == null)
+        {
+            width = getCharacterWidth(cid);
+            glyphWidths.put(cid, width);
+        }
+
+        return width;
+    }
+
+    @Override
+    public float getFontHeight(byte[] bytes, int offset, int length)
+    {
+        int cid = codeToCID(bytes, offset, length);
+        if (cid == 0)
+        {
+            LOG.error("No CID for code " + (bytes[offset] & 0xff) + " in " + fontname);
+            return 0;
+        }
+
+        float height = 0;
+        if (!glyphHeights.containsKey(cid))
+        {
+            height = getCharacterHeight(cid);
+            glyphHeights.put(cid, height);
+        }
+        return height;
+    }
+
+    // helper
+    private int codeToCID(byte[] bytes, int offset, int length)
+    {
+        return getCMap().lookupCID(bytes, offset, length);
+    }
+
+    /**
+     * Returns the CID for the given character code. If not found then CID 0 is returned.
+     *
+     * @param code character code
+     * @return CID
      */
-    public PDType1CFont getType1CFont()
+    public int codeToCID(int code)
+    {
+        //int length = getCMap().hasTwoByteMappings() ? 2 : 1; // todo: HACK: see PDFStreamEngine
+        int length = 2; // todo: HACK always use 2-byte mappings
+
+        byte[] bytes;
+        // todo: actually codes may be variable length (1 to 4 bytes)
+        if (length == 1)
+        {
+            bytes = new byte[] { (byte)(code & 0xff) };
+        }
+        else
+        {
+            bytes = new byte[] { (byte)(code >> 8 & 0xff), (byte)(code & 0xff) };
+        }
+        return getCMap().lookupCID(bytes, 0, length);
+    }
+
+    @Override
+    public float getStringWidth(String string) throws IOException
+    {
+        // todo: CMap currently has no methods which can do this correctly
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
+    public float getAverageFontWidth()
+    {
+        if (avgWidth == null)
+        {
+            avgWidth = getAverageCharacterWidth();
+        }
+        return avgWidth;
+    }
+
+    @Override
+    public PDRectangle getFontBoundingBox() throws IOException
+    {
+        if (fontBBox == null)
+        {
+            fontBBox = new PDRectangle(cffFont.getFontBBox());
+        }
+        return fontBBox;
+    }
+
+    @Override
+    public PDMatrix getFontMatrix()
     {
-        return type1CFont;
+        if (fontMatrix == null)
+        {
+            List<Number> numbers = cffFont.getFontMatrix();
+            if (numbers != null && numbers.size() == 6)
+            {
+                COSArray array = new COSArray();
+                for (Number number : numbers)
+                {
+                    array.add(new COSFloat(number.floatValue()));
+                }
+                fontMatrix = new PDMatrix(array);
+            }
+            else
+            {
+                // todo: the font should always have a Matrix, so why fallback?
+                super.getFontMatrix();
+            }
+        }
+        return fontMatrix;
     }
-    
+
+    // todo: this is a replacement for FontMetrics method
+    private float getCharacterWidth(int cid)
+    {
+        try
+        {
+            return cffFont.getType2CharString(cid).getWidth();
+        }
+        catch (IOException e)
+        {
+            // todo: HACK
+            LOG.error(e);
+            return 0;
+        }
+    }
+
+    // todo: this is a replacement for FontMetrics method
+    // todo: but in FontMetrics this method actually gets the advance-y for vertical mode
+    private float getCharacterHeight(int cid)
+    {
+        try
+        {
+            return (float)cffFont.getType2CharString(cid).getBounds().getHeight();
+        }
+        catch (IOException e)
+        {
+            // todo: HACK
+            LOG.error(e);
+            return 0;
+        }
+    }
+
+    // todo: this is a replacement for FontMetrics method
+    private float getAverageCharacterWidth()
+    {
+        // todo: not implemented, highly suspect
+        return 500;
+    }
+
     @Override
     public void clear()
     {
         super.clear();
-        if (type1CFont != null)
+        if (cffFont != null)
         {
-            type1CFont.clear();
-            type1CFont = null;
+            //cffFont.clear();
+            cffFont = null;
         }
     }
 }

Copied: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (from r1615712, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Font.java)
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?p2=pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java&p1=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Font.java&r1=1615712&r2=1618516&rev=1618516&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Font.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Sun Aug 17 20:02:18 2014
@@ -31,14 +31,15 @@ import org.apache.pdfbox.io.IOUtils;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 
 /**
- * A Type2 CIDFont (TrueType).
+ * Type 2 CIDFont (TrueType).
  * 
  * @author Ben Litchfield
  */
-public class PDCIDFontType2Font extends PDCIDFont
+public class PDCIDFontType2 extends PDCIDFont
 {
-    private static final Log LOG = LogFactory.getLog(PDCIDFontType2Font.class);
+    private static final Log LOG = LogFactory.getLog(PDCIDFontType2.class);
 
+    private final TrueTypeFont ttf;
     private Boolean hasCIDToGIDMap = null;
     private Boolean hasIdentityCIDToGIDMap = null;
     private int[] cid2gid = null;
@@ -48,9 +49,34 @@ public class PDCIDFontType2Font extends 
      * 
      * @param fontDictionary The font dictionary according to the PDF specification.
      */
-    public PDCIDFontType2Font(COSDictionary fontDictionary, PDType0Font parent)
+    public PDCIDFontType2(COSDictionary fontDictionary, PDType0Font parent) throws IOException
     {
         super(fontDictionary, parent);
+
+        PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary) getFontDescriptor();
+        PDStream ff2Stream = fd.getFontFile2();
+
+        if (ff2Stream != null)
+        {
+            // embedded
+            TTFParser ttfParser = new TTFParser(true);
+            ttf = ttfParser.parseTTF(ff2Stream.createInputStream());
+        }
+        else
+        {
+            // substitute
+            TrueTypeFont ttfSubstitute = ExternalFonts.getTrueTypeFont(getBaseFont());
+            if (ttfSubstitute != null)
+            {
+                ttf = ttfSubstitute;
+            }
+            else
+            {
+                // fallback
+                LOG.warn("Using fallback font for " + getBaseFont());
+                ttf = ExternalFonts.getFallbackFont();
+            }
+        }
     }
 
     /**
@@ -124,23 +150,6 @@ public class PDCIDFontType2Font extends 
         }
     }
 
-    /**
-     * Returns the CID2GID mapping if present.
-     * 
-     * @return the CID2GID mapping
-     */
-    public int[] getCID2GID()
-    {
-        if (hasCIDToGIDMap())
-        {
-            if (cid2gid == null)
-            {
-                readCIDToGIDMapping();
-            }
-        }
-        return cid2gid;
-    }
-
     private void readCIDToGIDMapping()
     {
         COSBase map = dict.getDictionaryObject(COSName.CID_TO_GID_MAP);
@@ -169,26 +178,15 @@ public class PDCIDFontType2Font extends 
     }
 
     /**
-     * Returns the embedded true type font.
-     *
-     * @return the true type font
-     * @throws IOException exception if something went wrong
+     * Returns the embedded or substituted TrueType font.
      */
-    public TrueTypeFont getTTFFont() throws IOException
+    public TrueTypeFont getTrueTypeFont()
     {
-        PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary) getFontDescriptor();
-        PDStream ff2Stream = fd.getFontFile2();
-        TrueTypeFont trueTypeFont = null;
-        if (ff2Stream != null)
-        {
-            TTFParser ttfParser = new TTFParser(true);
-            trueTypeFont = ttfParser.parseTTF(ff2Stream.createInputStream());
-        }
-        return trueTypeFont;
+        return ttf;
     }
 
     @Override
-    public float getFontWidth(byte[] c, int offset, int length) throws IOException
+    public float getFontWidth(byte[] c, int offset, int length)
     {
         // a suitable mapping is needed to address the correct width value
         int code = getCodeFromArray(c, offset, length);

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java Sun Aug 17 20:02:18 2014
@@ -26,7 +26,6 @@ import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.fontbox.afm.FontMetric;
 import org.apache.fontbox.cmap.CMap;
 import org.apache.fontbox.cmap.CMapParser;
 import org.apache.pdfbox.cos.COSArray;
@@ -172,7 +171,6 @@ public abstract class PDFont implements 
     protected PDFont(COSDictionary fontDictionary)
     {
         dict = fontDictionary;
-        determineEncoding();
     }
 
     /**
@@ -189,14 +187,7 @@ public abstract class PDFont implements 
             {
                 fontDescriptor = new PDFontDescriptorDictionary(fd);
             }
-            else
-            {
-                FontMetric afm = getAFM();
-                if (afm != null)
-                {
-                    fontDescriptor = new PDFontDescriptorAFM(afm);
-                }
-            }
+            // todo: NOTE: null return value here if fine, because we override this method
         }
         return fontDescriptor;
     }
@@ -220,7 +211,7 @@ public abstract class PDFont implements 
                 }
                 catch (IOException exception)
                 {
-                    LOG.debug("Debug: Could not find encoding for " + encodingName);
+                    LOG.warn("Debug: Could not find encoding for " + encodingName);
                 }
             }
             else if (encoding instanceof COSDictionary)
@@ -301,20 +292,14 @@ public abstract class PDFont implements 
      * @param offset The offset into the array.
      * @param length The length of the data.
      * @return The width is in 1000 unit of text space, ie 333 or 777
-     * @throws IOException If an error occurs while parsing.
      */
-    public float getFontWidth(byte[] c, int offset, int length) throws IOException
+    public float getFontWidth(byte[] c, int offset, int length)
     {
         int code = getCodeFromArray(c, offset, length);
         Float fontWidth = fontSizes.get(code);
         if (fontWidth == null)
         {
             fontWidth = getFontWidth(code);
-            if (fontWidth <= 0)
-            {
-                // TODO should this be in PDType1Font??
-                fontWidth = getFontWidthFromAFMFile(code);
-            }
             fontSizes.put(code, fontWidth);
         }
         return fontWidth;
@@ -327,61 +312,46 @@ public abstract class PDFont implements 
      * @param offset The offset into the array.
      * @param length The length of the data.
      * @return The height is in 1000 unit of text space, ie 333 or 777
-     * @throws IOException If an error occurs while parsing.
      */
-    public float getFontHeight(byte[] c, int offset, int length) throws IOException
+    public float getFontHeight(byte[] c, int offset, int length)
     {
         // maybe there is already a precalculated value
-        if (avgFontHeight > 0)
+        PDFontDescriptor desc = getFontDescriptor();
+        if (desc != null)
         {
-            return avgFontHeight;
-        }
-        float retval = 0;
-        FontMetric metric = getAFM();
-        if (metric != null)
-        {
-            int code = getCodeFromArray(c, offset, length);
-            Encoding encoding = getFontEncoding();
-            String characterName = encoding.getName(code);
-            retval = metric.getCharacterHeight(characterName);
-        }
-        else
-        {
-            PDFontDescriptor desc = getFontDescriptor();
-            if (desc != null)
+            // the following values are all more or less accurate at least all are average
+            // values. Maybe we'll find another way to get those value for every single glyph
+            // in the future if needed
+            PDRectangle fontBBox = desc.getFontBoundingBox();
+            float retval = 0;
+            if (fontBBox != null)
             {
-                // the following values are all more or less accurate at least all are average
-                // values. Maybe we'll find another way to get those value for every single glyph
-                // in the future if needed
-                PDRectangle fontBBox = desc.getFontBoundingBox();
-                if (fontBBox != null)
-                {
-                    retval = fontBBox.getHeight() / 2;
-                }
-                if (retval == 0)
-                {
-                    retval = desc.getCapHeight();
-                }
-                if (retval == 0)
-                {
-                    retval = desc.getAscent();
-                }
-                if (retval == 0)
+                retval = fontBBox.getHeight() / 2;
+            }
+            if (retval == 0)
+            {
+                retval = desc.getCapHeight();
+            }
+            if (retval == 0)
+            {
+                retval = desc.getAscent();
+            }
+            if (retval == 0)
+            {
+                retval = desc.getXHeight();
+                if (retval > 0)
                 {
-                    retval = desc.getXHeight();
-                    if (retval > 0)
-                    {
-                        retval -= desc.getDescent();
-                    }
+                    retval -= desc.getDescent();
                 }
-                avgFontHeight = retval;
             }
+            avgFontHeight = retval;
+            return retval;
         }
-        return retval;
+        return 0;
     }
 
     /**
-     * This will get the width of this string for this font.
+     * Returns the width of the given Unicode string.
      * 
      * @param string The string to get the width of.
      * @return The width of the string in 1000 units of text space, ie 333 567...
@@ -402,9 +372,9 @@ public abstract class PDFont implements 
      * This will get the average font width for all characters.
      * 
      * @return The width is in 1000 unit of text space, ie 333 or 777
-     * @throws IOException If an error occurs while parsing.
      */
-    public float getAverageFontWidth() throws IOException
+    // todo: this method is highly suspicious, the average glyph width is not usually a good metric
+    public float getAverageFontWidth()
     {
         float average;
         if (avgFontWidth != 0.0f)
@@ -435,7 +405,7 @@ public abstract class PDFont implements 
             }
             else
             {
-                average = getAverageFontWidthFromAFMFile();
+                average = 0;
             }
             avgFontWidth = average;
         }
@@ -462,52 +432,6 @@ public abstract class PDFont implements 
     }
 
     /**
-     * This will attempt to get the font width from an AFM file.
-     * 
-     * @param code The character code we are trying to get.
-     * @return The font width from the AFM file.
-     * @throws IOException if we cannot find the width.
-     */
-    private float getFontWidthFromAFMFile(int code) throws IOException
-    {
-        float retval = 0;
-        FontMetric metric = getAFM();
-        if (metric != null)
-        {
-            String characterName = fontEncoding.getName(code);
-            retval = metric.getCharacterWidth(characterName);
-        }
-        return retval;
-    }
-
-    /**
-     * This will attempt to get the average font width from an AFM file.
-     * 
-     * @return The average font width from the AFM file.
-     * @throws IOException if we cannot find the width.
-     */
-    private float getAverageFontWidthFromAFMFile() throws IOException
-    {
-        float retval = 0;
-        FontMetric metric = getAFM();
-        if (metric != null)
-        {
-            retval = metric.getAverageCharacterWidth();
-        }
-        return retval;
-    }
-
-    /**
-     * This will get an AFM object if one exists.
-     * 
-     * @return The afm object from the name.
-     */
-    protected FontMetric getAFM()
-    {
-        return null;
-    }
-
-    /**
      * Encode the given value using the CMap of the font.
      * 
      * @param code the code to encode.
@@ -538,7 +462,7 @@ public abstract class PDFont implements 
     }
 
     /**
-     * This will perform the encoding of a character if needed.
+     * Returns the Unicode character(s) for a given character code.
      * 
      * @param c The character to encode.
      * @param offset The offset into the array to get the data
@@ -871,7 +795,7 @@ public abstract class PDFont implements 
 
     /**
      * Returns the toUnicode mapping if present.
-     * 
+     *
      * @return the CMap representing the toUnicode mapping
      */
     public CMap getToUnicodeCMap()
@@ -881,7 +805,7 @@ public abstract class PDFont implements 
 
     /**
      * Returns the CMap if present.
-     * 
+     *
      * @return the CMap representing the character encoding
      */
     public CMap getCMap()
@@ -907,4 +831,10 @@ public abstract class PDFont implements 
     {
         return this.getCOSObject().hashCode();
     }
+
+    @Override
+    public String toString()
+    {
+        return getClass().getSimpleName() + " " + getBaseFont();
+    }
 }

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorAFM.java Sun Aug 17 20:02:18 2014
@@ -17,30 +17,26 @@
 package org.apache.pdfbox.pdmodel.font;
 
 import java.io.IOException;
-
-import org.apache.fontbox.afm.FontMetric;
-
+import org.apache.fontbox.afm.FontMetrics;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
-
 import org.apache.fontbox.util.BoundingBox;
 
 /**
  * This class represents the font descriptor when the font information
  * is coming from an AFM file.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.3 $
+ * @author Ben Litchfield
  */
 public class PDFontDescriptorAFM extends PDFontDescriptor
 {
-    private FontMetric afm;
+    private FontMetrics afm;
 
     /**
      * Constructor.
      *
      * @param afmFile The AFM file.
      */
-    public PDFontDescriptorAFM( FontMetric afmFile )
+    public PDFontDescriptorAFM( FontMetrics afmFile )
     {
         afm = afmFile;
     }

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java Sun Aug 17 20:02:18 2014
@@ -42,16 +42,16 @@ public class PDFontDescriptorDictionary 
     private int flags = -1;
 
     /**
-     * Constructor.
+     * Package-private constructor, for internal PDFBox use only.
      */
-    public PDFontDescriptorDictionary()
+    PDFontDescriptorDictionary()
     {
         dic = new COSDictionary();
         dic.setItem( COSName.TYPE, COSName.FONT_DESC );
     }
 
     /**
-     * Constructor.
+     * Creates a PDFontDescriptor from a COS dictionary.
      *
      * @param desc The wrapped COS Dictionary.
      */

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontFactory.java Sun Aug 17 20:02:18 2014
@@ -18,6 +18,7 @@ package org.apache.pdfbox.pdmodel.font;
 
 import java.io.IOException;
 
+import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.commons.logging.Log;
@@ -53,6 +54,14 @@ public class PDFontFactory
         COSName subType = dictionary.getCOSName(COSName.SUBTYPE);
         if (COSName.TYPE1.equals(subType))
         {
+            COSBase fd = dictionary.getDictionaryObject(COSName.FONT_DESC);
+            if (fd != null && fd instanceof COSDictionary)
+            {
+                if (((COSDictionary)fd).containsKey(COSName.FONT_FILE3))
+                {
+                    return new PDType1CFont(dictionary);
+                }
+            }
             return new PDType1Font(dictionary);
         }
         else if (COSName.MM_TYPE1.equals(subType))
@@ -101,17 +110,17 @@ public class PDFontFactory
         COSName type = dictionary.getCOSName(COSName.TYPE, COSName.FONT);
         if (!COSName.FONT.equals(type))
         {
-            throw new IOException("Expected 'Font' dictionary but found '" + type.getName() + "'");
+            throw new IllegalArgumentException("Expected 'Font' dictionary but found '" + type.getName() + "'");
         }
 
         COSName subType = dictionary.getCOSName(COSName.SUBTYPE);
         if (COSName.CID_FONT_TYPE0.equals(subType))
         {
-            return new PDCIDFontType0Font(dictionary, parent);
+            return new PDCIDFontType0(dictionary, parent);
         }
         else if (COSName.CID_FONT_TYPE2.equals(subType))
         {
-            return new PDCIDFontType2Font(dictionary, parent);
+            return new PDCIDFontType2(dictionary, parent);
         }
         else
         {

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDMMType1Font.java Sun Aug 17 20:02:18 2014
@@ -17,7 +17,8 @@
 package org.apache.pdfbox.pdmodel.font;
 
 import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
+
+import java.io.IOException;
 
 /**
  * Type 1 Multiple Master Font.
@@ -27,19 +28,11 @@ import org.apache.pdfbox.cos.COSName;
 public class PDMMType1Font extends PDType1Font
 {
     /**
-     * Constructor.
-     */
-    public PDMMType1Font()
-    {
-        dict.setItem(COSName.SUBTYPE, COSName.MM_TYPE1);
-    }
-
-    /**
-     * Constructor.
+     * Creates an MMType1Font from a Font dictionary in a PDF.
      *
-     * @param fontDictionary The font dictionary according to the PDF specification.
+     * @param fontDictionary font dictionary
      */
-    public PDMMType1Font(COSDictionary fontDictionary)
+    public PDMMType1Font(COSDictionary fontDictionary) throws IOException
     {
         super(fontDictionary);
     }

Modified: pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1618516&r1=1618515&r2=1618516&view=diff
==============================================================================
--- pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original)
+++ pdfbox/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Sun Aug 17 20:02:18 2014
@@ -20,39 +20,18 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fontbox.ttf.CMAPEncodingEntry;
 import org.apache.fontbox.ttf.CMAPTable;
-import org.apache.fontbox.ttf.GlyphData;
-import org.apache.fontbox.ttf.GlyphTable;
-import org.apache.fontbox.ttf.HeaderTable;
-import org.apache.fontbox.ttf.HorizontalHeaderTable;
-import org.apache.fontbox.ttf.HorizontalMetricsTable;
-import org.apache.fontbox.ttf.NameRecord;
-import org.apache.fontbox.ttf.NamingTable;
-import org.apache.fontbox.ttf.OS2WindowsMetricsTable;
-import org.apache.fontbox.ttf.PostScriptTable;
 import org.apache.fontbox.ttf.TTFParser;
 import org.apache.fontbox.ttf.TrueTypeFont;
-import org.apache.fontbox.util.SystemFontManager;
 import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.encoding.Encoding;
 import org.apache.pdfbox.encoding.MacOSRomanEncoding;
-import org.apache.pdfbox.encoding.WinAnsiEncoding;
-import org.apache.pdfbox.io.IOUtils;
 import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.pdmodel.common.COSArrayList;
-import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 
 /**
@@ -94,331 +73,58 @@ public class PDTrueTypeFont extends PDFo
      *
      * @param fontDictionary The font dictionary according to the PDF specification.
      */
-    public PDTrueTypeFont(COSDictionary fontDictionary)  throws IOException
+    public PDTrueTypeFont(COSDictionary fontDictionary) throws IOException
     {
         super(fontDictionary);
-        getTTFFont(); // load the font file
-    }
-
-    /**
-     * Creates a new TrueType font for embedding.
-     */
-    private PDTrueTypeFont(PDDocument document, InputStream ttfStream) throws IOException
-    {
-        dict.setItem(COSName.SUBTYPE, COSName.TRUE_TYPE);
-
-        PDStream stream = new PDStream(document, ttfStream, false);
-        stream.getStream().setInt(COSName.LENGTH1, stream.getByteArray().length); // todo: wrong?
-        stream.addCompression();
-
-        // only support winansi encoding right now, should really
-        // just use Identity-H with unicode mapping
-        Encoding encoding = new WinAnsiEncoding(); // fixme: read encoding from TTF
-
-        this.fontEncoding = encoding;
-        dict.setItem(COSName.ENCODING, encoding.getCOSObject());
-
-        // as the stream was close within the PDStream constructor, we have to recreate it
-        InputStream stream2 = null;
-        PDFontDescriptorDictionary fd;
-        try
-        {
-            stream2 = stream.createInputStream();
-            ttf = new TTFParser().parseTTF(stream2);
-            fd = makeFontDescriptor(ttf);
-        }
-        finally
-        {
-            IOUtils.closeQuietly(stream2);
-        }
-
-        fd.setFontFile2(stream);
-        dict.setItem(COSName.FONT_DESC, fd);
-    }
 
-    @Override
-    public PDFontDescriptor getFontDescriptor()
-    {
-        if (fontDescriptor == null)
+        PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary) super.getFontDescriptor();
+        if (fd != null)
         {
-            COSDictionary fd = (COSDictionary) dict.getDictionaryObject(COSName.FONT_DESC);
-            if (fd != null)
+            PDStream ff2Stream = fd.getFontFile2();
+            if (ff2Stream != null)
             {
-                fontDescriptor = new PDFontDescriptorDictionary(fd);
-            }
-            else
-            {
-                fontDescriptor = makeFontDescriptor(ttf);
+                // embedded
+                TTFParser ttfParser = new TTFParser(true);
+                ttf = ttfParser.parseTTF(ff2Stream.createInputStream());
             }
         }
-        return fontDescriptor;
-    }
-
-    // creates a new font descriptor dictionary for the given TTF
-    private PDFontDescriptorDictionary makeFontDescriptor(TrueTypeFont ttf)
-    {
-        PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
 
-        NamingTable naming = ttf.getNaming();
-        List<NameRecord> records = naming.getNameRecords();
-        for (NameRecord nr : records)
-        {
-            if (nr.getNameId() == NameRecord.NAME_POSTSCRIPT_NAME)
-            {
-                dict.setName(COSName.BASE_FONT, nr.getString());
-                fd.setFontName(nr.getString());
-            }
-            else if (nr.getNameId() == NameRecord.NAME_FONT_FAMILY_NAME)
-            {
-                fd.setFontFamily(nr.getString());
-            }
-        }
-
-        OS2WindowsMetricsTable os2 = ttf.getOS2Windows();
-        boolean isSymbolic = false;
-        switch (os2.getFamilyClass())
-        {
-            case OS2WindowsMetricsTable.FAMILY_CLASS_SYMBOLIC:
-                isSymbolic = true;
-                break;
-            case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS:
-                fd.setScript(true);
-                break;
-            case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS:
-            case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS:
-            case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS:
-            case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS:
-            case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS:
-                fd.setSerif(true);
-                break;
-        }
-
-        switch (os2.getWidthClass())
-        {
-            case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_CONDENSED:
-                fd.setFontStretch("UltraCondensed");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_CONDENSED:
-                fd.setFontStretch("ExtraCondensed");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_CONDENSED:
-                fd.setFontStretch("Condensed");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_CONDENSED:
-                fd.setFontStretch("SemiCondensed");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_MEDIUM:
-                fd.setFontStretch("Normal");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_EXPANDED:
-                fd.setFontStretch("SemiExpanded");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_EXPANDED:
-                fd.setFontStretch("Expanded");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_EXPANDED:
-                fd.setFontStretch("ExtraExpanded");
-                break;
-            case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_EXPANDED:
-                fd.setFontStretch("UltraExpanded");
-                break;
-        }
-        fd.setFontWeight(os2.getWeightClass());
-        fd.setSymbolic(isSymbolic);
-        fd.setNonSymbolic(!isSymbolic);
-
-        // todo retval.setItalic
-        // todo retval.setAllCap
-        // todo retval.setSmallCap
-        // todo retval.setForceBold
-
-        HeaderTable header = ttf.getHeader();
-        PDRectangle rect = new PDRectangle();
-        float scaling = 1000f / header.getUnitsPerEm();
-        rect.setLowerLeftX(header.getXMin() * scaling);
-        rect.setLowerLeftY(header.getYMin() * scaling);
-        rect.setUpperRightX(header.getXMax() * scaling);
-        rect.setUpperRightY(header.getYMax() * scaling);
-        fd.setFontBoundingBox(rect);
-
-        HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
-        fd.setAscent(hHeader.getAscender() * scaling);
-        fd.setDescent(hHeader.getDescender() * scaling);
-
-        GlyphTable glyphTable = ttf.getGlyph();
-        GlyphData[] glyphs = glyphTable.getGlyphs();
-
-        PostScriptTable ps = ttf.getPostScript();
-        fd.setFixedPitch(ps.getIsFixedPitch() > 0);
-        fd.setItalicAngle(ps.getItalicAngle());
-
-        String[] names = ps.getGlyphNames();
-
-        if (names != null)
-        {
-            for (int i = 0; i < names.length; i++)
-            {
-                // if we have a capital H then use that, otherwise use the tallest letter
-                if (names[i].equals("H"))
-                {
-                    fd.setCapHeight(glyphs[i].getBoundingBox().getUpperRightY() / scaling);
-                }
-                if (names[i].equals("x"))
-                {
-                    fd.setXHeight(glyphs[i].getBoundingBox().getUpperRightY() / scaling);
-                }
-            }
-        }
-
-        // hmm there does not seem to be a clear definition for StemV,
-        // this is close enough and I am told it doesn't usually get used.
-        fd.setStemV(fd.getFontBoundingBox().getWidth() * .13f);
-
-        CMAPTable cmapTable = ttf.getCMAP();
-        CMAPEncodingEntry[] cmaps = cmapTable.getCmaps();
-
-        CMAPEncodingEntry uniMap = getCmapSubtable(cmaps, CMAPTable.PLATFORM_UNICODE,
-                                                   CMAPTable.ENCODING_UNICODE_2_0_FULL);
-        if (uniMap == null)
-        {
-            uniMap = getCmapSubtable(cmaps, CMAPTable.PLATFORM_UNICODE,
-                                     CMAPTable.ENCODING_UNICODE_2_0_BMP);
-        }
-        if (uniMap == null)
-        {
-            uniMap = getCmapSubtable(cmaps, CMAPTable.PLATFORM_WINDOWS,
-                                     CMAPTable.ENCODING_WIN_UNICODE);
-        }
-        if (uniMap == null)
-        {
-            // Microsoft's "Recommendations for OpenType Fonts" says that "Symbol" encoding
-            // actually means "Unicode, non-standard character set"
-            uniMap = getCmapSubtable(cmaps, CMAPTable.PLATFORM_WINDOWS,
-                                     CMAPTable.ENCODING_WIN_SYMBOL);
-        }
-        if (uniMap == null)
-        {
-            // there should always be a usable cmap, if this happens we haven't tried hard enough
-            // to find one. Furthermore, if we loaded the font from disk then we should've checked
-            // first to see that it had a suitable cmap before calling makeFontDescriptor
-            throw new IllegalArgumentException("ttf: no suitable cmap for font '" +
-                    ttf.getNaming().getFontFamily() + "', found: " + Arrays.toString(cmaps));
-        }
-
-        if (this.getFontEncoding() == null)
+        // substitute
+        if (ttf == null)
         {
-            // todo: calling this.getFontEncoding() doesn't work if the font is loaded
-            //       from the local system, because it relies on the FontDescriptor!
-            //       We make do for now by returning an incomplete descriptor pending further
-            //       refactoring of PDFont#determineEncoding().
-            return fd;
+            ttf = ExternalFonts.getTrueTypeFont(getBaseFont());
         }
+        // todo: put the fallback here? (i.e. make this class fallback-aware - cleaner)
 
-        Map<Integer, String> codeToName = this.getFontEncoding().getCodeToNameMap();
-
-        int firstChar = Collections.min(codeToName.keySet());
-        int lastChar = Collections.max(codeToName.keySet());
-
-        HorizontalMetricsTable hMet = ttf.getHorizontalMetrics();
-        int[] widthValues = hMet.getAdvanceWidth();
-        // some monospaced fonts provide only one value for the width
-        // instead of an array containing the same value for every glyphid
-        boolean isMonospaced = fd.isFixedPitch() || widthValues.length == 1;
-        int nWidths = lastChar - firstChar + 1;
-        List<Integer> widths = new ArrayList<Integer>(nWidths);
-        // use the first width as default
-        // proportional fonts -> width of the .notdef character
-        // monospaced-fonts -> the first width
-        int defaultWidth = Math.round(widthValues[0] * scaling);
-        for (int i = 0; i < nWidths; i++)
-        {
-            widths.add(defaultWidth);
-        }
-        // Encoding singleton to have acces to the chglyph name to
-        // unicode cpoint point mapping of Adobe's glyphlist.txt
-        Encoding glyphlist = WinAnsiEncoding.INSTANCE;
-
-        // A character code is mapped to a glyph name via the provided font encoding
-        // Afterwards, the glyph name is translated to a glyph ID.
-        // For details, see PDFReference16.pdf, Section 5.5.5, p.401
-        //
-        for (Entry<Integer, String> e : codeToName.entrySet())
-        {
-            String name = e.getValue();
-            // pdf code to unicode by glyph list.
-            if (!name.equals(".notdef"))
-            {
-                String c = glyphlist.getCharacter(name);
-                int charCode = c.codePointAt(0);
-                int gid = uniMap.getGlyphId(charCode);
-                if (gid != 0)
-                {
-                    if (isMonospaced)
-                    {
-                        widths.set(e.getKey() - firstChar, defaultWidth);
-                    }
-                    else
-                    {
-                        widths.set(e.getKey() - firstChar,
-                                Math.round(widthValues[gid] * scaling));
-                    }
-                }
-            }
-        }
-        dict.setItem(COSName.WIDTHS, COSArrayList.converterToCOSArray(widths));
-        dict.setInt(COSName.FIRST_CHAR, firstChar);
-        dict.setInt(COSName.LAST_CHAR, lastChar);
-
-        return fd;
+        determineEncoding();
     }
 
     /**
-     * Returns the "cmap" subtable for the given platform and encoding, or null.
+     * Creates a new TrueType font for embedding.
      */
-    private CMAPEncodingEntry getCmapSubtable(CMAPEncodingEntry[] cmaps,
-                                              int platformId, int platformEncodingId)
+    private PDTrueTypeFont(PDDocument document, InputStream ttfStream) throws IOException
+    {
+        PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, dict, ttfStream);
+        fontEncoding = embedder.getFontEncoding();
+        ttf = embedder.getTrueTypeFont();
+    }
+
+    @Override
+    public PDFontDescriptor getFontDescriptor()
     {
-        for (CMAPEncodingEntry cmap : cmaps)
+        if (super.getFontDescriptor() == null)
         {
-            if (cmap.getPlatformId() == platformId &&
-                cmap.getPlatformEncodingId() == platformEncodingId)
-            {
-                return cmap;
-            }
+            // todo: this is an experiment: we now allow this to be null (i.e. we no longer synthesise)
+            //fontDescriptor = makeFontDescriptor(ttf);
         }
-        return null;
+        return fontDescriptor;
     }
 
     /**
-     * Return the TTF font as TrueTypeFont.
-     * 
-     * @return the TTF font
-     * @throws IOException If there is an error loading the data
+     * Returns the embedded or substituted TrueType font.
      */
-    public TrueTypeFont getTTFFont() throws IOException
+    public TrueTypeFont getTrueTypeFont()
     {
-        if (ttf == null)
-        {
-            PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary) super.getFontDescriptor();
-            if (fd != null)
-            {
-                PDStream ff2Stream = fd.getFontFile2();
-                if (ff2Stream != null)
-                {
-                    TTFParser ttfParser = new TTFParser(true);
-                    ttf = ttfParser.parseTTF(ff2Stream.createInputStream());
-                }
-            }
-            if (ttf == null)
-            {
-                // check if there is a font mapping for an external font file
-                ttf = SystemFontManager.findTTFont(getBaseFont());
-            }
-            if (ttf == null)
-            {
-                ttf = PDFFontManager.getTrueTypeFallbackFont();
-            }
-        }
         return ttf;
     }
 
@@ -434,25 +140,13 @@ public class PDTrueTypeFont extends PDFo
             }
             else
             {
-                TrueTypeFont ttf;
-                try
+                int code = getGIDForCharacterCode(charCode);
+                width = ttf.getAdvanceWidth(code);
+                int unitsPerEM = ttf.getUnitsPerEm();
+                // do we have to scale the width
+                if (unitsPerEM != 1000)
                 {
-                    ttf = getTTFFont();
-                    if (ttf != null)
-                    {
-                        int code = getGIDForCharacterCode(charCode);
-                        width = ttf.getAdvanceWidth(code);
-                        int unitsPerEM = ttf.getUnitsPerEm();
-                        // do we have to scale the width
-                        if (unitsPerEM != 1000)
-                        {
-                            width *= 1000f / unitsPerEM;
-                        }
-                    }
-                }
-                catch (IOException exception)
-                {
-                    width = 250;
+                    width *= 1000f / unitsPerEM;
                 }
                 advanceWidths.put(charCode, width);
             }
@@ -567,15 +261,6 @@ public class PDTrueTypeFont extends PDFo
             return;
         }
 
-        try
-        {
-            getTTFFont();
-        }
-        catch(IOException exception)
-        {
-            LOG.error("Can't read the true type font", exception);
-        }
-
         CMAPTable cmapTable = ttf.getCMAP();
         if (cmapTable != null)
         {
@@ -615,9 +300,6 @@ public class PDTrueTypeFont extends PDFo
         cmapMacintoshSymbol = null;
         cmapInitialized = false;
         ttf = null;
-        if (advanceWidths != null)
-        {
-            advanceWidths.clear();
-        }
+        advanceWidths.clear();
     }
 }