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
* Returns the subset information for this font.
* @return the subset information
*/
- public abstract CIDSubset getCIDSubset();
+ public abstract CIDSet getCIDSet();
// ---- Optional ----
/**
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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<Integer, Integer> 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();
+
+}
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)
* 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 {
}
}
- /**
- * 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<Integer, Integer> 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;
+ }
+
}
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);
*/
public boolean isSubsetEmbedded() {
load(true);
+ if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) {
+ return false;
+ }
return realFont.isMultiByte();
}
import java.nio.CharBuffer;
import java.nio.IntBuffer;
+import java.util.BitSet;
import java.util.Map;
import org.apache.commons.logging.Log;
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;
/**
* 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} */
}
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} */
/** {@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];
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} */
* @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();
}
/**
}
if (isCid) {
- multiFont = new MultiByteFont(resourceResolver);
+ multiFont = new MultiByteFont(resourceResolver, embeddingMode);
returnFont = multiFont;
multiFont.setTTCName(ttcFontName);
} else {
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;
} 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);
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;
}
}
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;
}
}
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 + "] "
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);
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;
/**
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;
// 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;
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);
}
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.
--- /dev/null
+/*
+ * 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);
+ }
+
+}
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}.
*/
public void testSubsetFontNamePrefix() {
class MockedFont extends MultiByteFont {
public MockedFont(InternalResourceResolver resolver) {
- super(resolver);
+ super(resolver, EmbeddingMode.AUTO);
}
@Override
}
@Override
- public CIDSubset getCIDSubset() {
- return new CIDSubset();
+ public CIDSet getCIDSet() {
+ return new CIDSubset(this);
}
}
PDFDocument doc = new PDFDocument("Test");