aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaren Lease <klease@apache.org>2002-05-22 20:20:50 +0000
committerKaren Lease <klease@apache.org>2002-05-22 20:20:50 +0000
commit963f7ee8c580b22d7cc6200e3a410fc01db8f223 (patch)
tree2f8e72f884b0b8fe3d2d6b7e0aaffbe8ed1db452
parentacf92c1f0a8e1697f03afdede7a9061f013f149e (diff)
downloadxmlgraphics-fop-963f7ee8c580b22d7cc6200e3a410fc01db8f223.tar.gz
xmlgraphics-fop-963f7ee8c580b22d7cc6200e3a410fc01db8f223.zip
Add support for hyphenation and some space distribution among inline areas
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194837 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java19
-rw-r--r--src/org/apache/fop/layoutmgr/BPLayoutManager.java9
-rw-r--r--src/org/apache/fop/layoutmgr/BreakPoss.java2
-rw-r--r--src/org/apache/fop/layoutmgr/BreakPossPosIter.java4
-rw-r--r--src/org/apache/fop/layoutmgr/HyphContext.java48
-rw-r--r--src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java92
-rw-r--r--src/org/apache/fop/layoutmgr/LayoutContext.java17
-rw-r--r--src/org/apache/fop/layoutmgr/LineBPLayoutManager.java194
-rw-r--r--src/org/apache/fop/layoutmgr/PositionIterator.java4
-rw-r--r--src/org/apache/fop/layoutmgr/TextBPLayoutManager.java302
10 files changed, 439 insertions, 252 deletions
diff --git a/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java
index b3b3ffa01..57725fb4a 100644
--- a/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java
@@ -134,18 +134,6 @@ public abstract class AbstractBPLayoutManager extends AbstractLayoutManager
}
-// /**
-// * Get the BreakPoss at the start of the next "area".
-// * @param lc The LayoutContext for this LayoutManager.
-// * @param bpPrevEnd The Position returned by the previous call
-// * to getNextBreakPoss, or null if none.
-// */
-// public BreakPoss getStartBreakPoss(LayoutContext lc,
-// BreakPoss.Position bpPrevEnd) {
-// return null;
-// }
-
-
/**
* Generate and return the next break possibility.
* Each layout manager must implement this.
@@ -179,7 +167,12 @@ public abstract class AbstractBPLayoutManager extends AbstractLayoutManager
}
- public void addAreas(PositionIterator parentIter) {
+ public void addAreas(PositionIterator parentIter, double dSpaceAdjust) {
+ }
+
+
+ public void getWordChars(StringBuffer sbChars,
+ BreakPoss.Position bp1, BreakPoss.Position bp2) {
}
/* ---------------------------------------------------------
diff --git a/src/org/apache/fop/layoutmgr/BPLayoutManager.java b/src/org/apache/fop/layoutmgr/BPLayoutManager.java
index 32f7df9d7..26245b464 100644
--- a/src/org/apache/fop/layoutmgr/BPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/BPLayoutManager.java
@@ -39,10 +39,6 @@ public interface BPLayoutManager extends LayoutManager {
public BreakPoss getNextBreakPoss(LayoutContext context);
- /** CURRENTLY NOT USED
- public BreakPoss getStartBreakPoss(LayoutContext lc,
- BreakPoss.Position bpPrevEnd);
- **/
/**
* Return a value indicating whether this LayoutManager has laid out
@@ -62,10 +58,13 @@ public interface BPLayoutManager extends LayoutManager {
* by BreakPoss.Position objectw which will be returned by the
* Iterator.
*/
- public void addAreas(PositionIterator posIter) ;
+ public void addAreas(PositionIterator posIter, double dSpaceAdjust) ;
public void init() ;
public void resetPosition(BreakPoss.Position position);
+ public void getWordChars(StringBuffer sbChars,
+ BreakPoss.Position bp1, BreakPoss.Position bp2);
+
}
diff --git a/src/org/apache/fop/layoutmgr/BreakPoss.java b/src/org/apache/fop/layoutmgr/BreakPoss.java
index 80fa797c7..484988160 100644
--- a/src/org/apache/fop/layoutmgr/BreakPoss.java
+++ b/src/org/apache/fop/layoutmgr/BreakPoss.java
@@ -40,6 +40,8 @@ public class BreakPoss {
// Set this flag if all fo:character generated Areas would
// suppressed at the end or beginning of a line
public static final int ALL_ARE_SUPPRESS_AT_LB = 0x80;
+ /** This break possibility is a hyphenation */
+ public static final int HYPHENATED = 0x100;
/** The top-level layout manager which generated this BreakPoss. */
diff --git a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java
index a868ac5e5..59a80cec1 100644
--- a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java
+++ b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java
@@ -35,6 +35,10 @@ public class BreakPossPosIter extends PositionIterator {
return super.next();
}
+ public BreakPoss getBP() {
+ return (BreakPoss)peekNext();
+ }
+
protected BPLayoutManager getLM(Object nextObj) {
return ((BreakPoss)nextObj).getLayoutManager();
}
diff --git a/src/org/apache/fop/layoutmgr/HyphContext.java b/src/org/apache/fop/layoutmgr/HyphContext.java
new file mode 100644
index 000000000..d89fd704b
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/HyphContext.java
@@ -0,0 +1,48 @@
+/*
+ * $Id$
+ * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+package org.apache.fop.layoutmgr;
+
+
+/**
+ * This class is used to pass information to the getNextBreakPoss()
+ * method concerning hyphenation. A reference to an instance of the
+ * class is contained in the LayoutContext object passed to each
+ * LayoutManager. It contains information concerning the hyphenation
+ * points in a word and the how many of those have previously been
+ * processed by a Layout Manager to generate size information.
+ */
+public class HyphContext {
+ private int[] m_hyphPoints;
+ private int m_iCurOffset=0;
+ private int m_iCurIndex=0;
+
+ public HyphContext(int[] hyphPoints) {
+ m_hyphPoints = hyphPoints;
+ }
+
+ public int getNextHyphPoint() {
+ for (; m_iCurIndex < m_hyphPoints.length; m_iCurIndex++) {
+ if (m_hyphPoints[m_iCurIndex] > m_iCurOffset) {
+ return (m_hyphPoints[m_iCurIndex] - m_iCurOffset);
+ }
+ }
+ return -1; // AT END!
+ }
+
+ public boolean hasMoreHyphPoints() {
+ for (; m_iCurIndex < m_hyphPoints.length; m_iCurIndex++) {
+ if (m_hyphPoints[m_iCurIndex] > m_iCurOffset) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void updateOffset(int iCharsProcessed) {
+ m_iCurOffset += iCharsProcessed;
+ }
+}
diff --git a/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
index 2a1763ea3..0f21d0e7b 100644
--- a/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
@@ -15,6 +15,7 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.MinOptMax;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.inline.Space;
import java.util.Iterator;
import java.util.ListIterator;
@@ -92,7 +93,6 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
protected void initProperties(PropertyManager propMgr) {
// super.initProperties(propMgr);
- System.err.println("InlineStackingBPLayoutManager.initProperties called");
m_inlineProps = propMgr.getInlineProps();
m_borderProps = propMgr.getBorderAndPadding();
// Calculdate border and padding size in BPD
@@ -140,7 +140,6 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
}
else {
// Backup to start of first child layout manager
- System.err.println("InlineStackingBPLM: resetPosition(null)");
m_prevBP = null;
super.resetPosition(prevPos);
}
@@ -172,6 +171,7 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
return (MinOptMax)m_hmPrevIPD.get(lm);
}
+
protected void clearPrevIPD() {
m_hmPrevIPD.clear();
}
@@ -210,8 +210,12 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
initChildLC(m_childLC, m_prevBP, lc.startsNewArea(), bFirstChildBP,
leadingSpace);
+ if (lc.tryHyphenate()) {
+ m_childLC.setHyphContext(lc.getHyphContext());
+ }
- if (((bp = curLM.getNextBreakPoss(m_childLC)) != null)) {
+ if (((bp = curLM.getNextBreakPoss(m_childLC)) != null) ||
+ (lc.tryHyphenate() && !lc.getHyphContext().hasMoreHyphPoints())) {
break;
}
// If LM has no content, should it generate any area? If not,
@@ -251,26 +255,6 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
}
-// protected boolean couldEndLine(BreakPoss bp) {
-// if (bp.canBreakAfter()) {
-// return true; // no keep, ends on break char
-// }
-// else if (bp.isSuppressible()) {
-// // NOTE: except at end of content for this LM!!
-// // Never break after only space chars or any other sequence
-// // of areas which would be suppressed at the end of the line.
-// return false;
-// }
-// else {
-// // See if could break before next area
-// LayoutContext lc=new LayoutContext();
-// BPLayoutManager nextLM = getChildLM();
-// return (nextLM == null ||
-// nextLM.canBreakBefore(lc));
-// }
-// }
-
-
private BreakPoss makeBreakPoss(BreakPoss bp, LayoutContext lc,
boolean bIsLast) {
@@ -295,39 +279,9 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
myBP.setLeadingSpace(lc.getPendingSpace());
}
-// if (lc.startsNewArea()) {
-// if (hasLeadingFence(!lc.isFirstArea())) {
-// // Space-start before first child area placed
-// prevIPD.add(bp.resolveLeadingSpace());
-// }
-// // Space-start sequence passed to ancestors
-// myBP.setLeadingSpace(lc.getPendingSpace());
-// m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
-// }
-// else {
-// // In case of reset to a previous position, it may already
-// // be calculated
-// prevIPD = (MinOptMax)m_hmPrevIPD.get(bp.getLayoutManager());
-// if (prevIPD == null) {
-// // ASSERT(m_prevBP.getLayoutManager() != bp.getLayoutManager());
-// /* This is first bp generated by child (in this parent area).
-// * Calculate space-start on this area in combination with any
-// * pending space-end with previous break.
-// * Corresponds to Space between two child areas.
-// */
-// prevIPD =
-// (MinOptMax)m_hmPrevIPD.get(m_prevBP.getLayoutManager());
-// prevIPD = MinOptMax.add(prevIPD, bp.resolveLeadingSpace());
-// prevIPD.add(m_prevBP.getStackingSize());
-// m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
-// }
-// }
+
// Add size of previous child areas which are finished
bpDim.add(prevIPD);
-// if (bp.isLastArea()) {
-// m_childLC.setPendingSpace((SpaceSpecifier)bp.getTrailingSpace().
-// clone());
-// }
SpaceSpecifier trailingSpace = bp.getTrailingSpace();
if (hasTrailingFence(!bIsLast)) {
@@ -362,8 +316,6 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
// Space-start before first child area placed
prevIPD.add(bp.resolveLeadingSpace());
}
- // Space-start sequence passed to ancestors
- // myBP.setLeadingSpace(lc.getPendingSpace());
m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
}
else {
@@ -377,8 +329,7 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
* pending space-end with previous break.
* Corresponds to Space between two child areas.
*/
- prevIPD =
- (MinOptMax)m_hmPrevIPD.get(prevBP.getLayoutManager());
+ prevIPD = (MinOptMax)m_hmPrevIPD.get(prevBP.getLayoutManager());
prevIPD = MinOptMax.add(prevIPD, bp.resolveLeadingSpace());
prevIPD.add(prevBP.getStackingSize());
m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
@@ -387,15 +338,32 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
return prevIPD;
}
+ public void getWordChars(StringBuffer sbChars,
+ BreakPoss.Position bp1, BreakPoss.Position bp2) {
+ WrappedPosition endPos = (WrappedPosition)bp2;
+ if (bp1 != null) {
+ WrappedPosition prevPos = (WrappedPosition)bp1;
+ if (prevPos.m_childLM == endPos.m_childLM) {
+ bp1 = prevPos.m_childPosition;
+ }
+ }
+ endPos.m_childLM.getWordChars(sbChars, bp1, endPos.m_childPosition);
+ }
/******
protected BreakableText getText(BreakPoss prevBP, BreakPoss lastBP) {
}
*****/
- // Generate and add areas to parent area
- // Set size etc
- public void addAreas(PositionIterator parentIter) {
+ /**
+ * Generate and add areas to parent area.
+ * Set size of each area.
+ * @param parentIter Iterator over BreakPoss.Position information returned
+ * by this LayoutManager.
+ * @param dSpaceAdjust Factor controlling how much extra space to add
+ * in order to justify the line.
+ */
+ public void addAreas(PositionIterator parentIter, double dSpaceAdjust) {
// Make areas from start to end
// Update childLM based on bpEnd
// It might be a previous sibling of the current one!
@@ -410,7 +378,7 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
StackingIter childPosIter = new StackingIter(parentIter);
BPLayoutManager childLM ;
while ((childLM = childPosIter.getNextChildLM())!= null) {
- childLM.addAreas(childPosIter);
+ childLM.addAreas(childPosIter, dSpaceAdjust);
}
parentLM.addChild(m_inlineArea);
diff --git a/src/org/apache/fop/layoutmgr/LayoutContext.java b/src/org/apache/fop/layoutmgr/LayoutContext.java
index 12e693716..a3dd778ce 100644
--- a/src/org/apache/fop/layoutmgr/LayoutContext.java
+++ b/src/org/apache/fop/layoutmgr/LayoutContext.java
@@ -34,6 +34,7 @@ public class LayoutContext {
*/
public static final int SUPPRESS_LEADING_SPACE = 0x10;
public static final int FIRST_AREA = 0x20;
+ public static final int TRY_HYPHENATE = 0x40;
public int flags; // Contains some set of flags defined above
@@ -56,11 +57,15 @@ public class LayoutContext {
/** Current pending space-after or space-end from preceding area */
SpaceSpecifier m_pendingSpace;
+ /** Current hyphenation context. May be null. */
+ private HyphContext m_hyphContext=null;
+
public LayoutContext(LayoutContext parentLC) {
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
this.m_stackLimit = null; // Don't reference parent MinOptMax!
this.m_pendingSpace = parentLC.m_pendingSpace; //???
+ this.m_hyphContext = parentLC.m_hyphContext;
// Copy other fields as necessary. Use clone???
}
@@ -119,4 +124,16 @@ public class LayoutContext {
public MinOptMax getStackLimit() {
return m_stackLimit ;
}
+
+ public void setHyphContext(HyphContext hyphContext) {
+ m_hyphContext = hyphContext;
+ }
+
+ public HyphContext getHyphContext() {
+ return m_hyphContext;
+ }
+
+ public boolean tryHyphenate() {
+ return ((this.flags & TRY_HYPHENATE) != 0);
+ }
}
diff --git a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
index 0517fc47f..ff3cffd64 100644
--- a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
@@ -12,6 +12,9 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.TextInfo;
import org.apache.fop.fo.PropertyManager;
import org.apache.fop.layout.MarginProps;
+import org.apache.fop.layout.HyphenationProps;
+import org.apache.fop.layout.hyphenation.Hyphenation;
+import org.apache.fop.layout.hyphenation.Hyphenator;
import org.apache.fop.traits.BlockProps;
import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
@@ -62,6 +65,7 @@ public class LineBPLayoutManager extends
private boolean m_bJustify = false; // True if fo:block text-align=JUSTIFY
private int m_iTextIndent = 0;
private int m_iIndents = 0;
+ private HyphenationProps m_hyphProps;
private int lineHeight;
private int lead;
@@ -77,13 +81,12 @@ public class LineBPLayoutManager extends
}
protected void initProperties(PropertyManager propMgr) {
- // super.initProperties(propMgr);
- System.err.println("LineBPLayoutManager.initProperties called");
MarginProps marginProps = propMgr.getMarginProps();
m_iIndents = marginProps.startIndent + marginProps.endIndent;
BlockProps blockProps = propMgr.getBlockProps();
m_bJustify = (blockProps.textAlign == TextAlign.JUSTIFY);
m_iTextIndent = blockProps.firstIndent;
+ m_hyphProps = propMgr.getHyphenationProps();
}
@@ -120,6 +123,7 @@ public class LineBPLayoutManager extends
LayoutContext inlineLC = new LayoutContext(context);
clearPrevIPD();
+ int iPrevLineEnd = m_vecInlineBreaks.size();
while ((curLM = getChildLM()) != null) {
// INITIALIZE LAYOUT CONTEXT FOR CALL TO CHILD LM
@@ -129,39 +133,31 @@ public class LineBPLayoutManager extends
(((BreakPoss)m_vecInlineBreaks.lastElement()).
getLayoutManager() != curLM));
- initChildLC(inlineLC, bp, (bp==null), bFirstBPforLM,
+ // Need previous breakpoint! ATTENTION when backing up for hyphenation!
+ prevBP = (m_vecInlineBreaks.isEmpty())? null:
+ (BreakPoss)m_vecInlineBreaks.lastElement();
+ initChildLC(inlineLC, prevBP,
+ (m_vecInlineBreaks.size()==iPrevLineEnd), bFirstBPforLM,
new SpaceSpecifier(true));
-// if (bp == null) {
-// // Start of a new line area
-// inlineLC.setFlags(LayoutContext.FIRST_AREA, bFirstBPforLM );
-// inlineLC.setPendingSpace(new SpaceSpecifier(true));
-// }
-// else if (bFirstBPforLM) {
-// // Space-after sequence from previous "area"
-// inlineLC.setFlags(LayoutContext.FIRST_AREA, true);
-// inlineLC.setPendingSpace(bp.getTrailingSpace());
-// }
-// else {
-// inlineLC.setPendingSpace(null);
-// }
-
/* If first BP in this line but line is not first in this
* LM and previous line end decision was not forced (LINEFEED),
* then set the SUPPRESS_LEADING_SPACE flag.
*/
inlineLC.setFlags(LayoutContext.SUPPRESS_LEADING_SPACE,
- (bp == null && !m_vecInlineBreaks.isEmpty() &&
+ (prevBP == null && !m_vecInlineBreaks.isEmpty() &&
((BreakPoss)m_vecInlineBreaks.lastElement()).
isForcedBreak()==false));
// GET NEXT POSSIBLE BREAK FROM CHILD LM
- prevBP = bp;
+ // prevBP = bp;
if ((bp = curLM.getNextBreakPoss(inlineLC, null)) != null) {
// Add any space before and previous content dimension
- MinOptMax prevIPD = updatePrevIPD(bp, prevBP, (prevBP==null),
- inlineLC.isFirstArea());
+ MinOptMax prevIPD =
+ updatePrevIPD(bp, prevBP,
+ (m_vecInlineBreaks.size()==iPrevLineEnd),
+ inlineLC.isFirstArea());
MinOptMax bpDim = MinOptMax.add(bp.getStackingSize(), prevIPD);
// check if this bp fits in line
@@ -175,41 +171,40 @@ public class LineBPLayoutManager extends
// TODO: stop if linebreak is forced (NEWLINE)
// PROBLEM: interaction with wrap which can be set
// at lower levels!
- System.err.println("BPdim=" + bpDim.opt);
+ // System.err.println("BPdim=" + bpDim.opt);
// Check if proposed area would fit in line
if (bpDim.min > availIPD.max) {
// See if we have already found a potential break
- if (vecPossEnd.size() > 0) break;
+ //if (vecPossEnd.size() > 0) break;
// This break position doesn't fit
// TODO: If we are in nowrap, we use it as is!
if (m_bJustify || m_prevBP == null) {
- // try to find a hyphenation point in the word
- // which spans the queued breaks and the proposed bp
- // Even if not justified, we must try to hyphenate if
- // there is no breakpoint at all up to this point!
- do {
- bp = findHyphenPoss(m_prevBP, bp);
- } while (bp != null &&
- (bp.getStackingSize().min > availIPD.max));
- if (bp == null) {
- // Couldn't find a hyphenation point. The line
- // will be "short".
+ // If we are already in a hyphenation loop, then stop.
+
+ if (inlineLC.tryHyphenate()) {
+ break;
}
- else {
- m_prevBP = bp;
+ // Otherwise, prepare to try hyphenation
+ if (!bBreakOK) {
+ // Make sure we collect the entire word!
+ m_vecInlineBreaks.add(bp);
+ continue;
}
- // Handle pendingIPD if any. The hyphenation point
- // may be within the "pending" content or after it.
- /* Make sure child LM are updated concerning the actual
- * hyphenation BreakPoss for their next call!
- */
+
+ inlineLC.setHyphContext(getHyphenContext(m_prevBP, bp));
+ if (inlineLC.getHyphContext()==null) break;
+ inlineLC.setFlags(LayoutContext.TRY_HYPHENATE, true);
+ // Reset to previous acceptable break
+ reset();
}
/* If we are not in justified text, we can end the line at
* prevBP.
*/
- break;
+ else {
+ break;
+ }
}
else {
// Add the BP to the list whether or not we can break
@@ -229,7 +224,6 @@ public class LineBPLayoutManager extends
* (ie, bpDim.opt closes to availIPD.opt), keeps
* and hyphenation.
*/
- System.err.println("Found potential linebreak");
vecPossEnd.add(new BreakCost(bp,
Math.abs(availIPD.opt - bpDim.opt )));
}
@@ -246,13 +240,17 @@ public class LineBPLayoutManager extends
* up. Just try the next child LM.
*/
}
+ if (inlineLC.tryHyphenate() &&
+ !inlineLC.getHyphContext().hasMoreHyphPoints()) {
+ break;
+ }
} // end of while on child LM
if ((curLM = getChildLM())== null) {
// No more content to layout!
setFinished(true);
}
-if(bp == null) return null;
+ if(bp == null) return null;
// Choose the best break
if (!bp.isForcedBreak() && vecPossEnd.size()>0) {
@@ -260,11 +258,7 @@ if(bp == null) return null;
}
// Backup child LM if necessary
if (bp != m_prevBP) {
- // Remove any pending breaks from the vector
- while (m_vecInlineBreaks.lastElement()!=m_prevBP) {
- m_vecInlineBreaks.remove(m_vecInlineBreaks.size()-1);
- }
- reset(m_prevBP.getLayoutManager(), m_prevBP.getPosition());
+ reset();
}
// Distribute space in the line
MinOptMax actual = MinOptMax.add(m_prevBP.getStackingSize(),
@@ -282,6 +276,14 @@ if(bp == null) return null;
return makeLineBreak(m_prevBP, availIPD, actual, bJustify);
}
+
+ private void reset() {
+ while (m_vecInlineBreaks.lastElement()!=m_prevBP) {
+ m_vecInlineBreaks.remove(m_vecInlineBreaks.size()-1);
+ }
+ reset(m_prevBP.getLayoutManager(), m_prevBP.getPosition());
+ }
+
protected boolean couldEndLine(BreakPoss bp) {
if (bp.canBreakAfter()) {
return true; // no keep, ends on break char
@@ -303,6 +305,7 @@ if(bp == null) return null;
}
+
private BreakPoss getBestBP(Vector vecPossEnd) {
if (vecPossEnd.size()==1) {
return ((BreakCost)vecPossEnd.elementAt(0)).getBP();
@@ -333,13 +336,62 @@ if(bp == null) return null;
- private BreakPoss findHyphenPoss(BreakPoss prevBP, BreakPoss newBP) {
+ private HyphContext getHyphenContext(BreakPoss prevBP, BreakPoss newBP) {
// Get a "word" to hyphenate by getting characters from all
// pending break poss which are in m_vecInlineBreaks, starting
- // with the position just AFTER prevBP.getPosition()
- return null;
+ // with the position just AFTER prevBP.getPosition()
+
+ m_vecInlineBreaks.add(newBP);
+ ListIterator bpIter = m_vecInlineBreaks.
+ listIterator(m_vecInlineBreaks.size());
+ while (bpIter.hasPrevious() && bpIter.previous() != prevBP);
+ if (bpIter.next() != prevBP) {
+ System.err.println("findHyphenPoss: problem!");
+ return null;
+ }
+ StringBuffer sbChars = new StringBuffer(30);
+ while (bpIter.hasNext()) {
+ BreakPoss bp = (BreakPoss)bpIter.next();
+ if (bp.getLayoutManager() == prevBP.getLayoutManager()) {
+ bp.getLayoutManager().getWordChars(sbChars, prevBP.getPosition(),
+ bp.getPosition());
+ }
+ else {
+ bp.getLayoutManager().getWordChars(sbChars, null, bp.getPosition());
+ }
+ prevBP = bp;
+ }
+ m_vecInlineBreaks.remove(m_vecInlineBreaks.size()-1); // remove last
+ System.err.println("Word to hyphenate: " + sbChars.toString());
+
+ // Now find all hyphenation points in this word (get in an array of offsets)
+ // hyphProps are from the block level?. Note that according to the spec,
+ // they also "apply to" fo:character. I don't know what that means, since
+ // if we change language in the middle of a "word", the effect would seem
+ // quite strange! Or perhaps in that case, we say that it's several words.
+ // We probably should bring the hyphenation props up from the actual
+ // TextLM which generate the hyphenation buffer, since these properties
+ // inherit and could be specified on an inline or wrapper below the block
+ // level.
+ Hyphenation hyph =
+ Hyphenator.hyphenate(m_hyphProps.language, m_hyphProps.country,
+ sbChars.toString(),
+ m_hyphProps.hyphenationRemainCharacterCount,
+ m_hyphProps.hyphenationPushCharacterCount);
+ // They hyph structure contains the information we need
+ // Now start from prevBP: reset to that position, ask that LM to get
+ // a Position for the first hyphenation offset. If the offset isn't in
+ // its characters, it returns null, but must tell how many chars it had.
+ // Keep looking at currentBP using next hyphenation point until the
+ // returned size is greater than the available size or no more hyphenation
+ // points remain. Choose the best break.
+ if (hyph != null) {
+ return new HyphContext(hyph.getHyphenationPoints());
+ }
+ else return null;
}
+
private BreakPoss makeLineBreak(BreakPoss inlineBP, MinOptMax target,
MinOptMax actual, boolean bJustify) {
// make a new BP
@@ -377,20 +429,28 @@ if(bp == null) return null;
// Generate and add areas to parent area
// Set size etc
- public void addAreas(PositionIterator parentIter) {
+ // dSpaceAdjust should reference extra space in the BPD
+ public void addAreas(PositionIterator parentIter, double dSpaceAdjust) {
BPLayoutManager childLM ;
int iStartPos = 0;
while (parentIter.hasNext()) {
LineBreakPosition lbp = (LineBreakPosition)parentIter.next();
- System.err.println("lbp.endpos=" + lbp.m_iPos);
m_lineArea = new LineArea();
// Add the inline areas to lineArea
- PositionIterator inlinePosIter =
+ BreakPossPosIter inlinePosIter =
new BreakPossPosIter(m_vecInlineBreaks,
iStartPos, lbp.m_iPos+1);
iStartPos = lbp.m_iPos+1;
while ((childLM = inlinePosIter.getNextChildLM())!= null) {
- childLM.addAreas(inlinePosIter);
+ BreakPoss bp = inlinePosIter.getBP();
+ int iSpaceSize = getLeadingSpace(bp, lbp.m_dAdjust);
+ if (iSpaceSize != 0) {
+ System.err.println("Add leading space: " + iSpaceSize);
+ Space ls = new Space();
+ ls.setWidth(iSpaceSize);
+ addChild(ls);
+ }
+ childLM.addAreas(inlinePosIter, lbp.m_dAdjust);
}
m_lineArea.verticalAlign(lineHeight, lead, follow);
parentLM.addChild(m_lineArea);
@@ -398,6 +458,26 @@ if(bp == null) return null;
m_lineArea = null;
}
+ protected int getLeadingSpace(BreakPoss bp, double dSpaceAdjust) {
+ MinOptMax leadSpace = bp.resolveLeadingSpace();
+ if (leadSpace != null) {
+ int iAdjust=0;
+ if (dSpaceAdjust > 0.0) {
+ // Stretch by factor
+ iAdjust = (int)((double)(leadSpace.max - leadSpace.opt) *
+ dSpaceAdjust);
+ }
+ else if (dSpaceAdjust < 0.0) {
+ // Shrink by factor
+ iAdjust = (int)((double)(leadSpace.opt - leadSpace.min) *
+ dSpaceAdjust);
+ }
+ return leadSpace.opt + iAdjust;
+ }
+ else return 0;
+ }
+
+
public boolean addChild(Area childArea) {
// Make sure childArea is inline area
if (childArea instanceof InlineArea) {
@@ -440,7 +520,7 @@ if(bp == null) return null;
}
}
}
- addAreas(new BreakPossPosIter(vecBreakPoss, 0, vecBreakPoss.size()));
+ addAreas(new BreakPossPosIter(vecBreakPoss, 0, vecBreakPoss.size()), 0.0);
return false;
}
diff --git a/src/org/apache/fop/layoutmgr/PositionIterator.java b/src/org/apache/fop/layoutmgr/PositionIterator.java
index be8978312..cd98c4136 100644
--- a/src/org/apache/fop/layoutmgr/PositionIterator.java
+++ b/src/org/apache/fop/layoutmgr/PositionIterator.java
@@ -83,6 +83,10 @@ abstract class PositionIterator implements Iterator
}
}
+ protected Object peekNext() {
+ return m_nextObj;
+ }
+
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException("PositionIterator doesn't support remove");
}
diff --git a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
index f1bec939d..7cf628e2c 100644
--- a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
@@ -52,10 +52,13 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
private class AreaInfo {
short m_iStartIndex;
short m_iBreakIndex;
+ short m_iWScount;
MinOptMax m_ipdArea;
- AreaInfo(short iStartIndex, short iBreakIndex, MinOptMax ipdArea) {
+ AreaInfo(short iStartIndex, short iBreakIndex, short iWScount,
+ MinOptMax ipdArea) {
m_iStartIndex = iStartIndex;
m_iBreakIndex = iBreakIndex;
+ m_iWScount = iWScount;
m_ipdArea = ipdArea;
}
}
@@ -71,19 +74,13 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
private TextInfo textInfo;
private static final char NEWLINE = '\n';
- private static final char RETURN = '\r';
- private static final char TAB = '\t';
- private static final char SPACE = ' ';
+ private static final char SPACE = '\u0020'; // Normal space
+ private static final char NBSPACE = '\u00A0'; // Non-breaking space
private static final char LINEBREAK = '\u2028';
private static final char ZERO_WIDTH_SPACE = '\u200B';
// byte order mark
private static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
- /* values that prev (below) may take */
- protected static final int NOTHING = 0;
- protected static final int WHITESPACE = 1;
- protected static final int TEXT = 2;
-
/** Start index of first character in this parent Area */
private short m_iAreaStart = 0;
/** Start index of next "word" */
@@ -94,6 +91,8 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
// private MinOptMax m_nextIPD= new MinOptMax(0);
/** size of a space character (U+0020) glyph in current font */
private int m_spaceIPD;
+ /** size of the hyphen character glyph in current font */
+ private int m_hyphIPD;
/** 1/2 of word-spacing value */
private SpaceVal m_halfWS;
/** Number of space characters after previous possible break position. */
@@ -109,6 +108,8 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
// With CID fonts, space isn't neccesary currentFontState.width(32)
m_spaceIPD = CharUtilities.getCharWidth(' ', textInfo.fs);
+ // Use hyphenationChar property
+ m_hyphIPD = CharUtilities.getCharWidth('-', textInfo.fs);
// Make half-space: <space> on either side of a word-space)
SpaceVal ws = textInfo.wordSpacing;
m_halfWS = new SpaceVal(MinOptMax.multiply(ws.space, 0.5),
@@ -145,42 +146,17 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
}
- // NOTE: currently not used. Remove if decide it isn't necessary!
-// /**
-// * Get the BreakPoss at the start of the next line.
-// * @param bpPrevEnd The BreakPoss at the end of the previous line
-// * or null if we should return the point at the beginning of this
-// * text run.
-// */
-// public BreakPoss getStartBreakPoss(LayoutContext lc,
-// BreakPoss.Position bpPrevEnd) {
-// BreakPoss bp = null;
-// if (bpPrevEnd == null) {
-// bp = new BreakPoss(this, new TextBreakPosition(0));
-// // Set minimum bpd (character ascent and descent)
-// // Or do this at the line level???
-// }
-// else {
-// // Skip suppressible white-space
-// // ASSERT (((TextBreakPosition)bpPrevEnd).m_iAreaIndex =
-// // m_iNextStart)
-// if ((lc.flags & LayoutContext.SUPPRESS_LEADING_SPACE)!=0) {
-// /* Skip any leading word-space characters. */
-// for (; m_iNextStart < chars.length &&
-// chars[m_iNextStart]==SPACE; m_iNextStart++);
-// }
-// // If now at end, nothing to compose here!
-// if (m_iNextStart >= chars.length) {
-// return null; // Or an "empty" BreakPoss?
-// }
-// else {
-// bp = new BreakPoss(this,
-// new TextBreakPosition(m_iNextStart));
-// }
-// }
-// return bp;
-// }
-
+ public void getWordChars(StringBuffer sbChars,
+ BreakPoss.Position bp1, BreakPoss.Position bp2) {
+ TextBreakPosition endPos = (TextBreakPosition)bp2;
+ AreaInfo ai =
+ (AreaInfo) m_vecAreaInfo.elementAt(endPos.m_iAreaIndex);
+ // Skip all leading spaces for hyphenation
+ int i;
+ for (i=ai.m_iStartIndex;i < ai.m_iBreakIndex &&
+ CharUtilities.isAnySpace(chars[i])==true ;i++);
+ sbChars.append(new String(chars, i, ai.m_iBreakIndex-i));
+ }
/**
* Return value indicating whether the next area to be generated could
@@ -204,13 +180,14 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
if (ai.m_iBreakIndex != m_iNextStart) {
m_iNextStart = ai.m_iBreakIndex;
m_vecAreaInfo.setSize(tbp.m_iAreaIndex+1);
- System.err.println("Discarded previous text break pos");
+ // TODO: reset or recalculate total IPD = sum of all word IPD
+ // up to the break position
+ m_ipdTotal = ai.m_ipdArea;
setFinished(false);
}
}
else {
// Reset to beginning!
- System.err.println("TextBPLM: resetPosition(null)");
m_vecAreaInfo.setSize(0);
m_iNextStart = 0;
setFinished(false);
@@ -218,6 +195,30 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
}
+ // TODO: see if we can use normal getNextBreakPoss for this with
+ // extra hyphenation information in LayoutContext
+ private boolean getHyphenIPD(HyphContext hc, MinOptMax hyphIPD) {
+ // Skip leading word-space before calculating count?
+ boolean bCanHyphenate = true;
+ int iStopIndex = m_iNextStart + hc.getNextHyphPoint();
+
+ if (chars.length < iStopIndex || textInfo.bCanHyphenate==false ) {
+ iStopIndex = chars.length;
+ bCanHyphenate = false;
+ }
+ hc.updateOffset(iStopIndex - m_iNextStart);
+
+ for (; m_iNextStart < iStopIndex; m_iNextStart++) {
+ char c = chars[m_iNextStart];
+ hyphIPD.opt += CharUtilities.getCharWidth(c, textInfo.fs);
+ // letter-space?
+ }
+ // Need to include hyphen size too, but don't count it in the
+ // stored running total, since it would be double counted
+ // with later hyphenation points
+ return bCanHyphenate;
+ }
+
/**
* Return the next break possibility that fits the constraints.
* @param context An object specifying the flags and input information
@@ -250,15 +251,17 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
*/
m_ipdTotal = new MinOptMax(0);
iFlags |= BreakPoss.ISFIRST;
- // May have leading space too which can combine with a
- // leading word-space or letter-space
}
- // HANDLE SUPPRESSED LEADING SPACES
+ /* HANDLE SUPPRESSED LEADING SPACES
+ * See W3C XSL Rec. 7.16.3.
+ * Suppress characters whose "suppress-at-line-break" property = "suppress"
+ * This can only be set on an explicit fo:character object. The default
+ * behavior is that U+0020 is suppressed; all other character codes are
+ * retained.
+ */
if (context.suppressLeadingSpace()) {
- /* If any leading space characters, ignore them. */
- // NOTE: Skips word-space chars only, not other white-space!
for (; m_iNextStart < chars.length &&
chars[m_iNextStart]==SPACE; m_iNextStart++);
// If now at end, nothing to compose here!
@@ -269,23 +272,33 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
}
- // Start of this "word", plus any non-suppressed leading space
- // This is any kind of white-space, not just word spaces
-
- short iThisStart = m_iNextStart;
- MinOptMax spaceIPD = new MinOptMax(0); // Variable IPD
- int wordIPD = 0; // Non-stretching IPD (length in base units)
+ /* Start of this "word", plus any non-suppressed leading space.
+ * Collapse any remaining word-space with leading space from
+ * ancestor FOs.
+ * Add up other leading space which is counted in the word IPD.
+ */
- // Handle inter-character spacing (word-space + letter-space)
- // What about context.getPendingSpace() on first char in word?
- SpaceSpecifier pendingSpace = new SpaceSpecifier(false);
+ SpaceSpecifier pendingSpace= new SpaceSpecifier(false);
+ short iThisStart = m_iNextStart; // Index of first character counted
+ MinOptMax spaceIPD = new MinOptMax(0); // Extra IPD from word-spacing
+ // Sum of glyph IPD of all characters in a word, inc. leading space
+ int wordIPD = 0;
+ short iWScount=0; // Count of word spaces
for (; m_iNextStart < chars.length; m_iNextStart++) {
char c = chars[m_iNextStart];
if (CharUtilities.isAnySpace(c)==false) break;
- if (c==SPACE) {
- pendingSpace.addSpace(m_halfWS);
- spaceIPD.add(pendingSpace.resolve(false));
+ if (c==SPACE || c==NBSPACE) {
+ ++iWScount;
+ // Counted as word-space
+ if (m_iNextStart == iThisStart &&
+ (iFlags & BreakPoss.ISFIRST) !=0 ) {
+ context.getPendingSpace().addSpace(m_halfWS);
+ }
+ else {
+ pendingSpace.addSpace(m_halfWS);
+ spaceIPD.add(pendingSpace.resolve(false));
+ }
wordIPD += m_spaceIPD; // Space glyph IPD
pendingSpace.clear();
pendingSpace.addSpace(m_halfWS);
@@ -305,64 +318,79 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
else {
// This FO ended with spaces. Return the BP
iFlags |= BreakPoss.ALL_ARE_SUPPRESS_AT_LB;
- // lc.trailingSpaceSeq.addSpace(m_halfWS);
- // Need to make SpaceSpecifier from m_halfWS!
- // Or at least a spaceval
- return makeBreakPoss(iThisStart, spaceIPD, 0, pendingSpace,
- iFlags);
+ return makeBreakPoss(iThisStart, spaceIPD, wordIPD,
+ context.getPendingSpace(), pendingSpace,
+ iFlags, iWScount);
}
+ if (context.tryHyphenate()) {
+ // Get the size of the next syallable
+ MinOptMax hyphIPD = new MinOptMax(0);
+ if (getHyphenIPD(context.getHyphContext(), hyphIPD)) {
+ iFlags |= (BreakPoss.CAN_BREAK_AFTER | BreakPoss.HYPHENATED);
+ }
+ wordIPD += hyphIPD.opt;
+ }
+ else {
// Look for a legal line-break: breakable white-space and certain
// characters such as '-' which can serve as word breaks.
// Don't look for hyphenation points here though
-
- for (; m_iNextStart < chars.length; m_iNextStart++) {
- char c = chars[m_iNextStart];
- if ((c == NEWLINE) ||
- // Include any breakable white-space as break char
- // even if fixed width
- (textInfo.bWrap &&
- (CharUtilities.isSpace(c) ||
- s_breakChars.indexOf(c)>=0))) {
- iFlags |= BreakPoss.CAN_BREAK_AFTER;
- if (c != SPACE) {
- m_iNextStart++;
- if (c != NEWLINE) {
- wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
- }
- else {
- iFlags |= BreakPoss.FORCE;
+ for (; m_iNextStart < chars.length; m_iNextStart++) {
+ char c = chars[m_iNextStart];
+ if ((c == NEWLINE) ||
+ // Include any breakable white-space as break char
+ // even if fixed width
+ (textInfo.bWrap &&
+ (CharUtilities.isSpace(c) ||
+ s_breakChars.indexOf(c)>=0))) {
+ iFlags |= BreakPoss.CAN_BREAK_AFTER;
+ if (c != SPACE) {
+ m_iNextStart++;
+ if (c != NEWLINE) {
+ wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
+ }
+ else {
+ iFlags |= BreakPoss.FORCE;
+ }
}
- }
- return makeBreakPoss(iThisStart, spaceIPD, wordIPD, null,
- iFlags);
- }
- wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
- // Note, if a normal non-breaking space, is it stretchable???
- // If so, keep a count of these embedded spaces.
- }
- return makeBreakPoss(iThisStart, spaceIPD, wordIPD, null, iFlags);
+ return makeBreakPoss(iThisStart, spaceIPD, wordIPD,
+ context.getPendingSpace(), null,
+ iFlags, iWScount);
+ }
+ wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
+ // Note, if a normal non-breaking space, is it stretchable???
+ // If so, keep a count of these embedded spaces.
+ }
+ }
+ return makeBreakPoss(iThisStart, spaceIPD, wordIPD,
+ context.getPendingSpace(), null, iFlags, iWScount);
}
private BreakPoss makeBreakPoss(short iWordStart, MinOptMax spaceIPD,
- int wordDim,
+ int wordDim, SpaceSpecifier leadingSpace,
SpaceSpecifier trailingSpace,
- int flags)
+ int flags, short iWScount)
{
MinOptMax ipd = new MinOptMax(wordDim);
ipd.add(spaceIPD);
+ ipd.add(m_ipdTotal); // sum of all words so far in line
+ // Note: break position now stores total size to here
// Position is the index of the info for this word in the vector
- m_vecAreaInfo.add(new AreaInfo(iWordStart, m_iNextStart, ipd));
+ m_vecAreaInfo.add(new AreaInfo(iWordStart, m_iNextStart, iWScount, ipd));
BreakPoss bp =
new BreakPoss(this,
new TextBreakPosition(m_vecAreaInfo.size()-1));
-
- ipd.add(m_ipdTotal); // sum of all words so far in line
- bp.setStackingSize(ipd);
m_ipdTotal = ipd;
- // TODO: make this correct (see Keiron's code below!)
+ if ((flags & BreakPoss.HYPHENATED)!=0) {
+ // Add the hyphen size, but don't change total IPD!
+ bp.setStackingSize(MinOptMax.add(ipd, new MinOptMax(m_hyphIPD)));
+ }
+ else {
+ bp.setStackingSize(ipd);
+ }
+ // TODO: make this correct (see Keiron's vertical alignment code)
bp.setNonStackingSize(new MinOptMax(textInfo.lineHeight));
/* Set max ascender and descender (offset from baseline),
@@ -382,28 +410,72 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
else {
bp.setTrailingSpace(new SpaceSpecifier(false));
}
- bp.setLeadingSpace(new SpaceSpecifier(false));
+ if (leadingSpace != null) {
+ bp.setLeadingSpace(leadingSpace);
+ }
+ else {
+ bp.setLeadingSpace(new SpaceSpecifier(false));
+ }
return bp;
}
/**
- * Add an area for each word and space (or one big one????)
+ * Generate and add areas to parent area.
+ * This can either generate an area for each "word" and each space, or
+ * an area containing all text with a parameter controlling the size of
+ * the word space. The latter is most efficient for PDF generation.
+ * Set size of each area.
+ * @param parentIter Iterator over BreakPoss.Position information returned
+ * by this LayoutManager.
+ * @param dSpaceAdjust Factor controlling how much extra space to add
+ * in order to justify the line.
*/
- public void addAreas(PositionIterator posIter) {
+ public void addAreas(PositionIterator posIter, double dSpaceAdjust) {
// Add word areas
- TextBreakPosition tbpStart, tbpNext;
+ AreaInfo ai=null ;
+ int iStart = -1;
+ int iWScount = 0;
+
+ /* On first area created, add any leading space.
+ * Calculate word-space stretch value.
+ */
while (posIter.hasNext()) {
- tbpNext = (TextBreakPosition)posIter.next();
- // System.err.println("tbp.pos = " + tbpNext.m_iAreaIndex);
- AreaInfo ai = (AreaInfo)m_vecAreaInfo.
- elementAt(tbpNext.m_iAreaIndex);
- // Make an area containing all characters between start and end.
- Word word = createWord(new String(chars, ai.m_iStartIndex,
- ai.m_iBreakIndex- ai.m_iStartIndex),
- ai.m_ipdArea.opt);
- parentLM.addChild(word);
+ TextBreakPosition tbpNext = (TextBreakPosition)posIter.next();
+ ai = (AreaInfo)m_vecAreaInfo.elementAt(tbpNext.m_iAreaIndex);
+ if (iStart == -1) {
+ iStart = ai.m_iStartIndex;
+ }
+ iWScount += ai.m_iWScount;
+ }
+ // Calculate total adjustment
+ int iAdjust = 0;
+ if (dSpaceAdjust > 0.0) {
+ // Stretch by factor
+ System.err.println("Potential stretch = " +
+ (ai.m_ipdArea.max - ai.m_ipdArea.opt));
+ iAdjust = (int)((double)(ai.m_ipdArea.max - ai.m_ipdArea.opt) *
+ dSpaceAdjust);
+ }
+ else if (dSpaceAdjust < 0.0) {
+ // Shrink by factor
+ System.err.println("Potential shrink = " +
+ (ai.m_ipdArea.opt - ai.m_ipdArea.min));
+ iAdjust = (int)((double)(ai.m_ipdArea.opt - ai.m_ipdArea.min) *
+ dSpaceAdjust);
+ }
+ System.err.println("Text adjustment factor = " + dSpaceAdjust +
+ " total=" + iAdjust);
+ if (iWScount > 0) {
+ System.err.println("Adjustment per word-space= " + iAdjust/iWScount);
+ }
+ // Make an area containing all characters between start and end.
+ Word word = createWord(new String(chars, iStart, ai.m_iBreakIndex - iStart),
+ ai.m_ipdArea.opt + iAdjust);
+ if (chars[iStart] == SPACE || chars[iStart] == NBSPACE ) {
+ // word.setLeadingSpace(m_halfWS);
}
+ parentLM.addChild(word);
}