Quellcode durchsuchen

Do text align before the line is rendered, not when the line is closed.

Moved page number resolving to just before text align. Removed page
number resolving from renderers.
Also, fix leader expansion in case page number resolving has eaten up
too much space for the page number, resolving in a possible area overflow.
Leaders may now be shortened down to leader-length.minimum if necessary.
PR: 1130, 17194


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_20_2-maintain@196009 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_20_5rc3
Joerg Pietschmann vor 21 Jahren
Ursprung
Commit
24afe873c1

+ 2
- 0
CHANGES Datei anzeigen

@@ -1,5 +1,7 @@
==============================================================================
Done since 0.20.4 release
- Fixed text alingment for lines containing forward pointing page number
citations. This should greatly improve TOC layout. (J.Pietschmann)
- Fixed repeatedly laid out small caps text (for example in static
content or due ot keeps). (J.Pietschmann)
- Fixed marker handling thouroughly. All retrieving boundaries and

+ 110
- 6
src/org/apache/fop/layout/FontState.java Datei anzeigen

@@ -215,14 +215,118 @@ public class FontState {
}

// Use default CodePointMapping
char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
if (d != 0) {
c = d;
} else {
c = '#';
char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
if (d != 0) {
c = d;
} else {
c = '#';
}
return c;
}

return c;
private int enWidth=-1;
private int emWidth=-1;

private final int getEmWidth() {
if (emWidth<0) {
char mappedChar = mapChar('m');
// The mapping returns '#' for unmapped characters in
// standard fonts. What happens for other fonts?
if (mappedChar == '#') {
emWidth = 500 * getFontSize();
} else {
emWidth = width(mappedChar);
}
}
return emWidth;
}

private final int getEnWidth() {
if (enWidth<0) {
char mappedChar = mapChar('n');
// The mapping returns '#' for unmapped characters in
// standard fonts. What happens for other fonts?
if (mappedChar != '#') {
// Should do something to discover non-proportional fonts.
enWidth = (getEmWidth()*9)/10;
} else {
enWidth = width(mappedChar);
}
}
return enWidth;
}

/**
* Helper method for getting the width of a unicode char
* from the current fontstate.
* This also performs some guessing on widths on various
* versions of space that might not exists in the font.
*/
public int getCharWidth(char c) {
if ((c == '\n') || (c == '\r') || (c == '\t')) {
return getCharWidth(' ');
} else {
char mappedChar = mapChar(c);
if (mappedChar == '#' || mappedChar == 0) {
// Estimate the width of spaces not represented in
// the font
if (c == '#') {
return width(mappedChar);
} else if (c == ' ') {
return getEmWidth();
} else if (c == '\u00A0') {
return getCharWidth(' ');
} else if (c == '\u2000') {
return getEnWidth();
} else if (c == '\u2001') {
return getEmWidth();
} else if (c == '\u2002') {
return getEnWidth();
} else if (c == '\u2003') {
return getEmWidth();
} else if (c == '\u2004') {
return getEmWidth() / 3;
} else if (c == '\u2005') {
return getEmWidth() / 4;
} else if (c == '\u2006') {
return getEmWidth() / 6;
} else if (c == '\u2007') {
return getCharWidth(' ');
} else if (c == '\u2008') {
return getCharWidth('.');
} else if (c == '\u2009') {
return getEmWidth() / 5;
} else if (c == '\u200A') {
return getEmWidth() / 10;
} else if (c == '\u200B') {
return 1;
} else if (c == '\u202F') {
return getCharWidth(' ') / 2;
} else if (c == '\u3000') {
return getCharWidth(' ') * 2;
} else {
return width(mappedChar);
}
} else {
return width(mappedChar);
}
}
}

/**
* Calculates the word width.
*/
public int getWordWidth(String word) {
if (word == null)
return 0;
int wordLength = word.length();
int width = 0;
char[] characters = new char[wordLength];
word.getChars(0, wordLength, characters, 0);
for (int i = 0; i < wordLength; i++) {
width += getCharWidth(characters[i]);
}
return width;
}

}

+ 259
- 276
src/org/apache/fop/layout/LineArea.java Datei anzeigen

@@ -50,24 +50,25 @@
*/
package org.apache.fop.layout;

// Java
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.awt.Rectangle;

// FOP
import org.apache.fop.render.Renderer;
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.layout.inline.*;
import org.apache.fop.fo.properties.WrapOption;
import org.apache.fop.fo.properties.WhiteSpaceCollapse;
import org.apache.fop.fo.properties.TextAlign;
import org.apache.fop.fo.properties.LeaderPattern;
import org.apache.fop.datatypes.IDReferences;
import org.apache.fop.fo.properties.Hyphenate;
import org.apache.fop.fo.properties.LeaderAlignment;
import org.apache.fop.fo.properties.LeaderPattern;
import org.apache.fop.fo.properties.TextAlign;
import org.apache.fop.fo.properties.VerticalAlign;
import org.apache.fop.fo.properties.WhiteSpaceCollapse;
import org.apache.fop.fo.properties.WrapOption;
import org.apache.fop.layout.hyphenation.Hyphenation;
import org.apache.fop.layout.hyphenation.Hyphenator;

// Java
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.awt.Rectangle;
import org.apache.fop.layout.inline.*;
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.render.Renderer;

public class LineArea extends Area {

@@ -81,24 +82,27 @@ public class LineArea extends Area {
protected int endIndent;

private int placementOffset;
private int textAlign;

private FontState currentFontState; // not the nominal, which is
// in this.fontState
private float red, green, blue;
private int wrapOption;
private int whiteSpaceCollapse;
int vAlign;
private int vAlign;

/* hyphenation */
HyphenationProps hyphProps;
private HyphenationProps hyphProps;

/*
* the width of text that has definitely made it into the line
* area
*/
protected int finalWidth = 0;
private int finalWidth = 0;

/* the position to shift a link rectangle in order to compensate for links embedded within a word */
/* the position to shift a link rectangle in order to compensate
* for links embedded within a word
*/
protected int embeddedLinkStart = 0;

/* the width of the current word so far */
@@ -111,33 +115,31 @@ public class LineArea extends Area {
protected static final int MULTIBYTECHAR = 3;

/* the character type of the previous character */
protected int prev = NOTHING;

/* the position in data[] of the start of the current word */
// protected int wordStart;

/* the length (in characters) of the current word */
// protected int wordLength = 0;
private int prev = NOTHING;

/* width of spaces before current word */
protected int spaceWidth = 0;
private int spaceWidth = 0;

/*
* the inline areas that have not yet been added to the line
* because subsequent characters to come (in a different addText)
* may be part of the same word
*/
protected ArrayList pendingAreas = new ArrayList();
private ArrayList pendingAreas = new ArrayList();

/* the width of the pendingAreas */
/* public for problem check in AbstractRenderer */
public int pendingWidth = 0;
private int pendingWidth = 0;

/* text-decoration of the previous text */
protected boolean prevUlState = false;
protected boolean prevOlState = false;
protected boolean prevLTState = false;

// Whether the line has already be aligned text and expanded
// leaders.
private boolean aligned = false;
private boolean hasPageNumbers = false;

public class Leader {
int leaderPattern;
int leaderLengthMinimum;
@@ -177,24 +179,27 @@ public class LineArea extends Area {
this.placementOffset=placementOffset;
this.position = position;
}
void expand(int leaderLength) {
void expand() {
char dot = '.';
int dotWidth = getCharWidth(dot);
int dotWidth = currentFontState.getCharWidth(dot);
char space = ' ';
int spaceWidth = getCharWidth(space);
int spaceWidth = currentFontState.getCharWidth(space);
int idx=children.indexOf(this);
children.remove(this);
switch (leaderPattern) {
case LeaderPattern.SPACE:
InlineSpace spaceArea = new InlineSpace(leaderLength,false);
InlineSpace spaceArea = new InlineSpace(leaderLengthOptimum
, false);
children.add(idx,spaceArea);
break;
case LeaderPattern.RULE:
LeaderArea leaderArea = new LeaderArea(this.fontState, this.red, this.green,
this.blue, "", leaderLength,
this.leaderPattern,
this.ruleThickness, this.ruleStyle);
leaderArea.setYOffset(this.placementOffset);
LeaderArea leaderArea = new LeaderArea(fontState, red, green,
blue, "",
leaderLengthOptimum,
leaderPattern,
ruleThickness,
ruleStyle);
leaderArea.setYOffset(placementOffset);
children.add(idx,leaderArea);
break;
case LeaderPattern.DOTS:
@@ -229,19 +234,19 @@ public class LineArea extends Area {
// shorten leaderLength, otherwise - in
// case of leaderLength=remaining length -
// it will cut off the end of leaderlength
leaderLength -= spaceBeforeLeader;
leaderLengthOptimum -= spaceBeforeLeader;
}
}
int factor = (int)Math.floor(leaderLength / dotWidth);
int factor = (int)Math.floor(leaderLengthOptimum / dotWidth);
char[] leaderChars = new char[factor];
for (int i = 0; i < factor; i++) {
leaderChars[i] = dot;
}
WordArea leaderPatternArea =
new WordArea(currentFontState,
this.red, this.green, this.blue,
new String(leaderChars), leaderLength);
leaderPatternArea.setYOffset(this.placementOffset);
new WordArea(currentFontState, red, green, blue,
new String(leaderChars),
leaderLengthOptimum);
leaderPatternArea.setYOffset(placementOffset);
children.add(idx, leaderPatternArea);
} else {
// if leader-alignment is used, calculate space to
@@ -263,33 +268,34 @@ public class LineArea extends Area {
// shorten leaderLength, otherwise - in
// case of leaderLength=remaining length -
// it will cut off the end of leaderlength
leaderLength -= spaceBeforeLeader;
leaderLengthOptimum -= spaceBeforeLeader;
}
}
// calculate the space to insert between the dots
// and create a inline area with this width
int dotsFactor =
(int)Math.floor(((double)leaderLength)
/ ((double)this.leaderPatternWidth));
(int)Math.floor(((double)leaderLengthOptimum)
/ ((double)leaderPatternWidth));
// add combination of dot + space to fill leader
// is there a way to do this in a more effective way?
for (int i = 0; i < dotsFactor; i++) {
InlineSpace spaceBetweenDots =
new InlineSpace(this.leaderPatternWidth - dotWidth, false);
new InlineSpace(leaderPatternWidth - dotWidth,
false);
WordArea leaderPatternArea =
new WordArea(this.fontState,
this.red, this.green, this.blue,
new String("."), dotWidth);
leaderPatternArea.setYOffset(this.placementOffset);
leaderPatternArea.setYOffset(placementOffset);
children.add(idx,leaderPatternArea);
idx++;
children.add(idx,spaceBetweenDots);
idx++;
}
// append at the end some space to fill up to leader length
children.add(idx,new InlineSpace(leaderLength
children.add(idx,new InlineSpace(leaderLengthOptimum
- dotsFactor
* this.leaderPatternWidth));
* leaderPatternWidth));
idx++;
}
break;
@@ -355,6 +361,153 @@ public class LineArea extends Area {
}

public void render(Renderer renderer) {
if (pendingWidth > 0) {
MessageHandler.error("Areas pending, text probably lost in line"
+ getLineText());
}
if (hasPageNumbers) {
IDReferences idReferences = renderer.getIDReferences();
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if ( o instanceof PageNumberInlineArea) {
PageNumberInlineArea pia = (PageNumberInlineArea)o;
FontState piaFontState = pia.getFontState();
finalWidth-=piaFontState.getWordWidth(pia.getText());
pia.resolve(idReferences);
finalWidth+=piaFontState.getWordWidth(pia.getText());
}
}
}
if (!aligned) {
int padding = 0;
switch (textAlign) {
case TextAlign.START: // left
padding = this.getContentWidth() - finalWidth;
endIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand();
}
}
break;
case TextAlign.END: // right
padding = this.getContentWidth() - finalWidth;
startIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand();
}
}
break;
case TextAlign.CENTER: // center
padding = (this.getContentWidth() - finalWidth) / 2;
startIndent += padding;
endIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand();
}
}
break;
case TextAlign.JUSTIFY: // justify
// first pass - count the spaces
int leaderCount = 0;
int spaceCount = 0;
for (int i = 0; i < children.size(); i++ ) {
Object o = children.get(i);
if (o instanceof InlineSpace) {
InlineSpace space = (InlineSpace)o;
if (space.getResizeable()) {
spaceCount++;
}
} else if(o instanceof LineArea.Leader) {
leaderCount++;
}
}
padding = (this.getContentWidth() - finalWidth);
if (padding!=0) {
if (leaderCount>0) {
int offset=0;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
int leaderExpansionMaximum=
leader.leaderLengthMaximum - leader.leaderLengthOptimum;
int leaderExpansionMinimum=
leader.leaderLengthMinimum - leader.leaderLengthOptimum;
if (leaderExpansionMaximum < padding) {
leader.leaderLengthOptimum =
leader.leaderLengthMaximum;
leader.expand();
padding-=leaderExpansionMaximum;
offset+=leaderExpansionMaximum;
} else if (padding < leaderExpansionMinimum) {
leader.leaderLengthOptimum =
leader.leaderLengthMinimum;
leader.expand();
padding-=leaderExpansionMinimum;
offset+=leaderExpansionMinimum;
} else {
leader.leaderLengthOptimum += padding;
leader.expand();
padding=0;
offset+=padding;
}
} else if (o instanceof InlineArea) {
((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + offset);
}
}
}
if (padding != 0) {
if (spaceCount > 0) {
if (padding > 0) {
// The line is actually short of
// padding mod spaceCount
// millipoints. Should implement
// Bresenham-like algorithm for
// compensating, but it's not worth
// yet.
// If there are ref-area aligned leaders,
// they will be no longer aligned.
padding = padding/spaceCount;
spaceCount = 0;
// second pass - add additional space
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof InlineSpace) {
InlineSpace space = (InlineSpace)o;
if (space.getResizeable()) {
space.setSize(space.getSize() + padding);
spaceCount++;
}
} else if (o instanceof InlineArea) {
((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + i * padding);
}
}
} else {
MessageHandler.log("Area overflow in line "
+ getLineText());
}
} else {
// no spaces
MessageHandler.log("No spaces to justify text in line "
+ getLineText());
}
}
}
break;
default:
MessageHandler.errorln("bad align: "+textAlign);
break;
}
}
renderer.renderLineArea(this);
}

@@ -368,7 +521,7 @@ public class LineArea extends Area {
// Space must be allocated for the page number, so currently we
// give it 3 spaces

int width = 3*getCharWidth(' ');
int width = 3*currentFontState.getCharWidth(' ');


PageNumberInlineArea pia
@@ -380,6 +533,7 @@ public class LineArea extends Area {
pendingAreas.add(pia);
pendingWidth += width;
prev = TEXT;
hasPageNumbers = true;

return -1;
}
@@ -402,7 +556,7 @@ public class LineArea extends Area {
int wordLength = 0;
int wordWidth = 0;
// With CID fonts, space isn't neccesary currentFontState.width(32)
int whitespaceWidth = getCharWidth(' ');
int whitespaceWidth = currentFontState.getCharWidth(' ');

boolean isText = false;
boolean isMultiByteChar = false;
@@ -414,7 +568,7 @@ public class LineArea extends Area {
char c = data[i];
if (!(isSpace(c) || (c == '\n') || (c == '\r') || (c == '\t')
|| (c == '\u2028'))) {
charWidth = getCharWidth(c);
charWidth = currentFontState.getCharWidth(c);
isText = true;
isMultiByteChar = (c > 127);
// Add support for zero-width spaces
@@ -424,7 +578,7 @@ public class LineArea extends Area {
if ((c == '\n') || (c == '\r') || (c == '\t'))
charWidth = whitespaceWidth;
else
charWidth = getCharWidth(c);
charWidth = currentFontState.getCharWidth(c);

isText = false;
isMultiByteChar = false;
@@ -435,7 +589,7 @@ public class LineArea extends Area {

if (this.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE) {
if (isSpace(c)) {
spaceWidth += getCharWidth(c);
spaceWidth += currentFontState.getCharWidth(c);
} else if (c == '\n' || c == '\u2028') {
// force line break
if (spaceWidth > 0) {
@@ -533,7 +687,7 @@ public class LineArea extends Area {
embeddedLinkStart =
0; // reset embeddedLinkStart since a space was encountered

spaceWidth = getCharWidth(c);
spaceWidth = currentFontState.getCharWidth(c);

/*
* here is the place for white-space-treatment value 'ignore':
@@ -563,7 +717,7 @@ public class LineArea extends Area {
if (this.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE) {
if (isSpace(c)) {
prev = WHITESPACE;
spaceWidth = getCharWidth(c);
spaceWidth = currentFontState.getCharWidth(c);
} else if (c == '\n') {
// force line break
// textdecoration not used because spaceWidth is 0
@@ -594,7 +748,9 @@ public class LineArea extends Area {
if ((finalWidth + spaceWidth + wordWidth)
> this.getContentWidth()) {
if (overrun)
MessageHandler.log("area contents overflows area");
MessageHandler.log("area contents overflows area "
+ "in line "
+ getLineText());
if (this.wrapOption == WrapOption.WRAP) {
return i;
}
@@ -706,7 +862,9 @@ public class LineArea extends Area {
(wordStart == start) &&
(finalWidth == 0)) {

MessageHandler.log("area contents overflows area");
MessageHandler.log("area contents overflows"
+ " area in line "
+ getLineText());
addSpacedWord(new String(data, wordStart, wordLength - 1),
ls,
embeddedLinkStart,
@@ -764,7 +922,8 @@ public class LineArea extends Area {
}

if (overrun)
MessageHandler.log("area contents overflows area");
MessageHandler.log("area contents overflows area in line "
+ getLineText());
return -1;
}

@@ -822,111 +981,12 @@ public class LineArea extends Area {
}

/**
* aligns line area
*
* Store text alignment.
* The line is aligned immediately before rendering, after
* page numbers have been resolved.
*/
public void align(int type) {
int padding = 0;

switch (type) {
case TextAlign.START: // left
padding = this.getContentWidth() - finalWidth;
endIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand(leader.leaderLengthOptimum);
}
}
break;
case TextAlign.END: // right
padding = this.getContentWidth() - finalWidth;
startIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand(leader.leaderLengthOptimum);
}
}
break;
case TextAlign.CENTER: // center
padding = (this.getContentWidth() - finalWidth) / 2;
startIndent += padding;
endIndent += padding;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
leader.expand(leader.leaderLengthOptimum);
}
}
break;
case TextAlign.JUSTIFY: // justify
// first pass - count the spaces
int leaderCount = 0;
int spaceCount = 0;
for (int i = 0; i < children.size(); i++ ) {
Object o = children.get(i);
if (o instanceof InlineSpace) {
InlineSpace space = (InlineSpace)o;
if (space.getResizeable()) {
spaceCount++;
}
} else if(o instanceof LineArea.Leader) {
leaderCount++;
}
}
padding = (this.getContentWidth() - finalWidth);
if (padding>0) {
if (leaderCount>0) {
int offset=0;
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof LineArea.Leader) {
LineArea.Leader leader = (LineArea.Leader)o;
int leaderExpansionMaximum=
leader.leaderLengthMaximum - leader.leaderLengthOptimum;
if (leaderExpansionMaximum < padding) {
leader.expand(leader.leaderLengthMaximum);
padding-=leaderExpansionMaximum;
offset+=leaderExpansionMaximum;
} else {
leader.expand(leader.leaderLengthOptimum + padding);
padding=0;
offset+=padding;
}
} else if (o instanceof InlineArea) {
((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + offset);
}
}
}
if (spaceCount > 0 && padding > 0) {
padding = padding/spaceCount;
} else { // no spaces
padding = 0;
}
spaceCount = 0;
// second pass - add additional space
for (int i = 0; i < children.size(); i++) {
Object o = children.get(i);
if (o instanceof InlineSpace) {
InlineSpace space = (InlineSpace)o;
if (space.getResizeable()) {
space.setSize(space.getSize() + padding);
spaceCount++;
}
} else if (o instanceof InlineArea) {
((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + i * padding);
}
}
}
break;
default:
MessageHandler.errorln("bad align: "+type);
break;
}
textAlign = type;
}

/**
@@ -936,9 +996,9 @@ public class LineArea extends Area {
int superHeight = -this.placementOffset;
int maxHeight = this.allocationHeight;
for (int i = 0; i < children.size(); i++ ) {
Box b = (Box)children.get(i);
if (b instanceof InlineArea) {
InlineArea ia = (InlineArea)b;
Object o = children.get(i);
if (o instanceof InlineArea) {
InlineArea ia = (InlineArea)o;
if (ia instanceof WordArea) {
ia.setYOffset(placementOffset);
}
@@ -953,7 +1013,7 @@ public class LineArea extends Area {
int fh = fontState.getAscender();
ia.setYOffset((int)(placementOffset + (2 * fh / 3.0)));
}
} else {}
}
}
// adjust the height of this line to the
// resulting alignment height.
@@ -1018,7 +1078,7 @@ public class LineArea extends Area {
* and wraps it in an InlineArea which is returned
*/
private InlineArea buildSimpleLeader(char c, int leaderLength) {
int width = getCharWidth(c);
int width = currentFontState.getCharWidth(c);
if (width == 0) {
MessageHandler.errorln("char " + c
+ " has width 0. Using width 100 instead.");
@@ -1075,7 +1135,9 @@ public class LineArea extends Area {
TextState textState) {
// check whether the language property has been set
if (this.hyphProps.language.equalsIgnoreCase("none")) {
MessageHandler.errorln("if property 'hyphenate' is used, a language must be specified");
MessageHandler.errorln("if property 'hyphenate' is used, a "
+ "language must be specified in line "
+ getLineText());
return wordStart;
}

@@ -1100,7 +1162,8 @@ public class LineArea extends Area {
String wordToHyphenate;

// width of hyphenation character
int hyphCharWidth = getCharWidth(this.hyphProps.hyphenationChar);
int hyphCharWidth = currentFontState
.getCharWidth(this.hyphProps.hyphenationChar);
remainingWidth -= hyphCharWidth;

// handles ' or " at the beginning of the word
@@ -1115,7 +1178,7 @@ public class LineArea extends Area {
// if the extracted word is smaller than the remaining width
// we have a non letter character inside the word. at the moment
// we will only handle hard hyphens and slashes
if (getWordWidth(wordToHyphenate) < remainingWidth) {
if (currentFontState.getWordWidth(wordToHyphenate) < remainingWidth) {
inwordPunctuation =
characters[wordStart + remainingString.length()
+ wordToHyphenate.length()];
@@ -1127,8 +1190,8 @@ public class LineArea extends Area {
wordStart + remainingString.length()
+ wordToHyphenate.length() + 1);
remainingWidth -=
(getWordWidth(wordToHyphenate)
+ getCharWidth(inwordPunctuation));
(currentFontState.getWordWidth(wordToHyphenate)
+ currentFontState.getCharWidth(inwordPunctuation));
}
}

@@ -1172,24 +1235,6 @@ public class LineArea extends Area {
return wordStart;
}


/**
* Calculates the wordWidth using the actual fontstate
*/
private int getWordWidth(String word) {
if (word == null)
return 0;
int wordLength = word.length();
int width = 0;
char[] characters = new char[wordLength];
word.getChars(0, wordLength, characters, 0);

for (int i = 0; i < wordLength; i++) {
width += getCharWidth(characters[i]);
}
return width;
}

public int getRemainingWidth() {
return this.getContentWidth() + startIndent - this.getCurrentXPosition();
}
@@ -1220,7 +1265,7 @@ public class LineArea extends Area {
public int addCharacter(char data, LinkSet ls, boolean ul) {
WordArea ia = null;
int remainingWidth = this.getRemainingWidth();
int width = getCharWidth(data);
int width = currentFontState.getCharWidth(data);
// if it doesn't fit, return
if (width > remainingWidth) {
return org.apache.fop.fo.flow.Character.DOESNOT_FIT;
@@ -1294,7 +1339,7 @@ public class LineArea extends Area {
pendingWidth = 0;
pendingAreas = new ArrayList();
String word = (wordBuf != null) ? wordBuf.toString() : "";
int wordWidth = this.getWordWidth(word);
int wordWidth = currentFontState.getWordWidth(word);
WordArea hia = new WordArea(currentFontState,
this.red, this.green, this.blue,
word, wordWidth);
@@ -1333,7 +1378,7 @@ public class LineArea extends Area {

for (int i = 0; i < numberOfHyphenationPoints; i++) {
wordBegin = hyph.getPreHyphenText(i);
if (this.getWordWidth(wordBegin) > remainingWidth) {
if (currentFontState.getWordWidth(wordBegin) > remainingWidth) {
break;
}
index = i;
@@ -1358,87 +1403,6 @@ public class LineArea extends Area {
return ret;
}

private final int getEmWidth() {
char mappedChar = currentFontState.mapChar('m');
// the mapping returns '#' for unmapped characters in standard fonts
// what happens for other fonts?
if (mappedChar == '#') {
return 500 * currentFontState.getFontSize();
} else {
return currentFontState.width(mappedChar);
}
}

private final int getEnWidth() {
char mappedChar = currentFontState.mapChar('n');
// the mapping returns '#' for unmapped characters in standard fonts
// what happens for other fonts?
if (mappedChar != '#') {
// should do something to discover non-proportional fonts
return (getEmWidth()*9)/10;
} else {
return currentFontState.width(mappedChar);
}
}

/**
* Helper method for getting the width of a unicode char
* from the current fontstate.
* This also performs some guessing on widths on various
* versions of space that might not exists in the font.
*/
private int getCharWidth(char c) {
if ((c == '\n') || (c == '\r') || (c == '\t')) {
return getCharWidth(' ');
} else {
char mappedChar = currentFontState.mapChar(c);
if (mappedChar == '#' || mappedChar == 0) {
// Estimate the width of spaces not represented in
// the font
if (c == '#') {
return currentFontState.width(mappedChar);
} else if (c == ' ') {
return getEmWidth();
} else if (c == '\u00A0') {
return getCharWidth(' ');
} else if (c == '\u2000') {
return getEnWidth();
} else if (c == '\u2001') {
return getEmWidth();
} else if (c == '\u2002') {
return getEnWidth();
} else if (c == '\u2003') {
return getEmWidth();
} else if (c == '\u2004') {
return getEmWidth() / 3;
} else if (c == '\u2005') {
return getEmWidth() / 4;
} else if (c == '\u2006') {
return getEmWidth() / 6;
} else if (c == '\u2007') {
return getCharWidth(' ');
} else if (c == '\u2008') {
return getCharWidth('.');
} else if (c == '\u2009') {
return getEmWidth() / 5;
} else if (c == '\u200A') {
return getEmWidth() / 10;
} else if (c == '\u200B') {
return 1;
} else if (c == '\u202F') {
return getCharWidth(' ') / 2;
} else if (c == '\u3000') {
return getCharWidth(' ') * 2;
} else if (c == '\u3000') {
return getCharWidth(' ') * 2;
} else {
return currentFontState.width(mappedChar);
}
} else {
return currentFontState.width(mappedChar);
}
}
}


/**
@@ -1501,7 +1465,8 @@ public class LineArea extends Area {
if (currentWord.length() == 1
&& (isNBSP(currentWord.charAt(0)))) {
// Add an InlineSpace
int spaceWidth = getCharWidth(currentWord.charAt(0));
int spaceWidth = currentFontState
.getCharWidth(currentWord.charAt(0));
if (spaceWidth > 0) {
InlineSpace is = new InlineSpace(spaceWidth);
startw += spaceWidth;
@@ -1523,7 +1488,7 @@ public class LineArea extends Area {
}
}
} else {
int wordWidth = getWordWidth(currentWord);
int wordWidth = currentFontState.getWordWidth(currentWord);
WordArea ia = new WordArea(currentFontState, this.red,
this.green, this.blue,
currentWord,
@@ -1554,5 +1519,23 @@ public class LineArea extends Area {
}
}

public String getLineText() {
StringBuffer b = new StringBuffer(120);
for (int i=0;i<children.size();i++) {
Object o = children.get(i);
if (o instanceof WordArea) {
b.append(((WordArea)o).getText());
} else if (o instanceof InlineSpace) {
b.append(' ');
} else if (o instanceof org.apache.fop.image.ImageArea) {
b.append("<img>");
} else {
b.append('<');
b.append(o.getClass().getName());
b.append('>');
}
}
return b.toString();
}
}


+ 0
- 5
src/org/apache/fop/layout/inline/InlineArea.java Datei anzeigen

@@ -63,7 +63,6 @@ public abstract class InlineArea extends Area {
private int xOffset = 0;
protected int height = 0;
private int verticalAlign = 0;
protected String pageNumberId = null;
private float red, green, blue;

// Textdecoration
@@ -125,10 +124,6 @@ public abstract class InlineArea extends Area {
return this.xOffset;
}

public String getPageNumberID() {
return pageNumberId;
}

public void setUnderlined(boolean ul) {
this.underlined = ul;
}

+ 10
- 2
src/org/apache/fop/layout/inline/PageNumberInlineArea.java Datei anzeigen

@@ -50,10 +50,12 @@
*/
package org.apache.fop.layout.inline;

import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.WordArea;
import org.apache.fop.layout.FontState;
import org.apache.fop.datatypes.IDReferences;

public class PageNumberInlineArea extends WordArea {
private String pageNumberId = null;

public PageNumberInlineArea(FontState fontState, float red, float green,
float blue, String refid, int width) {
@@ -61,4 +63,10 @@ public class PageNumberInlineArea extends WordArea {
this.pageNumberId = refid;
}

public void resolve(IDReferences idReferences) {
text = idReferences.getPageNumber(pageNumberId);
if (text == null) {
text = "";
}
}
}

+ 1
- 1
src/org/apache/fop/layout/inline/WordArea.java Datei anzeigen

@@ -55,7 +55,7 @@ import org.apache.fop.layout.FontState;

public class WordArea extends InlineArea {

private String text;
protected String text;

public WordArea(FontState fontState, float red, float green, float blue,
String text, int width) {

+ 6
- 8
src/org/apache/fop/render/AbstractRenderer.java Datei anzeigen

@@ -87,6 +87,8 @@ public abstract class AbstractRenderer implements Renderer {
*/
protected int currentAreaContainerXPosition = 0;

protected IDReferences idReferences;

public void setLogger(Logger logger) {
log = logger;
}
@@ -492,14 +494,6 @@ public abstract class AbstractRenderer implements Renderer {
* @param area area to render
*/
public void renderLineArea(LineArea area) {
if (area.pendingWidth > 0) {
final String pageNumber = (area.getPage() != null
? area.getPage().getFormattedNumber()
: "<unknown>");
log.error("Areas pending, text probably lost. Check Page " +
pageNumber +
" and following page.");
}
int rx = this.currentAreaContainerXPosition + area.getStartIndent();
int ry = this.currentYPosition;
int w = area.getContentWidth();
@@ -542,4 +536,8 @@ public abstract class AbstractRenderer implements Renderer {
if (page.getEnd() != null)
page.getEnd().render(this);
}

public IDReferences getIDReferences() {
return idReferences;
}
}

+ 0
- 6
src/org/apache/fop/render/PrintRenderer.java Datei anzeigen

@@ -134,11 +134,6 @@ public abstract class PrintRenderer extends AbstractRenderer {

protected FontInfo fontInfo;

/**
* the IDReferences for this document
*/
protected IDReferences idReferences;

/**
* set the document's producer
*
@@ -474,7 +469,6 @@ public abstract class PrintRenderer extends AbstractRenderer {
prevOverlineColor = null;
prevLineThroughColor = null;
fontInfo = null;
this.idReferences = null;
}

}

+ 2
- 0
src/org/apache/fop/render/Renderer.java Datei anzeigen

@@ -56,6 +56,7 @@ import org.apache.fop.image.ImageArea;
import org.apache.fop.apps.FOPException;
import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
import org.apache.fop.datatypes.IDReferences;

// Avalon
import org.apache.avalon.framework.logger.Logger;
@@ -175,4 +176,5 @@ public interface Renderer {
void stopRenderer(OutputStream outputStream)
throws IOException;

IDReferences getIDReferences();
}

+ 1
- 12
src/org/apache/fop/render/awt/AWTRenderer.java Datei anzeigen

@@ -106,8 +106,6 @@ public class AWTRenderer extends AbstractRenderer implements Printable, Pageable
protected Map fontStyles = new java.util.HashMap();
protected Color saveColor = null;

protected IDReferences idReferences = null;

/**
* Image Object and Graphics Object. The Graphics Object is the Graphics
* object that is contained withing the Image Object.
@@ -667,16 +665,7 @@ public class AWTRenderer extends AbstractRenderer implements Printable, Pageable
int bl = this.currentYPosition;


String s;
if (area.getPageNumberID()
!= null) { // this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null) {
s = "";
}
} else {
s = area.getText();
}
String s = area.getText();

Color oldColor = graphics.getColor();
java.awt.Font oldFont = graphics.getFont();

+ 1
- 9
src/org/apache/fop/render/pcl/PCLRenderer.java Datei anzeigen

@@ -684,15 +684,7 @@ public class PCLRenderer extends PrintRenderer {
int rx = this.currentXPosition;
int bl = this.currentYPosition;

String s;
if (area.getPageNumberID() != null) {
// this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null)
s = "";
} else {
s = area.getText();
}
String s = area.getText();

addWordLines(area, rx, bl, size, theAreaColor);


+ 1
- 11
src/org/apache/fop/render/pdf/PDFRenderer.java Datei anzeigen

@@ -716,17 +716,7 @@ public class PDFRenderer extends PrintRenderer {
prevWordWidth = area.getContentWidth();
prevWordX = rx;

String s;
if (area.getPageNumberID()
!= null) {// this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null) {
s = "";
}
} else {
s = area.getText();
}

String s = area.getText();
int l = s.length();

for (int i = 0; i < l; i++) {

+ 1
- 12
src/org/apache/fop/render/ps/PSRenderer.java Datei anzeigen

@@ -149,8 +149,6 @@ public class PSRenderer extends AbstractRenderer {

private int psLevel = 3;

protected IDReferences idReferences;

protected java.util.Map options;


@@ -720,16 +718,7 @@ public class PSRenderer extends AbstractRenderer {
FontState fs = area.getFontState();
String fontWeight = fs.getFontWeight();
StringBuffer sb = new StringBuffer();
String s;
if (area.getPageNumberID()
!= null) { // this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null) {
s = "";
}
} else {
s = area.getText();
}
String s = area.getText();
int l = s.length();

for (int i = 0; i < l; i++) {

+ 1
- 12
src/org/apache/fop/render/svg/SVGRenderer.java Datei anzeigen

@@ -106,8 +106,6 @@ public class SVGRenderer extends AbstractRenderer {
protected Map fontStyles = new java.util.HashMap();
protected Color saveColor = null;

protected IDReferences idReferences = null;

/**
* The current (internal) font name
*/
@@ -503,16 +501,7 @@ public class SVGRenderer extends AbstractRenderer {
int rx = this.currentXPosition;
int bl = this.currentYPosition;

String s; // = area.getText();
if (area.getPageNumberID()
!= null) { // this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null) {
s = "";
}
} else {
s = area.getText();
}
String s = area.getText();

if (saveColor != null) {
if (saveColor.getRed() != red || saveColor.getGreen() != green

+ 1
- 9
src/org/apache/fop/render/txt/TXTRenderer.java Datei anzeigen

@@ -1608,15 +1608,7 @@ public class TXTRenderer extends PrintRenderer {
int rx = this.currentXPosition;
int bl = this.currentYPosition;

String s;
if (area.getPageNumberID() != null) {
// this text is a page number, so resolve it
s = idReferences.getPageNumber(area.getPageNumberID());
if (s == null)
s = "";
} else {
s = area.getText();
}
String s = area.getText();

if (debug)
System.out.println("TXTRenderer.renderInlineArea: rx=" + rx

+ 8
- 0
src/org/apache/fop/render/xml/XMLRenderer.java Datei anzeigen

@@ -59,6 +59,7 @@ import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
import org.apache.fop.fo.properties.LeaderPattern;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.IDReferences;

// Avalon
import org.apache.avalon.framework.logger.Logger;
@@ -104,6 +105,8 @@ public class XMLRenderer implements Renderer {
protected java.util.Map options;
private boolean consistentOutput = false;

protected IDReferences idReferences;

public XMLRenderer() {}

/**
@@ -129,6 +132,7 @@ public class XMLRenderer implements Renderer {

public void render(Page page, OutputStream outputStream)
throws IOException {
idReferences = page.getIDReferences();
this.renderPage(page);
}

@@ -577,4 +581,8 @@ public class XMLRenderer implements Renderer {
this.writer.flush();
log.debug("written out XML");
}

public IDReferences getIDReferences() {
return idReferences;
}
}

Laden…
Abbrechen
Speichern