Bladeren bron

Bugzilla #49379:

Added ability to embed an external AFP page segment resource file (AFP output only).
Submitted by: Peter Hancock <peter.hancock.at.gmail.com>

Changes to patch:
- Replaced AFP parsing code with a more universal MO:DCA parser (as discussed).
- AFPDocumentHandler: addressed a TODO (clearing of the page segment map was not necessary for each page)
- AFPDocumentHandler: merged pageSegmentMap and pageSegmentUriMap by creating a combined object: PageSegmentDescriptor

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1005350 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Jeremias Maerki 13 jaren geleden
bovenliggende
commit
eff5b9fd40

+ 7
- 0
src/documentation/content/xdocs/trunk/output.xml Bestand weergeven

@@ -885,6 +885,13 @@ Note that the value of the encoding attribute in the example is the double-byte
segment in the generated file. Please also note that page segments cannot be scaled.
They are always rendered in their intrinsic size.
</p>
<p>
The include-page-segment extension element has the optional attribute
<i>resource-file</i>. The value of this is a URI to a resource containing a page
segment with the declared name. In this case FOP embeds the page segment into the
generated document so that the external resource does not have to be supplied in the
print job.
</p>
</section>
<section id="afp-tag-logical-element">
<title>Tag Logical Element (TLE) Extension</title>

+ 55
- 0
src/java/org/apache/fop/afp/AFPResourceManager.java Bestand weergeven

@@ -19,12 +19,15 @@

package org.apache.fop.afp;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@@ -38,6 +41,7 @@ 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.util.AFPResourceUtil;
import org.apache.fop.afp.util.ResourceAccessor;

/**
@@ -313,6 +317,57 @@ public class AFPResourceManager {
}
}

/**
* Creates an included resource extracting the named resource from an external source.
* @param resourceName the name of the resource
* @param uri the URI for the resource
* @param accessor resource accessor to access the resource with
* @throws IOException if an I/O error occurs while loading the resource
*/
public void createIncludedResourceFromExternal(final String resourceName,
final URI uri, final ResourceAccessor accessor) throws IOException {

AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);

AFPResourceInfo resourceInfo = new AFPResourceInfo();
resourceInfo.setLevel(resourceLevel);
resourceInfo.setName(resourceName);
resourceInfo.setUri(uri.toASCIIString());

String resource = (String)includeNameMap.get(resourceInfo);
if (resource == null) {

ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);

//resourceObject delegates write commands to copyNamedResource()
//The included resource may already be wrapped in a resource object
AbstractNamedAFPObject resourceObject = new AbstractNamedAFPObject(null) {

protected void writeContent(OutputStream os) throws IOException {
InputStream inputStream = null;
try {
inputStream = accessor.createInputStream(uri);
BufferedInputStream bin = new BufferedInputStream(inputStream);
AFPResourceUtil.copyNamedResource(resourceName, bin, os);
} finally {
IOUtils.closeQuietly(inputStream);
}
}

//bypass super.writeStart
protected void writeStart(OutputStream os) throws IOException { }
//bypass super.writeEnd
protected void writeEnd(OutputStream os) throws IOException { }
};

resourceGroup.addObject(resourceObject);

includeNameMap.put(resourceInfo, resourceName);

}
}


/**
* Sets resource level defaults. The existing defaults over merged with the ones passed in
* as parameter.

+ 1
- 1
src/java/org/apache/fop/afp/AFPStreamer.java Bestand weergeven

@@ -158,7 +158,7 @@ public class AFPStreamer implements Streamable {
*/
// write out any external resource groups
public void close() throws IOException {
Iterator it = pathResourceGroupMap.entrySet().iterator();
Iterator it = pathResourceGroupMap.values().iterator();
while (it.hasNext()) {
StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next();
resourceGroup.close();

+ 2
- 1
src/java/org/apache/fop/afp/modca/IncludedResourceObject.java Bestand weergeven

@@ -26,6 +26,7 @@ import java.net.URI;

import org.apache.commons.io.IOUtils;

import org.apache.fop.afp.util.AFPResourceUtil;
import org.apache.fop.afp.util.ResourceAccessor;


@@ -54,7 +55,7 @@ public class IncludedResourceObject extends AbstractNamedAFPObject {
public void writeToStream(OutputStream os) throws IOException {
InputStream in = resourceAccessor.createInputStream(this.uri);
try {
IOUtils.copy(in, os);
AFPResourceUtil.copyResourceFile(in, os);
} finally {
IOUtils.closeQuietly(in);
}

+ 7
- 3
src/java/org/apache/fop/afp/parser/MODCAParser.java Bestand weergeven

@@ -29,6 +29,9 @@ import java.io.InputStream;
*/
public class MODCAParser {

/** The carriage control character (0x5A) used to indicate the start of a structured field. */
public static final byte CARRIAGE_CONTROL_CHAR = (byte)(0x5A & 0xFF);

private DataInputStream din;

/**
@@ -61,10 +64,11 @@ public class MODCAParser {
try {
while (true) {
byte b = din.readByte(); //Skip 0x5A character if necessary (ex. AFP)
if (b == 0x0D || b == 0x0A) { //CR and LF may be used as field delimiters
if (b == 0x0D || b == 0x0A) {
//CR and LF may be used as field delimiters
continue;
} else if (b == 0x5A) { //Carriage Control Character
break;
} else if (b == CARRIAGE_CONTROL_CHAR) {
break; //Signals the start of a new structured field
}
}
} catch (EOFException eof) {

+ 214
- 0
src/java/org/apache/fop/afp/util/AFPResourceUtil.java Bestand weergeven

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

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.afp.modca.AbstractAFPObject.Category;
import org.apache.fop.afp.parser.MODCAParser;
import org.apache.fop.afp.parser.UnparsedStructuredField;

/**
* TODO better docs
* Utility for AFP resource handling
*
*
* A utility class to read structured fields from a MO:DCA document. Each
* component of a mixed object document is explicitly defined and delimited
* in the data. This is accomplished through the use of MO:DCA data structures,
* called structured fields. Structured fields are used to envelop document
* components and to provide commands and information to applications using
* the data. Structured fields may contain one or more parameters. Each
* parameter provides one value from a set of values defined by the architecture.
* <p/>
* MO:DCA structured fields consist of two parts: an introducer that identifies
* the length and type of the structured field, and data that provides the
* structured field's effect. The data is contained in a set of parameters,
* which can consist of other data structures and data elements. The maximum
* length of a structured field is 32767 bytes.
* <p/>
*/
public final class AFPResourceUtil {

private static final byte TYPE_CODE_BEGIN = (byte)(0xA8 & 0xFF);
private static final byte TYPE_CODE_END = (byte)(0xA9 & 0xFF);

private static final Log LOG = LogFactory.getLog(AFPResourceUtil.class);

private AFPResourceUtil() {
//nop
}

/**
* Get the next structured field as identified by the identifier
* parameter (this must be a valid MO:DCA structured field).
* @param identifier the three byte identifier
* @param inputStream the inputStream
* @throws IOException if an I/O exception occurred
* @return the next structured field or null when there are no more
*/
public static byte[] getNext(byte[] identifier, InputStream inputStream) throws IOException {
MODCAParser parser = new MODCAParser(inputStream);
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
return null;
}
if (field.getSfClassCode() == identifier[0]
&& field.getSfTypeCode() == identifier[1]
&& field.getSfCategoryCode() == identifier[2]) {
return field.getCompleteFieldAsBytes();
}
}
}

private static String getResourceName(UnparsedStructuredField field)
throws UnsupportedEncodingException {
//The first 8 bytes of the field data represent the resource name
byte[] nameBytes = new byte[8];
System.arraycopy(field.getData(), 0, nameBytes, 0, 8);
String asciiName;
asciiName = new String(nameBytes, AFPConstants.EBCIDIC_ENCODING);
return asciiName;
}

/**
* Copy a complete resource file to a given {@link OutputStream}.
* @param in external resource input
* @param out output destination
* @throws IOException if an I/O error occurs
*/
public static void copyResourceFile(final InputStream in, OutputStream out)
throws IOException {
MODCAParser parser = new MODCAParser(in);
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
break;
}
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
field.writeTo(out);
}
}

/**
* Copy a named resource to a given {@link OutputStream}. The MO:DCA fields read from the
* {@link InputStream} are scanned for the resource with the given name.
* @param name name of structured field
* @param in external resource input
* @param out output destination
* @throws IOException if an I/O error occurs
*/
public static void copyNamedResource(String name,
final InputStream in, final OutputStream out) throws IOException {
final MODCAParser parser = new MODCAParser(in);
Collection resourceNames = new java.util.HashSet();

//Find matching "Begin" field
final UnparsedStructuredField fieldBegin;
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
throw new IOException("Requested resource '" + name
+ "' not found. Encountered resource names: " + resourceNames);
}

if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin
continue; //Not a "Begin" field
}
String resourceName = getResourceName(field);
resourceNames.add(resourceName);
if (resourceName.equals(name)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Start of requested structured field found:\n"
+ field);
}
fieldBegin = field;
break; //Name doesn't match
}
}

//Decide whether the resource file has to be wrapped in a resource object
boolean wrapInResource;
if (fieldBegin.getSfCategoryCode() == Category.PAGE_SEGMENT) {
//A naked page segment must be wrapped in a resource object
wrapInResource = true;
} else if (fieldBegin.getSfCategoryCode() == Category.NAME_RESOURCE) {
//A resource object can be copied directly
wrapInResource = false;
} else {
throw new IOException("Cannot handle resource: " + fieldBegin);
}

//Copy structured fields (wrapped or as is)
if (wrapInResource) {
ResourceObject resourceObject = new ResourceObject(name) {
protected void writeContent(OutputStream os) throws IOException {
copyStructuredFields(name, fieldBegin, parser, out);
}
};
resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT);
resourceObject.writeToStream(out);
} else {
copyStructuredFields(name, fieldBegin, parser, out);
}
}

private static void copyStructuredFields(String name, UnparsedStructuredField fieldBegin,
MODCAParser parser, OutputStream out) throws IOException {
boolean inRequestedResource;

//The "Begin" field first
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
fieldBegin.writeTo(out);
UnparsedStructuredField field;

//Then the rest of the fields until the corresponding "End" field
inRequestedResource = true;
do {
field = parser.readNextStructuredField();
if (field == null) {
break; //Unexpected EOF
}

if (field.getSfTypeCode() == TYPE_CODE_END) {
String resourceName = getResourceName(field);
if (resourceName.equals(name)) {
inRequestedResource = false; //Signal end of loop
}
}
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
field.writeTo(out);
} while (inRequestedResource);
if (inRequestedResource) {
throw new IOException("Ending structured field not found for resource " + name);
}
}

}

+ 13
- 66
src/java/org/apache/fop/afp/util/StructuredFieldReader.java Bestand weergeven

@@ -54,80 +54,27 @@ public class StructuredFieldReader {
}

/**
* Get the next structured field as identified by the identifer
* parameter (this must be a valid MO:DCA structured field.
* Get the next structured field as identified by the identifier
* parameter (this must be a valid MO:DCA structured field).
* Note: The returned data does not include the field length and identifier!
* @param identifier the three byte identifier
* @throws IOException if an I/O exception occurred
* @return the next structured field or null when there are no more
*/
public byte[] getNext(byte[] identifier) throws IOException {

int bufferPointer = 0;
byte[] bufferData = new byte[identifier.length + 2];
for (int x = 0; x < identifier.length; x++) {
bufferData[x] = 0x00;
}

int c;
while ((c = inputStream.read()) > -1) {

bufferData[bufferPointer] = (byte) c;

// Check the last characters in the buffer
int index = 0;
boolean found = true;

for (int i = identifier.length - 1; i > -1; i--) {

int p = bufferPointer - index;
if (p < 0) {
p = bufferData.length + p;
}

index++;

if (identifier[i] != bufferData[p]) {
found = false;
break;
}

}

if (found) {

byte[] length = new byte[2];

int a = bufferPointer - identifier.length;
if (a < 0) {
a = bufferData.length + a;
}

int b = bufferPointer - identifier.length - 1;
if (b < 0) {
b = bufferData.length + b;
}

length[0] = bufferData[b];
length[1] = bufferData[a];

int reclength = ((length[0] & 0xFF) << 8)
+ (length[1] & 0xFF) - identifier.length - 2;

byte[] retval = new byte[reclength];

inputStream.read(retval, 0, reclength);

return retval;

}

bufferPointer++;
if (bufferPointer >= bufferData.length) {
bufferPointer = 0;
}
byte[] bytes = AFPResourceUtil.getNext(identifier, this.inputStream);

if (bytes != null) {
//Users of this class expect the field data without length and identifier
int srcPos = 2 + identifier.length;
byte[] tmp = new byte[bytes.length - srcPos];
System.arraycopy(bytes, srcPos, tmp, 0, tmp.length);
bytes = tmp;
}

return null;
return bytes;

}

}

+ 13
- 10
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java Bestand weergeven

@@ -47,6 +47,7 @@ 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.AFPPageOverlay;
import org.apache.fop.render.afp.extensions.AFPPageSegmentElement;
import org.apache.fop.render.afp.extensions.AFPPageSetup;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandler;
@@ -76,8 +77,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
private DataStream dataStream;

/** the map of page segments */
private Map/*<String,String>*/pageSegmentMap
= new java.util.HashMap/*<String,String>*/();
private Map/*<String,PageSegmentDescriptor>*/pageSegmentMap
= new java.util.HashMap/*<String,PageSegmentDescriptor>*/();

/** Medium Map referenced on previous page **/
private String lastMediumMap;
@@ -213,7 +214,6 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
throws IFException {
this.location = LOC_ELSEWHERE;
paintingState.clear();
pageSegmentMap.clear();

AffineTransform baseTransform = getBaseTransform();
paintingState.concatenate(baseTransform);
@@ -288,9 +288,12 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
null);
}
if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(element)) {
String name = aps.getName();
String source = aps.getValue();
pageSegmentMap.put(source, name);
AFPPageSegmentElement.AFPPageSegmentSetup apse
= (AFPPageSegmentElement.AFPPageSegmentSetup)aps;
String name = apse.getName();
String source = apse.getValue();
String uri = apse.getResourceSrc();
pageSegmentMap.put(source, new PageSegmentDescriptor(name, uri));
} else if (AFPElementMapping.NO_OPERATION.equals(element)) {
String content = aps.getContent();
if (content != null) {
@@ -392,13 +395,13 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
}

/**
* Returns the page segment name for a given URI if it actually represents a page segment.
* Returns the page segment descriptor for a given URI if it actually represents a page segment.
* Otherwise, it just returns null.
* @param uri the URI that identifies the page segment
* @return the page segment name or null if there's no page segment for the given URI
* @return the page segment descriptor or null if there's no page segment for the given URI
*/
String getPageSegmentNameFor(String uri) {
return (String)pageSegmentMap.get(uri);
PageSegmentDescriptor getPageSegmentNameFor(String uri) {
return (PageSegmentDescriptor)pageSegmentMap.get(uri);
}

}

+ 27
- 3
src/java/org/apache/fop/render/afp/AFPPainter.java Bestand weergeven

@@ -26,6 +26,8 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import org.w3c.dom.Document;
@@ -48,6 +50,8 @@ import org.apache.fop.afp.modca.AbstractPageObject;
import org.apache.fop.afp.modca.PresentationTextObject;
import org.apache.fop.afp.ptoca.PtocaBuilder;
import org.apache.fop.afp.ptoca.PtocaProducer;
import org.apache.fop.afp.util.DefaultFOPResourceAccessor;
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;
@@ -183,14 +187,34 @@ public class AFPPainter extends AbstractIFPainter {

/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
String name = documentHandler.getPageSegmentNameFor(uri);
if (name != null) {
PageSegmentDescriptor pageSegment = documentHandler.getPageSegmentNameFor(uri);

if (pageSegment != null) {
float[] srcPts = {rect.x, rect.y};
int[] coords = unitConv.mpts2units(srcPts);
int width = Math.round(unitConv.mpt2units(rect.width));
int height = Math.round(unitConv.mpt2units(rect.height));

getDataStream().createIncludePageSegment(name, coords[X], coords[Y], width, height);
getDataStream().createIncludePageSegment(pageSegment.getName(),
coords[X], coords[Y], width, height);

//Do we need to embed an external page segment?
if (pageSegment.getURI() != null) {
ResourceAccessor accessor = new DefaultFOPResourceAccessor (
documentHandler.getUserAgent(), null, null);
try {
URI resourceUri = new URI(pageSegment.getURI());
documentHandler.getResourceManager().createIncludedResourceFromExternal(
pageSegment.getName(), resourceUri, accessor);

} catch (URISyntaxException urie) {
throw new IFException("Could not handle resource url"
+ pageSegment.getURI(), urie);
} catch (IOException ioe) {
throw new IFException("Could not handle resource" + pageSegment.getURI(), ioe);
}
}

} else {
drawImageUsingURI(uri, rect);
}

+ 57
- 0
src/java/org/apache/fop/render/afp/PageSegmentDescriptor.java Bestand weergeven

@@ -0,0 +1,57 @@
/*
* 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;

/**
* Class holding information on a page segment.
*/
class PageSegmentDescriptor {

private String name;
private String uri;

/**
* Creates a new page segment descriptor.
* @param name the page segment name
* @param uri the URI identifying the external resource file (may be null if the page segment
* shall be referenced rather than embedded)
*/
public PageSegmentDescriptor(String name, String uri) {
this.name = name;
this.uri = uri;
}

/**
* Returns the name of the page segment (usually 8 upper case letters).
* @return the name of the page segment
*/
public String getName() {
return this.name;
}

/**
* Returns the URI of the external resource containing the page segment.
* @return the URI of the external resource (or null if the resource is not to be embedded)
*/
public String getURI() {
return this.uri;
}

}

+ 1
- 1
src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java Bestand weergeven

@@ -103,7 +103,7 @@ public class AFPElementMapping extends ElementMapping {

static class AFPIncludePageSegmentMaker extends ElementMapping.Maker {
public FONode make(FONode parent) {
return new AFPPageSetupElement(parent, INCLUDE_PAGE_SEGMENT);
return new AFPPageSegmentElement(parent, INCLUDE_PAGE_SEGMENT);
}
}


+ 26
- 0
src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java Bestand weergeven

@@ -29,6 +29,7 @@ import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.render.afp.extensions.AFPPageSegmentElement.AFPPageSegmentSetup;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;

@@ -96,6 +97,30 @@ public class AFPExtensionHandler extends DefaultHandler
if (name != null) {
returnedObject.setName(name);
}
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(localName)) {
AFPPageSegmentSetup pageSetupExtn = null;

pageSetupExtn = new AFPPageSegmentSetup(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);
}

String resourceSrc = lastAttributes.getValue("resource-file");
if (resourceSrc != null && pageSetupExtn != null) {
pageSetupExtn.setResourceSrc(resourceSrc);
}

if (content.length() > 0 && pageSetupExtn != null) {
pageSetupExtn.setContent(content.toString());
content.setLength(0); //Reset text buffer (see characters())
}
} else {
AFPPageSetup pageSetupExtn = null;
if (AFPElementMapping.INVOKE_MEDIUM_MAP.equals(localName)) {
@@ -117,6 +142,7 @@ public class AFPExtensionHandler extends DefaultHandler
content.setLength(0); //Reset text buffer (see characters())
}
}

}
}


+ 149
- 0
src/java/org/apache/fop/render/afp/extensions/AFPPageSegmentElement.java Bestand weergeven

@@ -0,0 +1,149 @@
/*
* 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 org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.extensions.ExtensionAttachment;

/**
* This class extends the org.apache.fop.extensions.ExtensionObj class. The
* object faciliates extraction of elements from formatted objects based on
* the static list as defined in the AFPElementMapping implementation.
* <p/>
*/
public class AFPPageSegmentElement extends AFPPageSetupElement {

private static final String ATT_RESOURCE_SRC = "resource-file";

/**
* Constructs an AFP object (called by Maker).
*
* @param parent the parent formatting object
* @param name the name of the afp element
*/
public AFPPageSegmentElement(FONode parent, String name) {
super(parent, name);
}


private AFPPageSegmentSetup getPageSetupAttachment() {
return (AFPPageSegmentSetup)getExtensionAttachment();
}


/** {@inheritDoc} */
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList propertyList)
throws FOPException {

AFPPageSegmentSetup pageSetup = getPageSetupAttachment();
super.processNode(elementName, locator, attlist, propertyList);


String attr = attlist.getValue(ATT_RESOURCE_SRC);

if (attr != null && attr.length() > 0) {
pageSetup.setResourceSrc(attr);
}

}

/** {@inheritDoc} */
protected ExtensionAttachment instantiateExtensionAttachment() {
return new AFPPageSegmentSetup(getLocalName());
}

/**
* This is the pass-through value object for the AFP extension.
*/
public static class AFPPageSegmentSetup extends AFPPageSetup {

private static final long serialVersionUID = 1L;

private String resourceSrc;

/**
* Default constructor.
*
* @param elementName the name of the setup code object, may be null
*/
public AFPPageSegmentSetup(String elementName) {
super(elementName);
}

/**
* Returns the source URI for the page segment.
* @return the source URI
*/
public String getResourceSrc() {
return resourceSrc;
}

/**
* Sets the source URI for the page segment.
* @param resourceSrc the source URI
*/
public void setResourceSrc(String resourceSrc) {
this.resourceSrc = resourceSrc.trim();
}


/** {@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 (value != null && value.length() > 0) {
atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value);
}

if (resourceSrc != null && resourceSrc.length() > 0) {
atts.addAttribute(null, ATT_RESOURCE_SRC, ATT_RESOURCE_SRC, "CDATA", resourceSrc);
}

handler.startElement(CATEGORY, elementName, elementName, atts);
if (content != null && content.length() > 0) {
char[] chars = content.toCharArray();
handler.characters(chars, 0, chars.length);
}
handler.endElement(CATEGORY, elementName, elementName);
}

/** {@inheritDoc} */
public String toString() {
return "AFPPageSegmentSetup(element-name=" + getElementName()
+ " name=" + getName()
+ " value=" + getValue()
+ " resource=" + getResourceSrc() + ")";
}

}


}

+ 3
- 0
status.xml Bestand weergeven

@@ -58,6 +58,9 @@
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" fixes-bug="49379" due-to="Peter Hancock">
Added ability to embed an external AFP page segment resource file (AFP output only).
</action>
<action context="Renderers" dev="JM" type="fix" fixes-bug="46360" due-to="Alexis Giotis">
Fixed a multi-threading issue when rendering SVG.
</action>

Laden…
Annuleren
Opslaan