svn commit: r1806787 - 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: Thu Aug 31 12:31:03 2017
New Revision: 1806787

URL: http://svn.apache.org/viewvc?rev=1806787&view=rev
Log:
FOP-2699: Fix subsetting large number of glyphs

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=1806787&r1=1806786&r2=1806787&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 Thu Aug 31 12:31:03 2017
@@ -172,11 +172,7 @@ public class OTFSubSetFile extends OTFSu
         //Keep offset of the topDICT so it can be updated once all data has been written
         int topDictOffset = currentPos;
         //Top DICT Index and Data
-        byte[] topDictIndex = cffReader.getTopDictIndex().getByteData();
-        int offSize = topDictIndex[2];
-        writeBytes(topDictIndex, 0, 3 + (offSize * 2));
-        int topDictDataOffset = currentPos;
-        writeTopDICT();
+        int topDictDataOffset = topDictOffset + writeTopDICT();
 
         //Create the char string index data and related local / global subroutines
         if (cffReader.getFDSelect() == null) {
@@ -251,27 +247,39 @@ public class OTFSubSetFile extends OTFSu
         return fontNameSIDs;
     }
 
-    protected void writeTopDICT() throws IOException {
+    protected int writeTopDICT() throws IOException {
         Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries();
         List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright",
                 "FullName", "FamilyName", "Weight", "PostScript");
+        ByteArrayOutputStream dict = new ByteArrayOutputStream();
+        int offsetExtra = 0;
         for (Map.Entry<String, DICTEntry> dictEntry : topDICT.entrySet()) {
             String dictKey = dictEntry.getKey();
             DICTEntry entry = dictEntry.getValue();
             //If the value is an SID, update the reference but keep the size the same
-            if (dictKey.equals("ROS")) {
-                writeROSEntry(entry);
+            entry.setOffset(entry.getOffset() + offsetExtra);
+            if (dictKey.equals("CharStrings") && entry.getOperandLength() == 3) {
+                byte[] extra = new byte[2];
+                offsetExtra += extra.length;
+                dict.write(extra);
+                dict.write(entry.getByteData());
+                entry.setOperandLength(5);
+            } else if (dictKey.equals("ROS")) {
+                dict.write(writeROSEntry(entry));
             } else if (dictKey.equals("CIDCount")) {
-                writeCIDCount(entry);
+                dict.write(writeCIDCount(entry));
             } else if (topDictStringEntries.contains(dictKey)) {
-                writeTopDictStringEntry(entry);
+                dict.write(writeTopDictStringEntry(entry));
             } else {
-                writeBytes(entry.getByteData());
+                dict.write(entry.getByteData());
             }
         }
+        byte[] topDictIndex = cffReader.getTopDictIndex().getByteData();
+        int offSize = topDictIndex[2];
+        return writeIndex(Arrays.asList(dict.toByteArray()), offSize) - dict.size();
     }
 
-    private void writeROSEntry(DICTEntry dictEntry) throws IOException {
+    private byte[] writeROSEntry(DICTEntry dictEntry) throws IOException {
         int sidA = dictEntry.getOperands().get(0).intValue();
         if (sidA > 390) {
             stringIndexData.add(cffReader.getStringIndex().getValue(sidA - NUM_STANDARD_STRINGS));
@@ -289,17 +297,17 @@ public class OTFSubSetFile extends OTFSu
                 dictEntry.getOperandLengths().get(1), sidBStringIndex);
         updateOffset(cidEntryByteData, dictEntry.getOperandLengths().get(0)
                 + dictEntry.getOperandLengths().get(1), dictEntry.getOperandLengths().get(2), 0);
-        writeBytes(cidEntryByteData);
+        return cidEntryByteData;
     }
 
-    protected void writeCIDCount(DICTEntry dictEntry) throws IOException {
+    protected byte[] writeCIDCount(DICTEntry dictEntry) throws IOException {
         byte[] cidCountByteData = dictEntry.getByteData();
         updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0),
                 subsetGlyphs.size());
-        writeBytes(cidCountByteData);
+        return cidCountByteData;
     }
 
-    private void writeTopDictStringEntry(DICTEntry dictEntry) throws IOException {
+    private byte[] writeTopDictStringEntry(DICTEntry dictEntry) throws IOException {
         int sid = dictEntry.getOperands().get(0).intValue();
         if (sid > 391) {
             stringIndexData.add(cffReader.getStringIndex().getValue(sid - 391));
@@ -307,7 +315,7 @@ public class OTFSubSetFile extends OTFSu
 
         byte[] newDictEntry = createNewRef(stringIndexData.size() + 390, dictEntry.getOperator(),
                 dictEntry.getOperandLength(), true);
-        writeBytes(newDictEntry);
+        return newDictEntry;
     }
 
     private void writeStringIndex() throws IOException {
@@ -906,17 +914,21 @@ public class OTFSubSetFile extends OTFSu
     }
 
     protected int writeIndex(List<byte[]> dataArray) {
+        int totLength = 1;
+        for (byte[] aDataArray1 : dataArray) {
+            totLength += aDataArray1.length;
+        }
+        int offSize = getOffSize(totLength);
+        return writeIndex(dataArray, offSize);
+    }
+
+    protected int writeIndex(List<byte[]> dataArray, int offSize) {
         int hdrTotal = 3;
         //2 byte number of items
         this.writeCard16(dataArray.size());
         //Offset Size: 1 byte = 256, 2 bytes = 65536 etc.
         //Offsets in the offset array are relative to the byte that precedes the object data.
         //Therefore the first element of the offset array is always 1.
-        int totLength = 1;
-        for (byte[] aDataArray1 : dataArray) {
-            totLength += aDataArray1.length;
-        }
-        int offSize = getOffSize(totLength);
         this.writeByte(offSize);
         //Count the first offset 1
         hdrTotal += offSize;
@@ -1126,11 +1138,15 @@ 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);
             break;
         case 2:
+            assert replacement <= 1131;
             if (replacement <= -876) {
                 out[position] = (byte)254;
             } else if (replacement <= -620) {
@@ -1155,6 +1171,7 @@ public class OTFSubSetFile extends OTFSu
             }
             break;
         case 3:
+            assert replacement <= 32767;
             out[position] = (byte)28;
             out[position + 1] = (byte)((replacement >> 8) & 0xFF);
             out[position + 2] = (byte)(replacement & 0xFF);

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=1806787&r1=1806786&r2=1806787&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 Thu Aug 31 12:31:03 2017
@@ -435,8 +435,8 @@ public class OTFSubSetFileTestCase exten
 
     @Test
     public void testFDSelect() throws IOException {
-        Assert.assertEquals(getSubset(1).length, 41);
-        Assert.assertEquals(getSubset(2).length, 48);
+        Assert.assertEquals(getSubset(1).length, 43);
+        Assert.assertEquals(getSubset(2).length, 50);
     }
 
     private byte[] getSubset(final int opLen) throws IOException {
@@ -480,7 +480,7 @@ public class OTFSubSetFileTestCase exten
             when(cffReader.getHeader()).thenReturn(new byte[0]);
             when(cffReader.getTopDictIndex()).thenReturn(new CFFDataReader().new CFFIndexData() {
                 public byte[] getByteData() throws IOException {
-                    return new byte[3];
+                    return new byte[] {0, 0, 1};
                 }
             });
 
@@ -501,4 +501,19 @@ public class OTFSubSetFileTestCase exten
             super.updateFixedOffsets(topDICT, dataTopDictOffset, charsetOffset, charStringOffset, encodingOffset);
         }
     }
+
+    @Test
+    public void testResizeOfOperand() throws IOException {
+        OTFSubSetFile otfSubSetFile = new OTFSubSetFile() {
+            protected void writeFDSelect() {
+                super.writeFDSelect();
+                writeBytes(new byte[1024 * 100]);
+            }
+        };
+        otfSubSetFile.readFont(sourceSansReader, "StandardOpenType", null, glyphs);
+        byte[] fontSubset = otfSubSetFile.getFontSubset();
+        CFFDataReader cffReader = new CFFDataReader(fontSubset);
+        assertEquals(cffReader.getTopDictEntries().get("CharStrings").getOperandLength(), 5);
+        assertEquals(cffReader.getTopDictEntries().get("CharStrings").getByteData().length, 6);
+    }
 }
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.