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);
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscr...@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-h...@xmlgraphics.apache.org

Reply via email to