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.