git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1694450 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_1
@@ -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 |
@@ -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); |
@@ -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 { |
@@ -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 |
@@ -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 */ |
@@ -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) |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
@@ -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 | |||
// ) | |||
// ); | |||
} |
@@ -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; | |||
} |
@@ -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); |
@@ -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; |
@@ -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); |
@@ -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"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |