--- old/area/inline/FilledArea.java Fri Oct 15 13:53:49 2004 +++ old/area/inline/FilledArea.java Fri Oct 15 13:31:34 2004 @@ -19,6 +19,7 @@ package org.apache.fop.area.inline; import java.util.List; +import java.util.ListIterator; import java.util.ArrayList; /** @@ -37,6 +38,29 @@ * Create a new filled area. */ 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); + } + } } /** --- old/layoutmgr/BlockLayoutManager.java Fri Oct 15 13:50:35 2004 +++ old/layoutmgr/BlockLayoutManager.java Fri Oct 15 14:06:16 2004 @@ -65,6 +65,7 @@ private int lead = 12000; private int lineHeight = 14000; private int follow = 2000; + private int middleShift = 0; private int iStartPos = 0; @@ -81,6 +82,7 @@ private void setBlockTextInfo(TextInfo ti) { lead = ti.fs.getAscender(); follow = -ti.fs.getDescender(); + middleShift = - ti.fs.getXHeight() / 2; lineHeight = ti.lineHeight; } @@ -156,7 +158,7 @@ */ 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()) { --- old/layoutmgr/CharacterLayoutManager.java Fri Oct 15 13:50:46 2004 +++ old/layoutmgr/CharacterLayoutManager.java Fri Oct 15 13:31:34 2004 @@ -47,6 +47,7 @@ super(node); InlineArea inline = getCharacterInlineArea(node); setCurrentArea(inline); + setAlignment(node.getPropEnum(PR_VERTICAL_ALIGN)); textInfo = node.getPropertyManager().getTextLayoutProps (node.getFOEventHandler().getFontInfo()); @@ -74,15 +75,15 @@ */ 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() + textInfo.fs.getXHeight() / 2); break; case VerticalAlign.TOP: - //curArea.setOffset(0); + curArea.setOffset(textInfo.fs.getAscender()); break; case VerticalAlign.BOTTOM: - curArea.setOffset(context.getLineHeight() - bpd); + curArea.setOffset(context.getLineHeight() - bpd + textInfo.fs.getAscender()); break; case VerticalAlign.BASELINE: default: @@ -121,16 +122,15 @@ 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 = textInfo.fs.getAscender(); + total = bpd; break; } --- old/layoutmgr/ContentLayoutManager.java Fri Oct 15 13:50:53 2004 +++ old/layoutmgr/ContentLayoutManager.java Fri Oct 15 13:31:34 2004 @@ -22,6 +22,7 @@ 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.Resolveable; import org.apache.fop.area.PageViewport; @@ -40,12 +41,12 @@ * For use with objects that contain inline areas such as * leader use-content and title. */ -public class ContentLayoutManager implements LayoutManager { +public class ContentLayoutManager implements InlineLayoutManager { private FOUserAgent userAgent; private Area holder; private int stackSize; private LayoutManager parentLM; - private List childLMs = new ArrayList(1); + private InlineLayoutManager childLM = null; /** * logging instance @@ -137,6 +138,19 @@ 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; } @@ -202,9 +216,6 @@ } /** @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 @@ * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs */ public List getChildLMs() { + List childLMs = new ArrayList(1); + childLMs.add(childLM); return childLMs; } @@ -271,7 +284,7 @@ } lm.setParent(this); lm.initialize(); - childLMs.add(lm); + childLM = (InlineLayoutManager)lm; log.trace(this.getClass().getName() + ": Adding child LM " + lm.getClass().getName()); } @@ -290,10 +303,27 @@ } } - public LinkedList getNextKnuthElements(LayoutContext context, - int alignment) { + 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) { @@ -314,10 +344,6 @@ int flaggedPenalty, int alignment) { return null; - } - - public int getWordSpaceIPD() { - return 0; } } --- old/layoutmgr/InlineLayoutManager.java Thu Jan 1 01:00:00 1970 +++ old/layoutmgr/InlineLayoutManager.java Fri Oct 15 13:31:34 2004 @@ -0,0 +1,84 @@ +/* + * Copyright 1999-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 InlineLayoutManager 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); +} --- old/layoutmgr/InlineStackingLayoutManager.java Fri Oct 15 13:51:11 2004 +++ old/layoutmgr/InlineStackingLayoutManager.java Fri Oct 15 13:31:34 2004 @@ -39,7 +39,8 @@ * LayoutManager for objects which stack children in the inline direction, * such as Inline or Line */ -public class InlineStackingLayoutManager extends AbstractLayoutManager { +public class InlineStackingLayoutManager extends AbstractLayoutManager + implements InlineLayoutManager { private static class StackingIter extends PositionIterator { @@ -222,86 +223,6 @@ hmPrevIPD.clear(); } - /** - * Get the next break position for this layout manager. - * The next break position will be an position within the - * areas return by the child inline layout managers. - * - * @param lc the layout context for finding breaks - * @return the next break position - */ - public BreakPoss getNextBreakPoss(LayoutContext lc) { - // Get a break from currently active child LM - BreakPoss bp = null; - LayoutManager curLM; - 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); - lc.getLeadingSpace().addSpace(inlineProps.spaceStart); - - // 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 - } - - // We only do this loop more than once if a childLM returns - // a null BreakPoss, meaning it has nothing (more) to layout. - while ((curLM = getChildLM()) != null) { - - // ignore nested blocks for now - if (!curLM.generatesInlineAreas()) { - log.warn("ignoring block inside inline fo"); - curLM.setFinished(true); - continue; - } - /* If first break for this child LM, set START_AREA flag - * and initialize pending space from previous LM sibling's - * trailing space specifiers. - */ - boolean bFirstChildBP = (prevBP == null - || prevBP.getLayoutManager() != curLM); - - initChildLC(childLC, prevBP, lc.startsNewArea(), - bFirstChildBP, leadingSpace); - if (lc.tryHyphenate()) { - childLC.setHyphContext(lc.getHyphContext()); - } - - if (((bp = curLM.getNextBreakPoss(childLC)) != null) - || (lc.tryHyphenate() - && !lc.getHyphContext().hasMoreHyphPoints())) { - break; - } - // If LM has no content, should it generate any area? If not, - // should trailing space from a previous area interact with - // leading space from a following area? - } - if (bp == null) { - setFinished(true); - return null; // There was no childLM with anything to layout - // Alternative is to return a BP with the isLast flag set - } else { - boolean bIsLast = false; - if (getChildLM() == null) { - bIsLast = true; - setFinished(true); - } else if (bp.couldEndLine()) { - /* Child LM ends with suppressible spaces. See if it could - * end this LM's area too. Child LM finish flag is NOT set! - */ - bIsLast = !hasMoreLM(bp.getLayoutManager()); - } - return makeBreakPoss(bp, lc, bIsLast); - } - } - /** ATTENTION: ALSO USED BY LineLayoutManager! */ protected void initChildLC(LayoutContext childLC, BreakPoss prevBP, boolean bStartParent, boolean bFirstChildBP, @@ -487,8 +408,9 @@ = new StackingIter(positionList.listIterator()); LayoutManager prevLM = null; - LayoutManager childLM ; - while ((childLM = childPosIter.getNextChildLM()) != null) { + InlineLayoutManager childLM ; + while ((childLM = (InlineLayoutManager) childPosIter.getNextChildLM()) + != null) { getContext().setFlags(LayoutContext.LAST_AREA, context.isLastArea() && childLM == lastLM); childLM.addAreas(childPosIter, getContext()); @@ -590,7 +512,7 @@ } public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) { - LayoutManager curLM; + InlineLayoutManager curLM; // the list returned by child LM LinkedList returnedList; @@ -616,7 +538,7 @@ clearPrevIPD(); // Clear stored prev content dimensions } - while ((curLM = getChildLM()) != null) { + while ((curLM = (InlineLayoutManager) getChildLM()) != null) { // get KnuthElements from curLM returnedList = curLM.getNextKnuthElements(lc, alignment); if (returnedList != null) { @@ -644,7 +566,8 @@ element.setPosition(savedPos.getPosition()); KnuthElement newElement - = element.getLayoutManager().addALetterSpaceTo(element); + = ((InlineLayoutManager) + element.getLayoutManager()).addALetterSpaceTo(element); newElement.setPosition (new NonLeafPosition(this, newElement.getPosition())); element.setPosition(savedPos); @@ -653,12 +576,14 @@ public void getWordChars(StringBuffer sbChars, Position pos) { Position newPos = ((NonLeafPosition) pos).getPosition(); - newPos.getLM().getWordChars(sbChars, newPos); + ((InlineLayoutManager) + newPos.getLM()).getWordChars(sbChars, newPos); } public void hyphenate(Position pos, HyphContext hc) { Position newPos = ((NonLeafPosition) pos).getPosition(); - newPos.getLM().hyphenate(newPos, hc); + ((InlineLayoutManager) + newPos.getLM()).hyphenate(newPos, hc); } public boolean applyChanges(List oldList) { @@ -673,14 +598,14 @@ // reset the iterator oldListIterator = oldList.listIterator(); - LayoutManager prevLM = null; - LayoutManager currLM; + InlineLayoutManager prevLM = null; + InlineLayoutManager currLM; int fromIndex = 0; boolean bSomethingChanged = false; while(oldListIterator.hasNext()) { oldElement = (KnuthElement) oldListIterator.next(); - currLM = oldElement.getLayoutManager(); + currLM = (InlineLayoutManager) oldElement.getLayoutManager(); // initialize prevLM if (prevLM == null) { prevLM = currLM; @@ -733,13 +658,13 @@ KnuthElement returnedElement; LinkedList returnedList = new LinkedList(); LinkedList returnList = new LinkedList(); - LayoutManager prevLM = null; - LayoutManager currLM; + InlineLayoutManager prevLM = null; + InlineLayoutManager currLM; int fromIndex = 0; while(oldListIterator.hasNext()) { oldElement = (KnuthElement) oldListIterator.next(); - currLM = oldElement.getLayoutManager(); + currLM = (InlineLayoutManager) oldElement.getLayoutManager(); if (prevLM == null) { prevLM = currLM; } @@ -782,15 +707,6 @@ returnList.add(returnedElement); } return returnList; - } - - public int getWordSpaceIPD() { - LayoutManager firstChild = getChildLM(); - if (firstChild != null) { - return firstChild.getWordSpaceIPD(); - } else { - return 0; - } } } --- old/layoutmgr/LayoutContext.java Fri Oct 15 13:51:21 2004 +++ old/layoutmgr/LayoutContext.java Fri Oct 15 14:07:47 2004 @@ -86,6 +86,7 @@ private int iLineHeight; private int iBaseline; + private int iMiddleShift; public LayoutContext(LayoutContext parentLC) { this.flags = parentLC.flags; @@ -98,6 +99,7 @@ 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 @@ 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 @@ "\nIPD Adjust: \t" + getIPDAdjust() + "\nLine Height: \t" + getLineHeight() + "\nBaseline: \t" + getBaseline() + + "\nMiddleBaseline: \t" + getMiddleBaseline() + "\nResolve Leading Space: \t" + resolveLeadingSpace() + "\nSuppress Leading Space: \t" + suppressLeadingSpace() + "\nIs First Area: \t" + isFirstArea() + --- old/layoutmgr/LayoutManager.java Fri Oct 15 13:51:32 2004 +++ old/layoutmgr/LayoutManager.java Fri Oct 15 13:31:34 2004 @@ -18,7 +18,6 @@ package org.apache.fop.layoutmgr; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -237,19 +236,4 @@ * @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(); } --- old/layoutmgr/LeaderLayoutManager.java Fri Oct 15 13:51:41 2004 +++ old/layoutmgr/LeaderLayoutManager.java Fri Oct 15 14:09:00 2004 @@ -23,6 +23,9 @@ 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.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 @@ Leader ldrNode; Font font = null; + private LinkedList contentList = null; + private ContentLayoutManager clm = null; + /** * Constructor * @@ -48,7 +54,7 @@ super(node); ldrNode = node; font = node.getFontState(); - setAlignment(node.getPropEnum(PR_LEADER_ALIGNMENT)); + setAlignment(node.getPropEnum(PR_VERTICAL_ALIGN)); } public InlineArea get(LayoutContext context) { @@ -83,10 +89,9 @@ 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 (ldrNode.getPatternWidth() > width) { @@ -115,7 +120,7 @@ // get breaks then add areas to FilledArea FilledArea fa = new FilledArea(); - ContentLayoutManager clm = new ContentLayoutManager(fa); + clm = new ContentLayoutManager(fa); clm.setUserAgent(ldrNode.getUserAgent()); addChildLM(clm); @@ -123,7 +128,7 @@ lm = new InlineStackingLayoutManager(ldrNode); clm.addChildLM(lm); - clm.fillArea(lm); + contentList = clm.getNextKnuthElements(new LayoutContext(0), 0); int width = clm.getStackingSize(); Space spacer = null; if (ldrNode.getPatternWidth() > width) { @@ -140,6 +145,90 @@ return leaderArea; } + protected void offsetArea(LayoutContext context) { + int pattern = ldrNode.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 (ldrNode.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; @@ -157,15 +246,13 @@ 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; } --- old/layoutmgr/LeafNodeLayoutManager.java Fri Oct 15 13:51:49 2004 +++ old/layoutmgr/LeafNodeLayoutManager.java Fri Oct 15 14:10:12 2004 @@ -33,12 +33,13 @@ * 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 InlineLayoutManager { /** * The inline area that this leafnode will add. */ protected InlineArea curArea = null; - protected int alignment; + protected int verticalAlignment; private int lead; private MinOptMax ipd; @@ -122,7 +123,7 @@ * @param al the vertical alignment positioning */ public void setAlignment(int al) { - alignment = al; + verticalAlignment = al; } /** @@ -153,49 +154,6 @@ } /** - * 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. * @param refIPD the ipd of the parent reference area @@ -206,19 +164,6 @@ } /** - * 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. * @param posIter the position iterator @@ -246,9 +191,9 @@ */ 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); @@ -307,7 +252,7 @@ int lead = 0; int total = 0; int middle = 0; - switch (alignment) { + switch (verticalAlignment) { case VerticalAlign.MIDDLE : middle = bpd / 2 ; lead = bpd / 2 ; break; @@ -341,8 +286,6 @@ } public void hyphenate(Position pos, HyphContext hc) { - // use the AbstractLayoutManager.hyphenate() null implementation - super.hyphenate(pos, hc); } public boolean applyChanges(List oldList) { --- old/layoutmgr/LineLayoutManager.java Fri Oct 15 13:51:56 2004 +++ old/layoutmgr/LineLayoutManager.java Fri Oct 15 14:15:30 2004 @@ -111,6 +111,7 @@ private int lineHeight; private int lead; private int follow; + private int middleShift; // offset of the middle baseline with respect to the main baseline // inline start pos when adding areas private int iStartPos = 0; @@ -136,6 +137,11 @@ // 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 @@ -257,10 +263,10 @@ // which was the first element in the paragraph // returned by each LM private class Update { - private LayoutManager inlineLM; + private InlineLayoutManager inlineLM; private int iFirstIndex; - public Update(LayoutManager lm, int index) { + public Update(InlineLayoutManager lm, int index) { inlineLM = lm; iFirstIndex = index; } @@ -273,28 +279,19 @@ 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 ++; } @@ -318,7 +315,7 @@ 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)); @@ -355,7 +352,7 @@ * @param l the default lead, from top to baseline * @param f the default follow, from baseline to bottom */ - public LineLayoutManager(FObj node, int lh, int l, int f) { + public LineLayoutManager(FObj node, int lh, int l, int f, int ms) { super(node); // the child FObj are owned by the parent BlockLM // this LM has all its childLMs preloaded @@ -363,6 +360,7 @@ lineHeight = lh; lead = l; follow = f; + middleShift = ms; initialize(); // Normally done when started by parent! } @@ -376,7 +374,7 @@ 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 + InlineLayoutManager curLM ; // currently active LM BreakPoss prev = null; BreakPoss bp = null; // proposed BreakPoss @@ -412,26 +410,24 @@ Paragraph knuthPar = new Paragraph(); knuthPar.startParagraph(availIPD.opt); - while ((curLM = getChildLM()) != null) { + while ((curLM = (InlineLayoutManager) 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 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(prevBox.getLayoutManager() + knuthPar.addLast(((InlineLayoutManager) + prevBox.getLayoutManager()) .addALetterSpaceTo(prevBox)); } else { // prevBox is the last element @@ -446,23 +442,34 @@ = (KnuthPenalty) knuthPar.removeLast(); prevBox = (KnuthBox) knuthPar.getLast(); knuthPar.addLast(auxPenalty); - knuthPar.addLast(prevBox.getLayoutManager() + knuthPar.addLast(((InlineLayoutManager) + prevBox.getLayoutManager()) .addALetterSpaceTo(prevBox)); knuthPar.addLast(auxBox); } } - if (((KnuthElement) returnedList.getLast()).isBox()) { + + // look at the last element + KnuthElement lastElement = (KnuthElement) returnedList.getLast(); + boolean bForceLinefeed = false; + if (lastElement.isBox()) { bPrevWasKnuthBox = true; } else { 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); - } else { - // a list with a single penalty item - // whose value is -inf - // represents a preserved linefeed, - // wich forces a line break + if (bForceLinefeed) { knuthPar.endParagraph(); knuthPar = new Paragraph(); knuthPar.startParagraph(availIPD.opt); @@ -472,7 +479,7 @@ // 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(); @@ -652,53 +659,11 @@ 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) { @@ -710,22 +675,29 @@ } 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 before 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 before and after 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()) { @@ -735,8 +707,13 @@ 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; } } } @@ -745,14 +722,14 @@ 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, @@ -974,8 +951,8 @@ LinkedList updateList = new LinkedList(); KnuthElement firstElement = null; KnuthElement nextElement = null; - // current TextLayoutManager - LayoutManager currLM = null; + // current InlineLayoutManager + InlineLayoutManager currLM = null; // number of KnuthBox elements containing word fragments int boxCount; // number of auxiliary KnuthElements between KnuthBoxes @@ -987,7 +964,7 @@ firstElement = (KnuthElement) currParIterator.next(); // if (firstElement.getLayoutManager() != currLM) { - currLM = firstElement.getLayoutManager(); + currLM = (InlineLayoutManager) firstElement.getLayoutManager(); if (currLM != null) { updateList.add(new Update(currLM, currParIterator.previousIndex())); } else { @@ -1008,7 +985,7 @@ if (nextElement.isBox() && !nextElement.isAuxiliary()) { // a non-auxiliary KnuthBox: append word chars if (currLM != nextElement.getLayoutManager()) { - currLM = nextElement.getLayoutManager(); + currLM = (InlineLayoutManager) nextElement.getLayoutManager(); updateList.add(new Update(currLM, currParIterator.previousIndex())); } // append text to recreate the whole word @@ -1036,7 +1013,8 @@ for (int i = 0; i < (boxCount + auxCount); i++) { element = (KnuthElement) currParIterator.next(); if (element.isBox() && !element.isAuxiliary()) { - element.getLayoutManager().hyphenate(element.getPosition(), hc); + ((InlineLayoutManager) + element.getLayoutManager()).hyphenate(element.getPosition(), hc); } else { // nothing to do, element is an auxiliary KnuthElement } @@ -1070,7 +1048,7 @@ // applyChanges() returns true if the LM modifies its data, // so it must return new KnuthElements to replace the old ones - if (currUpdate.inlineLM + if (((InlineLayoutManager) currUpdate.inlineLM) .applyChanges(currPar.subList(fromIndex + iAddedElements, toIndex + iAddedElements))) { // insert the new KnuthElements @@ -1420,6 +1398,7 @@ lineArea.setBPD(lbp.lineHeight); lc.setBaseline(lbp.baseline); lc.setLineHeight(lbp.lineHeight); + lc.setMiddleShift(middleShift); setCurrentArea(lineArea); Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex); --- old/layoutmgr/TextLayoutManager.java Fri Oct 15 13:52:01 2004 +++ old/layoutmgr/TextLayoutManager.java Fri Oct 15 14:17:04 2004 @@ -24,10 +24,12 @@ import java.util.ListIterator; import org.apache.fop.fo.FOText; +import org.apache.fop.fo.Constants; import org.apache.fop.traits.SpaceVal; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.InlineArea; import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.Space; import org.apache.fop.util.CharUtilities; import org.apache.fop.traits.MinOptMax; @@ -35,7 +37,7 @@ * LayoutManager for text (a sequence of characters) which generates one * or more inline areas. */ -public class TextLayoutManager extends AbstractLayoutManager { +public class TextLayoutManager extends LeafNodeLayoutManager { /** * Store information about each potential text area. @@ -115,6 +117,11 @@ private short iTempStart = 0; private LinkedList changeList = null; + private int textHeight; + private int lead = 0; + private int total = 0; + private int middle = 0; + /** * Create a Text layout manager. * @@ -155,6 +162,23 @@ wordSpaceIPD = new MinOptMax(spaceCharIPD + ws.getSpace().min, spaceCharIPD + ws.getSpace().opt, spaceCharIPD + ws.getSpace().max); + + // set text height + textHeight = foText.textInfo.fs.getAscender() + - foText.textInfo.fs.getDescender(); + + setAlignment(foText.textInfo.verticalAlign); + 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 = foText.textInfo.fs.getAscender(); + total = textHeight; + break; + } } /** @@ -576,7 +600,7 @@ 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 @@ -608,13 +632,27 @@ * @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(foText.textInfo.fs.getAscender() - foText.textInfo.fs.getDescender()); + int bpd = textArea.getBPD(); + switch (verticalAlignment) { + case VerticalAlign.MIDDLE: + textArea.setOffset(context.getMiddleBaseline() + foText.textInfo.fs.getXHeight() / 2); + break; + case VerticalAlign.TOP: textArea.setOffset(foText.textInfo.fs.getAscender()); - textArea.setOffset(base); + break; + case VerticalAlign.BOTTOM: + textArea.setOffset(context.getLineHeight() - bpd + foText.textInfo.fs.getAscender()); + break; + case VerticalAlign.BASELINE: + default: + textArea.setOffset(context.getBaseline()); + break; + } textArea.setTextArea(str); textArea.addTrait(Trait.FONT_NAME, foText.textInfo.fs.getFontName()); @@ -629,8 +667,16 @@ 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 @@ -638,14 +684,14 @@ (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, @@ -654,7 +700,7 @@ (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; @@ -719,8 +765,7 @@ 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)); @@ -751,14 +796,15 @@ // 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, @@ -769,7 +815,7 @@ (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; } @@ -783,17 +829,13 @@ } } - 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), @@ -912,13 +954,13 @@ // 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, @@ -943,14 +985,14 @@ 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, @@ -959,7 +1001,7 @@ (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;