diff options
Diffstat (limited to 'src/java/org/apache/fop/afp/modca')
4 files changed, 77 insertions, 480 deletions
diff --git a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java index 1c686a289..c043faf2e 100644 --- a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java +++ b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java @@ -35,7 +35,7 @@ import org.apache.fop.afp.fonts.AFPFont; * page has a set of data objects associated with it. Each page within a * document is independent from any other page, and each must establish its own * environment parameters. - * + * <p> * The page is the level in the document component hierarchy that is used for * printing or displaying a document's content. The data objects contained in * the page envelope in the data stream are presented when the page is @@ -43,12 +43,11 @@ import org.apache.fop.afp.fonts.AFPFont; * directs the placement and orientation of the data on the page. In addition, * each page contains layout information that specifies the measurement units, * page width, and page depth. - * + * <p> * A page is initiated by a begin page structured field and terminated by an end * page structured field. Structured fields that define objects and active * environment groups or that specify attributes of the page may be encountered * in page state. - * */ public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { @@ -202,7 +201,7 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen * * @return the presentation text object */ - private PresentationTextObject getPresentationTextObject() { + public PresentationTextObject getPresentationTextObject() { if (currentPresentationTextObject == null) { PresentationTextObject presentationTextObject = factory.createPresentationTextObject(); diff --git a/src/java/org/apache/fop/afp/modca/GraphicsObject.java b/src/java/org/apache/fop/afp/modca/GraphicsObject.java index 24b3f949e..a18ee1f07 100644 --- a/src/java/org/apache/fop/afp/modca/GraphicsObject.java +++ b/src/java/org/apache/fop/afp/modca/GraphicsObject.java @@ -179,20 +179,20 @@ public class GraphicsObject extends AbstractDataObject { } /** - * Sets whether the following shape is to be filled + * Sets whether the following shape is to be filled. * * @param fill true if the following shape is to be filled */ public void setFill(boolean fill) { - setPatternSymbol(fill ? - GraphicsSetPatternSymbol.SOLID_FILL : - GraphicsSetPatternSymbol.NO_FILL); + setPatternSymbol(fill + ? GraphicsSetPatternSymbol.SOLID_FILL + : GraphicsSetPatternSymbol.NO_FILL); } /** - * Sets the fill pattern of the next shape + * Sets the fill pattern of the next shape. * - * @param the fill pattern of the next shape + * @param patternSymbol the fill pattern of the next shape */ public void setPatternSymbol(byte patternSymbol) { if (patternSymbol != graphicsState.patternSymbol) { @@ -332,6 +332,7 @@ public class GraphicsObject extends AbstractDataObject { */ public void newSegment() { getData().newSegment(); + graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state } /** {@inheritDoc} */ @@ -366,7 +367,7 @@ public class GraphicsObject extends AbstractDataObject { } /** the internal graphics state */ - private class GraphicsState { + private static class GraphicsState { /** the current color */ private Color color; diff --git a/src/java/org/apache/fop/afp/modca/PresentationTextData.java b/src/java/org/apache/fop/afp/modca/PresentationTextData.java index 645a461d8..2b56caf1a 100644 --- a/src/java/org/apache/fop/afp/modca/PresentationTextData.java +++ b/src/java/org/apache/fop/afp/modca/PresentationTextData.java @@ -19,14 +19,13 @@ package org.apache.fop.afp.modca; -import java.awt.Color; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import org.apache.commons.io.output.ByteArrayOutputStream; -import org.apache.fop.afp.AFPLineDataInfo; -import org.apache.fop.afp.AFPTextDataInfo; + +import org.apache.fop.afp.ptoca.PtocaBuilder; +import org.apache.fop.afp.ptoca.PtocaConstants; import org.apache.fop.afp.util.BinaryUtils; /** @@ -36,20 +35,21 @@ import org.apache.fop.afp.util.BinaryUtils; * that position them - modal control sequences that adjust the positions by * small amounts - other functions causing text to be presented with differences * in appearance. - * + * <p> * The graphic characters are expected to conform to a coded font representation * so that they can be translated from the code point in the object data to the * character in the coded font. The units of measure for linear displacements * are derived from the PresentationTextDescriptor or from the hierarchical * defaults. - * + * <p> * In addition to graphic character code points, Presentation Text data can * contain embedded control sequences. These are strings of two or more bytes * which signal an alternate mode of processing for the content of the current * Presentation Text data. - * + * <p> + * The content for this object can be created using {@link PtocaBuilder}. */ -public class PresentationTextData extends AbstractAFPObject { +public class PresentationTextData extends AbstractAFPObject implements PtocaConstants { /** the maximum size of the presentation text data.*/ private static final int MAX_SIZE = 8192; @@ -57,27 +57,6 @@ public class PresentationTextData extends AbstractAFPObject { /** the AFP data relating to this presentation text data. */ private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - /** the current x coordinate. */ - private int currentX = -1; - - /** the current y cooridnate */ - private int currentY = -1; - - /** the current font */ - private String currentFont = ""; - - /** the current orientation */ - private int currentOrientation = 0; - - /** the current color */ - private Color currentColor = new Color(0, 0, 0); - - /** the current variable space increment */ - private int currentVariableSpaceCharacterIncrement = 0; - - /** the current inter character adjustment */ - private int currentInterCharacterAdjustment = 0; - /** * Default constructor for the PresentationTextData. */ @@ -85,6 +64,8 @@ public class PresentationTextData extends AbstractAFPObject { this(false); } + private static final int HEADER_LENGTH = 9; + /** * Constructor for the PresentationTextData, the boolean flag indicate * whether the control sequence prefix should be set to indicate the start @@ -105,7 +86,7 @@ public class PresentationTextData extends AbstractAFPObject { 0x00, // Reserved 0x00, // Reserved }; - baos.write(data, 0, 9); + baos.write(data, 0, HEADER_LENGTH); if (controlInd) { baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); @@ -113,420 +94,25 @@ public class PresentationTextData extends AbstractAFPObject { } /** - * The Set Coded Font Local control sequence activates a coded font and - * specifies the character attributes to be used. This is a modal control - * sequence. - * - * @param font - * The font local identifier. - * @param afpdata - * The output stream to which data should be written. - */ - private void setCodedFont(byte font, ByteArrayOutputStream afpdata) { - // Avoid unnecessary specification of the font - if (String.valueOf(font).equals(currentFont)) { - return; - } else { - currentFont = String.valueOf(font); - } - - afpdata.write(new byte[] {0x03, (byte) 0xF1, font}, 0, 3); - } - - /** - * Establishes the current presentation position on the baseline at a new - * I-axis coordinate, which is a specified number of measurement units from - * the B-axis. There is no change to the current B-axis coordinate. - * - * @param coordinate - * The coordinate for the inline move. - * @param afpdata - * The output stream to which data should be written. - */ - private void absoluteMoveInline(int coordinate, - ByteArrayOutputStream afpdata) { - byte[] b = BinaryUtils.convert(coordinate, 2); - afpdata.write(new byte[] {0x04, (byte) 0xC7, b[0], b[1]}, 0, 4); - currentX = coordinate; - } - - /** - * Establishes the baseline and the current presentation position at a new - * B-axis coordinate, which is a specified number of measurement units from - * the I-axis. There is no change to the current I-axis coordinate. - * - * @param coordinate - * The coordinate for the baseline move. - * @param afpdata - * The output stream to which data should be written. - */ - private void absoluteMoveBaseline(int coordinate, - ByteArrayOutputStream afpdata) { - byte[] b = BinaryUtils.convert(coordinate, 2); - afpdata.write(new byte[] {0x04, (byte) 0xD3, b[0], b[1]}, 0, 4); - currentY = coordinate; - } - - private static final int TRANSPARENT_MAX_SIZE = 253; - - /** - * The Transparent Data control sequence contains a sequence of code points - * that are presented without a scan for embedded control sequences. - * - * @param data - * The text data to add. - * @param afpdata - * The output stream to which data should be written. - */ - private void addTransparentData(byte[] data, ByteArrayOutputStream afpdata) { - // Calculate the length - int l = data.length + 2; - if (l > 255) { - // Check that we are not exceeding the maximum length - throw new IllegalArgumentException( - "Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes: " + data); - } - afpdata.write(new byte[] {BinaryUtils.convert(l)[0], (byte) 0xDB}, - 0, 2); - afpdata.write(data, 0, data.length); - } - - /** - * Draws a line of specified length and specified width in the B-direction - * from the current presentation position. The location of the current - * presentation position is unchanged. - * - * @param length - * The length of the rule. - * @param width - * The width of the rule. - * @param afpdata - * The output stream to which data should be written. - */ - private void drawBaxisRule(int length, int width, - ByteArrayOutputStream afpdata) { - afpdata.write(new byte[] { - 0x07, // Length - (byte) 0xE7, // Type - }, 0, 2); - // Rule length - byte[] data1 = BinaryUtils.shortToByteArray((short) length); - afpdata.write(data1, 0, data1.length); - // Rule width - byte[] data2 = BinaryUtils.shortToByteArray((short) width); - afpdata.write(data2, 0, data2.length); - // Rule width fraction - afpdata.write(0x00); - } - - /** - * Draws a line of specified length and specified width in the I-direction - * from the current presentation position. The location of the current - * presentation position is unchanged. - * - * @param length - * The length of the rule. - * @param width - * The width of the rule. - * @param afpdata - * The output stream to which data should be written. - */ - private void drawIaxisRule(int length, int width, - ByteArrayOutputStream afpdata) { - afpdata.write(new byte[] { - 0x07, // Length - (byte) 0xE5, // Type - }, 0, 2); - // Rule length - byte[] data1 = BinaryUtils.shortToByteArray((short) length); - afpdata.write(data1, 0, data1.length); - // Rule width - byte[] data2 = BinaryUtils.shortToByteArray((short) width); - afpdata.write(data2, 0, data2.length); - // Rule width fraction - afpdata.write(0x00); - } - - /** - * Create the presentation text data for the byte array of data. - * - * @param textDataInfo - * the afp text data - * @throws MaximumSizeExceededException - * thrown if the maximum number of text data is exceeded - * @throws UnsupportedEncodingException - * thrown if character encoding is not supported - */ - public void createTextData(AFPTextDataInfo textDataInfo) - throws MaximumSizeExceededException, UnsupportedEncodingException { - - ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - - int rotation = textDataInfo.getRotation(); - if (currentOrientation != rotation) { - setTextOrientation(rotation, afpdata); - currentOrientation = rotation; - currentX = -1; - currentY = -1; - } - - // Avoid unnecessary specification of the Y coordinate - int y = textDataInfo.getY(); - if (currentY != y) { - absoluteMoveBaseline(y, afpdata); - currentX = -1; - } - - // Avoid unnecessary specification of the X coordinate - int x = textDataInfo.getX(); - if (currentX != x) { - absoluteMoveInline(x, afpdata); - } - - // Avoid unnecessary specification of the variable space increment - if (textDataInfo.getVariableSpaceCharacterIncrement() - != currentVariableSpaceCharacterIncrement) { - setVariableSpaceCharacterIncrement(textDataInfo - .getVariableSpaceCharacterIncrement(), afpdata); - currentVariableSpaceCharacterIncrement = textDataInfo - .getVariableSpaceCharacterIncrement(); - } - - // Avoid unnecessary specification of the inter character adjustment - if (textDataInfo.getInterCharacterAdjustment() != currentInterCharacterAdjustment) { - setInterCharacterAdjustment(textDataInfo.getInterCharacterAdjustment(), - afpdata); - currentInterCharacterAdjustment = textDataInfo - .getInterCharacterAdjustment(); - } - - // Avoid unnecessary specification of the text color - if (!textDataInfo.getColor().equals(currentColor)) { - setExtendedTextColor(textDataInfo.getColor(), afpdata); - currentColor = textDataInfo.getColor(); - } - - setCodedFont(BinaryUtils.convert(textDataInfo.getFontReference())[0], - afpdata); - - // Add transparent data - String textString = textDataInfo.getString(); - String encoding = textDataInfo.getEncoding(); - byte[] data = textString.getBytes(encoding); - if (data.length <= TRANSPARENT_MAX_SIZE) { - addTransparentData(data, afpdata); - } else { - // data size greater than TRANSPARENT_MAX_SIZE so slice - int numTransData = data.length / TRANSPARENT_MAX_SIZE; - byte[] buff = new byte[TRANSPARENT_MAX_SIZE]; - int currIndex = 0; - for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { - currIndex = transDataCnt * TRANSPARENT_MAX_SIZE; - System.arraycopy(data, currIndex, buff, 0, TRANSPARENT_MAX_SIZE); - addTransparentData(buff, afpdata); - } - int remainingTransData = data.length / TRANSPARENT_MAX_SIZE; - buff = new byte[remainingTransData]; - System.arraycopy(data, currIndex, buff, 0, remainingTransData); - addTransparentData(buff, afpdata); - } - currentX = -1; - - int dataSize = afpdata.size(); - - if (baos.size() + dataSize > MAX_SIZE) { - currentX = -1; - currentY = -1; - throw new MaximumSizeExceededException(); - } - - byte[] outputdata = afpdata.toByteArray(); - baos.write(outputdata, 0, outputdata.length); - } - - private int ensurePositive(int value) { - if (value < 0) { - return 0; - } - return value; - } - - /** - * Drawing of lines using the starting and ending coordinates, thickness and - * colour arguments. - * - * @param lineDataInfo the line data information. - * @throws MaximumSizeExceededException - * thrown if the maximum number of line data has been exceeded - */ - public void createLineData(AFPLineDataInfo lineDataInfo) throws MaximumSizeExceededException { - - ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - - int orientation = lineDataInfo.getRotation(); - if (currentOrientation != orientation) { - setTextOrientation(orientation, afpdata); - currentOrientation = orientation; - } - - // Avoid unnecessary specification of the Y coordinate - int y1 = ensurePositive(lineDataInfo.getY1()); - if (y1 != currentY) { - absoluteMoveBaseline(y1, afpdata); - } - - // Avoid unnecessary specification of the X coordinate - int x1 = ensurePositive(lineDataInfo.getX1()); - if (x1 != currentX) { - absoluteMoveInline(x1, afpdata); - } - - Color color = lineDataInfo.getColor(); - if (!color.equals(currentColor)) { - setExtendedTextColor(color, afpdata); - currentColor = color; - } - - int x2 = ensurePositive(lineDataInfo.getX2()); - int y2 = ensurePositive(lineDataInfo.getY2()); - int thickness = lineDataInfo.getThickness(); - if (y1 == y2) { - drawIaxisRule(x2 - x1, thickness, afpdata); - } else if (x1 == x2) { - drawBaxisRule(y2 - y1, thickness, afpdata); - } else { - log.error("Invalid axis rule unable to draw line"); - return; - } - - int dataSize = afpdata.size(); - - if (baos.size() + dataSize > MAX_SIZE) { - currentX = -1; - currentY = -1; - throw new MaximumSizeExceededException(); - } - - byte[] outputdata = afpdata.toByteArray(); - baos.write(outputdata, 0, outputdata.length); - } - - /** - * The Set Text Orientation control sequence establishes the I-direction and - * B-direction for the subsequent text. This is a modal control sequence. - * - * Semantics: This control sequence specifies the I-axis and B-axis - * orientations with respect to the Xp-axis for the current Presentation - * Text object. The orientations are rotational values expressed in degrees - * and minutes. - * - * @param orientation - * The text orientation (0, 90, 180, 270). - * @param os - * The output stream to which data should be written. + * Returns the number of data bytes still available in this object until it is full and a new + * one has to be started. + * @return the number of data bytes available */ - private void setTextOrientation(int orientation, - ByteArrayOutputStream os) { - os.write(new byte[] {0x06, (byte) 0xF7, }, 0, 2); - switch (orientation) { - case 90: - os.write(0x2D); - os.write(0x00); - os.write(0x5A); - os.write(0x00); - break; - case 180: - os.write(0x5A); - os.write(0x00); - os.write(0x87); - os.write(0x00); - break; - case 270: - os.write(0x87); - os.write(0x00); - os.write(0x00); - os.write(0x00); - break; - default: - os.write(0x00); - os.write(0x00); - os.write(0x2D); - os.write(0x00); - break; - } + public int getBytesAvailable() { + return MAX_SIZE - baos.size() + HEADER_LENGTH; } /** - * The Set Extended Text Color control sequence specifies a color value and - * defines the color space and encoding for that value. The specified color - * value is applied to foreground areas of the text presentation space. This - * is a modal control sequence. - * - * @param col - * The color to be set. - * @param os - * The output stream to which data should be written. + * Returns the output stream the content data is written to. + * @return the output stream */ - private void setExtendedTextColor(Color col, ByteArrayOutputStream os) { - byte[] colorData = new byte[] { - 15, // Control sequence length - (byte) 0x81, // Control sequence function type - 0x00, // Reserved; must be zero - 0x01, // Color space - 0x01 = RGB - 0x00, // Reserved; must be zero - 0x00, // Reserved; must be zero - 0x00, // Reserved; must be zero - 0x00, // Reserved; must be zero - 8, // Number of bits in component 1 - 8, // Number of bits in component 2 - 8, // Number of bits in component 3 - 0, // Number of bits in component 4 - (byte) (col.getRed()), // Red intensity - (byte) (col.getGreen()), // Green intensity - (byte) (col.getBlue()), // Blue intensity - }; - - os.write(colorData, 0, colorData.length); - } - - /** - * //TODO This is a modal control sequence. - * - * @param incr - * The increment to be set. - * @param os - * The output stream to which data should be written. - */ - private void setVariableSpaceCharacterIncrement(int incr, - ByteArrayOutputStream os) { - byte[] b = BinaryUtils.convert(incr, 2); - - os.write(new byte[] { - 4, // Control sequence length - (byte) 0xC5, // Control sequence function type - b[0], b[1] }, - 0, 4); - } - - /** - * //TODO This is a modal control sequence. - * - * @param incr - * The increment to be set. - * @param os - * The output stream to which data should be written. - */ - private void setInterCharacterAdjustment(int incr, ByteArrayOutputStream os) { - byte[] b = BinaryUtils.convert(Math.abs(incr), 2); - os.write(new byte[] { - 5, // Control sequence length - (byte) 0xC3, // Control sequence function type - b[0], b[1], (byte) (incr >= 0 ? 0 : 1) // Direction - }, 0, 5); + protected OutputStream getOutputStream() { + return this.baos; } /** {@inheritDoc} */ public void writeToStream(OutputStream os) throws IOException { + assert getBytesAvailable() >= 0; byte[] data = baos.toByteArray(); byte[] size = BinaryUtils.convert(data.length - 1, 2); data[1] = size[0]; @@ -534,23 +120,4 @@ public class PresentationTextData extends AbstractAFPObject { os.write(data); } - /** - * A control sequence is a sequence of bytes that specifies a control - * function. A control sequence consists of a control sequence introducer - * and zero or more parameters. The control sequence can extend multiple - * presentation text data objects, but must eventually be terminated. This - * method terminates the control sequence. - * - * @throws MaximumSizeExceededException - * thrown in the event that maximum size has been exceeded - */ - public void endControlSequence() throws MaximumSizeExceededException { - byte[] data = new byte[2]; - data[0] = 0x02; - data[1] = (byte) 0xF8; - if (data.length + baos.size() > MAX_SIZE) { - throw new MaximumSizeExceededException(); - } - baos.write(data, 0, data.length); - } }
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/PresentationTextObject.java b/src/java/org/apache/fop/afp/modca/PresentationTextObject.java index 4a8bbbb18..f3b562d98 100644 --- a/src/java/org/apache/fop/afp/modca/PresentationTextObject.java +++ b/src/java/org/apache/fop/afp/modca/PresentationTextObject.java @@ -26,6 +26,10 @@ import java.util.List; import org.apache.fop.afp.AFPLineDataInfo; import org.apache.fop.afp.AFPTextDataInfo; +import org.apache.fop.afp.ptoca.LineDataInfoProducer; +import org.apache.fop.afp.ptoca.PtocaBuilder; +import org.apache.fop.afp.ptoca.PtocaProducer; +import org.apache.fop.afp.ptoca.TextDataInfoProducer; /** * The Presentation Text object is the data object used in document processing @@ -41,6 +45,8 @@ import org.apache.fop.afp.AFPTextDataInfo; * collection of the graphic characters and control codes is called Presentation * Text, and the object that contains the Presentation Text is called the * PresentationText object. + * <p> + * The content for this object can be created using {@link PtocaBuilder}. */ public class PresentationTextObject extends AbstractNamedAFPObject { @@ -54,6 +60,8 @@ public class PresentationTextObject extends AbstractNamedAFPObject { */ private List/*<PresentationTextData>*/ presentationTextDataList = null; + private PtocaBuilder builder = new DefaultBuilder(); + /** * Construct a new PresentationTextObject for the specified name argument, * the name should be an 8 character identifier. @@ -72,17 +80,37 @@ public class PresentationTextObject extends AbstractNamedAFPObject { * @throws UnsupportedEncodingException thrown if character encoding is not supported */ public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { + createControlSequences(new TextDataInfoProducer(textDataInfo)); + } + + /** + * Creates a chain of control sequences using a producer. + * @param producer the producer + * @throws UnsupportedEncodingException thrown if character encoding is not supported + */ + public void createControlSequences(PtocaProducer producer) + throws UnsupportedEncodingException { if (currentPresentationTextData == null) { startPresentationTextData(); } try { - currentPresentationTextData.createTextData(textDataInfo); - } catch (MaximumSizeExceededException msee) { - endPresentationTextData(); - createTextData(textDataInfo); + producer.produce(builder); } catch (UnsupportedEncodingException e) { endPresentationTextData(); throw e; + } catch (IOException ioe) { + endPresentationTextData(); + handleUnexpectedIOError(ioe); + } + } + + private class DefaultBuilder extends PtocaBuilder { + protected OutputStream getOutputStreamForControlSequence(int length) { + if (length > currentPresentationTextData.getBytesAvailable()) { + endPresentationTextData(); + startPresentationTextData(); + } + return currentPresentationTextData.getOutputStream(); } } @@ -93,14 +121,10 @@ public class PresentationTextObject extends AbstractNamedAFPObject { * @param lineDataInfo the line data information. */ public void createLineData(AFPLineDataInfo lineDataInfo) { - if (currentPresentationTextData == null) { - startPresentationTextData(); - } try { - currentPresentationTextData.createLineData(lineDataInfo); - } catch (MaximumSizeExceededException msee) { - endPresentationTextData(); - createLineData(lineDataInfo); + createControlSequences(new LineDataInfoProducer(lineDataInfo)); + } catch (UnsupportedEncodingException e) { + handleUnexpectedIOError(e); //Won't happen for lines } } @@ -157,18 +181,24 @@ public class PresentationTextObject extends AbstractNamedAFPObject { startPresentationTextData(); } try { - currentPresentationTextData.endControlSequence(); - } catch (MaximumSizeExceededException msee) { + builder.endChainedControlSequence(); + } catch (IOException ioe) { endPresentationTextData(); - endControlSequence(); + handleUnexpectedIOError(ioe); + //Should not occur since we're writing to byte arrays } } + private void handleUnexpectedIOError(IOException ioe) { + //"Unexpected" since we're currently dealing with ByteArrayOutputStreams here. + throw new RuntimeException("Unexpected I/O error: " + ioe.getMessage(), ioe); + } + /** {@inheritDoc} */ public String toString() { if (presentationTextDataList != null) { return presentationTextDataList.toString(); } - return null; + return super.toString(); } } |