浏览代码

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
tags/fop-2_3
Simon Steiner 7 年前
父节点
当前提交
0ede8c8d81

+ 1
- 1
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;
}

}

+ 92
- 0
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;
}
}

+ 3
- 0
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;
}


+ 1
- 73
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) {
@@ -406,41 +369,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
@@ -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;

+ 4
- 0
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);

+ 16
- 8
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]);
}
}
}

+ 5
- 0
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;
}
}

+ 7
- 6
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);
}
}

+ 13
- 5
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);
}

+ 96
- 6
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);

+ 10
- 8
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);
}

+ 13
- 16
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);
}
}

+ 3
- 4
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();
}


+ 0
- 2
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

+ 2
- 2
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;

+ 8
- 2
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);
}
}


+ 2
- 6
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();
}


+ 39
- 1
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"));
}
}

+ 2
- 2
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"));

+ 1
- 0
fop/build.xml 查看文件

@@ -640,6 +640,7 @@ list of possible build targets.
<include name="org/apache/fop/util/CharUtilities.class"/>
<include name="org/apache/fop/util/DecimalFormatCache*.class"/>
<include name="org/apache/fop/util/ImageObject.class"/>
<include name="org/apache/fop/util/HexEncoder.class"/>
</patternset>
<!-- PDF transcoder -->
<patternset>

正在加载...
取消
保存