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.