diff options
author | Jeremias Maerki <jeremias@apache.org> | 2005-08-24 20:53:55 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2005-08-24 20:53:55 +0000 |
commit | a35f808888428ef09e0c432d049b8d89e34c4880 (patch) | |
tree | 84046176c3ae26f709bd3ff9cb3f38c01a4a9193 | |
parent | 1560478d80eb8a3249b230cec84f1e5242fa902b (diff) | |
download | xmlgraphics-fop-a35f808888428ef09e0c432d049b8d89e34c4880.tar.gz xmlgraphics-fop-a35f808888428ef09e0c432d049b8d89e34c4880.zip |
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
4 files changed, 139 insertions, 119 deletions
diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 7663b5f2d..d22adb9cb 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -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(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 22e32d7dd..cfb73530f 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -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,50 +1167,12 @@ 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 * @param fs Font state diff --git a/src/java/org/apache/fop/render/ps/PSGenerator.java b/src/java/org/apache/fop/render/ps/PSGenerator.java index f6835c31c..efd07cab0 100644 --- a/src/java/org/apache/fop/render/ps/PSGenerator.java +++ b/src/java/org/apache/fop/render/ps/PSGenerator.java @@ -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); } /** diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 5b4688d90..9e9733d68 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -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 } |