git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FontMerging@1600606 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -6009,4 +6009,11 @@ | |||
<Method name="hasValueOfElementName"/> | |||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | |||
</Match> | |||
<Match> | |||
<Class name="org.apache.fop.pdf.PDFCFFStream"/> | |||
<Or> | |||
<Bug pattern="EI_EXPOSE_REP"/> | |||
<Bug pattern="EI_EXPOSE_REP2"/> | |||
</Or> | |||
</Match> | |||
</FindBugsFilter> |
@@ -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) { |
@@ -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; | |||
@@ -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; | |||
} | |||
} | |||
@@ -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; | |||
@@ -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); |
@@ -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++); |
@@ -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; |
@@ -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(); |
@@ -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); | |||
} | |||
/** |
@@ -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++) { |
@@ -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); |
@@ -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); | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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; |
@@ -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; |
@@ -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); |
@@ -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); |
@@ -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(); | |||
} |
@@ -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); | |||
} | |||
@@ -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) { |
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -576,6 +576,7 @@ class PDFRenderingUtil { | |||
} | |||
this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled()); | |||
pdfDoc.setMergeFontsEnabled(rendererConfig.getMergeFontsEnabled()); | |||
return this.pdfDoc; | |||
} |