Browse Source

Allow merging of fonts

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FontMerging@1600606 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Simon Steiner 10 years ago
parent
commit
4516274b5d
26 changed files with 415 additions and 204 deletions
  1. 7
    0
      findbugs-exclude.xml
  2. BIN
      lib/fontbox-1.8.5.jar
  3. BIN
      lib/fontbox-2.0.0-SNAPSHOT.jar
  4. 10
    7
      src/java/org/apache/fop/fonts/CustomFont.java
  5. 4
    0
      src/java/org/apache/fop/fonts/FontType.java
  6. 26
    24
      src/java/org/apache/fop/fonts/MultiByteFont.java
  7. 2
    2
      src/java/org/apache/fop/fonts/SingleByteFont.java
  8. 3
    1
      src/java/org/apache/fop/fonts/cff/CFFDataReader.java
  9. 6
    6
      src/java/org/apache/fop/fonts/truetype/GlyfTable.java
  10. 1
    1
      src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java
  11. 1
    1
      src/java/org/apache/fop/fonts/truetype/OTFFile.java
  12. 55
    56
      src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
  13. 8
    3
      src/java/org/apache/fop/fonts/truetype/OpenFont.java
  14. 61
    49
      src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
  15. 1
    1
      src/java/org/apache/fop/pdf/AbstractPDFStream.java
  16. 57
    0
      src/java/org/apache/fop/pdf/PDFCFFStream.java
  17. 10
    0
      src/java/org/apache/fop/pdf/PDFDocument.java
  18. 124
    50
      src/java/org/apache/fop/pdf/PDFFactory.java
  19. 2
    1
      src/java/org/apache/fop/pdf/PDFFont.java
  20. 1
    1
      src/java/org/apache/fop/pdf/PDFFontDescriptor.java
  21. 21
    0
      src/java/org/apache/fop/pdf/RefPDFFont.java
  22. 1
    1
      src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
  23. 2
    0
      src/java/org/apache/fop/render/pdf/PDFRendererConfig.java
  24. 6
    0
      src/java/org/apache/fop/render/pdf/PDFRendererOption.java
  25. 5
    0
      src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java
  26. 1
    0
      src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java

+ 7
- 0
findbugs-exclude.xml View File

<Method name="hasValueOfElementName"/> <Method name="hasValueOfElementName"/>
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
</Match> </Match>
<Match>
<Class name="org.apache.fop.pdf.PDFCFFStream"/>
<Or>
<Bug pattern="EI_EXPOSE_REP"/>
<Bug pattern="EI_EXPOSE_REP2"/>
</Or>
</Match>
</FindBugsFilter> </FindBugsFilter>

BIN
lib/fontbox-1.8.5.jar View File


BIN
lib/fontbox-2.0.0-SNAPSHOT.jar View File


+ 10
- 7
src/java/org/apache/fop/fonts/CustomFont.java View File

import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;


private Map<Integer, Map<Integer, Integer>> kerning; private Map<Integer, Map<Integer, Integer>> kerning;


private boolean useKerning = true; private boolean useKerning = true;
/** the character map, mapping Unicode ranges to glyph indices. */
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>();
private boolean useAdvanced = true; private boolean useAdvanced = true;


/** /**
public CustomFont(InternalResourceResolver resourceResolver) { public CustomFont(InternalResourceResolver resourceResolver) {
this.resourceResolver = resourceResolver; this.resourceResolver = resourceResolver;
} }
/** the character map, mapping Unicode ranges to glyph indices. */
protected CMapSegment[] cmap;



/** {@inheritDoc} */ /** {@inheritDoc} */
public String getFontName() { public String getFontName() {
* @param cmap the character map * @param cmap the character map
*/ */
public void setCMap(CMapSegment[] cmap) { public void setCMap(CMapSegment[] cmap) {
this.cmap = new CMapSegment[cmap.length];
System.arraycopy(cmap, 0, this.cmap, 0, cmap.length);
this.cmap.clear();
for (CMapSegment c : cmap) {
this.cmap.add(c);
}
} }


/** /**
* @return the character map * @return the character map
*/ */
public CMapSegment[] getCMap() { public CMapSegment[] getCMap() {
CMapSegment[] copy = new CMapSegment[cmap.length];
System.arraycopy(this.cmap, 0, copy, 0, this.cmap.length);
return copy;
return cmap.toArray(new CMapSegment[cmap.size()]);
} }


public int getUnderlinePosition(int size) { public int getUnderlinePosition(int size) {

+ 4
- 0
src/java/org/apache/fop/fonts/FontType.java View File

*/ */
public static final FontType TRUETYPE = new FontType("TrueType", 5); public static final FontType TRUETYPE = new FontType("TrueType", 5);


public static final FontType TYPE1C = new FontType("Type1C", 6);

public static final FontType CIDTYPE0 = new FontType("CIDFontType0", 7);

private final String name; private final String name;
private final int value; private final int value;



+ 26
- 24
src/java/org/apache/fop/fonts/MultiByteFont.java View File

package org.apache.fop.fonts; package org.apache.fop.fonts;


import java.awt.Rectangle; import java.awt.Rectangle;
import java.io.InputStream;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.BitSet; import java.util.BitSet;
private int defaultWidth; private int defaultWidth;
private CIDFontType cidType = CIDFontType.CIDTYPE2; private CIDFontType cidType = CIDFontType.CIDTYPE2;


private final CIDSet cidSet;
protected final CIDSet cidSet;


/* advanced typographic support */ /* advanced typographic support */
private GlyphDefinitionTable gdef; private GlyphDefinitionTable gdef;
if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) {
return mostLikelyGlyphs[idx]; return mostLikelyGlyphs[idx];
} }
for (int i = 0; (i < cmap.length) && retIdx == 0; i++) {
if (cmap[i].getUnicodeStart() <= idx
&& cmap[i].getUnicodeEnd() >= idx) {
retIdx = cmap[i].getGlyphStartIndex()
for (CMapSegment i : cmap) {
if (retIdx == 0
&& i.getUnicodeStart() <= idx
&& i.getUnicodeEnd() >= idx) {
retIdx = i.getGlyphStartIndex()
+ idx + idx
- cmap[i].getUnicodeStart();
- i.getUnicodeStart();
if (idx < NUM_MOST_LIKELY_GLYPHS) { if (idx < NUM_MOST_LIKELY_GLYPHS) {
mostLikelyGlyphs[idx] = retIdx; mostLikelyGlyphs[idx] = retIdx;
} }
* Add a private use mapping {PU,GI} to the existing character map. * Add a private use mapping {PU,GI} to the existing character map.
* N.B. Does not insert in order, merely appends to end of existing map. * N.B. Does not insert in order, merely appends to end of existing map.
*/ */
private synchronized void addPrivateUseMapping(int pu, int gi) {
protected synchronized void addPrivateUseMapping(int pu, int gi) {
assert findGlyphIndex(pu) == SingleByteEncoding.NOT_FOUND_CODE_POINT; assert findGlyphIndex(pu) == SingleByteEncoding.NOT_FOUND_CODE_POINT;
CMapSegment[] oldCmap = cmap;
int cmapLength = oldCmap.length;
CMapSegment[] newCmap = new CMapSegment [ cmapLength + 1 ];
System.arraycopy(oldCmap, 0, newCmap, 0, cmapLength);
newCmap [ cmapLength ] = new CMapSegment(pu, pu, gi);
cmap = newCmap;
cmap.add(new CMapSegment(pu, pu, gi));
} }


/** /**
// [TBD] - needs optimization, i.e., change from linear search to binary search // [TBD] - needs optimization, i.e., change from linear search to binary search
private int findCharacterFromGlyphIndex(int gi, boolean augment) { private int findCharacterFromGlyphIndex(int gi, boolean augment) {
int cc = 0; int cc = 0;
for (int i = 0, n = cmap.length; i < n; i++) {
CMapSegment segment = cmap [ i ];
for (CMapSegment segment : cmap) {
int s = segment.getGlyphStartIndex(); int s = segment.getGlyphStartIndex();
int e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart()); int e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart());
if ((gi >= s) && (gi <= e)) { if ((gi >= s) && (gi <= e)) {
bitset.set(0); bitset.set(0);
bitset.set(1); bitset.set(1);
bitset.set(2); bitset.set(2);
for (int i = 0; i < cmap.length; i++) {
int start = cmap[i].getUnicodeStart();
int end = cmap[i].getUnicodeEnd();
int glyphIndex = cmap[i].getGlyphStartIndex();
for (CMapSegment i : cmap) {
int start = i.getUnicodeStart();
int end = i.getUnicodeEnd();
int glyphIndex = i.getGlyphStartIndex();
while (start++ < end + 1) { while (start++ < end + 1) {
bitset.set(glyphIndex++); bitset.set(glyphIndex++);
} }
protected char[] getChars() { protected char[] getChars() {
// the width array is set when the font is built // the width array is set when the font is built
char[] chars = new char[width.length]; char[] chars = new char[width.length];
for (int i = 0; i < cmap.length; i++) {
int start = cmap[i].getUnicodeStart();
int end = cmap[i].getUnicodeEnd();
int glyphIndex = cmap[i].getGlyphStartIndex();
for (CMapSegment i : cmap) {
int start = i.getUnicodeStart();
int end = i.getUnicodeEnd();
int glyphIndex = i.getGlyphStartIndex();
while (start < end + 1) { while (start < end + 1) {
chars[glyphIndex++] = (char) start++; chars[glyphIndex++] = (char) start++;
} }
return cb; return cb;
} }


public Map<Integer, Integer> getWidthsMap() {
return null;
}

public InputStream getCmapStream() {
return null;
}
} }



+ 2
- 2
src/java/org/apache/fop/fonts/SingleByteFont.java View File

/** logger */ /** logger */
private static Log log = LogFactory.getLog(SingleByteFont.class); private static Log log = LogFactory.getLog(SingleByteFont.class);


private SingleByteEncoding mapping;
protected SingleByteEncoding mapping;
private boolean useNativeEncoding = false; private boolean useNativeEncoding = false;


private int[] width = null;
protected int[] width = null;


private Rectangle[] boundingBoxes; private Rectangle[] boundingBoxes;



+ 3
- 1
src/java/org/apache/fop/fonts/cff/CFFDataReader.java View File

LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData);
newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i));
DICTEntry fontFDEntry = fdEntries.get("FontName"); DICTEntry fontFDEntry = fdEntries.get("FontName");
newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue()));
if (fontFDEntry != null) {
newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue()));
}
DICTEntry privateFDEntry = fdEntries.get("Private"); DICTEntry privateFDEntry = fdEntries.get("Private");
if (privateFDEntry != null) { if (privateFDEntry != null) {
newFontDict = setFDData(privateFDEntry, newFontDict); newFontDict = setFDData(privateFDEntry, newFontDict);

+ 6
- 6
src/java/org/apache/fop/fonts/truetype/GlyfTable.java View File



private final Set<Long> remappedComposites; private final Set<Long> remappedComposites;


private final Map<Integer, Integer> subset;
protected final Map<Integer, Integer> subset;


private final FontFileReader in; private final FontFileReader in;


private Set<Integer> compositeGlyphs = new TreeSet<Integer>(); private Set<Integer> compositeGlyphs = new TreeSet<Integer>();


/** All the glyphs that are composed, but do not appear in the subset. */ /** All the glyphs that are composed, but do not appear in the subset. */
private Set<Integer> composedGlyphs = new TreeSet<Integer>();
protected Set<Integer> composedGlyphs = new TreeSet<Integer>();


GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry,
Map<Integer, Integer> glyphs) throws IOException {
protected GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry,
Map<Integer, Integer> glyphs) throws IOException {
mtxTab = metrics; mtxTab = metrics;
tableOffset = dirTableEntry.getOffset(); tableOffset = dirTableEntry.getOffset();
remappedComposites = new HashSet<Long>(); remappedComposites = new HashSet<Long>();
* *
* @throws IOException an I/O error * @throws IOException an I/O error
*/ */
void populateGlyphsWithComposites() throws IOException {
protected void populateGlyphsWithComposites() throws IOException {
for (int indexInOriginal : subset.keySet()) { for (int indexInOriginal : subset.keySet()) {
scanGlyphsRecursively(indexInOriginal); scanGlyphsRecursively(indexInOriginal);
} }
* Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves * Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves
* in the subset. * in the subset.
*/ */
private void addAllComposedGlyphsToSubset() {
protected void addAllComposedGlyphsToSubset() {
int newIndex = subset.size(); int newIndex = subset.size();
for (int composedGlyph : composedGlyphs) { for (int composedGlyph : composedGlyphs) {
subset.put(composedGlyph, newIndex++); subset.put(composedGlyph, newIndex++);

+ 1
- 1
src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java View File

/** /**
* This class represents a TrueType Mtx Entry. * This class represents a TrueType Mtx Entry.
*/ */
class OFMtxEntry {
public class OFMtxEntry {


private int wx; private int wx;
private int lsb; private int lsb;

+ 1
- 1
src/java/org/apache/fop/fonts/truetype/OTFFile.java View File

* @return The byte data found in the CFF table * @return The byte data found in the CFF table
*/ */
public static byte[] getCFFData(FontFileReader fontFile) throws IOException { public static byte[] getCFFData(FontFileReader fontFile) throws IOException {
byte[] cff = new byte[0];
byte[] cff = fontFile.getAllBytes();
CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); CFFDataInput input = new CFFDataInput(fontFile.getAllBytes());
input.readBytes(4); //OTTO input.readBytes(4); //OTTO
short numTables = input.readShort(); short numTables = input.readShort();

+ 55
- 56
src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java View File

*/ */
public class OTFSubSetFile extends OTFFile { public class OTFSubSetFile extends OTFFile {


private byte[] output;
private int currentPos = 0;
protected byte[] output;
protected int currentPos = 0;
private int realSize = 0; private int realSize = 0;


/** A map containing each glyph to be included in the subset /** A map containing each glyph to be included in the subset
* with their existing and new GID's **/ * with their existing and new GID's **/
private LinkedHashMap<Integer, Integer> subsetGlyphs;
protected LinkedHashMap<Integer, Integer> subsetGlyphs = new LinkedHashMap<Integer, Integer>();


/** A map of the new GID to SID used to construct the charset table **/ /** A map of the new GID to SID used to construct the charset table **/
private LinkedHashMap<Integer, Integer> gidToSID;
protected LinkedHashMap<Integer, Integer> gidToSID;


private CFFIndexData localIndexSubr;
private CFFIndexData globalIndexSubr;
protected CFFIndexData localIndexSubr;
protected CFFIndexData globalIndexSubr;


/** List of subroutines to write to the local / global indexes in the subset font **/ /** List of subroutines to write to the local / global indexes in the subset font **/
private List<byte[]> subsetLocalIndexSubr;
private List<byte[]> subsetGlobalIndexSubr;
protected List<byte[]> subsetLocalIndexSubr;
protected List<byte[]> subsetGlobalIndexSubr;


/** For fonts which have an FDSelect or ROS flag in Top Dict, this is used to store the /** 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 */ * local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */
private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect; private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect;


/** A list of unique subroutines from the global / local subroutine indexes */ /** A list of unique subroutines from the global / local subroutine indexes */
private List<Integer> localUniques;
private List<Integer> globalUniques;
protected List<Integer> localUniques;
protected List<Integer> globalUniques;


/** A store of the number of subroutines each global / local subroutine will store **/ /** A store of the number of subroutines each global / local subroutine will store **/
private int subsetLocalSubrCount;
private int subsetGlobalSubrCount;
protected int subsetLocalSubrCount;
protected int subsetGlobalSubrCount;


/** A list of char string data for each glyph to be stored in the subset font **/ /** A list of char string data for each glyph to be stored in the subset font **/
private List<byte[]> subsetCharStringsIndex;
protected List<byte[]> subsetCharStringsIndex;


/** The embedded name to change in the name table **/ /** The embedded name to change in the name table **/
private String embeddedName;
protected String embeddedName;


/** An array used to hold the string index data for the subset font **/ /** An array used to hold the string index data for the subset font **/
private List<byte[]> stringIndexData = new ArrayList<byte[]>();
protected List<byte[]> stringIndexData = new ArrayList<byte[]>();


/** The CFF reader object used to read data and offsets from the original font file */ /** The CFF reader object used to read data and offsets from the original font file */
private CFFDataReader cffReader = null;
protected CFFDataReader cffReader = null;


/** The class used to represent this font **/ /** The class used to represent this font **/
private MultiByteFont mbFont; private MultiByteFont mbFont;


/** The number of standard strings in CFF **/ /** The number of standard strings in CFF **/
private static final int NUM_STANDARD_STRINGS = 391;
public static final int NUM_STANDARD_STRINGS = 391;
/** The operator used to identify a local subroutine reference */ /** The operator used to identify a local subroutine reference */
private static final int LOCAL_SUBROUTINE = 10; private static final int LOCAL_SUBROUTINE = 10;
/** The operator used to identify a global subroutine reference */ /** The operator used to identify a global subroutine reference */
return result; return result;
} }


private void createCFF() throws IOException {
protected void createCFF() throws IOException {
//Header //Header
writeBytes(cffReader.getHeader()); writeBytes(cffReader.getHeader());


} }
} }


private List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException {
protected List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException {
ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>(); ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>();
List<FontDict> fdFonts = cffReader.getFDFonts(); List<FontDict> fdFonts = cffReader.getFDFonts();
for (int i = 0; i < uniqueNewRefs.size(); i++) { for (int i = 0; i < uniqueNewRefs.size(); i++) {
return fontNameSIDs; return fontNameSIDs;
} }


private void writeBytes(byte[] out) {
protected void writeBytes(byte[] out) {
for (int i = 0; i < out.length; i++) { for (int i = 0; i < out.length; i++) {
output[currentPos++] = out[i];
realSize++;
writeByte(out[i]);
} }
} }


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


private void writeTopDICT() throws IOException {
protected void writeTopDICT() throws IOException {
LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries();
List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright", List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright",
"FullName", "FamilyName", "Weight", "PostScript"); "FullName", "FamilyName", "Weight", "PostScript");
writeBytes(cidEntryByteData); writeBytes(cidEntryByteData);
} }


private void writeCIDCount(DICTEntry dictEntry) throws IOException {
protected void writeCIDCount(DICTEntry dictEntry) throws IOException {
byte[] cidCountByteData = dictEntry.getByteData(); byte[] cidCountByteData = dictEntry.getByteData();
cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0), cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0),
subsetGlyphs.size()); subsetGlyphs.size());
writeIndex(stringIndexData); writeIndex(stringIndexData);
} }


private void createCharStringDataCID() throws IOException {
protected void createCharStringDataCID() throws IOException {
CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); CFFIndexData charStringsIndex = cffReader.getCharStringIndex();


FDSelect fontDictionary = cffReader.getFDSelect(); FDSelect fontDictionary = cffReader.getFDSelect();
localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex());
byte[] data = charStringsIndex.getValue(gid); byte[] data = charStringsIndex.getValue(gid);
subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex());
subsetLocalSubrCount = foundLocalUniques.get(
subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()).size();
subsetLocalSubrCount = foundLocalUniques.get(subsetFDSelect.get(subsetGlyphs.get(gid))
.getNewFDIndex()).size();
data = readCharStringData(data, subsetLocalSubrCount); data = readCharStringData(data, subsetLocalSubrCount);
subsetCharStringsIndex.add(data); subsetCharStringsIndex.add(data);
} }
} }
} }


private void writeFDSelect() {
protected void writeFDSelect() {
writeByte(0); //Format writeByte(0); //Format
for (Integer gid : subsetFDSelect.keySet()) { for (Integer gid : subsetFDSelect.keySet()) {
writeByte(subsetFDSelect.get(gid).getNewFDIndex()); writeByte(subsetFDSelect.get(gid).getNewFDIndex());
} }
} }


private List<Integer> getUsedFDFonts() {
protected List<Integer> getUsedFDFonts() {
List<Integer> uniqueNewRefs = new ArrayList<Integer>(); List<Integer> uniqueNewRefs = new ArrayList<Integer>();
for (int gid : subsetFDSelect.keySet()) { for (int gid : subsetFDSelect.keySet()) {
int fdIndex = subsetFDSelect.get(gid).getOldFDIndex(); int fdIndex = subsetFDSelect.get(gid).getOldFDIndex();
return uniqueNewRefs; return uniqueNewRefs;
} }


private List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs)
protected List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs)
throws IOException { throws IOException {
List<Integer> privateDictOffsets = new ArrayList<Integer>(); List<Integer> privateDictOffsets = new ArrayList<Integer>();
List<FontDict> fdFonts = cffReader.getFDFonts(); List<FontDict> fdFonts = cffReader.getFDFonts();
return privateDictOffsets; return privateDictOffsets;
} }


private int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets,
protected int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets,
List<Integer> fontNameSIDs) List<Integer> fontNameSIDs)
throws IOException { throws IOException {
int offset = currentPos; int offset = currentPos;
return c; return c;
} }


private int writeIndex(List<byte[]> dataArray) {
protected int writeIndex(List<byte[]> dataArray) {
int hdrTotal = 3; int hdrTotal = 3;
//2 byte number of items //2 byte number of items
this.writeCard16(dataArray.size()); this.writeCard16(dataArray.size());
} }
} }


private void writePrivateDict() throws IOException {
protected void writePrivateDict() throws IOException {
Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries();


DICTEntry privateEntry = topDICT.get("Private"); DICTEntry privateEntry = topDICT.get("Private");
} }
} }


private void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset,
protected void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset,
int privateDictOffset, int localIndexOffset, int encodingOffset) int privateDictOffset, int localIndexOffset, int encodingOffset)
throws IOException { throws IOException {
Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries();


//Update the local subroutine index offset in the private dict //Update the local subroutine index offset in the private dict
DICTEntry subroutines = privateDICT.get("Subrs"); DICTEntry subroutines = privateDICT.get("Subrs");
int oldLocalSubrOffset = privateDictOffset + subroutines.getOffset();
//Value needs to be converted to -139 etc.
int encodeValue = 0;
if (subroutines.getOperandLength() == 1) {
encodeValue = 139;
if (subroutines != null) {
int oldLocalSubrOffset = privateDictOffset + subroutines.getOffset();
//Value needs to be converted to -139 etc.
int encodeValue = 0;
if (subroutines.getOperandLength() == 1) {
encodeValue = 139;
}
output = updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(),
(localIndexOffset - privateDictOffset) + encodeValue);
} }
output = updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(),
(localIndexOffset - privateDictOffset) + encodeValue);
} }
} }


private void updateFixedOffsets(Map<String, DICTEntry> topDICT, int dataTopDictOffset,
protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, int dataTopDictOffset,
int charsetOffset, int charStringOffset, int encodingOffset) { int charsetOffset, int charStringOffset, int encodingOffset) {
//Charset offset in the top dict //Charset offset in the top dict
DICTEntry charset = topDICT.get("charset"); DICTEntry charset = topDICT.get("charset");
} }
} }


private void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset,
protected void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset,
int charsetOffset, int charStringOffset, int encodingOffset) { int charsetOffset, int charStringOffset, int encodingOffset) {
LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries(); LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries();


updateFixedOffsets(topDict, topDictDataOffset, charsetOffset, charStringOffset, encodingOffset); updateFixedOffsets(topDict, topDictDataOffset, charsetOffset, charStringOffset, encodingOffset);
} }


private byte[] updateOffset(byte[] out, int position, int length, int replacement) {
protected byte[] updateOffset(byte[] out, int position, int length, int replacement) {
switch (length) { switch (length) {
case 1: case 1:
out[position] = (byte)(replacement & 0xFF); out[position] = (byte)(replacement & 0xFF);
* Appends a byte to the output array, * Appends a byte to the output array,
* updates currentPost but not realSize * updates currentPost but not realSize
*/ */
private void writeByte(int b) {
protected void writeByte(int b) {
output[currentPos++] = (byte)b; output[currentPos++] = (byte)b;
realSize++; realSize++;
} }
* Appends a USHORT to the output array, * Appends a USHORT to the output array,
* updates currentPost but not realSize * updates currentPost but not realSize
*/ */
private void writeCard16(int s) {
protected void writeCard16(int s) {
byte b1 = (byte)((s >> 8) & 0xff); byte b1 = (byte)((s >> 8) & 0xff);
byte b2 = (byte)(s & 0xff); byte b2 = (byte)(s & 0xff);
writeByte(b1); writeByte(b1);
byte b1 = (byte)((s >> 16) & 0xFF); byte b1 = (byte)((s >> 16) & 0xFF);
byte b2 = (byte)((s >> 8) & 0xFF); byte b2 = (byte)((s >> 8) & 0xFF);
byte b3 = (byte)(s & 0xFF); byte b3 = (byte)(s & 0xFF);
output[currentPos++] = b1;
output[currentPos++] = b2;
output[currentPos++] = b3;
realSize += 3;
writeByte(b1);
writeByte(b2);
writeByte(b3);
} }


/** /**
byte b2 = (byte)((s >> 16) & 0xff); byte b2 = (byte)((s >> 16) & 0xff);
byte b3 = (byte)((s >> 8) & 0xff); byte b3 = (byte)((s >> 8) & 0xff);
byte b4 = (byte)(s & 0xff); byte b4 = (byte)(s & 0xff);
output[currentPos++] = b1;
output[currentPos++] = b2;
output[currentPos++] = b3;
output[currentPos++] = b4;
realSize += 4;
writeByte(b1);
writeByte(b2);
writeByte(b3);
writeByte(b4);
} }


/** /**

+ 8
- 3
src/java/org/apache/fop/fonts/truetype/OpenFont.java View File

protected String notice = ""; protected String notice = "";
protected final Set<String> familyNames = new HashSet<String>(); protected final Set<String> familyNames = new HashSet<String>();
protected String subFamilyName = ""; protected String subFamilyName = "";
protected boolean cid = true;


private long italicAngle = 0; private long italicAngle = 0;
private long isFixedPitch = 0; private long isFixedPitch = 0;


unicodeMappings = new ArrayList<OpenFont.UnicodeMapping>(); unicodeMappings = new ArrayList<OpenFont.UnicodeMapping>();


seekTab(fontFile, OFTableName.CMAP, 2);
if (!seekTab(fontFile, OFTableName.CMAP, 2)) {
return true;
}
int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables
long cmapUniOffset = 0; long cmapUniOffset = 0;
long symbolMapOffset = 0; long symbolMapOffset = 0;
int unicodeStart; int unicodeStart;
int glyphStart; int glyphStart;
int unicodeEnd; int unicodeEnd;

if (unicodeMappings.isEmpty()) {
return;
}
Iterator<UnicodeMapping> e = unicodeMappings.iterator(); Iterator<UnicodeMapping> e = unicodeMappings.iterator();
UnicodeMapping um = e.next(); UnicodeMapping um = e.next();
UnicodeMapping lastMapping = um; UnicodeMapping lastMapping = um;
} }
} }


if (nhmtx < mtxSize) {
if (cid && nhmtx < mtxSize) {
// Fill in the missing widths // Fill in the missing widths
int lastWidth = mtxTab[nhmtx - 1].getWx(); int lastWidth = mtxTab[nhmtx - 1].getWx();
for (int i = nhmtx; i < mtxSize; i++) { for (int i = nhmtx; i < mtxSize; i++) {

+ 61
- 49
src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java View File

*/ */
public class TTFSubSetFile extends TTFFile { public class TTFSubSetFile extends TTFFile {


private byte[] output = null;
private int realSize = 0;
private int currentPos = 0;
protected byte[] output = null;
protected int realSize = 0;
protected int currentPos = 0;


/* /*
* Offsets in name table to be filled out by table. * Offsets in name table to be filled out by table.
* The offsets are to the checkSum field * The offsets are to the checkSum field
*/ */
private Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>();
protected Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>();


private int checkSumAdjustmentOffset = 0; private int checkSumAdjustmentOffset = 0;
private int locaOffset = 0;
protected int locaOffset = 0;


/** Stores the glyph offsets so that we can end strings at glyph boundaries */ /** Stores the glyph offsets so that we can end strings at glyph boundaries */
private int[] glyphOffsets;
protected int[] glyphOffsets;


/** /**
* Default Constructor * Default Constructor
} }


/** The dir tab entries in the new subset font. */ /** The dir tab entries in the new subset font. */
private Map<OFTableName, OFDirTabEntry> newDirTabs
protected Map<OFTableName, OFDirTabEntry> newDirTabs
= new HashMap<OFTableName, OFDirTabEntry>(); = new HashMap<OFTableName, OFDirTabEntry>();


private int determineTableCount() { private int determineTableCount() {
if (hasPrep()) { if (hasPrep()) {
numTables++; numTables++;
} }
if (!cid) {
numTables++; //cmap
}
} }
return numTables; return numTables;
} }
/** /**
* Create the directory table * Create the directory table
*/ */
private void createDirectory() {
protected void createDirectory() {
int numTables = determineTableCount(); int numTables = determineTableCount();
// Create the TrueType header // Create the TrueType header
writeByte((byte)0); writeByte((byte)0);
realSize += 2; realSize += 2;
// Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z])
writeTableName(OFTableName.OS2); writeTableName(OFTableName.OS2);

if (!cid) {
writeTableName(OFTableName.CMAP);
}
if (hasCvt()) { if (hasCvt()) {
writeTableName(OFTableName.CVT); writeTableName(OFTableName.CVT);
} }
/** /**
* Create an empty loca table without updating checksum * Create an empty loca table without updating checksum
*/ */
private void createLoca(int size) throws IOException {
protected void createLoca(int size) throws IOException {
pad4(); pad4();
locaOffset = currentPos; locaOffset = currentPos;
int dirTableOffset = offsets.get(OFTableName.LOCA); int dirTableOffset = offsets.get(OFTableName.LOCA);
if (entry != null) { if (entry != null) {
pad4(); pad4();
seekTab(in, tableName, 0); seekTab(in, tableName, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength()));


updateCheckSum(currentPos, (int) entry.getLength(), tableName); updateCheckSum(currentPos, (int) entry.getLength(), tableName);
currentPos += (int) entry.getLength(); currentPos += (int) entry.getLength();
/** /**
* Copy the cvt table as is from original font to subset font * Copy the cvt table as is from original font to subset font
*/ */
private boolean createCvt(FontFileReader in) throws IOException {
protected boolean createCvt(FontFileReader in) throws IOException {
return copyTable(in, OFTableName.CVT); return copyTable(in, OFTableName.CVT);
} }


/** /**
* Copy the fpgm table as is from original font to subset font * Copy the fpgm table as is from original font to subset font
*/ */
private boolean createFpgm(FontFileReader in) throws IOException {
protected boolean createFpgm(FontFileReader in) throws IOException {
return copyTable(in, OFTableName.FPGM); return copyTable(in, OFTableName.FPGM);
} }


/** /**
* Copy the name table as is from the original. * Copy the name table as is from the original.
*/ */
private boolean createName(FontFileReader in) throws IOException {
protected boolean createName(FontFileReader in) throws IOException {
return copyTable(in, OFTableName.NAME); return copyTable(in, OFTableName.NAME);
} }


/** /**
* Copy the OS/2 table as is from the original. * Copy the OS/2 table as is from the original.
*/ */
private boolean createOS2(FontFileReader in) throws IOException {
protected boolean createOS2(FontFileReader in) throws IOException {
return copyTable(in, OFTableName.OS2); return copyTable(in, OFTableName.OS2);
} }


* Copy the maxp table as is from original font to subset font * Copy the maxp table as is from original font to subset font
* and set num glyphs to size * and set num glyphs to size
*/ */
private void createMaxp(FontFileReader in, int size) throws IOException {
protected void createMaxp(FontFileReader in, int size) throws IOException {
OFTableName maxp = OFTableName.MAXP; OFTableName maxp = OFTableName.MAXP;
OFDirTabEntry entry = dirTabs.get(maxp); OFDirTabEntry entry = dirTabs.get(maxp);
if (entry != null) { if (entry != null) {
pad4(); pad4();
seekTab(in, maxp, 0); seekTab(in, maxp, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength()));
writeUShort(currentPos + 4, size); writeUShort(currentPos + 4, size);


updateCheckSum(currentPos, (int)entry.getLength(), maxp); updateCheckSum(currentPos, (int)entry.getLength(), maxp);
} }
} }


private void createPost(FontFileReader in) throws IOException {
protected void createPost(FontFileReader in) throws IOException {
OFTableName post = OFTableName.POST; OFTableName post = OFTableName.POST;
OFDirTabEntry entry = dirTabs.get(post); OFDirTabEntry entry = dirTabs.get(post);
if (entry != null) { if (entry != null) {
0, newPostTable, 0, newTableSize); 0, newPostTable, 0, newTableSize);
// set the post table to Format 3.0 // set the post table to Format 3.0
newPostTable[1] = 0x03; newPostTable[1] = 0x03;
System.arraycopy(newPostTable, 0, output, currentPos, newTableSize);
writeBytes(newPostTable);
updateCheckSum(currentPos, newTableSize, post); updateCheckSum(currentPos, newTableSize, post);
currentPos += newTableSize; currentPos += newTableSize;
realSize += newTableSize; realSize += newTableSize;
} else { } else {
throw new IOException("Can't find post table");
// throw new IOException("Can't find post table");
} }
} }


/** /**
* Copy the prep table as is from original font to subset font * Copy the prep table as is from original font to subset font
*/ */
private boolean createPrep(FontFileReader in) throws IOException {
protected boolean createPrep(FontFileReader in) throws IOException {
return copyTable(in, OFTableName.PREP); return copyTable(in, OFTableName.PREP);
} }


* Copy the hhea table as is from original font to subset font * Copy the hhea table as is from original font to subset font
* and fill in size of hmtx table * and fill in size of hmtx table
*/ */
private void createHhea(FontFileReader in, int size) throws IOException {
protected void createHhea(FontFileReader in, int size) throws IOException {
OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA); OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA);
if (entry != null) { if (entry != null) {
pad4(); pad4();
seekTab(in, OFTableName.HHEA, 0); seekTab(in, OFTableName.HHEA, 0);
System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0,
output, currentPos, (int) entry.getLength());
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength()));
writeUShort((int) entry.getLength() + currentPos - 2, size); writeUShort((int) entry.getLength() + currentPos - 2, size);


updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA);
* checkSumAdjustment to 0, store offset to checkSumAdjustment * checkSumAdjustment to 0, store offset to checkSumAdjustment
* in checkSumAdjustmentOffset * in checkSumAdjustmentOffset
*/ */
private void createHead(FontFileReader in) throws IOException {
protected void createHead(FontFileReader in) throws IOException {
OFTableName head = OFTableName.HEAD; OFTableName head = OFTableName.HEAD;
OFDirTabEntry entry = dirTabs.get(head); OFDirTabEntry entry = dirTabs.get(head);
if (entry != null) { if (entry != null) {
pad4(); pad4();
seekTab(in, head, 0); seekTab(in, head, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength()));


checkSumAdjustmentOffset = currentPos + 8; checkSumAdjustmentOffset = currentPos + 8;
output[currentPos + 8] = 0; // Set checkSumAdjustment to 0 output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
output[currentPos + 10] = 0; output[currentPos + 10] = 0;
output[currentPos + 11] = 0; output[currentPos + 11] = 0;
output[currentPos + 50] = 0; // long locaformat output[currentPos + 50] = 0; // long locaformat
output[currentPos + 51] = 1; // long locaformat

if (cid) {
output[currentPos + 51] = 1; // long locaformat
}
updateCheckSum(currentPos, (int)entry.getLength(), head); updateCheckSum(currentPos, (int)entry.getLength(), head);
currentPos += (int)entry.getLength(); currentPos += (int)entry.getLength();
realSize += (int)entry.getLength(); realSize += (int)entry.getLength();
glyphLength); glyphLength);
int endOffset1 = endOffset; int endOffset1 = endOffset;
// Copy glyph // Copy glyph
System.arraycopy(
glyphData, 0,
output, currentPos,
glyphLength);
writeBytes(glyphData);




// Update loca table // Update loca table
} }
} }


private int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) {
protected int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) {
int[] origIndexes = new int[glyphs.size()]; int[] origIndexes = new int[glyphs.size()];
for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) {
int origIndex = glyph.getKey(); int origIndex = glyph.getKey();
int subsetIndex = glyph.getValue(); int subsetIndex = glyph.getValue();
origIndexes[subsetIndex] = origIndex;
if (origIndexes.length > subsetIndex) {
origIndexes[subsetIndex] = origIndex;
}
} }
return origIndexes; return origIndexes;
} }
* Integer key and Integer value that maps the original * Integer key and Integer value that maps the original
* metric (key) to the subset metric (value) * metric (key) to the subset metric (value)
*/ */
private void createHmtx(FontFileReader in,
Map<Integer, Integer> glyphs) throws IOException {
protected void createHmtx(FontFileReader in,
Map<Integer, Integer> glyphs) throws IOException {
OFTableName hmtx = OFTableName.HMTX; OFTableName hmtx = OFTableName.HMTX;
OFDirTabEntry entry = dirTabs.get(hmtx); OFDirTabEntry entry = dirTabs.get(hmtx);


ttfOut.endFontStream(); ttfOut.endFontStream();
} }


private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs)
protected void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs)
throws IOException { throws IOException {
OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF);
if (glyfTableInfo == null) { if (glyfTableInfo == null) {
int length = 0; int length = 0;
try { try {
byte[] buf = str.getBytes("ISO-8859-1"); byte[] buf = str.getBytes("ISO-8859-1");
System.arraycopy(buf, 0, output, currentPos, buf.length);
writeBytes(buf);
length = buf.length; length = buf.length;
currentPos += length; currentPos += length;
} catch (java.io.UnsupportedEncodingException e) { } catch (java.io.UnsupportedEncodingException e) {
output[currentPos++] = b; output[currentPos++] = b;
} }


protected void writeBytes(byte[] b) {
if (b.length + currentPos > output.length) {
byte[] newoutput = new byte[output.length * 2];
System.arraycopy(output, 0, newoutput, 0, output.length);
output = newoutput;
}
System.arraycopy(b, 0, output, currentPos, b.length);
}

/** /**
* Appends a USHORT to the output array, * Appends a USHORT to the output array,
* updates currentPost but not realSize * updates currentPost but not realSize
*/ */
private void writeUShort(int s) {
protected void writeUShort(int s) {
byte b1 = (byte)((s >> 8) & 0xff); byte b1 = (byte)((s >> 8) & 0xff);
byte b2 = (byte)(s & 0xff); byte b2 = (byte)(s & 0xff);
writeByte(b1); writeByte(b1);
* Appends a USHORT to the output array, * Appends a USHORT to the output array,
* at the given position without changing currentPos * at the given position without changing currentPos
*/ */
private void writeUShort(int pos, int s) {
protected void writeUShort(int pos, int s) {
byte b1 = (byte)((s >> 8) & 0xff); byte b1 = (byte)((s >> 8) & 0xff);
byte b2 = (byte)(s & 0xff); byte b2 = (byte)(s & 0xff);
output[pos] = b1; output[pos] = b1;
* Appends a ULONG to the output array, * Appends a ULONG to the output array,
* at the given position without changing currentPos * at the given position without changing currentPos
*/ */
private void writeULong(int pos, int s) {
protected void writeULong(int pos, int s) {
byte b1 = (byte)((s >> 24) & 0xff); byte b1 = (byte)((s >> 24) & 0xff);
byte b2 = (byte)((s >> 16) & 0xff); byte b2 = (byte)((s >> 16) & 0xff);
byte b3 = (byte)((s >> 8) & 0xff); byte b3 = (byte)((s >> 8) & 0xff);
* Create a padding in the fontfile to align * Create a padding in the fontfile to align
* on a 4-byte boundary * on a 4-byte boundary
*/ */
private void pad4() {
protected void pad4() {
int padSize = getPadSize(currentPos); int padSize = getPadSize(currentPos);
if (padSize < 4) { if (padSize < 4) {
for (int i = 0; i < padSize; i++) { for (int i = 0; i < padSize; i++) {
} }




private void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) {
protected void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) {
int checksum = getCheckSum(output, tableStart, tableSize); int checksum = getCheckSum(output, tableStart, tableSize);
int offset = offsets.get(tableName); int offset = offsets.get(tableName);
int padSize = getPadSize(tableStart + tableSize); int padSize = getPadSize(tableStart + tableSize);
writeULong(offset + 8, tableSize); writeULong(offset + 8, tableSize);
} }


private static int getCheckSum(byte[] data, int start, int size) {
protected static int getCheckSum(byte[] data, int start, int size) {
// All the tables here are aligned on four byte boundaries // All the tables here are aligned on four byte boundaries
// Add remainder to size if it's not a multiple of 4 // Add remainder to size if it's not a multiple of 4
int remainder = size % 4; int remainder = size % 4;
long l = 0; long l = 0;
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
l <<= 8; l <<= 8;
l |= data[start + i + j] & 0xff;
if (data.length > (start + i + j)) {
l |= data[start + i + j] & 0xff;
}
} }
sum += l; sum += l;
} }
return (int) sum; return (int) sum;
} }


private void createCheckSumAdjustment() {
protected void createCheckSumAdjustment() {
long sum = getCheckSum(output, 0, realSize); long sum = getCheckSum(output, 0, realSize);
int checksum = (int)(0xb1b0afba - sum); int checksum = (int)(0xb1b0afba - sum);
writeULong(checkSumAdjustmentOffset, checksum); writeULong(checkSumAdjustmentOffset, checksum);

+ 1
- 1
src/java/org/apache/fop/pdf/AbstractPDFStream.java View File

return dictionary; return dictionary;
} }


protected Object get(String key) {
public Object get(String key) {
return dictionary.get(key); return dictionary.get(key);
} }



+ 57
- 0
src/java/org/apache/fop/pdf/PDFCFFStream.java View File

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.pdf;


import java.io.IOException;
import java.io.OutputStream;

/**
* Special PDFStream for embeddable CFF fonts.
*/
public class PDFCFFStream extends AbstractPDFFontStream {
private byte[] cffData;
private String type;

public PDFCFFStream(String type) {
this.type = type;
}

protected int getSizeHint() throws IOException {
if (this.cffData != null) {
return cffData.length;
} else {
return 0; //no hint available
}
}

protected void outputRawStreamData(OutputStream out) throws IOException {
out.write(this.cffData);
}

protected void populateStreamDict(Object lengthEntry) {
put("Subtype", new PDFName(type));
super.populateStreamDict(lengthEntry);
}

public void setData(byte[] data) throws IOException {
cffData = data;
}
}

+ 10
- 0
src/java/org/apache/fop/pdf/PDFDocument.java View File



private boolean accessibilityEnabled; private boolean accessibilityEnabled;


private boolean mergeFontsEnabled;

/** /**
* Creates an empty PDF document. * Creates an empty PDF document.
* *
return trailerDictionary; return trailerDictionary;
} }


public boolean isMergeFontsEnabled() {
return mergeFontsEnabled;
}

public void setMergeFontsEnabled(boolean mergeFontsEnabled) {
this.mergeFontsEnabled = mergeFontsEnabled;
}

private interface TrailerOutputHelper { private interface TrailerOutputHelper {


void outputStructureTreeElements(OutputStream stream) throws IOException; void outputStructureTreeElements(OutputStream stream) throws IOException;

+ 124
- 50
src/java/org/apache/fop/pdf/PDFFactory.java View File

PDFFont font = null; PDFFont font = null;


font = PDFFont.createFont(fontname, fonttype, subsetFontName, null); font = PDFFont.createFont(fontname, fonttype, subsetFontName, null);
getDocument().registerObject(font);
if (descriptor instanceof RefPDFFont) {
font.setObjectNumber(((RefPDFFont)descriptor).getRef().getObjectNumber());
font.setDocument(getDocument());
getDocument().addObject(font);
} else {
getDocument().registerObject(font);
}


if (fonttype == FontType.TYPE0) {
if ((fonttype == FontType.TYPE0 || fonttype == FontType.CIDTYPE0)) {
font.setEncoding(encoding); font.setEncoding(encoding);
CIDFont cidMetrics; CIDFont cidMetrics;
if (metrics instanceof LazyFont) { if (metrics instanceof LazyFont) {
PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
cidMetrics.getOrdering(), cidMetrics.getSupplement()); cidMetrics.getOrdering(), cidMetrics.getSupplement());
sysInfo.setDocument(document); sysInfo.setDocument(document);
assert pdfdesc instanceof PDFCIDFontDescriptor;
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(),
cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo,
(PDFCIDFontDescriptor) pdfdesc); (PDFCIDFontDescriptor) pdfdesc);
getDocument().registerObject(cidFont); getDocument().registerObject(cidFont);
PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H",

PDFCMap cmap;
if (cidMetrics instanceof MultiByteFont && ((MultiByteFont) cidMetrics).getCmapStream() != null) {
cmap = new PDFCMap("fop-ucs-H", null);
try {
cmap.setData(IOUtils.toByteArray(((MultiByteFont) cidMetrics).getCmapStream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H",
new PDFCIDSystemInfo("Adobe", "Identity", 0), false); new PDFCIDSystemInfo("Adobe", "Identity", 0), false);
}
getDocument().registerObject(cmap); getDocument().registerObject(cmap);
assert font instanceof PDFFontType0;
((PDFFontType0)font).setCMAP(cmap); ((PDFFontType0)font).setCMAP(cmap);
((PDFFontType0)font).setDescendantFonts(cidFont); ((PDFFontType0)font).setDescendantFonts(cidFont);
} else { } else {
assert font instanceof PDFFontNonBase14;
PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font;
nonBase14.setDescriptor(pdfdesc); nonBase14.setDescriptor(pdfdesc);


font.setEncoding(mapping.getName()); font.setEncoding(mapping.getName());
//No ToUnicode CMap necessary if PDF 1.4, chapter 5.9 (page 368) is to be //No ToUnicode CMap necessary if PDF 1.4, chapter 5.9 (page 368) is to be
//believed. //believed.
} else if (mapping.getName().equals("FOPPDFEncoding")) {
String[] charNameMap = mapping.getCharNameMap();
char[] intmap = mapping.getUnicodeCharMap();
PDFArray differences = new PDFArray();
int len = intmap.length;
if (charNameMap.length < len) {
len = charNameMap.length;
}
int last = 0;
for (int i = 0; i < len; i++) {
if (intmap[i] - 1 != last) {
differences.add(intmap[i]);
}
last = intmap[i];
differences.add(new PDFName(charNameMap[i]));
}
PDFEncoding pdfEncoding = new PDFEncoding(singleByteFont.getEncodingName());
getDocument().registerObject(pdfEncoding);
pdfEncoding.setDifferences(differences);
font.setEncoding(pdfEncoding);
if (mapping.getUnicodeCharMap() != null) {
generateToUnicodeCmap(nonBase14, mapping);
}
} else { } else {
Object pdfEncoding = createPDFEncoding(mapping, Object pdfEncoding = createPDFEncoding(mapping,
singleByteFont.getFontName()); singleByteFont.getFontName());
private PDFWArray getFontWidths(CIDFont cidFont) { private PDFWArray getFontWidths(CIDFont cidFont) {
// Create widths for reencoded chars // Create widths for reencoded chars
PDFWArray warray = new PDFWArray(); PDFWArray warray = new PDFWArray();
int[] widths = cidFont.getCIDSet().getWidths();
warray.addEntry(0, widths);
if (cidFont instanceof MultiByteFont && ((MultiByteFont)cidFont).getWidthsMap() != null) {
Map<Integer, Integer> map = ((MultiByteFont)cidFont).getWidthsMap();
for (Map.Entry<Integer, Integer> cid : map.entrySet()) {
warray.addEntry(cid.getKey(), new int[] {cid.getValue()});
}
// List<Integer> l = new ArrayList<Integer>(map.keySet());
// for (int i=0; i<map.size(); i++) {
// int cid = l.get(i);
// List<Integer> cids = new ArrayList<Integer>();
// cids.add(map.get(cid));
// while (i<map.size()-1 && l.get(i) + 1 == l.get(i + 1)) {
// cids.add(map.get(l.get(i + 1)));
// i++;
// }
// int[] cidsints = new int[cids.size()];
// for (int j=0; j<cids.size(); j++) {
// cidsints[j] = cids.get(j);
// }
// warray.addEntry(cid, cidsints);
// }
} else {
int[] widths = cidFont.getCIDSet().getWidths();
warray.addEntry(0, widths);
}
return warray; return warray;
} }


private PDFFontDescriptor makeFontDescriptor(FontDescriptor desc, String fontPrefix) { private PDFFontDescriptor makeFontDescriptor(FontDescriptor desc, String fontPrefix) {
PDFFontDescriptor descriptor = null; PDFFontDescriptor descriptor = null;


if (desc.getFontType() == FontType.TYPE0) {
if (desc.getFontType() == FontType.TYPE0 || desc.getFontType() == FontType.CIDTYPE0) {
// CID Font // CID Font
descriptor = new PDFCIDFontDescriptor(fontPrefix + desc.getEmbedFontName(), descriptor = new PDFCIDFontDescriptor(fontPrefix + desc.getEmbedFontName(),
desc.getFontBBox(), desc.getFontBBox(),
in = font.getInputStream(); in = font.getInputStream();
if (in == null) { if (in == null) {
return null; return null;
} else {
AbstractPDFStream embeddedFont = null;
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in);
byte[] fontBytes;
String header = OFFontLoader.readHeader(reader);
boolean isCFF = mbfont.isOTFFile();
if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
fontBytes = reader.getAllBytes();
if (isCFF) {
//Ensure version 1.6 for full OTF CFF embedding
document.setPDFVersion(Version.V1_6);
}
} else {
fontBytes = getFontSubsetBytes(reader, mbfont, header, fontPrefix, desc,
isCFF);
}
embeddedFont = getFontStream(font, fontBytes, isCFF);
} else if (desc.getFontType() == FontType.TYPE1) {
if (font.getEmbeddingMode() != EmbeddingMode.SUBSET) {
embeddedFont = fullyEmbedType1Font(in);
} else {
assert font instanceof SingleByteFont;
SingleByteFont sbfont = (SingleByteFont)font;
Type1SubsetFile pfbFile = new Type1SubsetFile();
byte[] subsetData = pfbFile.createSubset(in, sbfont, fontPrefix);
InputStream subsetStream = new ByteArrayInputStream(subsetData);
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(subsetStream);
embeddedFont = new PDFT1Stream();
((PDFT1Stream) embeddedFont).setData(pfb);
}
AbstractPDFStream embeddedFont = null;
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in);
byte[] fontBytes;
String header = OFFontLoader.readHeader(reader);
boolean isCFF = mbfont.isOTFFile();
if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
fontBytes = reader.getAllBytes();
if (isCFF) {
//Ensure version 1.6 for full OTF CFF embedding
document.setPDFVersion(Version.V1_6);
} }
} else { } else {
byte[] file = IOUtils.toByteArray(in);
embeddedFont = new PDFTTFStream(file.length);
((PDFTTFStream) embeddedFont).setData(file, file.length);
fontBytes = getFontSubsetBytes(reader, mbfont, header, fontPrefix, desc,
isCFF);
} }

/*
embeddedFont.getFilterList().addFilter("flate");
if (getDocument().isEncryptionActive()) {
getDocument().applyEncryption(embeddedFont);
embeddedFont = getFontStream(font, fontBytes, isCFF);
} else if (desc.getFontType() == FontType.TYPE1) {
if (font.getEmbeddingMode() != EmbeddingMode.SUBSET) {
embeddedFont = fullyEmbedType1Font(in);
} else { } else {
embeddedFont.getFilterList().addFilter("ascii-85");
}*/

return embeddedFont;
assert font instanceof SingleByteFont;
SingleByteFont sbfont = (SingleByteFont)font;
Type1SubsetFile pfbFile = new Type1SubsetFile();
byte[] subsetData = pfbFile.createSubset(in, sbfont, fontPrefix);
InputStream subsetStream = new ByteArrayInputStream(subsetData);
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(subsetStream);
embeddedFont = new PDFT1Stream();
((PDFT1Stream) embeddedFont).setData(pfb);
}
} else if (desc.getFontType() == FontType.TYPE1C) {
byte[] file = IOUtils.toByteArray(in);
PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C");
embeddedFont2.setData(file);
return embeddedFont2;
} else if (desc.getFontType() == FontType.CIDTYPE0) {
byte[] file = IOUtils.toByteArray(in);
PDFCFFStream embeddedFont2 = new PDFCFFStream("CIDFontType0C");
embeddedFont2.setData(file);
return embeddedFont2;
} else {
byte[] file = IOUtils.toByteArray(in);
embeddedFont = new PDFTTFStream(file.length);
((PDFTTFStream) embeddedFont).setData(file, file.length);
} }

/*
embeddedFont.getFilterList().addFilter("flate");
if (getDocument().isEncryptionActive()) {
getDocument().applyEncryption(embeddedFont);
} else {
embeddedFont.getFilterList().addFilter("ascii-85");
}*/

return embeddedFont;
} catch (IOException ioe) { } catch (IOException ioe) {
log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe);
return null; return null;

+ 2
- 1
src/java/org/apache/fop/pdf/PDFFont.java View File

public static PDFFont createFont(String fontname, public static PDFFont createFont(String fontname,
FontType subtype, String basefont, FontType subtype, String basefont,
Object encoding) { Object encoding) {
if (subtype == FontType.TYPE0) {
if (subtype == FontType.TYPE0 || subtype == FontType.CIDTYPE0) {
return new PDFFontType0(fontname, basefont, return new PDFFontType0(fontname, basefont,
encoding); encoding);
} else if ((subtype == FontType.TYPE1) } else if ((subtype == FontType.TYPE1)
|| (subtype == FontType.TYPE1C)
|| (subtype == FontType.MMTYPE1)) { || (subtype == FontType.MMTYPE1)) {
return new PDFFontType1(fontname, basefont, return new PDFFontType1(fontname, basefont,
encoding); encoding);

+ 1
- 1
src/java/org/apache/fop/pdf/PDFFontDescriptor.java View File

public void setFontFile(FontType subtype, AbstractPDFStream fontfile) { public void setFontFile(FontType subtype, AbstractPDFStream fontfile) {
if (subtype == FontType.TYPE1) { if (subtype == FontType.TYPE1) {
put("FontFile", fontfile); put("FontFile", fontfile);
} else if (fontfile instanceof PDFCFFStreamType0C) {
} else if (fontfile instanceof PDFCFFStreamType0C || subtype == FontType.TYPE1C) {
put("FontFile3", fontfile); put("FontFile3", fontfile);
} else { } else {
put("FontFile2", fontfile); put("FontFile2", fontfile);

+ 21
- 0
src/java/org/apache/fop/pdf/RefPDFFont.java View File

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.fop.pdf;

public interface RefPDFFont {
PDFDictionary getRef();
}

+ 1
- 1
src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java View File

if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
log.trace("Using ImageHandler: " + handler.getClass().getName()); log.trace("Using ImageHandler: " + handler.getClass().getName());
} }
context.putHint("fontinfo", getFontInfo());
handler.handleImage(context, effImage, rect); handler.handleImage(context, effImage, rect);
} }



+ 2
- 0
src/java/org/apache/fop/render/pdf/PDFRendererConfig.java View File

import static org.apache.fop.render.pdf.PDFEncryptionOption.USER_PASSWORD; import static org.apache.fop.render.pdf.PDFEncryptionOption.USER_PASSWORD;
import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE;
import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST;
import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS;
import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE;
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE;
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE;
configureEncryptionParams(cfg, userAgent, strict); configureEncryptionParams(cfg, userAgent, strict);
parseAndPut(OUTPUT_PROFILE, cfg); parseAndPut(OUTPUT_PROFILE, cfg);
parseAndPut(DISABLE_SRGB_COLORSPACE, cfg); parseAndPut(DISABLE_SRGB_COLORSPACE, cfg);
parseAndPut(MERGE_FONTS, cfg);


parseAndPut(VERSION, cfg); parseAndPut(VERSION, cfg);
} catch (ConfigurationException e) { } catch (ConfigurationException e) {

+ 6
- 0
src/java/org/apache/fop/render/pdf/PDFRendererOption.java View File

return Boolean.valueOf(value); return Boolean.valueOf(value);
} }
}, },
MERGE_FONTS("merge-fonts", false) {
@Override
Boolean deserialize(String value) {
return Boolean.valueOf(value);
}
},
/** Rendering Options key for the ICC profile for the output intent. */ /** Rendering Options key for the ICC profile for the output intent. */
OUTPUT_PROFILE("output-profile") { OUTPUT_PROFILE("output-profile") {
@Override @Override

+ 5
- 0
src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java View File



import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE;
import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST;
import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS;
import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE;
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE;
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE;
public Version getPDFVersion() { public Version getPDFVersion() {
return (Version) properties.get(VERSION); return (Version) properties.get(VERSION);
} }

public Boolean getMergeFontsEnabled() {
return (Boolean)properties.get(MERGE_FONTS);
}
} }

+ 1
- 0
src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java View File

} }


this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled()); this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled());
pdfDoc.setMergeFontsEnabled(rendererConfig.getMergeFontsEnabled());


return this.pdfDoc; return this.pdfDoc;
} }

Loading…
Cancel
Save