Browse Source

FOP-2750: Use streams for OTF subsetting

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1811797 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_3
Simon Steiner 6 years ago
parent
commit
c803867f45

+ 51
- 46
fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java View File

@@ -19,8 +19,10 @@

package org.apache.fop.fonts.truetype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -128,16 +130,11 @@ public class OTFSubSetFile extends OTFSubSetWriter {
this.mbFont = mbFont;
fontFile = in;

currentPos = 0;
realSize = 0;

this.embeddedName = embeddedName;

//Sort by the new GID and store in a LinkedHashMap
subsetGlyphs = sortByValue(usedGlyphs);

output = new byte[in.getFileSize()];

initializeFont(in);

cffReader = new CFFDataReader(fontFile);
@@ -710,7 +707,13 @@ public class OTFSubSetFile extends OTFSubSetWriter {
return 1 + (hstemCount + vstemCount - 1) / 8;
}

public int exec(int b0, byte[] data, int dataPos) {
private int exec(int b0, byte[] input, int curPos) throws IOException {
ByteArrayInputStream bis = new ByteArrayInputStream(input);
bis.skip(curPos + 1);
return exec(b0, bis);
}

public int exec(int b0, InputStream data) throws IOException {
int posDelta = 0;
if ((b0 >= 0 && b0 <= 27) || (b0 >= 29 && b0 <= 31)) {
if (b0 == 12) {
@@ -739,7 +742,7 @@ public class OTFSubSetFile extends OTFSubSetWriter {
lastOp = b0;
}
} else if (b0 == 28 || (b0 >= 32 && b0 <= 255)) {
BytesNumber operand = readNumber(b0, data, dataPos);
BytesNumber operand = readNumber(b0, data);
pushOperand(operand);
posDelta = operand.getNumBytes() - 1;
} else {
@@ -748,24 +751,24 @@ public class OTFSubSetFile extends OTFSubSetWriter {
return posDelta;
}

private BytesNumber readNumber(int b0, byte[] input, int curPos) {
private BytesNumber readNumber(int b0, InputStream input) throws IOException {
if (b0 == 28) {
int b1 = input[curPos + 1] & 0xff;
int b2 = input[curPos + 2] & 0xff;
int b1 = input.read();
int b2 = input.read();
return new BytesNumber((int) (short) (b1 << 8 | b2), 3);
} else if (b0 >= 32 && b0 <= 246) {
return new BytesNumber(b0 - 139, 1);
} else if (b0 >= 247 && b0 <= 250) {
int b1 = input[curPos + 1] & 0xff;
int b1 = input.read();
return new BytesNumber((b0 - 247) * 256 + b1 + 108, 2);
} else if (b0 >= 251 && b0 <= 254) {
int b1 = input[curPos + 1] & 0xff;
int b1 = input.read();
return new BytesNumber(-(b0 - 251) * 256 - b1 - 108, 2);
} else if (b0 == 255) {
int b1 = input[curPos + 1] & 0xff;
int b2 = input[curPos + 2] & 0xff;
int b3 = input[curPos + 3] & 0xff;
int b4 = input[curPos + 4] & 0xff;
int b1 = input.read();
int b2 = input.read();
int b3 = input.read();
int b4 = input.read();
return new BytesNumber((b1 << 24 | b2 << 16 | b3 << 8 | b4), 5);
} else {
throw new IllegalArgumentException();
@@ -778,33 +781,28 @@ public class OTFSubSetFile extends OTFSubSetWriter {
for (int dataPos = 0; dataPos < data.length; dataPos++) {
int b0 = data[dataPos] & 0xff;
if (b0 == LOCAL_SUBROUTINE && hasLocalSubroutines) {
int subrNumber = getSubrNumber(localIndexSubr.getNumObjects(), type2Parser.popOperand().getNumber());
if (!localUniques.contains(subrNumber) && subrNumber < localIndexSubr.getNumObjects()) {
localUniques.add(subrNumber);
}
if (subrNumber < localIndexSubr.getNumObjects()) {
byte[] subr = localIndexSubr.getValue(subrNumber);
preScanForSubsetIndexSize(subr);
} else {
throw new IllegalArgumentException("callsubr out of range");
}
preScanForSubsetIndexSize(localIndexSubr, localUniques);
} else if (b0 == GLOBAL_SUBROUTINE && hasGlobalSubroutines) {
int subrNumber = getSubrNumber(globalIndexSubr.getNumObjects(), type2Parser.popOperand().getNumber());
if (!globalUniques.contains(subrNumber) && subrNumber < globalIndexSubr.getNumObjects()) {
globalUniques.add(subrNumber);
}
if (subrNumber < globalIndexSubr.getNumObjects()) {
byte[] subr = globalIndexSubr.getValue(subrNumber);
preScanForSubsetIndexSize(subr);
} else {
throw new IllegalArgumentException("callgsubr out of range");
}
preScanForSubsetIndexSize(globalIndexSubr, globalUniques);
} else {
dataPos += type2Parser.exec(b0, data, dataPos);
}
}
}

private void preScanForSubsetIndexSize(CFFIndexData indexSubr, List<Integer> uniques) throws IOException {
int subrNumber = getSubrNumber(indexSubr.getNumObjects(), type2Parser.popOperand().getNumber());
if (!uniques.contains(subrNumber) && subrNumber < indexSubr.getNumObjects()) {
uniques.add(subrNumber);
}
if (subrNumber < indexSubr.getNumObjects()) {
byte[] subr = indexSubr.getValue(subrNumber);
preScanForSubsetIndexSize(subr);
} else {
throw new IllegalArgumentException("callgsubr out of range");
}
}

private int getSubrNumber(int numSubroutines, int operand) {
int bias = getBias(numSubroutines);
return bias + operand;
@@ -1111,57 +1109,64 @@ public class OTFSubSetFile extends OTFSubSetWriter {
if (privateDICT != null) {
//Private index offset in the top dict
int oldPrivateOffset = offsets.topDictData + privateEntry.getOffset();
updateOffset(output, oldPrivateOffset + privateEntry.getOperandLengths().get(0),
updateOffset(oldPrivateOffset + privateEntry.getOperandLengths().get(0),
privateEntry.getOperandLengths().get(1), offsets.privateDict);

//Update the local subroutine index offset in the private dict
DICTEntry subroutines = privateDICT.get("Subrs");
if (subroutines != null) {
int oldLocalSubrOffset = offsets.privateDict + subroutines.getOffset();
updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(),
updateOffset(oldLocalSubrOffset, subroutines.getOperandLength(),
(offsets.localIndex - offsets.privateDict));
}
}
}

protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, Offsets offsets) {
protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, Offsets offsets) throws IOException {
//Charset offset in the top dict
DICTEntry charset = topDICT.get("charset");
int oldCharsetOffset = offsets.topDictData + charset.getOffset();
updateOffset(output, oldCharsetOffset, charset.getOperandLength(), offsets.charset);
updateOffset(oldCharsetOffset, charset.getOperandLength(), offsets.charset);

//Char string index offset in the private dict
DICTEntry charString = topDICT.get("CharStrings");
int oldCharStringOffset = offsets.topDictData + charString.getOffset();
updateOffset(output, oldCharStringOffset, charString.getOperandLength(), offsets.charString);
updateOffset(oldCharStringOffset, charString.getOperandLength(), offsets.charString);

DICTEntry encodingEntry = topDICT.get("Encoding");
if (encodingEntry != null && encodingEntry.getOperands().get(0).intValue() != 0
&& encodingEntry.getOperands().get(0).intValue() != 1) {
int oldEncodingOffset = offsets.topDictData + encodingEntry.getOffset();
updateOffset(output, oldEncodingOffset, encodingEntry.getOperandLength(), offsets.encoding);
updateOffset(oldEncodingOffset, encodingEntry.getOperandLength(), offsets.encoding);
}
}

protected void updateCIDOffsets(Offsets offsets) {
protected void updateCIDOffsets(Offsets offsets) throws IOException {
Map<String, DICTEntry> topDict = cffReader.getTopDictEntries();

DICTEntry fdArrayEntry = topDict.get("FDArray");
if (fdArrayEntry != null) {
updateOffset(output, offsets.topDictData + fdArrayEntry.getOffset() - 1,
updateOffset(offsets.topDictData + fdArrayEntry.getOffset() - 1,
fdArrayEntry.getOperandLength(), offsets.fdArray);
}

DICTEntry fdSelect = topDict.get("FDSelect");
if (fdSelect != null) {
updateOffset(output, offsets.topDictData + fdSelect.getOffset() - 1,
updateOffset(offsets.topDictData + fdSelect.getOffset() - 1,
fdSelect.getOperandLength(), offsets.fdSelect);
}

updateFixedOffsets(topDict, offsets);
}

protected void updateOffset(byte[] out, int position, int length, int replacement) {
private void updateOffset(int position, int length, int replacement) throws IOException {
byte[] outBytes = output.toByteArray();
updateOffset(outBytes, position, length, replacement);
output.reset();
output.write(outBytes);
}

private void updateOffset(byte[] out, int position, int length, int replacement) {
switch (length) {
case 1:
out[position] = (byte)(replacement + 139);

+ 5
- 14
fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetWriter.java View File

@@ -18,12 +18,12 @@
/* $Id$ */
package org.apache.fop.fonts.truetype;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class OTFSubSetWriter extends OTFFile {
protected int currentPos;
protected int realSize;
protected byte[] output;
protected ByteArrayOutputStream output = new ByteArrayOutputStream();

public OTFSubSetWriter() throws IOException {
super();
@@ -43,8 +43,8 @@ public class OTFSubSetWriter extends OTFFile {
* updates currentPost but not realSize
*/
protected void writeByte(int b) {
output[currentPos++] = (byte)b;
realSize++;
output.write(b);
currentPos++;
}

/**
@@ -89,21 +89,12 @@ public class OTFSubSetWriter extends OTFFile {
}
}

protected void writeBytes(byte[] out, int offset, int length) {
for (int i = offset; i < offset + length; i++) {
output[currentPos++] = out[i];
realSize++;
}
}

/**
* Returns a subset of the fonts (readFont() MUST be called first in order to create the
* subset).
* @return byte array
*/
public byte[] getFontSubset() {
byte[] ret = new byte[realSize];
System.arraycopy(output, 0, ret, 0, realSize);
return ret;
return output.toByteArray();
}
}

+ 2
- 4
fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java View File

@@ -508,7 +508,7 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
super.createCFF();
}

protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, Offsets offsets) {
protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, Offsets offsets) throws IOException {
this.charsetOffset = offsets.charset;
super.updateFixedOffsets(topDICT, offsets);
}
@@ -621,7 +621,7 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
super.createCFF();
}

protected void updateCIDOffsets(Offsets offsets) {
protected void updateCIDOffsets(Offsets offsets) throws IOException {
super.updateCIDOffsets(offsets);
this.offsets = offsets;
}
@@ -658,7 +658,6 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
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[]>());
@@ -682,7 +681,6 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
OTFSubSetFile otfSubSetFile = new OTFSubSetFile() {
void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont,
Map<Integer, Integer> usedGlyphs) throws IOException {
output = new byte[7];
cffReader = makeCFFDataReader();
LinkedHashMap<String, DICTEntry> topDict = new LinkedHashMap<String, DICTEntry>();
DICTEntry entry = new DICTEntry();

Loading…
Cancel
Save