You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2012/06/22 20:07:09 UTC
svn commit: r1352986 [3/3] - in /xmlgraphics/fop/trunk: ./ lib/
src/documentation/content/xdocs/trunk/ src/java/org/apache/fop/afp/apps/
src/java/org/apache/fop/afp/parser/
src/java/org/apache/fop/complexscripts/fonts/
src/java/org/apache/fop/fonts/ sr...
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java Fri Jun 22 18:07:04 2012
@@ -20,8 +20,9 @@
package org.apache.fop.fonts.truetype;
import java.io.IOException;
-import java.util.Iterator;
+import java.util.HashMap;
import java.util.Map;
+import java.util.SortedSet;
/**
@@ -42,24 +43,18 @@ public class TTFSubSetFile extends TTFFi
* Offsets in name table to be filled out by table.
* The offsets are to the checkSum field
*/
- private int cvtDirOffset = 0;
- private int fpgmDirOffset = 0;
- private int glyfDirOffset = 0;
- private int headDirOffset = 0;
- private int hheaDirOffset = 0;
- private int hmtxDirOffset = 0;
- private int locaDirOffset = 0;
- private int maxpDirOffset = 0;
- private int prepDirOffset = 0;
+ private Map<TTFTableName, Integer> offsets = new HashMap<TTFTableName, Integer>();
private int checkSumAdjustmentOffset = 0;
private int locaOffset = 0;
+ /** Stores the glyph offsets so that we can end strings at glyph boundaries */
+ private int[] glyphOffsets;
+
/**
* Default Constructor
*/
public TTFSubSetFile() {
- this(false, false);
}
/**
@@ -71,16 +66,9 @@ public class TTFSubSetFile extends TTFFi
super(useKerning, useAdvanced);
}
- /**
- * Initalize the output array
- */
- private void init(int size) {
- output = new byte[size];
- realSize = 0;
- currentPos = 0;
-
- // createDirectory()
- }
+ /** The dir tab entries in the new subset font. */
+ private Map<TTFTableName, TTFDirTabEntry> newDirTabs
+ = new HashMap<TTFTableName, TTFDirTabEntry>();
private int determineTableCount() {
int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp
@@ -88,7 +76,7 @@ public class TTFSubSetFile extends TTFFi
throw new UnsupportedOperationException(
"OpenType fonts with CFF glyphs are not supported");
} else {
- numTables += 2; //1 req'd table: glyf,loca
+ numTables += 5; //5 req'd tables: glyf,loca,post,name,OS/2
if (hasCvt()) {
numTables++;
}
@@ -119,7 +107,7 @@ public class TTFSubSetFile extends TTFFi
// Create searchRange, entrySelector and rangeShift
int maxPow = maxPow2(numTables);
- int searchRange = maxPow * 16;
+ int searchRange = (int) Math.pow(2, maxPow) * 16;
writeUShort(searchRange);
realSize += 2;
@@ -128,151 +116,122 @@ public class TTFSubSetFile extends TTFFi
writeUShort((numTables * 16) - searchRange);
realSize += 2;
+ // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z])
+ writeTableName(TTFTableName.OS2);
- // Create space for the table entries
if (hasCvt()) {
- writeString("cvt ");
- cvtDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
+ writeTableName(TTFTableName.CVT);
}
-
if (hasFpgm()) {
- writeString("fpgm");
- fpgmDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
+ writeTableName(TTFTableName.FPGM);
}
+ writeTableName(TTFTableName.GLYF);
+ writeTableName(TTFTableName.HEAD);
+ writeTableName(TTFTableName.HHEA);
+ writeTableName(TTFTableName.HMTX);
+ writeTableName(TTFTableName.LOCA);
+ writeTableName(TTFTableName.MAXP);
+ writeTableName(TTFTableName.NAME);
+ writeTableName(TTFTableName.POST);
+ if (hasPrep()) {
+ writeTableName(TTFTableName.PREP);
+ }
+ newDirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0, currentPos));
+ }
- writeString("glyf");
- glyfDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("head");
- headDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("hhea");
- hheaDirOffset = currentPos;
+ private void writeTableName(TTFTableName tableName) {
+ writeString(tableName.getName());
+ offsets.put(tableName, currentPos);
currentPos += 12;
realSize += 16;
+ }
- writeString("hmtx");
- hmtxDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
- writeString("loca");
- locaDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
-
- writeString("maxp");
- maxpDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
+ private boolean hasCvt() {
+ return dirTabs.containsKey(TTFTableName.CVT);
+ }
- if (hasPrep()) {
- writeString("prep");
- prepDirOffset = currentPos;
- currentPos += 12;
- realSize += 16;
- }
+ private boolean hasFpgm() {
+ return dirTabs.containsKey(TTFTableName.FPGM);
}
+ private boolean hasPrep() {
+ return dirTabs.containsKey(TTFTableName.PREP);
+ }
/**
- * Copy the cvt table as is from original font to subset font
+ * Create an empty loca table without updating checksum
*/
- private boolean createCvt(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
+ private void createLoca(int size) throws IOException {
+ pad4();
+ locaOffset = currentPos;
+ int dirTableOffset = offsets.get(TTFTableName.LOCA);
+ writeULong(dirTableOffset + 4, currentPos);
+ writeULong(dirTableOffset + 8, size * 4 + 4);
+ currentPos += size * 4 + 4;
+ realSize += size * 4 + 4;
+ }
+
+ private boolean copyTable(FontFileReader in, TTFTableName tableName) throws IOException {
+ TTFDirTabEntry entry = dirTabs.get(tableName);
if (entry != null) {
pad4();
- seekTab(in, "cvt ", 0);
+ seekTab(in, tableName, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(cvtDirOffset, checksum);
- writeULong(cvtDirOffset + 4, currentPos);
- writeULong(cvtDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
+ updateCheckSum(currentPos, (int) entry.getLength(), tableName);
+ currentPos += (int) entry.getLength();
+ realSize += (int) entry.getLength();
return true;
} else {
return false;
- //throw new IOException("Can't find cvt table");
}
}
- private boolean hasCvt() {
- return dirTabs.containsKey("cvt ");
- }
-
- private boolean hasFpgm() {
- return dirTabs.containsKey("fpgm");
- }
-
- private boolean hasPrep() {
- return dirTabs.containsKey("prep");
+ /**
+ * Copy the cvt table as is from original font to subset font
+ */
+ private boolean createCvt(FontFileReader in) throws IOException {
+ return copyTable(in, TTFTableName.CVT);
}
/**
* Copy the fpgm table as is from original font to subset font
*/
private boolean createFpgm(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
- if (entry != null) {
- pad4();
- seekTab(in, "fpgm", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(fpgmDirOffset, checksum);
- writeULong(fpgmDirOffset + 4, currentPos);
- writeULong(fpgmDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- return true;
- } else {
- return false;
- }
+ return copyTable(in, TTFTableName.FPGM);
}
-
-
/**
- * Create an empty loca table without updating checksum
+ * Copy the name table as is from the original.
*/
- private void createLoca(int size) throws IOException {
- pad4();
- locaOffset = currentPos;
- writeULong(locaDirOffset + 4, currentPos);
- writeULong(locaDirOffset + 8, size * 4 + 4);
- currentPos += size * 4 + 4;
- realSize += size * 4 + 4;
+ private boolean createName(FontFileReader in) throws IOException {
+ return copyTable(in, TTFTableName.NAME);
}
+ /**
+ * Copy the OS/2 table as is from the original.
+ */
+ private boolean createOS2(FontFileReader in) throws IOException {
+ return copyTable(in, TTFTableName.OS2);
+ }
/**
* 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 {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
+ TTFTableName maxp = TTFTableName.MAXP;
+ TTFDirTabEntry entry = dirTabs.get(maxp);
if (entry != null) {
pad4();
- seekTab(in, "maxp", 0);
+ seekTab(in, maxp, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeUShort(currentPos + 4, size);
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(maxpDirOffset, checksum);
- writeULong(maxpDirOffset + 4, currentPos);
- writeULong(maxpDirOffset + 8, (int)entry.getLength());
+ updateCheckSum(currentPos, (int)entry.getLength(), maxp);
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
} else {
@@ -280,28 +239,34 @@ public class TTFSubSetFile extends TTFFi
}
}
+ private void createPost(FontFileReader in) throws IOException {
+ TTFTableName post = TTFTableName.POST;
+ TTFDirTabEntry entry = dirTabs.get(post);
+ if (entry != null) {
+ pad4();
+ seekTab(in, post, 0);
+ int newTableSize = 32; // This is the post table size with glyphs truncated
+ byte[] newPostTable = new byte[newTableSize];
+ // We only want the first 28 bytes (truncate the glyph names);
+ System.arraycopy(in.getBytes((int) entry.getOffset(), newTableSize),
+ 0, newPostTable, 0, newTableSize);
+ // set the post table to Format 3.0
+ newPostTable[1] = 0x03;
+ System.arraycopy(newPostTable, 0, output, currentPos, newTableSize);
+ updateCheckSum(currentPos, newTableSize, post);
+ currentPos += newTableSize;
+ realSize += newTableSize;
+ } else {
+ throw new IOException("Can't find post table");
+ }
+ }
+
/**
* Copy the prep table as is from original font to subset font
*/
private boolean createPrep(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
- if (entry != null) {
- pad4();
- seekTab(in, "prep", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(prepDirOffset, checksum);
- writeULong(prepDirOffset + 4, currentPos);
- writeULong(prepDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
- return true;
- } else {
- return false;
- }
+ return copyTable(in, TTFTableName.PREP);
}
@@ -310,20 +275,17 @@ public class TTFSubSetFile extends TTFFi
* and fill in size of hmtx table
*/
private void createHhea(FontFileReader in, int size) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
+ TTFDirTabEntry entry = dirTabs.get(TTFTableName.HHEA);
if (entry != null) {
pad4();
- seekTab(in, "hhea", 0);
- System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
- 0, output, currentPos, (int)entry.getLength());
- writeUShort((int)entry.getLength() + currentPos - 2, size);
-
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(hheaDirOffset, checksum);
- writeULong(hheaDirOffset + 4, currentPos);
- writeULong(hheaDirOffset + 8, (int)entry.getLength());
- currentPos += (int)entry.getLength();
- realSize += (int)entry.getLength();
+ seekTab(in, TTFTableName.HHEA, 0);
+ System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0,
+ output, currentPos, (int) entry.getLength());
+ writeUShort((int) entry.getLength() + currentPos - 2, size);
+
+ updateCheckSum(currentPos, (int) entry.getLength(), TTFTableName.HHEA);
+ currentPos += (int) entry.getLength();
+ realSize += (int) entry.getLength();
} else {
throw new IOException("Can't find hhea table");
}
@@ -337,10 +299,11 @@ public class TTFSubSetFile extends TTFFi
* in checkSumAdjustmentOffset
*/
private void createHead(FontFileReader in) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
+ TTFTableName head = TTFTableName.HEAD;
+ TTFDirTabEntry entry = dirTabs.get(head);
if (entry != null) {
pad4();
- seekTab(in, "head", 0);
+ seekTab(in, head, 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
@@ -352,11 +315,7 @@ public class TTFSubSetFile extends TTFFi
output[currentPos + 50] = 0; // long locaformat
output[currentPos + 51] = 1; // long locaformat
- int checksum = getCheckSum(currentPos, (int)entry.getLength());
- writeULong(headDirOffset, checksum);
- writeULong(headDirOffset + 4, currentPos);
- writeULong(headDirOffset + 8, (int)entry.getLength());
-
+ updateCheckSum(currentPos, (int)entry.getLength(), head);
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
} else {
@@ -369,30 +328,24 @@ public class TTFSubSetFile extends TTFFi
* Create the glyf table and fill in loca table
*/
private void createGlyf(FontFileReader in,
- Map glyphs) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
+ Map<Integer, Integer> glyphs) throws IOException {
+ TTFTableName glyf = TTFTableName.GLYF;
+ TTFDirTabEntry entry = dirTabs.get(glyf);
int size = 0;
- int start = 0;
+ int startPos = 0;
int endOffset = 0; // Store this as the last loca
if (entry != null) {
pad4();
- start = currentPos;
+ startPos = currentPos;
/* Loca table must be in order by glyph index, so build
* an array first and then write the glyph info and
* location offset.
*/
- int[] origIndexes = new int[glyphs.size()];
-
- Iterator e = glyphs.keySet().iterator();
- while (e.hasNext()) {
- Integer origIndex = (Integer)e.next();
- Integer subsetIndex = (Integer)glyphs.get(origIndex);
- origIndexes[subsetIndex.intValue()] = origIndex.intValue();
- }
+ int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs);
+ glyphOffsets = new int[origIndexes.length];
for (int i = 0; i < origIndexes.length; i++) {
- int glyphLength = 0;
int nextOffset = 0;
int origGlyphIndex = origIndexes[i];
if (origGlyphIndex >= (mtxTab.length - 1)) {
@@ -400,46 +353,64 @@ public class TTFSubSetFile extends TTFFi
} else {
nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
}
- glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
+ int glyphOffset = (int)mtxTab[origGlyphIndex].getOffset();
+ int glyphLength = nextOffset - glyphOffset;
+ byte[] glyphData = in.getBytes(
+ (int)entry.getOffset() + glyphOffset,
+ glyphLength);
+ int endOffset1 = endOffset;
// Copy glyph
System.arraycopy(
- in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
- glyphLength), 0,
+ glyphData, 0,
output, currentPos,
glyphLength);
// Update loca table
- writeULong(locaOffset + i * 4, currentPos - start);
- if ((currentPos - start + glyphLength) > endOffset) {
- endOffset = (currentPos - start + glyphLength);
+ writeULong(locaOffset + i * 4, currentPos - startPos);
+ if ((currentPos - startPos + glyphLength) > endOffset1) {
+ endOffset1 = (currentPos - startPos + glyphLength);
}
+ // Store the glyph boundary positions relative to the start of the font
+ glyphOffsets[i] = currentPos;
currentPos += glyphLength;
realSize += glyphLength;
+
+ endOffset = endOffset1;
}
- size = currentPos - start;
- int checksum = getCheckSum(start, size);
- writeULong(glyfDirOffset, checksum);
- writeULong(glyfDirOffset + 4, start);
- writeULong(glyfDirOffset + 8, size);
+ size = currentPos - startPos;
+
currentPos += 12;
realSize += 12;
+ updateCheckSum(startPos, size + 12, glyf);
// Update loca checksum and last loca index
writeULong(locaOffset + glyphs.size() * 4, endOffset);
-
- checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
- writeULong(locaDirOffset, checksum);
+ int locaSize = glyphs.size() * 4 + 4;
+ int checksum = getCheckSum(output, locaOffset, locaSize);
+ writeULong(offsets.get(TTFTableName.LOCA), checksum);
+ int padSize = (locaOffset + locaSize) % 4;
+ newDirTabs.put(TTFTableName.LOCA,
+ new TTFDirTabEntry(locaOffset, locaSize + padSize));
} else {
throw new IOException("Can't find glyf table");
}
}
+ private 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;
+ }
+ return origIndexes;
+ }
/**
* Create the hmtx table by copying metrics from original
@@ -448,8 +419,9 @@ public class TTFSubSetFile extends TTFFi
* metric (key) to the subset metric (value)
*/
private void createHmtx(FontFileReader in,
- Map glyphs) throws IOException {
- TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
+ Map<Integer, Integer> glyphs) throws IOException {
+ TTFTableName hmtx = TTFTableName.HMTX;
+ TTFDirTabEntry entry = dirTabs.get(hmtx);
int longHorMetricSize = glyphs.size() * 2;
int leftSideBearingSize = glyphs.size() * 2;
@@ -458,10 +430,9 @@ public class TTFSubSetFile extends TTFFi
if (entry != null) {
pad4();
//int offset = (int)entry.offset;
- Iterator e = glyphs.keySet().iterator();
- while (e.hasNext()) {
- Integer origIndex = (Integer)e.next();
- Integer subsetIndex = (Integer)glyphs.get(origIndex);
+ for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) {
+ Integer origIndex = glyph.getKey();
+ Integer subsetIndex = glyph.getValue();
writeUShort(currentPos + subsetIndex.intValue() * 4,
mtxTab[origIndex.intValue()].getWx());
@@ -469,10 +440,7 @@ public class TTFSubSetFile extends TTFFi
mtxTab[origIndex.intValue()].getLsb());
}
- int checksum = getCheckSum(currentPos, hmtxSize);
- writeULong(hmtxDirOffset, checksum);
- writeULong(hmtxDirOffset + 4, currentPos);
- writeULong(hmtxDirOffset + 8, hmtxSize);
+ updateCheckSum(currentPos, hmtxSize, hmtx);
currentPos += hmtxSize;
realSize += hmtxSize;
} else {
@@ -481,43 +449,37 @@ public class TTFSubSetFile extends TTFFi
}
/**
- * Returns a subset of the original font.
+ * Reads a font and creates a subset of the font.
*
* @param in FontFileReader to read from
* @param name Name to be checked for in the font file
* @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
* new index as (Integer) value)
- * @return A subset of the original font
* @throws IOException in case of an I/O problem
*/
- public byte[] readFont(FontFileReader in, String name,
+ public void readFont(FontFileReader in, String name,
Map<Integer, Integer> glyphs) throws IOException {
-
+ fontFile = in;
//Check if TrueType collection, and that the name exists in the collection
- if (!checkTTC(in, name)) {
+ if (!checkTTC(name)) {
throw new IOException("Failed to read font");
}
//Copy the Map as we're going to modify it
- Map<Integer, Integer> subsetGlyphs = new java.util.HashMap<Integer, Integer>(glyphs);
+ Map<Integer, Integer> subsetGlyphs = new HashMap<Integer, Integer>(glyphs);
output = new byte[in.getFileSize()];
- readDirTabs(in);
- readFontHeader(in);
- getNumGlyphs(in);
- readHorizontalHeader(in);
- readHorizontalMetrics(in);
- readIndexToLocation(in);
+ readDirTabs();
+ readFontHeader();
+ getNumGlyphs();
+ readHorizontalHeader();
+ readHorizontalMetrics();
+ readIndexToLocation();
scanGlyphs(in, subsetGlyphs);
- createDirectory(); // Create the TrueType header and directory
-
- createHead(in);
- createHhea(in, subsetGlyphs.size()); // Create the hhea table
- createHmtx(in, subsetGlyphs); // Create hmtx table
- createMaxp(in, subsetGlyphs.size()); // copy the maxp table
+ createDirectory(); // Create the TrueType header and directory
boolean optionalTableFound;
optionalTableFound = createCvt(in); // copy the cvt table
@@ -531,6 +493,16 @@ public class TTFSubSetFile extends TTFFi
// fpgm is optional (used in TrueType fonts only)
log.debug("TrueType: fpgm table not present. Skipped.");
}
+ createLoca(subsetGlyphs.size()); // create empty loca table
+ createGlyf(in, subsetGlyphs); //create glyf table and update loca table
+
+ createOS2(in); // copy the OS/2 table
+ createHead(in);
+ createHhea(in, subsetGlyphs.size()); // Create the hhea table
+ createHmtx(in, subsetGlyphs); // Create hmtx table
+ createMaxp(in, subsetGlyphs.size()); // copy the maxp table
+ createName(in); // copy the name table
+ createPost(in); // copy the post table
optionalTableFound = createPrep(in); // copy prep table
if (!optionalTableFound) {
@@ -538,21 +510,59 @@ public class TTFSubSetFile extends TTFFi
log.debug("TrueType: prep table not present. Skipped.");
}
- createLoca(subsetGlyphs.size()); // create empty loca table
- createGlyf(in, subsetGlyphs); //create glyf table and update loca table
-
pad4();
createCheckSumAdjustment();
+ }
+ /**
+ * Returns a subset of the fonts (readFont() MUST be called first in order to create the
+ * subset).
+ * @return byte array
+ */
+ public byte[] getFontSubset() {
byte[] ret = new byte[realSize];
System.arraycopy(output, 0, ret, 0, realSize);
-
return ret;
}
+ private void handleGlyphSubset(TTFGlyphOutputStream glyphOut) throws IOException {
+ glyphOut.startGlyphStream();
+ // Stream all but the last glyph
+ for (int i = 0; i < glyphOffsets.length - 1; i++) {
+ glyphOut.streamGlyph(output, glyphOffsets[i],
+ glyphOffsets[i + 1] - glyphOffsets[i]);
+ }
+ // Stream the last glyph
+ TTFDirTabEntry glyf = newDirTabs.get(TTFTableName.GLYF);
+ long lastGlyphLength = glyf.getLength()
+ - (glyphOffsets[glyphOffsets.length - 1] - glyf.getOffset());
+ glyphOut.streamGlyph(output, glyphOffsets[glyphOffsets.length - 1],
+ (int) lastGlyphLength);
+ glyphOut.endGlyphStream();
+ }
+
+ @Override
+ public void stream(TTFOutputStream ttfOut) throws IOException {
+ SortedSet<Map.Entry<TTFTableName, TTFDirTabEntry>> sortedDirTabs
+ = sortDirTabMap(newDirTabs);
+ TTFTableOutputStream tableOut = ttfOut.getTableOutputStream();
+ TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream();
+
+ ttfOut.startFontStream();
+ for (Map.Entry<TTFTableName, TTFDirTabEntry> entry : sortedDirTabs) {
+ if (entry.getKey().equals(TTFTableName.GLYF)) {
+ handleGlyphSubset(glyphOut);
+ } else {
+ tableOut.streamTable(output, (int) entry.getValue().getOffset(),
+ (int) entry.getValue().getLength());
+ }
+ }
+ ttfOut.endFontStream();
+ }
+
private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs)
throws IOException {
- TTFDirTabEntry glyfTableInfo = (TTFDirTabEntry) dirTabs.get("glyf");
+ TTFDirTabEntry glyfTableInfo = dirTabs.get(TTFTableName.GLYF);
if (glyfTableInfo == null) {
throw new IOException("Glyf table could not be found");
}
@@ -610,20 +620,6 @@ public class TTFSubSetFile extends TTFFi
output[pos + 1] = b2;
}
- /**
- * Appends a ULONG to the output array,
- * updates currentPos but not realSize
- */
- private void writeULong(int s) {
- byte b1 = (byte)((s >> 24) & 0xff);
- byte b2 = (byte)((s >> 16) & 0xff);
- byte b3 = (byte)((s >> 8) & 0xff);
- byte b4 = (byte)(s & 0xff);
- writeByte(b1);
- writeByte(b2);
- writeByte(b3);
- writeByte(b4);
- }
/**
* Appends a ULONG to the output array,
@@ -641,40 +637,16 @@ public class TTFSubSetFile extends TTFFi
}
/**
- * Read a signed short value at given position
- */
- private short readShort(int pos) {
- int ret = readUShort(pos);
- return (short)ret;
- }
-
- /**
- * Read a unsigned short value at given position
- */
- private int readUShort(int pos) {
- int ret = output[pos];
- if (ret < 0) {
- ret += 256;
- }
- ret = ret << 8;
- if (output[pos + 1] < 0) {
- ret |= output[pos + 1] + 256;
- } else {
- ret |= output[pos + 1];
- }
-
- return ret;
- }
-
- /**
* Create a padding in the fontfile to align
* on a 4-byte boundary
*/
private void pad4() {
- int padSize = currentPos % 4;
- for (int i = 0; i < padSize; i++) {
- output[currentPos++] = 0;
- realSize++;
+ int padSize = getPadSize(currentPos);
+ if (padSize < 4) {
+ for (int i = 0; i < padSize; i++) {
+ output[currentPos++] = 0;
+ realSize++;
+ }
}
}
@@ -683,23 +655,25 @@ public class TTFSubSetFile extends TTFFi
*/
private int maxPow2(int max) {
int i = 0;
- while (Math.pow(2, i) < max) {
+ while (Math.pow(2, i) <= max) {
i++;
}
return (i - 1);
}
- private int log2(int num) {
- return (int)(Math.log(num) / Math.log(2));
- }
-
- private int getCheckSum(int start, int size) {
- return (int)getLongCheckSum(start, size);
+ private void updateCheckSum(int tableStart, int tableSize, TTFTableName tableName) {
+ int checksum = getCheckSum(output, tableStart, tableSize);
+ int offset = offsets.get(tableName);
+ int padSize = getPadSize(tableStart + tableSize);
+ newDirTabs.put(tableName, new TTFDirTabEntry(tableStart, tableSize + padSize));
+ writeULong(offset, checksum);
+ writeULong(offset + 4, tableStart);
+ writeULong(offset + 8, tableSize);
}
- private long getLongCheckSum(int start, int size) {
+ private 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;
@@ -710,26 +684,19 @@ public class TTFSubSetFile extends TTFFi
long sum = 0;
for (int i = 0; i < size; i += 4) {
- int l = (output[start + i] << 24);
- l += (output[start + i + 1] << 16);
- l += (output[start + i + 2] << 16);
- l += (output[start + i + 3] << 16);
- sum += l;
- if (sum > 0xffffffff) {
- sum = sum - 0xffffffff;
+ long l = 0;
+ for (int j = 0; j < 4; j++) {
+ l <<= 8;
+ l |= data[start + i + j] & 0xff;
}
+ sum += l;
}
-
- return sum;
+ return (int) sum;
}
private void createCheckSumAdjustment() {
- long sum = getLongCheckSum(0, realSize);
+ long sum = getCheckSum(output, 0, realSize);
int checksum = (int)(0xb1b0afba - sum);
writeULong(checkSumAdjustmentOffset, checksum);
}
-
}
-
-
-
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFFactory.java Fri Jun 22 18:07:04 2012
@@ -45,6 +45,7 @@ import org.apache.commons.logging.LogFac
import org.apache.xmlgraphics.java2d.color.ColorUtil;
import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
+
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.fop.fonts.CIDFont;
@@ -1674,8 +1675,8 @@ public class PDFFactory {
FontFileReader reader = new FontFileReader(in);
TTFSubSetFile subset = new TTFSubSetFile();
- byte[] subsetFont = subset.readFont(reader,
- mbfont.getTTCName(), mbfont.getUsedGlyphs());
+ subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
+ byte[] subsetFont = subset.getFontSubset();
// Only TrueType CID fonts are supported now
embeddedFont = new PDFTTFStream(subsetFont.length);
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java Fri Jun 22 18:07:04 2012
@@ -89,7 +89,8 @@ public class ConfiguredFontCollection im
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
CustomFont fontMetrics = FontLoader.loadFont(
- fontFile, null, true, EncodingMode.AUTO,
+ fontFile, null, true, configFontInfo.getEmbeddingMode(),
+ EncodingMode.AUTO,
configFontInfo.getKerning(),
configFontInfo.getAdvanced(), fontResolver);
font = new CustomFontMetricsMapper(fontMetrics);
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/FontResourceCache.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/FontResourceCache.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/FontResourceCache.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/FontResourceCache.java Fri Jun 22 18:07:04 2012
@@ -42,19 +42,20 @@ class FontResourceCache {
}
/**
- * Returns the PSResource for the given font key.
+ * Returns the PSFontResource for the given font key.
* @param key the font key ("F*")
- * @return the matching PSResource
+ * @return the matching PSFontResource instance
*/
- public PSResource getPSResourceForFontKey(String key) {
- PSResource res = null;
+ public PSFontResource getFontResourceForFontKey(String key) {
+ PSFontResource res = null;
if (this.fontResources != null) {
- res = (PSResource)this.fontResources.get(key);
+ res = (PSFontResource)this.fontResources.get(key);
} else {
this.fontResources = new java.util.HashMap();
}
if (res == null) {
- res = new PSResource(PSResource.TYPE_FONT, getPostScriptNameForFontKey(key));
+ res = PSFontResource.createFontResource(
+ new PSResource(PSResource.TYPE_FONT, getPostScriptNameForFontKey(key)));
this.fontResources.put(key, res);
}
return res;
@@ -76,9 +77,9 @@ class FontResourceCache {
throw new IllegalStateException("Font not available: " + key);
}
if (postFix == null) {
- return tf.getFontName();
+ return tf.getEmbedFontName();
} else {
- return tf.getFontName() + postFix;
+ return tf.getEmbedFontName() + postFix;
}
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSDocumentHandler.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSDocumentHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSDocumentHandler.java Fri Jun 22 18:07:04 2012
@@ -50,6 +50,7 @@ import org.apache.xmlgraphics.ps.dsc.Res
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox;
+import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFContext;
@@ -107,6 +108,8 @@ public class PSDocumentHandler extends A
private static final int COMMENT_PAGE_TRAILER = 2;
private static final int PAGE_TRAILER_CODE_BEFORE = 3;
+ private PSEventProducer eventProducer;
+
/**
* Default constructor.
*/
@@ -126,7 +129,9 @@ public class PSDocumentHandler extends A
/** {@inheritDoc} */
public void setContext(IFContext context) {
super.setContext(context);
- this.psUtil = new PSRenderingUtil(context.getUserAgent());
+ FOUserAgent userAgent = context.getUserAgent();
+ this.psUtil = new PSRenderingUtil(userAgent);
+ eventProducer = PSEventProducer.Provider.get(userAgent.getEventBroadcaster());
}
/** {@inheritDoc} */
@@ -145,7 +150,7 @@ public class PSDocumentHandler extends A
try {
OutputStream out;
if (psUtil.isOptimizeResources()) {
- this.tempFile = File.createTempFile("fop", null);
+ this.tempFile = File.createTempFile("fop", ".ps");
out = new java.io.FileOutputStream(this.tempFile);
out = new java.io.BufferedOutputStream(out);
} else {
@@ -203,7 +208,7 @@ public class PSDocumentHandler extends A
gen.writeDSCComment(DSCConstants.BEGIN_SETUP);
PSRenderingUtil.writeSetupCodeList(gen, setupCodeList, "SetupCode");
if (!psUtil.isOptimizeResources()) {
- this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo));
+ this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo, eventProducer));
} else {
gen.commentln("%FOPFontSetup"); //Place-holder, will be replaced in the second pass
}
@@ -258,8 +263,8 @@ public class PSDocumentHandler extends A
in = new java.io.BufferedInputStream(in);
try {
try {
- ResourceHandler handler = new ResourceHandler(getUserAgent(), this.fontInfo,
- resTracker, this.formResources);
+ ResourceHandler handler = new ResourceHandler(getUserAgent(), eventProducer,
+ this.fontInfo, resTracker, this.formResources);
handler.process(in, this.outputStream,
this.currentPageNumber, this.documentBoundingBox);
this.outputStream.flush();
@@ -547,8 +552,8 @@ public class PSDocumentHandler extends A
* @param key the font key ("F*")
* @return the matching PSResource
*/
- protected PSResource getPSResourceForFontKey(String key) {
- return this.fontResources.getPSResourceForFontKey(key);
+ protected PSFontResource getPSResourceForFontKey(String key) {
+ return this.fontResources.getFontResourceForFontKey(key);
}
/**
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.java Fri Jun 22 18:07:04 2012
@@ -53,4 +53,11 @@ public interface PSEventProducer extends
*/
void postscriptDictionaryParseError(Object source, String content, Exception e);
+ /**
+ * PostScript Level 3 features are necessary.
+ *
+ * @param source the event source
+ * @event.severity FATAL
+ */
+ void postscriptLevel3Needed(Object source);
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.xml?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.xml (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSEventProducer.xml Fri Jun 22 18:07:04 2012
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalogue xml:lang="en">
<message key="postscriptDictionaryParseError">Failed to parse dictionary string. Reason: {e}, content = "{content}"</message>
+ <message key="postscriptLevel3Needed">PostScript Level 3 features are needed to handle this document.</message>
</catalogue>
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSFontUtils.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSFontUtils.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSFontUtils.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSFontUtils.java Fri Jun 22 18:07:04 2012
@@ -23,7 +23,11 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
@@ -38,14 +42,26 @@ import org.apache.xmlgraphics.ps.PSResou
import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
import org.apache.fop.fonts.Base14Font;
+import org.apache.fop.fonts.CIDFontType;
+import org.apache.fop.fonts.CIDSubset;
+import org.apache.fop.fonts.CMapSegment;
import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteEncoding;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.TTFFile;
+import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion;
+import org.apache.fop.fonts.truetype.TTFOutputStream;
+import org.apache.fop.fonts.truetype.TTFSubSetFile;
+import org.apache.fop.render.ps.fonts.PSTTFOutputStream;
+import org.apache.fop.util.HexEncoder;
/**
* Utility code for font handling in PostScript.
@@ -54,7 +70,6 @@ public class PSFontUtils extends org.apa
/** logging instance */
protected static final Log log = LogFactory.getLog(PSFontUtils.class);
-
/**
* Generates the PostScript code for the font dictionary. This method should only be
* used if no "resource optimization" is performed, i.e. when the fonts are not embedded
@@ -66,7 +81,22 @@ public class PSFontUtils extends org.apa
*/
public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo)
throws IOException {
- return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true);
+ return writeFontDict(gen, fontInfo, null);
+ }
+
+ /**
+ * Generates the PostScript code for the font dictionary. This method should only be
+ * used if no "resource optimization" is performed, i.e. when the fonts are not embedded
+ * in a second pass.
+ * @param gen PostScript generator to use for output
+ * @param fontInfo available fonts
+ * @param eventProducer to report events
+ * @return a Map of PSResource instances representing all defined fonts (key: font key)
+ * @throws IOException in case of an I/O problem
+ */
+ public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
+ PSEventProducer eventProducer) throws IOException {
+ return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true, eventProducer);
}
/**
@@ -76,13 +106,13 @@ public class PSFontUtils extends org.apa
* @param gen PostScript generator to use for output
* @param fontInfo available fonts
* @param fonts the set of fonts to work with
+ * @param eventProducer the event producer
* @return a Map of PSResource instances representing all defined fonts (key: font key)
* @throws IOException in case of an I/O problem
*/
- public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
- Map<String, Typeface> fonts)
- throws IOException {
- return writeFontDict(gen, fontInfo, fonts, false);
+ public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map<String, Typeface> fonts,
+ PSEventProducer eventProducer) throws IOException {
+ return writeFontDict(gen, fontInfo, fonts, false, eventProducer);
}
/**
@@ -96,15 +126,16 @@ public class PSFontUtils extends org.apa
* @throws IOException in case of an I/O problem
*/
private static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
- Map<String, Typeface> fonts, boolean encodeAllCharacters) throws IOException {
+ Map<String, Typeface> fonts, boolean encodeAllCharacters, PSEventProducer eventProducer)
+ throws IOException {
gen.commentln("%FOPBeginFontDict");
- Map fontResources = new java.util.HashMap();
+ Map fontResources = new HashMap();
for (String key : fonts.keySet()) {
Typeface tf = getTypeFace(fontInfo, fonts, key);
- PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getFontName());
- fontResources.put(key, fontRes);
- embedFont(gen, tf, fontRes);
+ PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName());
+ PSFontResource fontResource = embedFont(gen, tf, fontRes, eventProducer);
+ fontResources.put(key, fontResource);
if (tf instanceof SingleByteFont) {
SingleByteFont sbf = (SingleByteFont)tf;
@@ -117,9 +148,18 @@ public class PSFontUtils extends org.apa
SingleByteEncoding encoding = sbf.getAdditionalEncoding(i);
defineEncoding(gen, encoding);
String postFix = "_" + (i + 1);
- PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(),
- tf.getFontName() + postFix, encoding.getName());
- fontResources.put(key + postFix, derivedFontRes);
+ PSResource derivedFontRes;
+ if (tf.getFontType() == FontType.TRUETYPE
+ && sbf.getTrueTypePostScriptVersion() != PostScriptVersion.V2) {
+ derivedFontRes = defineDerivedTrueTypeFont(gen, eventProducer,
+ tf.getEmbedFontName(), tf.getEmbedFontName() + postFix, encoding,
+ sbf.getCMap());
+ } else {
+ derivedFontRes = defineDerivedFont(gen, tf.getEmbedFontName(),
+ tf.getEmbedFontName() + postFix, encoding.getName());
+ }
+ fontResources.put(key + postFix,
+ PSFontResource.createFontResource(derivedFontRes));
}
}
}
@@ -156,12 +196,12 @@ public class PSFontUtils extends org.apa
} else {
if (tf instanceof Base14Font) {
//Our Base 14 fonts don't use the default encoding
- redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName());
+ redefineFontEncoding(gen, tf.getEmbedFontName(), tf.getEncodingName());
} else if (tf instanceof SingleByteFont) {
SingleByteFont sbf = (SingleByteFont)tf;
if (!sbf.isUsingNativeEncoding()) {
//Font has been configured to use an encoding other than the default one
- redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName());
+ redefineFontEncoding(gen, tf.getEmbedFontName(), tf.getEncodingName());
}
}
}
@@ -184,39 +224,299 @@ public class PSFontUtils extends org.apa
return tf;
}
- /**
- * Embeds a font in the PostScript file.
- * @param gen the PostScript generator
- * @param tf the font
- * @param fontRes the PSResource associated with the font
- * @throws IOException In case of an I/O error
- */
- public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes)
- throws IOException {
- boolean embeddedFont = false;
- if (FontType.TYPE1 == tf.getFontType()) {
- if (tf instanceof CustomFont) {
- CustomFont cf = (CustomFont)tf;
- if (isEmbeddable(cf)) {
- InputStream in = getInputStreamOnFont(gen, cf);
- if (in != null) {
- gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
- fontRes);
- embedType1Font(gen, in);
- gen.writeDSCComment(DSCConstants.END_RESOURCE);
- gen.getResourceTracker().registerSuppliedResource(fontRes);
- embeddedFont = true;
- } else {
- gen.commentln("%WARNING: Could not embed font: " + cf.getFontName());
- log.warn("Font " + cf.getFontName() + " is marked as supplied in the"
- + " PostScript file but could not be embedded!");
+ private static PSFontResource embedFont(PSGenerator gen, Typeface tf, PSResource fontRes,
+ PSEventProducer eventProducer) throws IOException {
+ FontType fontType = tf.getFontType();
+ PSFontResource fontResource = null;
+ if (!(fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE
+ || fontType == FontType.TYPE0) || !(tf instanceof CustomFont)) {
+ gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
+ fontResource = PSFontResource.createFontResource(fontRes);
+ return fontResource;
+ }
+ CustomFont cf = (CustomFont)tf;
+ if (isEmbeddable(cf)) {
+ InputStream in = getInputStreamOnFont(gen, cf);
+ if (in == null) {
+ gen.commentln("%WARNING: Could not embed font: " + cf.getEmbedFontName());
+ log.warn("Font " + cf.getEmbedFontName() + " is marked as supplied in the"
+ + " PostScript file but could not be embedded!");
+ gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
+ fontResource = PSFontResource.createFontResource(fontRes);
+ return fontResource;
+ }
+ if (fontType == FontType.TYPE0) {
+ if (gen.embedIdentityH()) {
+ checkPostScriptLevel3(gen, eventProducer);
+ /*
+ * First CID-keyed font to be embedded; add
+ * %%IncludeResource: comment for ProcSet CIDInit.
+ */
+ gen.includeProcsetCIDInitResource();
+ }
+ PSResource cidFontResource = embedType2CIDFont(gen,
+ (MultiByteFont) tf, in);
+ fontResource = PSFontResource.createFontResource(fontRes,
+ gen.getProcsetCIDInitResource(), gen.getIdentityHCMapResource(),
+ cidFontResource);
+ }
+ gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, fontRes);
+ if (fontType == FontType.TYPE1) {
+ embedType1Font(gen, in);
+ fontResource = PSFontResource.createFontResource(fontRes);
+ } else if (fontType == FontType.TRUETYPE) {
+ embedTrueTypeFont(gen, (SingleByteFont) tf, in);
+ fontResource = PSFontResource.createFontResource(fontRes);
+ } else {
+ composeType0Font(gen, (MultiByteFont) tf, in);
+ }
+ gen.writeDSCComment(DSCConstants.END_RESOURCE);
+ gen.getResourceTracker().registerSuppliedResource(fontRes);
+ }
+ return fontResource;
+ }
+
+ private static void checkPostScriptLevel3(PSGenerator gen, PSEventProducer eventProducer) {
+ if (gen.getPSLevel() < 3) {
+ if (eventProducer != null) {
+ eventProducer.postscriptLevel3Needed(gen);
+ } else {
+ throw new IllegalStateException("PostScript Level 3 is"
+ + " required to use TrueType fonts,"
+ + " configured level is "
+ + gen.getPSLevel());
+ }
+ }
+ }
+
+ private static void embedTrueTypeFont(PSGenerator gen,
+ SingleByteFont font, InputStream fontStream) throws IOException {
+ /* See Adobe Technical Note #5012, "The Type 42 Font Format Specification" */
+ gen.commentln("%!PS-TrueTypeFont-65536-65536-1"); // TODO TrueType & font versions
+ gen.writeln("11 dict begin");
+ if (font.getEmbeddingMode() == EmbeddingMode.AUTO) {
+ font.setEmbeddingMode(EmbeddingMode.SUBSET);
+ }
+ FontFileReader reader = new FontFileReader(fontStream);
+ TTFFile ttfFile = new TTFFile();
+ ttfFile.readFont(reader, font.getFullName());
+ createType42DictionaryEntries(gen, font, font.getCMap(), ttfFile);
+ gen.writeln("FontName currentdict end definefont pop");
+ }
+
+ private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font,
+ CMapSegment[] cmap, TTFFile ttfFile) throws IOException {
+ gen.write("/FontName /");
+ gen.write(font.getEmbedFontName());
+ gen.writeln(" def");
+ gen.writeln("/PaintType 0 def");
+ gen.writeln("/FontMatrix [1 0 0 1 0 0] def");
+ writeFontBBox(gen, font);
+ gen.writeln("/FontType 42 def");
+ gen.writeln("/Encoding 256 array");
+ gen.writeln("0 1 255{1 index exch/.notdef put}for");
+ boolean buildCharStrings;
+ Set<String> glyphNames = new HashSet<String>();
+ if (font.getFontType() == FontType.TYPE0 && font.getEmbeddingMode() != EmbeddingMode.FULL) {
+ //"/Encoding" is required but ignored for CID fonts
+ //so we keep it minimal to save space
+ buildCharStrings = false;
+ } else {
+ buildCharStrings = true;
+ for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) {
+ gen.write("dup ");
+ gen.write(i);
+ gen.write(" /");
+ String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]);
+ if (glyphName.equals("")) {
+ gen.write(Glyphs.NOTDEF);
+ } else {
+ gen.write(glyphName);
+ glyphNames.add(glyphName);
+ }
+ gen.writeln(" put");
+ }
+ }
+ gen.writeln("readonly def");
+ TTFOutputStream ttfOut = new PSTTFOutputStream(gen);
+ ttfFile.stream(ttfOut);
+
+ buildCharStrings(gen, buildCharStrings, cmap, glyphNames, font);
+ }
+
+ private static void buildCharStrings(PSGenerator gen, boolean buildCharStrings,
+ CMapSegment[] cmap, Set<String> glyphNames, CustomFont font) throws IOException {
+ gen.write("/CharStrings ");
+ if (!buildCharStrings) {
+ gen.write(1);
+ } else if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
+ int charCount = 1; //1 for .notdef
+ for (CMapSegment segment : cmap) {
+ charCount += segment.getUnicodeEnd() - segment.getUnicodeStart() + 1;
+ }
+ gen.write(charCount);
+ } else {
+ gen.write(font.getCMap().length);
+ }
+ gen.writeln(" dict dup begin");
+ gen.write("/");
+ gen.write(Glyphs.NOTDEF);
+ gen.writeln(" 0 def"); // .notdef always has to be at index 0
+ if (!buildCharStrings) {
+ // If we're not building the full CharStrings we can end here
+ gen.writeln("end readonly def");
+ return;
+ }
+ if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
+ //Only performed in singly-byte mode, ignored for CID fonts
+ for (CMapSegment segment : cmap) {
+ int glyphIndex = segment.getGlyphStartIndex();
+ for (int ch = segment.getUnicodeStart(); ch <= segment.getUnicodeEnd(); ch++) {
+ char ch16 = (char)ch; //TODO Handle Unicode characters beyond 16bit
+ String glyphName = Glyphs.charToGlyphName(ch16);
+ if ("".equals(glyphName)) {
+ glyphName = "u" + Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
}
+ writeGlyphDefs(gen, glyphName, glyphIndex);
+
+ glyphIndex++;
}
}
+ } else {
+ for (String name : glyphNames) {
+ writeGlyphDefs(gen, name,
+ getGlyphIndex(Glyphs.getUnicodeSequenceForGlyphName(name).charAt(0),
+ font.getCMap()));
+ }
}
- if (!embeddedFont) {
- gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
+ gen.writeln("end readonly def");
+ }
+
+ private static void writeGlyphDefs(PSGenerator gen, String glyphName, int glyphIndex)
+ throws IOException {
+ gen.write("/");
+ gen.write(glyphName);
+ gen.write(" ");
+ gen.write(glyphIndex);
+ gen.writeln(" def");
+ }
+
+ private static int getGlyphIndex(char c, CMapSegment[] cmap) {
+ for (CMapSegment segment : cmap) {
+ if (segment.getUnicodeStart() <= c && c <= segment.getUnicodeEnd()) {
+ return segment.getGlyphStartIndex() + c - segment.getUnicodeStart();
+ }
}
+ return 0;
+ }
+
+ private static void composeType0Font(PSGenerator gen, MultiByteFont font,
+ InputStream fontStream) throws IOException {
+ String psName = font.getEmbedFontName();
+ gen.write("/");
+ gen.write(psName);
+ gen.write(" /Identity-H [/");
+ gen.write(psName);
+ gen.writeln("] composefont pop");
+ }
+
+ private static PSResource embedType2CIDFont(PSGenerator gen,
+ MultiByteFont font, InputStream fontStream) throws IOException {
+ assert font.getCIDType() == CIDFontType.CIDTYPE2;
+
+ String psName = font.getEmbedFontName();
+ gen.write("%%BeginResource: CIDFont ");
+ gen.writeln(psName);
+
+ gen.write("%%Title: (");
+ gen.write(psName);
+ gen.writeln(" Adobe Identity 0)");
+
+ gen.writeln("%%Version: 1"); // TODO use font revision?
+ gen.writeln("/CIDInit /ProcSet findresource begin");
+ gen.writeln("20 dict begin");
+
+ gen.write("/CIDFontName /");
+ gen.write(psName);
+ gen.writeln(" def");
+
+ gen.writeln("/CIDFontVersion 1 def"); // TODO same as %%Version above
+
+ gen.write("/CIDFontType ");
+ gen.write(font.getCIDType().getValue());
+ gen.writeln(" def");
+
+ gen.writeln("/CIDSystemInfo 3 dict dup begin");
+ gen.writeln(" /Registry (Adobe) def");
+ gen.writeln(" /Ordering (Identity) def");
+ gen.writeln(" /Supplement 0 def");
+ gen.writeln("end def");
+
+ // TODO UIDBase (and UIDOffset in CMap) necessary if PostScript Level 1 & 2
+ // interpreters are to be supported
+ // (Level 1: with composite font extensions; Level 2: those that do not offer
+ // native mode support for CID-keyed fonts)
+
+ // TODO XUID (optional but strongly recommended)
+
+ // TODO /FontInfo
+
+ gen.write("/CIDCount ");
+ CIDSubset cidSubset = font.getCIDSubset();
+ int subsetSize = cidSubset.getSubsetSize();
+ gen.write(subsetSize);
+ gen.writeln(" def");
+ gen.writeln("/GDBytes 2 def"); // TODO always 2?
+ gen.writeln("/CIDMap [<");
+ int colCount = 0;
+ int lineCount = 1;
+ for (int cid = 0; cid < subsetSize; cid++) {
+ if (colCount++ == 20) {
+ gen.newLine();
+ colCount = 1;
+ if (lineCount++ == 800) {
+ gen.writeln("> <");
+ lineCount = 1;
+ }
+ }
+ String gid;
+ if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
+ gid = HexEncoder.encode(cid, 4);
+ } else {
+ gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4);
+ }
+ gen.write(gid);
+ }
+ gen.writeln(">] def");
+ FontFileReader reader = new FontFileReader(fontStream);
+
+ TTFFile ttfFile;
+ if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
+ ttfFile = new TTFSubSetFile();
+ ttfFile.readFont(reader, font.getTTCName(), font.getUsedGlyphs());
+ } else {
+ ttfFile = new TTFFile();
+ ttfFile.readFont(reader, font.getTTCName());
+ }
+
+
+ createType42DictionaryEntries(gen, font, new CMapSegment[0], ttfFile);
+ gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop");
+ gen.writeln("end");
+ gen.writeln("%%EndResource");
+ PSResource cidFontResource = new PSResource(PSResource.TYPE_CIDFONT, psName);
+ gen.getResourceTracker().registerSuppliedResource(cidFontResource);
+ return cidFontResource;
+ }
+
+ private static void writeFontBBox(PSGenerator gen, CustomFont font) throws IOException {
+ int[] bbox = font.getFontBBox();
+ gen.write("/FontBBox[");
+ for (int i = 0; i < 4; i++) {
+ gen.write(" ");
+ gen.write(bbox[i]);
+ }
+ gen.writeln(" ] def");
}
private static boolean isEmbeddable(CustomFont font) {
@@ -273,12 +573,20 @@ public class PSFontUtils extends org.apa
Map fontResources = new java.util.HashMap();
for (String key : fonts.keySet()) {
Typeface tf = getTypeFace(fontInfo, fonts, key);
- PSResource fontRes = new PSResource("font", tf.getFontName());
+ PSResource fontRes = new PSResource("font", tf.getEmbedFontName());
fontResources.put(key, fontRes);
- if (FontType.TYPE1 == tf.getFontType()) {
+ FontType fontType = tf.getFontType();
+ if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE
+ || fontType == FontType.TYPE0) {
if (tf instanceof CustomFont) {
CustomFont cf = (CustomFont)tf;
if (isEmbeddable(cf)) {
+ if (fontType == FontType.TYPE0) {
+ resTracker.registerSuppliedResource(
+ new PSResource(PSResource.TYPE_CIDFONT, tf.getEmbedFontName()));
+ resTracker.registerSuppliedResource(
+ new PSResource(PSResource.TYPE_CMAP, "Identity-H"));
+ }
resTracker.registerSuppliedResource(fontRes);
}
if (tf instanceof SingleByteFont) {
@@ -289,7 +597,7 @@ public class PSFontUtils extends org.apa
PSResource.TYPE_ENCODING, encoding.getName());
resTracker.registerSuppliedResource(encodingRes);
PSResource derivedFontRes = new PSResource(
- PSResource.TYPE_FONT, tf.getFontName() + "_" + (i + 1));
+ PSResource.TYPE_FONT, tf.getEmbedFontName() + "_" + (i + 1));
resTracker.registerSuppliedResource(derivedFontRes);
}
}
@@ -366,4 +674,42 @@ public class PSFontUtils extends org.apa
return res;
}
+ private static PSResource defineDerivedTrueTypeFont(PSGenerator gen,
+ PSEventProducer eventProducer, String baseFontName, String fontName,
+ SingleByteEncoding encoding, CMapSegment[] cmap) throws IOException {
+ checkPostScriptLevel3(gen, eventProducer);
+ PSResource res = new PSResource(PSResource.TYPE_FONT, fontName);
+ gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res);
+ gen.commentln("%XGCDependencies: font " + baseFontName);
+ gen.commentln("%XGC+ encoding " + encoding.getName());
+ gen.writeln("/" + baseFontName + " findfont");
+ gen.writeln("dup length dict begin");
+ gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall");
+ gen.writeln(" /Encoding " + encoding.getName() + " def");
+
+ gen.writeln(" /CharStrings 256 dict dup begin");
+ String[] charNameMap = encoding.getCharNameMap();
+ char[] unicodeCharMap = encoding.getUnicodeCharMap();
+ assert charNameMap.length == unicodeCharMap.length;
+ for (int i = 0; i < charNameMap.length; i++) {
+ String glyphName = charNameMap[i];
+ gen.write(" /");
+ gen.write(glyphName);
+ gen.write(" ");
+ if (glyphName.equals(".notdef")) {
+ gen.write(0);
+ } else {
+ gen.write(getGlyphIndex(unicodeCharMap[i], cmap));
+ }
+ gen.writeln(" def");
+ }
+ gen.writeln(" end readonly def");
+
+ gen.writeln(" currentdict");
+ gen.writeln("end");
+ gen.writeln("/" + fontName + " exch definefont pop");
+ gen.writeDSCComment(DSCConstants.END_RESOURCE);
+ gen.getResourceTracker().registerSuppliedResource(res);
+ return res;
+ }
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSPainter.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSPainter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSPainter.java Fri Jun 22 18:07:04 2012
@@ -44,6 +44,7 @@ import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.RenderingContext;
@@ -55,6 +56,7 @@ import org.apache.fop.render.intermediat
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.CharUtilities;
+import org.apache.fop.util.HexEncoder;
/**
* IFPainter implementation that produces PostScript.
@@ -392,7 +394,7 @@ public class PSPainter extends AbstractI
if (currentEncoding != encoding) {
if (i > 0) {
writeText(text, start, i - start,
- letterSpacing, wordSpacing, dp, font, tf);
+ letterSpacing, wordSpacing, dp, font, tf, false);
}
if (encoding == 0) {
useFont(fontKey, sizeMillipoints);
@@ -404,19 +406,18 @@ public class PSPainter extends AbstractI
}
}
} else {
- //Simple single-font painting
useFont(fontKey, sizeMillipoints);
}
- writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, tf);
+ writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, tf,
+ tf instanceof MultiByteFont);
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
}
}
- private void writeText( // CSOK: ParameterNumber
- String text, int start, int len,
+ private void writeText(String text, int start, int len,
int letterSpacing, int wordSpacing, int[][] dp,
- Font font, Typeface tf) throws IOException {
+ Font font, Typeface tf, boolean multiByte) throws IOException {
PSGenerator generator = getGenerator();
int end = start + len;
int initialSize = len;
@@ -451,8 +452,12 @@ public class PSPainter extends AbstractI
if (dx != null && i < dxl - 1) {
glyphAdjust -= dx[i + 1];
}
- char codepoint = (char)(ch % 256);
- PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
+ if (multiByte) {
+ accText.append(HexEncoder.encode(ch));
+ } else {
+ char codepoint = (char)(ch % 256);
+ PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
+ }
if (glyphAdjust != 0) {
needTJ = true;
if (sb.length() == 0) {
@@ -463,9 +468,8 @@ public class PSPainter extends AbstractI
sb.append(PSGenerator.LF);
lineStart = sb.length();
}
- sb.append('(');
- sb.append(accText);
- sb.append(") ");
+ lineStart = writePostScriptString(sb, accText, multiByte, lineStart);
+ sb.append(' ');
accText.setLength(0); //reset accumulated text
}
sb.append(Integer.toString(glyphAdjust)).append(' ');
@@ -473,9 +477,10 @@ public class PSPainter extends AbstractI
}
if (needTJ) {
if (accText.length() > 0) {
- sb.append('(');
- sb.append(accText);
- sb.append(')');
+ if ((sb.length() - lineStart + accText.length()) > 200) {
+ sb.append(PSGenerator.LF);
+ }
+ writePostScriptString(sb, accText, multiByte);
}
if (hasLetterSpacing) {
sb.append("] " + formatMptAsPt(generator, letterSpacing) + " ATJ");
@@ -483,7 +488,7 @@ public class PSPainter extends AbstractI
sb.append("] TJ");
}
} else {
- sb.append('(').append(accText).append(")");
+ writePostScriptString(sb, accText, multiByte);
if (hasLetterSpacing) {
StringBuffer spb = new StringBuffer();
spb.append(formatMptAsPt(generator, letterSpacing))
@@ -497,12 +502,37 @@ public class PSPainter extends AbstractI
generator.writeln(sb.toString());
}
+ private void writePostScriptString(StringBuffer buffer, StringBuffer string,
+ boolean multiByte) {
+ writePostScriptString(buffer, string, multiByte, 0);
+ }
+
+ private int writePostScriptString(StringBuffer buffer, StringBuffer string, boolean multiByte,
+ int lineStart) {
+ buffer.append(multiByte ? '<' : '(');
+ int l = string.length();
+ int index = 0;
+ int maxCol = 200;
+ buffer.append(string.substring(index, Math.min(index + maxCol, l)));
+ index += maxCol;
+ while (index < l) {
+ if (!multiByte) {
+ buffer.append('\\');
+ }
+ buffer.append(PSGenerator.LF);
+ lineStart = buffer.length();
+ buffer.append(string.substring(index, Math.min(index + maxCol, l)));
+ index += maxCol;
+ }
+ buffer.append(multiByte ? '>' : ')');
+ return lineStart;
+ }
+
private void useFont(String key, int size) throws IOException {
- PSResource res = this.documentHandler.getPSResourceForFontKey(key);
+ PSFontResource res = this.documentHandler.getPSResourceForFontKey(key);
PSGenerator generator = getGenerator();
generator.useFont("/" + res.getName(), size / 1000f);
- generator.getResourceTracker().notifyResourceUsageOnPage(res);
+ res.notifyResourceUsageOnPage(generator.getResourceTracker());
}
-
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSTextPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSTextPainter.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSTextPainter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSTextPainter.java Fri Jun 22 18:07:04 2012
@@ -41,12 +41,15 @@ import org.apache.batik.gvt.text.TextSpa
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;
-import org.apache.xmlgraphics.ps.PSResource;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.svg.NativeTextPainter;
import org.apache.fop.util.CharUtilities;
+import org.apache.fop.util.HexEncoder;
/**
* Renders the attributed character iterator of a text node.
@@ -240,9 +243,9 @@ public class PSTextPainter extends Nativ
}
}
- private PSResource getResourceForFont(Font f, String postfix) {
+ private PSFontResource getResourceForFont(Font f, String postfix) {
String key = (postfix != null ? f.getFontName() + '_' + postfix : f.getFontName());
- return this.fontResources.getPSResourceForFontKey(key);
+ return this.fontResources.getFontResourceForFontKey(key);
}
private void clip(PSGraphics2D ps, Shape shape) throws IOException {
@@ -299,9 +302,9 @@ public class PSTextPainter extends Nativ
public void selectFont(Font f, char mapped) throws IOException {
int encoding = mapped / 256;
String postfix = (encoding == 0 ? null : Integer.toString(encoding));
- PSResource res = getResourceForFont(f, postfix);
+ PSFontResource res = getResourceForFont(f, postfix);
gen.useFont("/" + res.getName(), f.getFontSize() / 1000f);
- gen.getResourceTracker().notifyResourceUsageOnPage(res);
+ res.notifyResourceUsageOnPage(gen.getResourceTracker());
}
public Font getCurrentFont() {
@@ -427,15 +430,23 @@ public class PSTextPainter extends Nativ
textUtil.setCurrentFont(f, mapped);
applyColor(paint, gen);
+ FontMetrics metrics = f.getFontMetrics();
+ boolean multiByte = metrics instanceof MultiByteFont
+ || metrics instanceof LazyFont
+ && ((LazyFont) metrics).getRealFont() instanceof MultiByteFont;
StringBuffer sb = new StringBuffer();
- sb.append('(');
+ sb.append(multiByte ? '<' : '(');
for (int i = 0, c = this.currentChars.length(); i < c; i++) {
char ch = this.currentChars.charAt(i);
mapped = f.mapChar(ch);
- char codepoint = (char) (mapped % 256);
- PSGenerator.escapeChar(codepoint, sb);
+ if (multiByte) {
+ sb.append(HexEncoder.encode(mapped));
+ } else {
+ char codepoint = (char) (mapped % 256);
+ PSGenerator.escapeChar(codepoint, sb);
+ }
}
- sb.append(')');
+ sb.append(multiByte ? '>' : ')');
if (x || y) {
sb.append("\n[");
int idx = 0;
@@ -513,10 +524,20 @@ public class PSTextPainter extends Nativ
textUtil.selectFont(f, mapped);
textUtil.setCurrentFont(f, mapped);
}
- mapped = f.mapChar(this.currentChars.charAt(i));
//add glyph outlines to current path
- char codepoint = (char)(mapped % 256);
- gen.write("(" + codepoint + ")");
+ mapped = f.mapChar(this.currentChars.charAt(i));
+ FontMetrics metrics = f.getFontMetrics();
+ boolean multiByte = metrics instanceof MultiByteFont
+ || metrics instanceof LazyFont
+ && ((LazyFont) metrics).getRealFont() instanceof MultiByteFont;
+ if (multiByte) {
+ gen.write('<');
+ gen.write(HexEncoder.encode(mapped));
+ gen.write('>');
+ } else {
+ char codepoint = (char)(mapped % 256);
+ gen.write("(" + codepoint + ")");
+ }
gen.writeln(" false charpath");
if (iter.hasNext()) {
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ResourceHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ResourceHandler.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ResourceHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ResourceHandler.java Fri Jun 22 18:07:04 2012
@@ -83,6 +83,8 @@ public class ResourceHandler implements
private FOUserAgent userAgent;
private FontInfo fontInfo;
+ private PSEventProducer eventProducer;
+
private ResourceTracker resTracker;
//key: URI, values PSImageFormResource
@@ -93,13 +95,15 @@ public class ResourceHandler implements
/**
* Main constructor.
* @param userAgent the FO user agent
+ * @param eventProducer the event producer
* @param fontInfo the font information
* @param resTracker the resource tracker to use
* @param formResources Contains all forms used by this document (maintained by PSRenderer)
*/
- public ResourceHandler(FOUserAgent userAgent, FontInfo fontInfo,
- ResourceTracker resTracker, Map formResources) {
+ public ResourceHandler(FOUserAgent userAgent, PSEventProducer eventProducer,
+ FontInfo fontInfo, ResourceTracker resTracker, Map formResources) {
this.userAgent = userAgent;
+ this.eventProducer = eventProducer;
this.fontInfo = fontInfo;
this.resTracker = resTracker;
determineInlineForms(formResources);
@@ -222,7 +226,7 @@ public class ResourceHandler implements
if (fontSetupPlaceholder == null) {
throw new DSCException("Didn't find %FOPFontSetup comment in stream");
}
- PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts());
+ PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts(), eventProducer);
generateForms(globalFormResources, gen);
//Skip the prolog and to the first page
Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java
------------------------------------------------------------------------------
Merged /xmlgraphics/fop/branches/Temp_TrueTypeInPostScript/src/java/org/apache/fop/util/ColorExt.java:r949179-1352964
Modified: xmlgraphics/fop/trunk/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/status.xml?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/status.xml (original)
+++ xmlgraphics/fop/trunk/status.xml Fri Jun 22 18:07:04 2012
@@ -63,6 +63,9 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Renderers" dev="VH" type="add" fixes-bug="52338" importance="high">
+ Added possibility to embed TrueType fonts in PostScript.
+ </action>
<action context="Images" dev="GA" type="update" fixes-bug="40676" due-to="Luis Bernardo">
Update site documentation about PNG image loading configuration and support.
</action>
Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java Fri Jun 22 18:07:04 2012
@@ -28,10 +28,13 @@ import org.apache.fop.pdf.FileIDGenerato
import org.apache.fop.pdf.PDFDocumentGraphics2DTestCase;
import org.apache.fop.pdf.PDFEncryptionJCETestCase;
import org.apache.fop.pdf.PDFFactoryTestCase;
+import org.apache.fop.pdf.PDFNumberTestCase;
+import org.apache.fop.pdf.PDFObjectTestCase;
import org.apache.fop.traits.BorderPropsTestCase;
import org.apache.fop.util.BitmapImageUtilTestCase;
import org.apache.fop.util.ColorUtilTestCase;
import org.apache.fop.util.ElementListUtilsTestCase;
+import org.apache.fop.util.HexEncoderTestCase;
import org.apache.fop.util.XMLResourceBundleTestCase;
/**
@@ -49,7 +52,10 @@ import org.apache.fop.util.XMLResourceBu
PDFFactoryTestCase.class,
PDFEncryptionJCETestCase.class,
BitmapImageUtilTestCase.class,
- PDFDocumentGraphics2DTestCase.class
+ PDFDocumentGraphics2DTestCase.class,
+ PDFNumberTestCase.class,
+ PDFObjectTestCase.class,
+ HexEncoderTestCase.class
})
public class UtilityCodeTestSuite {
}
Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java Fri Jun 22 18:07:04 2012
@@ -43,7 +43,8 @@ public class DejaVuLGCSerifTestCase {
@Before
public void setUp() throws Exception {
File file = new File("test/resources/fonts/ttf/DejaVuLGCSerif.ttf");
- font = FontLoader.loadFont(file, "", true, EncodingMode.AUTO, fontResolver);
+ font = FontLoader.loadFont(file, "", true, EmbeddingMode.AUTO, EncodingMode.AUTO,
+ fontResolver);
}
/**
Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/EncodingModeTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/EncodingModeTestCase.java?rev=1352986&r1=1352985&r2=1352986&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/EncodingModeTestCase.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/fonts/EncodingModeTestCase.java Fri Jun 22 18:07:04 2012
@@ -19,10 +19,13 @@
package org.apache.fop.fonts;
-import static org.junit.Assert.assertEquals;
-
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link EncodingMode}.
+ */
public class EncodingModeTestCase {
@Test
@@ -34,8 +37,13 @@ public class EncodingModeTestCase {
@Test
public void testGetValue() {
- assertEquals(EncodingMode.AUTO, EncodingMode.getEncodingMode("auto"));
- assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getEncodingMode("single-byte"));
- assertEquals(EncodingMode.CID, EncodingMode.getEncodingMode("cid"));
+ assertEquals(EncodingMode.AUTO, EncodingMode.getValue("auto"));
+ assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getValue("single-byte"));
+ assertEquals(EncodingMode.CID, EncodingMode.getValue("cid"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getValueMustCheckForIllegalArguments() {
+ EncodingMode.getValue("fail");
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org