- A new interface InlineLevelLayoutManager, implemented by LeafNodeLM, InlineLM, TextLM, BasicLinkLM and ContentLM - Leaders with pattern "use-content" and "dots" now works - Better handling of preserved linefeeds - Correct calculation of the lineheight, according to the value of the property vertical-align For a few points which may need further work, see the bugzilla page. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198142 13f79535-47bb-0310-9956-ffa450edef68pull/30/head
@@ -19,6 +19,7 @@ | |||
package org.apache.fop.area.inline; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.ArrayList; | |||
/** | |||
@@ -39,6 +40,29 @@ public class FilledArea extends InlineParent { | |||
public FilledArea() { | |||
} | |||
/** | |||
* Set the offset of the descendant TextAreas, | |||
* instead of the offset of the FilledArea itself. | |||
* | |||
* @param v the offset | |||
*/ | |||
public void setOffset(int v) { | |||
setChildOffset(inlines.listIterator(), v); | |||
} | |||
private void setChildOffset(ListIterator childrenIterator, int v) { | |||
while (childrenIterator.hasNext()) { | |||
InlineArea child = (InlineArea) childrenIterator.next(); | |||
if (child instanceof InlineParent) { | |||
setChildOffset(((InlineParent) child).getChildAreas().listIterator(), v); | |||
} else if (child instanceof org.apache.fop.area.inline.Viewport) { | |||
// nothing | |||
} else { | |||
child.setOffset(v); | |||
} | |||
} | |||
} | |||
/** | |||
* Set the unit width for the areas to fill the full width. | |||
* |
@@ -84,6 +84,7 @@ public class Character extends FObj { | |||
private int textDecoration; | |||
// private ToBeImplementedProperty textShadow; | |||
private int textTransform; | |||
private int verticalAlign; | |||
private int visibility; | |||
private Property wordSpacing; | |||
// End of property values | |||
@@ -132,6 +133,7 @@ public class Character extends FObj { | |||
textDecoration = pList.get(PR_TEXT_DECORATION).getEnum(); | |||
// textShadow = pList.get(PR_TEXT_SHADOW); | |||
textTransform = pList.get(PR_TEXT_TRANSFORM).getEnum(); | |||
verticalAlign = pList.get(PR_VERTICAL_ALIGN).getEnum(); | |||
visibility = pList.get(PR_VISIBILITY).getEnum(); | |||
wordSpacing = pList.get(PR_WORD_SPACING); | |||
} | |||
@@ -224,6 +226,13 @@ public class Character extends FObj { | |||
return wordSpacing; | |||
} | |||
/** | |||
* Return the "vertical-align" property. | |||
*/ | |||
public int getVerticalAlign() { | |||
return verticalAlign; | |||
} | |||
/** | |||
* @see org.apache.fop.fo.FONode#addLayoutManager(List) | |||
*/ |
@@ -66,6 +66,7 @@ public class Inline extends FObjMixed { | |||
private KeepProperty keepWithPrevious; | |||
private Length lineHeight; | |||
private int textDecoration; | |||
private int verticalAlign; | |||
private int visibility; | |||
private Length width; | |||
private int wrapOption; | |||
@@ -106,6 +107,7 @@ public class Inline extends FObjMixed { | |||
keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); | |||
lineHeight = pList.get(PR_LINE_HEIGHT).getLength(); | |||
textDecoration = pList.get(PR_TEXT_DECORATION).getEnum(); | |||
verticalAlign = pList.get(PR_VERTICAL_ALIGN).getEnum(); | |||
visibility = pList.get(PR_VISIBILITY).getEnum(); | |||
width = pList.get(PR_WIDTH).getLength(); | |||
wrapOption = pList.get(PR_WRAP_OPTION).getEnum(); | |||
@@ -214,6 +216,13 @@ public class Inline extends FObjMixed { | |||
return textDecoration; | |||
} | |||
/** | |||
* Return the "vertical-align" property. | |||
*/ | |||
public int getVerticalAlign() { | |||
return verticalAlign; | |||
} | |||
/** | |||
* @see org.apache.fop.fo.FObjMixed#charIterator | |||
*/ |
@@ -54,6 +54,7 @@ public class Leader extends FObjMixed { | |||
private CommonRelativePosition commonRelativePosition; | |||
private Length alignmentAdjust; | |||
private int alignmentBaseline; | |||
private int verticalAlign; | |||
private Length baselineShift; | |||
private ColorType color; | |||
private int dominantBaseline; | |||
@@ -94,6 +95,7 @@ public class Leader extends FObjMixed { | |||
commonRelativePosition = pList.getRelativePositionProps(); | |||
alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); | |||
alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); | |||
verticalAlign = pList.get(PR_VERTICAL_ALIGN).getEnum(); | |||
baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); | |||
color = pList.get(PR_COLOR).getColorType(); | |||
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); | |||
@@ -136,7 +138,21 @@ public class Leader extends FObjMixed { | |||
protected void startOfNode() throws FOPException { | |||
checkId(id); | |||
} | |||
/** | |||
* Return the Common Margin Properties-Inline. | |||
*/ | |||
public CommonMarginInline getCommonMarginInline() { | |||
return commonMarginInline; | |||
} | |||
/** | |||
* Return the Common Border, Padding, and Background Properties. | |||
*/ | |||
public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { | |||
return commonBorderPaddingBackground; | |||
} | |||
/** | |||
* Return the Common Font Properties. | |||
*/ | |||
@@ -193,6 +209,13 @@ public class Leader extends FObjMixed { | |||
return leaderPatternWidth; | |||
} | |||
/** | |||
* Return the "vertical-align" property. | |||
*/ | |||
public int getVerticalAlign() { | |||
return verticalAlign; | |||
} | |||
/** | |||
* @see org.apache.fop.fo.FONode#addLayoutManager(List) | |||
*/ |
@@ -275,43 +275,6 @@ public abstract class AbstractLayoutManager implements LayoutManager, Constants | |||
* interface which are declared abstract in AbstractLayoutManager. | |||
* ---------------------------------------------------------*/ | |||
public LinkedList getNextKnuthElements(LayoutContext context, | |||
int alignment) { | |||
log.debug("null implementation of getNextKnuthElements() called!"); | |||
setFinished(true); | |||
return null; | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
log.debug("null implementation of addALetterSpaceTo() called!"); | |||
return element; | |||
} | |||
public void getWordChars(StringBuffer sbChars, Position pos) { | |||
log.debug("null implementation of getWordChars() called!"); | |||
} | |||
public void hyphenate(Position pos, HyphContext hc) { | |||
log.debug("null implementation of hyphenate called!"); | |||
} | |||
public boolean applyChanges(List oldList) { | |||
log.debug("null implementation of applyChanges() called!"); | |||
return false; | |||
} | |||
public LinkedList getChangedKnuthElements(List oldList, | |||
int flaggedPenalty, | |||
int alignment) { | |||
log.debug("null implementation of getChangeKnuthElement() called!"); | |||
return null; | |||
} | |||
public int getWordSpaceIPD() { | |||
log.debug("null implementation of getWordSpaceIPD() called!"); | |||
return 0; | |||
} | |||
public Area getParentArea(Area childArea) { | |||
return null; | |||
} |
@@ -27,7 +27,7 @@ import org.apache.fop.area.PageViewport; | |||
/** | |||
* LayoutManager for the fo:basic-link formatting object | |||
*/ | |||
public class BasicLinkLayoutManager extends InlineStackingLayoutManager { | |||
public class BasicLinkLayoutManager extends InlineLayoutManager { | |||
private BasicLink fobj; | |||
/** |
@@ -57,6 +57,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager { | |||
private int lead = 12000; | |||
private int lineHeight = 14000; | |||
private int follow = 2000; | |||
private int middleShift = 0; | |||
private int iStartPos = 0; | |||
@@ -71,6 +72,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager { | |||
lead = fs.getAscender(); | |||
follow = -fs.getDescender(); | |||
middleShift = -fs.getXHeight() / 2; | |||
lineHeight = fobj.getLineHeight().getOptimum().getLength().getValue(); | |||
} | |||
@@ -141,7 +143,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager { | |||
*/ | |||
private LineLayoutManager createLineManager(LayoutManager firstlm) { | |||
LineLayoutManager llm; | |||
llm = new LineLayoutManager(fobj, lineHeight, lead, follow); | |||
llm = new LineLayoutManager(fobj, lineHeight, lead, follow, middleShift); | |||
List inlines = new ArrayList(); | |||
inlines.add(firstlm); | |||
while (proxyLMiter.hasNext()) { |
@@ -48,6 +48,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { | |||
fobj = node; | |||
InlineArea inline = getCharacterInlineArea(node); | |||
setCurrentArea(inline); | |||
setAlignment(fobj.getVerticalAlign()); | |||
fs = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo()); | |||
SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing()); | |||
@@ -71,15 +72,15 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { | |||
*/ | |||
protected void offsetArea(LayoutContext context) { | |||
int bpd = curArea.getBPD(); | |||
switch (alignment) { | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE: | |||
curArea.setOffset(context.getBaseline() - bpd / 2 /* - fontLead/2 */); | |||
curArea.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2); | |||
break; | |||
case VerticalAlign.TOP: | |||
//curArea.setOffset(0); | |||
curArea.setOffset(fs.getAscender()); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
curArea.setOffset(context.getLineHeight() - bpd); | |||
curArea.setOffset(context.getLineHeight() - bpd + fs.getAscender()); | |||
break; | |||
case VerticalAlign.BASELINE: | |||
default: | |||
@@ -116,16 +117,15 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { | |||
int lead = 0; | |||
int total = 0; | |||
int middle = 0; | |||
switch (alignment) { | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE : middle = bpd / 2 ; | |||
lead = bpd / 2 ; | |||
break; | |||
case VerticalAlign.TOP : total = bpd; | |||
break; | |||
case VerticalAlign.TOP : // fall through | |||
case VerticalAlign.BOTTOM : total = bpd; | |||
break; | |||
case VerticalAlign.BASELINE: | |||
default: lead = bpd; | |||
case VerticalAlign.BASELINE: // fall through | |||
default : lead = fs.getAscender(); | |||
total = bpd; | |||
break; | |||
} | |||
@@ -22,6 +22,7 @@ import org.apache.fop.fo.FObj; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fo.flow.Marker; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.inline.InlineArea; | |||
import org.apache.fop.area.Resolvable; | |||
import org.apache.fop.area.PageViewport; | |||
@@ -40,12 +41,12 @@ import org.apache.commons.logging.LogFactory; | |||
* For use with objects that contain inline areas such as | |||
* leader use-content and title. | |||
*/ | |||
public class ContentLayoutManager implements LayoutManager { | |||
public class ContentLayoutManager implements InlineLevelLayoutManager { | |||
private FOUserAgent userAgent; | |||
private Area holder; | |||
private int stackSize; | |||
private LayoutManager parentLM; | |||
private List childLMs = new ArrayList(1); | |||
private InlineLevelLayoutManager childLM = null; | |||
/** | |||
* logging instance | |||
@@ -137,6 +138,19 @@ public class ContentLayoutManager implements LayoutManager { | |||
stackSize = stack.opt; | |||
} | |||
public void addAreas(PositionIterator posIter, LayoutContext context) { | |||
// add the content areas | |||
// the area width has already been adjusted, and it must remain unchanged | |||
// so save its value before calling addAreas, and set it again afterwards | |||
int savedIPD = ((InlineArea)holder).getIPD(); | |||
// set to zero the ipd adjustment ratio, to avoid spaces in the pattern | |||
// to be modified | |||
LayoutContext childContext = new LayoutContext(context); | |||
childContext.setIPDAdjust(0.0); | |||
childLM.addAreas(posIter, childContext); | |||
((InlineArea)holder).setIPD(savedIPD); | |||
} | |||
public int getStackingSize() { | |||
return stackSize; | |||
} | |||
@@ -201,9 +215,6 @@ public class ContentLayoutManager implements LayoutManager { | |||
//to be done | |||
} | |||
/** @see org.apache.fop.layoutmgr.LayoutManager */ | |||
public void addAreas(PositionIterator posIter, LayoutContext context) { } | |||
/** @see org.apache.fop.layoutmgr.LayoutManager */ | |||
public void initialize() { | |||
//to be done | |||
@@ -259,6 +270,8 @@ public class ContentLayoutManager implements LayoutManager { | |||
* @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs | |||
*/ | |||
public List getChildLMs() { | |||
List childLMs = new ArrayList(1); | |||
childLMs.add(childLM); | |||
return childLMs; | |||
} | |||
@@ -271,7 +284,7 @@ public class ContentLayoutManager implements LayoutManager { | |||
} | |||
lm.setParent(this); | |||
lm.initialize(); | |||
childLMs.add(lm); | |||
childLM = (InlineLevelLayoutManager)lm; | |||
log.trace(this.getClass().getName() | |||
+ ": Adding child LM " + lm.getClass().getName()); | |||
} | |||
@@ -292,8 +305,26 @@ public class ContentLayoutManager implements LayoutManager { | |||
public LinkedList getNextKnuthElements(LayoutContext context, | |||
int alignment) { | |||
LinkedList contentList = new LinkedList(); | |||
LinkedList returnedList; | |||
while (!childLM.isFinished()) { | |||
// get KnuthElements from childLM | |||
returnedList = childLM.getNextKnuthElements(context, alignment); | |||
if (returnedList != null) { | |||
// move elements to contentList, and accumulate their size | |||
KnuthElement contentElement; | |||
while (returnedList.size() > 0) { | |||
contentElement = (KnuthElement)returnedList.removeFirst(); | |||
stackSize += contentElement.getW(); | |||
contentList.add(contentElement); | |||
} | |||
} | |||
} | |||
setFinished(true); | |||
return null; | |||
return contentList; | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
@@ -315,9 +346,5 @@ public class ContentLayoutManager implements LayoutManager { | |||
int alignment) { | |||
return null; | |||
} | |||
public int getWordSpaceIPD() { | |||
return 0; | |||
} | |||
} | |||
@@ -18,8 +18,13 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.LinkedList; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.flow.Inline; | |||
import org.apache.fop.fo.flow.Leader; | |||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||
import org.apache.fop.fo.properties.CommonMarginInline; | |||
import org.apache.fop.fo.properties.SpaceProperty; | |||
@@ -30,8 +35,9 @@ import org.apache.fop.traits.SpaceVal; | |||
* LayoutManager for objects which stack children in the inline direction, | |||
* such as Inline or Line | |||
*/ | |||
public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
private Inline fobj; | |||
public class InlineLayoutManager extends InlineStackingLayoutManager | |||
implements InlineLevelLayoutManager { | |||
private FObj fobj; | |||
private CommonMarginInline inlineProps = null; | |||
private CommonBorderPaddingBackground borderProps = null; | |||
@@ -47,13 +53,31 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
super(node); | |||
fobj = node; | |||
} | |||
/** | |||
* Create an inline layout manager. | |||
* This is used for fo's that create areas that | |||
* contain inline areas. | |||
* | |||
* @param node the formatting object that creates the area | |||
*/ | |||
public InlineLayoutManager(Leader node) { | |||
super(node); | |||
fobj = node; | |||
} | |||
/** | |||
* @see org.apache.fop.layoutmgr.AbstractLayoutManager#initProperties() | |||
*/ | |||
protected void initProperties() { | |||
inlineProps = fobj.getCommonMarginInline(); | |||
borderProps = fobj.getCommonBorderPaddingBackground(); | |||
// fobj can be either an Inline or a Leader | |||
if (fobj instanceof Inline) { | |||
inlineProps = ((Inline) fobj).getCommonMarginInline(); | |||
borderProps = ((Inline) fobj).getCommonBorderPaddingBackground(); | |||
} else { | |||
inlineProps = ((Leader) fobj).getCommonMarginInline(); | |||
borderProps = ((Leader) fobj).getCommonBorderPaddingBackground(); | |||
} | |||
int iPad = borderProps.getPadding(CommonBorderPaddingBackground.BEFORE, false); | |||
iPad += borderProps.getBorderWidth(CommonBorderPaddingBackground.BEFORE, | |||
false); | |||
@@ -94,7 +118,6 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
return inlineProps.spaceEnd; | |||
} | |||
/** | |||
* Return value indicating whether the next area to be generated could | |||
* start a new line. This should only be called in the "START" condition | |||
@@ -121,5 +144,204 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
} | |||
} | |||
public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) { | |||
InlineLevelLayoutManager curLM; | |||
// the list returned by child LM | |||
LinkedList returnedList; | |||
KnuthElement returnedElement; | |||
// the list which will be returned to the parent LM | |||
LinkedList returnList = new LinkedList(); | |||
SpaceSpecifier leadingSpace = lc.getLeadingSpace(); | |||
if (lc.startsNewArea()) { | |||
// First call to this LM in new parent "area", but this may | |||
// not be the first area created by this inline | |||
childLC = new LayoutContext(lc); | |||
if (getSpaceStart() != null) { | |||
lc.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart())); | |||
} | |||
// Check for "fence" | |||
if (hasLeadingFence(!lc.isFirstArea())) { | |||
// Reset leading space sequence for child areas | |||
leadingSpace = new SpaceSpecifier(false); | |||
} | |||
// Reset state variables | |||
clearPrevIPD(); // Clear stored prev content dimensions | |||
} | |||
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) { | |||
// get KnuthElements from curLM | |||
returnedList = curLM.getNextKnuthElements(lc, alignment); | |||
if (returnedList != null) { | |||
// "wrap" the Position stored in each element of returnedList | |||
ListIterator listIter = returnedList.listIterator(); | |||
while (listIter.hasNext()) { | |||
returnedElement = (KnuthElement) listIter.next(); | |||
returnedElement.setPosition | |||
(new NonLeafPosition(this, | |||
returnedElement.getPosition())); | |||
returnList.add(returnedElement); | |||
} | |||
return returnList; | |||
} else { | |||
// curLM returned null because it finished; | |||
// just iterate once more to see if there is another child | |||
} | |||
} | |||
setFinished(true); | |||
return null; | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
NonLeafPosition savedPos = (NonLeafPosition) element.getPosition(); | |||
element.setPosition(savedPos.getPosition()); | |||
KnuthElement newElement | |||
= ((InlineLevelLayoutManager) | |||
element.getLayoutManager()).addALetterSpaceTo(element); | |||
newElement.setPosition | |||
(new NonLeafPosition(this, newElement.getPosition())); | |||
element.setPosition(savedPos); | |||
return newElement; | |||
} | |||
public void getWordChars(StringBuffer sbChars, Position pos) { | |||
Position newPos = ((NonLeafPosition) pos).getPosition(); | |||
((InlineLevelLayoutManager) | |||
newPos.getLM()).getWordChars(sbChars, newPos); | |||
} | |||
public void hyphenate(Position pos, HyphContext hc) { | |||
Position newPos = ((NonLeafPosition) pos).getPosition(); | |||
((InlineLevelLayoutManager) | |||
newPos.getLM()).hyphenate(newPos, hc); | |||
} | |||
public boolean applyChanges(List oldList) { | |||
// "unwrap" the Positions stored in the elements | |||
ListIterator oldListIterator = oldList.listIterator(); | |||
KnuthElement oldElement; | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(((NonLeafPosition) oldElement.getPosition()).getPosition()); | |||
} | |||
// reset the iterator | |||
oldListIterator = oldList.listIterator(); | |||
InlineLevelLayoutManager prevLM = null; | |||
InlineLevelLayoutManager currLM; | |||
int fromIndex = 0; | |||
boolean bSomethingChanged = false; | |||
while(oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager(); | |||
// initialize prevLM | |||
if (prevLM == null) { | |||
prevLM = currLM; | |||
} | |||
if (currLM != prevLM || !oldListIterator.hasNext()) { | |||
if (oldListIterator.hasNext()) { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex())) | |||
|| bSomethingChanged; | |||
prevLM = currLM; | |||
fromIndex = oldListIterator.previousIndex(); | |||
} else if (currLM == prevLM) { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldList.size())) | |||
|| bSomethingChanged; | |||
} else { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex())) | |||
|| bSomethingChanged; | |||
bSomethingChanged | |||
= currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size())) | |||
|| bSomethingChanged; | |||
} | |||
} | |||
} | |||
// "wrap" again the Positions stored in the elements | |||
oldListIterator = oldList.listIterator(); | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(new NonLeafPosition(this, oldElement.getPosition())); | |||
} | |||
return bSomethingChanged; | |||
} | |||
public LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, int alignment) { | |||
// "unwrap" the Positions stored in the elements | |||
ListIterator oldListIterator = oldList.listIterator(); | |||
KnuthElement oldElement; | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(((NonLeafPosition) oldElement.getPosition()).getPosition()); | |||
} | |||
// reset the iterator | |||
oldListIterator = oldList.listIterator(); | |||
KnuthElement returnedElement; | |||
LinkedList returnedList = new LinkedList(); | |||
LinkedList returnList = new LinkedList(); | |||
InlineLevelLayoutManager prevLM = null; | |||
InlineLevelLayoutManager currLM; | |||
int fromIndex = 0; | |||
while(oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager(); | |||
if (prevLM == null) { | |||
prevLM = currLM; | |||
} | |||
if (currLM != prevLM || !oldListIterator.hasNext()) { | |||
if (oldListIterator.hasNext()) { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, | |||
oldListIterator.previousIndex()), | |||
flaggedPenalty, alignment)); | |||
prevLM = currLM; | |||
fromIndex = oldListIterator.previousIndex(); | |||
} else if (currLM == prevLM) { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, oldList.size()), | |||
flaggedPenalty, alignment)); | |||
} else { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, | |||
oldListIterator.previousIndex()), | |||
flaggedPenalty, alignment)); | |||
returnedList.addAll | |||
(currLM.getChangedKnuthElements | |||
(oldList.subList(oldListIterator.previousIndex(), | |||
oldList.size()), | |||
flaggedPenalty, alignment)); | |||
} | |||
} | |||
} | |||
// "wrap" the Position stored in each element of returnedList | |||
ListIterator listIter = returnedList.listIterator(); | |||
while (listIter.hasNext()) { | |||
returnedElement = (KnuthElement) listIter.next(); | |||
returnedElement.setPosition | |||
(new NonLeafPosition(this, returnedElement.getPosition())); | |||
returnList.add(returnedElement); | |||
} | |||
return returnList; | |||
} | |||
} | |||
@@ -0,0 +1,84 @@ | |||
/* | |||
* Copyright 2004 The Apache Software Foundation. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
/** | |||
* The interface for LayoutManagers which generate inline areas | |||
*/ | |||
public interface InlineLevelLayoutManager extends LayoutManager { | |||
/** | |||
* Get a sequence of KnuthElements representing the content | |||
* of the node assigned to the LM | |||
* | |||
* @param context the LayoutContext used to store layout information | |||
* @param alignment the desired text alignement | |||
* @return the list of KnuthElements | |||
*/ | |||
LinkedList getNextKnuthElements(LayoutContext context, int alignment); | |||
/** | |||
* Tell the LM to modify its data, adding a letter space | |||
* to the word fragment represented by the given element, | |||
* and returning a corrected element | |||
* | |||
* @param element the element which must be given one more letter space | |||
* @return the new element replacing the old one | |||
*/ | |||
KnuthElement addALetterSpaceTo(KnuthElement element); | |||
/** | |||
* Get the word chars corresponding to the given position | |||
* | |||
* @param sbChars the StringBuffer used to append word chars | |||
* @param pos the Position referring to the needed word chars | |||
*/ | |||
void getWordChars(StringBuffer sbChars, Position pos); | |||
/** | |||
* Tell the LM to hyphenate a word | |||
* | |||
* @param pos the Position referring to the word | |||
* @param hc the HyphContext storing hyphenation information | |||
*/ | |||
void hyphenate(Position pos, HyphContext hc); | |||
/** | |||
* Tell the LM to apply the changes due to hyphenation | |||
* | |||
* @param oldList the list of the old elements the changes refer to | |||
* @return true if the LM had to change its data, false otherwise | |||
*/ | |||
boolean applyChanges(List oldList); | |||
/** | |||
* Get a sequence of KnuthElements representing the content | |||
* of the node assigned to the LM, after changes have been applied | |||
* | |||
* @param oldList the elements to replace | |||
* @param flaggedPenalty the penalty value for hyphenated lines | |||
* @param alignment the desired text alignment | |||
* @return the updated list of KnuthElements | |||
*/ | |||
LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, | |||
int alignment); | |||
} |
@@ -69,7 +69,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager { | |||
private Area currentArea; // LineArea or InlineParent | |||
private BreakPoss prevBP; | |||
private LayoutContext childLC ; | |||
protected LayoutContext childLC ; | |||
private LayoutManager lastChildLM = null; // Set when return last breakposs | |||
private boolean bAreaCreated = false; | |||
@@ -462,8 +462,9 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager { | |||
= new StackingIter(positionList.listIterator()); | |||
LayoutManager prevLM = null; | |||
LayoutManager childLM ; | |||
while ((childLM = childPosIter.getNextChildLM()) != null) { | |||
InlineLevelLayoutManager childLM ; | |||
while ((childLM = (InlineLevelLayoutManager) childPosIter.getNextChildLM()) | |||
!= null) { | |||
getContext().setFlags(LayoutContext.LAST_AREA, | |||
context.isLastArea() && childLM == lastLM); | |||
childLM.addAreas(childPosIter, getContext()); | |||
@@ -557,211 +558,5 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager { | |||
} | |||
} | |||
} | |||
public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) { | |||
LayoutManager curLM; | |||
// the list returned by child LM | |||
LinkedList returnedList; | |||
KnuthElement returnedElement; | |||
// the list which will be returned to the parent LM | |||
LinkedList returnList = new LinkedList(); | |||
SpaceSpecifier leadingSpace = lc.getLeadingSpace(); | |||
if (lc.startsNewArea()) { | |||
// First call to this LM in new parent "area", but this may | |||
// not be the first area created by this inline | |||
childLC = new LayoutContext(lc); | |||
if (getSpaceStart() != null) { | |||
lc.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart())); | |||
} | |||
// Check for "fence" | |||
if (hasLeadingFence(!lc.isFirstArea())) { | |||
// Reset leading space sequence for child areas | |||
leadingSpace = new SpaceSpecifier(false); | |||
} | |||
// Reset state variables | |||
clearPrevIPD(); // Clear stored prev content dimensions | |||
} | |||
while ((curLM = getChildLM()) != null) { | |||
// get KnuthElements from curLM | |||
returnedList = curLM.getNextKnuthElements(lc, alignment); | |||
if (returnedList != null) { | |||
// "wrap" the Position stored in each element of returnedList | |||
ListIterator listIter = returnedList.listIterator(); | |||
while (listIter.hasNext()) { | |||
returnedElement = (KnuthElement) listIter.next(); | |||
returnedElement.setPosition | |||
(new NonLeafPosition(this, | |||
returnedElement.getPosition())); | |||
returnList.add(returnedElement); | |||
} | |||
return returnList; | |||
} else { | |||
// curLM returned null because it finished; | |||
// just iterate once more to see if there is another child | |||
} | |||
} | |||
setFinished(true); | |||
return null; | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
NonLeafPosition savedPos = (NonLeafPosition) element.getPosition(); | |||
element.setPosition(savedPos.getPosition()); | |||
KnuthElement newElement | |||
= element.getLayoutManager().addALetterSpaceTo(element); | |||
newElement.setPosition | |||
(new NonLeafPosition(this, newElement.getPosition())); | |||
element.setPosition(savedPos); | |||
return newElement; | |||
} | |||
public void getWordChars(StringBuffer sbChars, Position pos) { | |||
Position newPos = ((NonLeafPosition) pos).getPosition(); | |||
newPos.getLM().getWordChars(sbChars, newPos); | |||
} | |||
public void hyphenate(Position pos, HyphContext hc) { | |||
Position newPos = ((NonLeafPosition) pos).getPosition(); | |||
newPos.getLM().hyphenate(newPos, hc); | |||
} | |||
public boolean applyChanges(List oldList) { | |||
// "unwrap" the Positions stored in the elements | |||
ListIterator oldListIterator = oldList.listIterator(); | |||
KnuthElement oldElement; | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(((NonLeafPosition) oldElement.getPosition()).getPosition()); | |||
} | |||
// reset the iterator | |||
oldListIterator = oldList.listIterator(); | |||
LayoutManager prevLM = null; | |||
LayoutManager currLM; | |||
int fromIndex = 0; | |||
boolean bSomethingChanged = false; | |||
while(oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
currLM = oldElement.getLayoutManager(); | |||
// initialize prevLM | |||
if (prevLM == null) { | |||
prevLM = currLM; | |||
} | |||
if (currLM != prevLM || !oldListIterator.hasNext()) { | |||
if (oldListIterator.hasNext()) { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex())) | |||
|| bSomethingChanged; | |||
prevLM = currLM; | |||
fromIndex = oldListIterator.previousIndex(); | |||
} else if (currLM == prevLM) { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldList.size())) | |||
|| bSomethingChanged; | |||
} else { | |||
bSomethingChanged | |||
= prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex())) | |||
|| bSomethingChanged; | |||
bSomethingChanged | |||
= currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size())) | |||
|| bSomethingChanged; | |||
} | |||
} | |||
} | |||
// "wrap" again the Positions stored in the elements | |||
oldListIterator = oldList.listIterator(); | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(new NonLeafPosition(this, oldElement.getPosition())); | |||
} | |||
return bSomethingChanged; | |||
} | |||
public LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, int alignment) { | |||
// "unwrap" the Positions stored in the elements | |||
ListIterator oldListIterator = oldList.listIterator(); | |||
KnuthElement oldElement; | |||
while (oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
oldElement.setPosition | |||
(((NonLeafPosition) oldElement.getPosition()).getPosition()); | |||
} | |||
// reset the iterator | |||
oldListIterator = oldList.listIterator(); | |||
KnuthElement returnedElement; | |||
LinkedList returnedList = new LinkedList(); | |||
LinkedList returnList = new LinkedList(); | |||
LayoutManager prevLM = null; | |||
LayoutManager currLM; | |||
int fromIndex = 0; | |||
while(oldListIterator.hasNext()) { | |||
oldElement = (KnuthElement) oldListIterator.next(); | |||
currLM = oldElement.getLayoutManager(); | |||
if (prevLM == null) { | |||
prevLM = currLM; | |||
} | |||
if (currLM != prevLM || !oldListIterator.hasNext()) { | |||
if (oldListIterator.hasNext()) { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, | |||
oldListIterator.previousIndex()), | |||
flaggedPenalty, alignment)); | |||
prevLM = currLM; | |||
fromIndex = oldListIterator.previousIndex(); | |||
} else if (currLM == prevLM) { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, oldList.size()), | |||
flaggedPenalty, alignment)); | |||
} else { | |||
returnedList.addAll | |||
(prevLM.getChangedKnuthElements | |||
(oldList.subList(fromIndex, | |||
oldListIterator.previousIndex()), | |||
flaggedPenalty, alignment)); | |||
returnedList.addAll | |||
(currLM.getChangedKnuthElements | |||
(oldList.subList(oldListIterator.previousIndex(), | |||
oldList.size()), | |||
flaggedPenalty, alignment)); | |||
} | |||
} | |||
} | |||
// "wrap" the Position stored in each element of returnedList | |||
ListIterator listIter = returnedList.listIterator(); | |||
while (listIter.hasNext()) { | |||
returnedElement = (KnuthElement) listIter.next(); | |||
returnedElement.setPosition | |||
(new NonLeafPosition(this, returnedElement.getPosition())); | |||
returnList.add(returnedElement); | |||
} | |||
return returnList; | |||
} | |||
public int getWordSpaceIPD() { | |||
LayoutManager firstChild = getChildLM(); | |||
if (firstChild != null) { | |||
return firstChild.getWordSpaceIPD(); | |||
} else { | |||
return 0; | |||
} | |||
} | |||
} | |||
@@ -86,6 +86,7 @@ public class LayoutContext { | |||
private int iLineHeight; | |||
private int iBaseline; | |||
private int iMiddleShift; | |||
public LayoutContext(LayoutContext parentLC) { | |||
this.flags = parentLC.flags; | |||
@@ -98,6 +99,7 @@ public class LayoutContext { | |||
this.ipdAdjust = parentLC.ipdAdjust; | |||
this.iLineHeight = parentLC.iLineHeight; | |||
this.iBaseline = parentLC.iBaseline; | |||
this.iMiddleShift = parentLC.iMiddleShift; | |||
// Copy other fields as necessary. Use clone??? | |||
} | |||
@@ -225,6 +227,14 @@ public class LayoutContext { | |||
return iBaseline; | |||
} | |||
public void setMiddleShift(int ms) { | |||
iMiddleShift = ms; | |||
} | |||
public int getMiddleBaseline() { | |||
return iBaseline + iMiddleShift; | |||
} | |||
public String toString() { | |||
return "Layout Context:" + | |||
"\nStack Limit: \t" + (getStackLimit() == null ? "null" : getStackLimit().toString()) + | |||
@@ -235,6 +245,7 @@ public class LayoutContext { | |||
"\nIPD Adjust: \t" + getIPDAdjust() + | |||
"\nLine Height: \t" + getLineHeight() + | |||
"\nBaseline: \t" + getBaseline() + | |||
"\nMiddle Baseline: \t" + getMiddleBaseline() + | |||
"\nResolve Leading Space: \t" + resolveLeadingSpace() + | |||
"\nSuppress Leading Space: \t" + suppressLeadingSpace() + | |||
"\nIs First Area: \t" + isFirstArea() + |
@@ -237,19 +237,4 @@ public interface LayoutManager { | |||
* @param newLMs the list of LMs to be added | |||
*/ | |||
void addChildLMs(List newLMs); | |||
LinkedList getNextKnuthElements(LayoutContext context, int alignment); | |||
KnuthElement addALetterSpaceTo(KnuthElement element); | |||
void getWordChars(StringBuffer sbChars, Position pos); | |||
void hyphenate(Position pos, HyphContext hc); | |||
boolean applyChanges(List oldList); | |||
LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, | |||
int alignment); | |||
int getWordSpaceIPD(); | |||
} |
@@ -23,7 +23,10 @@ import org.apache.fop.area.inline.FilledArea; | |||
import org.apache.fop.area.inline.InlineArea; | |||
import org.apache.fop.area.inline.Space; | |||
import org.apache.fop.area.inline.TextArea; | |||
import org.apache.fop.datatypes.Length; | |||
import org.apache.fop.datatypes.PercentBase; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.flow.Inline; | |||
import org.apache.fop.fo.flow.Leader; | |||
import org.apache.fop.fonts.Font; | |||
import org.apache.fop.traits.MinOptMax; | |||
@@ -38,6 +41,9 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
private Leader fobj; | |||
Font font = null; | |||
private LinkedList contentList = null; | |||
private ContentLayoutManager clm = null; | |||
/** | |||
* Constructor | |||
* | |||
@@ -48,7 +54,10 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
super(node); | |||
fobj = node; | |||
font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo()); | |||
setAlignment(node.getLeaderAlignment()); | |||
// the property leader-alignment does not affect vertical positioning | |||
// (see section 7.21.1 in the XSL Recommendation) | |||
// setAlignment(node.getLeaderAlignment()); | |||
setAlignment(fobj.getVerticalAlign()); | |||
} | |||
public InlineArea get(LayoutContext context) { | |||
@@ -84,10 +93,9 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
char dot = '.'; // userAgent.getLeaderDotCharacter(); | |||
t.setTextArea("" + dot); | |||
t.setIPD(font.getCharWidth(dot)); | |||
t.addTrait(Trait.FONT_NAME, font.getFontName()); | |||
t.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize())); | |||
// set offset of dot within inline parent | |||
t.setOffset(font.getAscender()); | |||
int width = font.getCharWidth(dot); | |||
Space spacer = null; | |||
if (fobj.getLeaderPatternWidth().getValue() > width) { | |||
@@ -116,15 +124,15 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
// get breaks then add areas to FilledArea | |||
FilledArea fa = new FilledArea(); | |||
ContentLayoutManager clm = new ContentLayoutManager(fa); | |||
clm = new ContentLayoutManager(fa); | |||
clm.setUserAgent(fobj.getUserAgent()); | |||
addChildLM(clm); | |||
InlineStackingLayoutManager lm; | |||
lm = new InlineStackingLayoutManager(fobj); | |||
InlineLayoutManager lm; | |||
lm = new InlineLayoutManager(fobj); | |||
clm.addChildLM(lm); | |||
clm.fillArea(lm); | |||
contentList = clm.getNextKnuthElements(new LayoutContext(0), 0); | |||
int width = clm.getStackingSize(); | |||
Space spacer = null; | |||
if (fobj.getLeaderPatternWidth().getValue() > width) { | |||
@@ -141,6 +149,90 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
return leaderArea; | |||
} | |||
protected void offsetArea(LayoutContext context) { | |||
int pattern = fobj.getLeaderPattern(); | |||
int bpd = curArea.getBPD(); | |||
switch (pattern) { | |||
case LeaderPattern.RULE: | |||
switch (verticalAlignment) { | |||
case VerticalAlign.TOP: | |||
curArea.setOffset(0); | |||
break; | |||
case VerticalAlign.MIDDLE: | |||
curArea.setOffset(context.getMiddleBaseline() - bpd / 2); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
curArea.setOffset(context.getLineHeight() - bpd); | |||
break; | |||
case VerticalAlign.BASELINE: // fall through | |||
default: | |||
curArea.setOffset(context.getBaseline() - bpd); | |||
break; | |||
} | |||
break; | |||
case LeaderPattern.DOTS: | |||
switch (verticalAlignment) { | |||
case VerticalAlign.TOP: | |||
curArea.setOffset(0); | |||
break; | |||
case VerticalAlign.MIDDLE: | |||
curArea.setOffset(context.getMiddleBaseline()); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
curArea.setOffset(context.getLineHeight() - bpd + font.getAscender()); | |||
break; | |||
case VerticalAlign.BASELINE: // fall through | |||
default: | |||
curArea.setOffset(context.getBaseline()); | |||
break; | |||
} | |||
break; | |||
case LeaderPattern.SPACE: | |||
// nothing to do | |||
break; | |||
case LeaderPattern.USECONTENT: | |||
switch (verticalAlignment) { | |||
case VerticalAlign.TOP: | |||
curArea.setOffset(0); | |||
break; | |||
case VerticalAlign.MIDDLE: | |||
curArea.setOffset(context.getMiddleBaseline()); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
curArea.setOffset(context.getLineHeight() - bpd); | |||
break; | |||
case VerticalAlign.BASELINE: // fall through | |||
default: | |||
curArea.setOffset(context.getBaseline()); | |||
break; | |||
} | |||
break; | |||
} | |||
} | |||
public void addAreas(PositionIterator posIter, LayoutContext context) { | |||
if (fobj.getLeaderPattern() != LeaderPattern.USECONTENT) { | |||
// use LeafNodeLayoutManager.addAreas() | |||
super.addAreas(posIter, context); | |||
} else { | |||
addId(); | |||
widthAdjustArea(context); | |||
// add content areas | |||
KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size()); | |||
clm.addAreas(contentIter, context); | |||
offsetArea(context); | |||
parentLM.addChild(curArea); | |||
while (posIter.hasNext()) { | |||
posIter.next(); | |||
} | |||
} | |||
} | |||
public LinkedList getNextKnuthElements(LayoutContext context, | |||
int alignment) { | |||
MinOptMax ipd; | |||
@@ -158,15 +250,13 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
int lead = 0; | |||
int total = 0; | |||
int middle = 0; | |||
switch (alignment) { | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE : middle = bpd / 2 ; | |||
lead = bpd / 2 ; | |||
break; | |||
case VerticalAlign.TOP : total = bpd; | |||
break; | |||
case VerticalAlign.TOP : // fall through | |||
case VerticalAlign.BOTTOM : total = bpd; | |||
break; | |||
case VerticalAlign.BASELINE: | |||
case VerticalAlign.BASELINE: // fall through | |||
default: lead = bpd; | |||
break; | |||
} |
@@ -33,12 +33,13 @@ import java.util.LinkedList; | |||
* This class can be extended to handle the creation and adding of the | |||
* inline area. | |||
*/ | |||
public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
public class LeafNodeLayoutManager extends AbstractLayoutManager | |||
implements InlineLevelLayoutManager { | |||
/** | |||
* The inline area that this leafnode will add. | |||
*/ | |||
protected InlineArea curArea = null; | |||
protected int alignment; | |||
protected int verticalAlignment; | |||
private int lead; | |||
private MinOptMax ipd; | |||
@@ -116,7 +117,7 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
* @param al the vertical alignment positioning | |||
*/ | |||
public void setAlignment(int al) { | |||
alignment = al; | |||
verticalAlignment = al; | |||
} | |||
/** | |||
@@ -146,49 +147,6 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
return null; | |||
} | |||
/** | |||
* Get the next break position. | |||
* Since this holds an inline area it will return a single | |||
* break position. | |||
* @param context the layout context for this inline area | |||
* @return the break poisition for adding this inline area | |||
*/ | |||
public BreakPoss getNextBreakPoss(LayoutContext context) { | |||
curArea = get(context); | |||
if (curArea == null) { | |||
setFinished(true); | |||
return null; | |||
} | |||
BreakPoss bp = new BreakPoss(new LeafPosition(this, 0), | |||
BreakPoss.CAN_BREAK_AFTER | |||
| BreakPoss.CAN_BREAK_BEFORE | BreakPoss.ISFIRST | |||
| BreakPoss.ISLAST); | |||
ipd = getAllocationIPD(context.getRefIPD()); | |||
bp.setStackingSize(ipd); | |||
bp.setNonStackingSize(new MinOptMax(curArea.getBPD())); | |||
bp.setTrailingSpace(new SpaceSpecifier(false)); | |||
int bpd = curArea.getBPD(); | |||
switch (alignment) { | |||
case VerticalAlign.MIDDLE: | |||
bp.setMiddle(bpd / 2 /* - fontLead/2 */); | |||
bp.setLead(bpd / 2 /* + fontLead/2 */); | |||
break; | |||
case VerticalAlign.TOP: | |||
bp.setTotal(bpd); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
bp.setTotal(bpd); | |||
break; | |||
case VerticalAlign.BASELINE: | |||
default: | |||
bp.setLead(bpd); | |||
break; | |||
} | |||
setFinished(true); | |||
return bp; | |||
} | |||
/** | |||
* Get the allocation ipd of the inline area. | |||
* This method may be overridden to handle percentage values. | |||
@@ -199,19 +157,6 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
return new MinOptMax(curArea.getIPD()); | |||
} | |||
/** | |||
* Reset the position. | |||
* If the reset position is null then this inline area should be | |||
* restarted. | |||
* @param resetPos the position to reset. | |||
*/ | |||
public void resetPosition(Position resetPos) { | |||
// only reset if setting null, start again | |||
if (resetPos == null) { | |||
setFinished(false); | |||
} | |||
} | |||
/** | |||
* Add the area for this layout manager. | |||
* This adds the single inline area to the parent. | |||
@@ -244,9 +189,9 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
*/ | |||
protected void offsetArea(LayoutContext context) { | |||
int bpd = curArea.getBPD(); | |||
switch (alignment) { | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE: | |||
curArea.setOffset(context.getBaseline() - bpd / 2 /* - fontLead/2 */); | |||
curArea.setOffset(context.getMiddleBaseline() - bpd / 2); | |||
break; | |||
case VerticalAlign.TOP: | |||
//curArea.setOffset(0); | |||
@@ -305,7 +250,7 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
int lead = 0; | |||
int total = 0; | |||
int middle = 0; | |||
switch (alignment) { | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE : middle = bpd / 2 ; | |||
lead = bpd / 2 ; | |||
break; | |||
@@ -331,6 +276,9 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
return returnList; | |||
} | |||
public void getWordChars(StringBuffer sbChars, Position bp) { | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
// return the unchanged box object | |||
return new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead, | |||
@@ -339,8 +287,6 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { | |||
} | |||
public void hyphenate(Position pos, HyphContext hc) { | |||
// use the AbstractLayoutManager.hyphenate() null implementation | |||
super.hyphenate(pos, hc); | |||
} | |||
public boolean applyChanges(List oldList) { |
@@ -58,7 +58,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
* @param l the default lead, from top to baseline | |||
* @param f the default follow, from baseline to bottom | |||
*/ | |||
public LineLayoutManager(Block node, int lh, int l, int f) { | |||
public LineLayoutManager(Block node, int lh, int l, int f, int ms) { | |||
super(node); | |||
fobj = node; | |||
// the child FObj are owned by the parent BlockLM | |||
@@ -67,6 +67,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
lineHeight = lh; | |||
lead = l; | |||
follow = f; | |||
middleShift = ms; | |||
initialize(); // Normally done when started by parent! | |||
} | |||
@@ -126,6 +127,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
private int lineHeight; | |||
private int lead; | |||
private int follow; | |||
// offset of the middle baseline with respect to the main baseline | |||
private int middleShift; | |||
// inline start pos when adding areas | |||
private int iStartPos = 0; | |||
@@ -151,6 +154,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
// suggested modification to the "optimum" number of lines | |||
private int looseness = 0; | |||
// this constant is used to create elements when text-align is center: | |||
// every TextLM descendant of LineLM must use the same value, | |||
// otherwise the line breaking algorithm does not find the right | |||
// break point | |||
public static final int DEFAULT_SPACE_WIDTH = 3336; | |||
private static final int INFINITE_RATIO = 1000; | |||
// this class represent a feasible breaking point | |||
@@ -272,10 +280,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
// which was the first element in the paragraph | |||
// returned by each LM | |||
private class Update { | |||
private LayoutManager inlineLM; | |||
private InlineLevelLayoutManager inlineLM; | |||
private int iFirstIndex; | |||
public Update(LayoutManager lm, int index) { | |||
public Update(InlineLevelLayoutManager lm, int index) { | |||
inlineLM = lm; | |||
iFirstIndex = index; | |||
} | |||
@@ -288,28 +296,19 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
public int ignoreAtEnd = 0; | |||
// minimum space at the end of the last line (in millipoints) | |||
public int lineFillerWidth; | |||
// word space dimension (in millipoints) | |||
private int wordSpaceIPD; | |||
public void startParagraph(int lineWidth) { | |||
// get the word space dimension, which needs to be known | |||
// in order to center text | |||
LayoutManager lm; | |||
if ((lm = getChildLM()) != null) { | |||
wordSpaceIPD = lm.getWordSpaceIPD(); | |||
} | |||
// set the minimum amount of empty space at the end of the | |||
// last line | |||
if (bTextAlignment == CENTER) { | |||
lineFillerWidth = 0; | |||
} else { | |||
lineFillerWidth = (int)(lineWidth / 6); | |||
lineFillerWidth = (int)(lineWidth / 12); | |||
} | |||
// add auxiliary elements at the beginning of the paragraph | |||
if (bTextAlignment == CENTER && bTextAlignmentLast != JUSTIFY) { | |||
this.add(new KnuthGlue(0, 3 * wordSpaceIPD, 0, | |||
this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0, | |||
null, false)); | |||
ignoreAtStart ++; | |||
} | |||
@@ -333,7 +332,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
if (this.size() > ignoreAtStart) { | |||
if (bTextAlignment == CENTER | |||
&& bTextAlignmentLast != JUSTIFY) { | |||
this.add(new KnuthGlue(0, 3 * wordSpaceIPD, 0, | |||
this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0, | |||
null, false)); | |||
this.add(new KnuthPenalty(0, -KnuthElement.INFINITE, | |||
false, null, false)); | |||
@@ -371,7 +370,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
public BreakPoss getNextBreakPoss(LayoutContext context) { | |||
// Get a break from currently active child LM | |||
// Set up constraints for inline level managers | |||
LayoutManager curLM ; // currently active LM | |||
InlineLevelLayoutManager curLM ; // currently active LM | |||
BreakPoss prev = null; | |||
BreakPoss bp = null; // proposed BreakPoss | |||
@@ -407,57 +406,66 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
Paragraph knuthPar = new Paragraph(); | |||
knuthPar.startParagraph(availIPD.opt); | |||
while ((curLM = getChildLM()) != null) { | |||
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) { | |||
if ((returnedList | |||
= curLM.getNextKnuthElements(inlineLC, | |||
effectiveAlignment)) | |||
!= null) { | |||
// if there are two consecutive KnuthBox, the first one | |||
// does not represent a whole word, so it must be given | |||
// one more letter space | |||
// look at the first element | |||
thisElement = (KnuthElement) returnedList.getFirst(); | |||
if (returnedList.size() > 1 | |||
|| !(thisElement.isPenalty() | |||
&& ((KnuthPenalty) thisElement).getP() | |||
== -KnuthElement.INFINITE)) { | |||
if (thisElement.isBox() && !thisElement.isAuxiliary() | |||
&& bPrevWasKnuthBox) { | |||
prevBox = (KnuthBox) knuthPar.removeLast(); | |||
if (!prevBox.isAuxiliary()) { | |||
// if letter spacing is constant, | |||
// only prevBox needs to be replaced; | |||
knuthPar.addLast(prevBox.getLayoutManager() | |||
.addALetterSpaceTo(prevBox)); | |||
} else { | |||
// prevBox is the last element | |||
// in the sub-sequence | |||
// <box> <aux penalty> <aux glue> <aux box> | |||
// the letter space is added to <aux glue>, | |||
// while the other elements are not changed | |||
KnuthBox auxBox = prevBox; | |||
KnuthGlue auxGlue | |||
= (KnuthGlue) knuthPar.removeLast(); | |||
KnuthPenalty auxPenalty | |||
= (KnuthPenalty) knuthPar.removeLast(); | |||
prevBox = (KnuthBox) knuthPar.getLast(); | |||
knuthPar.addLast(auxPenalty); | |||
knuthPar.addLast(prevBox.getLayoutManager() | |||
.addALetterSpaceTo(prevBox)); | |||
knuthPar.addLast(auxBox); | |||
} | |||
} | |||
if (((KnuthElement) returnedList.getLast()).isBox()) { | |||
bPrevWasKnuthBox = true; | |||
if (thisElement.isBox() && !thisElement.isAuxiliary() | |||
&& bPrevWasKnuthBox) { | |||
prevBox = (KnuthBox) knuthPar.removeLast(); | |||
// if there are two consecutive KnuthBoxes the | |||
// first one does not represent a whole word, | |||
// so it must be given one more letter space | |||
if (!prevBox.isAuxiliary()) { | |||
// if letter spacing is constant, | |||
// only prevBox needs to be replaced; | |||
knuthPar.addLast(((InlineLevelLayoutManager) | |||
prevBox.getLayoutManager()) | |||
.addALetterSpaceTo(prevBox)); | |||
} else { | |||
bPrevWasKnuthBox = false; | |||
// prevBox is the last element | |||
// in the sub-sequence | |||
// <box> <aux penalty> <aux glue> <aux box> | |||
// the letter space is added to <aux glue>, | |||
// while the other elements are not changed | |||
KnuthBox auxBox = prevBox; | |||
KnuthGlue auxGlue | |||
= (KnuthGlue) knuthPar.removeLast(); | |||
KnuthPenalty auxPenalty | |||
= (KnuthPenalty) knuthPar.removeLast(); | |||
prevBox = (KnuthBox) knuthPar.getLast(); | |||
knuthPar.addLast(auxPenalty); | |||
knuthPar.addLast(((InlineLevelLayoutManager) | |||
prevBox.getLayoutManager()) | |||
.addALetterSpaceTo(prevBox)); | |||
knuthPar.addLast(auxBox); | |||
} | |||
// add the new elements to the paragraph | |||
knuthPar.addAll(returnedList); | |||
} | |||
// look at the last element | |||
KnuthElement lastElement = (KnuthElement) returnedList.getLast(); | |||
boolean bForceLinefeed = false; | |||
if (lastElement.isBox()) { | |||
bPrevWasKnuthBox = true; | |||
} else { | |||
// a list with a single penalty item | |||
// whose value is -inf | |||
// represents a preserved linefeed, | |||
// wich forces a line break | |||
bPrevWasKnuthBox = false; | |||
if (lastElement.isPenalty() | |||
&& ((KnuthPenalty) lastElement).getP() | |||
== -KnuthPenalty.INFINITE) { | |||
// a penalty item whose value is -inf | |||
// represents a preserved linefeed, | |||
// wich forces a line break | |||
bForceLinefeed = true; | |||
returnedList.removeLast(); | |||
} | |||
} | |||
// add the new elements to the paragraph | |||
knuthPar.addAll(returnedList); | |||
if (bForceLinefeed) { | |||
knuthPar.endParagraph(); | |||
knuthPar = new Paragraph(); | |||
knuthPar.startParagraph(availIPD.opt); | |||
@@ -467,7 +475,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
// curLM returned null; this can happen | |||
// if it has nothing more to layout, | |||
// so just iterate once more to see | |||
// if there are other chilren | |||
// if there are other children | |||
} | |||
} | |||
knuthPar.endParagraph(); | |||
@@ -647,53 +655,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
double ratio = (textAlign == JUSTIFY) | |||
? bestActiveNode.adjustRatio : 0; | |||
// lead to baseline is | |||
// max of: baseline fixed alignment and middle/2 | |||
// after baseline is | |||
// max: top height-lead, middle/2 and bottom height-lead | |||
int halfLeading = (lineHeight - lead - follow) / 2; | |||
// height before baseline | |||
int lineLead = lead + halfLeading; | |||
// maximum size of top and bottom alignment | |||
int maxtb = follow + halfLeading; | |||
// max size of middle alignment below baseline | |||
int middlefollow = maxtb; | |||
// index of the first KnuthElement in this line | |||
int firstElementIndex = 0; | |||
if (line > 1) { | |||
firstElementIndex = bestActiveNode.previous.position + 1; | |||
} | |||
ListIterator inlineIterator = par.listIterator(firstElementIndex); | |||
for (int j = 0; | |||
j < (bestActiveNode.position - firstElementIndex + 1); | |||
j++) { | |||
KnuthElement element = (KnuthElement) inlineIterator.next(); | |||
if (element.isBox()) { | |||
if (((KnuthBox) element).getLead() > lineLead) { | |||
lineLead = ((KnuthBox) element).getLead(); | |||
} | |||
if (((KnuthBox) element).getTotal() > maxtb) { | |||
maxtb = ((KnuthBox) element).getTotal(); | |||
} | |||
if (((KnuthBox) element).getMiddle() > middlefollow) { | |||
middlefollow = ((KnuthBox) element).getMiddle(); | |||
} | |||
} | |||
} | |||
if (maxtb - lineLead > middlefollow) { | |||
middlefollow = maxtb - lineLead; | |||
} | |||
// add nodes at the beginning of the list, as they are found | |||
// backwards, from the last one to the first one | |||
breakpoints.add(0, | |||
new LineBreakPosition(this, | |||
makeLineBreakPosition(par, | |||
(i > 1 ? bestActiveNode.previous.position + 1: 0), | |||
bestActiveNode.position, | |||
ratio, 0, indent, | |||
lineLead + middlefollow, | |||
lineLead)); | |||
0, ratio, indent); | |||
bestActiveNode = bestActiveNode.previous; | |||
} | |||
if (bForced) { | |||
@@ -705,22 +671,29 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
} | |||
private void fallback(Paragraph par, int line) { | |||
// lead to baseline is | |||
// max of: baseline fixed alignment and middle/2 | |||
// after baseline is | |||
// max: top height-lead, middle/2 and bottom height-lead | |||
makeLineBreakPosition(par, | |||
lastDeactivatedNode.position, | |||
par.size() - 1, | |||
line, 0, 0); | |||
} | |||
private void makeLineBreakPosition(Paragraph par, | |||
int firstElementIndex, int lastElementIndex, | |||
int insertIndex, double ratio, int indent) { | |||
// line height calculation | |||
int halfLeading = (lineHeight - lead - follow) / 2; | |||
// height before baseline | |||
// height above the main baseline | |||
int lineLead = lead + halfLeading; | |||
// maximum size of top and bottom alignment | |||
int maxtb = follow + halfLeading; | |||
// max size of middle alignment below baseline | |||
// max size of middle alignment above and below the middle baseline | |||
int middlefollow = maxtb; | |||
ListIterator inlineIterator | |||
= par.listIterator(lastDeactivatedNode.position); | |||
for (int j = lastDeactivatedNode.position; | |||
j < (par.size()); | |||
= par.listIterator(firstElementIndex); | |||
for (int j = firstElementIndex; | |||
j <= lastElementIndex; | |||
j++) { | |||
KnuthElement element = (KnuthElement) inlineIterator.next(); | |||
if (element.isBox()) { | |||
@@ -730,8 +703,13 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
if (((KnuthBox) element).getTotal() > maxtb) { | |||
maxtb = ((KnuthBox) element).getTotal(); | |||
} | |||
if (((KnuthBox) element).getMiddle() > middlefollow) { | |||
middlefollow = ((KnuthBox) element).getMiddle(); | |||
if (((KnuthBox) element).getMiddle() > lineLead + middleShift) { | |||
lineLead += ((KnuthBox) element).getMiddle() | |||
- lineLead - middleShift; | |||
} | |||
if (((KnuthBox) element).getMiddle() > middlefollow - middleShift) { | |||
middlefollow += ((KnuthBox) element).getMiddle() | |||
- middlefollow + middleShift; | |||
} | |||
} | |||
} | |||
@@ -740,14 +718,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
middlefollow = maxtb - lineLead; | |||
} | |||
breakpoints.add(line, | |||
new LineBreakPosition(this, par.size() - 1, | |||
0, 0, 0, | |||
breakpoints.add(insertIndex, | |||
new LineBreakPosition(this, | |||
lastElementIndex , | |||
ratio, 0, indent, | |||
lineLead + middlefollow, | |||
lineLead)); | |||
} | |||
private void considerLegalBreak(LinkedList par, int lineWidth, | |||
KnuthElement element, | |||
int totalWidth, int totalStretch, | |||
@@ -969,8 +947,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
LinkedList updateList = new LinkedList(); | |||
KnuthElement firstElement = null; | |||
KnuthElement nextElement = null; | |||
// current TextLayoutManager | |||
LayoutManager currLM = null; | |||
// current InlineLevelLayoutManager | |||
InlineLevelLayoutManager currLM = null; | |||
// number of KnuthBox elements containing word fragments | |||
int boxCount; | |||
// number of auxiliary KnuthElements between KnuthBoxes | |||
@@ -982,7 +960,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
firstElement = (KnuthElement) currParIterator.next(); | |||
// | |||
if (firstElement.getLayoutManager() != currLM) { | |||
currLM = firstElement.getLayoutManager(); | |||
currLM = (InlineLevelLayoutManager) firstElement.getLayoutManager(); | |||
if (currLM != null) { | |||
updateList.add(new Update(currLM, currParIterator.previousIndex())); | |||
} else { | |||
@@ -1003,7 +981,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
if (nextElement.isBox() && !nextElement.isAuxiliary()) { | |||
// a non-auxiliary KnuthBox: append word chars | |||
if (currLM != nextElement.getLayoutManager()) { | |||
currLM = nextElement.getLayoutManager(); | |||
currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager(); | |||
updateList.add(new Update(currLM, currParIterator.previousIndex())); | |||
} | |||
// append text to recreate the whole word | |||
@@ -1031,7 +1009,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
for (int i = 0; i < (boxCount + auxCount); i++) { | |||
element = (KnuthElement) currParIterator.next(); | |||
if (element.isBox() && !element.isAuxiliary()) { | |||
element.getLayoutManager().hyphenate(element.getPosition(), hc); | |||
((InlineLevelLayoutManager) | |||
element.getLayoutManager()).hyphenate(element.getPosition(), hc); | |||
} else { | |||
// nothing to do, element is an auxiliary KnuthElement | |||
} | |||
@@ -1065,7 +1044,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
// applyChanges() returns true if the LM modifies its data, | |||
// so it must return new KnuthElements to replace the old ones | |||
if (currUpdate.inlineLM | |||
if (((InlineLevelLayoutManager) currUpdate.inlineLM) | |||
.applyChanges(currPar.subList(fromIndex + iAddedElements, | |||
toIndex + iAddedElements))) { | |||
// insert the new KnuthElements | |||
@@ -1415,6 +1394,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager { | |||
lineArea.setBPD(lbp.lineHeight); | |||
lc.setBaseline(lbp.baseline); | |||
lc.setLineHeight(lbp.lineHeight); | |||
lc.setMiddleShift(middleShift); | |||
setCurrentArea(lineArea); | |||
Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex); |
@@ -73,7 +73,8 @@ public class RetrieveMarkerLayoutManager extends AbstractLayoutManager { | |||
if (replaceLM == null) { | |||
return null; | |||
} | |||
return replaceLM.getNextKnuthElements(context, alignment); | |||
return ((InlineLevelLayoutManager) replaceLM) | |||
.getNextKnuthElements(context, alignment); | |||
} | |||
public void addAreas(PositionIterator parentIter, |
@@ -24,6 +24,7 @@ import java.util.LinkedList; | |||
import java.util.ListIterator; | |||
import org.apache.fop.fo.FOText; | |||
import org.apache.fop.fo.flow.Inline; | |||
import org.apache.fop.fonts.Font; | |||
import org.apache.fop.traits.SpaceVal; | |||
import org.apache.fop.area.Trait; | |||
@@ -36,7 +37,8 @@ import org.apache.fop.traits.MinOptMax; | |||
* LayoutManager for text (a sequence of characters) which generates one | |||
* or more inline areas. | |||
*/ | |||
public class TextLayoutManager extends AbstractLayoutManager { | |||
public class TextLayoutManager extends AbstractLayoutManager | |||
implements InlineLevelLayoutManager { | |||
/** | |||
* Store information about each potential text area. | |||
@@ -117,6 +119,12 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
private short iTempStart = 0; | |||
private LinkedList changeList = null; | |||
private int textHeight; | |||
private int lead = 0; | |||
private int total = 0; | |||
private int middle = 0; | |||
private int verticalAlignment = VerticalAlign.BASELINE; | |||
/** | |||
* Create a Text layout manager. | |||
* | |||
@@ -155,6 +163,26 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
// in the SpaceVal.makeWordSpacing() method | |||
letterSpaceIPD = ls.getSpace(); | |||
wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws.getSpace()); | |||
// set text height | |||
textHeight = fs.getAscender() | |||
- fs.getDescender(); | |||
// if the text node is son of an inline, set vertical align | |||
if (foText.getParent() instanceof Inline) { | |||
setAlignment(((Inline) foText.getParent()).getVerticalAlign()); | |||
} | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE : middle = textHeight / 2 ; | |||
break; | |||
case VerticalAlign.TOP : // fall through | |||
case VerticalAlign.BOTTOM : total = textHeight; | |||
break; | |||
case VerticalAlign.BASELINE: // fall through | |||
default : lead = fs.getAscender(); | |||
total = textHeight; | |||
break; | |||
} | |||
} | |||
/** | |||
@@ -458,8 +486,8 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
* used for calculating the bpd of the line area containing | |||
* this text. | |||
*/ | |||
//bp.setDescender(foText.textInfo.fs.getDescender()); | |||
//bp.setAscender(foText.textInfo.fs.getAscender()); | |||
//bp.setDescender(fs.getDescender()); | |||
//bp.setAscender(fs.getAscender()); | |||
if (iNextStart == textArray.length) { | |||
flags |= BreakPoss.ISLAST; | |||
setFinished(true); | |||
@@ -574,7 +602,7 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
iTotalAdjust += (iWordSpaceDim - wordSpaceIPD.opt) * iWScount; | |||
TextArea t = createTextArea(str, realWidth.opt + iTotalAdjust, | |||
context.getBaseline()); | |||
context); | |||
// iWordSpaceDim is computed in relation to wordSpaceIPD.opt | |||
// but the renderer needs to know the adjustment in relation | |||
@@ -606,12 +634,26 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
* @param base the baseline position | |||
* @return the new word area | |||
*/ | |||
protected TextArea createTextArea(String str, int width, int base) { | |||
protected TextArea createTextArea(String str, int width, LayoutContext context) { | |||
TextArea textArea = new TextArea(); | |||
textArea.setIPD(width); | |||
textArea.setBPD(fs.getAscender() - fs.getDescender()); | |||
textArea.setOffset(fs.getAscender()); | |||
textArea.setOffset(base); | |||
int bpd = textArea.getBPD(); | |||
switch (verticalAlignment) { | |||
case VerticalAlign.MIDDLE: | |||
textArea.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2); | |||
break; | |||
case VerticalAlign.TOP: | |||
textArea.setOffset(fs.getAscender()); | |||
break; | |||
case VerticalAlign.BOTTOM: | |||
textArea.setOffset(context.getLineHeight() - bpd + fs.getAscender()); | |||
break; | |||
case VerticalAlign.BASELINE: | |||
default: | |||
textArea.setOffset(context.getBaseline()); | |||
break; | |||
} | |||
textArea.setTextArea(str); | |||
textArea.addTrait(Trait.FONT_NAME, fs.getFontName()); | |||
@@ -620,13 +662,29 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
return textArea; | |||
} | |||
/** | |||
* Set the alignment of the inline area. | |||
* @param al the vertical alignment positioning | |||
*/ | |||
public void setAlignment(int al) { | |||
verticalAlignment = al; | |||
} | |||
public LinkedList getNextKnuthElements(LayoutContext context, | |||
int alignment) { | |||
LinkedList returnList = new LinkedList(); | |||
while (iNextStart < textArray.length) { | |||
if (textArray[iNextStart] == SPACE) { | |||
if (textArray[iNextStart] == SPACE | |||
|| textArray[iNextStart] == NBSPACE) { | |||
// normal, breaking space | |||
// or non-breaking space | |||
if (textArray[iNextStart] == NBSPACE) { | |||
returnList.add | |||
(new KnuthPenalty(0, KnuthElement.INFINITE, false, | |||
new LeafPosition(this, vecAreaInfo.size() - 1), | |||
false)); | |||
} | |||
switch (alignment) { | |||
case CENTER : | |||
vecAreaInfo.add | |||
@@ -634,14 +692,14 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
(short) 1, (short) 0, | |||
wordSpaceIPD, false)); | |||
returnList.add | |||
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, | |||
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, vecAreaInfo.size() - 1), false)); | |||
returnList.add | |||
(new KnuthPenalty(0, 0, false, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthGlue(wordSpaceIPD.opt, | |||
- 6 * wordSpaceIPD.opt, 0, | |||
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthBox(0, 0, 0, 0, | |||
@@ -650,7 +708,7 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
(new KnuthPenalty(0, KnuthElement.INFINITE, false, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, | |||
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, -1), true)); | |||
iNextStart ++; | |||
break; | |||
@@ -715,8 +773,7 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
iNextStart ++; | |||
} else if (textArray[iNextStart] == NEWLINE) { | |||
// linefeed; this can happen when linefeed-treatment="preserve" | |||
// the linefeed character is the first one in textArray, | |||
// so we can just return a list with a penalty item | |||
// add a penalty item to the list and return | |||
returnList.add | |||
(new KnuthPenalty(0, -KnuthElement.INFINITE, | |||
false, null, false)); | |||
@@ -747,14 +804,15 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
// constant letter space; simply return a box | |||
// whose width includes letter spaces | |||
returnList.add | |||
(new KnuthBox(wordIPD.opt, 0, 0, 0, | |||
(new KnuthBox(wordIPD.opt, lead, total, middle, | |||
new LeafPosition(this, vecAreaInfo.size() - 1), false)); | |||
iNextStart = iTempStart; | |||
} else { | |||
// adjustable letter space; | |||
// some other KnuthElements are needed | |||
returnList.add | |||
(new KnuthBox(wordIPD.opt - (iTempStart - iThisStart - 1) * letterSpaceIPD.opt, 0, 0, 0, | |||
(new KnuthBox(wordIPD.opt - (iTempStart - iThisStart - 1) * letterSpaceIPD.opt, | |||
lead, total, middle, | |||
new LeafPosition(this, vecAreaInfo.size() - 1), false)); | |||
returnList.add | |||
(new KnuthPenalty(0, KnuthElement.INFINITE, false, | |||
@@ -765,7 +823,7 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
(iTempStart - iThisStart - 1) * (letterSpaceIPD.opt - letterSpaceIPD.min), | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthBox(0, 0, 0, 0, | |||
(new KnuthBox(0, lead, total, middle, | |||
new LeafPosition(this, -1), true)); | |||
iNextStart = iTempStart; | |||
} | |||
@@ -779,17 +837,13 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
} | |||
} | |||
public int getWordSpaceIPD() { | |||
return wordSpaceIPD.opt; | |||
} | |||
public KnuthElement addALetterSpaceTo(KnuthElement element) { | |||
LeafPosition pos = (LeafPosition) element.getPosition(); | |||
AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos()); | |||
ai.iLScount ++; | |||
ai.ipdArea.add(letterSpaceIPD); | |||
if (letterSpaceIPD.min == letterSpaceIPD.max) { | |||
return new KnuthBox(ai.ipdArea.opt, 0, 0, 0, pos, false); | |||
return new KnuthBox(ai.ipdArea.opt, lead, total, middle, pos, false); | |||
} else { | |||
return new KnuthGlue(ai.iLScount * letterSpaceIPD.opt, | |||
ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt), | |||
@@ -908,13 +962,13 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
// ai refers either to a word or a word fragment | |||
if (letterSpaceIPD.min == letterSpaceIPD.max) { | |||
returnList.add | |||
(new KnuthBox(ai.ipdArea.opt, 0, 0, 0, | |||
(new KnuthBox(ai.ipdArea.opt, lead, total, middle, | |||
new LeafPosition(this, iReturnedIndex), false)); | |||
} else { | |||
returnList.add | |||
(new KnuthBox(ai.ipdArea.opt | |||
- ai.iLScount * letterSpaceIPD.opt, | |||
0, 0, 0, | |||
lead, total, middle, | |||
new LeafPosition(this, iReturnedIndex), false)); | |||
returnList.add | |||
(new KnuthPenalty(0, KnuthElement.INFINITE, false, | |||
@@ -939,14 +993,14 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
switch (alignment) { | |||
case CENTER : | |||
returnList.add | |||
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, | |||
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, iReturnedIndex), false)); | |||
returnList.add | |||
(new KnuthPenalty(0, 0, false, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthGlue(wordSpaceIPD.opt, | |||
- 6 * wordSpaceIPD.opt, 0, | |||
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthBox(0, 0, 0, 0, | |||
@@ -955,7 +1009,7 @@ public class TextLayoutManager extends AbstractLayoutManager { | |||
(new KnuthPenalty(0, KnuthElement.INFINITE, false, | |||
new LeafPosition(this, -1), true)); | |||
returnList.add | |||
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0, | |||
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, | |||
new LeafPosition(this, -1), true)); | |||
iReturnedIndex ++; | |||
break; |