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