diff options
Diffstat (limited to 'src/java')
50 files changed, 1121 insertions, 513 deletions
diff --git a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java index f6de7b5b4..792909b9e 100644 --- a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java +++ b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java @@ -24,6 +24,7 @@ import java.awt.geom.Rectangle2D; import org.apache.xmlgraphics.image.codec.tiff.TIFFImage; import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.fop.afp.ioca.IDEStructureParameter; import org.apache.fop.afp.ioca.ImageContent; import org.apache.fop.afp.modca.AbstractDataObject; import org.apache.fop.afp.modca.AbstractNamedAFPObject; @@ -113,12 +114,35 @@ public class AFPDataObjectFactory { } } - if (imageObjectInfo.isColor()) { - imageObj.setIDESize((byte) 24); - } else { - imageObj.setIDESize((byte) imageObjectInfo.getBitsPerPixel()); + ImageContent content = imageObj.getImageSegment().getImageContent(); + int bitsPerPixel = imageObjectInfo.getBitsPerPixel(); + imageObj.setIDESize((byte) bitsPerPixel); + IDEStructureParameter ideStruct; + switch (bitsPerPixel) { + case 1: + //Skip IDE Structure Parameter + break; + case 4: + case 8: + ideStruct = content.needIDEStructureParameter(); + ideStruct.setBitsPerComponent(new int[] {bitsPerPixel}); + break; + case 24: + ideStruct = content.needIDEStructureParameter(); + ideStruct.setDefaultRGBColorModel(); + break; + case 32: + ideStruct = content.needIDEStructureParameter(); + ideStruct.setDefaultCMYKColorModel(); + break; + default: + throw new IllegalArgumentException("Unsupported number of bits per pixel: " + + bitsPerPixel); + } + if (imageObjectInfo.isSubtractive()) { + ideStruct = content.needIDEStructureParameter(); + ideStruct.setSubtractive(imageObjectInfo.isSubtractive()); } - imageObj.setSubtractive(imageObjectInfo.isSubtractive()); imageObj.setData(imageObjectInfo.getData()); diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java index 578924d67..643dcb702 100644 --- a/src/java/org/apache/fop/afp/AFPPaintingState.java +++ b/src/java/org/apache/fop/afp/AFPPaintingState.java @@ -46,8 +46,10 @@ implements Cloneable { /** color image support */ private boolean colorImages = false; - /** images are supported in this AFP environment */ + /** true if certain image formats may be embedded unchanged in their native format. */ private boolean nativeImagesSupported = false; + /** true if CMYK images (requires IOCA FS45 suppport on the target platform) may be generated */ + private boolean cmykImagesSupported; /** default value for image depth */ private int bitsPerPixel = 8; @@ -64,6 +66,7 @@ implements Cloneable { /** a unit converter */ private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this); + /** * Sets the rotation to be used for portrait pages, valid values are 0 * (default), 90, 180, 270. @@ -186,6 +189,24 @@ implements Cloneable { } /** + * Controls whether CMYK images (IOCA FS45) are enabled. By default, support is disabled + * for wider compatibility. When disabled, any CMYK image is converted to the selected + * color format. + * @param value true to enabled CMYK images + */ + public void setCMYKImagesSupported(boolean value) { + this.cmykImagesSupported = value; + } + + /** + * Indicates whether CMYK images (IOCA FS45) are enabled. + * @return true if IOCA FS45 is enabled + */ + public boolean isCMYKImagesSupported() { + return this.cmykImagesSupported; + } + + /** * Sets the output/device resolution * * @param resolution diff --git a/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java index 4094314a2..6d6e44c97 100644 --- a/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java +++ b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java @@ -45,7 +45,7 @@ public class GraphicsCharacterString extends AbstractGraphicsCoord { */ public GraphicsCharacterString(String str, int x, int y) { super(x, y); - this.str = truncate(str); + this.str = truncate(str, MAX_STR_LEN); } /** @@ -57,7 +57,7 @@ public class GraphicsCharacterString extends AbstractGraphicsCoord { */ public GraphicsCharacterString(String str) { super(null); - this.str = truncate(str); + this.str = truncate(str, MAX_STR_LEN); } /** {@inheritDoc} */ @@ -83,20 +83,6 @@ public class GraphicsCharacterString extends AbstractGraphicsCoord { } /** - * Truncates the string as necessary - * - * @param str a character string - * @return a possibly truncated string - */ - private String truncate(String str) { - if (str.length() > MAX_STR_LEN) { - str = str.substring(0, MAX_STR_LEN); - log.warn("truncated character string, longer than " + MAX_STR_LEN + " chars"); - } - return str; - } - - /** * Returns the text string as an encoded byte array * * @return the text string as an encoded byte array diff --git a/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java b/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java new file mode 100644 index 000000000..8c0d0d49a --- /dev/null +++ b/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java @@ -0,0 +1,151 @@ +/* + * 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.ioca; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Streamable; + +/** + * This class represents the IOCA IDE Structure parameter (X'9B'). + */ +public class IDEStructureParameter implements Streamable { + + /** The RGB color model used by the IDE Structure parameter */ + public static final byte COLOR_MODEL_RGB = (byte)0x01; + /** The YCrCb color model used by the IDE Structure parameter */ + public static final byte COLOR_MODEL_YCRCB = (byte)0x02; + /** The CMYK color model used by the IDE Structure parameter */ + public static final byte COLOR_MODEL_CMYK = (byte)0x04; + /** The YCbCr color model used by the IDE Structure parameter */ + public static final byte COLOR_MODEL_YCBCR = (byte)0x12; + + /** additive/subtractive setting for ASFLAG */ + private boolean subtractive = false; + + /** setting for GRAYCODE flag */ + private boolean grayCoding = false; + + /** the image color model */ + private byte colorModel = COLOR_MODEL_RGB; + + /** the array with the number of bits/IDE for each component */ + private byte[] bitsPerIDE = new byte[] {(byte)1}; //1-bit by default + + /** + * Creates a new IDE Structure parameter. The values are initialized for a bi-level image + * using the RGB color model. + */ + public IDEStructureParameter() { + //nop + } + + /** + * Sets the image IDE color model. + * + * @param color the IDE color model. + */ + public void setColorModel(byte color) { + this.colorModel = color; + } + + /** + * Establishes the parameter values for the normal RGB 24bit color model. + */ + public void setDefaultRGBColorModel() { + this.colorModel = COLOR_MODEL_RGB; + setUniformBitsPerComponent(3, 8); + } + + /** + * Establishes the parameter values for the normal CMYK 32bit color model. + */ + public void setDefaultCMYKColorModel() { + this.colorModel = COLOR_MODEL_CMYK; + setUniformBitsPerComponent(4, 8); + } + + /** + * Sets + * @param numComponents + * @param bitsPerComponent + */ + public void setUniformBitsPerComponent(int numComponents, int bitsPerComponent) { + if (bitsPerComponent < 0 || bitsPerComponent >= 256) { + throw new IllegalArgumentException( + "The number of bits per component must be between 0 and 255"); + } + this.bitsPerIDE = new byte[numComponents]; + for (int i = 0; i < numComponents; i++) { + this.bitsPerIDE[i] = (byte)bitsPerComponent; + } + } + + /** + * Sets the array for the bits/IDE, one entry per component. + * @param bitsPerComponent the + */ + public void setBitsPerComponent(int[] bitsPerComponent) { + int numComponents = bitsPerComponent.length; + this.bitsPerIDE = new byte[numComponents]; + for (int i = 0; i < numComponents; i++) { + int bits = bitsPerComponent[i]; + if (bits < 0 || bits >= 256) { + throw new IllegalArgumentException( + "The number of bits per component must be between 0 and 255"); + } + this.bitsPerIDE[i] = (byte)bits; + } + } + + /** + * Set either additive or subtractive mode (used for ASFLAG). + * @param subtractive true for subtractive mode, false for additive mode + */ + public void setSubtractive(boolean subtractive) { + this.subtractive = subtractive; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + int length = 7 + bitsPerIDE.length; + + byte flags = 0x00; + if (subtractive) { + flags |= 1 << 7; + } + if (grayCoding) { + flags |= 1 << 6; + } + + DataOutputStream dout = new DataOutputStream(os); + dout.writeByte(0x9B); //ID + dout.writeByte(length - 2); //LENGTH + dout.writeByte(flags); //FLAGS + dout.writeByte(this.colorModel); //FORMAT + for (int i = 0; i < 3; i++) { + dout.writeByte(0); //RESERVED + } + dout.write(this.bitsPerIDE); //component sizes + } + +} diff --git a/src/java/org/apache/fop/afp/ioca/ImageContent.java b/src/java/org/apache/fop/afp/ioca/ImageContent.java index fe902b381..9c06589e0 100644 --- a/src/java/org/apache/fop/afp/ioca/ImageContent.java +++ b/src/java/org/apache/fop/afp/ioca/ImageContent.java @@ -56,21 +56,18 @@ public class ImageContent extends AbstractStructuredObject { /** the image size parameter */ private ImageSizeParameter imageSizeParameter = null; + /** the IDE Structure parameter */ + private IDEStructureParameter ideStructureParameter = null; + /** the image encoding */ private byte encoding = (byte)0x03; - /** the image ide size */ - private byte size = 1; + /** the image IDE (Image Data Element, Sample) size */ + private byte ideSize = 1; /** the image compression */ private byte compression = (byte)0xC0; - /** the image color model */ - private byte colorModel = (byte)0x01; - - /** additive/subtractive setting for ASFLAG */ - private boolean subtractive = false; - /** the image data */ private byte[] data; @@ -90,6 +87,34 @@ public class ImageContent extends AbstractStructuredObject { } /** + * Sets the IDE Structure parameter. + * @param parameter the IDE Structure parameter + */ + public void setIDEStructureParameter(IDEStructureParameter parameter) { + this.ideStructureParameter = parameter; + } + + /** + * Returns the (optional) IDE Structure parameter + * @return the IDE Structure parameter or null if none is set + */ + public IDEStructureParameter getIDEStructureParameter() { + return this.ideStructureParameter; + } + + /** + * Returns the (optional) IDE Structure parameter. If none is set an instance is prepared + * with defaults for a bi-level image. + * @return the IDE Structure parameter + */ + public IDEStructureParameter needIDEStructureParameter() { + if (this.ideStructureParameter == null) { + setIDEStructureParameter(new IDEStructureParameter()); + } + return getIDEStructureParameter(); + } + + /** * Sets the image encoding. * * @param enc The image encoding. @@ -113,24 +138,26 @@ public class ImageContent extends AbstractStructuredObject { * @param s The IDE size. */ public void setImageIDESize(byte s) { - this.size = s; + this.ideSize = s; } /** * Sets the image IDE color model. * * @param color the IDE color model. + * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead */ public void setImageIDEColorModel(byte color) { - this.colorModel = color; + needIDEStructureParameter().setColorModel(color); } /** * Set either additive or subtractive mode (used for ASFLAG). * @param subtractive true for subtractive mode, false for additive mode + * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead */ public void setSubtractive(boolean subtractive) { - this.subtractive = subtractive; + needIDEStructureParameter().setSubtractive(subtractive); } /** @@ -155,10 +182,12 @@ public class ImageContent extends AbstractStructuredObject { os.write(getImageIDESizeParameter()); - boolean useFS10 = (this.size == 1); - if (!useFS10) { - os.write(getIDEStructureParameter()); + if (getIDEStructureParameter() != null) { + getIDEStructureParameter().writeToStream(os); + } + boolean useFS10 = (this.ideSize == 1); + if (!useFS10) { os.write(getExternalAlgorithmParameter()); } @@ -243,58 +272,15 @@ public class ImageContent extends AbstractStructuredObject { * @return byte[] The data stream. */ private byte[] getImageIDESizeParameter() { - if (size != 1) { + if (ideSize != 1) { final byte[] ideSizeData = new byte[] { (byte)0x96, // ID 0x01, // Length - size}; + ideSize}; return ideSizeData; } else { return new byte[0]; } } - /** - * Helper method to return the external algorithm parameter. - * - * @return byte[] The data stream. - */ - private byte[] getIDEStructureParameter() { - byte flags = 0x00; - if (subtractive) { - flags |= 1 << 7; - } - if (colorModel != 0 && size == 24) { - final byte bits = (byte)(size / 3); - final byte[] ideStructData = new byte[] { - (byte)0x9B, // ID - 0x00, // Length - flags, // FLAGS - colorModel, // COLOR MODEL - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - bits, - bits, - bits, - }; - ideStructData[1] = (byte)(ideStructData.length - 2); - return ideStructData; - } else if (size == 1) { - final byte[] ideStructData = new byte[] { - (byte)0x9B, // ID - 0x00, // Length - flags, // FLAGS - colorModel, // COLOR MODEL - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - 0x01 - }; - ideStructData[1] = (byte)(ideStructData.length - 2); - return ideStructData; - } - return new byte[0]; - } - } diff --git a/src/java/org/apache/fop/afp/ioca/ImageSegment.java b/src/java/org/apache/fop/afp/ioca/ImageSegment.java index d8ba38ec0..9965bb94a 100644 --- a/src/java/org/apache/fop/afp/ioca/ImageSegment.java +++ b/src/java/org/apache/fop/afp/ioca/ImageSegment.java @@ -56,7 +56,11 @@ public class ImageSegment extends AbstractNamedAFPObject { this.factory = factory; } - private ImageContent getImageContent() { + /** + * Returns the image content object associated with this image segment. + * @return the image content + */ + public ImageContent getImageContent() { if (imageContent == null) { this.imageContent = factory.createImageContent(); } @@ -108,6 +112,7 @@ public class ImageSegment extends AbstractNamedAFPObject { * Sets the image IDE color model. * * @param colorModel the IDE color model. + * @deprecated Use {@link IDEStructureParameter#setColorModel(byte)} instead. */ public void setIDEColorModel(byte colorModel) { getImageContent().setImageIDEColorModel(colorModel); @@ -116,6 +121,7 @@ public class ImageSegment extends AbstractNamedAFPObject { /** * Set either additive or subtractive mode (used for ASFLAG). * @param subtractive true for subtractive mode, false for additive mode + * @deprecated Use {@link IDEStructureParameter#setSubtractive(boolean)} instead. */ public void setSubtractive(boolean subtractive) { getImageContent().setSubtractive(subtractive); @@ -124,7 +130,7 @@ public class ImageSegment extends AbstractNamedAFPObject { /** * Set the data image data. * - * @param data the image data + * @param imageData the image data */ public void setData(byte[] imageData) { getImageContent().setImageData(imageData); diff --git a/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java index ae1c83377..45239a6cf 100644 --- a/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java +++ b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java @@ -43,7 +43,7 @@ public abstract class AbstractAFPObject implements Streamable { /** the structured field class id */ protected static final byte SF_CLASS = (byte)0xD3; - private static final byte[] SF_HEADER = new byte[] { + protected static final byte[] SF_HEADER = new byte[] { 0x5A, // Structured field identifier 0x00, // Length byte 1 0x10, // Length byte 2 @@ -177,6 +177,21 @@ public abstract class AbstractAFPObject implements Streamable { } } + /** + * Truncates the string as necessary + * + * @param str a character string + * @param maxLength the maximum length allowed for the string + * @return a possibly truncated string + */ + protected String truncate(String str, int maxLength) { + if (str.length() > maxLength) { + str = str.substring(0, maxLength); + log.warn("truncated character string '" + str + "', longer than " + maxLength + " chars"); + } + return str; + } + /** structured field type codes */ public interface Type { diff --git a/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java index a14af2967..efc38f3b8 100644 --- a/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java +++ b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java @@ -27,9 +27,12 @@ import java.util.List; import org.apache.fop.afp.modca.Registry.ObjectType; import org.apache.fop.afp.modca.triplets.AbstractTriplet; +import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet; +import org.apache.fop.afp.modca.triplets.AttributeValueTriplet; import org.apache.fop.afp.modca.triplets.CommentTriplet; import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet; +import org.apache.fop.afp.modca.triplets.Triplet; /** * A MODCA structured object base class providing support for Triplets @@ -37,7 +40,7 @@ import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet; public class AbstractTripletStructuredObject extends AbstractStructuredObject { /** list of object triplets */ - protected List/*<AbstractTriplet>*/ triplets = new java.util.ArrayList/*<AbstractTriplet>*/(); + protected List/*<Triplet>*/ triplets = new java.util.ArrayList/*<Triplet>*/(); /** * Returns the triplet data length @@ -109,7 +112,7 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { * * @param triplet the triplet to add */ - protected void addTriplet(AbstractTriplet triplet) { + protected void addTriplet(Triplet triplet) { triplets.add(triplet); } @@ -130,7 +133,7 @@ public class AbstractTripletStructuredObject extends AbstractStructuredObject { } /** - * Sets the fully qualified name of this resource + * Sets the fully qualified name of this structured field * * @param fqnType the fully qualified name type of this resource * @param fqnFormat the fully qualified name format of this resource diff --git a/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java index 0f99d6624..38c60d7b6 100644 --- a/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java @@ -79,6 +79,8 @@ public class ContainerDataDescriptor extends AbstractDescriptor { data[18] = ysize[0]; data[19] = ysize[1]; data[20] = ysize[2]; + + os.write(data); } } diff --git a/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java index 0a7b665d7..386d2f40f 100644 --- a/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java @@ -31,6 +31,7 @@ public class ImageDataDescriptor extends AbstractDescriptor { public static final byte FUNCTION_SET_FS10 = 0x0A; public static final byte FUNCTION_SET_FS11 = 0x0B; + public static final byte FUNCTION_SET_FS45 = 45; private byte functionSet = FUNCTION_SET_FS11; // FCNSET = IOCA FS 11 diff --git a/src/java/org/apache/fop/afp/modca/ImageObject.java b/src/java/org/apache/fop/afp/modca/ImageObject.java index 65802f6ca..2f075ce33 100644 --- a/src/java/org/apache/fop/afp/modca/ImageObject.java +++ b/src/java/org/apache/fop/afp/modca/ImageObject.java @@ -24,9 +24,12 @@ import java.io.OutputStream; import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.xmlgraphics.util.MimeConstants; + import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPImageObjectInfo; import org.apache.fop.afp.Factory; +import org.apache.fop.afp.ioca.IDEStructureParameter; import org.apache.fop.afp.ioca.ImageSegment; /** @@ -50,7 +53,11 @@ public class ImageObject extends AbstractDataObject { super(factory, name); } - private ImageSegment getImageSegment() { + /** + * Returns the image segment object associated with this image object. + * @return the image segment + */ + public ImageSegment getImageSegment() { if (imageSegment == null) { this.imageSegment = factory.createImageSegment(); } @@ -71,6 +78,8 @@ public class ImageObject extends AbstractDataObject { = factory.createImageDataDescriptor(dataWidth, dataHeight, dataWidthRes, dataHeightRes); if (imageObjectInfo.getBitsPerPixel() == 1) { imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS10); + } else if (MimeConstants.MIME_AFP_IOCA_FS45.equals(imageObjectInfo.getMimeType())) { + imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS45); } getObjectEnvironmentGroup().setDataDescriptor(imageDataDescriptor); getObjectEnvironmentGroup().setMapImageObject( @@ -110,6 +119,7 @@ public class ImageObject extends AbstractDataObject { * Sets the image IDE color model. * * @param colorModel the IDE color model. + * @deprecated Use {@link IDEStructureParameter#setColorModel(byte)} instead. */ public void setIDEColorModel(byte colorModel) { getImageSegment().setIDEColorModel(colorModel); @@ -118,6 +128,7 @@ public class ImageObject extends AbstractDataObject { /** * Set either additive or subtractive mode (used for ASFLAG). * @param subtractive true for subtractive mode, false for additive mode + * @deprecated Use {@link IDEStructureParameter#setSubtractive(boolean)} instead. */ public void setSubtractive(boolean subtractive) { getImageSegment().setSubtractive(subtractive); diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java index 5c1f7bbbb..cb7a67d28 100644 --- a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java +++ b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java @@ -21,9 +21,10 @@ package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet; +import org.apache.fop.afp.modca.triplets.AttributeValueTriplet; +import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; import org.apache.fop.afp.util.BinaryUtils; /** @@ -45,7 +46,7 @@ import org.apache.fop.afp.util.BinaryUtils; * effect on the appearance of a document when it is presented. * <p/> */ -public class TagLogicalElement extends AbstractAFPObject { +public class TagLogicalElement extends AbstractTripletStructuredObject { /** * Name of the key, used within the TLE @@ -75,77 +76,43 @@ public class TagLogicalElement extends AbstractAFPObject { this.tleID = tleID; } - /** {@inheritDoc} */ - public void writeToStream(OutputStream os) throws IOException { - - // convert name and value to ebcdic - byte[] tleByteName = null; - byte[] tleByteValue = null; - try { - tleByteName = name.getBytes(AFPConstants.EBCIDIC_ENCODING); - tleByteValue = value.getBytes(AFPConstants.EBCIDIC_ENCODING); - } catch (UnsupportedEncodingException usee) { - tleByteName = name.getBytes(); - tleByteValue = value.getBytes(); - log.warn( - "Constructor:: UnsupportedEncodingException translating the name " - + name); - } - - byte[] data = new byte[27 + tleByteName.length + tleByteValue.length]; - - data[0] = 0x5A; - // Set the total record length - byte[] rl1 - = BinaryUtils.convert(26 + tleByteName.length + tleByteValue.length, 2); - //Ignore first byte - data[1] = rl1[0]; - data[2] = rl1[1]; - - // Structured field ID for a TLE - data[3] = (byte) 0xD3; - data[4] = (byte) Type.ATTRIBUTE; - data[5] = (byte) Category.PROCESS_ELEMENT; - - data[6] = 0x00; // Reserved - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - //Use 2 triplets, attribute name and value (the key for indexing) - - byte[] rl2 = BinaryUtils.convert(tleByteName.length + 4, 1); - data[9] = rl2[0]; // length of the triplet, including this field - data[10] = 0x02; //Identifies it as a FQN triplet - data[11] = 0x0B; // GID format - data[12] = 0x00; - - // write out TLE name - int pos = 13; - for (int i = 0; i < tleByteName.length; i++) { - data[pos++] = tleByteName[i]; - } - - byte[] rl3 = BinaryUtils.convert(tleByteValue.length + 4, 1); - data[pos++] = rl3[0]; // length of the triplet, including this field - data[pos++] = 0x36; //Identifies the triplet, attribute value - data[pos++] = 0x00; // Reserved - data[pos++] = 0x00; // Reserved + /** + * Sets the attribute value of this structured field + * + * @param value the attribute value + */ + public void setAttributeValue(String value) { + addTriplet(new AttributeValueTriplet(value)); + } - for (int i = 0; i < tleByteValue.length; i++) { - data[pos++] = tleByteValue[i]; - } - // attribute qualifier - data[pos++] = 0x0A; - data[pos++] = (byte)0x80; - byte[] id = BinaryUtils.convert(tleID, 4); - for (int i = 0; i < id.length; i++) { - data[pos++] = id[i]; - } - byte[] level = BinaryUtils.convert(1, 4); - for (int i = 0; i < level.length; i++) { - data[pos++] = level[i]; - } + /** + * Sets the attribute qualifier of this structured field + * + * @param seqNumber the attribute sequence number + * @param levNumber the attribute level number + */ + public void setAttributeQualifier(int seqNumber, int levNumber) { + addTriplet(new AttributeQualifierTriplet(seqNumber, levNumber)); + } + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + setFullyQualifiedName( + FullyQualifiedNameTriplet.TYPE_ATTRIBUTE_GID, + FullyQualifiedNameTriplet.FORMAT_CHARSTR, + name); + setAttributeQualifier(tleID, 1); + setAttributeValue(value); + + byte[] data = new byte[SF_HEADER.length]; + copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT); + + int tripletDataLength = getTripletDataLength(); + byte[] l = BinaryUtils.convert(data.length + tripletDataLength - 1, 2); + data[1] = l[0]; + data[2] = l[1]; os.write(data); + + writeTriplets(os); } } diff --git a/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java index 598df1b98..5cd136ab2 100644 --- a/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java +++ b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java @@ -19,70 +19,12 @@ package org.apache.fop.afp.modca.triplets; -import org.apache.fop.afp.Streamable; -import org.apache.fop.afp.StructuredData; +import org.apache.fop.afp.modca.AbstractAFPObject; /** * A simple implementation of a MOD:CA triplet */ -public abstract class AbstractTriplet implements Streamable, StructuredData { - public static final byte CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER = 0x01; - - /** Triplet identifiers */ - public static final byte FULLY_QUALIFIED_NAME = 0x02; - public static final byte MAPPING_OPTION = 0x04; - public static final byte OBJECT_CLASSIFICATION = 0x10; - public static final byte MODCA_INTERCHANGE_SET = 0x18; - public static final byte FONT_DESCRIPTOR_SPECIFICATION = 0x1F; - public static final byte OBJECT_FUNCTION_SET_SPECIFICATION = 0x21; - public static final byte EXTENDED_RESOURCE_LOCAL_IDENTIFIER = 0x22; - public static final byte RESOURCE_LOCAL_IDENTIFIER = 0x24; - public static final byte RESOURCE_SECTION_NUMBER = 0x25; - public static final byte CHARACTER_ROTATION = 0x26; - public static final byte OBJECT_BYTE_OFFSET = 0x2D; - public static final byte ATTRIBUTE_VALUE = 0x36; - public static final byte DESCRIPTOR_POSITION = 0x43; - public static final byte MEDIA_EJECT_CONTROL = 0x45; - public static final byte PAGE_OVERLAY_CONDITIONAL_PROCESSING = 0x46; - public static final byte RESOURCE_USAGE_ATTRIBUTE = 0x47; - public static final byte MEASUREMENT_UNITS = 0x4B; - public static final byte OBJECT_AREA_SIZE = 0x4C; - public static final byte AREA_DEFINITION = 0x4D; - public static final byte COLOR_SPECIFICATION = 0x4E; - public static final byte ENCODING_SCHEME_ID = 0x50; - public static final byte MEDIUM_MAP_PAGE_NUMBER = 0x56; - public static final byte OBJECT_BYTE_EXTENT = 0x57; - public static final byte OBJECT_STRUCTURED_FIELD_OFFSET = 0x58; - public static final byte OBJECT_STRUCTURED_FIELD_EXTENT = 0x59; - public static final byte OBJECT_OFFSET = 0x5A; - public static final byte FONT_HORIZONTAL_SCALE_FACTOR = 0x5D; - public static final byte OBJECT_COUNT = 0x5E; - public static final byte OBJECT_DATE_AND_TIMESTAMP = 0x62; - public static final byte COMMENT = 0x65; - public static final byte MEDIUM_ORIENTATION = 0x68; - public static final byte RESOURCE_OBJECT_INCLUDE = 0x6C; - public static final byte PRESENTATION_SPACE_RESET_MIXING = 0x70; - public static final byte PRESENTATION_SPACE_MIXING_RULE = 0x71; - public static final byte UNIVERSAL_DATE_AND_TIMESTAMP = 0x72; - public static final byte TONER_SAVER = 0x74; - public static final byte COLOR_FIDELITY = 0x75; - public static final byte FONT_FIDELITY = 0x78; - public static final byte ATTRIBUTE_QUALIFIER = (byte)0x80; - public static final byte PAGE_POSITION_INFORMATION = (byte)0x81; - public static final byte PARAMETER_VALUE = (byte)0x82; - public static final byte PRESENTATION_CONTROL = (byte)0x83; - public static final byte FONT_RESOLUTION_AND_METRIC_TECHNOLOGY = (byte)0x84; - public static final byte FINISHING_OPERATION = (byte)0x85; - public static final byte TEXT_FIDELITY = (byte)0x86; - public static final byte MEDIA_FIDELITY = (byte)0x87; - public static final byte FINISHING_FIDELITY = (byte)0x88; - public static final byte DATA_OBJECT_FONT_DESCRIPTOR = (byte)0x8B; - public static final byte LOCALE_SELECTOR = (byte)0x8C; - public static final byte UP3I_FINISHING_OPERATION = (byte)0x8E; - public static final byte COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR = (byte)0x91; - public static final byte RENDERING_INTENT = (byte)0x95; - public static final byte CMR_TAG_FIDELITY = (byte)0x96; - public static final byte DEVICE_APPEARANCE = (byte)0x97; +public abstract class AbstractTriplet extends AbstractAFPObject implements Triplet { /** the triplet identifier */ protected final byte id; diff --git a/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java new file mode 100644 index 000000000..2f924d585 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java @@ -0,0 +1,67 @@ +/* + * 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.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The attribute qualifier triplet is used to specify a qualifier for a document + * attribute. + */ +public class AttributeQualifierTriplet extends AbstractTriplet { + + private int seqNumber; + private int levNumber; + + /** + * Main constructor + * + * @param seqNumber the attribute qualifier sequence number + * @param levNumber the attribute qualifier level number + */ + public AttributeQualifierTriplet(int seqNumber, int levNumber) { + super(ATTRIBUTE_QUALIFIER); + this.seqNumber = seqNumber; + this.levNumber = levNumber; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + byte[] id = BinaryUtils.convert(seqNumber, 4); + System.arraycopy(id, 0, data, 2, id.length); + byte[] level = BinaryUtils.convert(levNumber, 4); + System.arraycopy(level, 0, data, 6, level.length); + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 10; + } + + /** {@inheritDoc} */ + public String toString() { + return "seqNumber=" + seqNumber + ", levNumber=" + levNumber; + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java new file mode 100644 index 000000000..ec2ae8d7c --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java @@ -0,0 +1,72 @@ +/* + * 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.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.apache.fop.afp.AFPConstants; + +/** + * The attribute value triplet is used to specify a value for a document + * attribute. + */ +public class AttributeValueTriplet extends AbstractTriplet { + private String attVal; + + /** + * Main constructor + * + * @param attVal an attribute value + */ + public AttributeValueTriplet(String attVal) { + super(ATTRIBUTE_VALUE); + this.attVal = truncate(attVal, MAX_LENGTH - 4); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = super.getData(); + data[2] = 0x00; // Reserved + data[3] = 0x00; // Reserved + + // convert name and value to ebcdic + byte[] tleByteValue = null; + try { + tleByteValue = attVal.getBytes(AFPConstants.EBCIDIC_ENCODING); + } catch (UnsupportedEncodingException usee) { + tleByteValue = attVal.getBytes(); + throw new IllegalArgumentException(attVal + " encoding failed"); + } + System.arraycopy(tleByteValue, 0, data, 4, tleByteValue.length); + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 4 + attVal.length(); + } + + /** {@inheritDoc} */ + public String toString() { + return attVal; + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/Triplet.java b/src/java/org/apache/fop/afp/modca/triplets/Triplet.java new file mode 100644 index 000000000..726727e3e --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/Triplet.java @@ -0,0 +1,85 @@ +/* + * 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.modca.triplets; + +import org.apache.fop.afp.Streamable; +import org.apache.fop.afp.StructuredData; + +public interface Triplet extends Streamable, StructuredData { + int MAX_LENGTH = 254; + + byte CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER = 0x01; + + /** Triplet identifiers */ + byte FULLY_QUALIFIED_NAME = 0x02; + byte MAPPING_OPTION = 0x04; + byte OBJECT_CLASSIFICATION = 0x10; + byte MODCA_INTERCHANGE_SET = 0x18; + byte FONT_DESCRIPTOR_SPECIFICATION = 0x1F; + byte OBJECT_FUNCTION_SET_SPECIFICATION = 0x21; + byte EXTENDED_RESOURCE_LOCAL_IDENTIFIER = 0x22; + byte RESOURCE_LOCAL_IDENTIFIER = 0x24; + byte RESOURCE_SECTION_NUMBER = 0x25; + byte CHARACTER_ROTATION = 0x26; + byte OBJECT_BYTE_OFFSET = 0x2D; + byte ATTRIBUTE_VALUE = 0x36; + byte DESCRIPTOR_POSITION = 0x43; + byte MEDIA_EJECT_CONTROL = 0x45; + byte PAGE_OVERLAY_CONDITIONAL_PROCESSING = 0x46; + byte RESOURCE_USAGE_ATTRIBUTE = 0x47; + byte MEASUREMENT_UNITS = 0x4B; + byte OBJECT_AREA_SIZE = 0x4C; + byte AREA_DEFINITION = 0x4D; + byte COLOR_SPECIFICATION = 0x4E; + byte ENCODING_SCHEME_ID = 0x50; + byte MEDIUM_MAP_PAGE_NUMBER = 0x56; + byte OBJECT_BYTE_EXTENT = 0x57; + byte OBJECT_STRUCTURED_FIELD_OFFSET = 0x58; + byte OBJECT_STRUCTURED_FIELD_EXTENT = 0x59; + byte OBJECT_OFFSET = 0x5A; + byte FONT_HORIZONTAL_SCALE_FACTOR = 0x5D; + byte OBJECT_COUNT = 0x5E; + byte OBJECT_DATE_AND_TIMESTAMP = 0x62; + byte COMMENT = 0x65; + byte MEDIUM_ORIENTATION = 0x68; + byte RESOURCE_OBJECT_INCLUDE = 0x6C; + byte PRESENTATION_SPACE_RESET_MIXING = 0x70; + byte PRESENTATION_SPACE_MIXING_RULE = 0x71; + byte UNIVERSAL_DATE_AND_TIMESTAMP = 0x72; + byte TONER_SAVER = 0x74; + byte COLOR_FIDELITY = 0x75; + byte FONT_FIDELITY = 0x78; + byte ATTRIBUTE_QUALIFIER = (byte)0x80; + byte PAGE_POSITION_INFORMATION = (byte)0x81; + byte PARAMETER_VALUE = (byte)0x82; + byte PRESENTATION_CONTROL = (byte)0x83; + byte FONT_RESOLUTION_AND_METRIC_TECHNOLOGY = (byte)0x84; + byte FINISHING_OPERATION = (byte)0x85; + byte TEXT_FIDELITY = (byte)0x86; + byte MEDIA_FIDELITY = (byte)0x87; + byte FINISHING_FIDELITY = (byte)0x88; + byte DATA_OBJECT_FONT_DESCRIPTOR = (byte)0x8B; + byte LOCALE_SELECTOR = (byte)0x8C; + byte UP3I_FINISHING_OPERATION = (byte)0x8E; + byte COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR = (byte)0x91; + byte RENDERING_INTENT = (byte)0x95; + byte CMR_TAG_FIDELITY = (byte)0x96; + byte DEVICE_APPEARANCE = (byte)0x97; +} diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index 043dfe3c8..2e6e204a8 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -109,6 +109,8 @@ public class CommandLineOptions { private boolean useStdIn = false; /* true if System.out (stdout) should be used for the output file */ private boolean useStdOut = false; + /* true if a catalog resolver should be used for entity and uri resolution */ + private boolean useCatalogResolver = false; /* rendering options (for the user agent) */ private Map renderingOptions = new java.util.HashMap(); /* target resolution (for the user agent) */ @@ -354,6 +356,8 @@ public class CommandLineOptions { } else { throw new FOPException("invalid param usage: use -param <name> <value>"); } + } else if (args[i].equals("-catalog")) { + useCatalogResolver = true; } else if (args[i].equals("-o")) { i = i + parsePDFOwnerPassword(args, i); } else if (args[i].equals("-u")) { @@ -1024,7 +1028,7 @@ public class CommandLineOptions { case IF_INPUT: return new IFInputHandler(iffile); case XSLT_INPUT: - return new InputHandler(xmlfile, xsltfile, xsltParams); + return new InputHandler(xmlfile, xsltfile, xsltParams, useCatalogResolver); case IMAGE_INPUT: return new ImageInputHandler(imagefile, xsltfile, xsltParams); default: @@ -1166,6 +1170,7 @@ public class CommandLineOptions { + " -xsl stylesheet xslt stylesheet \n \n" + " -param name value <value> to use for parameter <name> in xslt stylesheet\n" + " (repeat '-param name value' for each parameter)\n \n" + + " -catalog use catalog resolver for input XML and XSLT files\n" + " [OUTPUT] \n" + " outfile input will be rendered as PDF into outfile\n" + " (use '-' for outfile to pipe output to stdout)\n" diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java index 4f49ea269..a1ff1715b 100644 --- a/src/java/org/apache/fop/cli/InputHandler.java +++ b/src/java/org/apache/fop/cli/InputHandler.java @@ -19,7 +19,6 @@ package org.apache.fop.cli; -// Imported java.io classes import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; @@ -34,11 +33,13 @@ import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -51,27 +52,27 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.render.awt.viewer.Renderable; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; /** * Class for handling files input from command line * either with XML and XSLT files (and optionally xsl - * parameters) or FO File input alone + * parameters) or FO File input alone. */ public class InputHandler implements ErrorListener, Renderable { /** original source file */ - protected File sourcefile = null; - private File stylesheet = null; // for XML/XSLT usage - private Vector xsltParams = null; // for XML/XSLT usage + protected File sourcefile; + private File stylesheet; // for XML/XSLT usage + private Vector xsltParams; // for XML/XSLT usage + private EntityResolver entityResolver; + private URIResolver uriResolver; /** the logger */ protected Log log = LogFactory.getLog(InputHandler.class); /** * Constructor for XML->XSLT->FO input + * * @param xmlfile XML file * @param xsltfile XSLT file * @param params Vector of command-line parameters (name, value, @@ -84,6 +85,23 @@ public class InputHandler implements ErrorListener, Renderable { } /** + * Constructor for XML->XSLT->FO input + * + * @param xmlfile XML file + * @param xsltfile XSLT file + * @param params Vector of command-line parameters (name, value, + * name, value, ...) for XSL stylesheet, null if none + * @param useCatalogResolver if true, use a catalog resolver + * for XML parsing and XSLT URI resolution + */ + public InputHandler(File xmlfile, File xsltfile, Vector params, boolean useCatalogResolver) { + this(xmlfile, xsltfile, params); + if (useCatalogResolver) { + createCatalogResolver(); + } + } + + /** * Constructor for FO input * @param fofile the file to read the FO document. */ @@ -151,7 +169,7 @@ public class InputHandler implements ErrorListener, Renderable { * @return the Source for the main input file */ protected Source createMainSource() { - Source result; + Source source; InputStream in; String uri; if (this.sourcefile != null) { @@ -169,37 +187,91 @@ public class InputHandler implements ErrorListener, Renderable { try { InputSource is = new InputSource(in); is.setSystemId(uri); - SAXParserFactory spf = SAXParserFactory.newInstance(); - spf.setFeature("http://xml.org/sax/features/namespaces", true); - spf.setFeature("http://apache.org/xml/features/xinclude", true); - XMLReader xr = spf.newSAXParser().getXMLReader(); - result = new SAXSource(xr, is); + XMLReader xr = getXMLReader(); + if (entityResolver != null) { + xr.setEntityResolver(entityResolver); + } + source = new SAXSource(xr, is); } catch (SAXException e) { if (this.sourcefile != null) { - result = new StreamSource(this.sourcefile); + source = new StreamSource(this.sourcefile); } else { - result = new StreamSource(in, uri); + source = new StreamSource(in, uri); } } catch (ParserConfigurationException e) { if (this.sourcefile != null) { - result = new StreamSource(this.sourcefile); + source = new StreamSource(this.sourcefile); } else { - result = new StreamSource(in, uri); + source = new StreamSource(in, uri); + } + } + return source; + } + + /** + * Creates a catalog resolver and uses it for XML parsing and XSLT URI resolution. + * Tries the Apache Commons Resolver, and if unsuccessful, + * tries the same built into Java 6. + */ + private void createCatalogResolver() { + String[] classNames = new String[] { + "org.apache.xml.resolver.tools.CatalogResolver", + "com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver"}; + Class resolverClass = null; + for (int i = 0; i < classNames.length && resolverClass == null; ++i) { + try { + resolverClass = Class.forName(classNames[i]); + } catch (ClassNotFoundException e) { + // No worries } } - return result; + if (resolverClass == null) { + log.error("Could not find catalog resolver in class path"); + return; + } + try { + entityResolver = (EntityResolver) resolverClass.newInstance(); + uriResolver = (URIResolver) resolverClass.newInstance(); + } catch (InstantiationException e) { + log.error("Error creating the catalog resolver: " + e.getMessage()); + } catch (IllegalAccessException e) { + log.error("Error creating the catalog resolver: " + e.getMessage()); + } } /** * Creates a Source for the selected stylesheet. + * * @return the Source for the selected stylesheet or null if there's no stylesheet */ protected Source createXSLTSource() { + Source xslt = null; if (this.stylesheet != null) { - return new StreamSource(this.stylesheet); - } else { - return null; + if (entityResolver != null) { + try { + InputSource is = new InputSource(this.stylesheet.getPath()); + XMLReader xr = getXMLReader(); + xr.setEntityResolver(entityResolver); + xslt = new SAXSource(xr, is); + } catch (SAXException e) { + // return StreamSource + } catch (ParserConfigurationException e) { + // return StreamSource + } + } + if (xslt == null) { + xslt = new StreamSource(this.stylesheet); + } } + return xslt; + } + + private XMLReader getXMLReader() throws ParserConfigurationException, SAXException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setFeature("http://xml.org/sax/features/namespaces", true); + spf.setFeature("http://apache.org/xml/features/xinclude", true); + XMLReader xr = spf.newSAXParser().getXMLReader(); + return xr; } /** @@ -226,6 +298,9 @@ public class InputHandler implements ErrorListener, Renderable { (String) xsltParams.elementAt(i + 1)); } } + if (uriResolver != null) { + transformer.setURIResolver(uriResolver); + } } transformer.setErrorListener(this); diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 2ebfaaf95..133d932bc 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -56,7 +56,7 @@ public abstract class FObj extends FONode implements Constants { private List/*<ExtensionAttachment>*/ extensionAttachments = null; /** The map of foreign attributes, null if none */ - private Map foreignAttributes = null; + private Map/*<QName,String>*/ foreignAttributes = null; /** Used to indicate if this FO is either an Out Of Line FO (see rec) * or a descendant of one. Used during FO validation. @@ -591,7 +591,7 @@ public abstract class FObj extends FONode implements Constants { throw new NullPointerException("Parameter attributeName must not be null"); } if (foreignAttributes == null) { - foreignAttributes = new java.util.HashMap(); + foreignAttributes = new java.util.HashMap/*<QName,String>*/(); } foreignAttributes.put(attributeName, value); } diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java index c2505488b..6be4007ea 100644 --- a/src/java/org/apache/fop/fonts/CIDSubset.java +++ b/src/java/org/apache/fop/fonts/CIDSubset.java @@ -161,12 +161,12 @@ public class CIDSubset { } /** - * Returns a BitSet with bits set for each available glyph index. + * Returns a BitSet with bits set for each available glyph index in the subset. * @return a BitSet indicating available glyph indices */ public BitSet getGlyphIndexBitSet() { BitSet bitset = new BitSet(); - Iterator iter = usedGlyphs.keySet().iterator(); + Iterator iter = usedGlyphsIndex.keySet().iterator(); while (iter.hasNext()) { Integer cid = (Integer)iter.next(); bitset.set(cid.intValue()); diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index e9740c00c..d0a87efbf 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -170,6 +170,9 @@ public class Font { /** * Returns the amount of kerning between two characters. + * + * The value returned measures in pt. So it is already adjusted for font size. + * * @param ch1 first character * @param ch2 second character * @return the distance to adjust for kerning, 0 if there's no kerning @@ -179,7 +182,7 @@ public class Font { if (kernPair != null) { Integer width = (Integer)kernPair.get(new Integer(ch2)); if (width != null) { - return width.intValue(); + return width.intValue() * getFontSize() / 1000; } } return 0; diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java index 1a6f7cfb9..53a52597b 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java @@ -367,7 +367,7 @@ public abstract class AbstractBreaker { alg.setConstantLineWidth(flowBPD); int optimalPageCount = alg.findBreakingPoints(effectiveList, 1, true, BreakingAlgorithm.ALL_BREAKS); - if (alg.ipdChanged()) { + if (alg.getIPDdifference() != 0) { KnuthNode optimalBreak = alg.getBestNodeBeforeIPDChange(); int positionIndex = optimalBreak.position; KnuthElement elementAtBreak = alg.getElement(positionIndex); @@ -381,14 +381,19 @@ public abstract class AbstractBreaker { LayoutManager restartAtLM = null; List firstElements = Collections.EMPTY_LIST; if (containsNonRestartableLM(positionAtBreak)) { + if (alg.getIPDdifference() > 0) { + log.warn("Content that cannot handle IPD changes is flowing to a" + + " narrower page. Part of it may be clipped" + + " by the page border."); + } firstElements = new LinkedList(); boolean boxFound = false; - Iterator iter = effectiveList.listIterator(++positionIndex); + Iterator iter = effectiveList.listIterator(positionIndex + 1); Position position = null; while (iter.hasNext() && (position == null || containsNonRestartableLM(position))) { - KnuthElement element = (KnuthElement) iter.next(); positionIndex++; + KnuthElement element = (KnuthElement) iter.next(); position = element.getPosition(); if (element.isBox()) { boxFound = true; @@ -400,9 +405,11 @@ public abstract class AbstractBreaker { if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) { /* Retrieve the original position wrapped into this space position */ positionAtBreak = position.getPosition(); + } else { + positionAtBreak = null; } } - if (positionAtBreak.getIndex() == -1) { + if (positionAtBreak != null && positionAtBreak.getIndex() == -1) { /* * This is an indication that we are between two blocks * (possibly surrounded by another block), not inside a @@ -588,7 +595,7 @@ public abstract class AbstractBreaker { .listIterator(startElementIndex); while (effectiveListIterator.nextIndex() <= endElementIndex) { KnuthElement tempEl = (KnuthElement)effectiveListIterator.next(); - if (tempEl.isBox() && tempEl.getW() > 0) { + if (tempEl.isBox() && tempEl.getWidth() > 0) { boxCount++; } } @@ -678,8 +685,23 @@ public abstract class AbstractBreaker { BlockSequence blockList; List returnedList; - if (positionAtIPDChange == null) { + if (firstElements == null) { returnedList = getNextKnuthElements(childLC, alignment); + } else if (positionAtIPDChange == null) { + /* + * No restartable element found after changing IPD break. Simply add the + * non-restartable elements found after the break. + */ + returnedList = firstElements; + /* + * Remove the last 3 penalty-filler-forced break elements that were added by + * the Knuth algorithm. They will be re-added later on. + */ + ListIterator iter = returnedList.listIterator(returnedList.size()); + for (int i = 0; i < 3; i++) { + iter.previous(); + iter.remove(); + } } else { returnedList = getNextKnuthElements(childLC, alignment, positionAtIPDChange, restartAtLM); @@ -861,9 +883,9 @@ public abstract class AbstractBreaker { case BlockLevelLayoutManager.LINE_NUMBER_ADJUSTMENT: // potential line number adjustment lineNumberMaxAdjustment.max += ((KnuthGlue) thisElement) - .getY(); + .getStretch(); lineNumberMaxAdjustment.min -= ((KnuthGlue) thisElement) - .getZ(); + .getShrink(); adjustableLinesList.add(thisElement); break; case BlockLevelLayoutManager.LINE_HEIGHT_ADJUSTMENT: @@ -885,9 +907,9 @@ public abstract class AbstractBreaker { KnuthGlue blockSpace = (KnuthGlue) unconfirmedList .removeFirst(); spaceMaxAdjustment.max += ((KnuthGlue) blockSpace) - .getY(); + .getStretch(); spaceMaxAdjustment.min -= ((KnuthGlue) blockSpace) - .getZ(); + .getShrink(); blockSpacesList.add(blockSpace); } } @@ -898,11 +920,11 @@ public abstract class AbstractBreaker { log.debug("| space adj = " + spaceMaxAdjustment); - if (thisElement.isPenalty() && thisElement.getW() > 0) { + if (thisElement.isPenalty() && thisElement.getWidth() > 0) { log.debug(" mandatory variation to the number of lines!"); ((BlockLevelLayoutManager) thisElement .getLayoutManager()).negotiateBPDAdjustment( - thisElement.getW(), thisElement); + thisElement.getWidth(), thisElement); } if (thisBreak.bpdAdjust != 0 @@ -967,7 +989,7 @@ public abstract class AbstractBreaker { int partial = 0; while (spaceListIterator.hasNext()) { KnuthGlue blockSpace = (KnuthGlue)spaceListIterator.next(); - partial += (difference > 0 ? blockSpace.getY() : blockSpace.getZ()); + partial += (difference > 0 ? blockSpace.getStretch() : blockSpace.getShrink()); if (log.isDebugEnabled()) { log.debug("available = " + partial + " / " + total); log.debug("competenza = " @@ -990,7 +1012,7 @@ public abstract class AbstractBreaker { int partial = 0; while (lineListIterator.hasNext()) { KnuthGlue line = (KnuthGlue)lineListIterator.next(); - partial += (difference > 0 ? line.getY() : line.getZ()); + partial += (difference > 0 ? line.getStretch() : line.getShrink()); int newAdjust = ((BlockLevelLayoutManager) line.getLayoutManager()).negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, line); adjustedDiff += newAdjust; } diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index e86c5feaf..3378d86d7 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -1133,7 +1133,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager // by this BlockLM, and must be ignored if (element.getLayoutManager() != this) { splitList.add(element); - splitLength += element.getW(); + splitLength += element.getWidth(); lastLM = element.getLayoutManager(); } } diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java index 53dc5b38c..d7453a399 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -339,7 +339,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager // by this BlockLM, and must be ignored if (element.getLayoutManager() != this) { splitList.add(element); - splitLength += element.getW(); + splitLength += element.getWidth(); lastLM = element.getLayoutManager(); } } diff --git a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java index 9a0dbe220..92a423098 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java @@ -695,11 +695,11 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> bpunit con penalty"); KnuthPenalty storedPenalty = (KnuthPenalty) storedList.get(mappingPos.getLastIndex()); - if (storedPenalty.getW() > 0) { + if (storedPenalty.getWidth() > 0) { // the original penalty has width > 0 /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> chiamata passata"); return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager()) - .negotiateBPDAdjustment(storedPenalty.getW(), + .negotiateBPDAdjustment(storedPenalty.getWidth(), storedPenalty); } else { // the original penalty has width = 0 @@ -1406,17 +1406,18 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager while (oldListIterator.hasNext()) { KnuthElement element = (KnuthElement) oldListIterator.next(); if (element.isBox()) { - totalLength.add(new MinOptMax(element.getW())); - //log.debug("box " + element.getW()); + totalLength.add(new MinOptMax(element.getWidth())); + //log.debug("box " + element.getWidth()); } else if (element.isGlue()) { - totalLength.min -= element.getZ(); - totalLength.max += element.getY(); + totalLength.min -= element.getShrink(); + totalLength.max += element.getStretch(); //leafValue = ((LeafPosition) element.getPosition()).getLeafPos(); - //log.debug("glue " + element.getW() + " + " - // + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ()); + //log.debug("glue " + element.getWidth() + " + " + // + ((KnuthGlue) element).getStretch() + " - " + // + ((KnuthGlue) element).getShrink()); } else { - //log.debug((((KnuthPenalty)element).getP() == KnuthElement.INFINITE - // ? "PENALTY " : "penalty ") + element.getW()); + //log.debug((((KnuthPenalty)element).getPenalty() == KnuthElement.INFINITE + // ? "PENALTY " : "penalty ") + element.getWidth()); } } // compute the total amount of "units" @@ -1443,22 +1444,22 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager KnuthElement element = (KnuthElement) oldListIterator.next(); lastIndex++; if (element.isBox()) { - lengthBeforeBreak.add(new MinOptMax(element.getW())); - lengthAfterBreak.subtract(new MinOptMax(element.getW())); + lengthBeforeBreak.add(new MinOptMax(element.getWidth())); + lengthAfterBreak.subtract(new MinOptMax(element.getWidth())); bPrevIsBox = true; } else if (element.isGlue()) { - lengthBeforeBreak.min -= element.getZ(); - lengthAfterBreak.min += element.getZ(); - lengthBeforeBreak.max += element.getY(); - lengthAfterBreak.max -= element.getY(); + lengthBeforeBreak.min -= element.getShrink(); + lengthAfterBreak.min += element.getShrink(); + lengthBeforeBreak.max += element.getStretch(); + lengthAfterBreak.max -= element.getStretch(); bPrevIsBox = false; } else { - lengthBeforeBreak.add(new MinOptMax(element.getW())); + lengthBeforeBreak.add(new MinOptMax(element.getWidth())); bPrevIsBox = false; } // create the new elements - if (element.isPenalty() && element.getP() < KnuthElement.INFINITE + if (element.isPenalty() && element.getPenalty() < KnuthElement.INFINITE || element.isGlue() && bPrevIsBox || !oldListIterator.hasNext()) { // suppress elements after the breaking point @@ -1468,8 +1469,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager iStepsForward++; if (el.isGlue()) { // suppressed glue - lengthAfterBreak.min += el.getZ(); - lengthAfterBreak.max -= el.getY(); + lengthAfterBreak.min += el.getShrink(); + lengthAfterBreak.max -= el.getStretch(); } else if (el.isPenalty()) { // suppressed penalty, do nothing } else { @@ -1489,8 +1490,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager for (int i = 0; i < iStepsForward; i++) { KnuthElement el = (KnuthElement) oldListIterator.previous(); if (el.isGlue()) { - lengthAfterBreak.min -= el.getZ(); - lengthAfterBreak.max += el.getY(); + lengthAfterBreak.min -= el.getShrink(); + lengthAfterBreak.max += el.getStretch(); } } @@ -1611,7 +1612,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager } if (element.isPenalty()) { - lengthBeforeBreak.add(new MinOptMax(-element.getW())); + lengthBeforeBreak.add(new MinOptMax(-element.getWidth())); } } @@ -1640,14 +1641,14 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager - neededUnits(totalLength.opt - adjustedSpaceBefore)) * bpUnit; // insert the correct elements - newList.addFirst(new KnuthBox(wrongBox.getW() - decreasedLength, + newList.addFirst(new KnuthBox(wrongBox.getWidth() - decreasedLength, wrongBox.getPosition(), false)); newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT, wrongBox.getPosition(), false)); - //log.debug(" rimosso box " + neededUnits(wrongBox.getW())); + //log.debug(" rimosso box " + neededUnits(wrongBox.getWidth())); //log.debug(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0"); //log.debug(" aggiunto box " + neededUnits( - // wrongBox.getW() - decreasedLength)); + // wrongBox.getWidth() - decreasedLength)); } // if space-after.conditionality is "discard", correct newList @@ -1663,7 +1664,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager // (it cannot be parted and has some stretch or shrink) // the wrong box is the first one, not the last one LinkedList preserveList = new LinkedList(); - if (wrongBox.getW() == 0) { + if (wrongBox.getWidth() == 0) { preserveList.add(wrongBox); preserveList.addFirst((KnuthGlue) newList.removeLast()); preserveList.addFirst((KnuthPenalty) newList.removeLast()); @@ -1676,7 +1677,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager - neededUnits(totalLength.opt - adjustedSpaceAfter)) * bpUnit; // insert the correct box - newList.addLast(new KnuthBox(wrongBox.getW() - decreasedLength, + newList.addLast(new KnuthBox(wrongBox.getWidth() - decreasedLength, wrongBox.getPosition(), false)); // add preserved elements if (!preserveList.isEmpty()) { @@ -1685,9 +1686,9 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager // insert the correct glue newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT, wrongBox.getPosition(), false)); - //log.debug(" rimosso box " + neededUnits(wrongBox.getW())); + //log.debug(" rimosso box " + neededUnits(wrongBox.getWidth())); //log.debug(" aggiunto box " + neededUnits( - // wrongBox.getW() - decreasedLength)); + // wrongBox.getWidth() - decreasedLength)); //log.debug(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0"); } diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java index 3a688cce8..4516c8d97 100644 --- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java @@ -491,7 +491,7 @@ public abstract class BreakingAlgorithm { elementIndex, previousIsBox, allowedBreaks).isBox(); if (activeNodeCount == 0) { - if (ipdChanged()) { + if (getIPDdifference() != 0) { return handleIpdChange(); } if (!force) { @@ -538,8 +538,8 @@ public abstract class BreakingAlgorithm { return line; } - protected boolean ipdChanged() { - return false; + protected int getIPDdifference() { + return 0; } protected int handleIpdChange() { @@ -676,7 +676,7 @@ public abstract class BreakingAlgorithm { protected void handleBox(KnuthBox box) { // a KnuthBox object is not a legal line break, // just add the width to the total - totalWidth += box.getW(); + totalWidth += box.getWidth(); } /** @@ -697,9 +697,9 @@ public abstract class BreakingAlgorithm { && !(allowedBreaks == ONLY_FORCED_BREAKS)) { considerLegalBreak(glue, position); } - totalWidth += glue.getW(); - totalStretch += glue.getY(); - totalShrink += glue.getZ(); + totalWidth += glue.getWidth(); + totalStretch += glue.getStretch(); + totalShrink += glue.getShrink(); } /** @@ -716,8 +716,8 @@ public abstract class BreakingAlgorithm { // only if its penalty is not infinite; // consider all penalties, non-flagged penalties or non-forcing penalties // according to the value of allowedBreaks - if (((penalty.getP() < KnuthElement.INFINITE) - && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isFlagged()) + if (((penalty.getPenalty() < KnuthElement.INFINITE) + && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isPenaltyFlagged()) && (!(allowedBreaks == ONLY_FORCED_BREAKS) || penalty.isForcedBreak()))) { considerLegalBreak(penalty, position); @@ -880,7 +880,7 @@ public abstract class BreakingAlgorithm { */ protected boolean elementCanEndLine(KnuthElement element, int line, int difference) { return (!element.isPenalty() - || element.getP() < KnuthElement.INFINITE); + || element.getPenalty() < KnuthElement.INFINITE); } /** @@ -921,9 +921,9 @@ public abstract class BreakingAlgorithm { if (tempElement.isBox()) { break; } else if (tempElement.isGlue()) { - newWidth += tempElement.getW(); - newStretch += tempElement.getY(); - newShrink += tempElement.getZ(); + newWidth += tempElement.getWidth(); + newStretch += tempElement.getStretch(); + newShrink += tempElement.getShrink(); } else if (tempElement.isForcedBreak() && i != elementIdx) { break; } @@ -1034,9 +1034,9 @@ public abstract class BreakingAlgorithm { if (tempElement.isBox()) { break; } else if (tempElement.isGlue()) { - newWidth += tempElement.getW(); - newStretch += tempElement.getY(); - newShrink += tempElement.getZ(); + newWidth += tempElement.getWidth(); + newStretch += tempElement.getStretch(); + newShrink += tempElement.getShrink(); } else if (tempElement.isForcedBreak() && i != elementIdx) { break; } @@ -1075,7 +1075,7 @@ public abstract class BreakingAlgorithm { // compute the adjustment ratio int actualWidth = totalWidth - activeNode.totalWidth; if (element.isPenalty()) { - actualWidth += element.getW(); + actualWidth += element.getWidth(); } return getLineWidth() - actualWidth; } @@ -1133,7 +1133,7 @@ public abstract class BreakingAlgorithm { double f = Math.abs(r); f = 1 + 100 * f * f * f; if (element.isPenalty()) { - double penalty = element.getP(); + double penalty = element.getPenalty(); if (penalty >= 0) { f += penalty; demerits = f * f; @@ -1146,9 +1146,9 @@ public abstract class BreakingAlgorithm { demerits = f * f; } - if (element.isPenalty() && ((KnuthPenalty) element).isFlagged() + if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged() && getElement(activeNode.position).isPenalty() - && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) { + && ((KnuthPenalty) getElement(activeNode.position)).isPenaltyFlagged()) { // add demerit for consecutive breaks at flagged penalties demerits += repeatedFlaggedDemerit; // there are at least two consecutive lines ending with a flagged penalty; @@ -1160,7 +1160,7 @@ public abstract class BreakingAlgorithm { prevNode = prevNode.previous) { KnuthElement prevElement = getElement(prevNode.position); if (prevElement.isPenalty() - && ((KnuthPenalty) prevElement).isFlagged()) { + && ((KnuthPenalty) prevElement).isPenaltyFlagged()) { // the previous line ends with a flagged penalty too flaggedPenaltiesCount++; } else { diff --git a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java index d3403cd6b..ca11d27c2 100644 --- a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java +++ b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java @@ -62,13 +62,14 @@ public final class ElementListUtils { if (el.isPenalty()) { KnuthPenalty penalty = (KnuthPenalty)el; //Convert all penalties to break inhibitors - if (penalty.getP() < KnuthPenalty.INFINITE) { - iter.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE, - penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary())); + if (penalty.getPenalty() < KnuthPenalty.INFINITE) { + iter.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE, + penalty.isPenaltyFlagged(), penalty.getPosition(), + penalty.isAuxiliary())); } } else if (el.isGlue()) { KnuthGlue glue = (KnuthGlue)el; - len += glue.getW(); + len += glue.getWidth(); iter.previous(); el = (ListElement)iter.previous(); iter.next(); @@ -84,7 +85,7 @@ public final class ElementListUtils { } } else { KnuthElement kel = (KnuthElement)el; - len += kel.getW(); + len += kel.getWidth(); } if (len >= constraint) { return false; @@ -109,13 +110,14 @@ public final class ElementListUtils { if (el.isPenalty()) { KnuthPenalty penalty = (KnuthPenalty)el; //Convert all penalties to break inhibitors - if (penalty.getP() < KnuthPenalty.INFINITE) { - i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE, - penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary())); + if (penalty.getPenalty() < KnuthPenalty.INFINITE) { + i.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE, + penalty.isPenaltyFlagged(), penalty.getPosition(), + penalty.isAuxiliary())); } } else if (el.isGlue()) { KnuthGlue glue = (KnuthGlue)el; - len += glue.getW(); + len += glue.getWidth(); el = (ListElement)i.previous(); i.next(); if (el.isBox()) { @@ -134,7 +136,7 @@ public final class ElementListUtils { } } else { KnuthElement kel = (KnuthElement)el; - len += kel.getW(); + len += kel.getWidth(); } if (len >= constraint) { return false; @@ -158,9 +160,9 @@ public final class ElementListUtils { while (iter.hasNext()) { ListElement el = (ListElement)iter.next(); if (el.isBox()) { - len += ((KnuthElement)el).getW(); + len += ((KnuthElement)el).getWidth(); } else if (el.isGlue()) { - len += ((KnuthElement)el).getW(); + len += ((KnuthElement)el).getWidth(); } else { //log.debug("Ignoring penalty: " + el); //ignore penalties @@ -210,7 +212,7 @@ public final class ElementListUtils { */ public static boolean endsWithNonInfinitePenalty(List elems) { ListElement last = (ListElement) ListUtil.getLast(elems); - if (last.isPenalty() && ((KnuthPenalty)last).getP() < KnuthElement.INFINITE) { + if (last.isPenalty() && ((KnuthPenalty)last).getPenalty() < KnuthElement.INFINITE) { return true; } else if (last instanceof BreakElement && ((BreakElement)last).getPenaltyValue() < KnuthElement.INFINITE) { @@ -230,7 +232,7 @@ public final class ElementListUtils { int prevBreak = startIndex - 1; while (prevBreak >= 0) { KnuthElement el = (KnuthElement)elems.get(prevBreak); - if (el.isPenalty() && el.getP() < KnuthElement.INFINITE) { + if (el.isPenalty() && el.getPenalty() < KnuthElement.INFINITE) { break; } prevBreak--; diff --git a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java index 104c71131..0d00b710a 100644 --- a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java +++ b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java @@ -72,7 +72,7 @@ public class InlineKnuthSequence extends KnuthSequence { lastOldElement = getLast(); firstNewElement = sequence.getElement(0); if (firstNewElement.isBox() && !((KnuthElement) firstNewElement).isAuxiliary() - && lastOldElement.isBox() && ((KnuthElement) lastOldElement).getW() != 0) { + && lastOldElement.isBox() && ((KnuthElement) lastOldElement).getWidth() != 0) { addALetterSpace(); } addAll(sequence); diff --git a/src/java/org/apache/fop/layoutmgr/KnuthBox.java b/src/java/org/apache/fop/layoutmgr/KnuthBox.java index 7c3df61fa..d7615dda1 100644 --- a/src/java/org/apache/fop/layoutmgr/KnuthBox.java +++ b/src/java/org/apache/fop/layoutmgr/KnuthBox.java @@ -37,12 +37,12 @@ public class KnuthBox extends KnuthElement { /** * Create a new KnuthBox. * - * @param w the width of this box + * @param width the width of this box * @param pos the Position stored in this box - * @param bAux is this box auxiliary? + * @param auxiliary is this box auxiliary? */ - public KnuthBox(int w, Position pos, boolean bAux) { - super(w, pos, bAux); + public KnuthBox(int width, Position pos, boolean auxiliary) { + super(width, pos, auxiliary); } /** {@inheritDoc} */ @@ -52,14 +52,14 @@ public class KnuthBox extends KnuthElement { /** {@inheritDoc} */ public String toString() { - StringBuffer sb = new StringBuffer(64); + StringBuffer buffer = new StringBuffer(64); if (isAuxiliary()) { - sb.append("aux. "); + buffer.append("aux. "); } - sb.append("box"); - sb.append(" w="); - sb.append(getW()); - return sb.toString(); + buffer.append("box"); + buffer.append(" w="); + buffer.append(getWidth()); + return buffer.toString(); } } diff --git a/src/java/org/apache/fop/layoutmgr/KnuthElement.java b/src/java/org/apache/fop/layoutmgr/KnuthElement.java index 41c813010..e8ca6d85b 100644 --- a/src/java/org/apache/fop/layoutmgr/KnuthElement.java +++ b/src/java/org/apache/fop/layoutmgr/KnuthElement.java @@ -33,44 +33,44 @@ public abstract class KnuthElement extends ListElement { public static final int INFINITE = 1000; private int width; - private boolean bIsAuxiliary; + private boolean auxiliary; /** * Create a new KnuthElement. * This class being abstract, this can be called only by subclasses. * - * @param w the width of this element + * @param width the width of this element * @param pos the Position stored in this element - * @param bAux is this an auxiliary element? + * @param auxiliary is this an auxiliary element? */ - protected KnuthElement(int w, Position pos, boolean bAux) { + protected KnuthElement(int width, Position pos, boolean auxiliary) { super(pos); - width = w; - bIsAuxiliary = bAux; + this.width = width; + this.auxiliary = auxiliary; } /** @return true if this element is an auxiliary one. */ public boolean isAuxiliary() { - return bIsAuxiliary; + return auxiliary; } /** @return the width of this element. */ - public int getW() { + public int getWidth() { return width; } /** @return the penalty value of this element, if applicable. */ - public int getP() { + public int getPenalty() { throw new RuntimeException("Element is not a penalty"); } /** @return the stretch value of this element, if applicable. */ - public int getY() { + public int getStretch() { throw new RuntimeException("Element is not a glue"); } /** @return the shrink value of this element, if applicable. */ - public int getZ() { + public int getShrink() { throw new RuntimeException("Element is not a glue"); } diff --git a/src/java/org/apache/fop/layoutmgr/KnuthGlue.java b/src/java/org/apache/fop/layoutmgr/KnuthGlue.java index fbb291f6b..7533a4117 100644 --- a/src/java/org/apache/fop/layoutmgr/KnuthGlue.java +++ b/src/java/org/apache/fop/layoutmgr/KnuthGlue.java @@ -54,24 +54,25 @@ public class KnuthGlue extends KnuthElement { /** * Create a new KnuthGlue. * - * @param w the width of this glue - * @param y the stretchability of this glue - * @param z the shrinkability of this glue + * @param width the width of this glue + * @param stretchability the stretchability of this glue + * @param shrinkability the shrinkability of this glue * @param pos the Position stored in this glue - * @param bAux is this glue auxiliary? + * @param auxiliary is this glue auxiliary? */ - public KnuthGlue(int w, int y, int z, Position pos, boolean bAux) { - super(w, pos, bAux); - stretchability = y; - shrinkability = z; + public KnuthGlue(int width, int stretchability, int shrinkability, Position pos, + boolean auxiliary) { + super(width, pos, auxiliary); + this.stretchability = stretchability; + this.shrinkability = shrinkability; } - public KnuthGlue(int w, int y, int z, - int iAdjClass, Position pos, boolean bAux) { - super(w, pos, bAux); - stretchability = y; - shrinkability = z; - adjustmentClass = iAdjClass; + public KnuthGlue(int width, int stretchability, int shrinkability, int adjustmentClass, + Position pos, boolean auxiliary) { + super(width, pos, auxiliary); + this.stretchability = stretchability; + this.shrinkability = shrinkability; + this.adjustmentClass = adjustmentClass; } /** {@inheritDoc} */ @@ -80,12 +81,12 @@ public class KnuthGlue extends KnuthElement { } /** @return the stretchability of this glue. */ - public int getY() { + public int getStretch() { return stretchability; } /** @return the shrinkability of this glue. */ - public int getZ() { + public int getShrink() { return shrinkability; } @@ -96,18 +97,18 @@ public class KnuthGlue extends KnuthElement { /** {@inheritDoc} */ public String toString() { - StringBuffer sb = new StringBuffer(64); + StringBuffer buffer = new StringBuffer(64); if (isAuxiliary()) { - sb.append("aux. "); + buffer.append("aux. "); } - sb.append("glue"); - sb.append(" w=").append(getW()); - sb.append(" stretch=").append(getY()); - sb.append(" shrink=").append(getZ()); + buffer.append("glue"); + buffer.append(" w=").append(getWidth()); + buffer.append(" stretch=").append(getStretch()); + buffer.append(" shrink=").append(getShrink()); if (getAdjustmentClass() >= 0) { - sb.append(" adj-class=").append(getAdjustmentClass()); + buffer.append(" adj-class=").append(getAdjustmentClass()); } - return sb.toString(); + return buffer.toString(); } } diff --git a/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java b/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java index 9031b6b64..c17e9c7a2 100644 --- a/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java +++ b/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java @@ -45,39 +45,40 @@ public class KnuthPenalty extends KnuthElement { public static final int FLAGGED_PENALTY = 50; private int penalty; - private boolean isFlagged; + private boolean penaltyFlagged; private int breakClass = -1; /** * Create a new KnuthPenalty. * - * @param w the width of this penalty - * @param p the penalty value of this penalty - * @param f is this penalty flagged? + * @param width the width of this penalty + * @param penalty the penalty value of this penalty + * @param penaltyFlagged is this penalty flagged? * @param pos the Position stored in this penalty - * @param isAuxiliary is this penalty auxiliary? + * @param auxiliary is this penalty auxiliary? */ - public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) { - super(w, pos, isAuxiliary); - penalty = p; - isFlagged = f; + public KnuthPenalty(int width, int penalty, boolean penaltyFlagged, Position pos, + boolean auxiliary) { + super(width, pos, auxiliary); + this.penalty = penalty; + this.penaltyFlagged = penaltyFlagged; } /** * Create a new KnuthPenalty. * - * @param w the width of this penalty - * @param p the penalty value of this penalty - * @param f is this penalty flagged? + * @param width the width of this penalty + * @param penalty the penalty value of this penalty + * @param penaltyFlagged is this penalty flagged? * @param breakClass the break class of this penalty (one of * {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE}, * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}) * @param pos the Position stored in this penalty * @param isAuxiliary is this penalty auxiliary? */ - public KnuthPenalty(int w, int p, boolean f, - int breakClass, Position pos, boolean isAuxiliary) { - this(w, p, f, pos, isAuxiliary); + public KnuthPenalty(int width, int penalty, boolean penaltyFlagged, int breakClass, + Position pos, boolean isAuxiliary) { + this(width, penalty, penaltyFlagged, pos, isAuxiliary); this.breakClass = breakClass; } @@ -90,6 +91,8 @@ public class KnuthPenalty extends KnuthElement { * (Mainly used in {@link #toString()} methods, to improve readability * of the trace logs.) * + * TODO: shouldn't be penalty a class of its own? + * * @param penaltyValue the penalty value * @return the penalty value as a {@link java.lang.String} */ @@ -110,21 +113,21 @@ public class KnuthPenalty extends KnuthElement { /** * @return the penalty value of this penalty. */ - public int getP() { + public int getPenalty() { return penalty; } /** * Sets a new penalty value. - * @param p the new penalty value + * @param penalty the new penalty value */ - public void setP(int p) { - this.penalty = p; + public void setPenalty(int penalty) { + this.penalty = penalty; } /** @return true is this penalty is a flagged one. */ - public boolean isFlagged() { - return isFlagged; + public boolean isPenaltyFlagged() { + return penaltyFlagged; } /** {@inheritDoc} */ @@ -142,28 +145,28 @@ public class KnuthPenalty extends KnuthElement { /** {@inheritDoc} */ public String toString() { - StringBuffer sb = new StringBuffer(64); + StringBuffer buffer = new StringBuffer(64); if (isAuxiliary()) { - sb.append("aux. "); + buffer.append("aux. "); } - sb.append("penalty"); - sb.append(" p="); - sb.append(valueOf(this.penalty)); - if (this.isFlagged) { - sb.append(" [flagged]"); + buffer.append("penalty"); + buffer.append(" p="); + buffer.append(valueOf(this.penalty)); + if (this.penaltyFlagged) { + buffer.append(" [flagged]"); } - sb.append(" w="); - sb.append(getW()); + buffer.append(" w="); + buffer.append(getWidth()); if (isForcedBreak()) { - sb.append(" (forced break, ") + buffer.append(" (forced break, ") .append(getBreakClassName(this.breakClass)) .append(")"); } else if (this.penalty >= 0 && this.breakClass != -1) { //penalty corresponding to a keep constraint - sb.append(" (keep constraint, ") + buffer.append(" (keep constraint, ") .append(getBreakClassName(this.breakClass)) .append(")"); } - return sb.toString(); + return buffer.toString(); } } diff --git a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java index feb633265..7c712040a 100644 --- a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java +++ b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java @@ -26,9 +26,12 @@ import java.util.List; import java.util.ListIterator; /** - * Represents a list of Knuth elements. + * Represents a list of {@link KnuthElement Knuth elements}. */ public abstract class KnuthSequence extends ArrayList { + + //TODO: do not extend ArrayList + /** * Creates a new and empty list. */ diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java index 52238e9be..83dea01bf 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java @@ -96,7 +96,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { //Controls whether a single part should be forced if possible (ex. block-container) private boolean favorSinglePart = false; - private boolean ipdChange; + private int ipdDifference; private KnuthNode bestNodeForIPDChange; //Used to keep track of switches in keep-context @@ -320,7 +320,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { * will not have considered it a legal break, but it could still * be one. */ - if (penalty.getP() == KnuthPenalty.INFINITE) { + if (penalty.getPenalty() == KnuthPenalty.INFINITE) { int breakClass = penalty.getBreakClass(); if (breakClass == Constants.EN_PAGE || breakClass == Constants.EN_COLUMN) { @@ -363,7 +363,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { noteListIterator.hasNext();) { final KnuthElement element = (KnuthElement) noteListIterator.next(); if (element.isBox() || element.isGlue()) { - noteLength += element.getW(); + noteLength += element.getWidth(); } } int prevLength = (lengthList == null || lengthList.isEmpty()) @@ -445,22 +445,22 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { return true; } else { KnuthPenalty p = (KnuthPenalty) element; - if (p.getP() <= 0) { + if (p.getPenalty() <= 0) { return true; } else { int context = p.getBreakClass(); switch (context) { case Constants.EN_LINE: case Constants.EN_COLUMN: - return p.getP() < KnuthPenalty.INFINITE; + return p.getPenalty() < KnuthPenalty.INFINITE; case Constants.EN_PAGE: - return p.getP() < KnuthPenalty.INFINITE + return p.getPenalty() < KnuthPenalty.INFINITE || !pageProvider.endPage(line - 1); case Constants.EN_AUTO: log.debug("keep is not auto but context is"); return true; default: - if (p.getP() < KnuthPenalty.INFINITE) { + if (p.getPenalty() < KnuthPenalty.INFINITE) { log.debug("Non recognized keep context:" + context); return true; } else { @@ -479,7 +479,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { int footnoteSplit = 0; boolean canDeferOldFootnotes; if (element.isPenalty()) { - actualWidth += element.getW(); + actualWidth += element.getWidth(); } if (footnotesPending) { // compute the total length of the footnotes not yet inserted @@ -588,7 +588,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { index++) { if (par.getElement(index).isGlue() && par.getElement(index - 1).isBox() || par.getElement(index).isPenalty() - && ((KnuthElement) par.getElement(index)).getP() < KnuthElement.INFINITE) { + && ((KnuthElement) par.getElement(index)).getPenalty() < KnuthElement.INFINITE) { // break found break; } @@ -711,7 +711,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { element = (KnuthElement) noteListIterator.next(); if (element.isBox()) { // element is a box - splitLength += element.getW(); + splitLength += element.getWidth(); boxPreceding = true; } else if (element.isGlue()) { // element is a glue @@ -721,10 +721,10 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { break; } boxPreceding = false; - splitLength += element.getW(); + splitLength += element.getWidth(); } else { // element is a penalty - if (element.getP() < KnuthElement.INFINITE) { + if (element.getPenalty() < KnuthElement.INFINITE) { // end of the sub-sequence index = noteListIterator.previousIndex(); break; @@ -792,7 +792,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { double f = Math.abs(r); f = 1 + 100 * f * f * f; if (element.isPenalty()) { - double penalty = element.getP(); + double penalty = element.getPenalty(); if (penalty >= 0) { f += penalty; demerits = f * f; @@ -805,9 +805,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { demerits = f * f; } - if (element.isPenalty() && ((KnuthPenalty) element).isFlagged() + if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged() && getElement(activeNode.position).isPenalty() - && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) { + && ((KnuthPenalty) getElement(activeNode.position)).isPenaltyFlagged()) { // add demerit for consecutive breaks at flagged penalties demerits += repeatedFlaggedDemerit; } @@ -1077,8 +1077,8 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { } /** {@inheritDoc} */ - protected boolean ipdChanged() { - return ipdChange; + protected int getIPDdifference() { + return ipdDifference; } /** {@inheritDoc} */ @@ -1104,9 +1104,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { * @param node the active node to add */ protected void addNode(int line, KnuthNode node) { - if (node.position < par.size() - 1 && line > 0 && ipdChange(line - 1)) { + if (node.position < par.size() - 1 && line > 0 + && (ipdDifference = compareIPDs(line - 1)) != 0) { log.trace("IPD changes at page " + line); - ipdChange = true; if (bestNodeForIPDChange == null || node.totalDemerits < bestNodeForIPDChange.totalDemerits) { bestNodeForIPDChange = node; @@ -1117,7 +1117,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { * The whole sequence could actually fit on the last page before * the IPD change. No need to do any special handling. */ - ipdChange = false; + ipdDifference = 0; } super.addNode(line, node); } @@ -1127,12 +1127,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { return bestNodeForIPDChange; } - /** {@inheritDoc} */ - protected boolean ipdChange(int line) { + private int compareIPDs(int line) { if (pageProvider == null) { - return false; + return 0; } - return pageProvider.ipdChange(line); + return pageProvider.compareIPDs(line); } } diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java index bd556366a..2e531a8d8 100644 --- a/src/java/org/apache/fop/layoutmgr/PageProvider.java +++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java @@ -161,12 +161,13 @@ public class PageProvider implements Constants { } /** - * Returns true if the part following the given one has a different IPD. + * Compares the IPD of the given part with the following one. * * @param index index of the current part - * @return true if the following part has a different IPD, false otherwise + * @return a negative integer, zero or a positive integer as the current IPD is less + * than, equal to or greater than the IPD of the following part */ - public boolean ipdChange(int index) { + public int compareIPDs(int index) { int columnCount = 0; int colIndex = startColumnOfCurrentElementList + index; int pageIndex = -1; @@ -179,11 +180,11 @@ public class PageProvider implements Constants { } while (colIndex >= columnCount); if (colIndex + 1 < columnCount) { // Next part is a column on same page => same IPD - return false; + return 0; } else { Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST); return page.getPageViewport().getBodyRegion().getIPD() - != nextPage.getPageViewport().getBodyRegion().getIPD(); + - nextPage.getPageViewport().getBodyRegion().getIPD(); } } diff --git a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java index 95f798161..4680f642e 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java @@ -266,12 +266,12 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager KnuthSequence ks = (KnuthSequence)obj; for (Iterator it = ks.iterator(); it.hasNext(); ) { contentElement = (KnuthElement)it.next(); - stackSize += contentElement.getW(); + stackSize += contentElement.getWidth(); contentList.add(contentElement); } } else { contentElement = (KnuthElement)obj; - stackSize += contentElement.getW(); + stackSize += contentElement.getWidth(); contentList.add(contentElement); } } diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java index 7c30ab9bb..0b95ef859 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -680,7 +680,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager assert lastElement != null; previousIsBox = lastElement.isBox() && !((KnuthElement) lastElement).isAuxiliary() - && ((KnuthElement) lastElement).getW() != 0; + && ((KnuthElement) lastElement).getWidth() != 0; // if last paragraph is open, add the new elements to the paragraph // else this is the last paragraph @@ -705,7 +705,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager // finish last paragraph if it was closed with a linefeed if (lastElement.isPenalty() - && ((KnuthPenalty) lastElement).getP() == -KnuthPenalty.INFINITE) { + && ((KnuthPenalty) lastElement).getPenalty() == -KnuthPenalty.INFINITE) { // a penalty item whose value is -inf // represents a preserved linefeed, // which forces a line break @@ -1172,7 +1172,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager LeafPosition pos = (LeafPosition)lastElement.getPosition(); int totalAdj = adj; //if (lastElement.isPenalty()) { - // totalAdj += lastElement.getW(); + // totalAdj += lastElement.getWidth(); //} //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight); int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index b8a2b283f..f793bb3bb 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -57,6 +57,8 @@ import org.apache.fop.util.ListUtil; */ public class TextLayoutManager extends LeafNodeLayoutManager { + //TODO: remove all final modifiers at local variables + /** * Store information about each potential text area. * Index of character which ends the area, IPD of area, including @@ -703,39 +705,39 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } private AreaInfo processWord(final int alignment, final KnuthSequence sequence, - AreaInfo prevAi, final char ch, final boolean breakOpportunity, + AreaInfo prevAreaInfo, final char ch, final boolean breakOpportunity, final boolean checkEndsWithHyphen) { - AreaInfo ai; + //Word boundary found, process widths and kerning int lastIndex = this.nextStart; while (lastIndex > 0 - && this.foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) { + && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) { lastIndex--; } final boolean endsWithHyphen = checkEndsWithHyphen - && this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN; + && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN; final Font font = FontSelector - .selectFontForCharactersInText(this.foText, - this.thisStart, lastIndex, this.foText, this); + .selectFontForCharactersInText(foText, + this.thisStart, lastIndex, foText, this); final int wordLength = lastIndex - this.thisStart; final boolean kerning = font.hasKerning(); final MinOptMax wordIPD = new MinOptMax(0); for (int i = this.thisStart; i < lastIndex; i++) { - final char c = this.foText.charAt(i); + final char currentChar = foText.charAt(i); //character width - final int charWidth = font.getCharWidth(c); + final int charWidth = font.getCharWidth(currentChar); wordIPD.add(charWidth); //kerning if (kerning) { int kern = 0; if (i > this.thisStart) { - final char previous = this.foText.charAt(i - 1); - kern = font.getKernValue(previous, c) * font.getFontSize() / 1000; - } else if (prevAi != null && !prevAi.isSpace && prevAi.breakIndex > 0) { - final char previous = this.foText.charAt(prevAi.breakIndex - 1); - kern = font.getKernValue(previous, c) * font.getFontSize() / 1000; + final char previousChar = foText.charAt(i - 1); + kern = font.getKernValue(previousChar, currentChar); + } else if (prevAreaInfo != null && !prevAreaInfo.isSpace && prevAreaInfo.breakIndex > 0) { + final char previousChar = foText.charAt(prevAreaInfo.breakIndex - 1); + kern = font.getKernValue(previousChar, currentChar); } if (kern != 0) { this.addToLetterAdjust(i, kern); @@ -748,11 +750,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager { && !TextLayoutManager.isSpace(ch) && lastIndex > 0 && endsWithHyphen) { - final int kern = font.getKernValue( - this.foText.charAt(lastIndex - 1), ch) - * font.getFontSize() / 1000; + final int kern = font.getKernValue(foText.charAt(lastIndex - 1), ch); if (kern != 0) { this.addToLetterAdjust(lastIndex, kern); + //TODO: add kern to wordIPD? } } int iLetterSpaces = wordLength - 1; @@ -765,20 +766,20 @@ public class TextLayoutManager extends LeafNodeLayoutManager { wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces)); // create the AreaInfo object - ai = new AreaInfo(this.thisStart, lastIndex, 0, + AreaInfo areaInfo = new AreaInfo(this.thisStart, lastIndex, 0, iLetterSpaces, wordIPD, endsWithHyphen, false, breakOpportunity, font); - prevAi = ai; - this.vecAreaInfo.add(ai); + prevAreaInfo = areaInfo; + this.vecAreaInfo.add(areaInfo); this.tempStart = this.nextStart; //add the elements - this.addElementsForAWordFragment(sequence, alignment, ai, + this.addElementsForAWordFragment(sequence, alignment, areaInfo, this.vecAreaInfo.size() - 1, this.letterSpaceIPD); - ai = null; this.thisStart = this.nextStart; - return prevAi; + + return prevAreaInfo; } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java index fb88bb79d..9848584c0 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java @@ -298,14 +298,14 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager int stepPenalty = 0; KnuthElement endEl = (KnuthElement)elementLists[0].get(end[0]); if (endEl instanceof KnuthPenalty) { - additionalPenaltyHeight = endEl.getW(); - stepPenalty = Math.max(stepPenalty, endEl.getP()); + additionalPenaltyHeight = endEl.getWidth(); + stepPenalty = Math.max(stepPenalty, endEl.getPenalty()); } endEl = (KnuthElement)elementLists[1].get(end[1]); if (endEl instanceof KnuthPenalty) { additionalPenaltyHeight = Math.max( - additionalPenaltyHeight, endEl.getW()); - stepPenalty = Math.max(stepPenalty, endEl.getP()); + additionalPenaltyHeight, endEl.getWidth()); + stepPenalty = Math.max(stepPenalty, endEl.getPenalty()); } int boxHeight = step - addedBoxHeight - penaltyHeight; @@ -367,7 +367,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager end[i]++; KnuthElement el = (KnuthElement)elementLists[i].get(end[i]); if (el.isPenalty()) { - if (el.getP() < KnuthElement.INFINITE) { + if (el.getPenalty() < KnuthElement.INFINITE) { //First legal break point break; } @@ -379,9 +379,9 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager break; } } - partialHeights[i] += el.getW(); + partialHeights[i] += el.getWidth(); } else { - partialHeights[i] += el.getW(); + partialHeights[i] += el.getWidth(); } } if (end[i] < start[i]) { diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index 53e798e3c..f249d769f 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -158,9 +158,9 @@ class ActiveCell { private int contentLength; FillerPenalty(KnuthPenalty p, int length) { - super(length, p.getP(), p.isFlagged(), p.getBreakClass(), + super(length, p.getPenalty(), p.isPenaltyFlagged(), p.getBreakClass(), p.getPosition(), p.isAuxiliary()); - contentLength = p.getW(); + contentLength = p.getWidth(); } FillerPenalty(int length) { @@ -190,7 +190,7 @@ class ActiveCell { } else if (el instanceof FillerBox) { return 0; } else { - return el.getW(); + return el.getWidth(); } } @@ -248,17 +248,17 @@ class ActiveCell { KnuthElement el = (KnuthElement) iter.next(); if (el.isBox()) { prevIsBox = true; - cumulateLength += el.getW(); + cumulateLength += el.getWidth(); } else if (el.isGlue()) { if (prevIsBox) { elementList.add(iter.nextIndex() - 1, new FillerPenalty(minBPD - cumulateLength)); } prevIsBox = false; - cumulateLength += el.getW(); + cumulateLength += el.getWidth(); } else { prevIsBox = false; - if (cumulateLength + el.getW() < minBPD) { + if (cumulateLength + el.getWidth() < minBPD) { iter.set(new FillerPenalty((KnuthPenalty) el, minBPD - cumulateLength)); } } @@ -314,7 +314,7 @@ class ActiveCell { KnuthElement el = (KnuthElement) knuthIter.next(); if (el.isPenalty()) { prevIsBox = false; - if (el.getP() < KnuthElement.INFINITE + if (el.getPenalty() < KnuthElement.INFINITE || ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) { // TODO too much is being done in that test, only to handle // keep.within-column properly. @@ -322,8 +322,8 @@ class ActiveCell { // First legal break point breakFound = true; KnuthPenalty p = (KnuthPenalty) el; - afterNextStep.penaltyLength = p.getW(); - afterNextStep.penaltyValue = p.getP(); + afterNextStep.penaltyLength = p.getWidth(); + afterNextStep.penaltyValue = p.getPenalty(); if (p.isForcedBreak()) { afterNextStep.breakClass = p.getBreakClass(); } @@ -333,9 +333,9 @@ class ActiveCell { // Second legal break point breakFound = true; } else { - afterNextStep.contentLength += el.getW(); + afterNextStep.contentLength += el.getWidth(); if (!boxFound) { - afterNextStep.condBeforeContentLength += el.getW(); + afterNextStep.condBeforeContentLength += el.getWidth(); } } prevIsBox = false; @@ -348,7 +348,7 @@ class ActiveCell { } prevIsBox = true; boxFound = true; - afterNextStep.contentLength += el.getW(); + afterNextStep.contentLength += el.getWidth(); } } afterNextStep.end = knuthIter.nextIndex() - 1; diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 7e32fdd5e..b3cb06582 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -361,7 +361,7 @@ class RowPainter { while (iter.nextIndex() < endIndex) { KnuthElement el = (KnuthElement) iter.next(); if (el.isBox() || el.isGlue()) { - len += el.getW(); + len += el.getWidth(); } } len += ActiveCell.getElementContentLength((KnuthElement) iter.next()); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 4e3c0b102..ea2e64afb 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -202,7 +202,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager if (lastItem.isForcedBreak()) { KnuthPenalty p = (KnuthPenalty) lastItem; primaryGridUnit.setBreakAfter(p.getBreakClass()); - p.setP(0); + p.setPenalty(0); } setFinished(true); diff --git a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java index 79ed10f48..faef636f6 100644 --- a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java +++ b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java @@ -76,7 +76,7 @@ public abstract class PDFFontNonBase14 extends PDFFont { if (getDocumentSafely().getProfile().isFontEmbeddingRequired()) { if (this.getDescriptor().getFontFile() == null) { throw new PDFConformanceException("For " + getDocumentSafely().getProfile() - + ", all fonts have to be embedded!"); + + ", all fonts have to be embedded! Offending font: " + getBaseFont()); } } } diff --git a/src/java/org/apache/fop/render/afp/AFPCustomizable.java b/src/java/org/apache/fop/render/afp/AFPCustomizable.java index ed1ea443b..5f3fe6823 100644 --- a/src/java/org/apache/fop/render/afp/AFPCustomizable.java +++ b/src/java/org/apache/fop/render/afp/AFPCustomizable.java @@ -51,6 +51,14 @@ public interface AFPCustomizable { void setNativeImagesSupported(boolean nativeImages); /** + * Controls whether CMYK images (IOCA FS45) are enabled. By default, support is disabled + * for wider compatibility. When disabled, any CMYK image is converted to the selected + * color format. + * @param value true to enabled CMYK images + */ + void setCMYKImagesSupported(boolean value); + + /** * Sets the shading mode for painting filled rectangles. * @param shadingMode the shading mode */ diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index 1f7a732d1..3fec25d8d 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -357,6 +357,11 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } /** {@inheritDoc} */ + public void setCMYKImagesSupported(boolean value) { + paintingState.setCMYKImagesSupported(value); + } + + /** {@inheritDoc} */ public void setShadingMode(AFPShadingMode shadingMode) { this.shadingMode = shadingMode; } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java index 99ede8e79..fcfc9c64c 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java @@ -24,6 +24,7 @@ import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.util.MimeConstants; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.render.RenderingContext; @@ -35,6 +36,7 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { ImageFlavor.RAW_JPEG, + ImageFlavor.RAW_TIFF, ImageFlavor.RAW_EPS, }; @@ -63,7 +65,12 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { if (targetContext instanceof AFPRenderingContext) { AFPRenderingContext afpContext = (AFPRenderingContext)targetContext; return (afpContext.getPaintingState().isNativeImagesSupported()) - && (image == null || image instanceof ImageRawJPEG || image instanceof ImageRawEPS); + && (image == null + || image instanceof ImageRawJPEG + || image instanceof ImageRawEPS + || ((image instanceof ImageRawStream) + && (MimeConstants.MIME_TIFF.equals( + ((ImageRawStream)image).getMimeType())))); } return false; } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java index 8f7918583..b0988e754 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java @@ -89,7 +89,11 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima int resolution = paintingState.getResolution(); int maxPixelSize = paintingState.getBitsPerPixel(); if (paintingState.isColorImages()) { - maxPixelSize *= 3; //RGB only at the moment + if (paintingState.isCMYKImagesSupported()) { + maxPixelSize *= 4; //CMYK is maximum + } else { + maxPixelSize *= 3; //RGB is maximum + } } RenderedImage renderedImage = imageRendered.getRenderedImage(); @@ -97,6 +101,7 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima ImageSize intrinsicSize = imageInfo.getSize(); boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage); + int functionSet = useFS10 ? 10 : 11; boolean usePageSegments = useFS10 && !imageObjectInfo.getResourceInfo().getLevel().isInline(); @@ -124,11 +129,6 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima resampledDim.width, resampledDim.height, resolution); } } - if (useFS10) { - imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10); - } else { - imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11); - } imageObjectInfo.setDataHeightRes((int)Math.round( effIntrinsicSize.getDpiHorizontal() * 10)); @@ -156,9 +156,9 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima byte[] imageData = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); boolean allowDirectEncoding = true; - if (allowDirectEncoding && pixelSize <= maxPixelSize) { + if (allowDirectEncoding && (pixelSize <= maxPixelSize)) { //Attempt to encode without resampling the image - ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage); + ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage, pixelSize == 32); ColorModel encodedColorModel = helper.getEncodedColorModel(); boolean directEncode = true; if (helper.getEncodedColorModel().getPixelSize() > maxPixelSize) { @@ -180,6 +180,9 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima log.trace("set subtractive mode"); imageObjectInfo.setSubtractive(true); } + if (pixelSize == 32) { + functionSet = 45; //IOCA FS45 required for CMYK + } helper.encode(baos); imageData = baos.toByteArray(); @@ -191,6 +194,7 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima //Convert image to 24bit RGB ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, baos); imageData = baos.toByteArray(); + imageObjectInfo.setBitsPerPixel(24); boolean colorImages = paintingState.isColorImages(); imageObjectInfo.setColor(colorImages); @@ -212,6 +216,20 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima } } + switch (functionSet) { + case 10: + imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10); + break; + case 11: + imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11); + break; + case 45: + imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45); + break; + default: + throw new IllegalStateException("Invalid IOCA function set: " + functionSet); + } + imageObjectInfo.setData(imageData); // set object area info diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index f019c6a47..250ff9624 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -90,8 +90,8 @@ 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; import org.apache.fop.render.afp.extensions.AFPPageOverlay; +import org.apache.fop.render.afp.extensions.AFPPageSetup; /** * This is an implementation of a FOP Renderer that renders areas to AFP. @@ -444,6 +444,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust ImageFlavor.XML_DOM, /*ImageFlavor.RAW_PNG, */ // PNG not natively supported in AFP ImageFlavor.RAW_JPEG, ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_EPS, + ImageFlavor.RAW_TIFF, ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { @@ -831,6 +832,11 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust } /** {@inheritDoc} */ + public void setCMYKImagesSupported(boolean value) { + paintingState.setCMYKImagesSupported(value); + } + + /** {@inheritDoc} */ public void setShadingMode(AFPShadingMode shadingMode) { this.shadingMode = shadingMode; } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index 49e51b3d1..1e15d4c72 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -318,6 +318,9 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator String imagesMode = imagesCfg.getAttribute("mode", IMAGES_MODE_GRAYSCALE); if (IMAGES_MODE_COLOR.equals(imagesMode)) { customizable.setColorImages(true); + + boolean cmyk = imagesCfg.getAttributeAsBoolean("cmyk", false); + customizable.setCMYKImagesSupported(cmyk); } else { customizable.setColorImages(false); // default to 8 bits per pixel diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java index da25478c3..cfb8c8ade 100644 --- a/src/java/org/apache/fop/tools/anttasks/Fop.java +++ b/src/java/org/apache/fop/tools/anttasks/Fop.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.util.List; +import java.util.Vector; // FOP import org.apache.fop.apps.FOPException; @@ -67,7 +68,10 @@ import org.xml.sax.SAXException; public class Fop extends Task { private File foFile; - private List filesets = new java.util.ArrayList(); + private File xmlFile; + private File xsltFile; + private String xsltParams; + private List/*<FileSet>*/ filesets = new java.util.ArrayList/*<FileSet>*/(); private File outFile; private File outDir; private String format; //MIME type @@ -112,6 +116,54 @@ public class Fop extends Task { } /** + * Gets the input XML file. + * @return the input XML file. + */ + public File getXmlFile() { + return xmlFile; + } + + /** + * Sets the input XML file. + * @param xmlFile the input XML file. + */ + public void setXmlFile(File xmlFile) { + this.xmlFile = xmlFile; + } + + /** + * Gets the input XSLT file. + * @return the input XSLT file. + */ + public File getXsltFile() { + return xsltFile; + } + + /** + * Sets the input XSLT file. + * @param xsltFile the input XSLT file. + */ + public void setXsltFile(File xsltFile) { + this.xsltFile = xsltFile; + } + + /** + * Gets the XSLT parameters + * @return the XSLT parameters + */ + public String getXsltParams() { + return xsltParams; + } + + /** + * Sets the XSLT parameters + * @param xsltParams the XSLT parameters + */ + public void setXsltParams(String xsltParams) { + this.xsltParams = xsltParams; + } + + /** * Adds a set of XSL-FO files (nested fileset attribute). * @param set a fileset */ @@ -491,10 +543,39 @@ class FOPTaskStarter { skippedcount++; } } + } else if (task.getXmlFile() != null && task.getXsltFile() != null) { + if (task.getXmlFile().exists() && task.getXsltFile().exists()) { + File outf = task.getOutfile(); + if (outf == null) { + throw new BuildException("outfile is required when fofile is used"); + } + if (task.getOutdir() != null) { + outf = new File(task.getOutdir(), outf.getName()); + } + // Render if "force" flag is set OR + // OR output file doesn't exist OR + // output file is older than input file + if (task.getForce() || !outf.exists() + || (task.getXmlFile().lastModified() > outf.lastModified() || + task.getXsltFile().lastModified() > outf.lastModified())) { + render(task.getXmlFile(), task.getXsltFile(), outf, outputFormat); + actioncount++; + } else if (outf.exists() + && (task.getXmlFile().lastModified() <= outf.lastModified() || + task.getXsltFile().lastModified() <= outf.lastModified())) { + skippedcount++; + } + } } GlobPatternMapper mapper = new GlobPatternMapper(); - mapper.setFrom("*.fo"); + + String inputExtension = ".fo"; + File xsltFile = task.getXsltFile(); + if (xsltFile != null) { + inputExtension = ".xml"; + } + mapper.setFrom("*" + inputExtension); mapper.setTo("*" + newExtension); // deal with the filesets @@ -507,16 +588,19 @@ class FOPTaskStarter { File f = new File(fs.getDir(task.getProject()), files[j]); File outf = null; - if (task.getOutdir() != null && files[j].endsWith(".fo")) { + if (task.getOutdir() != null && files[j].endsWith(inputExtension)) { String[] sa = mapper.mapFileName(files[j]); outf = new File(task.getOutdir(), sa[0]); } else { - outf = replaceExtension(f, ".fo", newExtension); + outf = replaceExtension(f, inputExtension, newExtension); if (task.getOutdir() != null) { outf = new File(task.getOutdir(), outf.getName()); } } - + File dir = outf.getParentFile(); + if (!dir.exists()) { + dir.mkdirs(); + } try { if (task.getRelativebase()) { this.baseURL = f.getParentFile().toURI().toURL(). @@ -536,7 +620,11 @@ class FOPTaskStarter { // output file is older than input file if (task.getForce() || !outf.exists() || (f.lastModified() > outf.lastModified() )) { - render(f, outf, outputFormat); + if (xsltFile != null) { + render(f, xsltFile, outf, outputFormat); + } else { + render(f, outf, outputFormat); + } actioncount++; } else if (outf.exists() && (f.lastModified() <= outf.lastModified() )) { skippedcount++; @@ -554,10 +642,7 @@ class FOPTaskStarter { } } - private void render(File foFile, File outFile, - String outputFormat) throws FOPException { - InputHandler inputHandler = new InputHandler(foFile); - + private void renderInputHandler(InputHandler inputHandler, File outFile, String outputFormat) throws Exception { OutputStream out = null; try { out = new java.io.FileOutputStream(outFile); @@ -565,11 +650,6 @@ class FOPTaskStarter { } catch (Exception ex) { throw new BuildException("Failed to open " + outFile, ex); } - - if (task.getLogFiles()) { - task.log(foFile + " -> " + outFile, Project.MSG_INFO); - } - boolean success = false; try { FOUserAgent userAgent = fopFactory.newFOUserAgent(); @@ -580,7 +660,7 @@ class FOPTaskStarter { if (task.getThrowexceptions()) { throw new BuildException(ex); } - logger.error("Error rendering fo file: " + foFile, ex); + throw ex; } finally { try { out.close(); @@ -593,5 +673,31 @@ class FOPTaskStarter { } } + private void render(File foFile, File outFile, + String outputFormat) throws FOPException { + InputHandler inputHandler = new InputHandler(foFile); + try { + renderInputHandler(inputHandler, outFile, outputFormat); + } catch (Exception ex) { + logger.error("Error rendering fo file: " + foFile, ex); + } + if (task.getLogFiles()) { + task.log(foFile + " -> " + outFile, Project.MSG_INFO); + } + } + + private void render(File xmlFile, File xsltFile, File outFile, String outputFormat) { + //TODO: implement support for XSLT params + final Vector xsltParams = null; + InputHandler inputHandler = new InputHandler(xmlFile, xsltFile, xsltParams); + try { + renderInputHandler(inputHandler, outFile, outputFormat); + } catch (Exception ex) { + logger.error("Error rendering xml/xslt files: " + xmlFile + ", " + xsltFile, ex); + } + if (task.getLogFiles()) { + task.log("xml: " + xmlFile + ", xslt: " + xsltFile + " -> " + outFile, Project.MSG_INFO); + } + } } |