in fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java [454:562]
private void writeText(String text, int start, int len,
int letterSpacing, int wordSpacing, int[][] dp,
Font font, Typeface tf, boolean multiByte) throws IOException {
PSGenerator generator = getGenerator();
int end = start + len;
int initialSize = len;
initialSize += initialSize / 2;
boolean hasLetterSpacing = (letterSpacing != 0);
boolean needTJ = false;
int lineStart = 0;
StringBuffer accText = new StringBuffer(initialSize);
StringBuffer sb = new StringBuffer(initialSize);
boolean isOTF = multiByte && ((MultiByteFont)tf).isOTFFile();
for (int i = start; i < end; i++) {
int orgChar = text.charAt(i);
int ch;
int cw;
int xGlyphAdjust = 0;
int yGlyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
//Fixed width space are rendered as spaces so copy/paste works in a reader
ch = font.mapChar(CharUtilities.SPACE);
cw = font.getCharWidth(orgChar);
xGlyphAdjust = font.getCharWidth(ch) - cw;
} else {
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
xGlyphAdjust -= wordSpacing;
}
// surrogate pairs have to be merged in a single code point
if (CharUtilities.containsSurrogatePairAt(text, i)) {
orgChar = Character.toCodePoint((char) orgChar, text.charAt(++i));
}
ch = font.mapCodePoint(orgChar);
}
if (dp != null && i < dp.length && dp[i] != null) {
// get x advancement adjust
xGlyphAdjust -= dp[i][2] - dp[i][0];
yGlyphAdjust += dp[i][3] - dp[i][1];
}
if (dp != null && i < dp.length - 1 && dp[i + 1] != null) {
// get x placement adjust for next glyph
xGlyphAdjust -= dp[i + 1][0];
yGlyphAdjust += dp[i + 1][1];
}
if (!multiByte || isOTF) {
char codepoint = (char)(ch % 256);
if (isOTF) {
accText.append(HexEncoder.encode(codepoint, 2));
} else {
PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
}
} else {
accText.append(HexEncoder.encode(ch));
}
if (xGlyphAdjust != 0 || yGlyphAdjust != 0) {
needTJ = true;
if (sb.length() == 0) {
sb.append('['); //Need to start TJ
}
if (accText.length() > 0) {
if ((sb.length() - lineStart + accText.length()) > 200) {
sb.append(PSGenerator.LF);
lineStart = sb.length();
}
lineStart = writePostScriptString(sb, accText, multiByte, lineStart);
sb.append(' ');
accText.setLength(0); //reset accumulated text
}
if (yGlyphAdjust == 0) {
sb.append(Integer.toString(xGlyphAdjust)).append(' ');
} else {
sb.append('[');
sb.append(Integer.toString(yGlyphAdjust)).append(' ');
sb.append(Integer.toString(xGlyphAdjust)).append(']').append(' ');
}
}
}
if (needTJ) {
if (accText.length() > 0) {
if ((sb.length() - lineStart + accText.length()) > 200) {
sb.append(PSGenerator.LF);
}
writePostScriptString(sb, accText, multiByte);
}
if (hasLetterSpacing) {
sb.append("] " + formatMptAsPt(generator, letterSpacing) + " ATJ");
} else {
sb.append("] TJ");
}
} else {
writePostScriptString(sb, accText, multiByte);
if (hasLetterSpacing) {
StringBuffer spb = new StringBuffer();
spb.append(formatMptAsPt(generator, letterSpacing))
.append(" 0 ");
sb.insert(0, spb.toString());
sb.append(" " + generator.mapCommand("ashow"));
} else {
sb.append(" " + generator.mapCommand("show"));
}
}
generator.writeln(sb.toString());
}