]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Bugzilla#53868: Full font embedding in PDF
authorMehdi Houshmand <mehdi@apache.org>
Fri, 14 Sep 2012 09:13:40 +0000 (09:13 +0000)
committerMehdi Houshmand <mehdi@apache.org>
Fri, 14 Sep 2012 09:13:40 +0000 (09:13 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1384690 13f79535-47bb-0310-9956-ffa450edef68

14 files changed:
src/java/org/apache/fop/fonts/CIDFont.java
src/java/org/apache/fop/fonts/CIDFull.java [new file with mode: 0644]
src/java/org/apache/fop/fonts/CIDSet.java [new file with mode: 0644]
src/java/org/apache/fop/fonts/CIDSubset.java
src/java/org/apache/fop/fonts/FontReader.java
src/java/org/apache/fop/fonts/LazyFont.java
src/java/org/apache/fop/fonts/MultiByteFont.java
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
src/java/org/apache/fop/pdf/PDFFactory.java
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java
src/java/org/apache/fop/render/ps/PSFontUtils.java
status.xml
test/java/org/apache/fop/fonts/CIDFullTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/pdf/PDFFactoryTestCase.java

index 82213dd6554c99a8ac14935ee72df2fc29cdc93c..dc398263ed692d39027559c2302ac9b4dcc6c258 100644 (file)
@@ -29,7 +29,7 @@ import org.apache.fop.apps.io.InternalResourceResolver;
 public abstract class CIDFont extends CustomFont {
 
     /** Contains the character widths for all characters in the font */
-    protected int[] width = null;
+    protected int[] width;
 
     /**
      * @param resourceResolver the URI resolver for controlling file access
@@ -69,7 +69,7 @@ public abstract class CIDFont extends CustomFont {
      * Returns the subset information for this font.
      * @return the subset information
      */
-    public abstract CIDSubset getCIDSubset();
+    public abstract CIDSet getCIDSet();
 
     // ---- Optional ----
     /**
diff --git a/src/java/org/apache/fop/fonts/CIDFull.java b/src/java/org/apache/fop/fonts/CIDFull.java
new file mode 100644 (file)
index 0000000..ee062a2
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.fop.util.CharUtilities;
+
+/**
+ * Provides methods to get font information.
+ * Naming:
+ * glyph index: original index of the glyph in the non-subset font (!= unicode index)
+ * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset
+ * fonts, this is the same as the glyph index.
+ * Unicode index: The Unicode codepoint of a character.
+ * Glyph name: the Adobe glyph name (as found in Glyphs.java)
+ */
+public class CIDFull implements CIDSet {
+
+    private BitSet glyphIndices;
+    private final MultiByteFont font;
+
+    public CIDFull(MultiByteFont mbf) {
+        font = mbf;
+    }
+
+    private void initGlyphIndices() {
+        // this cannot be called in the constructor since the font is not ready...
+        if (glyphIndices == null) {
+            glyphIndices = font.getGlyphIndices();
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int getOriginalGlyphIndex(int index) {
+        return index;
+    }
+
+    /** {@inheritDoc} */
+    public char getUnicode(int index) {
+        initGlyphIndices();
+        if (glyphIndices.get(index)) {
+            return (char) index;
+        } else {
+            return CharUtilities.NOT_A_CHARACTER;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int mapChar(int glyphIndex, char unicode) {
+        return (char) glyphIndex;
+    }
+
+    /** {@inheritDoc} */
+    public Map<Integer, Integer> getGlyphs() {
+        // this is never really called for full embedded fonts but the equivalent map would be the identity
+        initGlyphIndices();
+        Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>();
+        int nextBitSet = 0;
+        for (int j = 0; j < glyphIndices.cardinality(); j++) {
+            nextBitSet = glyphIndices.nextSetBit(nextBitSet);
+            glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet));
+            nextBitSet++;
+        }
+        return Collections.unmodifiableMap(glyphs);
+    }
+
+    /** {@inheritDoc} */
+    public char[] getChars() {
+        return font.getChars();
+    }
+
+    /** {@inheritDoc} */
+    public int getNumberOfGlyphs() {
+        initGlyphIndices();
+        // note: the real number of glyphs is given by the cardinality() method (not the length()) but since
+        // we will pad gaps in the indices with zeros we really want the length() here. this method is only
+        // called when embedding a font in PostScript and this will be the value of the CIDCount entry
+        return glyphIndices.length();
+    }
+
+    /** {@inheritDoc} */
+    public BitSet getGlyphIndices() {
+        initGlyphIndices();
+        return glyphIndices;
+    }
+
+    /** {@inheritDoc} */
+    public int[] getWidths() {
+        return font.getWidths();
+    }
+
+}
diff --git a/src/java/org/apache/fop/fonts/CIDSet.java b/src/java/org/apache/fop/fonts/CIDSet.java
new file mode 100644 (file)
index 0000000..30d1a5e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.util.BitSet;
+import java.util.Map;
+
+/**
+ * Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font.
+ */
+public interface CIDSet {
+
+    /**
+     * Returns the original index of the glyph inside the (non-subset) font's glyph list. This
+     * index can be used to access the character width information, for example.
+     * @param index the subset index (character selector) to access the glyph
+     * @return the original index (or -1 if no glyph index is available for the subset index)
+     */
+    int getOriginalGlyphIndex(int index);
+
+    /**
+     * Returns the Unicode value for a subset index (character selector). If there's no such
+     * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned.
+     * @param subsetIndex the subset index (character selector)
+     * @return the Unicode value or "NOT A CHARACTER" (0xFFFF)
+     */
+    char getUnicode(int index);
+
+    /**
+     * Maps a character to a character selector for a font subset. If the character isn't in the
+     * subset, yet, it is added and a new character selector returned. Otherwise, the already
+     * allocated character selector is returned from the existing map/subset.
+     * @param glyphIndex the glyph index of the character
+     * @param unicode the Unicode index of the character
+     * @return the subset index
+     */
+    int mapChar(int glyphIndex, char unicode);
+
+    /**
+     * Returns an unmodifiable Map of the font subset. It maps from glyph index to
+     * character selector (i.e. the subset index in this case).
+     * @return Map Map&lt;Integer, Integer&gt; of the font subset
+     */
+    Map<Integer, Integer> getGlyphs();
+
+    /**
+     * Returns a char array containing all Unicode characters that are in the subset.
+     * @return a char array with all used Unicode characters
+     */
+    char[] getChars();
+
+    /**
+     * Returns the number of glyphs in the subset.
+     * @return the number of glyphs in the subset
+     */
+    int getNumberOfGlyphs();
+
+    /**
+     * Returns a BitSet with bits set for each available glyph index in the subset.
+     * @return a BitSet indicating available glyph indices
+     */
+    BitSet getGlyphIndices();
+
+    /**
+     * Return the array of widths.
+     * <p>
+     * This is used to get an array for inserting in an output format.
+     * It should not be used for lookup.
+     * @return an array of widths
+     */
+    int[] getWidths();
+
+}
index 372a638d1b3e490d18bb46d666877d480fb88618..f442c13ed56e675e182ec6b245c001c6195ff12a 100644 (file)
@@ -26,18 +26,16 @@ import java.util.Map;
 
 import org.apache.fop.util.CharUtilities;
 
-//Naming:
-//glyph index: original index of the glyph in the non-subset font (!= unicode index)
-//character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For
-//  non-subset fonts, this is the same as the glyph index.
-//Unicode index: The Unicode codepoint of a character.
-//Glyph name: the Adobe glyph name (as found in Glyphs.java)
-
 /**
- * Keeps track of the glyphs used in a document. This information is later used to build
- * a subset of a font.
+ * Provides methods to get font information.
+ * Naming:
+ * glyph index: original index of the glyph in the non-subset font (!= unicode index)
+ * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset
+ * fonts, this is the same as the glyph index.
+ * Unicode index: The Unicode codepoint of a character.
+ * Glyph name: the Adobe glyph name (as found in Glyphs.java)
  */
-public class CIDSubset {
+public class CIDSubset implements CIDSet {
 
     /**
      * usedGlyphs contains orginal, new glyph index (glyph index -> char selector)
@@ -48,51 +46,36 @@ public class CIDSubset {
      * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index)
      */
     private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>();
-    private int usedGlyphsCount = 0;
+    private int usedGlyphsCount;
 
     /**
      * usedCharsIndex contains new glyph, original char (char selector -> Unicode)
      */
     private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>();
 
-    /**
-     * Default constructor.
-     */
-    public CIDSubset() {
-    }
+    private final MultiByteFont font;
 
-    /**
-     * Adds the first glyph which is reserved for .notdef for all CID subsets.
-     */
-    public void setupFirstGlyph() {
-        usedGlyphs.put(Integer.valueOf(0), Integer.valueOf(0));
-        usedGlyphsIndex.put(Integer.valueOf(0), Integer.valueOf(0));
+    public CIDSubset(MultiByteFont mbf) {
+        font = mbf;
+        // The zeroth value is reserved for .notdef
+        usedGlyphs.put(0, 0);
+        usedGlyphsIndex.put(0, 0);
         usedGlyphsCount++;
     }
 
-    /**
-     * Returns the original index of the glyph inside the (non-subset) font's glyph list. This
-     * index can be used to access the character width information, for example.
-     * @param subsetIndex the subset index (character selector) to access the glyph
-     * @return the original index (or -1 if no glyph index is available for the subset index)
-     */
-    public int getGlyphIndexForSubsetIndex(int subsetIndex) {
-        Integer glyphIndex = usedGlyphsIndex.get(Integer.valueOf(subsetIndex));
+    /** {@inheritDoc} */
+    public int getOriginalGlyphIndex(int index) {
+        Integer glyphIndex = usedGlyphsIndex.get(index);
         if (glyphIndex != null) {
-            return glyphIndex.intValue();
+            return glyphIndex;
         } else {
             return -1;
         }
     }
 
-    /**
-     * Returns the Unicode value for a subset index (character selector). If there's no such
-     * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned.
-     * @param subsetIndex the subset index (character selector)
-     * @return the Unicode value or "NOT A CHARACTER" (0xFFFF)
-     */
-    public char getUnicodeForSubsetIndex(int subsetIndex) {
-        Character mapValue = usedCharsIndex.get(Integer.valueOf(subsetIndex));
+    /** {@inheritDoc} */
+    public char getUnicode(int index) {
+        Character mapValue = usedCharsIndex.get(index);
         if (mapValue != null) {
             return mapValue.charValue();
         } else {
@@ -100,72 +83,60 @@ public class CIDSubset {
         }
     }
 
-    /**
-     * Maps a character to a character selector for a font subset. If the character isn't in the
-     * subset, yet, it is added and a new character selector returned. Otherwise, the already
-     * allocated character selector is returned from the existing map/subset.
-     * @param glyphIndex the glyph index of the character
-     * @param unicode the Unicode index of the character
-     * @return the subset index
-     */
-    public int mapSubsetChar(int glyphIndex, char unicode) {
+    /** {@inheritDoc} */
+    public int mapChar(int glyphIndex, char unicode) {
         // Reencode to a new subset font or get the reencoded value
         // IOW, accumulate the accessed characters and build a character map for them
-        Integer subsetCharSelector = usedGlyphs.get(Integer.valueOf(glyphIndex));
+        Integer subsetCharSelector = usedGlyphs.get(glyphIndex);
         if (subsetCharSelector == null) {
             int selector = usedGlyphsCount;
-            usedGlyphs.put(Integer.valueOf(glyphIndex),
-                           Integer.valueOf(selector));
-            usedGlyphsIndex.put(Integer.valueOf(selector),
-                                Integer.valueOf(glyphIndex));
-            usedCharsIndex.put(Integer.valueOf(selector),
-                                Character.valueOf(unicode));
+            usedGlyphs.put(glyphIndex, selector);
+            usedGlyphsIndex.put(selector, glyphIndex);
+            usedCharsIndex.put(selector, unicode);
             usedGlyphsCount++;
             return selector;
         } else {
-            return subsetCharSelector.intValue();
+            return subsetCharSelector;
         }
     }
 
-    /**
-     * Returns an unmodifiable Map of the font subset. It maps from glyph index to
-     * character selector (i.e. the subset index in this case).
-     * @return Map Map&lt;Integer, Integer&gt; of the font subset
-     */
-    public Map<Integer, Integer> getSubsetGlyphs() {
+    /** {@inheritDoc} */
+    public Map<Integer, Integer> getGlyphs() {
         return Collections.unmodifiableMap(this.usedGlyphs);
     }
 
-    /**
-     * Returns a char array containing all Unicode characters that are in the subset.
-     * @return a char array with all used Unicode characters
-     */
-    public char[] getSubsetChars() {
+    /** {@inheritDoc} */
+    public char[] getChars() {
         char[] charArray = new char[usedGlyphsCount];
         for (int i = 0; i < usedGlyphsCount; i++) {
-            charArray[i] = getUnicodeForSubsetIndex(i);
+            charArray[i] = getUnicode(i);
         }
         return charArray;
     }
 
-    /**
-     * Returns the number of glyphs in the subset.
-     * @return the number of glyphs in the subset
-     */
-    public int getSubsetSize() {
+    /** {@inheritDoc} */
+    public int getNumberOfGlyphs() {
         return this.usedGlyphsCount;
     }
 
-    /**
-     * Returns a BitSet with bits set for each available glyph index in the subset.
-     * @return a BitSet indicating available glyph indices
-     */
-    public BitSet getGlyphIndexBitSet() {
+    /** {@inheritDoc} */
+    public BitSet getGlyphIndices() {
         BitSet bitset = new BitSet();
         for (Integer cid : usedGlyphs.keySet()) {
-            bitset.set(cid.intValue());
+            bitset.set(cid);
         }
         return bitset;
     }
 
+    /** {@inheritDoc} */
+    public int[] getWidths() {
+        int[] widths = font.getWidths();
+        int[] tmpWidth = new int[getNumberOfGlyphs()];
+        for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) {
+            int nwx = Math.max(0, getOriginalGlyphIndex(i));
+            tmpWidth[i] = widths[nwx];
+        }
+        return tmpWidth;
+    }
+
 }
index 68c5c7177bbf69cc2823b45b49e4b2e0dd18081a..0448c317ec13bba2bd053cc2dbde7c607d5e2e09 100644 (file)
@@ -157,7 +157,7 @@ public class FontReader extends DefaultHandler {
             throws SAXException {
         if (localName.equals("font-metrics")) {
             if ("TYPE0".equals(attributes.getValue("type"))) {
-                multiFont = new MultiByteFont(resourceResolver);
+                multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO);
                 returnFont = multiFont;
                 isCID = true;
                 TTFReader.checkMetricsVersion(attributes);
index 4c42387f2bbffe8a3da332f91b1a8ade0fa4cb6c..fef42f74ce282ae70dad5a938b32a6e094f2e476 100644 (file)
@@ -438,6 +438,9 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
      */
     public boolean isSubsetEmbedded() {
         load(true);
+        if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) {
+            return false;
+        }
         return realFont.isMultiByte();
     }
 
index a460140cb61b25305d975e453a2d6f8c439921a5..da454c5049ad7ce65d20c63335c8101cef25cf1d 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.fonts;
 
 import java.nio.CharBuffer;
 import java.nio.IntBuffer;
+import java.util.BitSet;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
@@ -44,13 +45,13 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
     private static final Log log // CSOK: ConstantNameCheck
         = LogFactory.getLog(MultiByteFont.class);
 
-    private String ttcName = null;
+    private String ttcName;
     private String encoding = "Identity-H";
 
-    private int defaultWidth = 0;
+    private int defaultWidth;
     private CIDFontType cidType = CIDFontType.CIDTYPE2;
 
-    private CIDSubset subset = new CIDSubset();
+    private final CIDSet cidSet;
 
     /* advanced typographic support */
     private GlyphDefinitionTable gdef;
@@ -69,10 +70,15 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
     /**
      * Default constructor
      */
-    public MultiByteFont(InternalResourceResolver resourceResolver) {
+    public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) {
         super(resourceResolver);
-        subset.setupFirstGlyph();
         setFontType(FontType.TYPE0);
+        setEmbeddingMode(embeddingMode);
+        if (embeddingMode != EmbeddingMode.FULL) {
+            cidSet = new CIDSubset(this);
+        } else {
+            cidSet = new CIDFull(this);
+        }
     }
 
     /** {@inheritDoc} */
@@ -129,13 +135,16 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
     }
 
     public boolean isSubsetEmbedded() {
+        if (getEmbeddingMode() == EmbeddingMode.FULL) {
+            return false;
+        }
         return true;
     }
 
     /** {@inheritDoc} */
     @Override
-    public CIDSubset getCIDSubset() {
-        return this.subset;
+    public CIDSet getCIDSet() {
+        return this.cidSet;
     }
 
     /** {@inheritDoc} */
@@ -147,7 +156,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
     /** {@inheritDoc} */
     public int getWidth(int i, int size) {
         if (isEmbeddable()) {
-            int glyphIndex = subset.getGlyphIndexForSubsetIndex(i);
+            int glyphIndex = cidSet.getOriginalGlyphIndex(i);
             return size * width[glyphIndex];
         } else {
             return size * width[i];
@@ -283,9 +292,39 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
             glyphIndex = findGlyphIndex(Typeface.NOT_FOUND);
         }
         if (isEmbeddable()) {
-            glyphIndex = subset.mapSubsetChar(glyphIndex, c);
+            glyphIndex = cidSet.mapChar(glyphIndex, c);
         }
-        return (char)glyphIndex;
+        return (char) glyphIndex;
+    }
+
+    protected BitSet getGlyphIndices() {
+        BitSet bitset = new BitSet();
+        bitset.set(0);
+        bitset.set(1);
+        bitset.set(2);
+        for (int i = 0; i < cmap.length; i++) {
+            int start = cmap[i].getUnicodeStart();
+            int end = cmap[i].getUnicodeEnd();
+            int glyphIndex = cmap[i].getGlyphStartIndex();
+            while (start++ < end + 1) {
+                bitset.set(glyphIndex++);
+            }
+        }
+        return bitset;
+    }
+
+    protected char[] getChars() {
+        // the width array is set when the font is built
+        char[] chars = new char[width.length];
+        for (int i = 0; i < cmap.length; i++) {
+            int start = cmap[i].getUnicodeStart();
+            int end = cmap[i].getUnicodeEnd();
+            int glyphIndex = cmap[i].getGlyphStartIndex();
+            while (start < end + 1) {
+                chars[glyphIndex++] = (char) start++;
+            }
+        }
+        return chars;
     }
 
     /** {@inheritDoc} */
@@ -331,15 +370,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
      * @return Map Map of used Glyphs
      */
     public Map<Integer, Integer> getUsedGlyphs() {
-        return subset.getSubsetGlyphs();
-    }
-
-    /** @return an array of the chars used */
-    public char[] getCharsUsed() {
-        if (!isEmbeddable()) {
-            return null;
-        }
-        return subset.getSubsetChars();
+        return cidSet.getGlyphs();
     }
 
     /**
index c97b172115e4295ff150d834e3c2686fdaae8e82..a427fe54e45ef611a569a914de3fc9980de7c751 100644 (file)
@@ -127,7 +127,7 @@ public class TTFFontLoader extends FontLoader {
         }
 
         if (isCid) {
-            multiFont = new MultiByteFont(resourceResolver);
+            multiFont = new MultiByteFont(resourceResolver, embeddingMode);
             returnFont = multiFont;
             multiFont.setTTCName(ttcFontName);
         } else {
index 585f6d86dc3498daa15f3eaeb0c15c8f02d1ddff..31be73a00b52241c2b6aeb29434222411648247c 100644 (file)
@@ -44,9 +44,9 @@ import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
 import org.apache.xmlgraphics.xmp.Metadata;
 
 import org.apache.fop.fonts.CIDFont;
-import org.apache.fop.fonts.CIDSubset;
 import org.apache.fop.fonts.CodePointMapping;
 import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.EmbeddingMode;
 import org.apache.fop.fonts.FontDescriptor;
 import org.apache.fop.fonts.FontMetrics;
 import org.apache.fop.fonts.FontType;
@@ -1369,23 +1369,14 @@ public class PDFFactory {
                 } else {
                     cidMetrics = (CIDFont)metrics;
                 }
-                PDFCIDSystemInfo sysInfo
-                    = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
-                                         cidMetrics.getOrdering(),
-                                         cidMetrics.getSupplement());
-                PDFCIDFont cidFont = new PDFCIDFont(subsetFontName,
-                                   cidMetrics.getCIDType(),
-                                   cidMetrics.getDefaultWidth(),
-                                   getSubsetWidths(cidMetrics), sysInfo,
-                                   (PDFCIDFontDescriptor)pdfdesc);
+                PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
+                        cidMetrics.getOrdering(), cidMetrics.getSupplement());
+                PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(),
+                        cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo,
+                        (PDFCIDFontDescriptor) pdfdesc);
                 getDocument().registerObject(cidFont);
-
-                PDFCMap cmap = new PDFToUnicodeCMap(
-                        cidMetrics.getCIDSubset().getSubsetChars(),
-                        "fop-ucs-H",
-                        new PDFCIDSystemInfo("Adobe",
-                            "Identity",
-                            0), false);
+                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H",
+                        new PDFCIDSystemInfo("Adobe", "Identity", 0), false);
                 getDocument().registerObject(cmap);
                 ((PDFFontType0)font).setCMAP(cmap);
                 ((PDFFontType0)font).setDescendantFonts(cidFont);
@@ -1476,23 +1467,11 @@ public class PDFFactory {
         return PDFEncoding.createPDFEncoding(encoding, fontName);
     }
 
-    /**
-     * Creates and returns a width array with the widths of all the characters in the subset.
-     * @param cidFont the font
-     * @return the width array
-     */
-    public PDFWArray getSubsetWidths(CIDFont cidFont) {
+    private PDFWArray getFontWidths(CIDFont cidFont) {
         // Create widths for reencoded chars
         PDFWArray warray = new PDFWArray();
-        int[] widths = cidFont.getWidths();
-        CIDSubset subset = cidFont.getCIDSubset();
-        int[] tmpWidth = new int[subset.getSubsetSize()];
-
-        for (int i = 0, c = subset.getSubsetSize(); i < c; i++) {
-            int nwx = Math.max(0, subset.getGlyphIndexForSubsetIndex(i));
-            tmpWidth[i] = widths[nwx];
-        }
-        warray.addEntry(0, tmpWidth);
+        int[] widths = cidFont.getCIDSet().getWidths();
+        warray.addEntry(0, widths);
         return warray;
     }
 
@@ -1560,13 +1539,13 @@ public class PDFFactory {
     }
 
     private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) {
-        BitSet cidSubset = cidFont.getCIDSubset().getGlyphIndexBitSet();
-        PDFStream cidSet = makeStream(null, true);
-        ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1);
+        BitSet cidSet = cidFont.getCIDSet().getGlyphIndices();
+        PDFStream pdfStream = makeStream(null, true);
+        ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSet.length() / 8 + 1);
         int value = 0;
-        for (int i = 0, c = cidSubset.length(); i < c; i++) {
+        for (int i = 0, c = cidSet.length(); i < c; i++) {
             int shift = i % 8;
-            boolean b = cidSubset.get(i);
+            boolean b = cidSet.get(i);
             if (b) {
                 value |= 1 << 7 - shift;
             }
@@ -1577,8 +1556,8 @@ public class PDFFactory {
         }
         baout.write(value);
         try {
-            cidSet.setData(baout.toByteArray());
-            descriptor.setCIDSet(cidSet);
+            pdfStream.setData(baout.toByteArray());
+            descriptor.setCIDSet(pdfStream);
         } catch (IOException ioe) {
             log.error(
                     "Failed to write CIDSet [" + cidFont + "] "
@@ -1609,14 +1588,16 @@ public class PDFFactory {
                 if (desc.getFontType() == FontType.TYPE0) {
                     MultiByteFont mbfont = (MultiByteFont) font;
                     FontFileReader reader = new FontFileReader(in);
-
-                    TTFSubSetFile subset = new TTFSubSetFile();
-                    subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
-                    byte[] subsetFont = subset.getFontSubset();
-                    // Only TrueType CID fonts are supported now
-
-                    embeddedFont = new PDFTTFStream(subsetFont.length);
-                    ((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length);
+                    byte[] fontBytes;
+                    if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
+                        fontBytes = reader.getAllBytes();
+                    } else {
+                        TTFSubSetFile ttfFile = new TTFSubSetFile();
+                        ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
+                        fontBytes = ttfFile.getFontSubset();
+                    }
+                    embeddedFont = new PDFTTFStream(fontBytes.length);
+                    ((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length);
                 } else if (desc.getFontType() == FontType.TYPE1) {
                     PFBParser parser = new PFBParser();
                     PFBData pfb = parser.parsePFB(in);
index d536167c361e345cedf9e63f4102367b1990ca94..0de02c766c423bd60e0798f558b0f001904e597c 100644 (file)
@@ -24,7 +24,6 @@ import org.apache.xmlgraphics.image.writer.ResolutionUnit;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
 import org.apache.fop.render.intermediate.IFContext;
-import org.apache.fop.render.intermediate.IFDocumentHandler;
 import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
 
 /**
index c99bb21e1701894c9dbaabeb2cba7aae03588c74..9e810c824cd0391c7ea5c1a375fd7b9790865dfa 100644 (file)
@@ -38,7 +38,7 @@ 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.CIDSet;
 import org.apache.fop.fonts.CMapSegment;
 import org.apache.fop.fonts.CustomFont;
 import org.apache.fop.fonts.EmbeddingMode;
@@ -457,15 +457,17 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
         // TODO /FontInfo
 
         gen.write("/CIDCount ");
-        CIDSubset cidSubset = font.getCIDSubset();
-        int subsetSize = cidSubset.getSubsetSize();
-        gen.write(subsetSize);
+        CIDSet cidSet = font.getCIDSet();
+        int numberOfGlyphs = cidSet.getNumberOfGlyphs();
+        gen.write(numberOfGlyphs);
         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++) {
+        int nextBitSet = 0;
+        int previousBitSet = 0;
+        for (int cid = 0; cid < numberOfGlyphs; cid++) {
             if (colCount++ == 20) {
                 gen.newLine();
                 colCount = 1;
@@ -478,7 +480,23 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
             if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
                 gid = HexEncoder.encode(cid, 4);
             } else {
-                gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4);
+                previousBitSet = nextBitSet;
+                nextBitSet = cidSet.getGlyphIndices().nextSetBit(nextBitSet);
+                while (previousBitSet++ < nextBitSet) {
+                    // if there are gaps in the indices we pad them with zeros
+                    gen.write("0000");
+                    cid++;
+                    if (colCount++ == 20) {
+                        gen.newLine();
+                        colCount = 1;
+                        if (lineCount++ == 800) {
+                            gen.writeln("> <");
+                            lineCount = 1;
+                        }
+                    }
+                }
+                gid = HexEncoder.encode(nextBitSet, 4);
+                nextBitSet++;
             }
             gen.write(gid);
         }
index b39d3d9e0540258919d85966db5551085175c622..7571ddfda1c024ac71cf22518a42184bcfad91fc 100644 (file)
@@ -62,6 +62,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="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo">
+        Full font embedding in PDF
+      </action>
       <action context="Renderers" dev="PH" type="add" fixes-bug="53865" importance="low">
         Added configuration for RowPerStrip configuration in the Tiff renderer.
         RowsPerStrip can be configured to 1 or to the total # of rows.
diff --git a/test/java/org/apache/fop/fonts/CIDFullTestCase.java b/test/java/org/apache/fop/fonts/CIDFullTestCase.java
new file mode 100644 (file)
index 0000000..7df6cc2
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.fop.util.CharUtilities;
+
+public class CIDFullTestCase {
+
+    private CIDFull cidFull;
+    private MultiByteFont mbFont;
+    private BitSet bs;
+    private char[] chars;
+    private int[] widths;
+    private Map<Integer, Integer> glyphs;
+
+    @Before
+    public void setup() {
+        bs = new BitSet();
+        glyphs = new HashMap<Integer, Integer>();
+        chars = new char[18];
+        widths = new int[18];
+        int i = 0;
+        for (int j = 0; j < 20; j++) {
+            if (j == 10 || j == 11) {
+                continue;
+            }
+            bs.set(j);
+            glyphs.put(Integer.valueOf(j), Integer.valueOf(j));
+            chars[i] = (char) j;
+            widths[i] = 100;
+            i++;
+        }
+        mbFont = mock(MultiByteFont.class);
+        when(mbFont.getGlyphIndices()).thenReturn(bs);
+        when(mbFont.getChars()).thenReturn(chars);
+        when(mbFont.getWidths()).thenReturn(widths);
+        cidFull = new CIDFull(mbFont);
+    }
+
+    @Test
+    public void testGetOriginalGlyphIndex() {
+        // index 5 exists
+        assertEquals(cidFull.getOriginalGlyphIndex(5), 5);
+    }
+
+    @Test
+    public void testGetUnicode() {
+        // index 9 exists
+        assertEquals(cidFull.getUnicode(9), (char) 9);
+        // index 10 does not
+        assertEquals(cidFull.getUnicode(10), CharUtilities.NOT_A_CHARACTER);
+    }
+
+    @Test
+    public void testMapChar() {
+        // index 9 exists
+        char c = 'a';
+        assertEquals(cidFull.mapChar(9, c), (char) 9);
+    }
+
+    @Test
+    public void testGetGlyphs() {
+        Map<Integer, Integer> fontGlyphs = cidFull.getGlyphs();
+        for (Integer key : fontGlyphs.keySet()) {
+            assertEquals(fontGlyphs.get(key), glyphs.get(key));
+        }
+        assertTrue(fontGlyphs.size() == glyphs.size());
+    }
+
+    @Test
+    public void testGetChars() {
+        assertArrayEquals(cidFull.getChars(), chars);
+    }
+
+    @Test
+    public void testGetNumberOfGlyphs() {
+        assertTrue(cidFull.getNumberOfGlyphs() == 20);
+    }
+
+    @Test
+    public void testGetGlyphIndices() {
+        assertEquals(bs, cidFull.getGlyphIndices());
+    }
+
+    @Test
+    public void testGetWidths() {
+        assertArrayEquals(cidFull.getWidths(), widths);
+    }
+
+}
index ac9df4046544f688320f2d4b0d1b8756251d5a5b..971471fa2e0d350771c463bf68375e469dcba4d6 100644 (file)
@@ -24,14 +24,16 @@ import java.net.URI;
 
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+
 import org.apache.fop.apps.io.InternalResourceResolver;
 import org.apache.fop.apps.io.ResourceResolver;
 import org.apache.fop.apps.io.ResourceResolverFactory;
+import org.apache.fop.fonts.CIDSet;
 import org.apache.fop.fonts.CIDSubset;
+import org.apache.fop.fonts.EmbeddingMode;
 import org.apache.fop.fonts.MultiByteFont;
 
-import static org.junit.Assert.assertEquals;
-
 /**
  * Test case for {@link PDFFactory}.
  */
@@ -45,7 +47,7 @@ public class PDFFactoryTestCase {
     public void testSubsetFontNamePrefix() {
         class MockedFont extends MultiByteFont {
             public MockedFont(InternalResourceResolver resolver) {
-                super(resolver);
+                super(resolver, EmbeddingMode.AUTO);
             }
 
             @Override
@@ -54,8 +56,8 @@ public class PDFFactoryTestCase {
             }
 
             @Override
-            public CIDSubset getCIDSubset() {
-                return new CIDSubset();
+            public CIDSet getCIDSet() {
+                return new CIDSubset(this);
             }
         }
         PDFDocument doc = new PDFDocument("Test");