diff options
author | Simon Steiner <ssteiner@apache.org> | 2017-01-16 15:57:25 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2017-01-16 15:57:25 +0000 |
commit | d78aa6ee137f6095d50fba09edd66b5762bf17c6 (patch) | |
tree | ce946acfaf6ecb6ea78d8c74e93e4fde5e914f62 /fop-core | |
parent | d2205830cbf59ce090dacfdbae834f8f9a816015 (diff) | |
download | xmlgraphics-fop-d78aa6ee137f6095d50fba09edd66b5762bf17c6.tar.gz xmlgraphics-fop-d78aa6ee137f6095d50fba09edd66b5762bf17c6.zip |
FOP-2679: PTX records are incorrectly chained
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1779051 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'fop-core')
4 files changed, 282 insertions, 162 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/afp/modca/AbstractPageObject.java b/fop-core/src/main/java/org/apache/fop/afp/modca/AbstractPageObject.java index b3e733673..55457a1ae 100644 --- a/fop-core/src/main/java/org/apache/fop/afp/modca/AbstractPageObject.java +++ b/fop-core/src/main/java/org/apache/fop/afp/modca/AbstractPageObject.java @@ -156,7 +156,11 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen * @param lineDataInfo the line data information. */ public void createLine(AFPLineDataInfo lineDataInfo) { - getPresentationTextObject().createLineData(lineDataInfo); + boolean success = getPresentationTextObject().createLineData(lineDataInfo); + if (!success) { + endPresentationObject(); + getPresentationTextObject().createLineData(lineDataInfo); + } } /** @@ -168,7 +172,11 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen */ public void createText(PtocaProducer producer) throws UnsupportedEncodingException { //getPresentationTextObject().createTextData(textDataInfo); - getPresentationTextObject().createControlSequences(producer); + boolean success = getPresentationTextObject().createControlSequences(producer); + if (!success) { + endPresentationObject(); + getPresentationTextObject().createControlSequences(producer); + } } diff --git a/fop-core/src/main/java/org/apache/fop/afp/modca/PresentationTextObject.java b/fop-core/src/main/java/org/apache/fop/afp/modca/PresentationTextObject.java index 33744b465..6fc313d7c 100644 --- a/fop-core/src/main/java/org/apache/fop/afp/modca/PresentationTextObject.java +++ b/fop-core/src/main/java/org/apache/fop/afp/modca/PresentationTextObject.java @@ -19,6 +19,7 @@ package org.apache.fop.afp.modca; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; @@ -88,12 +89,15 @@ public class PresentationTextObject extends AbstractNamedAFPObject { * @param producer the producer * @throws UnsupportedEncodingException thrown if character encoding is not supported */ - public void createControlSequences(PtocaProducer producer) + public boolean createControlSequences(PtocaProducer producer) throws UnsupportedEncodingException { if (currentPresentationTextData == null) { startPresentationTextData(); } try { + if (getBytesAvailable() != null && getBytesAvailable() < getSize(producer)) { + return false; + } producer.produce(builder); } catch (UnsupportedEncodingException e) { endPresentationTextData(); @@ -102,6 +106,18 @@ public class PresentationTextObject extends AbstractNamedAFPObject { endPresentationTextData(); handleUnexpectedIOError(ioe); } + return true; + } + + private int getSize(PtocaProducer producer) throws IOException { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + PtocaBuilder pb = new PtocaBuilder() { + protected OutputStream getOutputStreamForControlSequence(int length) { + return bos; + } + }; + producer.produce(pb); + return bos.size(); } private class DefaultBuilder extends PtocaBuilder { @@ -127,12 +143,13 @@ public class PresentationTextObject extends AbstractNamedAFPObject { * * @param lineDataInfo the line data information. */ - public void createLineData(AFPLineDataInfo lineDataInfo) { + public boolean createLineData(AFPLineDataInfo lineDataInfo) { try { - createControlSequences(new LineDataInfoProducer(lineDataInfo)); + return createControlSequences(new LineDataInfoProducer(lineDataInfo)); } catch (UnsupportedEncodingException e) { handleUnexpectedIOError(e); //Won't happen for lines } + return false; } /** diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPPainter.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPPainter.java index efa17989f..69cfb4f80 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPPainter.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPPainter.java @@ -30,10 +30,11 @@ import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.CharacterCodingException; import java.security.MessageDigest; import java.util.Map; @@ -898,187 +899,218 @@ public class AFPPainter extends AbstractIFPainter<AFPDocumentHandler> { } /** {@inheritDoc} */ - public void drawText(int x, int y, final int letterSpacing, final int wordSpacing, - final int[][] dp, final String text) throws IFException { - final int fontSize = this.state.getFontSize(); - getPaintingState().setFontSize(fontSize); - - FontTriplet triplet = new FontTriplet( - state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); - //TODO Ignored: state.getFontVariant() - String fontKey = getFontKey(triplet); - - // register font as necessary - Map<String, Typeface> fontMetricMap = getFontInfo().getFonts(); - final AFPFont afpFont = (AFPFont) fontMetricMap.get(fontKey); - final Font font = getFontInfo().getFontInstance(triplet, fontSize); - AFPPageFonts pageFonts = getPaintingState().getPageFonts(); - AFPFontAttributes fontAttributes = pageFonts.registerFont(fontKey, afpFont, fontSize); - - final int fontReference = fontAttributes.getFontReference(); + public void drawText(int x, int y, + final int letterSpacing, final int wordSpacing, final int[][] dp, + final String text) throws IFException { + new DefaultPtocaProducer(x, y, letterSpacing, wordSpacing, dp, text); + } - final int[] coords = unitConv.mpts2units(new float[] {x, y}); + private final class DefaultPtocaProducer implements PtocaProducer { + final int[] coords; + final int fontReference; + final String text; + final int[][] dp; + final int letterSpacing; + final int wordSpacing; + final Font font; + final AFPFont afpFont; + final CharacterSet charSet; + final PresentationTextObject pto; + + private DefaultPtocaProducer(int x, int y, + final int letterSpacing, final int wordSpacing, final int[][] dp, + final String text) throws IFException { + this.letterSpacing = letterSpacing; + this.wordSpacing = wordSpacing; + this.text = text; + this.dp = dp; + final int fontSize = state.getFontSize(); + getPaintingState().setFontSize(fontSize); + + FontTriplet triplet = new FontTriplet( + state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); + //TODO Ignored: state.getFontVariant() + String fontKey = getFontKey(triplet); + + // register font as necessary + Map<String, Typeface> fontMetricMap = getFontInfo().getFonts(); + afpFont = (AFPFont) fontMetricMap.get(fontKey); + font = getFontInfo().getFontInstance(triplet, fontSize); + AFPPageFonts pageFonts = getPaintingState().getPageFonts(); + AFPFontAttributes fontAttributes = pageFonts.registerFont(fontKey, afpFont, fontSize); + + fontReference = fontAttributes.getFontReference(); + + coords = unitConv.mpts2units(new float[] {x, y}); + + charSet = afpFont.getCharacterSet(fontSize); + + if (afpFont.isEmbeddable()) { + try { + getDocumentHandler().getResourceManager().embedFont(afpFont, charSet); + } catch (IOException ioe) { + throw new IFException("Error while embedding font resources", ioe); + } + } - final CharacterSet charSet = afpFont.getCharacterSet(fontSize); + AbstractPageObject page = getDataStream().getCurrentPage(); - if (afpFont.isEmbeddable()) { try { - getDocumentHandler().getResourceManager().embedFont(afpFont, charSet); + if (bytesAvailable != null && bytesAvailable < getSize()) { + page.endPresentationObject(); + } + pto = page.getPresentationTextObject(); + pto.createControlSequences(this); } catch (IOException ioe) { - throw new IFException("Error while embedding font resources", ioe); + throw new IFException("I/O error in drawText()", ioe); } } - AbstractPageObject page = getDataStream().getCurrentPage(); - - try { - int size = charSet.encodeChars(text).getLength(); - if (bytesAvailable != null && bytesAvailable < size) { - page.endPresentationObject(); - } - } catch (CharacterCodingException e) { - throw new IFException(e.getMessage(), e); + private int getSize() throws IOException { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + PtocaBuilder pb = new PtocaBuilder() { + protected OutputStream getOutputStreamForControlSequence(int length) { + return bos; + } + }; + produce(pb); + return bos.size(); } - final PresentationTextObject pto = page.getPresentationTextObject(); - try { - pto.createControlSequences(new PtocaProducer() { - public void produce(PtocaBuilder builder) throws IOException { - Point p = getPaintingState().getPoint(coords[X], coords[Y]); - builder.setTextOrientation(getPaintingState().getRotation()); - builder.absoluteMoveBaseline(p.y); - builder.absoluteMoveInline(p.x); + public void produce(PtocaBuilder builder) throws IOException { + Point p = getPaintingState().getPoint(coords[X], coords[Y]); + builder.setTextOrientation(getPaintingState().getRotation()); + builder.absoluteMoveBaseline(p.y); + builder.absoluteMoveInline(p.x); - builder.setExtendedTextColor(state.getTextColor()); - builder.setCodedFont((byte) fontReference); + builder.setExtendedTextColor(state.getTextColor()); + builder.setCodedFont((byte) fontReference); - int l = text.length(); - int[] dx = IFUtil.convertDPToDX(dp); - int dxl = (dx != null ? dx.length : 0); - StringBuffer sb = new StringBuffer(); + int l = text.length(); + int[] dx = IFUtil.convertDPToDX(dp); + int dxl = (dx != null ? dx.length : 0); + StringBuffer sb = new StringBuffer(); - if (dxl > 0 && dx[0] != 0) { - int dxu = Math.round(unitConv.mpt2units(dx[0])); - builder.relativeMoveInline(-dxu); - } + if (dxl > 0 && dx[0] != 0) { + int dxu = Math.round(unitConv.mpt2units(dx[0])); + builder.relativeMoveInline(-dxu); + } - //Following are two variants for glyph placement. - //SVI does not seem to be implemented in the same way everywhere, so - //a fallback alternative is preserved here. - final boolean usePTOCAWordSpacing = true; - if (usePTOCAWordSpacing) { + //Following are two variants for glyph placement. + //SVI does not seem to be implemented in the same way everywhere, so + //a fallback alternative is preserved here. + final boolean usePTOCAWordSpacing = true; + if (usePTOCAWordSpacing) { - int interCharacterAdjustment = 0; - if (letterSpacing != 0) { - interCharacterAdjustment = Math.round(unitConv.mpt2units( - letterSpacing)); + int interCharacterAdjustment = 0; + if (letterSpacing != 0) { + interCharacterAdjustment = Math.round(unitConv.mpt2units( + letterSpacing)); + } + builder.setInterCharacterAdjustment(interCharacterAdjustment); + + int spaceWidth = font.getCharWidth(CharUtilities.SPACE); + int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units( + spaceWidth + letterSpacing)); + int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement; + if (wordSpacing != 0) { + varSpaceCharacterIncrement = Math.round(unitConv.mpt2units( + spaceWidth + wordSpacing + letterSpacing)); + } + builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement); + + boolean fixedSpaceMode = false; + int ttPos = p.x; + + for (int i = 0; i < l; i++) { + char orgChar = text.charAt(i); + float glyphAdjust = 0; + if (afpFont.getFontType() == FontType.TRUETYPE) { + flushText(builder, sb, charSet); + fixedSpaceMode = true; + int charWidth = font.getCharWidth(orgChar); + sb.append(orgChar); + glyphAdjust += charWidth; + } else if (CharUtilities.isFixedWidthSpace(orgChar)) { + flushText(builder, sb, charSet); + builder.setVariableSpaceCharacterIncrement( + fixedSpaceCharacterIncrement); + fixedSpaceMode = true; + sb.append(CharUtilities.SPACE); + int charWidth = font.getCharWidth(orgChar); + glyphAdjust += (charWidth - spaceWidth); + } else { + if (fixedSpaceMode) { + flushText(builder, sb, charSet); + builder.setVariableSpaceCharacterIncrement( + varSpaceCharacterIncrement); + fixedSpaceMode = false; } - builder.setInterCharacterAdjustment(interCharacterAdjustment); + char ch; + if (orgChar == CharUtilities.NBSPACE) { + ch = ' '; //converted to normal space to allow word spacing + } else { + ch = orgChar; + } + sb.append(ch); + } + if (i < dxl - 1) { + glyphAdjust += dx[i + 1]; + } + + if (afpFont.getFontType() == FontType.TRUETYPE) { + flushText(builder, sb, charSet); + ttPos += Math.round(unitConv.mpt2units(glyphAdjust)); + builder.absoluteMoveInline(ttPos); + } else if (glyphAdjust != 0) { + flushText(builder, sb, charSet); + int increment = Math.round(unitConv.mpt2units(glyphAdjust)); + builder.relativeMoveInline(increment); + } + } + } else { + for (int i = 0; i < l; i++) { + char orgChar = text.charAt(i); + float glyphAdjust = 0; + if (CharUtilities.isFixedWidthSpace(orgChar)) { + sb.append(CharUtilities.SPACE); int spaceWidth = font.getCharWidth(CharUtilities.SPACE); - int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units( - spaceWidth + letterSpacing)); - int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement; - if (wordSpacing != 0) { - varSpaceCharacterIncrement = Math.round(unitConv.mpt2units( - spaceWidth + wordSpacing + letterSpacing)); - } - builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement); - - boolean fixedSpaceMode = false; - int ttPos = p.x; - - for (int i = 0; i < l; i++) { - char orgChar = text.charAt(i); - float glyphAdjust = 0; - if (afpFont.getFontType() == FontType.TRUETYPE) { - flushText(builder, sb, charSet); - fixedSpaceMode = true; - int charWidth = font.getCharWidth(orgChar); - sb.append(orgChar); - glyphAdjust += charWidth; - } else if (CharUtilities.isFixedWidthSpace(orgChar)) { - flushText(builder, sb, charSet); - builder.setVariableSpaceCharacterIncrement( - fixedSpaceCharacterIncrement); - fixedSpaceMode = true; - sb.append(CharUtilities.SPACE); - int charWidth = font.getCharWidth(orgChar); - glyphAdjust += (charWidth - spaceWidth); - } else { - if (fixedSpaceMode) { - flushText(builder, sb, charSet); - builder.setVariableSpaceCharacterIncrement( - varSpaceCharacterIncrement); - fixedSpaceMode = false; - } - char ch; - if (orgChar == CharUtilities.NBSPACE) { - ch = ' '; //converted to normal space to allow word spacing - } else { - ch = orgChar; - } - sb.append(ch); - } - - if (i < dxl - 1) { - glyphAdjust += dx[i + 1]; - } - - if (afpFont.getFontType() == FontType.TRUETYPE) { - flushText(builder, sb, charSet); - ttPos += Math.round(unitConv.mpt2units(glyphAdjust)); - builder.absoluteMoveInline(ttPos); - } else if (glyphAdjust != 0) { - flushText(builder, sb, charSet); - int increment = Math.round(unitConv.mpt2units(glyphAdjust)); - builder.relativeMoveInline(increment); - } - } + int charWidth = font.getCharWidth(orgChar); + glyphAdjust += (charWidth - spaceWidth); } else { - for (int i = 0; i < l; i++) { - char orgChar = text.charAt(i); - float glyphAdjust = 0; - if (CharUtilities.isFixedWidthSpace(orgChar)) { - sb.append(CharUtilities.SPACE); - int spaceWidth = font.getCharWidth(CharUtilities.SPACE); - int charWidth = font.getCharWidth(orgChar); - glyphAdjust += (charWidth - spaceWidth); - } else { - sb.append(orgChar); - } - - if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) { - glyphAdjust += wordSpacing; - } - glyphAdjust += letterSpacing; - if (i < dxl - 1) { - glyphAdjust += dx[i + 1]; - } - - if (glyphAdjust != 0) { - flushText(builder, sb, charSet); - int increment = Math.round(unitConv.mpt2units(glyphAdjust)); - builder.relativeMoveInline(increment); - } - } + sb.append(orgChar); } - flushText(builder, sb, charSet); - bytesAvailable = pto.getBytesAvailable(); - } - private void flushText(PtocaBuilder builder, StringBuffer sb, - final CharacterSet charSet) throws IOException { - if (sb.length() > 0) { - builder.addTransparentData(charSet.encodeChars(sb)); - sb.setLength(0); + if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) { + glyphAdjust += wordSpacing; + } + glyphAdjust += letterSpacing; + if (i < dxl - 1) { + glyphAdjust += dx[i + 1]; + } + + if (glyphAdjust != 0) { + flushText(builder, sb, charSet); + int increment = Math.round(unitConv.mpt2units(glyphAdjust)); + builder.relativeMoveInline(increment); } } + } + flushText(builder, sb, charSet); + if (pto != null) { + bytesAvailable = pto.getBytesAvailable(); + } + } - }); - } catch (IOException ioe) { - throw new IFException("I/O error in drawText()", ioe); + private void flushText(PtocaBuilder builder, StringBuffer sb, + final CharacterSet charSet) throws IOException { + if (sb.length() > 0) { + builder.addTransparentData(charSet.encodeChars(sb)); + sb.setLength(0); + } } + } /** diff --git a/fop-core/src/test/java/org/apache/fop/render/afp/AFPPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/afp/AFPPainterTestCase.java index 2c3cb5332..abb1ecdcb 100644 --- a/fop-core/src/test/java/org/apache/fop/render/afp/AFPPainterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/afp/AFPPainterTestCase.java @@ -24,6 +24,7 @@ import java.awt.Dimension; import java.awt.Rectangle; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -61,12 +62,14 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.Constants; +import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.ImageHandlerRegistry; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.traits.BorderProps; +import org.apache.fop.util.ColorUtil; public class AFPPainterTestCase { @@ -183,6 +186,28 @@ public class AFPPainterTestCase { + "END DOCUMENT DOC00001\n"); } + @Test + public void testPresentationText2() throws URISyntaxException, IFException, IOException { + List<String> strings = new ArrayList<String>(); + for (int i = 0; i < 5000; i++) { + strings.add("tes"); + } + Assert.assertEquals(writeText(strings), "BEGIN DOCUMENT DOC00001\n" + + "BEGIN PAGE PGN00001\n" + + "BEGIN ACTIVE_ENVIRONMENT_GROUP AEG00001\n" + + "DESCRIPTOR PAGE\n" + + "MIGRATION PRESENTATION_TEXT\n" + + "END ACTIVE_ENVIRONMENT_GROUP AEG00001\n" + + "BEGIN PRESENTATION_TEXT PT000001\n" + + "DATA PRESENTATION_TEXT\n" + + "END PRESENTATION_TEXT PT000001\n" + + "BEGIN PRESENTATION_TEXT PT000002\n" + + "DATA PRESENTATION_TEXT\n" + + "END PRESENTATION_TEXT PT000002\n" + + "END PAGE PGN00001\n" + + "END DOCUMENT DOC00001\n"); + } + private String writeText(List<String> text) throws URISyntaxException, IOException, IFException { FOUserAgent agent = FopFactory.newInstance(new URI(".")).newFOUserAgent(); IFContext context = new IFContext(agent); @@ -213,4 +238,42 @@ public class AFPPainterTestCase { new AFPParser(false).read(bis, sb); return sb.toString(); } + + @Test + public void testDrawBorderRect3() throws IFException, PropertyException, IOException { + FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); + AFPDocumentHandler documentHandler = new AFPDocumentHandler(new IFContext(ua)); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + documentHandler.setResult(new StreamResult(os)); + documentHandler.startDocument(); + documentHandler.startPage(0, "", "", new Dimension()); + AFPPainter afpPainter = new AFPPainter(documentHandler); + int style = Constants.EN_DOTTED; + BorderProps.Mode mode = BorderProps.Mode.COLLAPSE_OUTER; + Color color = ColorUtil.parseColorString(ua, "fop-rgb-icc(0.5019608,0.5019608,0.5019608,#CMYK,,0,0,0,0.5)"); + int borderWidth = 500; + int radiusStart = 0; + int radiusEnd = 0; + BorderProps border1 = new BorderProps(style, borderWidth, radiusStart, radiusEnd, color, mode); + afpPainter.drawBorderRect(new Rectangle(0, 0, 552755, 16090), null, border1, null, null, Color.WHITE); + documentHandler.endDocument(); + + InputStream bis = new ByteArrayInputStream(os.toByteArray()); + StringBuilder sb = new StringBuilder(); + new AFPParser(false).read(bis, sb); + Assert.assertEquals(sb.toString(), "BEGIN DOCUMENT DOC00001\n" + + "BEGIN PAGE PGN00001\n" + + "BEGIN ACTIVE_ENVIRONMENT_GROUP AEG00001\n" + + "DESCRIPTOR PAGE\n" + + "MIGRATION PRESENTATION_TEXT\n" + + "END ACTIVE_ENVIRONMENT_GROUP AEG00001\n" + + "BEGIN PRESENTATION_TEXT PT000001\n" + + "DATA PRESENTATION_TEXT\n" + + "END PRESENTATION_TEXT PT000001\n" + + "BEGIN PRESENTATION_TEXT PT000002\n" + + "DATA PRESENTATION_TEXT\n" + + "END PRESENTATION_TEXT PT000002\n" + + "END PAGE PGN00001\n" + + "END DOCUMENT DOC00001\n"); + } } |