aboutsummaryrefslogtreecommitdiffstats
path: root/fop-core/src
diff options
context:
space:
mode:
authorSimon Steiner <ssteiner@apache.org>2017-04-25 10:18:07 +0000
committerSimon Steiner <ssteiner@apache.org>2017-04-25 10:18:07 +0000
commit0ede8c8d8198c6a072dbb589d9f1d665b3a9e274 (patch)
tree7fbb9686dbc3a3160670bf56bbd5a481265352a1 /fop-core/src
parent6803be47127d99fc7ab425ecc0ce4ac9a8ddf830 (diff)
downloadxmlgraphics-fop-0ede8c8d8198c6a072dbb589d9f1d665b3a9e274.tar.gz
xmlgraphics-fop-0ede8c8d8198c6a072dbb589d9f1d665b3a9e274.zip
FOP-2702: OTF fonts not working on Mac Preview
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1792597 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'fop-core/src')
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/CIDFont.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java92
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java3
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/SingleByteFont.java74
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/Typeface.java4
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java24
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFFile.java5
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java13
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFCFFStreamType0C.java18
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java102
-rw-r--r--fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java18
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java29
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/ps/PSFontUtils.java7
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/svg/PDFTextPainter.java4
-rw-r--r--fop-core/src/main/java/org/apache/fop/svg/PDFTextUtil.java10
-rw-r--r--fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java8
-rw-r--r--fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java40
-rw-r--r--fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java4
19 files changed, 317 insertions, 142 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/CIDFont.java b/fop-core/src/main/java/org/apache/fop/fonts/CIDFont.java
index dc398263e..5aa7237e9 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/CIDFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/CIDFont.java
@@ -82,7 +82,7 @@ public abstract class CIDFont extends CustomFont {
/** {@inheritDoc} */
public boolean isMultiByte() {
- return true;
+ return getFontType() != FontType.TYPE1C;
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java b/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
index ed9f1f039..4422ef8c3 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
@@ -19,6 +19,7 @@
package org.apache.fop.fonts;
+import java.awt.Rectangle;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
@@ -81,6 +82,8 @@ public abstract class CustomFont extends Typeface
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>();
private boolean useAdvanced = true;
private boolean simulateStyle;
+ protected List<SimpleSingleByteEncoding> additionalEncodings;
+ protected Map<Character, SingleByteFont.UnencodedCharacter> unencodedCharacters;
/**
* @param resourceResolver the URI resource resolver for controlling file access
@@ -590,4 +593,93 @@ public abstract class CustomFont extends Typeface
* @return The character
*/
public abstract char getUnicodeFromGID(int glyphIndex);
+
+ /**
+ * Indicates whether the encoding has additional encodings besides the primary encoding.
+ * @return true if there are additional encodings.
+ */
+ public boolean hasAdditionalEncodings() {
+ return (this.additionalEncodings != null) && (this.additionalEncodings.size() > 0);
+ }
+
+ /**
+ * Returns the number of additional encodings this single-byte font maintains.
+ * @return the number of additional encodings
+ */
+ public int getAdditionalEncodingCount() {
+ if (hasAdditionalEncodings()) {
+ return this.additionalEncodings.size();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns an additional encoding.
+ * @param index the index of the additional encoding
+ * @return the additional encoding
+ * @throws IndexOutOfBoundsException if the index is out of bounds
+ */
+ public SimpleSingleByteEncoding getAdditionalEncoding(int index)
+ throws IndexOutOfBoundsException {
+ if (hasAdditionalEncodings()) {
+ return this.additionalEncodings.get(index);
+ } else {
+ throw new IndexOutOfBoundsException("No additional encodings available");
+ }
+ }
+
+ /**
+ * Adds an unencoded character (one that is not supported by the primary encoding).
+ * @param ch the named character
+ * @param width the width of the character
+ */
+ public void addUnencodedCharacter(NamedCharacter ch, int width, Rectangle bbox) {
+ if (this.unencodedCharacters == null) {
+ this.unencodedCharacters = new HashMap<Character, SingleByteFont.UnencodedCharacter>();
+ }
+ if (ch.hasSingleUnicodeValue()) {
+ SingleByteFont.UnencodedCharacter uc = new SingleByteFont.UnencodedCharacter(ch, width, bbox);
+ this.unencodedCharacters.put(ch.getSingleUnicodeValue(), uc);
+ } else {
+ //Cannot deal with unicode sequences, so ignore this character
+ }
+ }
+
+ /**
+ * Adds a character to additional encodings
+ * @param ch character to map
+ */
+ protected char mapUnencodedChar(char ch) {
+ if (this.unencodedCharacters != null) {
+ SingleByteFont.UnencodedCharacter unencoded = this.unencodedCharacters.get(ch);
+ if (unencoded != null) {
+ if (this.additionalEncodings == null) {
+ this.additionalEncodings = new ArrayList<SimpleSingleByteEncoding>();
+ }
+ SimpleSingleByteEncoding encoding = null;
+ char mappedStart = 0;
+ int additionalsCount = this.additionalEncodings.size();
+ for (int i = 0; i < additionalsCount; i++) {
+ mappedStart += 256;
+ encoding = getAdditionalEncoding(i);
+ char alt = encoding.mapChar(ch);
+ if (alt != 0) {
+ return (char)(mappedStart + alt);
+ }
+ }
+ if (encoding != null && encoding.isFull()) {
+ encoding = null;
+ }
+ if (encoding == null) {
+ encoding = new SimpleSingleByteEncoding(
+ getFontName() + "EncodingSupp" + (additionalsCount + 1));
+ this.additionalEncodings.add(encoding);
+ mappedStart += 256;
+ }
+ return (char)(mappedStart + encoding.addCharacter(unencoded.getCharacter()));
+ }
+ }
+ return 0;
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java b/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
index 9e542f71e..c5af86822 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
@@ -371,6 +371,9 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
if (isEmbeddable()) {
glyphIndex = cidSet.mapChar(glyphIndex, c);
}
+ if (isCID() && glyphIndex > 256) {
+ mapUnencodedChar(c);
+ }
return (char) glyphIndex;
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/SingleByteFont.java b/fop-core/src/main/java/org/apache/fop/fonts/SingleByteFont.java
index eb273d172..262ea0a75 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/SingleByteFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/SingleByteFont.java
@@ -20,11 +20,9 @@
package org.apache.fop.fonts;
import java.awt.Rectangle;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -53,8 +51,6 @@ public class SingleByteFont extends CustomFont {
private Rectangle[] boundingBoxes;
- private Map<Character, UnencodedCharacter> unencodedCharacters;
- private List<SimpleSingleByteEncoding> additionalEncodings;
private Map<Character, Character> alternativeCodes;
private PostScriptVersion ttPostScriptVersion;
@@ -253,39 +249,6 @@ public class SingleByteFont extends CustomFont {
}
}
- private char mapUnencodedChar(char ch) {
- if (this.unencodedCharacters != null) {
- UnencodedCharacter unencoded = this.unencodedCharacters.get(ch);
- if (unencoded != null) {
- if (this.additionalEncodings == null) {
- this.additionalEncodings = new ArrayList<SimpleSingleByteEncoding>();
- }
- SimpleSingleByteEncoding encoding = null;
- char mappedStart = 0;
- int additionalsCount = this.additionalEncodings.size();
- for (int i = 0; i < additionalsCount; i++) {
- mappedStart += 256;
- encoding = getAdditionalEncoding(i);
- char alt = encoding.mapChar(ch);
- if (alt != 0) {
- return (char)(mappedStart + alt);
- }
- }
- if (encoding != null && encoding.isFull()) {
- encoding = null;
- }
- if (encoding == null) {
- encoding = new SimpleSingleByteEncoding(
- getFontName() + "EncodingSupp" + (additionalsCount + 1));
- this.additionalEncodings.add(encoding);
- mappedStart += 256;
- }
- return (char)(mappedStart + encoding.addCharacter(unencoded.getCharacter()));
- }
- }
- return 0;
- }
-
/** {@inheritDoc} */
@Override
public boolean hasChar(char c) {
@@ -407,41 +370,6 @@ public class SingleByteFont extends CustomFont {
}
/**
- * Indicates whether the encoding has additional encodings besides the primary encoding.
- * @return true if there are additional encodings.
- */
- public boolean hasAdditionalEncodings() {
- return (this.additionalEncodings != null) && (this.additionalEncodings.size() > 0);
- }
-
- /**
- * Returns the number of additional encodings this single-byte font maintains.
- * @return the number of additional encodings
- */
- public int getAdditionalEncodingCount() {
- if (hasAdditionalEncodings()) {
- return this.additionalEncodings.size();
- } else {
- return 0;
- }
- }
-
- /**
- * Returns an additional encoding.
- * @param index the index of the additional encoding
- * @return the additional encoding
- * @throws IndexOutOfBoundsException if the index is out of bounds
- */
- public SimpleSingleByteEncoding getAdditionalEncoding(int index)
- throws IndexOutOfBoundsException {
- if (hasAdditionalEncodings()) {
- return this.additionalEncodings.get(index);
- } else {
- throw new IndexOutOfBoundsException("No additional encodings available");
- }
- }
-
- /**
* Returns an array with the widths for an additional encoding.
* @param index the index of the additional encoding
* @return the width array
@@ -458,7 +386,7 @@ public class SingleByteFont extends CustomFont {
return arr;
}
- private static final class UnencodedCharacter {
+ protected static final class UnencodedCharacter {
private final NamedCharacter character;
private final int width;
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/Typeface.java b/fop-core/src/main/java/org/apache/fop/fonts/Typeface.java
index faf79abc7..c36f0ca91 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/Typeface.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/Typeface.java
@@ -98,6 +98,10 @@ public abstract class Typeface implements FontMetrics {
return false;
}
+ public boolean isCID() {
+ return getFontType() == FontType.TYPE1C;
+ }
+
/** {@inheritDoc} */
public int getMaxAscent(int size) {
return getAscender(size);
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
index 3a4b1d771..a0060ccb6 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
@@ -182,6 +182,10 @@ public class OFFontLoader extends FontLoader {
returnFont.setWeight(otf.getWeightClass());
if (isCid) {
if (otf instanceof OTFFile) {
+ if (((OTFFile) otf).isType1() && embeddingMode == EmbeddingMode.SUBSET) {
+ multiFont.setFontType(FontType.TYPE1C);
+ copyGlyphMetricsSingleByte(otf);
+ }
multiFont.setCIDType(CIDFontType.CIDTYPE0);
} else {
multiFont.setCIDType(CIDFontType.CIDTYPE2);
@@ -223,17 +227,21 @@ public class OFFontLoader extends FontLoader {
private void copyGlyphMetricsSingleByte(OpenFont otf) {
int[] wx = otf.getWidths();
Rectangle[] bboxes = otf.getBoundingBoxes();
- for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) {
- singleFont.setWidth(i, otf.getCharWidth(i));
- int[] bbox = otf.getBBox(i);
- singleFont.setBoundingBox(i,
- new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]));
+ if (singleFont != null) {
+ for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) {
+ singleFont.setWidth(i, otf.getCharWidth(i));
+ int[] bbox = otf.getBBox(i);
+ singleFont.setBoundingBox(i,
+ new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]));
+ }
}
-
for (CMapSegment segment : otf.getCMaps()) {
if (segment.getUnicodeStart() < 0xFFFE) {
for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) {
- int codePoint = singleFont.getEncoding().mapChar(u);
+ int codePoint = 0;
+ if (singleFont != null) {
+ codePoint = singleFont.getEncoding().mapChar(u);
+ }
if (codePoint <= 0) {
int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart();
String glyphName = otf.getGlyphName(glyphIndex);
@@ -243,7 +251,7 @@ public class OFFontLoader extends FontLoader {
if (glyphName.length() > 0) {
String unicode = Character.toString(u);
NamedCharacter nc = new NamedCharacter(glyphName, unicode);
- singleFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]);
+ returnFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]);
}
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFFile.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFFile.java
index a96cb3d0e..2f52fa791 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFFile.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFFile.java
@@ -24,6 +24,7 @@ import java.io.IOException;
import org.apache.fontbox.cff.CFFDataInput;
import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.cff.CFFParser;
+import org.apache.fontbox.cff.CFFType1Font;
public class OTFFile extends OpenFont {
@@ -133,4 +134,8 @@ public class OTFFile extends OpenFont {
private static long readLong(CFFDataInput input) throws IOException {
return (input.readCard16() << 16) | input.readCard16();
}
+
+ public boolean isType1() {
+ return fileFont instanceof CFFType1Font;
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
index 84ad09858..942bcae79 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java
@@ -111,10 +111,8 @@ public class OTFSubSetFile extends OTFSubSetWriter {
super();
}
- public void readFont(FontFileReader in, String embeddedName, String header,
- MultiByteFont mbFont) throws IOException {
- this.mbFont = mbFont;
- readFont(in, embeddedName, header, mbFont.getUsedGlyphs());
+ public void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont) throws IOException {
+ readFont(in, embeddedName, mbFont, mbFont.getUsedGlyphs());
}
/**
@@ -122,13 +120,13 @@ public class OTFSubSetFile extends OTFSubSetWriter {
*
* @param in FontFileReader to read from
* @param embeddedName Name to be checked for in the font file
- * @param header The header of the font file
* @param usedGlyphs Map of glyphs (glyphs has old index as (Integer) key and
* new index as (Integer) value)
* @throws IOException in case of an I/O problem
*/
- void readFont(FontFileReader in, String embeddedName, String header,
+ void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont,
Map<Integer, Integer> usedGlyphs) throws IOException {
+ this.mbFont = mbFont;
fontFile = in;
currentPos = 0;
@@ -1038,6 +1036,9 @@ public class OTFSubSetFile extends OTFSubSetWriter {
} else {
writeByte(0);
for (int entry : gidToSID.values()) {
+ if (entry == 0) {
+ continue;
+ }
writeCard16(entry);
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFCFFStreamType0C.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFCFFStreamType0C.java
index 53f0b36b4..1756cf107 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFCFFStreamType0C.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFCFFStreamType0C.java
@@ -22,21 +22,30 @@ package org.apache.fop.pdf;
import java.io.IOException;
import java.io.OutputStream;
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.FontType;
+
/**
* PDFStream for embeddable OpenType CFF fonts.
*/
public class PDFCFFStreamType0C extends AbstractPDFFontStream {
private byte[] cffData;
- private boolean fullEmbed;
+ private String type;
/**
* Main constructor
- * @param fullEmbed Determines whether the font is fully embedded
*/
- public PDFCFFStreamType0C(boolean fullEmbed) {
+ public PDFCFFStreamType0C(CustomFont font) {
super();
- this.fullEmbed = fullEmbed;
+ if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
+ type = "OpenType";
+ } else if (font.getFontType() == FontType.TYPE0) {
+ type = "CIDFontType0C";
+ } else {
+ type = font.getFontType().getName();
+ }
}
protected int getSizeHint() throws IOException {
@@ -54,7 +63,6 @@ public class PDFCFFStreamType0C extends AbstractPDFFontStream {
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
- String type = (fullEmbed) ? "OpenType" : "CIDFontType0C";
put("Subtype", new PDFName(type));
super.populateStreamDict(lengthEntry);
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
index 4e9a58cdf..856e7d765 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
@@ -28,9 +28,11 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
@@ -987,6 +989,9 @@ public class PDFFactory {
assert font instanceof PDFFontType0;
((PDFFontType0)font).setCMAP(cmap);
((PDFFontType0)font).setDescendantFonts(cidFont);
+ } else if (fonttype == FontType.TYPE1C
+ && (metrics instanceof LazyFont || metrics instanceof MultiByteFont)) {
+ handleType1CFont(pdfdesc, font, metrics, fontname, basefont, descriptor);
} else {
assert font instanceof PDFFontNonBase14;
PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font;
@@ -1123,6 +1128,84 @@ public class PDFFactory {
}
}
+ private void handleType1CFont(PDFFontDescriptor pdfdesc, PDFFont font, FontMetrics metrics, String fontname,
+ String basefont, FontDescriptor descriptor) {
+ PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font;
+ nonBase14.setDescriptor(pdfdesc);
+ MultiByteFont singleByteFont;
+ if (metrics instanceof LazyFont) {
+ singleByteFont = (MultiByteFont)((LazyFont)metrics).getRealFont();
+ } else {
+ singleByteFont = (MultiByteFont)metrics;
+ }
+ Map<Integer, Integer> usedGlyphs = singleByteFont.getUsedGlyphs();
+ SortedSet<Integer> keys = new TreeSet<Integer>(usedGlyphs.keySet());
+ keys.remove(0);
+ int count = keys.size();
+ Iterator<String> usedGlyphNames = singleByteFont.getUsedGlyphNames().values().iterator();
+ count = setupFontMetrics(nonBase14, pdfdesc, usedGlyphNames, 0, count, metrics);
+ List<PDFFontNonBase14> additionalEncodings = addAdditionalEncodings(metrics, descriptor, fontname, basefont);
+ for (int j = 0; j < additionalEncodings.size(); j++) {
+ PDFFontNonBase14 additional = additionalEncodings.get(j);
+ int start = 256 * (j + 1);
+ count = setupFontMetrics(additional, pdfdesc, usedGlyphNames, start, count, metrics);
+ }
+ }
+
+ private int setupFontMetrics(PDFFontNonBase14 font, PDFFontDescriptor pdfdesc,
+ Iterator<String> usedGlyphNames, int start, int count, FontMetrics metrics) {
+ font.setDescriptor(pdfdesc);
+ PDFArray differences = new PDFArray();
+ int firstChar = 0;
+ differences.add(firstChar);
+ int lastChar = Math.min(count, 255);
+ int[] newWidths = new int[lastChar + 1];
+ for (int i = 0; i < newWidths.length; i++) {
+ newWidths[i] = metrics.getWidth(start + i, 1);
+ differences.add(new PDFName(usedGlyphNames.next()));
+ count--;
+ }
+ font.setWidthMetrics(firstChar,
+ lastChar,
+ new PDFArray(null, newWidths));
+ PDFEncoding pdfEncoding = new PDFEncoding("WinAnsiEncoding");
+ getDocument().registerTrailerObject(pdfEncoding);
+ pdfEncoding.setDifferences(differences);
+ font.setEncoding(pdfEncoding);
+ return count;
+ }
+
+ private List<PDFFontNonBase14> addAdditionalEncodings(FontMetrics metrics, FontDescriptor descriptor,
+ String fontname, String basefont) {
+ List<PDFFontNonBase14> additionalEncodings = new ArrayList<PDFFontNonBase14>();
+ FontType fonttype = metrics.getFontType();
+ if (descriptor != null && (fonttype != FontType.TYPE0)) {
+ CustomFont singleByteFont;
+ if (metrics instanceof LazyFont) {
+ singleByteFont = (CustomFont)((LazyFont)metrics).getRealFont();
+ } else {
+ singleByteFont = (CustomFont)metrics;
+ }
+ //Handle additional encodings (characters outside the primary encoding)
+ if (singleByteFont.hasAdditionalEncodings()) {
+ for (int i = additionalEncodings.size(),
+ c = singleByteFont.getAdditionalEncodingCount(); i < c; i++) {
+ SimpleSingleByteEncoding addEncoding
+ = singleByteFont.getAdditionalEncoding(i);
+ String name = fontname + "_" + (i + 1);
+ Object pdfenc = createPDFEncoding(addEncoding, singleByteFont.getFontName());
+ PDFFontNonBase14 addFont = (PDFFontNonBase14)PDFFont.createFont(
+ name, fonttype,
+ basefont, pdfenc);
+ getDocument().registerObject(addFont);
+ getDocument().getResources().addFont(addFont);
+ additionalEncodings.add(addFont);
+ }
+ }
+ }
+ return additionalEncodings;
+ }
+
private void generateToUnicodeCmap(PDFFont font, SingleByteEncoding encoding) {
PDFCMap cmap = new PDFToUnicodeCMap(encoding.getUnicodeCharMap(),
"fop-ucs-H",
@@ -1315,10 +1398,17 @@ public class PDFFactory {
((PDFT1Stream) embeddedFont).setData(pfb);
}
} else if (desc.getFontType() == FontType.TYPE1C) {
- byte[] file = IOUtils.toByteArray(in);
- PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C");
- embeddedFont2.setData(file);
- return embeddedFont2;
+ if (font.getEmbeddingMode() == EmbeddingMode.SUBSET) {
+ FontFileReader reader = new FontFileReader(in);
+ String header = OFFontLoader.readHeader(reader);
+ byte[] fontBytes = getFontSubsetBytes(reader, (MultiByteFont) font, header, fontPrefix, desc, true);
+ embeddedFont = getFontStream(font, fontBytes, true);
+ } else {
+ byte[] file = IOUtils.toByteArray(in);
+ PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C");
+ embeddedFont2.setData(file);
+ return embeddedFont2;
+ }
} else if (desc.getFontType() == FontType.CIDTYPE0) {
byte[] file = IOUtils.toByteArray(in);
PDFCFFStream embeddedFont2 = new PDFCFFStream("CIDFontType0C");
@@ -1361,7 +1451,7 @@ public class PDFFactory {
String fontPrefix, FontDescriptor desc, boolean isCFF) throws IOException {
if (isCFF) {
OTFSubSetFile otfFile = new OTFSubSetFile();
- otfFile.readFont(reader, fontPrefix + desc.getEmbedFontName(), header, mbfont);
+ otfFile.readFont(reader, fontPrefix + desc.getEmbedFontName(), mbfont);
return otfFile.getFontSubset();
} else {
TTFSubSetFile otfFile = new TTFSubSetFile();
@@ -1374,7 +1464,7 @@ public class PDFFactory {
throws IOException {
AbstractPDFStream embeddedFont;
if (isCFF) {
- embeddedFont = new PDFCFFStreamType0C(font.getEmbeddingMode() == EmbeddingMode.FULL);
+ embeddedFont = new PDFCFFStreamType0C(font);
((PDFCFFStreamType0C) embeddedFont).setData(fontBytes, fontBytes.length);
} else {
embeddedFont = new PDFTTFStream(fontBytes.length);
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
index bd7c8c4ae..2a1dc5039 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFTextUtil.java
@@ -51,6 +51,7 @@ public abstract class PDFTextUtil {
private String startText;
private String endText;
private boolean useMultiByte;
+ private boolean useCid;
private StringBuffer bufTJ;
private int textRenderingMode = TR_FILL;
@@ -92,9 +93,9 @@ public abstract class PDFTextUtil {
PDFNumber.doubleOut(lt[5], DEC, sb);
}
- private static void writeChar(char ch, StringBuffer sb, boolean multibyte) {
+ private static void writeChar(char ch, StringBuffer sb, boolean multibyte, boolean cid) {
if (!multibyte) {
- if (ch < 32 || ch > 127) {
+ if (cid || ch < 32 || ch > 127) {
sb.append("\\").append(Integer.toOctalString(ch));
} else {
switch (ch) {
@@ -113,7 +114,7 @@ public abstract class PDFTextUtil {
}
private void writeChar(char ch, StringBuffer sb) {
- writeChar(ch, sb, useMultiByte);
+ writeChar(ch, sb, useMultiByte, useCid);
}
private void checkInTextObject() {
@@ -199,13 +200,14 @@ public abstract class PDFTextUtil {
* @param fontSize the font size (in points)
* @param multiByte true indicates the font is a multi-byte font, false means single-byte
*/
- public void updateTf(String fontName, double fontSize, boolean multiByte) {
+ public void updateTf(String fontName, double fontSize, boolean multiByte, boolean cid) {
checkInTextObject();
if (!fontName.equals(this.currentFontName) || (fontSize != this.currentFontSize)) {
writeTJ();
this.currentFontName = fontName;
this.currentFontSize = fontSize;
this.useMultiByte = multiByte;
+ this.useCid = cid;
writeTf(fontName, fontSize);
}
}
@@ -338,11 +340,11 @@ public abstract class PDFTextUtil {
* Writes a "Tj" command with specified character code.
* @param ch character code to write
*/
- public void writeTj(char ch) {
+ public void writeTj(char ch, boolean multibyte, boolean cid) {
StringBuffer sb = new StringBuffer();
- sb.append('<');
- writeChar(ch, sb, true);
- sb.append('>');
+ sb.append(startText);
+ writeChar(ch, sb, multibyte, cid);
+ sb.append(endText);
sb.append(" Tj\n");
write(sb);
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
index c08dd86c8..942027673 100644
--- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -451,15 +451,11 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontKey);
- SingleByteFont singleByteFont = null;
- if (tf instanceof SingleByteFont) {
- singleByteFont = (SingleByteFont)tf;
- }
Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
String fontName = font.getFontName();
PDFTextUtil textutil = generator.getTextUtil();
- textutil.updateTf(fontKey, fontSize, tf.isMultiByte());
+ textutil.updateTf(fontKey, fontSize, tf.isMultiByte(), tf.isCID());
double shear = 0;
boolean simulateStyle = tf instanceof CustomFont && ((CustomFont) tf).getSimulateStyle();
@@ -488,7 +484,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
float glyphAdjust = 0;
if (font.hasChar(orgChar)) {
ch = font.mapChar(orgChar);
- ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize, textutil, ch);
+ ch = selectAndMapSingleByteFont(tf, fontName, fontSize, textutil, ch);
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
glyphAdjust += wordSpacing;
}
@@ -504,8 +500,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
glyphAdjust += wordSpacing;
}
}
- ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize,
- textutil, ch);
+ ch = selectAndMapSingleByteFont(tf, fontName, fontSize, textutil, ch);
}
textutil.writeTJMappedChar(ch);
@@ -533,7 +528,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
assert dp != null;
String fk = getFontInfo().getInternalFontKey(triplet);
Typeface tf = getTypeface(fk);
- if (tf.isMultiByte()) {
+ if (tf.isMultiByte() || tf.isCID()) {
int fs = state.getFontSize();
float fsPoints = fs / 1000f;
Font f = getFontInfo().getFontInstance(triplet, fs);
@@ -544,7 +539,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
double yoLast = 0f;
double wox = wordSpacing;
tu.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f));
- tu.updateTf(fk, fsPoints, true);
+ tu.updateTf(fk, fsPoints, tf.isMultiByte(), true);
generator.updateCharacterSpacing(letterSpacing / 1000f);
for (int i = 0, n = text.length(); i < n; i++) {
char ch = text.charAt(i);
@@ -556,7 +551,9 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
double xd = (xo - xoLast) / 1000f;
double yd = (yo - yoLast) / 1000f;
tu.writeTd(xd, yd);
- tu.writeTj(f.mapChar(ch));
+ ch = f.mapChar(ch);
+ ch = selectAndMapSingleByteFont(tf, f.getFontName(), fsPoints, tu, ch);
+ tu.writeTj(ch, tf.isMultiByte(), true);
xc += xa + pa[2];
yc += ya + pa[3];
xoLast = xo;
@@ -587,15 +584,15 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
}
*/
- private char selectAndMapSingleByteFont(SingleByteFont singleByteFont, String fontName,
- float fontSize, PDFTextUtil textutil, char ch) {
- if (singleByteFont != null && singleByteFont.hasAdditionalEncodings()) {
+ private char selectAndMapSingleByteFont(Typeface tf, String fontName, float fontSize, PDFTextUtil textutil,
+ char ch) {
+ if ((tf instanceof SingleByteFont && ((SingleByteFont)tf).hasAdditionalEncodings()) || tf.isCID()) {
int encoding = ch / 256;
if (encoding == 0) {
- textutil.updateTf(fontName, fontSize, singleByteFont.isMultiByte());
+ textutil.updateTf(fontName, fontSize, tf.isMultiByte(), tf.isCID());
} else {
textutil.updateTf(fontName + "_" + Integer.toString(encoding),
- fontSize, singleByteFont.isMultiByte());
+ fontSize, tf.isMultiByte(), tf.isCID());
ch = (char)(ch % 256);
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/ps/PSFontUtils.java b/fop-core/src/main/java/org/apache/fop/render/ps/PSFontUtils.java
index 1a8291f05..f2f6bdaf3 100644
--- a/fop-core/src/main/java/org/apache/fop/render/ps/PSFontUtils.java
+++ b/fop-core/src/main/java/org/apache/fop/render/ps/PSFontUtils.java
@@ -248,7 +248,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
PSFontResource fontResource = null;
PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName());
if (!(fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE
- || fontType == FontType.TYPE0) || !(tf instanceof CustomFont)) {
+ || fontType == FontType.TYPE0 || fontType == FontType.TYPE1C) || !(tf instanceof CustomFont)) {
gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
fontResource = PSFontResource.createFontResource(fontRes);
return fontResource;
@@ -262,7 +262,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
if (i > 0) {
fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName() + "." + i);
}
- if (fontType == FontType.TYPE0) {
+ if (fontType == FontType.TYPE0 || fontType == FontType.TYPE1C) {
if (((MultiByteFont) tf).isOTFFile()) {
checkPostScriptLevel3(gen, eventProducer, "OpenType CFF");
embedType2CFF(gen, (MultiByteFont) tf, in);
@@ -525,7 +525,6 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
private static void embedType2CFF(PSGenerator gen,
MultiByteFont font, InputStream fontStream) throws IOException {
FontFileReader reader = new FontFileReader(fontStream);
- String header = OFFontLoader.readHeader(reader);
String psName;
CFFDataReader cffReader = new CFFDataReader(reader);
if (cffReader.getFDSelect() != null) {
@@ -560,7 +559,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
} else {
psName = font.getEmbedFontName();
OTFSubSetFile otfFile = new OTFSubSetFile();
- otfFile.readFont(reader, psName, header, font);
+ otfFile.readFont(reader, psName, font);
bytes = otfFile.getFontSubset();
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java b/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
index f0f10a1e0..2400ff7d3 100644
--- a/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
@@ -40,7 +40,6 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSResource;
-import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
@@ -491,7 +490,6 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
if (!multiByte || isOTF) {
char codepoint = (char)(ch % 256);
if (isOTF) {
- codepoint -= (((MultiByteFont)tf).getEmbeddingMode() == EmbeddingMode.FULL) ? 0 : 1;
accText.append(HexEncoder.encode(codepoint, 2));
} else {
PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
diff --git a/fop-core/src/main/java/org/apache/fop/svg/PDFTextPainter.java b/fop-core/src/main/java/org/apache/fop/svg/PDFTextPainter.java
index 0320438f8..5c5308ace 100644
--- a/fop-core/src/main/java/org/apache/fop/svg/PDFTextPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/svg/PDFTextPainter.java
@@ -127,7 +127,7 @@ class PDFTextPainter extends NativeTextPainter {
double xoLast = 0f;
double yoLast = 0f;
textUtil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, initialPos.getX(), initialPos.getY()));
- textUtil.updateTf(fk, fsPoints, true);
+ textUtil.updateTf(fk, fsPoints, true, false);
int[][] dp = gv.getGlyphPositionAdjustments();
for (int i = 0, n = gv.getNumGlyphs(); i < n; i++) {
int gc = gv.getGlyphCode(i);
@@ -139,7 +139,7 @@ class PDFTextPainter extends NativeTextPainter {
double xd = (xo - xoLast) / 1000f;
double yd = (yo - yoLast) / 1000f;
textUtil.writeTd(xd, yd);
- textUtil.writeTj((char) gc);
+ textUtil.writeTj((char) gc, true, false);
xc += xa + pa[2];
yc += ya + pa[3];
xoLast = xo;
diff --git a/fop-core/src/main/java/org/apache/fop/svg/PDFTextUtil.java b/fop-core/src/main/java/org/apache/fop/svg/PDFTextUtil.java
index 23fadc542..b3a346509 100644
--- a/fop-core/src/main/java/org/apache/fop/svg/PDFTextUtil.java
+++ b/fop-core/src/main/java/org/apache/fop/svg/PDFTextUtil.java
@@ -91,6 +91,11 @@ public abstract class PDFTextUtil extends org.apache.fop.pdf.PDFTextUtil {
return f.isMultiByte();
}
+ protected boolean isCIDFont(String name) {
+ Typeface f = fontInfo.getFonts().get(name);
+ return f.isCID();
+ }
+
/**
* Writes a "Tf" command, setting a new current font.
* @param f the font to select
@@ -99,10 +104,11 @@ public abstract class PDFTextUtil extends org.apache.fop.pdf.PDFTextUtil {
String fontName = f.getFontName();
float fontSize = (float)f.getFontSize() / 1000f;
boolean isMultiByte = isMultiByteFont(fontName);
+ boolean isCid = isCIDFont(fontName);
if (!isMultiByte && encoding != 0) {
- updateTf(fontName + "_" + Integer.toString(encoding), fontSize, isMultiByte);
+ updateTf(fontName + "_" + Integer.toString(encoding), fontSize, isMultiByte, isCid);
} else {
- updateTf(fontName, fontSize, isMultiByte);
+ updateTf(fontName, fontSize, isMultiByte, isCid);
}
}
diff --git a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java
index 73fd6028a..608d8c3dc 100644
--- a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java
@@ -64,8 +64,7 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
}
sourceSansSubset = new OTFSubSetFile();
- String sourceSansHeader = OFFontLoader.readHeader(sourceSansReader);
- sourceSansSubset.readFont(sourceSansReader, "SourceSansProBold", sourceSansHeader, glyphs);
+ sourceSansSubset.readFont(sourceSansReader, "SourceSansProBold", null, glyphs);
byte[] sourceSansData = sourceSansSubset.getFontSubset();
cffReaderSourceSans = new CFFDataReader(sourceSansData);
}
@@ -442,11 +441,8 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase {
private byte[] getSubset(final int opLen) throws IOException {
FontFileReader reader = sourceSansReader;
- String header = OFFontLoader.readHeader(reader);
-
OTFSubSetFile otfSubSetFile = new MyOTFSubSetFile(opLen);
-
- otfSubSetFile.readFont(reader, "StandardOpenType", header, new HashMap<Integer, Integer>());
+ otfSubSetFile.readFont(reader, "StandardOpenType", null, new HashMap<Integer, Integer>());
return otfSubSetFile.getFontSubset();
}
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
index edbc7e449..220464e6e 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
@@ -19,12 +19,14 @@
package org.apache.fop.pdf;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.IOException;
import java.net.URI;
import org.junit.Test;
-
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import org.apache.xmlgraphics.io.ResourceResolver;
@@ -32,8 +34,11 @@ import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.CIDSet;
import org.apache.fop.fonts.CIDSubset;
+import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.FontUris;
import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.truetype.OFFontLoader;
/**
* Test case for {@link PDFFactory}.
@@ -75,4 +80,37 @@ public class PDFFactoryTestCase {
PDFFont pdfArial = pdfFactory.makeFont("Arial", "Arial", "TTF", font, font);
assertEquals("/EAAAAB+Arial", pdfArial.getBaseFont().toString());
}
+
+ @Test
+ public void testMakeOTFFont() throws IOException {
+ InternalResourceResolver rr =
+ ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI());
+ PDFDocument doc = new PDFDocument("");
+ PDFFactory pdfFactory = new PDFFactory(doc);
+ URI uri = new File("test/resources/fonts/otf/SourceSansProBold.otf").toURI();
+ CustomFont sb = OFFontLoader.loadFont(new FontUris(uri, null),
+ null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false);
+ for (char c = 0; c < 512; c++) {
+ sb.mapChar(c);
+ }
+ pdfFactory.makeFont("a", "a", "WinAnsiEncoding", sb, sb);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ doc.outputTrailer(bos);
+
+ assertEquals(pdfFactory.getDocument().getFontMap().size(), 2);
+ PDFFont pdfFont = pdfFactory.getDocument().getFontMap().get("a_1");
+ PDFEncoding enc = (PDFEncoding) pdfFont.get("Encoding");
+ PDFArray diff = (PDFArray) enc.get("Differences");
+ assertEquals(diff.length(), 80);
+ assertEquals(diff.get(1).toString(), "/nacute");
+
+ pdfFont = pdfFactory.getDocument().getFontMap().get("a");
+ enc = (PDFEncoding) pdfFont.get("Encoding");
+ diff = (PDFArray) enc.get("Differences");
+ assertEquals(diff.length(), 257);
+ assertEquals(diff.get(2).toString(), "/space");
+
+ assertTrue(bos.toString().contains("/Subtype /Type1\n"));
+ assertTrue(bos.toString().contains("/Subtype /Type1C"));
+ }
}
diff --git a/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java
index 8ad8d753b..c2bc2017f 100644
--- a/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java
@@ -219,9 +219,9 @@ public class PSPainterTestCase {
+ "<00000000000000000000> t\n"
+ "/OTFFont.0 0.01 F\n"
+ "1 0 0 -1 0 0 Tm\n"
- + "<FFFFFFFFFF> t\n"
+ + "<0000000000> t\n"
+ "1 0 0 -1 0 0 Tm\n"
- + "<FFFFFFFFFF> t\n"
+ + "<0000000000> t\n"
+ "/TTFFont 0.01 F\n"
+ "1 0 0 -1 0 0 Tm\n"
+ "<00000000000000000000> t\n"));