Added support for embedding external AFP form maps (form defs) using the afp:include-form-map extension. Fixed a small problem with AFP-related events. DefaultFOPResourceAccessor got a fallback to the user agent's base URI if no category base URI is specified. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@798207 13f79535-47bb-0310-9956-ffa450edef68pull/37/head
@@ -355,12 +355,13 @@ list of possible build targets. | |||
<fileset dir="${src.java.dir}"> | |||
<include name="**/*.java"/> | |||
<exclude name="org/apache/fop/render/*/**/*.java"/> | |||
<exclude name="org/apache/fop/afp/**/*.java"/> | |||
</fileset> | |||
</eventResourceGenerator> | |||
<fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/> | |||
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/afp/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml"> | |||
<fileset dir="${src.java.dir}"> | |||
<include name="org/apache/fop/render/afp/**/*.java"/> | |||
<include name="org/apache/fop/afp/**/*.java"/> | |||
</fileset> | |||
</eventResourceGenerator> | |||
<fixcrlf file="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml" tab="remove" tablength="2"/> |
@@ -651,6 +651,11 @@ out = proc.getOutputStream();]]></source> | |||
<font-triplet name="monospace" style="normal" weight="bold"/> | |||
<font-triplet name="Courier" style="normal" weight="bold"/> | |||
</font>]]></source> | |||
<p> | |||
By default, all manually configured fonts are embedded, unless they are matched in the | |||
<a href="fonts.html#embedding"><code>referenced-fonts</code> section of the configuration file</a>. | |||
However, the default fonts shown above will not be embedded. | |||
</p> | |||
</section> | |||
<section id="afp-renderer-resolution-config"> | |||
<title>Output Resolution</title> | |||
@@ -836,6 +841,35 @@ out = proc.getOutputStream();]]></source> | |||
available on the target platform. | |||
</p> | |||
</section> | |||
<section id="afp-form-maps"> | |||
<title>Form Maps/Defs</title> | |||
<p> | |||
Apache FOP supports embedding an external form map resource in the | |||
generated AFP output. This is done using the <code>afp:include-form-map</code> | |||
extension. An example: | |||
</p> | |||
<source><![CDATA[ | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" | |||
xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp"> | |||
[..] | |||
<fo:declarations> | |||
<afp:include-form-map name="F1SAMP1" src="file:f1samp1.fde"/> | |||
</fo:declarations> | |||
]]></source> | |||
<p> | |||
The <code>afp:include-form-map</code> is to be placed as a direct child of | |||
<code>fo:declarations</code>. The <code>name</code> is an AFP resource name | |||
(max. 8 characters) and the <code>src</code> attribute is the URI identifying the | |||
external form map resource. When such a form map is embedded, you can use the | |||
<code>afp:invoke-medium-map</code> extension (described above) to invoke any medium | |||
map included in the form map. | |||
</p> | |||
<note> | |||
Apache FOP doesn't support a way to define a form map or medium map using XML means | |||
inside an XSL-FO document. You will have to build the form map with some third-party | |||
tool. | |||
</note> | |||
</section> | |||
</section> | |||
<section id="afp-foreign-attributes"> | |||
<title>Foreign Attributes</title> |
@@ -80,4 +80,14 @@ public interface AFPEventProducer extends EventProducer { | |||
* @event.severity ERROR | |||
*/ | |||
void characterSetEncodingError(Object source, String charSetName, String encoding); | |||
/** | |||
* Triggered when an external resource fails to be embedded. | |||
* | |||
* @param source the event source | |||
* @param resourceName the name of the resource where the error occurred | |||
* @param e the original exception | |||
* @event.severity ERROR | |||
*/ | |||
void resourceEmbeddingError(Object source, String resourceName, Exception e); | |||
} |
@@ -3,4 +3,5 @@ | |||
<message key="org.apache.fop.afp.AFPEventProducer.warnDefaultFontSetup">No AFP fonts configured. Using default setup.</message> | |||
<message key="org.apache.fop.afp.AFPEventProducer.warnMissingDefaultFont">No AFP default "any", {style}, {weight} font configured.</message> | |||
<message key="org.apache.fop.afp.AFPEventProducer.characterSetEncodingError">An error occurred when attempting to encode character set {charSetName} with encoding scheme {encoding}.</message> | |||
<message key="org.apache.fop.afp.AFPEventProducer.resourceEmbeddingError">An error occurs while embedding the resource named "{resourceName}".[ Reason: {e}]</message> | |||
</catalogue> |
@@ -28,6 +28,8 @@ import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
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.IncludeObject; | |||
@@ -169,7 +171,7 @@ public class AFPResourceManager { | |||
useInclude &= resourceGroup != null; | |||
if (useInclude) { | |||
boolean usePageSegment = dataObjectInfo.isCreatePageSegment(); | |||
// if it is to reside within a resource group at print-file or external level | |||
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) { | |||
if (usePageSegment) { | |||
@@ -179,14 +181,14 @@ public class AFPResourceManager { | |||
seg.addObject(namedObj); | |||
namedObj = seg; | |||
} | |||
// wrap newly created data object in a resource object | |||
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType); | |||
} | |||
// add data object into its resource group destination | |||
resourceGroup.addObject(namedObj); | |||
// create the include object | |||
objectName = namedObj.getName(); | |||
if (usePageSegment) { | |||
@@ -217,10 +219,32 @@ public class AFPResourceManager { | |||
private void includeObject(AFPDataObjectInfo dataObjectInfo, | |||
String objectName) { | |||
IncludeObject includeObject | |||
= dataObjectFactory.createInclude(objectName, dataObjectInfo); | |||
dataStream.getCurrentPage().addObject(includeObject); | |||
IncludeObject includeObject | |||
= dataObjectFactory.createInclude(objectName, dataObjectInfo); | |||
dataStream.getCurrentPage().addObject(includeObject); | |||
} | |||
/** | |||
* Handles font embedding. If a font is embeddable and has not already been embedded it will be. | |||
* @param afpFont the AFP font to be checked for embedding | |||
* @param charSet the associated character set | |||
* @throws IOException if there's a problem while embedding the external resources | |||
*/ | |||
public void embedFont(AFPFont afpFont, CharacterSet charSet) | |||
throws IOException { | |||
if (afpFont.isEmbeddable()) { | |||
//Embed fonts (char sets and code pages) | |||
if (charSet.getResourceAccessor() != null) { | |||
ResourceAccessor accessor = charSet.getResourceAccessor(); | |||
createIncludedResource( | |||
charSet.getName(), accessor, | |||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||
createIncludedResource( | |||
charSet.getCodePage(), accessor, | |||
ResourceObject.TYPE_CODE_PAGE); | |||
} | |||
} | |||
} | |||
private void includePageSegment(AFPDataObjectInfo dataObjectInfo, | |||
String pageSegmentName) { | |||
@@ -240,7 +264,6 @@ public class AFPResourceManager { | |||
*/ | |||
public void createIncludedResource(String resourceName, ResourceAccessor accessor, | |||
byte resourceObjectType) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
URI uri; | |||
try { | |||
uri = new URI(resourceName.trim()); | |||
@@ -249,6 +272,21 @@ public class AFPResourceManager { | |||
+ " (" + e.getMessage() + ")"); | |||
} | |||
createIncludedResource(resourceName, uri, accessor, resourceObjectType); | |||
} | |||
/** | |||
* Creates an included resource object by loading the contained object from a file. | |||
* @param resourceName the name of the resource | |||
* @param uri the URI for the resource | |||
* @param accessor resource accessor to access the resource with | |||
* @param resourceObjectType the resource object type ({@link ResourceObject}.*) | |||
* @throws IOException if an I/O error occurs while loading the resource | |||
*/ | |||
public void createIncludedResource(String resourceName, URI uri, ResourceAccessor accessor, | |||
byte resourceObjectType) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | |||
resourceInfo.setLevel(resourceLevel); | |||
resourceInfo.setName(resourceName); |
@@ -80,22 +80,22 @@ public class AFPBase12FontCollection implements FontCollection { | |||
/** standard font family reference names for Helvetica font */ | |||
final String[] helveticaNames = {"Helvetica", "Arial", "sans-serif"}; | |||
font = new RasterFont("Helvetica"); | |||
font = createReferencedRasterFont("Helvetica"); | |||
addCharacterSet(font, "C0H200", new Helvetica()); | |||
num = addFontProperties(fontInfo, font, helveticaNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Helvetica Italic"); | |||
font = createReferencedRasterFont("Helvetica Italic"); | |||
addCharacterSet(font, "C0H300", new HelveticaOblique()); | |||
num = addFontProperties(fontInfo, font, helveticaNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Helvetica (Semi) Bold"); | |||
font = createReferencedRasterFont("Helvetica (Semi) Bold"); | |||
addCharacterSet(font, "C0H400", new HelveticaBold()); | |||
num = addFontProperties(fontInfo, font, helveticaNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); | |||
font = new RasterFont("Helvetica Italic (Semi) Bold"); | |||
font = createReferencedRasterFont("Helvetica Italic (Semi) Bold"); | |||
addCharacterSet(font, "C0H500", new HelveticaOblique()); | |||
num = addFontProperties(fontInfo, font, helveticaNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); | |||
@@ -107,22 +107,22 @@ public class AFPBase12FontCollection implements FontCollection { | |||
final String[] timesNames = {"Times", "TimesRoman", "Times Roman", "Times-Roman", | |||
"Times New Roman", "TimesNewRoman", "serif", "any"}; | |||
font = new RasterFont("Times Roman"); | |||
font = createReferencedRasterFont("Times Roman"); | |||
addCharacterSet(font, "CON200", new TimesRoman()); | |||
num = addFontProperties(fontInfo, font, timesNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Times Roman Italic"); | |||
font = createReferencedRasterFont("Times Roman Italic"); | |||
addCharacterSet(font, "CON300", new TimesItalic()); | |||
num = addFontProperties(fontInfo, font, timesNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Times Roman Bold"); | |||
font = createReferencedRasterFont("Times Roman Bold"); | |||
addCharacterSet(font, "CON400", new TimesBold()); | |||
num = addFontProperties(fontInfo, font, timesNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); | |||
font = new RasterFont("Times Roman Italic Bold"); | |||
font = createReferencedRasterFont("Times Roman Italic Bold"); | |||
addCharacterSet(font, "CON500", new TimesBoldItalic()); | |||
num = addFontProperties(fontInfo, font, timesNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); | |||
@@ -131,22 +131,22 @@ public class AFPBase12FontCollection implements FontCollection { | |||
/** standard font family reference names for Courier font */ | |||
final String[] courierNames = {"Courier", "monospace"}; | |||
font = new RasterFont("Courier"); | |||
font = createReferencedRasterFont("Courier"); | |||
addCharacterSet(font, "C04200", new Courier()); | |||
num = addFontProperties(fontInfo, font, courierNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Courier Italic"); | |||
font = createReferencedRasterFont("Courier Italic"); | |||
addCharacterSet(font, "C04300", new CourierOblique()); | |||
num = addFontProperties(fontInfo, font, courierNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); | |||
font = new RasterFont("Courier Bold"); | |||
font = createReferencedRasterFont("Courier Bold"); | |||
addCharacterSet(font, "C04400", new CourierBold()); | |||
num = addFontProperties(fontInfo, font, courierNames, | |||
Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); | |||
font = new RasterFont("Courier Italic Bold"); | |||
font = createReferencedRasterFont("Courier Italic Bold"); | |||
addCharacterSet(font, "C04500", new CourierBoldOblique()); | |||
num = addFontProperties(fontInfo, font, courierNames, | |||
Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); | |||
@@ -154,4 +154,10 @@ public class AFPBase12FontCollection implements FontCollection { | |||
return num; | |||
} | |||
private RasterFont createReferencedRasterFont(String fontFamily) { | |||
RasterFont font = new RasterFont(fontFamily); | |||
font.setEmbeddable(false); //Font is assumed to be available on the target platform | |||
return font; | |||
} | |||
} |
@@ -36,6 +36,8 @@ public abstract class AFPFont extends Typeface { | |||
/** The font name */ | |||
protected String name; | |||
private boolean embeddable = true; | |||
/** | |||
* Constructor for the base font requires the name. | |||
* @param name the name of the font | |||
@@ -97,12 +99,20 @@ public abstract class AFPFont extends Typeface { | |||
*/ | |||
public abstract CharacterSet getCharacterSet(int size); | |||
/** | |||
* Controls whether this font is embeddable or not. | |||
* @param value true to enable embedding, false otherwise. | |||
*/ | |||
public void setEmbeddable(boolean value) { | |||
this.embeddable = value; | |||
} | |||
/** | |||
* Indicates if this font may be embedded. | |||
* @return True, if embedding is possible/permitted | |||
*/ | |||
public boolean isEmbeddable() { | |||
return false; //TODO Complete AFP font embedding | |||
return this.embeddable; | |||
} | |||
/** {@inheritDoc} */ |
@@ -63,8 +63,10 @@ public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { | |||
URI resolved = resolveAgainstBase(uri); | |||
//Step 2: resolve against the user agent --> stream | |||
Source src; | |||
src = userAgent.resolveURI(resolved.toASCIIString(), this.categoryBaseURI); | |||
String base = (this.categoryBaseURI != null | |||
? this.categoryBaseURI | |||
: this.userAgent.getBaseURL()); | |||
Source src = userAgent.resolveURI(resolved.toASCIIString(), base); | |||
if (src == null) { | |||
throw new FileNotFoundException("Resource not found: " + uri.toASCIIString()); |
@@ -105,7 +105,4 @@ Any reference to it will be considered a reference to the first occurrence in th | |||
<message key="org.apache.fop.fonts.FontEventAdapter.fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message> | |||
<message key="org.apache.fop.fonts.FontEventAdapter.fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message> | |||
<message key="org.apache.fop.fonts.FontEventAdapter.glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message> | |||
<message key="org.apache.fop.afp.AFPEventProducer.warnDefaultFontSetup"/> | |||
<message key="org.apache.fop.afp.AFPEventProducer.warnMissingDefaultFont"/> | |||
<message key="org.apache.fop.afp.AFPEventProducer.characterSetEncodingError"/> | |||
</catalogue> |
@@ -35,12 +35,16 @@ import org.apache.fop.afp.AbstractAFPPainter; | |||
import org.apache.fop.afp.DataStream; | |||
import org.apache.fop.afp.fonts.AFPFontCollection; | |||
import org.apache.fop.afp.fonts.AFPPageFonts; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.util.DefaultFOPResourceAccessor; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.fop.render.afp.extensions.AFPIncludeFormMap; | |||
import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; | |||
import org.apache.fop.render.afp.extensions.AFPPageSetup; | |||
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; | |||
@@ -275,7 +279,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
} else { | |||
if (this.location != LOC_IN_PAGE_HEADER) { | |||
throw new IFException( | |||
"AFP page setup extension encountered outside the page header: " + aps, null); | |||
"AFP page setup extension encountered outside the page header: " + aps, | |||
null); | |||
} | |||
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) { | |||
String overlay = aps.getName(); | |||
@@ -304,6 +309,18 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
if (mediumMap != null) { | |||
dataStream.createInvokeMediumMap(mediumMap); | |||
} | |||
} else if (extension instanceof AFPIncludeFormMap) { | |||
AFPIncludeFormMap formMap = (AFPIncludeFormMap)extension; | |||
ResourceAccessor accessor = new DefaultFOPResourceAccessor( | |||
getUserAgent(), null, null); | |||
try { | |||
getResourceManager().createIncludedResource(formMap.getName(), | |||
formMap.getSrc(), accessor, | |||
ResourceObject.TYPE_FORMDEF); | |||
} catch (IOException ioe) { | |||
throw new IFException( | |||
"I/O error while embedding form map resource: " + formMap.getName(), ioe); | |||
} | |||
} | |||
} | |||
@@ -46,10 +46,8 @@ import org.apache.fop.afp.fonts.AFPPageFonts; | |||
import org.apache.fop.afp.fonts.CharacterSet; | |||
import org.apache.fop.afp.modca.AbstractPageObject; | |||
import org.apache.fop.afp.modca.PresentationTextObject; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.ptoca.PtocaBuilder; | |||
import org.apache.fop.afp.ptoca.PtocaProducer; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.fonts.Font; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontTriplet; | |||
@@ -345,17 +343,7 @@ public class AFPPainter extends AbstractIFPainter { | |||
if (afpFont.isEmbeddable()) { | |||
try { | |||
//Embed fonts (char sets and code pages) | |||
//TODO This should be moved to a place where it has less performance impact | |||
if (charSet.getResourceAccessor() != null) { | |||
ResourceAccessor accessor = charSet.getResourceAccessor(); | |||
documentHandler.getResourceManager().createIncludedResource( | |||
charSet.getName(), accessor, | |||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||
documentHandler.getResourceManager().createIncludedResource( | |||
charSet.getCodePage(), accessor, | |||
ResourceObject.TYPE_CODE_PAGE); | |||
} | |||
documentHandler.getResourceManager().embedFont(afpFont, charSet); | |||
} catch (IOException ioe) { | |||
throw new IFException("Error while embedding font resources", ioe); | |||
} |
@@ -61,10 +61,14 @@ import org.apache.fop.afp.fonts.AFPFontCollection; | |||
import org.apache.fop.afp.fonts.AFPPageFonts; | |||
import org.apache.fop.afp.fonts.CharacterSet; | |||
import org.apache.fop.afp.modca.PageObject; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.util.DefaultFOPResourceAccessor; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.CTM; | |||
import org.apache.fop.area.OffDocumentExtensionAttachment; | |||
import org.apache.fop.area.OffDocumentItem; | |||
import org.apache.fop.area.PageSequence; | |||
import org.apache.fop.area.PageViewport; | |||
@@ -83,6 +87,8 @@ import org.apache.fop.render.AbstractPathOrientedRenderer; | |||
import org.apache.fop.render.Graphics2DAdapter; | |||
import org.apache.fop.render.RendererContext; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.fop.render.afp.extensions.AFPExtensionAttachment; | |||
import org.apache.fop.render.afp.extensions.AFPIncludeFormMap; | |||
import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; | |||
import org.apache.fop.render.afp.extensions.AFPPageSetup; | |||
@@ -279,8 +285,30 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust | |||
/** {@inheritDoc} */ | |||
public void processOffDocumentItem(OffDocumentItem odi) { | |||
// TODO | |||
log.debug("NYI processOffDocumentItem(" + odi + ")"); | |||
if (odi instanceof OffDocumentExtensionAttachment) { | |||
ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)odi).getAttachment(); | |||
if (attachment != null) { | |||
if (AFPExtensionAttachment.CATEGORY.equals(attachment.getCategory())) { | |||
if (attachment instanceof AFPIncludeFormMap) { | |||
handleIncludeFormMap((AFPIncludeFormMap)attachment); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
private void handleIncludeFormMap(AFPIncludeFormMap formMap) { | |||
ResourceAccessor accessor = new DefaultFOPResourceAccessor( | |||
getUserAgent(), null, null); | |||
try { | |||
this.resourceManager.createIncludedResource(formMap.getName(), | |||
formMap.getSrc(), accessor, | |||
ResourceObject.TYPE_FORMDEF); | |||
} catch (IOException ioe) { | |||
AFPEventProducer eventProducer | |||
= AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); | |||
eventProducer.resourceEmbeddingError(this, formMap.getName(), ioe); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -566,6 +594,16 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust | |||
AFPFontAttributes fontAttributes = pageFonts.registerFont(internalFontName, font, fontSize); | |||
Font fnt = getFontFromArea(text); | |||
if (font.isEmbeddable()) { | |||
CharacterSet charSet = font.getCharacterSet(fontSize); | |||
try { | |||
this.resourceManager.embedFont(font, charSet); | |||
} catch (IOException ioe) { | |||
AFPEventProducer eventProducer | |||
= AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); | |||
eventProducer.resourceEmbeddingError(this, charSet.getName(), ioe); | |||
} | |||
} | |||
// create text data info | |||
AFPTextDataInfo textDataInfo = new AFPTextDataInfo(); |
@@ -68,8 +68,12 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
} | |||
private AFPFontInfo buildFont(Configuration fontCfg, String fontPath) | |||
throws ConfigurationException { | |||
throws ConfigurationException { | |||
FontManager fontManager = this.userAgent.getFactory().getFontManager(); | |||
FontTriplet.Matcher referencedFontsMatcher = fontManager.getReferencedFontsMatcher(); | |||
boolean embeddable = true; | |||
Configuration[] triple = fontCfg.getChildren("font-triplet"); | |||
List/*<FontTriplet>*/ tripletList = new java.util.ArrayList/*<FontTriplet>*/(); | |||
if (triple.length == 0) { | |||
@@ -81,6 +85,9 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
FontTriplet triplet = new FontTriplet(triple[j].getAttribute("name"), | |||
triple[j].getAttribute("style"), | |||
weight); | |||
if (referencedFontsMatcher != null && referencedFontsMatcher.matches(triplet)) { | |||
embeddable = false; | |||
} | |||
tripletList.add(triplet); | |||
} | |||
@@ -110,7 +117,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
} | |||
ResourceAccessor accessor = new DefaultFOPResourceAccessor( | |||
this.userAgent, | |||
this.userAgent.getFactory().getFontManager().getFontBaseURL(), | |||
fontManager.getFontBaseURL(), | |||
baseURI); | |||
String type = afpFontCfg.getAttribute("type"); | |||
@@ -135,11 +142,12 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
// Create a new font object | |||
RasterFont font = new RasterFont(name); | |||
font.setEmbeddable(embeddable); | |||
Configuration[] rasters = afpFontCfg.getChildren("afp-raster-font"); | |||
if (rasters.length == 0) { | |||
log.error( | |||
"Mandatory font configuration elements '<afp-raster-font...' are missing"); | |||
log.error("Mandatory font configuration elements '<afp-raster-font...'" | |||
+ " are missing at " + afpFontCfg.getLocation()); | |||
return null; | |||
} | |||
for (int j = 0; j < rasters.length; j++) { | |||
@@ -212,6 +220,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
} | |||
// Create a new font object | |||
OutlineFont font = new OutlineFont(name, characterSet); | |||
font.setEmbeddable(embeddable); | |||
return new AFPFontInfo(font, tripletList); | |||
} else { | |||
log.error("No or incorrect type attribute"); |
@@ -42,6 +42,9 @@ public class AFPElementMapping extends ElementMapping { | |||
/** include page segment element */ | |||
public static final String INCLUDE_PAGE_SEGMENT = "include-page-segment"; | |||
/** include form map element */ | |||
public static final String INCLUDE_FORM_MAP = "include-form-map"; | |||
/** NOP */ | |||
public static final String NO_OPERATION = "no-operation"; | |||
@@ -80,6 +83,9 @@ public class AFPElementMapping extends ElementMapping { | |||
foObjs.put( | |||
INCLUDE_PAGE_OVERLAY, | |||
new AFPIncludePageOverlayMaker()); | |||
foObjs.put( | |||
INCLUDE_FORM_MAP, | |||
new AFPIncludeFormMapMaker()); | |||
foObjs.put( | |||
NO_OPERATION, | |||
new AFPNoOperationMaker()); | |||
@@ -101,6 +107,12 @@ public class AFPElementMapping extends ElementMapping { | |||
} | |||
} | |||
static class AFPIncludeFormMapMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPIncludeFormMapElement(parent, INCLUDE_FORM_MAP); | |||
} | |||
} | |||
static class AFPTagLogicalElementMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPPageSetupElement(parent, TAG_LOGICAL_ELEMENT); |
@@ -19,6 +19,9 @@ | |||
package org.apache.fop.render.afp.extensions; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
@@ -48,13 +51,14 @@ public class AFPExtensionHandler extends DefaultHandler | |||
public void startElement(String uri, String localName, String qName, Attributes attributes) | |||
throws SAXException { | |||
boolean handled = false; | |||
if (AFPPageSetup.CATEGORY.equals(uri)) { | |||
if (AFPExtensionAttachment.CATEGORY.equals(uri)) { | |||
lastAttributes = attributes; | |||
handled = true; | |||
if (localName.equals(AFPElementMapping.NO_OPERATION) | |||
|| localName.equals(AFPElementMapping.TAG_LOGICAL_ELEMENT) | |||
|| localName.equals(AFPElementMapping.INCLUDE_PAGE_OVERLAY) | |||
|| localName.equals(AFPElementMapping.INCLUDE_PAGE_SEGMENT) | |||
|| localName.equals(AFPElementMapping.INCLUDE_FORM_MAP) | |||
|| localName.equals(AFPElementMapping.INVOKE_MEDIUM_MAP)) { | |||
//handled in endElement | |||
} else { | |||
@@ -62,7 +66,7 @@ public class AFPExtensionHandler extends DefaultHandler | |||
} | |||
} | |||
if (!handled) { | |||
if (AFPPageSetup.CATEGORY.equals(uri)) { | |||
if (AFPExtensionAttachment.CATEGORY.equals(uri)) { | |||
throw new SAXException("Unhandled element " + localName | |||
+ " in namespace: " + uri); | |||
} else { | |||
@@ -74,26 +78,38 @@ public class AFPExtensionHandler extends DefaultHandler | |||
/** {@inheritDoc} */ | |||
public void endElement(String uri, String localName, String qName) throws SAXException { | |||
if (AFPPageSetup.CATEGORY.equals(uri)) { | |||
AFPPageSetup pageSetupExtn = null; | |||
if (localName.equals(AFPElementMapping.INVOKE_MEDIUM_MAP)) { | |||
this.returnedObject = new AFPInvokeMediumMap(); | |||
} | |||
else { | |||
pageSetupExtn = new AFPPageSetup(localName); | |||
this.returnedObject = pageSetupExtn; | |||
} | |||
String name = lastAttributes.getValue("name"); | |||
if (name != null) { | |||
returnedObject.setName(name); | |||
} | |||
String value = lastAttributes.getValue("value"); | |||
if (value != null && pageSetupExtn != null) { | |||
pageSetupExtn.setValue(value); | |||
} | |||
if (content.length() > 0 && pageSetupExtn != null) { | |||
pageSetupExtn.setContent(content.toString()); | |||
content.setLength(0); //Reset text buffer (see characters()) | |||
if (AFPExtensionAttachment.CATEGORY.equals(uri)) { | |||
if (AFPElementMapping.INCLUDE_FORM_MAP.equals(localName)) { | |||
AFPIncludeFormMap formMap = new AFPIncludeFormMap(); | |||
String name = lastAttributes.getValue("name"); | |||
formMap.setName(name); | |||
String src = lastAttributes.getValue("src"); | |||
try { | |||
formMap.setSrc(new URI(src)); | |||
} catch (URISyntaxException e) { | |||
throw new SAXException("Invalid URI: " + src, e); | |||
} | |||
this.returnedObject = formMap; | |||
} else { | |||
AFPPageSetup pageSetupExtn = null; | |||
if (AFPElementMapping.INVOKE_MEDIUM_MAP.equals(localName)) { | |||
this.returnedObject = new AFPInvokeMediumMap(); | |||
} else { | |||
pageSetupExtn = new AFPPageSetup(localName); | |||
this.returnedObject = pageSetupExtn; | |||
} | |||
String name = lastAttributes.getValue("name"); | |||
if (name != null) { | |||
returnedObject.setName(name); | |||
} | |||
String value = lastAttributes.getValue("value"); | |||
if (value != null && pageSetupExtn != null) { | |||
pageSetupExtn.setValue(value); | |||
} | |||
if (content.length() > 0 && pageSetupExtn != null) { | |||
pageSetupExtn.setContent(content.toString()); | |||
content.setLength(0); //Reset text buffer (see characters()) | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,87 @@ | |||
/* | |||
* 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.extensions; | |||
import java.net.URI; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
/** | |||
* This extension allows to include an AFP form map resource. It is implemented as an extension | |||
* attachment ({@link ExtensionAttachment}). | |||
*/ | |||
public class AFPIncludeFormMap extends AFPExtensionAttachment { | |||
private static final long serialVersionUID = 8548056652642588914L; | |||
/** src attribute containing the URI to the form map resource */ | |||
protected static final String ATT_SRC = "src"; | |||
/** | |||
* the URI identifying the form map resource. | |||
*/ | |||
protected URI src; | |||
/** | |||
* Default constructor. | |||
*/ | |||
public AFPIncludeFormMap() { | |||
super(AFPElementMapping.INCLUDE_FORM_MAP); | |||
} | |||
/** | |||
* Returns the URI of the form map. | |||
* @return the form map URI | |||
*/ | |||
public URI getSrc() { | |||
return this.src; | |||
} | |||
/** | |||
* Sets the URI of the form map. | |||
* @param value the form map URI | |||
*/ | |||
public void setSrc(URI value) { | |||
this.src = value; | |||
} | |||
/** {@inheritDoc} */ | |||
public void toSAX(ContentHandler handler) throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
if (name != null && name.length() > 0) { | |||
atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); | |||
} | |||
if (this.src != null) { | |||
atts.addAttribute(null, ATT_SRC, ATT_SRC, "CDATA", this.src.toASCIIString()); | |||
} | |||
handler.startElement(CATEGORY, elementName, elementName, atts); | |||
handler.endElement(CATEGORY, elementName, elementName); | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return getClass().getName() + "(element-name=" + getElementName() | |||
+ " name=" + getName() + " src=" + getSrc() + ")"; | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* 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.extensions; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.Locator; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.PropertyList; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
import org.apache.fop.fo.extensions.ExtensionObj; | |||
/** | |||
* This class extends the {@link ExtensionObj} class. It represents the "include-form-map" | |||
* extension in the FO tree. | |||
*/ | |||
public class AFPIncludeFormMapElement extends AbstractAFPExtensionObject { | |||
private static final String ATT_SRC = "src"; | |||
/** | |||
* Constructs an AFP object (called by Maker). | |||
* | |||
* @param parent the parent formatting object | |||
* @param name the name of the AFP element | |||
*/ | |||
public AFPIncludeFormMapElement(FONode parent, String name) { | |||
super(parent, name); | |||
} | |||
private AFPIncludeFormMap getFormMapAttachment() { | |||
return (AFPIncludeFormMap)getExtensionAttachment(); | |||
} | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
super.startOfNode(); | |||
if (parent.getNameId() != Constants.FO_DECLARATIONS) { | |||
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), | |||
"rule.childOfDeclarations"); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void processNode(String elementName, Locator locator, | |||
Attributes attlist, PropertyList propertyList) | |||
throws FOPException { | |||
super.processNode(elementName, locator, attlist, propertyList); | |||
AFPIncludeFormMap formMap = getFormMapAttachment(); | |||
String attr = attlist.getValue(ATT_SRC); | |||
if (attr != null && attr.length() > 0) { | |||
try { | |||
formMap.setSrc(new URI(attr)); | |||
} catch (URISyntaxException e) { | |||
getFOValidationEventProducer().invalidPropertyValue(this, | |||
elementName, ATT_SRC, attr, null, getLocator()); | |||
} | |||
} else { | |||
missingPropertyError(ATT_SRC); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
protected ExtensionAttachment instantiateExtensionAttachment() { | |||
return new AFPIncludeFormMap(); | |||
} | |||
} |
@@ -36,6 +36,9 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
*/ | |||
public class AFPPageSetupElement extends AbstractAFPExtensionObject { | |||
private static final String ATT_VALUE = "value"; | |||
private static final String ATT_SRC = "src"; | |||
/** | |||
* Constructs an AFP object (called by Maker). | |||
* | |||
@@ -86,18 +89,18 @@ public class AFPPageSetupElement extends AbstractAFPExtensionObject { | |||
super.processNode(elementName, locator, attlist, propertyList); | |||
AFPPageSetup pageSetup = getPageSetupAttachment(); | |||
if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(elementName)) { | |||
String attr = attlist.getValue("src"); | |||
String attr = attlist.getValue(ATT_SRC); | |||
if (attr != null && attr.length() > 0) { | |||
pageSetup.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a src attribute."); | |||
missingPropertyError(ATT_SRC); | |||
} | |||
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(elementName)) { | |||
String attr = attlist.getValue("value"); | |||
String attr = attlist.getValue(ATT_VALUE); | |||
if (attr != null && attr.length() > 0) { | |||
pageSetup.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a value attribute."); | |||
missingPropertyError(ATT_VALUE); | |||
} | |||
} | |||
} |
@@ -58,6 +58,15 @@ | |||
documents. Example: the fix of marks layering will be such a case when it's done. | |||
--> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Renderers" dev="JM" type="add"> | |||
AFP Output: Added support for embedding external AFP form maps (form defs) using the | |||
afp:include-form-map extension. | |||
</action> | |||
<action context="Renderers" dev="JM" type="add"> | |||
AFP Output: Added support for AFP font embedding. Note: this changes the default behaviour. | |||
Like with PDF and PS, all fonts are embedded by default unless matched in the | |||
"referenced-fonts" section in the configuration. | |||
</action> | |||
<action context="Renderers" dev="AD" type="fix" fixes-bug="47508" due-to="Bharat Attaluri"> | |||
Bugfix: Error while writing TLE's attribute qualifier in the output. | |||
</action> |
@@ -36,8 +36,13 @@ | |||
<fo:region-body/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
<fo:declarations> | |||
<afp:include-form-map name="FORMMAP1" src="file:../../resources/afp/F1SAMPLE.afp"/> | |||
</fo:declarations> | |||
<fo:page-sequence master-reference="normal" fox:test-ignore="this"> | |||
<afp:invoke-medium-map name="MYMAP"/> | |||
<afp:invoke-medium-map name="NOPAR"/> | |||
<afp:tag-logical-element name="foo" value="bar"/> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block>Text on page <fo:page-number/>.</fo:block> | |||
@@ -47,6 +52,9 @@ | |||
</fo:root> | |||
</fo> | |||
<checks xmlns:afp="apache:fop:extensions:afp"> | |||
<eval expected="FORMMAP1" xpath="/areaTree/extension-attachments/afp:include-form-map/@name"/> | |||
<eval expected="file:../../resources/afp/F1SAMPLE.afp" xpath="/areaTree/extension-attachments/afp:include-form-map/@src"/> | |||
<eval expected="4" xpath="count(/areaTree/pageSequence/pageViewport[@nr=1]/page/extension-attachments/child::*)"/> | |||
<eval expected="O1SAMP1 " xpath="/areaTree/pageSequence/pageViewport[@nr=1]/page/extension-attachments/child::*[1]/@name"/> | |||
<eval expected="S1ISLOGO" xpath="/areaTree/pageSequence/pageViewport[@nr=1]/page/extension-attachments/child::*[2]/@name"/> | |||
@@ -57,7 +65,7 @@ | |||
<eval expected="4" xpath="count(/areaTree/pageSequence/pageViewport[@nr=2]/page/extension-attachments/child::*)"/> | |||
<eval expected="2" xpath="count(/areaTree/pageSequence/extension-attachments/child::*)"/> | |||
<eval expected="MYMAP" xpath="/areaTree/pageSequence/extension-attachments/child::*[1]/@name"/> | |||
<eval expected="NOPAR" xpath="/areaTree/pageSequence/extension-attachments/child::*[1]/@name"/> | |||
<eval expected="bar" xpath="/areaTree/pageSequence/extension-attachments/afp:tag-logical-element[@name = 'foo']/@value"/> | |||
<!-- This just tests if extension attributes make it through to the PageSequence object. --> | |||
@@ -65,6 +73,9 @@ | |||
</checks> | |||
<if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate" | |||
xmlns:afp="apache:fop:extensions:afp"> | |||
<eval expected="FORMMAP1" xpath="/if:document/if:header/afp:include-form-map/@name"/> | |||
<eval expected="file:../../resources/afp/F1SAMPLE.afp" xpath="/if:document/if:header/afp:include-form-map/@src"/> | |||
<eval expected="4" xpath="count(//if:page[@name = '1']/if:page-header/child::*)"/> | |||
<eval expected="O1SAMP1 " xpath="//if:page[@name = '1']/if:page-header/afp:include-page-overlay[1]/@name"/> | |||
<eval expected="S1ISLOGO" xpath="//if:page[@name = '1']/if:page-header/afp:include-page-segment[1]/@name"/> | |||
@@ -74,7 +85,7 @@ | |||
<eval expected="4" xpath="count(//if:page[@name = '2']/if:page-header/child::*)"/> | |||
<eval expected="MYMAP" xpath="//if:page-sequence/afp:invoke-medium-map/@name"/> | |||
<eval expected="NOPAR" xpath="//if:page-sequence/afp:invoke-medium-map/@name"/> | |||
<eval expected="bar" xpath="//if:page-sequence/afp:tag-logical-element[@name = 'foo']/@value"/> | |||
<!-- This just tests if extension attributes make it through to the PageSequence object. --> |