Browse Source

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
pull/57/head
Simon Steiner 7 years ago
parent
commit
26c2ba05b3

+ 10
- 2
fop-core/src/main/java/org/apache/fop/afp/modca/AbstractPageObject.java View File

@@ -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);
}

}


+ 20
- 3
fop-core/src/main/java/org/apache/fop/afp/modca/PresentationTextObject.java View File

@@ -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;
}

/**

+ 189
- 157
fop-core/src/main/java/org/apache/fop/render/afp/AFPPainter.java View File

@@ -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);
}
}

}

/**

+ 63
- 0
fop-core/src/test/java/org/apache/fop/render/afp/AFPPainterTestCase.java View File

@@ -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");
}
}

Loading…
Cancel
Save