svn commit: r1811062 - in /xmlgraphics/fop/trunk/fop-core/src: main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java

[email protected]
Newsgroups gmane.text.xml.fop.cvs
Message-ID <[email protected]>
Author: ssteiner
Date: Wed Oct  4 11:25:37 2017
New Revision: 1811062

URL: http://svn.apache.org/viewvc?rev=1811062&view=rev
Log:
FOP-2737: OTF subsetting: Resize privateDict to fit op size

Modified:
    xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
    xmlgraphics/fop/trunk/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java

Modified: xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java?rev=1811062&r1=1811061&r2=1811062&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java (original)
+++ xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java Wed Oct  4 11:25:37 2017
@@ -30,7 +30,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -69,7 +68,7 @@ public class OTFSubSetFile extends OTFSu
 
     /** For fonts which have an FDSelect or ROS flag in Top Dict, this is used to store the
      * local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */
-    private List<List<byte[]>> fdSubrs;
+    protected List<List<byte[]>> fdSubrs;
 
     /** The subset FD Select table used to store the mappings between glyphs and their
      * associated FDFont object which point to a private dict and local subroutines. */
@@ -264,7 +263,7 @@ public class OTFSubSetFile extends OTFSu
     protected List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException {
         List<Integer> fontNameSIDs = new ArrayList<Integer>();
         List<FontDict> fdFonts = cffReader.getFDFonts();
-        for (Integer uniqueNewRef : uniqueNewRefs) {
+        for (int uniqueNewRef : uniqueNewRefs) {
             FontDict fdFont = fdFonts.get(uniqueNewRef);
             byte[] fdFontByteData = fdFont.getByteData();
             Map<String, DICTEntry> fdFontDict = cffReader.parseDictData(fdFontByteData);
@@ -354,29 +353,29 @@ public class OTFSubSetFile extends OTFSu
 
         for (Entry<Integer, Integer> subsetGlyph : subsetGlyphs.entrySet()) {
             int gid = subsetGlyph.getKey();
+            int v = subsetGlyph.getValue();
             int sid = cffReader.getSIDFromGID(charsetOffset, gid);
             //Check whether the SID falls into the standard string set
             if (sid < NUM_STANDARD_STRINGS) {
-                gidToSID.put(subsetGlyph.getValue(), sid);
+                gidToSID.put(v, sid);
                 if (mbFont != null) {
-                    mbFont.mapUsedGlyphName(subsetGlyph.getValue(),
-                            CFFStandardString.getName(sid));
+                    mbFont.mapUsedGlyphName(v, CFFStandardString.getName(sid));
                 }
             } else {
                 int index = sid - NUM_STANDARD_STRINGS;
                 //index is 0 based, should use < not <=
                 if (index < cffReader.getStringIndex().getNumObjects()) {
+                    byte[] value = cffReader.getStringIndex().getValue(index);
                     if (mbFont != null) {
-                        mbFont.mapUsedGlyphName(subsetGlyph.getValue(),
-                                new String(cffReader.getStringIndex().getValue(index), "UTF-8"));
+                        mbFont.mapUsedGlyphName(v, new String(value, "UTF-8"));
                     }
-                    gidToSID.put(subsetGlyph.getValue(), stringIndexData.size() + 391);
-                    stringIndexData.add(cffReader.getStringIndex().getValue(index));
+                    gidToSID.put(v, stringIndexData.size() + 391);
+                    stringIndexData.add(value);
                 } else {
                     if (mbFont != null) {
-                        mbFont.mapUsedGlyphName(subsetGlyph.getValue(), ".notdef");
+                        mbFont.mapUsedGlyphName(v, ".notdef");
                     }
-                    gidToSID.put(subsetGlyph.getValue(), index);
+                    gidToSID.put(v, index);
                 }
             }
         }
@@ -395,22 +394,25 @@ public class OTFSubSetFile extends OTFSu
             Map<Integer, Integer> subsetGroups = new HashMap<Integer, Integer>();
 
             List<Integer> uniqueGroups = new ArrayList<Integer>();
+            Map<Integer, Integer> rangeMap = fdSelect.getRanges();
+            Integer[] ranges = rangeMap.keySet().toArray(new Integer[rangeMap.size()]);
             for (int gid : subsetGlyphs.keySet()) {
-                Set<Integer> rangeKeys = fdSelect.getRanges().keySet();
-                Integer[] ranges = rangeKeys.toArray(new Integer[rangeKeys.size()]);
-                for (int i = 0; i < ranges.length; i++) {
-                    int nextRange = -1;
+                int i = 0;
+                for (Entry<Integer, Integer> entry : rangeMap.entrySet()) {
+                    int nextRange;
                     if (i < ranges.length - 1) {
                         nextRange = ranges[i + 1];
                     } else {
                         nextRange = fdSelect.getSentinelGID();
                     }
-                    if (gid >= ranges[i] && gid < nextRange) {
-                        subsetGroups.put(gid, fdSelect.getRanges().get(ranges[i]));
-                        if (!uniqueGroups.contains(fdSelect.getRanges().get(ranges[i]))) {
-                            uniqueGroups.add(fdSelect.getRanges().get(ranges[i]));
+                    if (gid >= entry.getKey() && gid < nextRange) {
+                        int r = entry.getValue();
+                        subsetGroups.put(gid, r);
+                        if (!uniqueGroups.contains(r)) {
+                            uniqueGroups.add(r);
                         }
                     }
+                    i++;
                 }
             }
 
@@ -425,7 +427,7 @@ public class OTFSubSetFile extends OTFSu
             subsetFDSelect = new LinkedHashMap<Integer, FDIndexReference>();
 
             List<List<Integer>> foundLocalUniques = new ArrayList<List<Integer>>();
-            for (Integer uniqueGroup1 : uniqueGroups) {
+            for (int u : uniqueGroups) {
                 foundLocalUniques.add(new ArrayList<Integer>());
             }
             Map<Integer, Integer> gidHintMaskLengths = new HashMap<Integer, Integer>();
@@ -455,7 +457,7 @@ public class OTFSubSetFile extends OTFSu
                 fdSubrs.add(new ArrayList<byte[]>());
             }
             List<List<Integer>> foundLocalUniquesB = new ArrayList<List<Integer>>();
-            for (Integer uniqueGroup : uniqueGroups) {
+            for (int u : uniqueGroups) {
                 foundLocalUniquesB.add(new ArrayList<Integer>());
             }
             for (Entry<Integer, Integer> subsetGlyph : subsetGlyphs.entrySet()) {
@@ -463,11 +465,11 @@ public class OTFSubSetFile extends OTFSu
                 int value = subsetGlyph.getValue();
                 int group = subsetGroups.get(gid);
                 localIndexSubr = cffReader.getFDFonts().get(group).getLocalSubrData();
-                localUniques = foundLocalUniquesB.get(subsetFDSelect.get(value).getNewFDIndex());
+                int newFDIndex = subsetFDSelect.get(value).getNewFDIndex();
+                localUniques = foundLocalUniquesB.get(newFDIndex);
                 byte[] data = charStringsIndex.getValue(gid);
-                subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(value).getNewFDIndex());
-                subsetLocalSubrCount = foundLocalUniques.get(subsetFDSelect.get(value)
-                        .getNewFDIndex()).size();
+                subsetLocalIndexSubr = fdSubrs.get(newFDIndex);
+                subsetLocalSubrCount = foundLocalUniques.get(newFDIndex).size();
                 type2Parser = new Type2Parser();
                 type2Parser.setMaskLength(gidHintMaskLengths.get(gid));
                 data = readCharStringData(data, subsetLocalSubrCount);
@@ -528,23 +530,37 @@ public class OTFSubSetFile extends OTFSu
             throws IOException {
         List<Integer> privateDictOffsets = new ArrayList<Integer>();
         List<FontDict> fdFonts = cffReader.getFDFonts();
-        for (int i = 0; i < uniqueNewRefs.size(); i++) {
-            FontDict curFDFont = fdFonts.get(uniqueNewRefs.get(i));
+        int i = 0;
+        for (int ref : uniqueNewRefs) {
+            FontDict curFDFont = fdFonts.get(ref);
             byte[] fdPrivateDictByteData = curFDFont.getPrivateDictData();
             Map<String, DICTEntry> fdPrivateDict = cffReader.parseDictData(fdPrivateDictByteData);
             int privateDictOffset = currentPos;
             privateDictOffsets.add(privateDictOffset);
-            if (fdPrivateDict.get("Subrs") != null) {
-                updateOffset(fdPrivateDictByteData, fdPrivateDict.get("Subrs").getOffset(),
-                        fdPrivateDict.get("Subrs").getOperandLength(),
+            DICTEntry subrs = fdPrivateDict.get("Subrs");
+            if (subrs != null) {
+                fdPrivateDictByteData = resizeToFitOpLen(fdPrivateDictByteData, subrs);
+                updateOffset(fdPrivateDictByteData, subrs.getOffset(),
+                        subrs.getOperandLength(),
                         fdPrivateDictByteData.length);
             }
             writeBytes(fdPrivateDictByteData);
             writeIndex(fdSubrs.get(i));
+            i++;
         }
         return privateDictOffsets;
     }
 
+    private byte[] resizeToFitOpLen(byte[] fdPrivateDictByteData, DICTEntry subrs) throws IOException {
+        if (subrs.getOperandLength() == 2 && fdPrivateDictByteData.length < 108) {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            bos.write(fdPrivateDictByteData);
+            bos.write(new byte[108 - fdPrivateDictByteData.length]);
+            fdPrivateDictByteData = bos.toByteArray();
+        }
+        return fdPrivateDictByteData;
+    }
+
     protected int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets,
             List<Integer> fontNameSIDs)
             throws IOException {
@@ -552,8 +568,9 @@ public class OTFSubSetFile extends OTFSu
         List<FontDict> fdFonts = cffReader.getFDFonts();
         List<byte[]> index = new ArrayList<byte[]>();
 
-        for (int i = 0; i < uniqueNewRefs.size(); i++) {
-            FontDict fdFont = fdFonts.get(uniqueNewRefs.get(i));
+        int i = 0;
+        for (int ref : uniqueNewRefs) {
+            FontDict fdFont = fdFonts.get(ref);
             byte[] fdFontByteData = fdFont.getByteData();
             Map<String, DICTEntry> fdFontDict = cffReader.parseDictData(fdFontByteData);
             //Update the SID to the FontName
@@ -566,6 +583,7 @@ public class OTFSubSetFile extends OTFSu
                     fdFontDict.get("Private").getOperandLengths().get(1),
                     privateDictOffsets.get(i));
             index.add(fdFontByteData);
+            i++;
         }
         writeIndex(index);
         return offset;
@@ -817,7 +835,7 @@ public class OTFSubSetFile extends OTFSu
                 if (newRef != -1) {
                     byte[] newData = constructNewRefData(dataPos, data, operand, subsetGlobalSubrCount,
                             newRef, new int[] {29});
-                    dataPos -= (data.length - newData.length);
+                    dataPos -= data.length - newData.length;
                     data = newData;
                 }
             } else {
@@ -933,8 +951,8 @@ public class OTFSubSetFile extends OTFSu
 
     protected int writeIndex(List<byte[]> dataArray) {
         int totLength = 1;
-        for (byte[] aDataArray1 : dataArray) {
-            totLength += aDataArray1.length;
+        for (byte[] data : dataArray) {
+            totLength += data.length;
         }
         int offSize = getOffSize(totLength);
         return writeIndex(dataArray, offSize);
@@ -951,9 +969,10 @@ public class OTFSubSetFile extends OTFSu
         //Count the first offset 1
         hdrTotal += offSize;
         int total = 0;
-        for (int i = 0; i < dataArray.size(); i++) {
+        int i = 0;
+        for (byte[] data : dataArray) {
             hdrTotal += offSize;
-            int length = dataArray.get(i).length;
+            int length = data.length;
             switch (offSize) {
             case 1:
                 if (i == 0) {
@@ -986,6 +1005,7 @@ public class OTFSubSetFile extends OTFSu
             default:
                 throw new AssertionError("Offset Size was not an expected value.");
             }
+            i++;
         }
         for (byte[] aDataArray : dataArray) {
             writeBytes(aDataArray);
@@ -1148,9 +1168,6 @@ public class OTFSubSetFile extends OTFSu
     }
 
     protected void updateOffset(byte[] out, int position, int length, int replacement) {
-        if (length == 2 && replacement < 108 && replacement > -108) {
-            length = 1;
-        }
         switch (length) {
         case 1:
             out[position] = (byte)(replacement + 139);

Modified: xmlgraphics/fop/trunk/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java?rev=1811062&r1=1811061&r2=1811062&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java (original)
+++ xmlgraphics/fop/trunk/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java Wed Oct  4 11:25:37 2017
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.when;
 import org.apache.fontbox.cff.CFFFont;
 import org.apache.fontbox.cff.CFFParser;
 
+import org.apache.fop.fonts.MultiByteFont;
 import org.apache.fop.fonts.cff.CFFDataReader;
 import org.apache.fop.fonts.cff.CFFDataReader.CFFIndexData;
 import org.apache.fop.fonts.cff.CFFDataReader.DICTEntry;
@@ -500,7 +501,9 @@ public class OTFSubSetFileTestCase exten
             map.put("charset", dict);
             map.put("CharStrings", dict);
             when((cffReader.getTopDictEntries())).thenReturn(map);
-            when(cffReader.getFDSelect()).thenReturn(new CFFDataReader().new Format3FDSelect());
+            CFFDataReader.Format3FDSelect fdSelect = new CFFDataReader().new Format3FDSelect();
+            fdSelect.setRanges(new HashMap<Integer, Integer>());
+            when(cffReader.getFDSelect()).thenReturn(fdSelect);
             cffReader.getTopDictEntries().get("CharStrings").setOperandLength(opLen);
             super.createCFF();
         }
@@ -558,14 +561,7 @@ public class OTFSubSetFileTestCase exten
                     return new byte[128];
                 }
             };
-            cffReader = mock(CFFDataReader.class);
-            LinkedHashMap<String, DICTEntry> map = new LinkedHashMap<String, DICTEntry>();
-            DICTEntry e = new DICTEntry();
-            e.setOffset(1);
-            e.setOperandLengths(Arrays.asList(0, 0));
-            map.put("FontName", e);
-            map.put("Private", e);
-            when(cffReader.parseDictData(any(byte[].class))).thenReturn(map);
+            cffReader = makeCFFDataReader();
             when(cffReader.getFDFonts()).thenReturn(fdFonts);
 
             fdFonts.clear();
@@ -611,15 +607,7 @@ public class OTFSubSetFileTestCase exten
         }
 
         protected void createCFF() throws IOException {
-            cffReader = mock(CFFDataReader.class);
-            when(cffReader.getHeader()).thenReturn(new byte[0]);
-            when(cffReader.getTopDictIndex()).thenReturn(cffReader.new CFFIndexData() {
-                public byte[] getByteData() throws IOException {
-                    return new byte[]{0, 0, 1};
-                }
-            });
-            when(cffReader.getFDSelect()).thenReturn(cffReader.new Format3FDSelect());
-
+            cffReader = makeCFFDataReader();
             LinkedHashMap<String, DICTEntry> topDict = new LinkedHashMap<String, DICTEntry>();
             DICTEntry entry = new DICTEntry();
             entry.setOperands(Arrays.<Number>asList(0));
@@ -638,4 +626,54 @@ public class OTFSubSetFileTestCase exten
             this.offsets = offsets;
         }
     }
+
+    private static CFFDataReader makeCFFDataReader() throws IOException {
+        CFFDataReader cffReader = mock(CFFDataReader.class);
+        when(cffReader.getHeader()).thenReturn(new byte[0]);
+        when(cffReader.getTopDictIndex()).thenReturn(cffReader.new CFFIndexData() {
+            public byte[] getByteData() throws IOException {
+                return new byte[]{0, 0, 1};
+            }
+        });
+        CFFDataReader.Format3FDSelect fdSelect = cffReader.new Format3FDSelect();
+        fdSelect.setRanges(new HashMap<Integer, Integer>());
+        when(cffReader.getFDSelect()).thenReturn(fdSelect);
+        CFFDataReader.FontDict fd = mock(CFFDataReader.FontDict.class);
+        when(fd.getPrivateDictData()).thenReturn(new byte[0]);
+        when(cffReader.getFDFonts()).thenReturn(Arrays.asList(fd));
+
+        LinkedHashMap<String, DICTEntry> map = new LinkedHashMap<String, DICTEntry>();
+        DICTEntry e = new DICTEntry();
+        e.setOffset(1);
+        e.setOperandLengths(Arrays.asList(0, 0));
+        e.setOperandLength(2);
+        map.put("FontName", e);
+        map.put("Private", e);
+        map.put("Subrs", e);
+        when(cffReader.parseDictData(any(byte[].class))).thenReturn(map);
+        return cffReader;
+    }
+
+    @Test
+    public void testWriteCIDDictsAndSubrs() throws IOException {
+        OTFSubSetFile subSetFile = new OTFSubSetFile() {
+            public void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont) throws IOException {
+                output = new byte[128];
+                cffReader = makeCFFDataReader();
+                fdSubrs = new ArrayList<List<byte[]>>();
+                fdSubrs.add(new ArrayList<byte[]>());
+                writeCIDDictsAndSubrs(Arrays.asList(0));
+            }
+        };
+        subSetFile.readFont(null, null, (MultiByteFont) null);
+
+        ByteArrayInputStream is = new ByteArrayInputStream(subSetFile.getFontSubset());
+        is.skip(1);
+        Assert.assertEquals(is.read(), 247);
+        Assert.assertEquals(is.read(), 0);
+        final int sizeOfPrivateDictByteData = 108;
+        is.skip(sizeOfPrivateDictByteData - 3);
+        is.skip(2); //start index
+        Assert.assertEquals(is.read(), 1);
+    }
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.