FOP-2981: Convert CFF CID to Type1

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1882997 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/CFFToType1Font.java b/fop-core/src/main/java/org/apache/fop/fonts/CFFToType1Font.java
index a1b5238..3ef9b6e 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/CFFToType1Font.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/CFFToType1Font.java
@@ -30,7 +30,6 @@
 import org.apache.commons.io.IOUtils;
 import org.apache.fontbox.cff.CFFFont;
 import org.apache.fontbox.cff.CFFParser;
-import org.apache.fontbox.cff.CFFType1Font;
 
 import org.apache.fop.apps.io.InternalResourceResolver;
 import org.apache.fop.fonts.type1.PFBData;
@@ -57,9 +56,6 @@
 
     private List<InputStream> convertOTFToType1(InputStream in) throws IOException {
         CFFFont f = new CFFParser().parse(IOUtils.toByteArray(in)).get(0);
-        if (!(f instanceof  CFFType1Font)) {
-            throw new IOException(getEmbedFileURI() + ": only OTF CFF Type1 font can be converted to Type1");
-        }
         List<InputStream> fonts = new ArrayList<InputStream>();
         Map<Integer, Integer> glyphs = cidSet.getGlyphs();
         int i = 0;
@@ -88,9 +84,10 @@
         return allGlyphs;
     }
 
-    private InputStream convertOTFToType1(Map<Integer, Integer> glyphs, CFFFont f, String i) throws IOException {
-        byte[] t1 = new Type1FontFormatter(glyphs).format((CFFType1Font) f, i);
-        PFBData pfb = new PFBParser().parsePFB(new ByteArrayInputStream(t1));
+    private InputStream convertOTFToType1(Map<Integer, Integer> glyphs, CFFFont cffFont, String splitGlyphsId)
+        throws IOException {
+        byte[] type1Bytes = new Type1FontFormatter(glyphs).format(cffFont, splitGlyphsId);
+        PFBData pfb = new PFBParser().parsePFB(new ByteArrayInputStream(type1Bytes));
         ByteArrayOutputStream s1 = new ByteArrayOutputStream();
         s1.write(pfb.getHeaderSegment());
         ByteArrayOutputStream s2 = new ByteArrayOutputStream();
diff --git a/fop-core/src/main/java/org/apache/fop/render/ps/Type1FontFormatter.java b/fop-core/src/main/java/org/apache/fop/render/ps/Type1FontFormatter.java
index 0d19367..776d410 100644
--- a/fop-core/src/main/java/org/apache/fop/render/ps/Type1FontFormatter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/ps/Type1FontFormatter.java
@@ -24,6 +24,8 @@
 import java.util.Locale;
 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.cff.DataOutput;
 import org.apache.fontbox.cff.Type1FontUtil;
@@ -47,13 +49,13 @@
      * @return the Type1 font
      * @throws IOException if an error occurs during reading the given font
      */
-    public byte[] format(CFFType1Font font, String i) throws IOException {
+    public byte[] format(CFFFont font, String i) throws IOException {
         DataOutput output = new DataOutput();
         printFont(font, output, i);
         return output.getBytes();
     }
 
-    private void printFont(CFFType1Font font, DataOutput output, String iStr)
+    private void printFont(CFFFont font, DataOutput output, String iStr)
             throws IOException {
         output.println("%!FontType1-1.0 " + font.getName() + iStr + " "
                 + font.getTopDict().get("version"));
@@ -73,7 +75,7 @@
         output.println("cleartomark");
     }
 
-    private void printFontDictionary(CFFType1Font font, DataOutput output, String iStr)
+    private void printFontDictionary(CFFFont font, DataOutput output, String iStr)
             throws IOException {
         output.println("10 dict begin");
         output.println("/FontInfo 10 dict dup begin");
@@ -112,7 +114,13 @@
         int max = 0;
         StringBuilder sb = new StringBuilder();
         for (Map.Entry<Integer, Integer> gid : gids.entrySet()) {
-            String name = font.getCharset().getNameForGID(gid.getKey());
+            String name = "gid_" + gid.getKey();
+            if (gid.getKey() == 0) {
+                name = ".notdef";
+            }
+            if (font instanceof CFFType1Font) {
+                name = font.getCharset().getNameForGID(gid.getKey());
+            }
             sb.append(String.format("dup %d /%s put", gid.getValue(), name)).append('\n');
             max = Math.max(max, gid.getValue());
         }
@@ -133,32 +141,48 @@
         output.write(eexecBytes);
     }
 
-    private void printEexecFontDictionary(CFFType1Font font, DataOutput output)
+    private void printEexecFontDictionary(CFFFont font, DataOutput output)
             throws IOException {
         output.println("dup /Private 15 dict dup begin");
         output.println("/RD {string currentfile exch readstring pop} executeonly def");
         output.println("/ND {noaccess def} executeonly def");
         output.println("/NP {noaccess put} executeonly def");
+        Map<String, Object> privDict;
+        if (font instanceof CFFCIDFont) {
+            privDict = ((CFFCIDFont)font).getPrivDicts().get(0);
+        } else {
+            privDict = ((CFFType1Font)font).getPrivateDict();
+        }
         output.println("/BlueValues "
-                + formatArray(font.getPrivateDict().get("BlueValues"), true) + " ND");
+                + formatArray(privDict.get("BlueValues"), true) + " ND");
         output.println("/OtherBlues "
-                + formatArray(font.getPrivateDict().get("OtherBlues"), true) + " ND");
-        output.println("/BlueScale " + font.getPrivateDict().get("BlueScale") + " def");
-        output.println("/BlueShift " + font.getPrivateDict().get("BlueShift") + " def");
-        output.println("/BlueFuzz " + font.getPrivateDict().get("BlueFuzz") + " def");
-        output.println("/StdHW " + formatArray(font.getPrivateDict().get("StdHW"), true)
+                + formatArray(privDict.get("OtherBlues"), true) + " ND");
+        output.println("/BlueScale " + privDict.get("BlueScale") + " def");
+        output.println("/BlueShift " + privDict.get("BlueShift") + " def");
+        output.println("/BlueFuzz " + privDict.get("BlueFuzz") + " def");
+        output.println("/StdHW " + formatArray(privDict.get("StdHW"), true)
                 + " ND");
-        output.println("/StdVW " + formatArray(font.getPrivateDict().get("StdVW"), true)
+        output.println("/StdVW " + formatArray(privDict.get("StdVW"), true)
                 + " ND");
-        output.println("/ForceBold " + font.getPrivateDict().get("ForceBold") + " def");
+        output.println("/ForceBold " + privDict.get("ForceBold") + " def");
         output.println("/MinFeature {16 16} def");
         output.println("/password 5839 def");
 
         output.println("2 index /CharStrings " + gids.size() + " dict dup begin");
         Type1CharStringFormatter formatter = new Type1CharStringFormatter();
         for (int gid : gids.keySet()) {
-            String mapping = font.getCharset().getNameForGID(gid);
-            byte[] type1Bytes = formatter.format(font.getType1CharString(mapping).getType1Sequence());
+            String mapping = "gid_" + gid;
+            if (gid == 0) {
+                mapping = ".notdef";
+            }
+            byte[] type1Bytes;
+            if (font instanceof CFFCIDFont) {
+                int cid = font.getCharset().getCIDForGID(gid);
+                type1Bytes = formatter.format(((CFFCIDFont)font).getType2CharString(cid).getType1Sequence());
+            } else {
+                mapping = font.getCharset().getNameForGID(gid);
+                type1Bytes = formatter.format(((CFFType1Font)font).getType1CharString(mapping).getType1Sequence());
+            }
             byte[] charstringBytes = Type1FontUtil.charstringEncrypt(type1Bytes, 4);
             output.print("/" + mapping + " " + charstringBytes.length + " RD ");
             output.write(charstringBytes);
diff --git a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java
index adea1d1..9194d16 100644
--- a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -54,6 +55,20 @@
         Assert.assertEquals(t1.getFontType(), FontType.TYPE1);
     }
 
+    @Test
+    public void testCIDFont() throws IOException {
+        CFFToType1Font realFont = (CFFToType1Font)getRealFont("test/resources/fonts/otf/AlexBrush-Regular-cid.otf");
+        for (int i = 0; i < 10240; i++) {
+            realFont.mapChar((char) i);
+        }
+        List<InputStream> fonts = realFont.getInputStreams();
+        InputStream is = fonts.get(0);
+        Type1Font t1 = Type1Font.createWithPFB(is);
+        Assert.assertEquals(t1.getFontName(), "AlexBrush-Regular.0");
+        Assert.assertTrue(t1.getCharStringsDict().keySet().contains(".notdef"));
+        Assert.assertTrue(t1.getCharStringsDict().keySet().contains("gid_1"));
+    }
+
     private Type1Font getFont(String s) throws IOException {
         InputStream is = ((CFFToType1Font)getRealFont(s)).getInputStreams().get(0);
         return Type1Font.createWithPFB(is);
diff --git a/fop/test/resources/fonts/otf/AlexBrush-Regular-cid.otf b/fop/test/resources/fonts/otf/AlexBrush-Regular-cid.otf
new file mode 100644
index 0000000..4b015be
--- /dev/null
+++ b/fop/test/resources/fonts/otf/AlexBrush-Regular-cid.otf
Binary files differ