From a11874283eb80e4ce5759196bb1a751e3c93e5ac Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Mon, 27 Jul 2009 16:33:01 +0000 Subject: [PATCH] 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. 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-ffa450edef68 --- build.xml | 3 +- .../content/xdocs/trunk/output.xml | 34 +++++++ .../org/apache/fop/afp/AFPEventProducer.java | 10 ++ .../org/apache/fop/afp/AFPEventProducer.xml | 1 + .../apache/fop/afp/AFPResourceManager.java | 54 +++++++++-- .../afp/fonts/AFPBase12FontCollection.java | 30 +++--- .../org/apache/fop/afp/fonts/AFPFont.java | 12 ++- .../afp/util/DefaultFOPResourceAccessor.java | 6 +- .../org/apache/fop/events/EventFormatter.xml | 3 - .../fop/render/afp/AFPDocumentHandler.java | 19 +++- .../org/apache/fop/render/afp/AFPPainter.java | 14 +-- .../apache/fop/render/afp/AFPRenderer.java | 42 ++++++++- .../render/afp/AFPRendererConfigurator.java | 17 +++- .../afp/extensions/AFPElementMapping.java | 12 +++ .../afp/extensions/AFPExtensionHandler.java | 60 +++++++----- .../afp/extensions/AFPIncludeFormMap.java | 87 +++++++++++++++++ .../extensions/AFPIncludeFormMapElement.java | 89 ++++++++++++++++++ .../afp/extensions/AFPPageSetupElement.java | 11 ++- status.xml | 9 ++ .../standard-testcases/afp-extension_1.xml | 17 +++- test/resources/afp/F1SAMPLE.afp | Bin 0 -> 834 bytes 21 files changed, 454 insertions(+), 76 deletions(-) create mode 100644 src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMap.java create mode 100644 src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMapElement.java create mode 100644 test/resources/afp/F1SAMPLE.afp diff --git a/build.xml b/build.xml index e9cc16a21..06e641005 100644 --- a/build.xml +++ b/build.xml @@ -355,12 +355,13 @@ list of possible build targets. + - + diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml index 135d56516..bae54d8b3 100644 --- a/src/documentation/content/xdocs/trunk/output.xml +++ b/src/documentation/content/xdocs/trunk/output.xml @@ -651,6 +651,11 @@ out = proc.getOutputStream();]]> ]]> +

+ By default, all manually configured fonts are embedded, unless they are matched in the + referenced-fonts section of the configuration file. + However, the default fonts shown above will not be embedded. +

Output Resolution @@ -836,6 +841,35 @@ out = proc.getOutputStream();]]> available on the target platform.

+
+ Form Maps/Defs +

+ Apache FOP supports embedding an external form map resource in the + generated AFP output. This is done using the afp:include-form-map + extension. An example: +

+ + [..] + + + +]]> +

+ The afp:include-form-map is to be placed as a direct child of + fo:declarations. The name is an AFP resource name + (max. 8 characters) and the src attribute is the URI identifying the + external form map resource. When such a form map is embedded, you can use the + afp:invoke-medium-map extension (described above) to invoke any medium + map included in the form map. +

+ + 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. + +
Foreign Attributes diff --git a/src/java/org/apache/fop/afp/AFPEventProducer.java b/src/java/org/apache/fop/afp/AFPEventProducer.java index 49792183f..b56250fc2 100644 --- a/src/java/org/apache/fop/afp/AFPEventProducer.java +++ b/src/java/org/apache/fop/afp/AFPEventProducer.java @@ -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); } diff --git a/src/java/org/apache/fop/afp/AFPEventProducer.xml b/src/java/org/apache/fop/afp/AFPEventProducer.xml index 8e6bb5429..364cd92ff 100644 --- a/src/java/org/apache/fop/afp/AFPEventProducer.xml +++ b/src/java/org/apache/fop/afp/AFPEventProducer.xml @@ -3,4 +3,5 @@ No AFP fonts configured. Using default setup. No AFP default "any", {style}, {weight} font configured. An error occurred when attempting to encode character set {charSetName} with encoding scheme {encoding}. + An error occurs while embedding the resource named "{resourceName}".[ Reason: {e}] diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java index 09ebde296..b7e1abc01 100644 --- a/src/java/org/apache/fop/afp/AFPResourceManager.java +++ b/src/java/org/apache/fop/afp/AFPResourceManager.java @@ -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); diff --git a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java index fd9b05304..417250df1 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java +++ b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java @@ -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; + } + } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFont.java b/src/java/org/apache/fop/afp/fonts/AFPFont.java index f56611087..a1c257d3e 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFont.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFont.java @@ -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} */ diff --git a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java index 97646542b..053db01af 100644 --- a/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java +++ b/src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java @@ -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()); diff --git a/src/java/org/apache/fop/events/EventFormatter.xml b/src/java/org/apache/fop/events/EventFormatter.xml index 07ac2111e..147744a0d 100644 --- a/src/java/org/apache/fop/events/EventFormatter.xml +++ b/src/java/org/apache/fop/events/EventFormatter.xml @@ -105,7 +105,4 @@ Any reference to it will be considered a reference to the first occurrence in th Font "{requested}" not found. Substituting with "{effective}". Unable to load font file: {fontURL}.[ Reason: {e}] Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}". - - - diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index febfb9672..d8a2d04e9 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -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); + } } } diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index e591812f9..7fcd0b3d1 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -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); } diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index b9eb345b7..e23cf7825 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -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(); diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index 95cc239b3..007dd3861 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -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/**/ tripletList = new java.util.ArrayList/**/(); 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 ' 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()) + } } } } diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMap.java b/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMap.java new file mode 100644 index 000000000..06c7cbc9d --- /dev/null +++ b/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMap.java @@ -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() + ")"; + } +} diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMapElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMapElement.java new file mode 100644 index 000000000..719d8c765 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/extensions/AFPIncludeFormMapElement.java @@ -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(); + } +} diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java index 0c6dfadc4..19f98f32a 100755 --- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java @@ -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); } } } diff --git a/status.xml b/status.xml index a26b7bc9e..1ce3a0471 100644 --- a/status.xml +++ b/status.xml @@ -58,6 +58,15 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + AFP Output: Added support for embedding external AFP form maps (form defs) using the + afp:include-form-map extension. + + + 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. + Bugfix: Error while writing TLE's attribute qualifier in the output. diff --git a/test/layoutengine/standard-testcases/afp-extension_1.xml b/test/layoutengine/standard-testcases/afp-extension_1.xml index 70bbef450..41659ab6d 100644 --- a/test/layoutengine/standard-testcases/afp-extension_1.xml +++ b/test/layoutengine/standard-testcases/afp-extension_1.xml @@ -36,8 +36,13 @@ + + + + + - + Text on page . @@ -47,6 +52,9 @@ + + + @@ -57,7 +65,7 @@ - + @@ -65,6 +73,9 @@ + + + @@ -74,7 +85,7 @@ - + diff --git a/test/resources/afp/F1SAMPLE.afp b/test/resources/afp/F1SAMPLE.afp new file mode 100644 index 0000000000000000000000000000000000000000..9dfd5b910503399f6344491a33459121e14cdcac GIT binary patch literal 834 zcmZ|ONlwEs6b9fwsgPPIp+JFB=6RlHRyl`PU2+u8!J;%05@!IF1rjWfl}0R)dI5$7 zNJ!x&&LeiC#v8|x-}{o^5y;ENGteWVNfXEmIP&HeC?LKBDzbhF^wLVLP*aP@T_D=v z(S|;Ol59KyMZXo?y}GU&mwEvD1&Xpx69*PTt~+4XEoJLE@`@S`(k2>F|7*G(vO)(h zc(dN|WqpS~sy`JUj{1Alznu10pppAW|ARdLpiu^m>7a@U8t(?GnxKgUWOsrl88nsl zSD