diff options
author | Jeremias Maerki <jeremias@apache.org> | 2005-05-13 19:16:54 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2005-05-13 19:16:54 +0000 |
commit | e835307c9373bed3a8f41bb43e4faee15fdaf548 (patch) | |
tree | 04b42bcff456d9216e96b4cfcb572c59baba76e1 /src/java/org/apache/fop/layoutmgr/AbstractBreaker.java | |
parent | da85c0b44d79ca790b51fcc0e2700c30e72e9260 (diff) | |
download | xmlgraphics-fop-e835307c9373bed3a8f41bb43e4faee15fdaf548.tar.gz xmlgraphics-fop-e835307c9373bed3a8f41bb43e4faee15fdaf548.zip |
Merge of branch Temp_KnuthStylePageBreaking back into HEAD.
Temp_KnuthStylePageBreaking branch and HEAD have been tagged prior to the merge, so merging uncommitted work from the branch should be easier.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198627 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/layoutmgr/AbstractBreaker.java')
-rw-r--r-- | src/java/org/apache/fop/layoutmgr/AbstractBreaker.java | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java new file mode 100644 index 000000000..36adad77b --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java @@ -0,0 +1,661 @@ +/* + * Copyright 2004-2005 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; +import java.util.ListIterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.fo.Constants; +import org.apache.fop.traits.MinOptMax; + +/** + * Abstract base class for breakers (page breakers, static region handlers etc.). + */ +public abstract class AbstractBreaker { + + /** logging instance */ + protected static Log log = LogFactory.getLog(AbstractBreaker.class); + + /*LF*/ + public static class PageBreakPosition extends LeafPosition { + double bpdAdjust; // Percentage to adjust (stretch or shrink) + int difference; + + PageBreakPosition(LayoutManager lm, int iBreakIndex, + double bpdA, int diff) { + super(lm, iBreakIndex); + bpdAdjust = bpdA; + difference = diff; + } + } + + public class BlockSequence extends KnuthSequence { + + /** + * startOn represents where on the page/which page layout + * should start for this BlockSequence. Acceptable values: + * Constants.EN_ANY (can continue from finished location + * of previous BlockSequence?), EN_COLUMN, EN_ODD_PAGE, + * EN_EVEN_PAGE. + */ + private int startOn; + + public BlockSequence(int iStartOn) { + super(); + startOn = iStartOn; + } + + public int getStartOn() { + return this.startOn; + } + + public BlockSequence endBlockSequence() { + KnuthSequence temp = super.endSequence(); + if (temp != null) { + BlockSequence returnSequence = new BlockSequence(startOn); + returnSequence.addAll(temp); + returnSequence.ignoreAtEnd = this.ignoreAtEnd; + return returnSequence; + } else { + return null; + } + } + } + + /** blockListIndex of the current BlockSequence in blockLists */ + private int blockListIndex = 0; +/*LF*/ + /*LF*/ + private List blockLists = null; + + private int alignment; + private int alignmentLast; + /*LF*/ + + protected abstract int getCurrentDisplayAlign(); + protected abstract boolean hasMoreContent(); + protected abstract void addAreas(PositionIterator posIter, LayoutContext context); + protected abstract LayoutManager getTopLevelLM(); + protected abstract LayoutManager getCurrentChildLM(); + protected abstract LinkedList getNextKnuthElements(LayoutContext context, int alignment); + + /** @return true if there's no content that could be handled. */ + public boolean isEmpty() { + return (blockLists.size() == 0); + } + + protected void startPart(BlockSequence list, boolean bIsFirstPage) { + //nop + } + + protected abstract void finishPart(); + + protected LayoutContext createLayoutContext() { + return new LayoutContext(0); + } + + public void doLayout(int flowBPD) { + LayoutContext childLC = createLayoutContext(); + childLC.setStackLimit(new MinOptMax(flowBPD)); + + //System.err.println("Vertical alignment: " + + // currentSimplePageMaster.getRegion(FO_REGION_BODY).getDisplayAlign()); + if (getCurrentDisplayAlign() == Constants.EN_X_FILL) { + //EN_FILL is non-standard (by LF) + alignment = Constants.EN_JUSTIFY; + } else { + alignment = Constants.EN_START; + } + alignmentLast = Constants.EN_START; + + BlockSequence blockList; + blockLists = new java.util.ArrayList(); + + System.out.println("PLM> flow BPD =" + flowBPD); + + //*** Phase 1: Get Knuth elements *** + int nextSequenceStartsOn = Constants.EN_ANY; + while (hasMoreContent()) { + nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn, blockLists); + } + + //*** Phase 2: Alignment and breaking *** + System.out.println("PLM> blockLists.size() = " + blockLists.size()); + for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) { + blockList = (BlockSequence) blockLists.get(blockListIndex); + + //debug code start + System.err.println(" blockListIndex = " + blockListIndex); + String pagina = (blockList.startOn == Constants.EN_ANY) ? "any page" + : (blockList.startOn == Constants.EN_ODD_PAGE) ? "odd page" + : "even page"; + System.err.println(" sequence starts on " + pagina); + logBlocklist(blockList); + //debug code end + + System.out.println("PLM> start of algorithm (" + this.getClass().getName() + + "), flow BPD =" + flowBPD); + PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(), + alignment, alignmentLast); + int iOptPageNumber; + + BlockSequence effectiveList; + if (alignment == Constants.EN_JUSTIFY) { + /* justification */ + effectiveList = justifyBoxes(blockList, alg, flowBPD); + } else { + /* no justification */ + effectiveList = blockList; + } + + //iOptPageNumber = alg.firstFit(effectiveList, flowBPD, 1, true); + iOptPageNumber = alg.findBreakingPoints(effectiveList, flowBPD, 1, + true, true); + System.out.println("PLM> iOptPageNumber= " + iOptPageNumber + + " pageBreaks.size()= " + alg.getPageBreaks().size()); + + + //*** Phase 3: Add areas *** + doPhase3(alg, iOptPageNumber, blockList, effectiveList); + } + } + + /** + * Phase 3 of Knuth algorithm: Adds the areas + * @param alg PageBreakingAlgorithm instance which determined the breaks + * @param partCount number of parts (pages) to be rendered + * @param originalList original Knuth element list + * @param effectiveList effective Knuth element list (after adjustments) + */ + protected abstract void doPhase3(PageBreakingAlgorithm alg, int partCount, + BlockSequence originalList, BlockSequence effectiveList); + + /** + * Phase 3 of Knuth algorithm: Adds the areas + * @param alg PageBreakingAlgorithm instance which determined the breaks + * @param partCount number of parts (pages) to be rendered + * @param originalList original Knuth element list + * @param effectiveList effective Knuth element list (after adjustments) + */ + protected void addAreas(PageBreakingAlgorithm alg, int partCount, + BlockSequence originalList, BlockSequence effectiveList) { + LayoutContext childLC; + // add areas + ListIterator effectiveListIterator = effectiveList.listIterator(); + int startElementIndex = 0; + int endElementIndex = 0; + for (int p = 0; p < partCount; p++) { + PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(p); + endElementIndex = pbp.getLeafPos(); + System.out.println("PLM> part: " + (p + 1) + + ", break at position " + endElementIndex); + + startPart(effectiveList, (p == 0)); + + int displayAlign = getCurrentDisplayAlign(); + + // ignore the first elements added by the + // PageSequenceLayoutManager + startElementIndex += (startElementIndex == 0) + ? effectiveList.ignoreAtStart + : 0; + + // ignore the last elements added by the + // PageSequenceLayoutManager + endElementIndex -= (endElementIndex == (originalList.size() - 1)) + ? effectiveList.ignoreAtEnd + : 0; + + // ignore the last element in the page if it is a KnuthGlue + // object + if (((KnuthElement) effectiveList.get(endElementIndex)) + .isGlue()) { + endElementIndex--; + } + + // ignore KnuthGlue and KnuthPenalty objects + // at the beginning of the line + effectiveListIterator = effectiveList + .listIterator(startElementIndex); + while (effectiveListIterator.hasNext() + && !((KnuthElement) effectiveListIterator.next()) + .isBox()) { + startElementIndex++; + } + + if (startElementIndex <= endElementIndex) { + System.out.println(" addAreas da " + startElementIndex + + " a " + endElementIndex); + childLC = new LayoutContext(0); + // add space before if display-align is center or bottom + // add space after if display-align is distribute and + // this is not the last page + if (pbp.difference != 0 && displayAlign == Constants.EN_CENTER) { + childLC.setSpaceBefore(pbp.difference / 2); + } else if (pbp.difference != 0 && displayAlign == Constants.EN_AFTER) { + childLC.setSpaceBefore(pbp.difference); + } else if (pbp.difference != 0 && displayAlign == Constants.EN_X_DISTRIBUTE + && p < (partCount - 1)) { + // count the boxes whose width is not 0 + int boxCount = 0; + effectiveListIterator = effectiveList + .listIterator(startElementIndex); + while (effectiveListIterator.nextIndex() <= endElementIndex) { + KnuthElement tempEl = (KnuthElement)effectiveListIterator.next(); + if (tempEl.isBox() && tempEl.getW() > 0) { + boxCount++; + } + } + // split the difference + if (boxCount >= 2) { + childLC.setSpaceAfter(pbp.difference / (boxCount - 1)); + } + } + + /* *** *** non-standard extension *** *** */ + if (displayAlign == Constants.EN_X_FILL) { + int averageLineLength = optimizeLineLength(effectiveList, startElementIndex, endElementIndex); + if (averageLineLength != 0) { + childLC.setStackLimit(new MinOptMax(averageLineLength)); + } + } + /* *** *** non-standard extension *** *** */ + + addAreas(new KnuthPossPosIter(effectiveList, + startElementIndex, endElementIndex + 1), childLC); + } + + finishPart(); + + startElementIndex = pbp.getLeafPos() + 1; + } + } + + /** + * Gets the next block list (sequence) and adds it to a list of block lists if it's not empty. + * @param childLC LayoutContext to use + * @param nextSequenceStartsOn indicates on what page the next sequence should start + * @param blockLists list of block lists (sequences) + * @return the page on which the next content should appear after a hard break + */ + private int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn, List blockLists) { + LinkedList returnedList; + BlockSequence blockList; + if ((returnedList = getNextKnuthElements(childLC, alignment)) != null) { + if (returnedList.size() == 0) { + return nextSequenceStartsOn; + } + blockList = new BlockSequence(nextSequenceStartsOn); + if (((KnuthElement) returnedList.getLast()).isPenalty() + && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) { + KnuthPenalty breakPenalty = (KnuthPenalty) returnedList + .removeLast(); + switch (breakPenalty.getBreakClass()) { + case Constants.EN_PAGE: + System.err.println("PLM> break - PAGE"); + nextSequenceStartsOn = Constants.EN_ANY; + break; + case Constants.EN_COLUMN: + System.err.println("PLM> break - COLUMN"); + //TODO Fix this when implementing multi-column layout + nextSequenceStartsOn = Constants.EN_COLUMN; + break; + case Constants.EN_ODD_PAGE: + System.err.println("PLM> break - ODD PAGE"); + nextSequenceStartsOn = Constants.EN_ODD_PAGE; + break; + case Constants.EN_EVEN_PAGE: + System.err.println("PLM> break - EVEN PAGE"); + nextSequenceStartsOn = Constants.EN_EVEN_PAGE; + break; + default: + throw new IllegalStateException("Invalid break class: " + + breakPenalty.getBreakClass()); + } + } + blockList.addAll(returnedList); + BlockSequence seq = null; + seq = blockList.endBlockSequence(); + if (seq != null) { + blockLists.add(seq); + } + } + return nextSequenceStartsOn; + } + + /** + * @param effectiveList effective block list to work on + * @param startElementIndex + * @param endElementIndex + * @return the average line length, 0 if there's no content + */ + private int optimizeLineLength(KnuthSequence effectiveList, int startElementIndex, int endElementIndex) { + ListIterator effectiveListIterator; + // optimize line length + //System.out.println(" "); + int boxCount = 0; + int accumulatedLineLength = 0; + int greatestMinimumLength = 0; + effectiveListIterator = effectiveList + .listIterator(startElementIndex); + while (effectiveListIterator.nextIndex() <= endElementIndex) { + KnuthElement tempEl = (KnuthElement) effectiveListIterator + .next(); + if (tempEl instanceof KnuthBlockBox) { + KnuthBlockBox blockBox = (KnuthBlockBox) tempEl; + if (blockBox.getBPD() > 0) { + log.debug("PSLM> nominal length of line = " + blockBox.getBPD()); + log.debug(" range = " + + blockBox.getIPDRange()); + boxCount++; + accumulatedLineLength += ((KnuthBlockBox) tempEl) + .getBPD(); + } + if (blockBox.getIPDRange().min > greatestMinimumLength) { + greatestMinimumLength = blockBox + .getIPDRange().min; + } + } + } + int averageLineLength = 0; + if (accumulatedLineLength > 0 && boxCount > 0) { + averageLineLength = (int) (accumulatedLineLength / boxCount); + //System.out.println("PSLM> lunghezza media = " + averageLineLength); + if (averageLineLength < greatestMinimumLength) { + averageLineLength = greatestMinimumLength; + //System.out.println(" correzione, ora e' = " + averageLineLength); + } + } + return averageLineLength; + } + + /** + * Justifies the boxes and returns them as a new KnuthSequence. + * @param blockList block list to justify + * @param alg reference to the algorithm instance + * @param availableBPD the available BPD + * @return the effective list + */ + private BlockSequence justifyBoxes(BlockSequence blockList, PageBreakingAlgorithm alg, int availableBPD) { + int iOptPageNumber; + iOptPageNumber = alg.findBreakingPoints(blockList, availableBPD, 1, + true, true); + System.out.println("PLM> iOptPageNumber= " + iOptPageNumber); + + // + ListIterator sequenceIterator = blockList.listIterator(); + ListIterator breakIterator = alg.getPageBreaks().listIterator(); + KnuthElement thisElement = null; + PageBreakPosition thisBreak; + int accumulatedS; // accumulated stretch or shrink + int adjustedDiff; // difference already adjusted + int firstElementIndex; + + while (breakIterator.hasNext()) { + thisBreak = (PageBreakPosition) breakIterator.next(); + System.out.println("| first page: break= " + + thisBreak.getLeafPos() + " difference= " + + thisBreak.difference + " ratio= " + + thisBreak.bpdAdjust); + accumulatedS = 0; + adjustedDiff = 0; + + // glue and penalty items at the beginning of the page must + // be ignored: + // the first element returned by sequenceIterator.next() + // inside the + // while loop must be a box + KnuthElement firstElement; + while (!(firstElement = (KnuthElement) sequenceIterator + .next()).isBox()) { + // + System.out.println("PLM> ignoring glue or penalty element " + + "at the beginning of the sequence"); + if (firstElement.isGlue()) { + ((BlockLevelLayoutManager) firstElement + .getLayoutManager()) + .discardSpace((KnuthGlue) firstElement); + } + } + firstElementIndex = sequenceIterator.previousIndex(); + sequenceIterator.previous(); + + // scan the sub-sequence representing a page, + // collecting information about potential adjustments + MinOptMax lineNumberMaxAdjustment = new MinOptMax(0); + MinOptMax spaceMaxAdjustment = new MinOptMax(0); + double spaceAdjustmentRatio = 0.0; + LinkedList blockSpacesList = new LinkedList(); + LinkedList unconfirmedList = new LinkedList(); + LinkedList adjustableLinesList = new LinkedList(); + boolean bBoxSeen = false; + while (sequenceIterator.hasNext() + && sequenceIterator.nextIndex() <= thisBreak + .getLeafPos()) { + thisElement = (KnuthElement) sequenceIterator.next(); + if (thisElement.isGlue()) { + // glue elements are used to represent adjustable + // lines + // and adjustable spaces between blocks + switch (((KnuthGlue) thisElement) + .getAdjustmentClass()) { + case BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT: + // fall through + case BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT: + // potential space adjustment + // glue items before the first box or after the + // last one + // must be ignored + unconfirmedList.add(thisElement); + break; + case BlockLevelLayoutManager.LINE_NUMBER_ADJUSTMENT: + // potential line number adjustment + lineNumberMaxAdjustment.max += ((KnuthGlue) thisElement) + .getY(); + lineNumberMaxAdjustment.min -= ((KnuthGlue) thisElement) + .getZ(); + adjustableLinesList.add(thisElement); + break; + case BlockLevelLayoutManager.LINE_HEIGHT_ADJUSTMENT: + // potential line height adjustment + break; + default: + // nothing + } + } else if (thisElement.isBox()) { + if (!bBoxSeen) { + // this is the first box met in this page + bBoxSeen = true; + } else if (unconfirmedList.size() > 0) { + // glue items in unconfirmedList were not after + // the last box + // in this page; they must be added to + // blockSpaceList + while (unconfirmedList.size() > 0) { + KnuthGlue blockSpace = (KnuthGlue) unconfirmedList + .removeFirst(); + spaceMaxAdjustment.max += ((KnuthGlue) blockSpace) + .getY(); + spaceMaxAdjustment.min -= ((KnuthGlue) blockSpace) + .getZ(); + blockSpacesList.add(blockSpace); + } + } + } + } + System.out.println("| line number adj= " + + lineNumberMaxAdjustment); + System.out.println("| space adj = " + + spaceMaxAdjustment); + + if (thisElement.isPenalty() && thisElement.getW() > 0) { + System.out + .println(" mandatory variation to the number of lines!"); + ((BlockLevelLayoutManager) thisElement + .getLayoutManager()).negotiateBPDAdjustment( + thisElement.getW(), thisElement); + } + + if (thisBreak.bpdAdjust != 0 + && (thisBreak.difference > 0 && thisBreak.difference <= spaceMaxAdjustment.max) + || (thisBreak.difference < 0 && thisBreak.difference >= spaceMaxAdjustment.min)) { + // modify only the spaces between blocks + spaceAdjustmentRatio = ((double) thisBreak.difference / (thisBreak.difference > 0 ? spaceMaxAdjustment.max + : spaceMaxAdjustment.min)); + adjustedDiff += adjustBlockSpaces( + blockSpacesList, + thisBreak.difference, + (thisBreak.difference > 0 ? spaceMaxAdjustment.max + : -spaceMaxAdjustment.min)); + System.out.println("single space: " + + (adjustedDiff == thisBreak.difference + || thisBreak.bpdAdjust == 0 ? "ok" + : "ERROR")); + } else if (thisBreak.bpdAdjust != 0) { + adjustedDiff += adjustLineNumbers( + adjustableLinesList, + thisBreak.difference, + (thisBreak.difference > 0 ? lineNumberMaxAdjustment.max + : -lineNumberMaxAdjustment.min)); + adjustedDiff += adjustBlockSpaces( + blockSpacesList, + thisBreak.difference - adjustedDiff, + ((thisBreak.difference - adjustedDiff) > 0 ? spaceMaxAdjustment.max + : -spaceMaxAdjustment.min)); + System.out.println("lines and space: " + + (adjustedDiff == thisBreak.difference + || thisBreak.bpdAdjust == 0 ? "ok" + : "ERROR")); + + } + } + + // create a new sequence: the new elements will contain the + // Positions + // which will be used in the addAreas() phase + BlockSequence effectiveList = new BlockSequence(blockList.getStartOn()); + effectiveList.addAll(getCurrentChildLM().getChangedKnuthElements( + blockList.subList(0, blockList.size() - blockList.ignoreAtEnd), + /* 0, */0)); + //effectiveList.add(new KnuthPenalty(0, -KnuthElement.INFINITE, + // false, new Position(this), false)); + effectiveList.endSequence(); + + logEffectiveList(effectiveList); + + alg.getPageBreaks().clear(); //Why this? + return effectiveList; + } + + /** + * Logs the contents of a block list for debugging purposes + * @param blockList block list to log + */ + private void logBlocklist(KnuthSequence blockList) { + ListIterator tempIter = blockList.listIterator(); + + KnuthElement temp; + System.out.println(" "); + while (tempIter.hasNext()) { + temp = (KnuthElement) tempIter.next(); + if (temp.isBox()) { + System.out.println(tempIter.previousIndex() + + ") " + temp); + } else if (temp.isGlue()) { + System.out.println(tempIter.previousIndex() + + ") " + temp); + } else { + System.out.println(tempIter.previousIndex() + + ") " + temp); + } + if (temp.getPosition() != null) { + System.out.println(" " + temp.getPosition()); + } + } + System.out.println(" "); + } + + /** + * Logs the contents of an effective block list for debugging purposes + * @param effectiveList block list to log + */ + private void logEffectiveList(KnuthSequence effectiveList) { + System.out.println("Effective list"); + logBlocklist(effectiveList); + } + + private int adjustBlockSpaces(LinkedList spaceList, int difference, int total) { + /*LF*/ System.out.println("AdjustBlockSpaces: difference " + difference + " / " + total + " on " + spaceList.size() + " spaces in block"); + ListIterator spaceListIterator = spaceList.listIterator(); + int adjustedDiff = 0; + int partial = 0; + while (spaceListIterator.hasNext()) { + KnuthGlue blockSpace = (KnuthGlue)spaceListIterator.next(); + partial += (difference > 0 ? blockSpace.getY() : blockSpace.getZ()); + System.out.println("available = " + partial + " / " + total); + System.out.println("competenza = " + (((int) ((float) partial * difference / total)) - adjustedDiff) + " / " + difference); + int newAdjust = ((BlockLevelLayoutManager) blockSpace.getLayoutManager()).negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, blockSpace); + adjustedDiff += newAdjust; + } + return adjustedDiff; + } + + private int adjustLineNumbers(LinkedList lineList, int difference, int total) { + /*LF*/ System.out.println("AdjustLineNumbers: difference " + difference + " / " + total + " on " + lineList.size() + " elements"); + +// int adjustedDiff = 0; +// int partial = 0; +// KnuthGlue prevLine = null; +// KnuthGlue currLine = null; +// ListIterator lineListIterator = lineList.listIterator(); +// while (lineListIterator.hasNext()) { +// currLine = (KnuthGlue)lineListIterator.next(); +// if (prevLine != null +// && prevLine.getLayoutManager() != currLine.getLayoutManager()) { +// int newAdjust = ((BlockLevelLayoutManager) prevLine.getLayoutManager()) +// .negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, prevLine); +// adjustedDiff += newAdjust; +// } +// partial += (difference > 0 ? currLine.getY() : currLine.getZ()); +// prevLine = currLine; +// } +// if (currLine != null) { +// int newAdjust = ((BlockLevelLayoutManager) currLine.getLayoutManager()) +// .negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, currLine); +// adjustedDiff += newAdjust; +// } +// return adjustedDiff; + + ListIterator lineListIterator = lineList.listIterator(); + int adjustedDiff = 0; + int partial = 0; + while (lineListIterator.hasNext()) { + KnuthGlue line = (KnuthGlue)lineListIterator.next(); + partial += (difference > 0 ? line.getY() : line.getZ()); + int newAdjust = ((BlockLevelLayoutManager) line.getLayoutManager()).negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, line); + adjustedDiff += newAdjust; + } + return adjustedDiff; + } + + +} |