diff options
author | Simon Steiner <ssteiner@apache.org> | 2014-06-05 11:27:11 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2014-06-05 11:27:11 +0000 |
commit | 4516274b5dc400d4576a2a0849354ae9e0ec23b7 (patch) | |
tree | c826f2ec612804be4b976dd0aa4d62264471c4b6 /src/java/org/apache | |
parent | aa0ba8e8319462222cb23def3895c2e1e435f971 (diff) | |
download | xmlgraphics-fop-4516274b5dc400d4576a2a0849354ae9e0ec23b7.tar.gz xmlgraphics-fop-4516274b5dc400d4576a2a0849354ae9e0ec23b7.zip |
Allow merging of fonts
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FontMerging@1600606 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
23 files changed, 408 insertions, 204 deletions
diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index 96b70feea..5c0673b04 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -22,9 +22,11 @@ package org.apache.fop.fonts; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -74,6 +76,8 @@ public abstract class CustomFont extends Typeface private Map<Integer, Map<Integer, Integer>> kerning; private boolean useKerning = true; + /** the character map, mapping Unicode ranges to glyph indices. */ + protected List<CMapSegment> cmap = new ArrayList<CMapSegment>(); private boolean useAdvanced = true; /** @@ -82,8 +86,7 @@ public abstract class CustomFont extends Typeface public CustomFont(InternalResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } - /** the character map, mapping Unicode ranges to glyph indices. */ - protected CMapSegment[] cmap; + /** {@inheritDoc} */ public String getFontName() { @@ -503,8 +506,10 @@ public abstract class CustomFont extends Typeface * @param cmap the character map */ 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); + } } /** @@ -513,9 +518,7 @@ public abstract class CustomFont extends Typeface * @return the character map */ 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) { diff --git a/src/java/org/apache/fop/fonts/FontType.java b/src/java/org/apache/fop/fonts/FontType.java index edd8d0c37..fc820c8b9 100644 --- a/src/java/org/apache/fop/fonts/FontType.java +++ b/src/java/org/apache/fop/fonts/FontType.java @@ -49,6 +49,10 @@ public class FontType { */ 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 int value; diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index cc3d06650..2e743ade9 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -20,6 +20,7 @@ package org.apache.fop.fonts; import java.awt.Rectangle; +import java.io.InputStream; import java.nio.CharBuffer; import java.nio.IntBuffer; import java.util.BitSet; @@ -53,7 +54,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl private int defaultWidth; private CIDFontType cidType = CIDFontType.CIDTYPE2; - private final CIDSet cidSet; + protected final CIDSet cidSet; /* advanced typographic support */ private GlyphDefinitionTable gdef; @@ -222,13 +223,13 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { 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 - - cmap[i].getUnicodeStart(); + - i.getUnicodeStart(); if (idx < NUM_MOST_LIKELY_GLYPHS) { mostLikelyGlyphs[idx] = retIdx; } @@ -241,14 +242,9 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl * 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. */ - private synchronized void addPrivateUseMapping(int pu, int gi) { + protected synchronized void addPrivateUseMapping(int pu, int gi) { 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)); } /** @@ -306,8 +302,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl // [TBD] - needs optimization, i.e., change from linear search to binary search private int findCharacterFromGlyphIndex(int gi, boolean augment) { 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 e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart()); if ((gi >= s) && (gi <= e)) { @@ -330,10 +325,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl bitset.set(0); bitset.set(1); 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) { bitset.set(glyphIndex++); } @@ -344,10 +339,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl protected char[] getChars() { // the width array is set when the font is built 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) { chars[glyphIndex++] = (char) start++; } @@ -642,5 +637,12 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl return cb; } + public Map<Integer, Integer> getWidthsMap() { + return null; + } + + public InputStream getCmapStream() { + return null; + } } diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index 7b17c0b5d..31393f569 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -46,10 +46,10 @@ public class SingleByteFont extends CustomFont { /** logger */ private static Log log = LogFactory.getLog(SingleByteFont.class); - private SingleByteEncoding mapping; + protected SingleByteEncoding mapping; private boolean useNativeEncoding = false; - private int[] width = null; + protected int[] width = null; private Rectangle[] boundingBoxes; diff --git a/src/java/org/apache/fop/fonts/cff/CFFDataReader.java b/src/java/org/apache/fop/fonts/cff/CFFDataReader.java index 66126fb84..3ce63a2a4 100644 --- a/src/java/org/apache/fop/fonts/cff/CFFDataReader.java +++ b/src/java/org/apache/fop/fonts/cff/CFFDataReader.java @@ -580,7 +580,9 @@ public class CFFDataReader { LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); 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"); if (privateFDEntry != null) { newFontDict = setFDData(privateFDEntry, newFontDict); diff --git a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java b/src/java/org/apache/fop/fonts/truetype/GlyfTable.java index 90abccaf2..1233a586e 100644 --- a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java +++ b/src/java/org/apache/fop/fonts/truetype/GlyfTable.java @@ -37,7 +37,7 @@ public class GlyfTable { private final Set<Long> remappedComposites; - private final Map<Integer, Integer> subset; + protected final Map<Integer, Integer> subset; private final FontFileReader in; @@ -45,10 +45,10 @@ public class GlyfTable { private Set<Integer> compositeGlyphs = new TreeSet<Integer>(); /** 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; tableOffset = dirTableEntry.getOffset(); remappedComposites = new HashSet<Long>(); @@ -121,7 +121,7 @@ public class GlyfTable { * * @throws IOException an I/O error */ - void populateGlyphsWithComposites() throws IOException { + protected void populateGlyphsWithComposites() throws IOException { for (int indexInOriginal : subset.keySet()) { scanGlyphsRecursively(indexInOriginal); } @@ -166,7 +166,7 @@ public class GlyfTable { * Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves * in the subset. */ - private void addAllComposedGlyphsToSubset() { + protected void addAllComposedGlyphsToSubset() { int newIndex = subset.size(); for (int composedGlyph : composedGlyphs) { subset.put(composedGlyph, newIndex++); diff --git a/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java b/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java index 89af2296f..968ecd3b9 100644 --- a/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java +++ b/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java @@ -24,7 +24,7 @@ import java.util.List; /** * This class represents a TrueType Mtx Entry. */ -class OFMtxEntry { +public class OFMtxEntry { private int wx; private int lsb; diff --git a/src/java/org/apache/fop/fonts/truetype/OTFFile.java b/src/java/org/apache/fop/fonts/truetype/OTFFile.java index ab9654beb..57d875f9c 100644 --- a/src/java/org/apache/fop/fonts/truetype/OTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/OTFFile.java @@ -147,7 +147,7 @@ public class OTFFile extends OpenFont { * @return The byte data found in the CFF table */ public static byte[] getCFFData(FontFileReader fontFile) throws IOException { - byte[] cff = new byte[0]; + byte[] cff = fontFile.getAllBytes(); CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); input.readBytes(4); //OTTO short numTables = input.readShort(); diff --git a/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java index 9cb3458c8..3d9cf5e23 100644 --- a/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java @@ -49,23 +49,23 @@ import org.apache.fop.fonts.cff.CFFDataReader.Format3FDSelect; */ public class OTFSubSetFile extends OTFFile { - private byte[] output; - private int currentPos = 0; + protected byte[] output; + protected int currentPos = 0; private int realSize = 0; /** A map containing each glyph to be included in the subset * 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 **/ - 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 **/ - 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 * local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */ @@ -76,30 +76,30 @@ public class OTFSubSetFile extends OTFFile { private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect; /** 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 **/ - 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 **/ - private List<byte[]> subsetCharStringsIndex; + protected List<byte[]> subsetCharStringsIndex; /** 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 **/ - 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 */ - private CFFDataReader cffReader = null; + protected CFFDataReader cffReader = null; /** The class used to represent this font **/ private MultiByteFont mbFont; /** 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 */ private static final int LOCAL_SUBROUTINE = 10; /** The operator used to identify a global subroutine reference */ @@ -162,7 +162,7 @@ public class OTFSubSetFile extends OTFFile { return result; } - private void createCFF() throws IOException { + protected void createCFF() throws IOException { //Header writeBytes(cffReader.getHeader()); @@ -238,7 +238,7 @@ public class OTFSubSetFile extends OTFFile { } } - private List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException { + protected List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException { ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>(); List<FontDict> fdFonts = cffReader.getFDFonts(); for (int i = 0; i < uniqueNewRefs.size(); i++) { @@ -252,14 +252,13 @@ public class OTFSubSetFile extends OTFFile { return fontNameSIDs; } - private void writeBytes(byte[] out) { + protected void writeBytes(byte[] out) { 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++) { output[currentPos++] = out[i]; realSize++; @@ -280,7 +279,7 @@ public class OTFSubSetFile extends OTFFile { } } - private void writeTopDICT() throws IOException { + protected void writeTopDICT() throws IOException { LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright", "FullName", "FamilyName", "Weight", "PostScript"); @@ -321,7 +320,7 @@ public class OTFSubSetFile extends OTFFile { writeBytes(cidEntryByteData); } - private void writeCIDCount(DICTEntry dictEntry) throws IOException { + protected void writeCIDCount(DICTEntry dictEntry) throws IOException { byte[] cidCountByteData = dictEntry.getByteData(); cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0), subsetGlyphs.size()); @@ -375,7 +374,7 @@ public class OTFSubSetFile extends OTFFile { writeIndex(stringIndexData); } - private void createCharStringDataCID() throws IOException { + protected void createCharStringDataCID() throws IOException { CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); FDSelect fontDictionary = cffReader.getFDSelect(); @@ -451,22 +450,22 @@ public class OTFSubSetFile extends OTFFile { localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); byte[] data = charStringsIndex.getValue(gid); 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); subsetCharStringsIndex.add(data); } } } - private void writeFDSelect() { + protected void writeFDSelect() { writeByte(0); //Format for (Integer gid : subsetFDSelect.keySet()) { writeByte(subsetFDSelect.get(gid).getNewFDIndex()); } } - private List<Integer> getUsedFDFonts() { + protected List<Integer> getUsedFDFonts() { List<Integer> uniqueNewRefs = new ArrayList<Integer>(); for (int gid : subsetFDSelect.keySet()) { int fdIndex = subsetFDSelect.get(gid).getOldFDIndex(); @@ -477,7 +476,7 @@ public class OTFSubSetFile extends OTFFile { return uniqueNewRefs; } - private List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs) + protected List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs) throws IOException { List<Integer> privateDictOffsets = new ArrayList<Integer>(); List<FontDict> fdFonts = cffReader.getFDFonts(); @@ -499,7 +498,7 @@ public class OTFSubSetFile extends OTFFile { return privateDictOffsets; } - private int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets, + protected int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets, List<Integer> fontNameSIDs) throws IOException { int offset = currentPos; @@ -796,7 +795,7 @@ public class OTFSubSetFile extends OTFFile { return c; } - private int writeIndex(List<byte[]> dataArray) { + protected int writeIndex(List<byte[]> dataArray) { int hdrTotal = 3; //2 byte number of items this.writeCard16(dataArray.size()); @@ -939,7 +938,7 @@ public class OTFSubSetFile extends OTFFile { } } - private void writePrivateDict() throws IOException { + protected void writePrivateDict() throws IOException { Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); DICTEntry privateEntry = topDICT.get("Private"); @@ -948,7 +947,7 @@ public class OTFSubSetFile extends OTFFile { } } - private void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset, + protected void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset, int privateDictOffset, int localIndexOffset, int encodingOffset) throws IOException { Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); @@ -973,18 +972,20 @@ public class OTFSubSetFile extends OTFFile { //Update the local subroutine index offset in the private dict 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) { //Charset offset in the top dict DICTEntry charset = topDICT.get("charset"); @@ -1004,7 +1005,7 @@ public class OTFSubSetFile extends OTFFile { } } - private void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset, + protected void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset, int charsetOffset, int charStringOffset, int encodingOffset) { LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries(); @@ -1023,7 +1024,7 @@ public class OTFSubSetFile extends OTFFile { 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) { case 1: out[position] = (byte)(replacement & 0xFF); @@ -1061,7 +1062,7 @@ public class OTFSubSetFile extends OTFFile { * Appends a byte to the output array, * updates currentPost but not realSize */ - private void writeByte(int b) { + protected void writeByte(int b) { output[currentPos++] = (byte)b; realSize++; } @@ -1070,7 +1071,7 @@ public class OTFSubSetFile extends OTFFile { * Appends a USHORT to the output array, * updates currentPost but not realSize */ - private void writeCard16(int s) { + protected void writeCard16(int s) { byte b1 = (byte)((s >> 8) & 0xff); byte b2 = (byte)(s & 0xff); writeByte(b1); @@ -1081,10 +1082,9 @@ public class OTFSubSetFile extends OTFFile { byte b1 = (byte)((s >> 16) & 0xFF); byte b2 = (byte)((s >> 8) & 0xFF); byte b3 = (byte)(s & 0xFF); - output[currentPos++] = b1; - output[currentPos++] = b2; - output[currentPos++] = b3; - realSize += 3; + writeByte(b1); + writeByte(b2); + writeByte(b3); } /** @@ -1096,11 +1096,10 @@ public class OTFSubSetFile extends OTFFile { byte b2 = (byte)((s >> 16) & 0xff); byte b3 = (byte)((s >> 8) & 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); } /** diff --git a/src/java/org/apache/fop/fonts/truetype/OpenFont.java b/src/java/org/apache/fop/fonts/truetype/OpenFont.java index 3f4765cdc..98fced01f 100644 --- a/src/java/org/apache/fop/fonts/truetype/OpenFont.java +++ b/src/java/org/apache/fop/fonts/truetype/OpenFont.java @@ -187,6 +187,7 @@ public abstract class OpenFont { protected String notice = ""; protected final Set<String> familyNames = new HashSet<String>(); protected String subFamilyName = ""; + protected boolean cid = true; private long italicAngle = 0; private long isFixedPitch = 0; @@ -393,7 +394,9 @@ public abstract class OpenFont { 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 long cmapUniOffset = 0; long symbolMapOffset = 0; @@ -796,7 +799,9 @@ public abstract class OpenFont { int unicodeStart; int glyphStart; int unicodeEnd; - + if (unicodeMappings.isEmpty()) { + return; + } Iterator<UnicodeMapping> e = unicodeMappings.iterator(); UnicodeMapping um = e.next(); UnicodeMapping lastMapping = um; @@ -1229,7 +1234,7 @@ public abstract class OpenFont { } } - if (nhmtx < mtxSize) { + if (cid && nhmtx < mtxSize) { // Fill in the missing widths int lastWidth = mtxTab[nhmtx - 1].getWx(); for (int i = nhmtx; i < mtxSize; i++) { diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index ff46af1c7..58e3a6fa2 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -35,21 +35,21 @@ import java.util.SortedSet; */ 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. * 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 locaOffset = 0; + protected int locaOffset = 0; /** Stores the glyph offsets so that we can end strings at glyph boundaries */ - private int[] glyphOffsets; + protected int[] glyphOffsets; /** * Default Constructor @@ -67,7 +67,7 @@ public class TTFSubSetFile extends TTFFile { } /** The dir tab entries in the new subset font. */ - private Map<OFTableName, OFDirTabEntry> newDirTabs + protected Map<OFTableName, OFDirTabEntry> newDirTabs = new HashMap<OFTableName, OFDirTabEntry>(); private int determineTableCount() { @@ -86,6 +86,9 @@ public class TTFSubSetFile extends TTFFile { if (hasPrep()) { numTables++; } + if (!cid) { + numTables++; //cmap + } } return numTables; } @@ -93,7 +96,7 @@ public class TTFSubSetFile extends TTFFile { /** * Create the directory table */ - private void createDirectory() { + protected void createDirectory() { int numTables = determineTableCount(); // Create the TrueType header writeByte((byte)0); @@ -118,7 +121,9 @@ public class TTFSubSetFile extends TTFFile { realSize += 2; // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) writeTableName(OFTableName.OS2); - + if (!cid) { + writeTableName(OFTableName.CMAP); + } if (hasCvt()) { writeTableName(OFTableName.CVT); } @@ -162,7 +167,7 @@ public class TTFSubSetFile extends TTFFile { /** * Create an empty loca table without updating checksum */ - private void createLoca(int size) throws IOException { + protected void createLoca(int size) throws IOException { pad4(); locaOffset = currentPos; int dirTableOffset = offsets.get(OFTableName.LOCA); @@ -177,8 +182,7 @@ public class TTFSubSetFile extends TTFFile { if (entry != null) { pad4(); 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); currentPos += (int) entry.getLength(); @@ -192,28 +196,28 @@ public class TTFSubSetFile extends TTFFile { /** * 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); } /** * 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); } /** * 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); } /** * 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); } @@ -221,14 +225,13 @@ public class TTFSubSetFile extends TTFFile { * Copy the maxp table as is from original font to subset font * 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; OFDirTabEntry entry = dirTabs.get(maxp); if (entry != null) { pad4(); 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); updateCheckSum(currentPos, (int)entry.getLength(), maxp); @@ -239,7 +242,7 @@ public class TTFSubSetFile extends TTFFile { } } - private void createPost(FontFileReader in) throws IOException { + protected void createPost(FontFileReader in) throws IOException { OFTableName post = OFTableName.POST; OFDirTabEntry entry = dirTabs.get(post); if (entry != null) { @@ -252,12 +255,12 @@ public class TTFSubSetFile extends TTFFile { 0, newPostTable, 0, newTableSize); // set the post table to Format 3.0 newPostTable[1] = 0x03; - System.arraycopy(newPostTable, 0, output, currentPos, newTableSize); + writeBytes(newPostTable); updateCheckSum(currentPos, newTableSize, post); currentPos += newTableSize; realSize += newTableSize; } else { - throw new IOException("Can't find post table"); +// throw new IOException("Can't find post table"); } } @@ -265,7 +268,7 @@ public class TTFSubSetFile extends TTFFile { /** * 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); } @@ -274,13 +277,12 @@ public class TTFSubSetFile extends TTFFile { * Copy the hhea table as is from original font to subset font * 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); if (entry != null) { pad4(); 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); updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); @@ -298,14 +300,13 @@ public class TTFSubSetFile extends TTFFile { * checkSumAdjustment to 0, store offset to checkSumAdjustment * in checkSumAdjustmentOffset */ - private void createHead(FontFileReader in) throws IOException { + protected void createHead(FontFileReader in) throws IOException { OFTableName head = OFTableName.HEAD; OFDirTabEntry entry = dirTabs.get(head); if (entry != null) { pad4(); 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; output[currentPos + 8] = 0; // Set checkSumAdjustment to 0 @@ -313,8 +314,9 @@ public class TTFSubSetFile extends TTFFile { output[currentPos + 10] = 0; output[currentPos + 11] = 0; 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); currentPos += (int)entry.getLength(); realSize += (int)entry.getLength(); @@ -361,10 +363,7 @@ public class TTFSubSetFile extends TTFFile { glyphLength); int endOffset1 = endOffset; // Copy glyph - System.arraycopy( - glyphData, 0, - output, currentPos, - glyphLength); + writeBytes(glyphData); // Update loca table @@ -402,12 +401,14 @@ public class TTFSubSetFile extends TTFFile { } } - private int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) { + protected int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) { int[] origIndexes = new int[glyphs.size()]; for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { int origIndex = glyph.getKey(); int subsetIndex = glyph.getValue(); - origIndexes[subsetIndex] = origIndex; + if (origIndexes.length > subsetIndex) { + origIndexes[subsetIndex] = origIndex; + } } return origIndexes; } @@ -418,8 +419,8 @@ public class TTFSubSetFile extends TTFFile { * Integer key and Integer value that maps the original * 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; OFDirTabEntry entry = dirTabs.get(hmtx); @@ -560,7 +561,7 @@ public class TTFSubSetFile extends TTFFile { ttfOut.endFontStream(); } - private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) + protected void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) throws IOException { OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); if (glyfTableInfo == null) { @@ -580,7 +581,7 @@ public class TTFSubSetFile extends TTFFile { int length = 0; try { byte[] buf = str.getBytes("ISO-8859-1"); - System.arraycopy(buf, 0, output, currentPos, buf.length); + writeBytes(buf); length = buf.length; currentPos += length; } catch (java.io.UnsupportedEncodingException e) { @@ -598,11 +599,20 @@ public class TTFSubSetFile extends TTFFile { 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, * updates currentPost but not realSize */ - private void writeUShort(int s) { + protected void writeUShort(int s) { byte b1 = (byte)((s >> 8) & 0xff); byte b2 = (byte)(s & 0xff); writeByte(b1); @@ -613,7 +623,7 @@ public class TTFSubSetFile extends TTFFile { * Appends a USHORT to the output array, * 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 b2 = (byte)(s & 0xff); output[pos] = b1; @@ -625,7 +635,7 @@ public class TTFSubSetFile extends TTFFile { * Appends a ULONG to the output array, * 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 b2 = (byte)((s >> 16) & 0xff); byte b3 = (byte)((s >> 8) & 0xff); @@ -640,7 +650,7 @@ public class TTFSubSetFile extends TTFFile { * Create a padding in the fontfile to align * on a 4-byte boundary */ - private void pad4() { + protected void pad4() { int padSize = getPadSize(currentPos); if (padSize < 4) { for (int i = 0; i < padSize; i++) { @@ -663,7 +673,7 @@ public class TTFSubSetFile extends TTFFile { } - 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 offset = offsets.get(tableName); int padSize = getPadSize(tableStart + tableSize); @@ -673,7 +683,7 @@ public class TTFSubSetFile extends TTFFile { 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 // Add remainder to size if it's not a multiple of 4 int remainder = size % 4; @@ -687,14 +697,16 @@ public class TTFSubSetFile extends TTFFile { long l = 0; for (int j = 0; j < 4; j++) { l <<= 8; - l |= data[start + i + j] & 0xff; + if (data.length > (start + i + j)) { + l |= data[start + i + j] & 0xff; + } } sum += l; } return (int) sum; } - private void createCheckSumAdjustment() { + protected void createCheckSumAdjustment() { long sum = getCheckSum(output, 0, realSize); int checksum = (int)(0xb1b0afba - sum); writeULong(checkSumAdjustmentOffset, checksum); diff --git a/src/java/org/apache/fop/pdf/AbstractPDFStream.java b/src/java/org/apache/fop/pdf/AbstractPDFStream.java index 13bd1bda1..331d4f7a5 100644 --- a/src/java/org/apache/fop/pdf/AbstractPDFStream.java +++ b/src/java/org/apache/fop/pdf/AbstractPDFStream.java @@ -60,7 +60,7 @@ public abstract class AbstractPDFStream extends PDFObject { return dictionary; } - protected Object get(String key) { + public Object get(String key) { return dictionary.get(key); } diff --git a/src/java/org/apache/fop/pdf/PDFCFFStream.java b/src/java/org/apache/fop/pdf/PDFCFFStream.java new file mode 100644 index 000000000..4a73c3b4f --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFCFFStream.java @@ -0,0 +1,57 @@ +/* + * 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; + } +} diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index bcd54fcb9..a8d3d10c0 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -167,6 +167,8 @@ public class PDFDocument { private boolean accessibilityEnabled; + private boolean mergeFontsEnabled; + /** * Creates an empty PDF document. * @@ -1082,6 +1084,14 @@ public class PDFDocument { return trailerDictionary; } + public boolean isMergeFontsEnabled() { + return mergeFontsEnabled; + } + + public void setMergeFontsEnabled(boolean mergeFontsEnabled) { + this.mergeFontsEnabled = mergeFontsEnabled; + } + private interface TrailerOutputHelper { void outputStructureTreeElements(OutputStream stream) throws IOException; diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index eb4f61077..1d93e9979 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -1344,9 +1344,15 @@ public class PDFFactory { PDFFont font = 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); CIDFont cidMetrics; if (metrics instanceof LazyFont) { @@ -1357,16 +1363,30 @@ public class PDFFactory { PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), cidMetrics.getOrdering(), cidMetrics.getSupplement()); sysInfo.setDocument(document); + assert pdfdesc instanceof PDFCIDFontDescriptor; PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, (PDFCIDFontDescriptor) pdfdesc); 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); + } getDocument().registerObject(cmap); + assert font instanceof PDFFontType0; ((PDFFontType0)font).setCMAP(cmap); ((PDFFontType0)font).setDescendantFonts(cidFont); } else { + assert font instanceof PDFFontNonBase14; PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; nonBase14.setDescriptor(pdfdesc); @@ -1432,6 +1452,29 @@ public class PDFFactory { font.setEncoding(mapping.getName()); //No ToUnicode CMap necessary if PDF 1.4, chapter 5.9 (page 368) is to be //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 { Object pdfEncoding = createPDFEncoding(mapping, singleByteFont.getFontName()); @@ -1495,8 +1538,30 @@ public class PDFFactory { private PDFWArray getFontWidths(CIDFont cidFont) { // Create widths for reencoded chars 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; } @@ -1526,7 +1591,7 @@ public class PDFFactory { private PDFFontDescriptor makeFontDescriptor(FontDescriptor desc, String fontPrefix) { PDFFontDescriptor descriptor = null; - if (desc.getFontType() == FontType.TYPE0) { + if (desc.getFontType() == FontType.TYPE0 || desc.getFontType() == FontType.CIDTYPE0) { // CID Font descriptor = new PDFCIDFontDescriptor(fontPrefix + desc.getEmbedFontName(), desc.getFontBBox(), @@ -1608,55 +1673,64 @@ public class PDFFactory { in = font.getInputStream(); if (in == 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 { - 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 { - 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) { log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); return null; diff --git a/src/java/org/apache/fop/pdf/PDFFont.java b/src/java/org/apache/fop/pdf/PDFFont.java index 9b9d1c129..dcd69d8bc 100644 --- a/src/java/org/apache/fop/pdf/PDFFont.java +++ b/src/java/org/apache/fop/pdf/PDFFont.java @@ -105,10 +105,11 @@ public class PDFFont extends PDFDictionary { public static PDFFont createFont(String fontname, FontType subtype, String basefont, Object encoding) { - if (subtype == FontType.TYPE0) { + if (subtype == FontType.TYPE0 || subtype == FontType.CIDTYPE0) { return new PDFFontType0(fontname, basefont, encoding); } else if ((subtype == FontType.TYPE1) + || (subtype == FontType.TYPE1C) || (subtype == FontType.MMTYPE1)) { return new PDFFontType1(fontname, basefont, encoding); diff --git a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java index 73dbebc3f..50bb107e7 100644 --- a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java +++ b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java @@ -102,7 +102,7 @@ public class PDFFontDescriptor extends PDFDictionary { public void setFontFile(FontType subtype, AbstractPDFStream fontfile) { if (subtype == FontType.TYPE1) { put("FontFile", fontfile); - } else if (fontfile instanceof PDFCFFStreamType0C) { + } else if (fontfile instanceof PDFCFFStreamType0C || subtype == FontType.TYPE1C) { put("FontFile3", fontfile); } else { put("FontFile2", fontfile); diff --git a/src/java/org/apache/fop/pdf/RefPDFFont.java b/src/java/org/apache/fop/pdf/RefPDFFont.java new file mode 100644 index 000000000..5870cdcb7 --- /dev/null +++ b/src/java/org/apache/fop/pdf/RefPDFFont.java @@ -0,0 +1,21 @@ +/* + * 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(); +} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java index f69fe2091..2c04a0714 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -245,7 +245,7 @@ public abstract class AbstractIFPainter<T extends IFDocumentHandler> implements if (log.isTraceEnabled()) { log.trace("Using ImageHandler: " + handler.getClass().getName()); } - + context.putHint("fontinfo", getFontInfo()); handler.handleImage(context, effImage, rect); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java index 5e87deb6b..f01cdb717 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfig.java @@ -56,6 +56,7 @@ import static org.apache.fop.render.pdf.PDFEncryptionOption.OWNER_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.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.PDF_A_MODE; import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; @@ -135,6 +136,7 @@ public final class PDFRendererConfig implements RendererConfig { configureEncryptionParams(cfg, userAgent, strict); parseAndPut(OUTPUT_PROFILE, cfg); parseAndPut(DISABLE_SRGB_COLORSPACE, cfg); + parseAndPut(MERGE_FONTS, cfg); parseAndPut(VERSION, cfg); } catch (ConfigurationException e) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOption.java b/src/java/org/apache/fop/render/pdf/PDFRendererOption.java index 2ebd691fe..9c45f981d 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererOption.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOption.java @@ -66,6 +66,12 @@ public enum PDFRendererOption implements RendererConfigOption { 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. */ OUTPUT_PROFILE("output-profile") { @Override diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java index 71102ecf0..3a1a24339 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererOptionsConfig.java @@ -31,6 +31,7 @@ import org.apache.fop.pdf.Version; 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.MERGE_FONTS; 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_X_MODE; @@ -120,4 +121,8 @@ public final class PDFRendererOptionsConfig { public Version getPDFVersion() { return (Version) properties.get(VERSION); } + + public Boolean getMergeFontsEnabled() { + return (Boolean)properties.get(MERGE_FONTS); + } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 4352dae6c..8498e81c6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -576,6 +576,7 @@ class PDFRenderingUtil { } this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled()); + pdfDoc.setMergeFontsEnabled(rendererConfig.getMergeFontsEnabled()); return this.pdfDoc; } |