You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by ga...@apache.org on 2012/02/26 03:29:29 UTC
svn commit: r1293736 [19/38] - in /xmlgraphics/fop/trunk: ./
src/codegen/java/org/apache/fop/tools/
src/codegen/unicode/java/org/apache/fop/complexscripts/
src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/
src/documentation/content/xdocs/tru...
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -32,6 +32,7 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.complexscripts.bidi.BidiResolver;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.Constants;
@@ -111,6 +112,7 @@ public class LineLayoutManager extends I
private final double dAdjust; // Percentage to adjust (stretch or shrink)
private final double ipdAdjust; // Percentage to adjust (stretch or shrink)
private final int startIndent;
+ private final int endIndent;
private final int lineHeight;
private final int lineWidth;
private final int spaceBefore;
@@ -119,8 +121,8 @@ public class LineLayoutManager extends I
LineBreakPosition( // CSOK: ParameterNumber
LayoutManager lm, int index, int startIndex, int breakIndex,
- int shrink, int stretch, int diff, double ipdA, double adjust, int ind,
- int lh, int lw, int sb, int sa, int bl) {
+ int shrink, int stretch, int diff, double ipdA, double adjust, int si,
+ int ei, int lh, int lw, int sb, int sa, int bl) {
super(lm, breakIndex);
availableShrink = shrink;
availableStretch = stretch;
@@ -129,7 +131,8 @@ public class LineLayoutManager extends I
this.startIndex = startIndex;
ipdAdjust = ipdA;
dAdjust = adjust;
- startIndent = ind;
+ startIndent = si;
+ endIndent = ei;
lineHeight = lh;
lineWidth = lw;
spaceBefore = sb;
@@ -140,6 +143,7 @@ public class LineLayoutManager extends I
}
+ private int bidiLevel = -1;
private int textAlignment = EN_JUSTIFY;
private int textAlignmentLast;
private int effectiveAlignment;
@@ -333,13 +337,38 @@ public class LineLayoutManager extends I
int total) {
// compute indent and adjustment ratio, according to
// the value of text-align and text-align-last
- int indent = 0;
+ int startIndent;
+ int endIndent;
int difference = bestActiveNode.difference;
int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
- indent += (textAlign == Constants.EN_CENTER)
+
+ switch ( textAlign ) {
+ case Constants.EN_START:
+ startIndent = 0;
+ endIndent = difference > 0 ? difference : 0;
+ break;
+ case Constants.EN_END:
+ startIndent = difference > 0 ? difference : 0;
+ endIndent = 0;
+ break;
+ case Constants.EN_CENTER:
+ startIndent = difference / 2;
+ endIndent = startIndent;
+ break;
+ default:
+ case Constants.EN_JUSTIFY:
+ startIndent = 0;
+ endIndent = 0;
+ break;
+ }
+
+ /*
+ startIndent += (textAlign == Constants.EN_CENTER)
? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
- indent += (bestActiveNode.line == 1 && indentFirstPart && isFirstInBlock)
+ */
+ startIndent += (bestActiveNode.line == 1 && indentFirstPart && isFirstInBlock)
? textIndent : 0;
+
double ratio = (textAlign == Constants.EN_JUSTIFY
|| difference < 0 && -difference <= bestActiveNode.availableShrink)
? bestActiveNode.adjustRatio : 0;
@@ -377,7 +406,7 @@ public class LineLayoutManager extends I
bestActiveNode.availableShrink - (addedPositions > 0
? 0 : ((Paragraph) par).lineFiller.getShrink()),
bestActiveNode.availableStretch,
- difference, ratio, indent), activePossibility);
+ difference, ratio, startIndent, endIndent), activePossibility);
addedPositions++;
}
@@ -389,7 +418,8 @@ public class LineLayoutManager extends I
private LineBreakPosition makeLineBreakPosition( // CSOK: ParameterNumber
KnuthSequence par, int firstElementIndex, int lastElementIndex, int availableShrink,
- int availableStretch, int difference, double ratio, int indent) {
+ int availableStretch, int difference, double ratio, int startIndent,
+ int endIndent) {
// line height calculation - spaceBefore may differ from spaceAfter
// by 1mpt due to rounding
int spaceBefore = (lineHeight - lead - follow) / 2;
@@ -456,14 +486,14 @@ public class LineLayoutManager extends I
knuthParagraphs.indexOf(par),
firstElementIndex, lastElementIndex,
availableShrink, availableStretch,
- difference, ratio, 0, indent,
+ difference, ratio, 0, startIndent, endIndent,
0, ipd, 0, 0, 0);
} else {
return new LineBreakPosition(thisLLM,
knuthParagraphs.indexOf(par),
firstElementIndex, lastElementIndex,
availableShrink, availableStretch,
- difference, ratio, 0, indent,
+ difference, ratio, 0, startIndent, endIndent,
lineLead + lineFollow,
ipd, spaceBefore, spaceAfter,
lineLead);
@@ -544,6 +574,7 @@ public class LineLayoutManager extends I
/** {@inheritDoc} */
@Override
public void initialize() {
+ bidiLevel = fobj.getBidiLevel();
textAlignment = fobj.getTextAlign();
textAlignmentLast = fobj.getTextAlignLast();
textIndent = fobj.getTextIndent();
@@ -1429,8 +1460,12 @@ public class LineLayoutManager extends I
if (lbp.startIndent != 0) {
lineArea.addTrait(Trait.START_INDENT, lbp.startIndent);
}
+ if (lbp.endIndent != 0) {
+ lineArea.addTrait(Trait.END_INDENT, new Integer(lbp.endIndent));
+ }
lineArea.setBPD(lbp.lineHeight);
lineArea.setIPD(lbp.lineWidth);
+ lineArea.setBidiLevel(bidiLevel);
lineArea.addTrait(Trait.SPACE_BEFORE, lbp.spaceBefore);
lineArea.addTrait(Trait.SPACE_AFTER, lbp.spaceAfter);
alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);
@@ -1506,7 +1541,10 @@ public class LineLayoutManager extends I
&& (!context.isLastArea() || !isLastPosition)) {
lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
}
- lineArea.finalise();
+ lineArea.finish();
+ if ( lineArea.getBidiLevel() >= 0 ) {
+ BidiResolver.reorder ( lineArea );
+ }
parentLayoutManager.addChildArea(lineArea);
}
@@ -1556,6 +1594,9 @@ public class LineLayoutManager extends I
blocklc.setTrailingSpace(new SpaceSpecifier(false));
}
lineArea.updateExtentsFromChildren();
+ if ( lineArea.getBidiLevel() >= 0 ) {
+ BidiResolver.reorder ( lineArea );
+ }
parentLayoutManager.addChildArea(lineArea);
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -56,22 +56,24 @@ public class PageNumberCitationLastLayou
*/
private InlineArea getPageNumberCitationLastInlineArea(LayoutManager parentLM) {
TextArea text = null;
- resolved = false;
+ int level = getBidiLevel();
if (!getPSLM().associateLayoutManagerID(fobj.getRefId())) {
text = new UnresolvedPageNumber(fobj.getRefId(), font, UnresolvedPageNumber.LAST);
getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable)text);
String str = "MMM"; // reserve three spaces for page number
int width = getStringWidth(str);
+ text.setBidiLevel(level);
text.setIPD(width);
+ resolved = false;
} else {
PageViewport page = getPSLM().getLastPVWithID(fobj.getRefId());
String str = page.getPageNumberString();
// get page string from parent, build area
text = new TextArea();
int width = getStringWidth(str);
- text.addWord(str, 0);
+ text.setBidiLevel(level);
+ text.addWord(str, 0, level);
text.setIPD(width);
-
resolved = true;
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -50,27 +50,32 @@ public class PageNumberCitationLayoutMan
/**
* if id can be resolved then simply return a word, otherwise
* return a resolvable area
+ *
+ * TODO: [GA] May need to run bidi algorithm and script processor
+ * on resolved page number.
*/
private InlineArea getPageNumberCitationInlineArea() {
PageViewport page = getPSLM().getFirstPVWithID(fobj.getRefId());
TextArea text = null;
+ int level = getBidiLevel();
if (page != null) {
String str = page.getPageNumberString();
// get page string from parent, build area
text = new TextArea();
- int width = getStringWidth(str);
- text.addWord(str, 0);
- text.setIPD(width);
+ int width = getStringWidth(str); // TODO: [GA] !I18N!
+ text.setBidiLevel(level);
+ text.addWord(str, 0, level);
+ text.setIPD(width); // TODO: [GA] !I18N!
resolved = true;
} else {
- resolved = false;
text = new UnresolvedPageNumber(fobj.getRefId(), font);
String str = "MMM"; // reserve three spaces for page number
- int width = getStringWidth(str);
- text.setIPD(width);
+ int width = getStringWidth(str); // TODO: [GA] !I18N!
+ text.setBidiLevel(level);
+ text.setIPD(width); // TODO: [GA] !I18N!
+ resolved = false;
}
updateTextAreaTraits(text);
-
return text;
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -101,7 +101,7 @@ public class PageNumberLayoutManager ext
TraitSetter.setProducerID(ta, fobj.getId());
ta.setIPD(baseArea.getIPD());
ta.setBPD(baseArea.getBPD());
- ta.setOffset(baseArea.getOffset());
+ ta.setBlockProgressionOffset(baseArea.getBlockProgressionOffset());
ta.setBaselineOffset(baseArea.getBaselineOffset());
ta.addTrait(Trait.COLOR, fobj.getColor()); //only to initialize the trait map
ta.getTraits().putAll(baseArea.getTraits());
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/ScaledBaselineTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/ScaledBaselineTable.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/ScaledBaselineTable.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/ScaledBaselineTable.java Sun Feb 26 02:29:01 2012
@@ -20,6 +20,7 @@
package org.apache.fop.layoutmgr.inline;
import org.apache.fop.fo.Constants;
+import org.apache.fop.traits.WritingMode;
/**
@@ -43,7 +44,7 @@ final class ScaledBaselineTable {
private final int dominantBaselineIdentifier;
- private final int writingMode;
+ private final WritingMode writingMode;
private final int dominantBaselineOffset;
@@ -66,7 +67,7 @@ final class ScaledBaselineTable {
int depth,
int xHeight,
int dominantBaselineIdentifier,
- int writingMode) {
+ WritingMode writingMode) {
this.altitude = altitude;
this.depth = depth;
this.xHeight = xHeight;
@@ -89,7 +90,7 @@ final class ScaledBaselineTable {
* Return the writing mode for this baseline table.
* @return the writing mode
*/
- int getWritingMode() {
+ WritingMode getWritingMode() {
return this.writingMode;
}
@@ -139,7 +140,7 @@ final class ScaledBaselineTable {
}
private boolean isHorizontalWritingMode() {
- return writingMode == Constants.EN_LR_TB || writingMode == Constants.EN_RL_TB;
+ return writingMode.isHorizontal();
}
/**
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -19,6 +19,7 @@
package org.apache.fop.layoutmgr.inline;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -29,6 +30,8 @@ import org.apache.commons.logging.LogFac
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.complexscripts.fonts.GlyphPositioningTable;
+import org.apache.fop.complexscripts.util.CharScript;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FOText;
import org.apache.fop.fonts.Font;
@@ -71,6 +74,7 @@ public class TextLayoutManager extends L
private final int startIndex;
private final int breakIndex;
+ private int wordCharLength;
private final int wordSpaceCount;
private int letterSpaceCount;
private MinOptMax areaIPD;
@@ -78,14 +82,17 @@ public class TextLayoutManager extends L
private final boolean isSpace;
private boolean breakOppAfter;
private final Font font;
+ private final int level;
+ private final int[][] gposAdjustments;
- AreaInfo( // CSOK: ParameterNumber
- int startIndex, int breakIndex, int wordSpaceCount, int letterSpaceCount,
- MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, boolean breakOppAfter,
- Font font) {
+ AreaInfo // CSOK: ParameterNumber
+ (int startIndex, int breakIndex, int wordSpaceCount, int letterSpaceCount,
+ MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, boolean breakOppAfter,
+ Font font, int level, int[][] gposAdjustments) {
assert startIndex <= breakIndex;
this.startIndex = startIndex;
this.breakIndex = breakIndex;
+ this.wordCharLength = -1;
this.wordSpaceCount = wordSpaceCount;
this.letterSpaceCount = letterSpaceCount;
this.areaIPD = areaIPD;
@@ -93,10 +100,26 @@ public class TextLayoutManager extends L
this.isSpace = isSpace;
this.breakOppAfter = breakOppAfter;
this.font = font;
+ this.level = level;
+ this.gposAdjustments = gposAdjustments;
}
- private int getCharLength() {
- return breakIndex - startIndex;
+ /**
+ * Obtain number of 'characters' contained in word. If word
+ * is mapped, then this number may be less than or greater than the
+ * original length (breakIndex - startIndex). We compute and
+ * memoize thius length upon first invocation of this method.
+ */
+ private int getWordLength() {
+ if ( wordCharLength == -1 ) {
+ if ( foText.hasMapping ( startIndex, breakIndex ) ) {
+ wordCharLength = foText.getMapping ( startIndex, breakIndex ).length();
+ } else {
+ assert breakIndex >= startIndex;
+ wordCharLength = breakIndex - startIndex;
+ }
+ }
+ return wordCharLength;
}
private void addToAreaIPD(MinOptMax idp) {
@@ -104,16 +127,16 @@ public class TextLayoutManager extends L
}
public String toString() {
- return "AreaInfo["
- + "letterSpaceCount = " + letterSpaceCount
- + ", wordSpaceCount = " + wordSpaceCount
+ return super.toString() + "{"
+ + "interval = [" + startIndex + "," + breakIndex + "]"
+ + ", isSpace = " + isSpace
+ + ", level = " + level
+ ", areaIPD = " + areaIPD
- + ", startIndex = " + startIndex
- + ", breakIndex = " + breakIndex
+ + ", letterSpaceCount = " + letterSpaceCount
+ + ", wordSpaceCount = " + wordSpaceCount
+ ", isHyphenated = " + isHyphenated
- + ", isSpace = " + isSpace
+ ", font = " + font
- + "]";
+ + "}";
}
}
@@ -149,7 +172,7 @@ public class TextLayoutManager extends L
* be used to influence the start position of the first letter. The entry i+1 defines the
* cursor advancement after the character i. A null entry means no special advancement.
*/
- private final MinOptMax[] letterAdjustArray; //size = textArray.length + 1
+ private final MinOptMax[] letterSpaceAdjustArray; //size = textArray.length + 1
/** Font used for the space between words. */
private Font spaceFont = null;
@@ -192,7 +215,7 @@ public class TextLayoutManager extends L
*/
public TextLayoutManager(FOText node) {
foText = node;
- letterAdjustArray = new MinOptMax[node.length() + 1];
+ letterSpaceAdjustArray = new MinOptMax[node.length() + 1];
areaInfos = new ArrayList();
}
@@ -269,7 +292,9 @@ public class TextLayoutManager extends L
}
if (tbpNext.getLeafPos() != -1) {
areaInfo = (AreaInfo) areaInfos.get(tbpNext.getLeafPos());
- if (lastAreaInfo == null || areaInfo.font != lastAreaInfo.font) {
+ if (lastAreaInfo == null
+ || ( areaInfo.font != lastAreaInfo.font )
+ || ( areaInfo.level != lastAreaInfo.level ) ) {
if (lastAreaInfo != null) {
addAreaInfoAreas(lastAreaInfo, wordSpaceCount,
letterSpaceCount, firstAreaInfoIndex,
@@ -291,6 +316,7 @@ public class TextLayoutManager extends L
addAreaInfoAreas(lastAreaInfo, wordSpaceCount, letterSpaceCount, firstAreaInfoIndex,
lastAreaInfoIndex, realWidth, context);
}
+
}
private void addAreaInfoAreas(AreaInfo areaInfo, int wordSpaceCount, int letterSpaceCount,
@@ -301,7 +327,7 @@ public class TextLayoutManager extends L
// changes. However, it seems as if they should use the AreaInfo from
// firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last areaInfo.
// This needs to be checked.
- int textLength = areaInfo.getCharLength();
+ int textLength = areaInfo.getWordLength();
if (areaInfo.letterSpaceCount == textLength && !areaInfo.isHyphenated
&& context.isLastArea()) {
// the line ends at a character like "/" or "-";
@@ -311,8 +337,8 @@ public class TextLayoutManager extends L
}
for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
- MinOptMax letterAdjustment = letterAdjustArray[i + 1];
- if (letterAdjustment != null && letterAdjustment.isElastic()) {
+ MinOptMax letterSpaceAdjustment = letterSpaceAdjustArray[i + 1];
+ if (letterSpaceAdjustment != null && letterSpaceAdjustment.isElastic()) {
letterSpaceCount++;
}
}
@@ -387,21 +413,27 @@ public class TextLayoutManager extends L
private final class TextAreaBuilder {
- private final MinOptMax width;
- private final int adjust;
- private final LayoutContext context;
- private final int firstIndex;
- private final int lastIndex;
- private final boolean isLastArea;
- private final Font font;
-
- private int blockProgressionDimension;
- private AreaInfo areaInfo;
- private StringBuffer wordChars;
- private int[] letterAdjust;
- private int letterAdjustIndex;
-
- private TextArea textArea;
+ // constructor initialized state
+ private final MinOptMax width; // content ipd
+ private final int adjust; // content ipd adjustment
+ private final LayoutContext context; // layout context
+ private final int firstIndex; // index of first AreaInfo
+ private final int lastIndex; // index of last AreaInfo
+ private final boolean isLastArea; // true if last inline area in line area
+ private final Font font; // applicable font
+
+ // other, non-constructor state
+ private TextArea textArea; // text area being constructed
+ private int blockProgressionDimension; // calculated bpd
+ private AreaInfo areaInfo; // current area info when iterating over words
+ private StringBuffer wordChars; // current word's character buffer
+ private int[] letterSpaceAdjust; // current word's letter space adjustments
+ private int letterSpaceAdjustIndex; // last written letter space adjustment index
+ private int[] wordLevels; // current word's bidi levels
+ private int wordLevelsIndex; // last written bidi level index
+ private int wordIPD; // accumulated ipd of current word
+ private int[][] gposAdjustments; // current word's glyph position adjustments
+ private int gposAdjustmentsIndex; // last written glyph position adjustment index
/**
* Creates a new <code>TextAreaBuilder</code> which itself builds an inline word area. This
@@ -432,7 +464,7 @@ public class TextLayoutManager extends L
calcBlockProgressionDimension();
setBlockProgressionDimension();
setBaselineOffset();
- setOffset();
+ setBlockProgressionOffset();
setText();
TraitSetter.addFontTraits(textArea, font);
textArea.addTrait(Trait.COLOR, foText.getColor());
@@ -471,11 +503,11 @@ public class TextLayoutManager extends L
textArea.setBaselineOffset(font.getAscender());
}
- private void setOffset() {
+ private void setBlockProgressionOffset() {
if (blockProgressionDimension == alignmentContext.getHeight()) {
- textArea.setOffset(0);
+ textArea.setBlockProgressionOffset(0);
} else {
- textArea.setOffset(alignmentContext.getOffset());
+ textArea.setBlockProgressionOffset(alignmentContext.getOffset());
}
}
@@ -483,7 +515,7 @@ public class TextLayoutManager extends L
* Sets the text of the TextArea, split into words and spaces.
*/
private void setText() {
- int wordStartIndex = -1;
+ int areaInfoIndex = -1;
int wordCharLength = 0;
for (int wordIndex = firstIndex; wordIndex <= lastIndex; wordIndex++) {
areaInfo = getAreaInfo(wordIndex);
@@ -491,15 +523,15 @@ public class TextLayoutManager extends L
addSpaces();
} else {
// areaInfo stores information about a word fragment
- if (wordStartIndex == -1) {
+ if (areaInfoIndex == -1) {
// here starts a new word
- wordStartIndex = wordIndex;
+ areaInfoIndex = wordIndex;
wordCharLength = 0;
}
- wordCharLength += areaInfo.getCharLength();
+ wordCharLength += areaInfo.getWordLength();
if (isWordEnd(wordIndex)) {
- addWord(wordStartIndex, wordIndex, wordCharLength);
- wordStartIndex = -1;
+ addWord(areaInfoIndex, wordIndex, wordCharLength);
+ areaInfoIndex = -1;
}
}
}
@@ -509,26 +541,78 @@ public class TextLayoutManager extends L
return areaInfoIndex == lastIndex || getAreaInfo(areaInfoIndex + 1).isSpace;
}
- private void addWord(int startIndex, int endIndex, int charLength) {
+ /**
+ * Add word with fragments from STARTINDEX to ENDINDEX, where
+ * total length of (possibly mapped) word is CHARLENGTH.
+ * A word is composed from one or more word fragments, where each
+ * fragment corresponds to distinct instance in a sequence of
+ * area info instances starting at STARTINDEX continuing through (and
+ * including) ENDINDEX.
+ * @param startIndex index of first area info of word to add
+ * @param endIndex index of last area info of word to add
+ * @param wordLength number of (mapped) characters in word
+ */
+ private void addWord(int startIndex, int endIndex, int wordLength) {
+ int blockProgressionOffset = 0;
+ boolean gposAdjusted = false;
if (isHyphenated(endIndex)) {
- charLength++;
+ // TODO may be problematic in some I18N contexts [GA]
+ wordLength++;
}
- initWord(charLength);
+ initWord(wordLength);
+ // iterate over word's fragments, adding word chars (with bidi
+ // levels), letter space adjustments, and glyph position adjustments
for (int i = startIndex; i <= endIndex; i++) {
AreaInfo wordAreaInfo = getAreaInfo(i);
addWordChars(wordAreaInfo);
addLetterAdjust(wordAreaInfo);
+ if ( addGlyphPositionAdjustments(wordAreaInfo) ) {
+ gposAdjusted = true;
+ }
}
if (isHyphenated(endIndex)) {
+ // TODO may be problematic in some I18N contexts [GA]
addHyphenationChar();
}
- textArea.addWord(wordChars.toString(), 0, letterAdjust);
+ if ( !gposAdjusted ) {
+ gposAdjustments = null;
+ }
+ textArea.addWord(wordChars.toString(), wordIPD, letterSpaceAdjust,
+ getNonEmptyLevels(), gposAdjustments, blockProgressionOffset);
+ }
+
+ private int[] getNonEmptyLevels() {
+ if ( wordLevels != null ) {
+ assert wordLevelsIndex <= wordLevels.length;
+ boolean empty = true;
+ for ( int i = 0, n = wordLevelsIndex; i < n; i++ ) {
+ if ( wordLevels [ i ] >= 0 ) {
+ empty = false;
+ break;
+ }
+ }
+ return empty ? null : wordLevels;
+ } else {
+ return null;
+ }
}
- private void initWord(int charLength) {
- wordChars = new StringBuffer(charLength);
- letterAdjust = new int[charLength];
- letterAdjustIndex = 0;
+ /**
+ * Fully allocate word character buffer, letter space adjustments
+ * array, bidi levels array, and glyph position adjustments array.
+ * based on full word length, including all (possibly mapped) fragments.
+ * @param wordLength length of word including all (possibly mapped) fragments
+ */
+ private void initWord(int wordLength) {
+ wordChars = new StringBuffer(wordLength);
+ letterSpaceAdjust = new int[wordLength];
+ letterSpaceAdjustIndex = 0;
+ wordLevels = new int[wordLength];
+ wordLevelsIndex = 0;
+ Arrays.fill ( wordLevels, -1 );
+ gposAdjustments = new int[wordLength][4];
+ gposAdjustmentsIndex = 0;
+ wordIPD = 0;
}
private boolean isHyphenated(int endIndex) {
@@ -537,27 +621,112 @@ public class TextLayoutManager extends L
private void addHyphenationChar() {
wordChars.append(foText.getCommonHyphenation().getHyphChar(font));
+ // [TBD] expand bidi word levels, letter space adjusts, gpos adjusts
+ // [TBD] [GA] problematic in bidi context... what is level of hyphen?
}
+ /**
+ * Given a word area info associated with a word fragment,
+ * (1) concatenate (possibly mapped) word characters to word character buffer;
+ * (2) concatenante (possibly mapped) word bidi levels to levels buffer;
+ * (3) update word's IPD with optimal IPD of fragment.
+ * @param wordAreaInfo fragment info
+ */
private void addWordChars(AreaInfo wordAreaInfo) {
- for (int i = wordAreaInfo.startIndex; i < wordAreaInfo.breakIndex; i++) {
- wordChars.append(foText.charAt(i));
+ int s = wordAreaInfo.startIndex;
+ int e = wordAreaInfo.breakIndex;
+ if ( foText.hasMapping ( s, e ) ) {
+ wordChars.append ( foText.getMapping ( s, e ) );
+ addWordLevels ( foText.getMappingBidiLevels ( s, e ) );
+ } else {
+ for (int i = s; i < e; i++) {
+ wordChars.append(foText.charAt(i));
+ }
+ addWordLevels ( foText.getBidiLevels ( s, e ) );
}
+ wordIPD += wordAreaInfo.areaIPD.getOpt();
}
+ /**
+ * Given a (possibly null) bidi levels array associated with a word fragment,
+ * concatenante (possibly mapped) word bidi levels to levels buffer.
+ * @param levels bidi levels array or null
+ */
+ private void addWordLevels ( int[] levels ) {
+ int numLevels = ( levels != null ) ? levels.length : 0;
+ if ( numLevels > 0 ) {
+ int need = wordLevelsIndex + numLevels;
+ if ( need <= wordLevels.length ) {
+ System.arraycopy ( levels, 0, wordLevels, wordLevelsIndex, numLevels );
+ } else {
+ throw new IllegalStateException
+ ( "word levels array too short: expect at least "
+ + need + " entries, but has only " + wordLevels.length + " entries" );
+ }
+ }
+ wordLevelsIndex += numLevels;
+ }
+
+ /**
+ * Given a word area info associated with a word fragment,
+ * concatenate letter space adjustments for each (possibly mapped) character.
+ * @param wordAreaInfo fragment info
+ */
private void addLetterAdjust(AreaInfo wordAreaInfo) {
int letterSpaceCount = wordAreaInfo.letterSpaceCount;
- for (int i = wordAreaInfo.startIndex; i < wordAreaInfo.breakIndex; i++) {
- if (letterAdjustIndex > 0) {
- MinOptMax adj = letterAdjustArray[i];
- letterAdjust[letterAdjustIndex] = adj == null ? 0 : adj.getOpt();
+ int wordLength = wordAreaInfo.getWordLength();
+ int taAdjust = textArea.getTextLetterSpaceAdjust();
+ for ( int i = 0, n = wordLength; i < n; i++ ) {
+ int j = letterSpaceAdjustIndex + i;
+ if ( j > 0 ) {
+ int k = wordAreaInfo.startIndex + i;
+ MinOptMax adj = ( k < letterSpaceAdjustArray.length )
+ ? letterSpaceAdjustArray [ k ] : null;
+ letterSpaceAdjust [ j ] = ( adj == null ) ? 0 : adj.getOpt();
}
- if (letterSpaceCount > 0) {
- letterAdjust[letterAdjustIndex] += textArea.getTextLetterSpaceAdjust();
+ if ( letterSpaceCount > 0 ) {
+ letterSpaceAdjust [ j ] += taAdjust;
letterSpaceCount--;
}
- letterAdjustIndex++;
}
+ letterSpaceAdjustIndex += wordLength;
+ }
+
+ /**
+ * Given a word area info associated with a word fragment,
+ * concatenate glyph position adjustments for each (possibly mapped) character.
+ * @param wordAreaInfo fragment info
+ * @return true if an adjustment was non-zero
+ */
+ private boolean addGlyphPositionAdjustments(AreaInfo wordAreaInfo) {
+ boolean adjusted = false;
+ int[][] gpa = wordAreaInfo.gposAdjustments;
+ int numAdjusts = ( gpa != null ) ? gpa.length : 0;
+ int wordLength = wordAreaInfo.getWordLength();
+ if ( numAdjusts > 0 ) {
+ int need = gposAdjustmentsIndex + numAdjusts;
+ if ( need <= gposAdjustments.length ) {
+ for ( int i = 0, n = wordLength, j = 0; i < n; i++ ) {
+ if ( i < numAdjusts ) {
+ int[] wpa1 = gposAdjustments [ gposAdjustmentsIndex + i ];
+ int[] wpa2 = gpa [ j++ ];
+ for ( int k = 0; k < 4; k++ ) {
+ int a = wpa2 [ k ];
+ if ( a != 0 ) {
+ wpa1 [ k ] += a; adjusted = true;
+ }
+ }
+ }
+ }
+ } else {
+ throw new IllegalStateException
+ ( "gpos adjustments array too short: expect at least "
+ + need + " entries, but has only " + gposAdjustments.length
+ + " entries" );
+ }
+ }
+ gposAdjustmentsIndex += wordLength;
+ return adjusted;
}
/**
@@ -566,13 +735,44 @@ public class TextLayoutManager extends L
* Add the spaces - except zero-width spaces - to the TextArea.
*/
private void addSpaces() {
+ int blockProgressionOffset = 0;
+ // [TBD] need to better handling of spaceIPD assignment, for now,
+ // divide the area info's allocated IPD evenly among the
+ // non-zero-width space characters
+ int numZeroWidthSpaces = 0;
for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
char spaceChar = foText.charAt(i);
+ if (CharUtilities.isZeroWidthSpace(spaceChar)) {
+ numZeroWidthSpaces++;
+ }
+ }
+ int numSpaces = areaInfo.breakIndex - areaInfo.startIndex - numZeroWidthSpaces;
+ int spaceIPD = areaInfo.areaIPD.getOpt() / ( ( numSpaces > 0 ) ? numSpaces : 1 );
+ // add space area children, one for each non-zero-width space character
+ for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+ char spaceChar = foText.charAt(i);
+ int level = foText.bidiLevelAt(i);
if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
- textArea.addSpace(spaceChar, 0, CharUtilities.isAdjustableSpace(spaceChar));
+ textArea.addSpace
+ ( spaceChar, spaceIPD,
+ CharUtilities.isAdjustableSpace(spaceChar),
+ blockProgressionOffset, level );
}
}
}
+
+ }
+
+ private void addAreaInfo ( AreaInfo ai ) {
+ addAreaInfo ( areaInfos.size(), ai );
+ }
+
+ private void addAreaInfo ( int index, AreaInfo ai ) {
+ areaInfos.add ( index, ai );
+ }
+
+ private void removeAreaInfo ( int index ) {
+ areaInfos.remove ( index );
}
private AreaInfo getAreaInfo(int index) {
@@ -580,10 +780,10 @@ public class TextLayoutManager extends L
}
private void addToLetterAdjust(int index, int width) {
- if (letterAdjustArray[index] == null) {
- letterAdjustArray[index] = MinOptMax.getInstance(width);
+ if (letterSpaceAdjustArray[index] == null) {
+ letterSpaceAdjustArray[index] = MinOptMax.getInstance(width);
} else {
- letterAdjustArray[index] = letterAdjustArray[index].plus(width);
+ letterSpaceAdjustArray[index] = letterSpaceAdjustArray[index].plus(width);
}
}
@@ -600,6 +800,7 @@ public class TextLayoutManager extends L
/** {@inheritDoc} */
public List getNextKnuthElements(final LayoutContext context, final int alignment) {
+
lineStartBAP = context.getLineStartBorderAndPaddingWidth();
lineEndBAP = context.getLineEndBorderAndPaddingWidth();
alignmentContext = context.getAlignmentContext();
@@ -610,13 +811,19 @@ public class TextLayoutManager extends L
AreaInfo prevAreaInfo = null;
returnList.add(sequence);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug ( "GK: [" + nextStart + "," + foText.length() + "]" );
+ }
LineBreakStatus lineBreakStatus = new LineBreakStatus();
thisStart = nextStart;
boolean inWord = false;
boolean inWhitespace = false;
char ch = 0;
+ int level = -1;
+ int prevLevel = -1;
while (nextStart < foText.length()) {
ch = foText.charAt(nextStart);
+ level = foText.bidiLevelAt(nextStart);
boolean breakOpportunity = false;
byte breakAction = keepTogether
? LineBreakStatus.PROHIBITED_BREAK
@@ -635,17 +842,29 @@ public class TextLayoutManager extends L
default:
TextLayoutManager.LOG.error("Unexpected breakAction: " + breakAction);
}
+ if (LOG.isDebugEnabled()) {
+ LOG.debug ( "GK: {"
+ + " index = " + nextStart
+ + ", char = " + CharUtilities.charToNCRef ( ch )
+ + ", level = " + level
+ + ", levelPrev = " + prevLevel
+ + ", inWord = " + inWord
+ + ", inSpace = " + inWhitespace
+ + "}" );
+ }
if (inWord) {
- if (breakOpportunity
- || TextLayoutManager.isSpace(ch)
- || CharUtilities.isExplicitBreak(ch)) {
+ if ( breakOpportunity
+ || TextLayoutManager.isSpace(ch)
+ || CharUtilities.isExplicitBreak(ch)
+ || ( ( prevLevel != -1 ) && ( level != prevLevel ) ) ) {
// this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN
prevAreaInfo = processWord(alignment, sequence, prevAreaInfo, ch,
- breakOpportunity, true);
+ breakOpportunity, true, prevLevel);
}
} else if (inWhitespace) {
if (ch != CharUtilities.SPACE || breakOpportunity) {
- prevAreaInfo = processWhitespace(alignment, sequence, breakOpportunity);
+ prevAreaInfo = processWhitespace(alignment, sequence,
+ breakOpportunity, prevLevel);
}
} else {
if (areaInfo != null) {
@@ -665,14 +884,14 @@ public class TextLayoutManager extends L
// preserved space or non-breaking space:
// create the AreaInfo object
areaInfo = new AreaInfo(nextStart, nextStart + 1, 1, 0, wordSpaceIPD, false, true,
- breakOpportunity, spaceFont);
+ breakOpportunity, spaceFont, level, null);
thisStart = nextStart + 1;
} else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
// create the AreaInfo object
Font font = FontSelector.selectFontForCharacterInText(ch, foText, this);
MinOptMax ipd = MinOptMax.getInstance(font.getCharWidth(ch));
areaInfo = new AreaInfo(nextStart, nextStart + 1, 0, 0, ipd, false, true,
- breakOpportunity, font);
+ breakOpportunity, font, level, null);
thisStart = nextStart + 1;
} else if (CharUtilities.isExplicitBreak(ch)) {
//mandatory break-character: only advance index
@@ -682,14 +901,15 @@ public class TextLayoutManager extends L
inWord = !TextLayoutManager.isSpace(ch) && !CharUtilities.isExplicitBreak(ch);
inWhitespace = ch == CharUtilities.SPACE
&& foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
+ prevLevel = level;
nextStart++;
}
// Process any last elements
if (inWord) {
- processWord(alignment, sequence, prevAreaInfo, ch, false, false);
+ processWord(alignment, sequence, prevAreaInfo, ch, false, false, prevLevel);
} else if (inWhitespace) {
- processWhitespace(alignment, sequence, !keepTogether);
+ processWhitespace(alignment, sequence, !keepTogether, prevLevel);
} else if (areaInfo != null) {
processLeftoverAreaInfo(alignment, sequence, areaInfo,
ch == CharUtilities.ZERO_WIDTH_SPACE);
@@ -708,6 +928,8 @@ public class TextLayoutManager extends L
} else {
return returnList;
}
+
+
}
private KnuthSequence processLinebreak(List returnList, KnuthSequence sequence) {
@@ -723,20 +945,27 @@ public class TextLayoutManager extends L
private void processLeftoverAreaInfo(int alignment,
KnuthSequence sequence, AreaInfo areaInfo,
boolean breakOpportunityAfter) {
- areaInfos.add(areaInfo);
+ addAreaInfo(areaInfo);
areaInfo.breakOppAfter = breakOpportunityAfter;
addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
}
private AreaInfo processWhitespace(final int alignment,
- final KnuthSequence sequence, final boolean breakOpportunity) {
+ final KnuthSequence sequence, final boolean breakOpportunity, int level) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug ( "PS: [" + thisStart + "," + nextStart + "]" );
+ }
+
// End of whitespace
// create the AreaInfo object
assert nextStart >= thisStart;
- AreaInfo areaInfo = new AreaInfo(thisStart, nextStart, nextStart - thisStart, 0,
- wordSpaceIPD.mult(nextStart - thisStart), false, true, breakOpportunity, spaceFont);
+ AreaInfo areaInfo = new AreaInfo
+ ( thisStart, nextStart, nextStart - thisStart, 0,
+ wordSpaceIPD.mult(nextStart - thisStart),
+ false, true, breakOpportunity, spaceFont, level, null );
- areaInfos.add(areaInfo);
+ addAreaInfo(areaInfo);
// create the elements
addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
@@ -745,22 +974,136 @@ public class TextLayoutManager extends L
return areaInfo;
}
- private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
- AreaInfo prevAreaInfo, final char ch, final boolean breakOpportunity,
- final boolean checkEndsWithHyphen) {
+ private AreaInfo processWordMapping
+ ( int lastIndex, final Font font, AreaInfo prevAreaInfo, final char breakOpportunityChar,
+ final boolean endsWithHyphen, int level ) {
+ int s = this.thisStart; // start index of word in FOText character buffer
+ int e = lastIndex; // end index of word in FOText character buffer
+ int nLS = 0; // # of letter spaces
+ String script = foText.getScript();
+ String language = foText.getLanguage();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug ( "PW: [" + thisStart + "," + lastIndex + "]: {"
+ + " +M"
+ + ", level = " + level
+ + " }" );
+ }
+
+ // 1. extract unmapped character sequence
+ CharSequence ics = foText.subSequence ( s, e );
+
+ // 2. if script is not specified (by FO property) or it is specified as 'auto',
+ // then compute dominant script
+ if ( ( script == null ) || "auto".equals(script) ) {
+ script = CharScript.scriptTagFromCode ( CharScript.dominantScript ( ics ) );
+ }
+ if ( ( language == null ) || "none".equals(language) ) {
+ language = "dflt";
+ }
+
+ // 3. perform mapping of chars to glyphs ... to glyphs ... to chars
+ CharSequence mcs = font.performSubstitution ( ics, script, language );
+
+ // 4. compute glyph position adjustments on (substituted) characters
+ int[][] gpa;
+ if ( font.performsPositioning() ) {
+ // handle GPOS adjustments
+ gpa = font.performPositioning ( mcs, script, language );
+ } else if ( font.hasKerning() ) {
+ // handle standard (non-GPOS) kerning adjustments
+ gpa = getKerningAdjustments ( mcs, font );
+ } else {
+ gpa = null;
+ }
- //Word boundary found, process widths and kerning
- int lastIndex = nextStart;
- while (lastIndex > 0 && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
- lastIndex--;
+ // 5. reorder combining marks so that they precede (within the mapped char sequence) the
+ // base to which they are applied; N.B. position adjustments (gpa) are reordered in place
+ mcs = font.reorderCombiningMarks ( mcs, gpa, script, language );
+
+ // 6. if mapped sequence differs from input sequence, then memoize mapped sequence
+ if ( !CharUtilities.isSameSequence ( mcs, ics ) ) {
+ foText.addMapping ( s, e, mcs );
+ }
+
+ // 7. compute word ipd based on final position adjustments
+ MinOptMax ipd = MinOptMax.ZERO;
+ for ( int i = 0, n = mcs.length(); i < n; i++ ) {
+ int c = mcs.charAt ( i );
+ // TODO !BMP
+ int w = font.getCharWidth ( c );
+ if ( w < 0 ) {
+ w = 0;
+ }
+ if ( gpa != null ) {
+ w += gpa [ i ] [ GlyphPositioningTable.Value.IDX_X_ADVANCE ];
+ }
+ ipd = ipd.plus ( w );
+ }
+
+ // [TBD] - handle letter spacing
+
+ return new AreaInfo
+ ( s, e, 0, nLS, ipd, endsWithHyphen, false,
+ breakOpportunityChar != 0, font, level, gpa );
+ }
+
+ /**
+ * Given a mapped character sequence MCS, obtain glyph position adjustments
+ * from the font's kerning data.
+ * @param mcs mapped character sequence
+ * @param font applicable font
+ * @return glyph position adjustments (or null if no kerning)
+ */
+ private int[][] getKerningAdjustments ( CharSequence mcs, final Font font ) {
+ int nc = mcs.length();
+ // extract kerning array
+ int[] ka = new int [ nc ]; // kerning array
+ for ( int i = 0, n = nc, cPrev = -1; i < n; i++ ) {
+ int c = mcs.charAt ( i );
+ // TODO !BMP
+ if ( cPrev >= 0 ) {
+ ka[i] = font.getKernValue ( cPrev, c );
+ }
+ cPrev = c;
+ }
+ // was there a non-zero kerning?
+ boolean hasKerning = false;
+ for ( int i = 0, n = nc; i < n; i++ ) {
+ if ( ka[i] != 0 ) {
+ hasKerning = true;
+ break;
+ }
}
- Font font = FontSelector
- .selectFontForCharactersInText(foText, thisStart, lastIndex, foText, this);
+ // if non-zero kerning, then create and return glyph position adjustment array
+ if ( hasKerning ) {
+ int[][] gpa = new int [ nc ] [ 4 ];
+ for ( int i = 0, n = nc; i < n; i++ ) {
+ if ( i > 0 ) {
+ gpa [ i - 1 ] [ GlyphPositioningTable.Value.IDX_X_ADVANCE ] = ka [ i ];
+ }
+ }
+ return gpa;
+ } else {
+ return null;
+ }
+ }
+
+ private AreaInfo processWordNoMapping(int lastIndex, final Font font, AreaInfo prevAreaInfo,
+ final char breakOpportunityChar, final boolean endsWithHyphen, int level) {
boolean kerning = font.hasKerning();
MinOptMax wordIPD = MinOptMax.ZERO;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug ( "PW: [" + thisStart + "," + lastIndex + "]: {"
+ + " -M"
+ + ", level = " + level
+ + " }" );
+ }
+
for (int i = thisStart; i < lastIndex; i++) {
char currentChar = foText.charAt(i);
-
+
//character width
int charWidth = font.getCharWidth(currentChar);
wordIPD = wordIPD.plus(charWidth);
@@ -782,14 +1125,12 @@ public class TextLayoutManager extends L
}
}
}
- boolean endsWithHyphen = checkEndsWithHyphen
- && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
if (kerning
- && breakOpportunity
- && !TextLayoutManager.isSpace(ch)
+ && ( breakOpportunityChar != 0 )
+ && !TextLayoutManager.isSpace(breakOpportunityChar)
&& lastIndex > 0
&& endsWithHyphen) {
- int kern = font.getKernValue(foText.charAt(lastIndex - 1), ch);
+ int kern = font.getKernValue(foText.charAt(lastIndex - 1), breakOpportunityChar);
if (kern != 0) {
addToLetterAdjust(lastIndex, kern);
//TODO: add kern to wordIPD?
@@ -801,23 +1142,46 @@ public class TextLayoutManager extends L
int letterSpaces = 0;
if (wordLength != 0) {
letterSpaces = wordLength - 1;
- // if there is a break opportunity and the next one
+ // if there is a break opportunity and the next one (break character)
// is not a space, it could be used as a line end;
// add one more letter space, in case other text follows
- if (breakOpportunity && !TextLayoutManager.isSpace(ch)) {
- letterSpaces++;
+ if (( breakOpportunityChar != 0 ) && !TextLayoutManager.isSpace(breakOpportunityChar)) {
+ letterSpaces++;
}
}
assert letterSpaces >= 0;
wordIPD = wordIPD.plus(letterSpaceIPD.mult(letterSpaces));
- // create the AreaInfo object
- AreaInfo areaInfo = new AreaInfo(thisStart, lastIndex, 0,
- letterSpaces, wordIPD,
- endsWithHyphen,
- false, breakOpportunity, font);
+ // create and return the AreaInfo object
+ return new AreaInfo(thisStart, lastIndex, 0,
+ letterSpaces, wordIPD,
+ endsWithHyphen,
+ false, breakOpportunityChar != 0, font, level, null);
+ }
+
+ private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
+ AreaInfo prevAreaInfo, final char ch, final boolean breakOpportunity,
+ final boolean checkEndsWithHyphen, int level) {
+
+ //Word boundary found, process widths and kerning
+ int lastIndex = nextStart;
+ while (lastIndex > 0 && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
+ lastIndex--;
+ }
+ final boolean endsWithHyphen = checkEndsWithHyphen
+ && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
+ Font font = FontSelector.selectFontForCharactersInText
+ ( foText, thisStart, lastIndex, foText, this );
+ AreaInfo areaInfo;
+ if ( font.performsSubstitution() || font.performsPositioning() ) {
+ areaInfo = processWordMapping
+ ( lastIndex, font, prevAreaInfo, breakOpportunity ? ch : 0, endsWithHyphen, level );
+ } else {
+ areaInfo = processWordNoMapping
+ ( lastIndex, font, prevAreaInfo, breakOpportunity ? ch : 0, endsWithHyphen, level );
+ }
prevAreaInfo = areaInfo;
- areaInfos.add(areaInfo);
+ addAreaInfo(areaInfo);
tempStart = nextStart;
//add the elements
@@ -902,22 +1266,22 @@ public class TextLayoutManager extends L
newIPD = newIPD.plus(font.getCharWidth(ch));
//if (i > startIndex) {
if (i < stopIndex) {
- MinOptMax letterAdjust = letterAdjustArray[i + 1];
+ MinOptMax letterSpaceAdjust = letterSpaceAdjustArray[i + 1];
if (i == stopIndex - 1 && hyphenFollows) {
//the letter adjust here needs to be handled further down during
//element generation because it depends on hyph/no-hyph condition
- letterAdjust = null;
+ letterSpaceAdjust = null;
}
- if (letterAdjust != null) {
- newIPD = newIPD.plus(letterAdjust);
+ if (letterSpaceAdjust != null) {
+ newIPD = newIPD.plus(letterSpaceAdjust);
}
}
}
// add letter spaces
boolean isWordEnd
- = stopIndex == areaInfo.breakIndex
- && areaInfo.letterSpaceCount < areaInfo.getCharLength();
+ = (stopIndex == areaInfo.breakIndex)
+ && (areaInfo.letterSpaceCount < areaInfo.getWordLength());
int letterSpaceCount = isWordEnd ? stopIndex - startIndex - 1 : stopIndex - startIndex;
assert letterSpaceCount >= 0;
@@ -925,8 +1289,11 @@ public class TextLayoutManager extends L
if (!(nothingChanged && stopIndex == areaInfo.breakIndex && !hyphenFollows)) {
// the new AreaInfo object is not equal to the old one
- changeList.add(new PendingChange(new AreaInfo(startIndex, stopIndex, 0,
- letterSpaceCount, newIPD, hyphenFollows, false, false, font),
+ changeList.add
+ ( new PendingChange
+ ( new AreaInfo(startIndex, stopIndex, 0,
+ letterSpaceCount, newIPD, hyphenFollows,
+ false, false, font, -1, null),
((LeafPosition) pos).getLeafPos() + changeOffset));
nothingChanged = false;
}
@@ -992,9 +1359,9 @@ public class TextLayoutManager extends L
areaInfosAdded++;
oldIndex = currChange.index;
changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
- areaInfos.remove(changeIndex);
+ removeAreaInfo(changeIndex);
}
- areaInfos.add(changeIndex, currChange.areaInfo);
+ addAreaInfo(changeIndex, currChange.areaInfo);
}
changeList.clear();
}
@@ -1035,7 +1402,7 @@ public class TextLayoutManager extends L
int leafValue = ((LeafPosition) pos).getLeafPos() + changeOffset;
if (leafValue != -1) {
AreaInfo areaInfo = getAreaInfo(leafValue);
- StringBuffer buffer = new StringBuffer(areaInfo.getCharLength());
+ StringBuffer buffer = new StringBuffer(areaInfo.getWordLength());
for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
buffer.append(foText.charAt(i));
}
@@ -1209,7 +1576,7 @@ public class TextLayoutManager extends L
MinOptMax widthIfNoBreakOccurs = null;
if (areaInfo.breakIndex < foText.length()) {
//Add in kerning in no-break condition
- widthIfNoBreakOccurs = letterAdjustArray[areaInfo.breakIndex];
+ widthIfNoBreakOccurs = letterSpaceAdjustArray[areaInfo.breakIndex];
}
//if (areaInfo.breakIndex)
@@ -1325,4 +1692,14 @@ public class TextLayoutManager extends L
}
+ /** {@inheritDoc} */
+ public String toString() {
+ return super.toString() + "{"
+ + "chars = \'"
+ + CharUtilities.toNCRefs ( foText.getCharSequence().toString() )
+ + "\'"
+ + ", len = " + foText.length()
+ + "}";
+ }
+
}
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -120,8 +120,8 @@ public class ListBlockLayoutManager exte
}
/**
- * The table area is a reference area that contains areas for
- * columns, bodies, rows and the contents are in cells.
+ * A list block generates one or more normal block areas whose child areas are
+ * normal block areas returned by the children of fo:list-block. See XSL-FO 1.1 6.8.2.
*
* @param parentIter the position iterator
* @param layoutContext the layout context for adding areas
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -45,7 +45,7 @@ public class ListItemContentLayoutManage
private Block curBlockArea;
- private int xoffset;
+ private int xOffset;
private int itemIPD;
/**
@@ -80,7 +80,7 @@ public class ListItemContentLayoutManage
* @param off the x offset
*/
public void setXOffset(int off) {
- xoffset = off;
+ xOffset = off;
}
/**
@@ -175,7 +175,7 @@ public class ListItemContentLayoutManage
curBlockArea = new Block();
curBlockArea.setPositioning(Block.ABSOLUTE);
// set position
- curBlockArea.setXOffset(xoffset);
+ curBlockArea.setXOffset(xOffset);
//TODO: Check - itemIPD never set?
curBlockArea.setIPD(itemIPD);
//curBlockArea.setHeight();
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java Sun Feb 26 02:29:01 2012
@@ -465,7 +465,6 @@ public class ListItemLayoutManager exten
/**
* Add the areas for the break points.
- * This sets the offset of each cell as it is added.
*
* @param parentIter the position iterator
* @param layoutContext the layout context for adding areas
@@ -507,12 +506,12 @@ public class ListItemLayoutManager exten
int bodyFirstIndex = ((ListItemPosition) positionList.getFirst()).getBodyFirstIndex();
int bodyLastIndex = ((ListItemPosition) positionList.getLast()).getBodyLastIndex();
- //Determine previous break if any
+ //Determine previous break if any (in item label list)
int previousBreak = ElementListUtils.determinePreviousBreak(labelList, labelFirstIndex);
SpaceResolver.performConditionalsNotification(labelList,
labelFirstIndex, labelLastIndex, previousBreak);
- //Determine previous break if any
+ //Determine previous break if any (in item body list)
previousBreak = ElementListUtils.determinePreviousBreak(bodyList, bodyFirstIndex);
SpaceResolver.performConditionalsNotification(bodyList,
bodyFirstIndex, bodyLastIndex, previousBreak);
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java Sun Feb 26 02:29:01 2012
@@ -33,6 +33,9 @@ import org.apache.fop.fo.expr.RelativeNu
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.properties.TableColLength;
+import org.apache.fop.traits.Direction;
+import org.apache.fop.traits.WritingModeTraits;
+import org.apache.fop.traits.WritingModeTraitsGetter;
/**
* Class holding a number of columns making up the column setup of a row.
@@ -43,6 +46,7 @@ public class ColumnSetup {
private static Log log = LogFactory.getLog(ColumnSetup.class);
private Table table;
+ private WritingModeTraitsGetter wmTraits;
private List columns = new java.util.ArrayList();
private List colWidths = new java.util.ArrayList();
@@ -53,7 +57,9 @@ public class ColumnSetup {
* @param table the table to construct this column setup for
*/
public ColumnSetup(Table table) {
+ assert table != null;
this.table = table;
+ this.wmTraits = WritingModeTraits.getWritingModeTraitsGetter ( table );
prepareColumns();
initializeColumnWidths();
}
@@ -232,11 +238,47 @@ public class ColumnSetup {
}
/**
+ * Determine the X offset of the indicated column, where this
+ * offset denotes the left edge of the column irrespective of writing
+ * mode. If writing mode's column progression direction is right-to-left,
+ * then the first column is the right-most column and the last column is
+ * the left-most column; otherwise, the first column is the left-most
+ * column.
* @param col column index (1 is first column)
* @param context the context for percentage based calculations
* @return the X offset of the requested column
*/
public int getXOffset(int col, PercentBaseContext context) {
+ // TODO handle vertical WMs [GA]
+ if ( (wmTraits != null) && (wmTraits.getColumnProgressionDirection() == Direction.RL) ) {
+ return getXOffsetRTL(col, context);
+ } else {
+ return getXOffsetLTR(col, context);
+ }
+ }
+
+ /*
+ * Determine x offset by summing widths of columns to left of specified
+ * column; i.e., those columns whose column numbers are greater than the
+ * specified column number.
+ */
+ private int getXOffsetRTL(int col, PercentBaseContext context) {
+ int xoffset = 0;
+ for (int i = col, nc = colWidths.size(); ++i < nc;) {
+ int effCol = i;
+ if (colWidths.get(effCol) != null) {
+ xoffset += ((Length) colWidths.get(effCol)).getValue(context);
+ }
+ }
+ return xoffset;
+ }
+
+ /*
+ * Determine x offset by summing widths of columns to left of specified
+ * column; i.e., those columns whose column numbers are less than the
+ * specified column number.
+ */
+ private int getXOffsetLTR(int col, PercentBaseContext context) {
int xoffset = 0;
for (int i = col; --i >= 0;) {
int effCol;
Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFTextUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFTextUtil.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFTextUtil.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFTextUtil.java Sun Feb 26 02:29:01 2012
@@ -81,8 +81,8 @@ public abstract class PDFTextUtil {
sb.append(PDFNumber.doubleOut(lt[5], DEC));
}
- private void writeChar(char ch, StringBuffer sb) {
- if (!useMultiByte) {
+ private static void writeChar(char ch, StringBuffer sb, boolean multibyte) {
+ if (!multibyte) {
if (ch < 32 || ch > 127) {
sb.append("\\").append(Integer.toOctalString(ch));
} else {
@@ -101,6 +101,10 @@ public abstract class PDFTextUtil {
}
}
+ private void writeChar(char ch, StringBuffer sb) {
+ writeChar ( ch, sb, useMultiByte );
+ }
+
private void checkInTextObject() {
if (!inTextObject) {
throw new IllegalStateException("Not in text object");
@@ -245,24 +249,38 @@ public abstract class PDFTextUtil {
bufTJ = new StringBuffer();
}
if (bufTJ.length() == 0) {
- bufTJ.append("[").append(startText);
+ bufTJ.append("[");
+ bufTJ.append(startText);
}
writeChar(codepoint, bufTJ);
}
/**
* Writes a glyph adjust value to the "TJ-Buffer".
+
+ * <p>Assumes the following:</p>
+ * <ol>
+ * <li>if buffer is currently empty, then this is the start of the array object
+ * that encodes the adjustment and character values, and, therfore, a LEFT
+ * SQUARE BRACKET '[' must be prepended; and
+ * </li>
+ * <li>otherwise (the buffer is
+ * not empty), then the last element written to the buffer was a mapped
+ * character, and, therefore, a terminating '>' or ')' followed by a space
+ * must be appended to the buffer prior to appending the adjustment value.
+ * </li>
+ * </ol>
* @param adjust the glyph adjust value in thousands of text unit space.
*/
public void adjustGlyphTJ(double adjust) {
if (bufTJ == null) {
bufTJ = new StringBuffer();
}
- if (bufTJ.length() > 0) {
- bufTJ.append(endText).append(" ");
- }
if (bufTJ.length() == 0) {
bufTJ.append("[");
+ } else {
+ bufTJ.append(endText);
+ bufTJ.append(" ");
}
bufTJ.append(PDFNumber.doubleOut(adjust, DEC - 4));
bufTJ.append(" ");
@@ -285,4 +303,31 @@ public abstract class PDFTextUtil {
return bufTJ != null && bufTJ.length() > 0;
}
+ /**
+ * Writes a "Td" command with specified x and y coordinates.
+ * @param x coordinate
+ * @param y coordinate
+ */
+ public void writeTd ( double x, double y ) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(PDFNumber.doubleOut(x, DEC));
+ sb.append(' ');
+ sb.append(PDFNumber.doubleOut(y, DEC));
+ sb.append ( " Td\n" );
+ write ( sb.toString() );
+ }
+
+ /**
+ * Writes a "Tj" command with specified character code.
+ * @param ch character code to write
+ */
+ public void writeTj ( char ch ) {
+ StringBuffer sb = new StringBuffer();
+ sb.append ( '<' );
+ writeChar ( ch, sb, true );
+ sb.append ( '>' );
+ sb.append ( " Tj\n" );
+ write ( sb.toString() );
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org