Browse Source

FOP-2504: Truetype support for AFP

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1694450 13f79535-47bb-0310-9956-ffa450edef68
pull/39/head
Simon Steiner 8 years ago
parent
commit
aff2383ae1

BIN
lib/xmlgraphics-commons-svn-trunk.jar View File


+ 76
- 15
src/java/org/apache/fop/afp/AFPResourceManager.java View File

@@ -36,15 +36,21 @@ import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.fonts.CharacterSet;
import org.apache.fop.afp.modca.AbstractNamedAFPObject;
import org.apache.fop.afp.modca.AbstractPageObject;
import org.apache.fop.afp.modca.ActiveEnvironmentGroup;
import org.apache.fop.afp.modca.IncludeObject;
import org.apache.fop.afp.modca.IncludedResourceObject;
import org.apache.fop.afp.modca.ObjectContainer;
import org.apache.fop.afp.modca.PageSegment;
import org.apache.fop.afp.modca.Registry;
import org.apache.fop.afp.modca.ResourceGroup;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.afp.modca.triplets.EncodingTriplet;
import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
import org.apache.fop.afp.util.AFPResourceAccessor;
import org.apache.fop.afp.util.AFPResourceUtil;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.fonts.FontType;
import org.apache.fop.render.afp.AFPFontConfig;

/**
* Manages the creation and storage of document resources
@@ -330,12 +336,19 @@ public class AFPResourceManager {
//Embed fonts (char sets and code pages)
if (charSet.getResourceAccessor() != null) {
AFPResourceAccessor accessor = charSet.getResourceAccessor();
createIncludedResource(
charSet.getName(), accessor,
ResourceObject.TYPE_FONT_CHARACTER_SET);
createIncludedResource(
charSet.getCodePage(), accessor,
ResourceObject.TYPE_CODE_PAGE);
if (afpFont.getFontType() == FontType.TRUETYPE) {

createIncludedResource(afpFont.getFontName(), accessor.resolveURI("."), accessor,
ResourceObject.TYPE_OBJECT_CONTAINER, true,
((AFPFontConfig.AFPTrueTypeFont) afpFont).getTTC());
} else {
createIncludedResource(
charSet.getName(), accessor,
ResourceObject.TYPE_FONT_CHARACTER_SET);
createIncludedResource(
charSet.getCodePage(), accessor,
ResourceObject.TYPE_CODE_PAGE);
}
}
}
}
@@ -366,7 +379,7 @@ public class AFPResourceManager {
+ " (" + e.getMessage() + ")");
}

createIncludedResource(resourceName, uri, accessor, resourceObjectType);
createIncludedResource(resourceName, uri, accessor, resourceObjectType, false, null);
}

/**
@@ -378,7 +391,7 @@ public class AFPResourceManager {
* @throws IOException if an I/O error occurs while loading the resource
*/
public void createIncludedResource(String resourceName, URI uri, AFPResourceAccessor accessor,
byte resourceObjectType) throws IOException {
byte resourceObjectType, boolean truetype, String ttc) throws IOException {
AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE);

AFPResourceInfo resourceInfo = new AFPResourceInfo();
@@ -391,15 +404,46 @@ public class AFPResourceManager {
if (log.isDebugEnabled()) {
log.debug("Adding included resource: " + resourceName);
}
IncludedResourceObject resourceContent = new IncludedResourceObject(
resourceName, accessor, uri);

ResourceObject resourceObject = factory.createResource(resourceName);
resourceObject.setDataObject(resourceContent);
resourceObject.setType(resourceObjectType);

ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
resourceGroup.addObject(resourceObject);

if (truetype) {
ResourceObject res = factory.createResource();
res.setType(ResourceObject.TYPE_OBJECT_CONTAINER);

ActiveEnvironmentGroup.setupTruetypeMDR(res, false);

ObjectContainer oc = factory.createObjectContainer();
InputStream is;
try {
is = accessor.createInputStream(new URI("."));
} catch (URISyntaxException e) {
throw new IOException(e);
}

if (ttc != null) {
oc.setData(extractTTC(ttc, is));
} else {
oc.setData(IOUtils.toByteArray(is));
}

ActiveEnvironmentGroup.setupTruetypeMDR(oc, true);

res.addTriplet(new EncodingTriplet(1200));

res.setFullyQualifiedName(FullyQualifiedNameTriplet.TYPE_REPLACE_FIRST_GID_NAME,
FullyQualifiedNameTriplet.FORMAT_CHARSTR, resourceName, true);

res.setDataObject(oc);
resourceGroup.addObject(res);
} else {
ResourceObject resourceObject = factory.createResource(resourceName);
IncludedResourceObject resourceContent = new IncludedResourceObject(
resourceName, accessor, uri);
resourceObject.setDataObject(resourceContent);
resourceObject.setType(resourceObjectType);
resourceGroup.addObject(resourceObject);
}

//TODO what is the data object?
cachedObject = new CachedObject(resourceName, null);
@@ -411,6 +455,23 @@ public class AFPResourceManager {
}
}

private byte[] extractTTC(String ttc, InputStream is) throws IOException {
// TrueTypeCollection trueTypeCollection = new TrueTypeCollection(is);
// for (TrueTypeFont ttf : trueTypeCollection.getFonts()) {
// String name = ttf.getNaming().getFontFamily();
// if (name.equals(ttc)) {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// TTFSubsetter s = new TTFSubsetter(ttf, null);
// for (int i = 0; i < 256 * 256; i++) {
// s.addCharCode(i);
// }
// s.writeToStream(bos);
// return bos.toByteArray();
// }
// }
throw new IOException(ttc + " not supported");
}

/**
* Creates an included resource extracting the named resource from an external source.
* @param resourceName the name of the resource

+ 6
- 2
src/java/org/apache/fop/afp/fonts/CharacterSet.java View File

@@ -108,8 +108,12 @@ public class CharacterSet {

// the character set name must be 8 chars long
this.name = padName(name);
// the code page name must be 8 chars long
this.codePage = padName(codePage);
if (codePage == null) {
this.codePage = null;
} else {
// the code page name must be 8 chars long
this.codePage = padName(codePage);
}

this.encoding = encoding;
this.encoder = charsetType.getEncoder(encoding);

+ 6
- 0
src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java View File

@@ -232,6 +232,12 @@ public abstract class CharacterSetBuilder {
eventProducer);
}

public CharacterSet build(String characterSetName, String codePageName, String encoding,
Typeface typeface, AFPResourceAccessor accessor, AFPEventProducer eventProducer)
throws IOException {
return new FopCharacterSet(codePageName, encoding, characterSetName, typeface, accessor, eventProducer);
}

private CharacterSet processFont(String characterSetName, String codePageName, String encoding,
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer)
throws IOException {

+ 6
- 0
src/java/org/apache/fop/afp/fonts/FopCharacterSet.java View File

@@ -49,6 +49,12 @@ public class FopCharacterSet extends CharacterSet {
this.charSet = charSet;
}

public FopCharacterSet(String codePage, String encoding, String name, Typeface charSet,
AFPResourceAccessor accessor, AFPEventProducer eventProducer) {
super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, accessor, eventProducer);
this.charSet = charSet;
}

/**
* Ascender height is the distance from the character baseline to the
* top of the character box. A negative ascender height signifies that

+ 6
- 2
src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java View File

@@ -103,7 +103,7 @@ public abstract class AbstractTripletStructuredObject extends AbstractStructured
*
* @param triplet the triplet to add
*/
protected void addTriplet(AbstractTriplet triplet) {
public void addTriplet(AbstractTriplet triplet) {
triplets.add(triplet);
}

@@ -131,7 +131,11 @@ public abstract class AbstractTripletStructuredObject extends AbstractStructured
* @param fqName the fully qualified name of this resource
*/
public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName) {
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName));
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName, false));
}

public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName, boolean utf16be) {
addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName, utf16be));
}

/** @return the fully qualified name of this triplet or null if it does not exist */

+ 97
- 13
src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java View File

@@ -23,8 +23,17 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.afp.Factory;
import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.modca.triplets.AbstractTriplet;
import org.apache.fop.afp.modca.triplets.EncodingTriplet;
import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet;
import org.apache.fop.afp.util.BinaryUtils;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fonts.FontType;
import org.apache.fop.render.afp.AFPFontConfig;

/**
* An Active Environment Group (AEG) is associated with each page,
@@ -63,6 +72,8 @@ public final class ActiveEnvironmentGroup extends AbstractEnvironmentGroup {
/** the resource manager */
private final Factory factory;

private MapDataResource mdr;

/**
* Constructor for the ActiveEnvironmentGroup, this takes a
* name parameter which must be 8 characters long.
@@ -169,27 +180,100 @@ public final class ActiveEnvironmentGroup extends AbstractEnvironmentGroup {
* @param orientation the orientation of the font (e.g. 0, 90, 180, 270)
*/
public void createFont(int fontRef, AFPFont font, int size, int orientation) {
MapCodedFont mapCodedFont = getCurrentMapCodedFont();
if (mapCodedFont == null) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(mapCodedFont);
}
if (font.getFontType() == FontType.TRUETYPE) {
if (mdr == null) {
mdr = factory.createMapDataResource();
mapCodedFonts.add(mdr);
}
mdr.addTriplet(new EncodingTriplet(1200));
String name = font.getFontName();
if (((AFPFontConfig.AFPTrueTypeFont)font).getTTC() != null) {
name = ((AFPFontConfig.AFPTrueTypeFont)font).getTTC();
}
mdr.setFullyQualifiedName(FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_EXTERNAL_RESOURCE_REF,
FullyQualifiedNameTriplet.FORMAT_CHARSTR, name, true);
mdr.addTriplet(new FontFullyQualifiedNameTriplet((byte) fontRef));

try {
mapCodedFont.addFont(fontRef, font, size, orientation);
} catch (MaximumSizeExceededException msee) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(mapCodedFont);
setupTruetypeMDR(mdr, false);
mdr.addTriplet(new DataObjectFontTriplet(size / 1000));
mdr.finishElement();
} else {
MapCodedFont mapCodedFont = getCurrentMapCodedFont();
if (mapCodedFont == null) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(mapCodedFont);
}

try {
mapCodedFont.addFont(fontRef, font, size, orientation);
} catch (MaximumSizeExceededException ex) {
// Should never happen (but log just in case)
LOG.error("createFont():: resulted in a MaximumSizeExceededException");
} catch (MaximumSizeExceededException msee) {
mapCodedFont = factory.createMapCodedFont();
mapCodedFonts.add(mapCodedFont);

try {
mapCodedFont.addFont(fontRef, font, size, orientation);
} catch (MaximumSizeExceededException ex) {
// Should never happen (but log just in case)
LOG.error("createFont():: resulted in a MaximumSizeExceededException");
}
}
}
}

public static void setupTruetypeMDR(AbstractTripletStructuredObject mdr, boolean res) {
AFPDataObjectInfo dataInfo = new AFPDataObjectInfo();
dataInfo.setMimeType(MimeConstants.MIME_AFP_TRUETYPE);
mdr.setObjectClassification(ObjectClassificationTriplet.CLASS_DATA_OBJECT_FONT,
dataInfo.getObjectType(), res, false, res);
}

public static class FontFullyQualifiedNameTriplet extends AbstractTriplet {
private byte fqName;
public FontFullyQualifiedNameTriplet(byte fqName) {
super(FULLY_QUALIFIED_NAME);
this.fqName = fqName;
}

public int getDataLength() {
return 5;
}

public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = FullyQualifiedNameTriplet.TYPE_DATA_OBJECT_INTERNAL_RESOURCE_REF;
data[3] = FullyQualifiedNameTriplet.FORMAT_CHARSTR;
data[4] = fqName;
os.write(data);
}
}

static class DataObjectFontTriplet extends AbstractTriplet {
private int pointSize;

public DataObjectFontTriplet(int size) {
super(DATA_OBJECT_FONT_DESCRIPTOR);
pointSize = size;
}

public int getDataLength() {
return 16;
}

public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[3] = 0x20;
byte[] pointSizeBytes = BinaryUtils.convert(pointSize * 20, 2);
data[4] = pointSizeBytes[0]; //vfs
data[5] = pointSizeBytes[1];
// data[6] = pointSizeBytes[0]; //hsf
// data[7] = pointSizeBytes[1];
//charrot
data[11] = 0x03; //encenv
data[13] = 0x01; //encid
os.write(data);
}
}

/**
* Getter method for the most recent MapCodedFont added to the
* Active Environment Group (returns null if no MapCodedFonts exist)

+ 35
- 8
src/java/org/apache/fop/afp/modca/MapDataResource.java View File

@@ -21,7 +21,11 @@ package org.apache.fop.afp.modca;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.fop.afp.modca.triplets.AbstractTriplet;
import org.apache.fop.afp.modca.triplets.Triplet;
import org.apache.fop.afp.util.BinaryUtils;

/**
@@ -29,6 +33,7 @@ import org.apache.fop.afp.util.BinaryUtils;
* required for presentation.
*/
public class MapDataResource extends AbstractTripletStructuredObject {
private List<List<AbstractTriplet>> tripletsList = new ArrayList<List<AbstractTriplet>>();

/**
* Main constructor
@@ -36,23 +41,45 @@ public class MapDataResource extends AbstractTripletStructuredObject {
public MapDataResource() {
}

public void finishElement() {
tripletsList.add(triplets);
triplets = new ArrayList<AbstractTriplet>();
}

@Override
protected int getTripletDataLength() {
int dataLength = 0;
for (List<AbstractTriplet> l : tripletsList) {
dataLength += getTripletDataLength(l) + 2;
}
return dataLength;
}

private int getTripletDataLength(List<AbstractTriplet> l) {
int dataLength = 0;
for (Triplet triplet : l) {
dataLength += triplet.getDataLength();
}
return dataLength;
}

/** {@inheritDoc} */
public void writeToStream(OutputStream os) throws IOException {
super.writeStart(os);
byte[] data = new byte[11];
byte[] data = new byte[9];
copySF(data, Type.MAP, Category.DATA_RESOURCE);

int tripletDataLen = getTripletDataLength();

byte[] len = BinaryUtils.convert(10 + tripletDataLen, 2);
byte[] len = BinaryUtils.convert(8 + tripletDataLen, 2);
data[1] = len[0];
data[2] = len[1];

len = BinaryUtils.convert(2 + tripletDataLen, 2);
data[9] = len[0];
data[10] = len[1];

os.write(data);
writeTriplets(os);

for (List<AbstractTriplet> l : tripletsList) {
len = BinaryUtils.convert(2 + getTripletDataLength(l), 2);
os.write(len);
writeObjects(l, os);
}
}
}

+ 1
- 1
src/java/org/apache/fop/afp/modca/ObjectContainer.java View File

@@ -36,7 +36,7 @@ import org.apache.fop.afp.util.BinaryUtils;
public class ObjectContainer extends AbstractDataObject {

/** the object container data maximum length */
private static final int MAX_DATA_LEN = 32759;
private static final int MAX_DATA_LEN = 8192;

private byte[] data;


+ 12
- 12
src/java/org/apache/fop/afp/modca/Registry.java View File

@@ -174,24 +174,24 @@ public final class Registry {
MimeConstants.MIME_PCL
)
);
mimeObjectTypeMap.put(
MimeConstants.MIME_AFP_TRUETYPE,
new ObjectType(
COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT,
new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x33},
"TrueType/OpenType Font Resource Object",
true,
MimeConstants.MIME_AFP_TRUETYPE
)
);
// mimeObjectTypeMap.put(
// null,
// new ObjectType(
// COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT,
// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x33},
// "TrueType/OpenType Font Resource Object",
// true,
// null
// )
// );
// mimeObjectTypeMap.put(
// null,
// MimeConstants.MIME_AFP_TTC,
// new ObjectType(
// COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT,
// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x35},
// "TrueType/OpenType Font Collection Resource Object",
// true,
// null
// MimeConstants.MIME_AFP_TTC
// )
// );
}

+ 10
- 3
src/java/org/apache/fop/afp/modca/triplets/FullyQualifiedNameTriplet.java View File

@@ -150,6 +150,10 @@ public class FullyQualifiedNameTriplet extends AbstractTriplet {
/** the actual fully qualified name */
private final String fqName;

private String encoding = AFPConstants.EBCIDIC_ENCODING;

private int charlen = 1;

/**
* Main constructor
*
@@ -157,11 +161,15 @@ public class FullyQualifiedNameTriplet extends AbstractTriplet {
* @param format the fully qualified name format
* @param fqName the fully qualified name
*/
public FullyQualifiedNameTriplet(byte type, byte format, String fqName) {
public FullyQualifiedNameTriplet(byte type, byte format, String fqName, boolean utf16be) {
super(FULLY_QUALIFIED_NAME);
this.type = type;
this.format = format;
this.fqName = fqName;
if (utf16be) {
encoding = "UTF-16BE";
charlen = 2;
}
}

/**
@@ -180,7 +188,7 @@ public class FullyQualifiedNameTriplet extends AbstractTriplet {

/** {@inheritDoc} */
public int getDataLength() {
return 4 + fqName.length();
return 4 + (fqName.length() * charlen);
}

/** {@inheritDoc} */
@@ -191,7 +199,6 @@ public class FullyQualifiedNameTriplet extends AbstractTriplet {

// FQName
byte[] fqNameBytes;
String encoding = AFPConstants.EBCIDIC_ENCODING;
if (format == FORMAT_URL) {
encoding = AFPConstants.US_ASCII_ENCODING;
}

+ 1
- 1
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

@@ -399,7 +399,7 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
try {
getResourceManager().createIncludedResource(formMap.getName(),
formMap.getSrc(), accessor,
ResourceObject.TYPE_FORMDEF);
ResourceObject.TYPE_FORMDEF, false, null);
} catch (IOException ioe) {
throw new IFException(
"I/O error while embedding form map resource: " + formMap.getName(), ioe);

+ 80
- 4
src/java/org/apache/fop/render/afp/AFPFontConfig.java View File

@@ -20,6 +20,8 @@
package org.apache.fop.render.afp;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -42,12 +44,16 @@ import org.apache.fop.afp.util.AFPResourceAccessor;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.events.EventProducer;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.FontConfig;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.FontTriplet.Matcher;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.FontUris;
import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.fonts.Typeface;

/**
@@ -154,6 +160,13 @@ public final class AFPFontConfig implements FontConfig {
triplet.getAttribute("style"), weight);
tripletList.add(fontTriplet);
}

String tturi = fontCfg.getAttribute("embed-url", null);
if (tturi != null) {
fontFromType(tripletList, "truetype", null, "UTF-16BE", fontCfg, eventProducer, tturi);
return;
}

//build the fonts
Configuration[] config = fontCfg.getChildren("afp-font");
if (config.length == 0) {
@@ -199,8 +212,9 @@ public final class AFPFontConfig implements FontConfig {
embedURI);
} else if ("CIDKeyed".equalsIgnoreCase(type)) {
config = getCIDKeyedFont(fontTriplets, type, codepage, encoding, cfg,
eventProducer,
embedURI);
eventProducer, embedURI);
} else if ("truetype".equalsIgnoreCase(type)) {
config = getTruetypeFont(fontTriplets, type, codepage, encoding, cfg, eventProducer, embedURI);
} else {
LOG.error("No or incorrect type attribute: " + type);
}
@@ -240,6 +254,19 @@ public final class AFPFontConfig implements FontConfig {
name, base14, isEmbbedable(fontTriplets), uri);
}

private TrueTypeFontConfig getTruetypeFont(List<FontTriplet> fontTriplets, String type, String codepage,
String encoding, Configuration cfg, AFPEventProducer eventProducer,
String uri) throws ConfigurationException {
String name = cfg.getAttribute("name", null);
if (name == null) {
eventProducer.fontConfigMissing(this, "font name attribute", cfg.getLocation());
return null;
}
String subfont = cfg.getAttribute("sub-font", null);
return new TrueTypeFontConfig(fontTriplets, type, codepage, encoding, "",
name, subfont, isEmbbedable(fontTriplets), uri);
}

private RasterFontConfig getRasterFont(List<FontTriplet> triplets, String type,
String codepage, String encoding, Configuration cfg,
AFPEventProducer eventProducer, String uri)
@@ -281,12 +308,12 @@ public final class AFPFontConfig implements FontConfig {
}

abstract static class AFPFontConfigData {
private final List<FontTriplet> triplets;
protected final List<FontTriplet> triplets;
private final String codePage;
private final String encoding;
private final String name;
private final boolean embeddable;
private final String uri;
protected final String uri;

AFPFontConfigData(List<FontTriplet> triplets, String type, String codePage,
String encoding, String name, boolean embeddable, String uri) {
@@ -334,6 +361,55 @@ public final class AFPFontConfig implements FontConfig {
}
}

static final class TrueTypeFontConfig extends AFPFontConfigData {
private String characterset;
private String subfont;

private TrueTypeFontConfig(List<FontTriplet> triplets, String type, String codePage,
String encoding, String characterset, String name, String subfont,
boolean embeddable, String uri) {
super(triplets, type, codePage, encoding, name, embeddable, uri);
this.characterset = characterset;
this.subfont = subfont;
}

@Override
AFPFontInfo getFontInfo(InternalResourceResolver resourceResolver, AFPEventProducer eventProducer)
throws IOException {
Typeface tf;
try {
tf = new LazyFont(new EmbedFontInfo(
new FontUris(new URI(uri), null)
, false, true, null, subfont), resourceResolver, false).getRealFont();
} catch (URISyntaxException e) {
throw new IOException(e);
}
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset, super.codePage,
super.encoding, tf, accessor, eventProducer);
OutlineFont font = new AFPTrueTypeFont(super.name, super.embeddable, characterSet,
eventProducer, subfont);
return getFontInfo(font, this);
}
}

public static class AFPTrueTypeFont extends OutlineFont {
private String ttc;
public AFPTrueTypeFont(String name, boolean embeddable, CharacterSet charSet, AFPEventProducer eventProducer,
String ttc) {
super(name, embeddable, charSet, eventProducer);
this.ttc = ttc;
}

public FontType getFontType() {
return FontType.TRUETYPE;
}

public String getTTC() {
return ttc;
}
}

static final class OutlineFontConfig extends AFPFontConfigData {
private final String base14;
private final String characterset;

+ 14
- 2
src/java/org/apache/fop/render/afp/AFPPainter.java View File

@@ -68,6 +68,7 @@ import org.apache.fop.afp.ptoca.PtocaProducer;
import org.apache.fop.afp.util.AFPResourceAccessor;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.ImageHandlerUtil;
import org.apache.fop.render.RenderingContext;
@@ -973,11 +974,18 @@ public class AFPPainter extends AbstractIFPainter<AFPDocumentHandler> {
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement);

boolean fixedSpaceMode = false;
int ttPos = p.x;

for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
if (afpFont.getFontType() == FontType.TRUETYPE) {
flushText(builder, sb, charSet);
fixedSpaceMode = true;
int charWidth = font.getCharWidth(orgChar);
sb.append(orgChar);
glyphAdjust += charWidth;
} else if (CharUtilities.isFixedWidthSpace(orgChar)) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
fixedSpaceCharacterIncrement);
@@ -1005,7 +1013,11 @@ public class AFPPainter extends AbstractIFPainter<AFPDocumentHandler> {
glyphAdjust += dx[i + 1];
}

if (glyphAdjust != 0) {
if (afpFont.getFontType() == FontType.TRUETYPE) {
flushText(builder, sb, charSet);
ttPos += Math.round(unitConv.mpt2units(glyphAdjust));
builder.absoluteMoveInline(ttPos);
} else if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);

+ 235
- 0
test/java/org/apache/fop/render/afp/AFPParser.java View File

@@ -0,0 +1,235 @@
/*
* 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.render.afp;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.ptoca.PtocaBuilder;

import junit.framework.Assert;

public class AFPParser {
private boolean readText;
public AFPParser(boolean readText) {
this.readText = readText;
}

public void read(InputStream bis, StringBuilder sb) throws IOException {
while (bis.available() > 0) {
readField(bis, sb);
}
}

private void readField(InputStream bis, StringBuilder sb) throws IOException {
bis.read();
int len = getLength(bis.read(), bis.read());
byte[] field = new byte[len - 2];
bis.read(field);
InputStream fieldStream = new ByteArrayInputStream(field);
fieldStream.read();
byte type = (byte) fieldStream.read();
byte category = (byte) fieldStream.read();
fieldStream.skip(3);
String typeStr = TYPE_MAP.get(type & 0xFF);
String catStr = CATEGORY_MAP.get(category & 0xFF);
if (typeStr != null && catStr != null) {
sb.append(typeStr + " " + catStr);
if (typeStr.equals("BEGIN") || typeStr.equals("END")) {
byte[] name = new byte[8];
fieldStream.read(name);
sb.append(" " + new String(name, AFPConstants.EBCIDIC_ENCODING));
fieldStream.skip(2);
readTriplet(fieldStream, sb);
} else if (typeStr.equals("MAP")) {
fieldStream.skip(2);
readTriplet(fieldStream, sb);
} else if (typeStr.equals("DESCRIPTOR") && catStr.equals("OBJECT_AREA")) {
readTriplet(fieldStream, sb);
} else if (typeStr.equals("DATA") && catStr.equals("PRESENTATION_TEXT") && readText) {
readData(fieldStream, sb);
}
sb.append("\n");
}
}

private void readData(InputStream bis, StringBuilder sb) throws IOException {
Assert.assertEquals(bis.read(), 0x2B);
Assert.assertEquals(bis.read(), 0xD3);
while (bis.available() > 0) {
int len = bis.read();
int functionType = bis.read();

sb.append(" " + PTOCA_MAP.get(functionType));

if ("TRN".equals(PTOCA_MAP.get(functionType))) {
byte[] data = new byte[len - 2];
bis.read(data);
sb.append(" " + new String(data, "UTF-16BE"));
} else {
bis.skip(len - 2);
}
}
}

private void readTriplet(InputStream des, StringBuilder sb) throws IOException {
if (des.available() > 0) {
sb.append(" Triplets: ");
}
while (des.available() > 0) {
int len2 = des.read();
int id = des.read();
int b = id & 0xFF;
if (TRIPLET_MAP.containsKey(b)) {
sb.append(TRIPLET_MAP.get(b) + ",");
} else {
sb.append(String.format("0x%02X,", b));
}
des.skip(len2 - 2);
}
}

private int getLength(int a, int b) {
return (a * 256) + b;
}

private static final Map<Integer, String> TYPE_MAP = new HashMap<Integer, String>();
private static final Map<Integer, String> CATEGORY_MAP = new HashMap<Integer, String>();
private static final Map<Integer, String> TRIPLET_MAP = new HashMap<Integer, String>();
private static final Map<Integer, String> PTOCA_MAP = new HashMap<Integer, String>();
static {
PTOCA_MAP.put(0xC2 | PtocaBuilder.CHAIN_BIT, "SIA");
PTOCA_MAP.put(0xC4 | PtocaBuilder.CHAIN_BIT, "SVI");
PTOCA_MAP.put(0xC6 | PtocaBuilder.CHAIN_BIT, "AMI");
PTOCA_MAP.put(0xC8 | PtocaBuilder.CHAIN_BIT, "RMI");
PTOCA_MAP.put(0xD2 | PtocaBuilder.CHAIN_BIT, "AMB");
PTOCA_MAP.put(0xDA | PtocaBuilder.CHAIN_BIT, "TRN");
PTOCA_MAP.put(0xE4 | PtocaBuilder.CHAIN_BIT, "DIR");
PTOCA_MAP.put(0xE6 | PtocaBuilder.CHAIN_BIT, "DBR");
PTOCA_MAP.put(0x80 | PtocaBuilder.CHAIN_BIT, "SEC");
PTOCA_MAP.put(0xF0 | PtocaBuilder.CHAIN_BIT, "SCFL");
PTOCA_MAP.put(0xF6 | PtocaBuilder.CHAIN_BIT, "STO");
PTOCA_MAP.put(0xF8 | PtocaBuilder.CHAIN_BIT, "NOP");

TYPE_MAP.put(0xA0, "ATTRIBUTE");
TYPE_MAP.put(0xA2, "COPY_COUNT");
TYPE_MAP.put(0xA6, "DESCRIPTOR");
TYPE_MAP.put(0xA7, "CONTROL");
TYPE_MAP.put(0xA8, "BEGIN");
TYPE_MAP.put(0xA9, "END");
TYPE_MAP.put(0xAB, "MAP");
TYPE_MAP.put(0xAC, "POSITION");
TYPE_MAP.put(0xAD, "PROCESS");
TYPE_MAP.put(0xAF, "INCLUDE");
TYPE_MAP.put(0xB0, "TABLE");
TYPE_MAP.put(0xB1, "MIGRATION");
TYPE_MAP.put(0xB2, "VARIABLE");
TYPE_MAP.put(0xB4, "LINK");
TYPE_MAP.put(0xEE, "DATA");

CATEGORY_MAP.put(0x5F, "PAGE_SEGMENT");
CATEGORY_MAP.put(0x6B, "OBJECT_AREA");
CATEGORY_MAP.put(0x77, "COLOR_ATTRIBUTE_TABLE");
CATEGORY_MAP.put(0x7B, "IM_IMAGE");
CATEGORY_MAP.put(0x88, "MEDIUM");
CATEGORY_MAP.put(0x8A, "CODED_FONT");
CATEGORY_MAP.put(0x90, "PROCESS_ELEMENT");
CATEGORY_MAP.put(0x92, "OBJECT_CONTAINER");
CATEGORY_MAP.put(0x9B, "PRESENTATION_TEXT");
CATEGORY_MAP.put(0xA7, "INDEX");
CATEGORY_MAP.put(0xA8, "DOCUMENT");
CATEGORY_MAP.put(0xAD, "PAGE_GROUP");
CATEGORY_MAP.put(0xAF, "PAGE");
CATEGORY_MAP.put(0xBB, "GRAPHICS");
CATEGORY_MAP.put(0xC3, "DATA_RESOURCE");
CATEGORY_MAP.put(0xC4, "DOCUMENT_ENVIRONMENT_GROUP");
CATEGORY_MAP.put(0xC6, "RESOURCE_GROUP");
CATEGORY_MAP.put(0xC7, "OBJECT_ENVIRONMENT_GROUP");
CATEGORY_MAP.put(0xC9, "ACTIVE_ENVIRONMENT_GROUP");
CATEGORY_MAP.put(0xCC, "MEDIUM_MAP");
CATEGORY_MAP.put(0xCD, "FORM_MAP");
CATEGORY_MAP.put(0xCE, "NAME_RESOURCE");
CATEGORY_MAP.put(0xD8, "PAGE_OVERLAY");
CATEGORY_MAP.put(0xD9, "RESOURCE_ENVIROMENT_GROUP");
CATEGORY_MAP.put(0xDF, "OVERLAY");
CATEGORY_MAP.put(0xEA, "DATA_SUPRESSION");
CATEGORY_MAP.put(0xEB, "BARCODE");
CATEGORY_MAP.put(0xEE, "NO_OPERATION");
CATEGORY_MAP.put(0xFB, "IMAGE");

TRIPLET_MAP.put(0x02, "FULLY_QUALIFIED_NAME");
TRIPLET_MAP.put(0x04, "MAPPING_OPTION");
TRIPLET_MAP.put(0x10, "OBJECT_CLASSIFICATION");
TRIPLET_MAP.put(0x18, "MODCA_INTERCHANGE_SET");
TRIPLET_MAP.put(0x1F, "FONT_DESCRIPTOR_SPECIFICATION");
TRIPLET_MAP.put(0x21, "OBJECT_FUNCTION_SET_SPECIFICATION");
TRIPLET_MAP.put(0x22, "EXTENDED_RESOURCE_LOCAL_IDENTIFIER");
TRIPLET_MAP.put(0x24, "RESOURCE_LOCAL_IDENTIFIER");
TRIPLET_MAP.put(0x25, "RESOURCE_SECTION_NUMBER");
TRIPLET_MAP.put(0x26, "CHARACTER_ROTATION");
TRIPLET_MAP.put(0x2D, "OBJECT_BYTE_OFFSET");
TRIPLET_MAP.put(0x36, "ATTRIBUTE_VALUE");
TRIPLET_MAP.put(0x43, "DESCRIPTOR_POSITION");
TRIPLET_MAP.put(0x45, "MEDIA_EJECT_CONTROL");
TRIPLET_MAP.put(0x46, "PAGE_OVERLAY_CONDITIONAL_PROCESSING");
TRIPLET_MAP.put(0x47, "RESOURCE_USAGE_ATTRIBUTE");
TRIPLET_MAP.put(0x4B, "MEASUREMENT_UNITS");
TRIPLET_MAP.put(0x4C, "OBJECT_AREA_SIZE");
TRIPLET_MAP.put(0x4D, "AREA_DEFINITION");
TRIPLET_MAP.put(0x4E, "COLOR_SPECIFICATION");
TRIPLET_MAP.put(0x50, "ENCODING_SCHEME_ID");
TRIPLET_MAP.put(0x56, "MEDIUM_MAP_PAGE_NUMBER");
TRIPLET_MAP.put(0x57, "OBJECT_BYTE_EXTENT");
TRIPLET_MAP.put(0x58, "OBJECT_STRUCTURED_FIELD_OFFSET");
TRIPLET_MAP.put(0x59, "OBJECT_STRUCTURED_FIELD_EXTENT");
TRIPLET_MAP.put(0x5A, "OBJECT_OFFSET");
TRIPLET_MAP.put(0x5D, "FONT_HORIZONTAL_SCALE_FACTOR");
TRIPLET_MAP.put(0x5E, "OBJECT_COUNT");
TRIPLET_MAP.put(0x62, "OBJECT_DATE_AND_TIMESTAMP");
TRIPLET_MAP.put(0x65, "COMMENT");
TRIPLET_MAP.put(0x68, "MEDIUM_ORIENTATION");
TRIPLET_MAP.put(0x6C, "RESOURCE_OBJECT_INCLUDE");
TRIPLET_MAP.put(0x70, "PRESENTATION_SPACE_RESET_MIXING");
TRIPLET_MAP.put(0x71, "PRESENTATION_SPACE_MIXING_RULE");
TRIPLET_MAP.put(0x72, "UNIVERSAL_DATE_AND_TIMESTAMP");
TRIPLET_MAP.put(0x74, "TONER_SAVER");
TRIPLET_MAP.put(0x75, "COLOR_FIDELITY");
TRIPLET_MAP.put(0x78, "FONT_FIDELITY");
TRIPLET_MAP.put(0x80, "ATTRIBUTE_QUALIFIER");
TRIPLET_MAP.put(0x81, "PAGE_POSITION_INFORMATION");
TRIPLET_MAP.put(0x82, "PARAMETER_VALUE");
TRIPLET_MAP.put(0x83, "PRESENTATION_CONTROL");
TRIPLET_MAP.put(0x84, "FONT_RESOLUTION_AND_METRIC_TECHNOLOGY");
TRIPLET_MAP.put(0x85, "FINISHING_OPERATION");
TRIPLET_MAP.put(0x86, "TEXT_FIDELITY");
TRIPLET_MAP.put(0x87, "MEDIA_FIDELITY");
TRIPLET_MAP.put(0x88, "FINISHING_FIDELITY");
TRIPLET_MAP.put(0x8B, "DATA_OBJECT_FONT_DESCRIPTOR");
TRIPLET_MAP.put(0x8C, "LOCALE_SELECTOR");
TRIPLET_MAP.put(0x8E, "UP3I_FINISHING_OPERATION");
TRIPLET_MAP.put(0x91, "COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR");
TRIPLET_MAP.put(0x95, "RENDERING_INTENT");
TRIPLET_MAP.put(0x96, "CMR_TAG_FIDELITY");
TRIPLET_MAP.put(0x97, "DEVICE_APPEARANCE");
}
}

+ 181
- 0
test/java/org/apache/fop/render/afp/AFPTrueTypeTestCase.java View File

@@ -0,0 +1,181 @@
/*
* 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.render.afp;

import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.junit.Test;

import org.xml.sax.SAXException;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.DataStream;
import org.apache.fop.afp.Factory;
import org.apache.fop.afp.fonts.FopCharacterSet;
import org.apache.fop.afp.modca.PageObject;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopConfParser;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FopFactoryBuilder;
import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.render.intermediate.IFException;

import junit.framework.Assert;

public class AFPTrueTypeTestCase {
@Test
public void testAFPTrueType() throws IOException, SAXException, TransformerException {
String fopxconf = "<fop version=\"1.0\">\n"
+ " <renderers>\n"
+ " <renderer mime=\"application/x-afp\">\n"
+ " <fonts>\n"
+ " <font name=\"Univers\" embed-url=\"test/resources/fonts/ttf/DejaVuLGCSerif.ttf\">\n"
+ " <font-triplet name=\"Univers\" style=\"normal\" weight=\"normal\"/>\n"
+ " <font-triplet name=\"any\" style=\"normal\" weight=\"normal\"/>\n"
+ " </font>\n"
+ " </fonts>\n"
+ " </renderer>\n"
+ " </renderers>\n"
+ "</fop>";
String fo = "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n"
+ " <fo:layout-master-set>\n"
+ " <fo:simple-page-master master-name=\"simple\">\n"
+ " <fo:region-body />\n"
+ " </fo:simple-page-master>\n"
+ " </fo:layout-master-set>\n"
+ " <fo:page-sequence master-reference=\"simple\">\n"
+ " <fo:flow flow-name=\"xsl-region-body\">\n"
+ " <fo:block font-family=\"Univers\">Univers</fo:block>\n"
+ " </fo:flow>\n"
+ " </fo:page-sequence>\n"
+ "</fo:root>";

FopFactoryBuilder confBuilder = new FopConfParser(
new ByteArrayInputStream(fopxconf.getBytes()), new File(".").toURI()).getFopFactoryBuilder();
FopFactory fopFactory = confBuilder.build();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Fop fop = fopFactory.newFop("application/x-afp", foUserAgent, bos);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
Source src = new StreamSource(new ByteArrayInputStream(fo.getBytes()));
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
bos.close();

StringBuilder sb = new StringBuilder();
InputStream bis = new ByteArrayInputStream(bos.toByteArray());
new AFPParser(false).read(bis, sb);

String format = "BEGIN RESOURCE_GROUP RG000001\n"
+ "BEGIN NAME_RESOURCE RES00001 Triplets: OBJECT_FUNCTION_SET_SPECIFICATION"
+ ",OBJECT_CLASSIFICATION,0x01,FULLY_QUALIFIED_NAME,\n"
+ "BEGIN OBJECT_CONTAINER OC000001 Triplets: 0x41,0x00,0x00,\n";
for (int i = 0; i < 29; i++) {
format += "DATA OBJECT_CONTAINER\n";
}
format += "END OBJECT_CONTAINER OC000001\n"
+ "END NAME_RESOURCE RES00001\n"
+ "END RESOURCE_GROUP RG000001\n"
+ "BEGIN DOCUMENT DOC00001\n"
+ "BEGIN PAGE_GROUP PGP00001\n"
+ "BEGIN PAGE PGN00001\n"
+ "BEGIN ACTIVE_ENVIRONMENT_GROUP AEG00001\n"
+ "MAP DATA_RESOURCE Triplets: 0x01,FULLY_QUALIFIED_NAME,FULLY_QUALIFIED_NAME"
+ ",OBJECT_CLASSIFICATION,DATA_OBJECT_FONT_DESCRIPTOR,\n"
+ "DESCRIPTOR PAGE\n"
+ "MIGRATION PRESENTATION_TEXT\n"
+ "END ACTIVE_ENVIRONMENT_GROUP AEG00001\n"
+ "BEGIN PRESENTATION_TEXT PT000001\n"
+ "DATA PRESENTATION_TEXT\n"
+ "END PRESENTATION_TEXT PT000001\n"
+ "END PAGE PGN00001\n"
+ "END PAGE_GROUP PGP00001\n"
+ "END DOCUMENT DOC00001\n";

Assert.assertEquals(sb.toString(), format);
}

@Test
public void testAFPPainter() throws IFException, IOException {
AFPDocumentHandler afpDocumentHandler = mock(AFPDocumentHandler.class);
when(afpDocumentHandler.getPaintingState()).thenReturn(new AFPPaintingState());
when(afpDocumentHandler.getResourceManager()).thenReturn(new AFPResourceManager(null));

DataStream ds = mock(DataStream.class);
when(afpDocumentHandler.getDataStream()).thenReturn(ds);
PageObject po = new PageObject(new Factory(), "PAGE0001", 0, 0, 0, 0, 0);
when(ds.getCurrentPage()).thenReturn(po);

AFPPainter afpPainter = new MyAFPPainter(afpDocumentHandler);
afpPainter.setFont("any", "normal", 400, null, null, Color.BLACK);
afpPainter.drawText(0, 0, 0, 0, null, "test");

ByteArrayOutputStream bos = new ByteArrayOutputStream();
po.writeToStream(bos);

InputStream bis = new ByteArrayInputStream(bos.toByteArray());
StringBuilder sb = new StringBuilder();
new AFPParser(true).read(bis, sb);
Assert.assertTrue(sb.toString(),
sb.toString().contains("DATA PRESENTATION_TEXT AMB AMI SCFL TRN t TRN e TRN s TRN t"));
}

class MyAFPPainter extends AFPPainter {
public MyAFPPainter(AFPDocumentHandler documentHandler) {
super(documentHandler);
}

protected FOUserAgent getUserAgent() {
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
return fopFactory.newFOUserAgent();
}

protected FontInfo getFontInfo() {
FontInfo f = new FontInfo();
f.addFontProperties("any", FontTriplet.DEFAULT_FONT_TRIPLET);
MultiByteFont font = new MultiByteFont(null, EmbeddingMode.AUTO);
font.setWidthArray(new int[100]);
f.addMetrics("any", new AFPFontConfig.AFPTrueTypeFont("", true,
new FopCharacterSet("", "UTF-16BE", "", font, null, null), null, null));
return f;
}
}
}

Loading…
Cancel
Save