Browse Source

Improved text painting for PostScript (including letter-space and word-space)

Moved text-decoration painting to the common base class and reused the border line painting method for this purpose.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@239925 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_90-alpha1
Jeremias Maerki 19 years ago
parent
commit
a35f808888

+ 46
- 4
src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java View File

@@ -19,9 +19,7 @@
package org.apache.fop.render;

import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.List;

import org.apache.fop.area.Area;
@@ -30,11 +28,12 @@ import org.apache.fop.area.BlockViewport;
import org.apache.fop.area.CTM;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.image.FopImage;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.render.pdf.CTMHelper;
import org.apache.fop.traits.BorderProps;

/**
@@ -554,6 +553,49 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
/** Indicates the end of a text object. */
protected abstract void endTextObject();
/**
* Paints the text decoration marks.
* @param tf Current typeface
* @param fontsize Current font size
* @param inline inline area to paint the marks for
* @param baseline position of the baseline
* @param startx start IPD
*/
protected void renderTextDecoration(Typeface tf, int fontsize, InlineArea inline,
int baseline, int startx) {
boolean hasTextDeco = inline.hasUnderline()
|| inline.hasOverline()
|| inline.hasLineThrough();
if (hasTextDeco) {
endTextObject();
float descender = tf.getDescender(fontsize) / 1000f;
float capHeight = tf.getCapHeight(fontsize) / 1000f;
float halfLineWidth = (descender / -8f) / 2f;
float endx = (startx + inline.getIPD()) / 1000f;
if (inline.hasUnderline()) {
ColorType ct = (ColorType) inline.getTrait(Trait.UNDERLINE_COLOR);
float y = baseline - descender / 2f;
drawBorderLine(startx / 1000f, (y - halfLineWidth) / 1000f,
endx, (y + halfLineWidth) / 1000f,
true, true, Constants.EN_SOLID, ct);
}
if (inline.hasOverline()) {
ColorType ct = (ColorType) inline.getTrait(Trait.OVERLINE_COLOR);
float y = (float)(baseline - (1.1 * capHeight));
drawBorderLine(startx / 1000f, (y - halfLineWidth) / 1000f,
endx, (y + halfLineWidth) / 1000f,
true, true, Constants.EN_SOLID, ct);
}
if (inline.hasLineThrough()) {
ColorType ct = (ColorType) inline.getTrait(Trait.LINETHROUGH_COLOR);
float y = (float)(baseline - (0.45 * capHeight));
drawBorderLine(startx / 1000f, (y - halfLineWidth) / 1000f,
endx, (y + halfLineWidth) / 1000f,
true, true, Constants.EN_SOLID, ct);
}
}
}

/** Clip using the current path. */
protected abstract void clip();

+ 7
- 44
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -687,6 +687,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
}
}
/** @see org.apache.fop.render.AbstractPathOrientedRenderer#updateLineStyle(int) */
private void updateLineStyle(int style) {
switch (style) {
case Constants.EN_DASHED:
@@ -1037,8 +1038,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
int size = ((Integer) ch.getTrait(Trait.FONT_SIZE)).intValue();

// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface f = (Typeface) fontInfo.getFonts().get(name);
boolean useMultiByte = f.isMultiByte();
Typeface tf = (Typeface) fontInfo.getFonts().get(name);
boolean useMultiByte = tf.isMultiByte();

// String startText = useMultiByte ? "<FEFF" : "(";
String startText = useMultiByte ? "<" : "(";
@@ -1095,7 +1096,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {

currentStream.add(pdf.toString());

renderTextDecoration(fs, ch, bl, rx);
renderTextDecoration(tf, size, ch, bl, rx);
super.renderCharacter(ch);
}
@@ -1111,8 +1112,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface f = (Typeface) fontInfo.getFonts().get(name);
boolean useMultiByte = f.isMultiByte();
Typeface tf = (Typeface) fontInfo.getFonts().get(name);
boolean useMultiByte = tf.isMultiByte();

// String startText = useMultiByte ? "<FEFF" : "(";
String startText = useMultiByte ? "<" : "(";
@@ -1166,49 +1167,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {

currentStream.add(pdf.toString());

renderTextDecoration(fs, text, bl, rx);
renderTextDecoration(tf, size, text, bl, rx);
super.renderText(text);
}
/**
* Paints the text decoration marks.
* @param fs Current font
* @param inline inline area to paint the marks for
* @param baseline position of the baseline
* @param startx start IPD
*/
protected void renderTextDecoration(Font fs, InlineArea inline,
int baseline, int startx) {
boolean hasTextDeco = inline.hasUnderline()
|| inline.hasOverline()
|| inline.hasLineThrough();
if (hasTextDeco) {
endTextObject();
updateLineStyle(Constants.EN_SOLID);
updateLineWidth(fs.getDescender() / -8 / 1000f);
float endx = (startx + inline.getIPD()) / 1000f;
if (inline.hasUnderline()) {
ColorType ct = (ColorType) inline.getTrait(Trait.UNDERLINE_COLOR);
updateColor(ct, false, null);
float y = baseline - fs.getDescender() / 2;
drawLine(startx / 1000f, y / 1000f, endx, y / 1000f);
}
if (inline.hasOverline()) {
ColorType ct = (ColorType) inline.getTrait(Trait.OVERLINE_COLOR);
updateColor(ct, false, null);
float y = (float)(baseline - (1.1 * fs.getCapHeight()));
drawLine(startx / 1000f, y / 1000f, endx, y / 1000f);
}
if (inline.hasLineThrough()) {
ColorType ct = (ColorType) inline.getTrait(Trait.LINETHROUGH_COLOR);
updateColor(ct, false, null);
float y = (float)(baseline - (0.45 * fs.getCapHeight()));
drawLine(startx / 1000f, y / 1000f, endx, y / 1000f);
}
}
}

/**
* Escapes text according to PDF rules.
* @param s Text to escape

+ 4
- 1
src/java/org/apache/fop/render/ps/PSGenerator.java View File

@@ -46,6 +46,9 @@ public class PSGenerator {
public static final AtendIndicator ATEND = new AtendIndicator() {
};

/** Line feed used by PostScript */
public static final char LF = '\n';
private OutputStream out;
private boolean commentsEnabled = true;
@@ -87,7 +90,7 @@ public class PSGenerator {
* @throws IOException In case of an I/O problem
*/
public final void newLine() throws IOException {
out.write('\n');
out.write(LF);
}

/**

+ 82
- 70
src/java/org/apache/fop/render/ps/PSRenderer.java View File

@@ -51,6 +51,7 @@ import org.apache.fop.image.ImageFactory;
import org.apache.fop.image.XMLImage;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.util.CharUtilities;

import org.w3c.dom.Document;

@@ -292,7 +293,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer {

/** Restores the last graphics state of the rendering engine. */
public void restoreGraphicsState() {
endTextObject();
try {
//delegate
gen.restoreGraphicsState();
@@ -301,22 +301,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer {
}
}

/** Indicates the beginning of a text object. */
protected void beginTextObject() {
if (!inTextMode) {
writeln("BT");
inTextMode = true;
}
}

/** Indicates the end of a text object. */
protected void endTextObject() {
if (inTextMode) {
writeln("ET");
inTextMode = false;
}
}

/**
* Concats the transformation matrix.
* @param a A part
@@ -365,6 +349,26 @@ public class PSRenderer extends AbstractPathOrientedRenderer {
gen.useRGBColor(toColor(col));
}

/** @see org.apache.fop.render.AbstractPathOrientedRenderer#updateLineStyle(int) */
protected void updateLineStyle(int style) {
try {
switch (style) {
case Constants.EN_DASHED:
gen.useDash("[3] 0");
break;
case Constants.EN_DOTTED:
gen.useDash("[1 7] 0");
break;
default:
// solid
gen.useDash("[] 0");
break;
}
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
}

/** @see org.apache.fop.render.AbstractPathOrientedRenderer */
protected void drawBackAndBorders(Area area, float startx, float starty,
float width, float height) {
@@ -668,31 +672,22 @@ public class PSRenderer extends AbstractPathOrientedRenderer {
}
}
/**
* Paints text.
* @param rx X coordinate
* @param bl Y coordinate
* @param text Text to paint
* @param font Font to use
*/
protected void paintText(int rx, int bl, String text, Typeface font) {
saveGraphicsState();
beginTextObject();
writeln("1 0 0 -1 " + gen.formatDouble(rx / 1000f)
+ " " + gen.formatDouble(bl / 1000f) + " Tm");
/** Indicates the beginning of a text object. */
protected void beginTextObject() {
if (!inTextMode) {
saveGraphicsState();
writeln("BT");
inTextMode = true;
}
}

int initialSize = text.length();
initialSize += initialSize / 2;
StringBuffer sb = new StringBuffer(initialSize);
sb.append("(");
for (int i = 0; i < text.length(); i++) {
final char c = text.charAt(i);
final char mapped = font.mapChar(c);
PSGenerator.escapeChar(mapped, sb);
/** Indicates the end of a text object. */
protected void endTextObject() {
if (inTextMode) {
writeln("ET");
restoreGraphicsState();
inTextMode = false;
}
sb.append(") t");
writeln(sb.toString());
restoreGraphicsState();
}

/**
@@ -703,7 +698,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer {
int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE);

// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface f = (Typeface) fontInfo.getFonts().get(fontname);
Typeface tf = (Typeface) fontInfo.getFonts().get(fontname);

//Determine position
int rx = currentIPPosition;
@@ -718,39 +713,56 @@ public class PSRenderer extends AbstractPathOrientedRenderer {
handleIOTrouble(ioe);
}
}
paintText(rx, bl, area.getTextArea(), f);
//paintText(rx, bl, , f);
String text = area.getTextArea();
beginTextObject();
writeln("1 0 0 -1 " + gen.formatDouble(rx / 1000f)
+ " " + gen.formatDouble(bl / 1000f) + " Tm");

/*
String psString = null;
if (area.getFontState().getLetterSpacing() > 0) {
//float f = area.getFontState().getLetterSpacing()
// * 1000 / this.currentFontSize;
float f = area.getFontState().getLetterSpacing();
psString = (new StringBuffer().append(f).append(" 0.0 (")
.append(sb.toString()).append(") A")).toString();
int initialSize = text.length();
initialSize += initialSize / 2;
StringBuffer sb = new StringBuffer(initialSize);
int textLen = text.length();
if (area.getTextLetterSpaceAdjust() == 0 && area.getTextWordSpaceAdjust() == 0) {
sb.append("(");
for (int i = 0; i < textLen; i++) {
final char c = text.charAt(i);
final char mapped = tf.mapChar(c);
PSGenerator.escapeChar(mapped, sb);
}
sb.append(") t");
} else {
psString = (new StringBuffer("(").append(sb.toString())
.append(") t")).toString();
sb.append("(");
int[] offsets = new int[textLen];
for (int i = 0; i < textLen; i++) {
final char c = text.charAt(i);
final char mapped = tf.mapChar(c);
int wordSpace;
//TODO Synchronize word space behaviour with TextLayoutManager
//Check the other renderers, too!
if (CharUtilities.isAnySpace(mapped)
&& mapped != CharUtilities.ZERO_WIDTH_SPACE
&& mapped != CharUtilities.ZERO_WIDTH_NOBREAK_SPACE) {
wordSpace = area.getTextWordSpaceAdjust();
} else {
wordSpace = 0;
}
int cw = tf.getWidth(mapped, fontsize) / 1000;
offsets[i] = cw + area.getTextLetterSpaceAdjust() + wordSpace;
PSGenerator.escapeChar(mapped, sb);
}
sb.append(")" + PSGenerator.LF + "[");
for (int i = 0; i < textLen; i++) {
if (i > 0) {
sb.append(" ");
}
sb.append(gen.formatDouble(offsets[i] / 1000f));
}
sb.append("]" + PSGenerator.LF + "xshow");
}
writeln(sb.toString());


// System.out.println("["+s+"] --> ["+sb.toString()+"]");

// comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
useFont(fs.getFontName(), fs.getFontSize());
useColor(area.getRed(), area.getGreen(), area.getBlue());
if (area.getUnderlined() || area.getLineThrough()
|| area.getOverlined())
write("ULS");
write(psString);
if (area.getUnderlined())
write("ULE");
if (area.getLineThrough())
write("SOE");
if (area.getOverlined())
write("OLE");
this.currentXPosition += area.getContentWidth();
*/
renderTextDecoration(tf, fontsize, area, bl, rx);
super.renderText(area); //Updates IPD
}


Loading…
Cancel
Save