]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Add t1 merging Temp_FontMerging Temp_FontMerging
authorSimon Steiner <ssteiner@apache.org>
Fri, 20 Jun 2014 09:27:37 +0000 (09:27 +0000)
committerSimon Steiner <ssteiner@apache.org>
Fri, 20 Jun 2014 09:27:37 +0000 (09:27 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FontMerging@1604113 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/fonts/truetype/OpenFont.java
src/java/org/apache/fop/fonts/type1/PostscriptParser.java
src/java/org/apache/fop/fonts/type1/Type1SubsetFile.java
src/java/org/apache/fop/pdf/PDFFactory.java
src/java/org/apache/fop/render/ps/PSFontUtils.java
test/java/org/apache/fop/fonts/type1/Type1SubsetFileTestCase.java

index 98fced01f248c8263a630a899444f9030311b907..7b259b92631339564626085480e83de961fda573 100644 (file)
@@ -168,7 +168,7 @@ public abstract class OpenFont {
     protected List<UnicodeMapping> unicodeMappings;
 
     private int upem;                                // unitsPerEm from "head" table
-    private int nhmtx;                               // Number of horizontal metrics
+    protected int nhmtx;                               // Number of horizontal metrics
     private PostScriptVersion postScriptVersion;
     protected int locaFormat;
     /**
index 05c3c6453f8e46ea9a5d6867bf9f43c6b088e9fc..87ff6d60981ef2eda63267521e4a176cdc7771f9 100644 (file)
@@ -31,7 +31,7 @@ import java.util.Scanner;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-class PostscriptParser {
+public class PostscriptParser {
 
     protected static final Log LOG = LogFactory.getLog(PostscriptParser.class);
     /* Patterns used to identify Postscript elements */
index 6e6a7f26b4fded853905d3d1f8b1ef8a9442f317..7b05e567d9c9f90f8406f9360a582b7cf7272db1 100644 (file)
@@ -51,32 +51,31 @@ public class Type1SubsetFile {
 
     protected static final Log LOG = LogFactory.getLog(Type1SubsetFile.class);
     /* The subset list of char strings */
-    private HashMap<String, byte[]> subsetCharStrings;
+    protected HashMap<String, byte[]> subsetCharStrings;
     /* The list of character names in the subset font */
-    private List<String> charNames = null;
+    protected List<String> charNames = null;
     /* A list of unique subroutines references */
-    private LinkedHashMap<Integer, byte[]> uniqueSubs;
+    protected LinkedHashMap<Integer, byte[]> uniqueSubs;
     private SingleByteFont sbfont = null;
     /* New line character */
-    private String eol = "\n";
+    protected String eol = "\n";
     /* An option to determine whether the subroutines are subset */
-    private boolean subsetSubroutines = true;
+    protected boolean subsetSubroutines = true;
     private byte[] fullFont;
     //List of parsed Postscript elements
-    private List<PSElement> headerSection;
-    private List<PSElement> mainSection;
+    protected List<PSElement> headerSection;
+    protected List<PSElement> mainSection;
     //Determines whether the current font uses standard encoding
-    private boolean standardEncoding = false;
+    protected boolean standardEncoding = false;
 
     //Type 1 operators
     private static final int OP_SEAC = 6;
     private static final int OP_CALLSUBR = 10;
     private static final int OP_CALLOTHERSUBR = 16;
 
-    public byte[] createSubset(InputStream in, SingleByteFont sbfont,
-            String fontPrefix) throws IOException {
+    public byte[] createSubset(InputStream in, SingleByteFont sbfont) throws IOException {
         fullFont = IOUtils.toByteArray(in);
-        byte[] subsetFont = createSubset(sbfont, fontPrefix, true);
+        byte[] subsetFont = createSubset(sbfont, true);
         //This should never happen but ensure that subset is shorter than original font
         return (subsetFont.length == 0 || subsetFont.length > fullFont.length)
                 ? fullFont : subsetFont;
@@ -84,17 +83,14 @@ public class Type1SubsetFile {
 
     /**
      * Creates a new subset from the given type 1 font input stream
-     * @param in The type 1 font to subset
      * @param sbfont The font object containing information such as the
      * characters from which to create the subset
-     * @param fontPrefix The prefix used in identifying the subset font
-     * @param allSubroutines This option will force the subset to include all
+     * @param subsetSubroutines This option will force the subset to include all
      * subroutines.
      * @return Returns the subset as a byte array
      * @throws IOException
      */
-    private byte[] createSubset(SingleByteFont sbfont,
-            String fontPrefix, boolean subsetSubroutines) throws IOException {
+    private byte[] createSubset(SingleByteFont sbfont, boolean subsetSubroutines) throws IOException {
         this.subsetSubroutines = subsetSubroutines;
         InputStream in = new ByteArrayInputStream(fullFont);
         //Initialise resources used for the font creation
@@ -132,8 +128,8 @@ public class Type1SubsetFile {
 
         //Process and write the main section
         PSElement charStrings = getElement("/CharStrings", mainSection);
-        int result = readMainSection(mainSection, decoded, subsetEncodingEntries, charStrings);
-        if (result == 0) {
+        boolean result = readMainSection(mainSection, decoded, subsetEncodingEntries, charStrings);
+        if (!result) {
             /* This check handles the case where a font uses a postscript method to return a
              * subroutine index. As there is currently no java postscript interpreter and writing
              * one would be very difficult it prevents us from handling this eventuality. The way
@@ -142,16 +138,16 @@ public class Type1SubsetFile {
             uniqueSubs.clear();
             subsetCharStrings.clear();
             charNames.clear();
-            return createSubset(sbfont, fontPrefix, false);
+            return createSubset(sbfont, false);
         }
 
         //Write header section
-        ByteArrayOutputStream boasHeader = writeHeader(pfbData, encoding, subsetEncodingEntries);
+        ByteArrayOutputStream boasHeader = writeHeader(pfbData, encoding);
 
         ByteArrayOutputStream boasMain = writeMainSection(decoded, mainSection, charStrings);
         byte[] mainSectionBytes = boasMain.toByteArray();
         mainSectionBytes = BinaryCoder.encodeBytes(mainSectionBytes, 55665, 4);
-        boasMain = new ByteArrayOutputStream();
+        boasMain.reset();
         boasMain.write(mainSectionBytes);
 
         ByteArrayOutputStream baosTrailer = new ByteArrayOutputStream();
@@ -160,8 +156,8 @@ public class Type1SubsetFile {
         return stitchFont(boasHeader, boasMain, baosTrailer);
     }
 
-    byte[] stitchFont(ByteArrayOutputStream boasHeader, ByteArrayOutputStream boasMain,
-            ByteArrayOutputStream boasTrailer) throws IOException {
+    protected byte[] stitchFont(ByteArrayOutputStream boasHeader, ByteArrayOutputStream boasMain,
+                                ByteArrayOutputStream boasTrailer) throws IOException {
         int headerLength = boasHeader.size();
         int mainLength = boasMain.size();
 
@@ -205,7 +201,7 @@ public class Type1SubsetFile {
                 /* If no matches are found, create a new entry for the character so
                  * that it can be added even if it's not in the current encoding. */
                 if (matches.size() == 0) {
-                    matches = new ArrayList<String>();
+                    matches.clear();
                     if (glyph == 0) {
                         matches.add("dup 0 /.notdef put");
                     } else {
@@ -237,7 +233,7 @@ public class Type1SubsetFile {
         return subsetEncodingEntries;
     }
 
-    private List<String> searchEntries(HashMap<Integer, String> encodingEntries, int glyph) {
+    protected List<String> searchEntries(HashMap<Integer, String> encodingEntries, int glyph) {
         List<String> matches = new ArrayList<String>();
         for (Entry<Integer, String> entry : encodingEntries.entrySet()) {
             String tag = getEntryPart(entry.getValue(), 3);
@@ -249,15 +245,13 @@ public class Type1SubsetFile {
         return matches;
     }
 
-    private ByteArrayOutputStream writeHeader(PFBData pfbData, PSElement encoding,
-            List<String> subsetEncodingEntries) throws UnsupportedEncodingException,
-            IOException {
+    protected ByteArrayOutputStream writeHeader(PFBData pfbData, PSElement encoding) throws IOException {
         ByteArrayOutputStream boasHeader = new ByteArrayOutputStream();
         boasHeader.write(pfbData.getHeaderSegment(), 0, encoding.getStartPoint() - 1);
 
         if (!standardEncoding) {
             //Write out the new encoding table for the subset font
-            String encodingArray = eol + String.format("/Encoding %d array", 256) + eol
+            String encodingArray = eol + "/Encoding 256 array" + eol
                     + "0 1 255 {1 index exch /.notdef put } for" + eol;
             byte[] encodingDefinition = encodingArray.getBytes("ASCII");
             boasHeader.write(encodingDefinition, 0, encodingDefinition.length);
@@ -287,7 +281,7 @@ public class Type1SubsetFile {
         return boas;
     }
 
-    private int readMainSection(List<PSElement> mainSection, byte[] decoded,
+    private boolean readMainSection(List<PSElement> mainSection, byte[] decoded,
             List<String> subsetEncodingEntries, PSElement charStrings) {
         subsetEncodingEntries.add(0, "dup 0 /.notdef put");
         /* Reads and parses the charStrings section to subset the charString
@@ -322,19 +316,19 @@ public class Type1SubsetFile {
                 /* Recursively scan the charString array for subroutines and if found, copy the
                  * entry to our subset entries and update any references. */
                 charStringEntry = createSubsetCharStrings(decoded, charStringEntry, subroutines,
-                        subsetEncodingEntries, tag);
+                        subsetEncodingEntries);
             }
             if (charStringEntry.length == 0) {
-                return 0;
+                return false;
             }
             charStringEntry = BinaryCoder.encodeBytes(charStringEntry, 4330, skipBytes);
             subsetCharStrings.put(tag, charStringEntry);
         }
-        return 1;
+        return true;
     }
 
     private byte[] createSubsetCharStrings(byte[] decoded, byte[] data, PSFixedArray subroutines,
-            List<String> subsetEncodingEntries, String glyphName) {
+            List<String> subsetEncodingEntries) {
         List<BytesNumber> operands = new ArrayList<BytesNumber>();
         for (int i = 0; i < data.length; i++) {
             int cur = data[i] & 0xFF;
@@ -348,11 +342,11 @@ public class Type1SubsetFile {
                     if (uniqueSubs.get(operands.get(operands.size() - 1).getNumber()) == null) {
                         uniqueSubs.put(operands.get(operands.size() - 1).getNumber(), new byte[0]);
                         data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries,
-                                glyphName, data, i, 1, -1, operands.get(
+                                data, i, 1, -1, operands.get(
                                         operands.size() - 1).getNumber());
                     } else {
                         data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries,
-                                glyphName, data, i, 1, getSubrIndex(operands.get(
+                                data, i, 1, getSubrIndex(operands.get(
                                         operands.size() - 1).getNumber()), operands.get(
                                                 operands.size() - 1).getNumber());
                     }
@@ -390,7 +384,7 @@ public class Type1SubsetFile {
                             return new byte[0];
                         }
                         data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries,
-                                glyphName, data, i, 2, -1, operands.get(0).getNumber());
+                                data, i, 2, -1, operands.get(0).getNumber());
                     }
                 }
                 if (data.length == 0) {
@@ -431,14 +425,14 @@ public class Type1SubsetFile {
     }
 
     private byte[] addSubroutine(PSFixedArray subroutines, List<BytesNumber> operands, byte[] decoded,
-            List<String> subsetEncodingEntries, String glyphName, byte[] data, int i, int opLength,
+            List<String> subsetEncodingEntries, byte[] data, int i, int opLength,
             int existingSubrRef, int subrID) {
         if (existingSubrRef == -1) {
             int[] subrData = subroutines.getBinaryEntryByIndex(subrID);
             byte[] subroutine = getBinaryEntry(subrData, decoded);
             subroutine = BinaryCoder.decodeBytes(subroutine, 4330, 4);
             subroutine = createSubsetCharStrings(decoded, subroutine, subroutines,
-                    subsetEncodingEntries, glyphName);
+                    subsetEncodingEntries);
             if (subroutine.length == 0) {
                 return new byte[0];
             }
@@ -451,8 +445,8 @@ public class Type1SubsetFile {
         return data;
     }
 
-    private ByteArrayOutputStream writeMainSection(byte[] decoded, List<PSElement> mainSection,
-            PSElement charStrings) throws IOException {
+    protected ByteArrayOutputStream writeMainSection(byte[] decoded, List<PSElement> mainSection,
+                                                     PSElement charStrings) throws IOException {
         ByteArrayOutputStream main = new ByteArrayOutputStream();
         PSElement subrs = getElement("/Subrs", mainSection);
 
@@ -470,11 +464,9 @@ public class Type1SubsetFile {
             writeString(eol + String.format("/Subrs %d array", uniqueSubs.size()), main);
             int count = 0;
             for (Entry<Integer, byte[]> entry : uniqueSubs.entrySet()) {
-                byte[] newSubrBytes = (eol + String.format("dup %d %d %s ", count++,
-                        entry.getValue().length, rd)).getBytes("ASCII");
-                newSubrBytes = concatArray(newSubrBytes, entry.getValue());
-                newSubrBytes = concatArray(newSubrBytes, String.format(" %s", np).getBytes("ASCII"));
-                main.write(newSubrBytes);
+                writeString(eol + String.format("dup %d %d %s ", count++, entry.getValue().length, rd), main);
+                main.write(entry.getValue());
+                writeString(" " + np, main);
             }
             writeString(eol + nd, main);
         } else {
@@ -498,8 +490,8 @@ public class Type1SubsetFile {
         return main;
     }
 
-    private String findVariable(byte[] decoded, List<PSElement> elements, String[] matches,
-            String fallback) throws UnsupportedEncodingException {
+    protected String findVariable(byte[] decoded, List<PSElement> elements, String[] matches,
+                                  String fallback) throws UnsupportedEncodingException {
         for (PSElement element : elements) {
             if (element instanceof PSSubroutine) {
                 byte[] var = new byte[element.getEndPoint() - element.getStartPoint()];
@@ -575,8 +567,8 @@ public class Type1SubsetFile {
         sbfont.mapUsedGlyphName(charIndex, charName);
     }
 
-    private void writeString(String entry, ByteArrayOutputStream boas)
-            throws UnsupportedEncodingException, IOException {
+    protected void writeString(String entry, ByteArrayOutputStream boas)
+            throws IOException {
         byte[] byteEntry = entry.getBytes("ASCII");
         boas.write(byteEntry);
     }
@@ -696,7 +688,7 @@ public class Type1SubsetFile {
      * @param decoded The array from which to copy a section of data
      * @return Returns the copy of the data section
      */
-    byte[] getBinaryEntry(int[] position, byte[] decoded) {
+    protected byte[] getBinaryEntry(int[] position, byte[] decoded) {
         int start = position[0];
         int finish = position[1];
         byte[] line = new byte[finish - start];
@@ -704,7 +696,7 @@ public class Type1SubsetFile {
         return line;
     }
 
-    private String getEntryPart(String entry, int part) {
+    protected String getEntryPart(String entry, int part) {
         Scanner s = new Scanner(entry).useDelimiter(" ");
         for (int i = 1; i < part; i++) {
             s.next();
@@ -712,7 +704,7 @@ public class Type1SubsetFile {
         return s.next();
     }
 
-    private PSElement getElement(String elementID, List<PSElement> elements) {
+    protected PSElement getElement(String elementID, List<PSElement> elements) {
         for (PSElement element : elements) {
             if (element.getOperator().equals(elementID)) {
                 return element;
@@ -721,14 +713,6 @@ public class Type1SubsetFile {
         return null;
     }
 
-    /**
-     * Gets the list of subset character names
-     * @return Returns the subset character names
-     */
-    public List<String> getCharNames() {
-        return charNames;
-    }
-
     /**
      * A class to encode and decode sections of a type 1 font file. See Adobe
      * Type 1 Font Format Section 7.2 for more details.
index 1d93e9979f9228a8004b0d756461873a593338c8..0f723d22846a8d5283a1226189968e552870c149 100644 (file)
@@ -1699,7 +1699,7 @@ public class PDFFactory {
                     assert font instanceof SingleByteFont;
                     SingleByteFont sbfont = (SingleByteFont)font;
                     Type1SubsetFile pfbFile = new Type1SubsetFile();
-                    byte[] subsetData = pfbFile.createSubset(in, sbfont, fontPrefix);
+                    byte[] subsetData = pfbFile.createSubset(in, sbfont);
                     InputStream subsetStream = new ByteArrayInputStream(subsetData);
                     PFBParser parser = new PFBParser();
                     PFBData pfb = parser.parsePFB(subsetStream);
index 5bb723eeabc1795aa58e99d23b8849c03e978f68..b98919ca232fde1bb5da59facbc6df9143c4a3f5 100644 (file)
@@ -324,7 +324,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
         boolean embed = true;
         if (font.getEmbeddingMode() == EmbeddingMode.SUBSET) {
             Type1SubsetFile subset = new Type1SubsetFile();
-            byte[] byteSubset = subset.createSubset(fontStream, font, "");
+            byte[] byteSubset = subset.createSubset(fontStream, font);
             fontStream = new ByteArrayInputStream(byteSubset);
         }
         embedType1Font(gen, fontStream);
index e18173a6bfe6217d616bb5ab76ec5d732b7ccca1..3d7093bd35425c93e3a3fb3d9b79d641e5cb2b57 100644 (file)
@@ -54,7 +54,7 @@ public class Type1SubsetFileTestCase {
     @Test
     public void test() throws IOException {
         InputStream in = new FileInputStream(TEST_FONT_A);
-        compareCharStringData(in, TEST_FONT_A, createFontASubset(in, TEST_FONT_A));
+        compareCharStringData(TEST_FONT_A, createFontASubset(in, TEST_FONT_A));
     }
 
     @Test
@@ -135,12 +135,12 @@ public class Type1SubsetFileTestCase {
         assertEquals(segment[3], 65);
     }
 
-    private void compareCharStringData(InputStream in, String font, byte[] subsetFont)
+    private void compareCharStringData(String font, byte[] subsetFont)
             throws IOException {
         decodedSections = new ArrayList<byte[]>();
 
         //Reinitialise the input stream as reset only supports 1000 bytes.
-        in = new FileInputStream(font);
+        InputStream in = new FileInputStream(font);
         List<PSElement> origElements = parseElements(in);
         List<PSElement> subsetElements = parseElements(new ByteArrayInputStream(subsetFont));
 
@@ -173,8 +173,6 @@ public class Type1SubsetFileTestCase {
         SingleByteFont sbfont = mock(SingleByteFont.class);
         //Glyph index & selector
         Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>();
-        //Selector & unicode
-        Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>();
         Map<Integer, String> usedCharNames = new HashMap<Integer, String>();
         int count = 0;
         for (int i = 32; i < 127; i++) {
@@ -185,7 +183,6 @@ public class Type1SubsetFileTestCase {
         }
         for (int i = 161; i < 204; i++) {
             glyphs.put(i, count++);
-            usedCharsIndex.put(count, (char)i);
             when(sbfont.getUnicodeFromSelector(count)).thenReturn((char)i);
             usedCharNames.put(i, String.format("/%s", Glyphs.charToGlyphName((char)i)));
             when(sbfont.getGlyphName(i)).thenReturn(AdobeStandardEncoding.getCharFromCodePoint(i));
@@ -195,14 +192,12 @@ public class Type1SubsetFileTestCase {
         };
         for (int i = 0; i < randomGlyphs.length; i++) {
             glyphs.put(randomGlyphs[i], count++);
-            usedCharsIndex.put(count, (char)randomGlyphs[i]);
             when(sbfont.getUnicodeFromSelector(count)).thenReturn((char)randomGlyphs[i]);
             usedCharNames.put(i, String.format("/%s", Glyphs.charToGlyphName((char)i)));
             when(sbfont.getGlyphName(i)).thenReturn(AdobeStandardEncoding.getCharFromCodePoint(i));
         }
         for (int i = 256; i < 335; i++) {
             glyphs.put(i, count++);
-            usedCharsIndex.put(count, (char)i);
             when(sbfont.getUnicodeFromSelector(count)).thenReturn((char)i);
             usedCharNames.put(i, String.format("/%s", Glyphs.charToGlyphName((char)i)));
             when(sbfont.getGlyphName(i)).thenReturn(AdobeStandardEncoding.getCharFromCodePoint(i));
@@ -211,7 +206,7 @@ public class Type1SubsetFileTestCase {
         when(sbfont.getUsedGlyphs()).thenReturn(glyphs);
         when(sbfont.getEmbedFileURI()).thenReturn(URI.create(font));
         Type1SubsetFile subset = new Type1SubsetFile();
-        return subset.createSubset(in, sbfont, "AAAAAA");
+        return subset.createSubset(in, sbfont);
     }
 
     private List<PSElement> parseElements(InputStream in)
@@ -235,7 +230,6 @@ public class Type1SubsetFileTestCase {
 
     private byte[] readFullCharString(byte[] decoded, byte[] data, PSFixedArray subroutines) {
         List<BytesNumber> operands = new ArrayList<BytesNumber>();
-        List<BytesNumber> fullList = new ArrayList<BytesNumber>();
         for (int i = 0; i < data.length; i++) {
             int cur = data[i] & 0xFF;
             if (cur >= 0 && cur <= 31) {
@@ -256,20 +250,16 @@ public class Type1SubsetFileTestCase {
                     }
                     BytesNumber operand = new BytesNumber(cur, i);
                     operand.setName(getName(cur, next));
-                    fullList.add(operand);
                 }
                 operands.clear();
             }
             if (cur >= 32 && cur <= 246) {
                 operands.add(new BytesNumber(cur - 139, 1));
-                fullList.add(operands.get(operands.size() - 1));
             } else if (cur >= 247 && cur <= 250) {
                 operands.add(new BytesNumber((cur - 247) * 256 + (data[i + 1] & 0xFF) + 108, 2));
-                fullList.add(operands.get(operands.size() - 1));
                 i++;
             } else if (cur >= 251 && cur <= 254) {
                 operands.add(new BytesNumber(-(cur - 251) * 256 - (data[i + 1] & 0xFF) - 108, 2));
-                fullList.add(operands.get(operands.size() - 1));
                 i++;
             } else if (cur == 255) {
                 int b1 = data[i + 1] & 0xFF;
@@ -278,7 +268,6 @@ public class Type1SubsetFileTestCase {
                 int b4 = data[i + 4] & 0xFF;
                 int value = b1 << 24 | b2 << 16 | b3 << 8 | b4;
                 operands.add(new BytesNumber(value, 5));
-                fullList.add(operands.get(operands.size() - 1));
                 i += 4;
             }
         }