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-ffa450edef68tags/fop-0_90-alpha1
@@ -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(); | |||
@@ -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 |
@@ -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); | |||
} | |||
/** |
@@ -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 | |||
} | |||