int PR_INTRUSION_DISPLACE = 247;
int PR_INDEX_CLASS = 248; // XSL 1.1
int PR_INDEX_KEY = 249; // XSL 1.1
- int PROPERTY_COUNT = 249;
+ int PR_X_BLOCK_PROGRESSION_UNIT = 250; //Custom extension
+ int PROPERTY_COUNT = 250;
// compound property constants
int EN_VISIBLE = 159;
int EN_WIDER = 160;
int EN_WRAP = 161;
- int ENUM_COUNT = 161;
+ int EN_X_FILL = 162; //non-standard for display-align
+ int EN_X_DISTRIBUTE = 163; //non-standard for display-align
+ int ENUM_COUNT = 163;
}
m.addEnum("after", getEnumProperty(EN_AFTER, "AFTER"));
m.addEnum("center", getEnumProperty(EN_CENTER, "CENTER"));
m.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
+/*LF*/ m.addEnum("distribute", getEnumProperty(EN_X_DISTRIBUTE, "DISTRIBUTE"));
+/*LF*/ m.addEnum("fill", getEnumProperty(EN_X_FILL, "FILL"));
m.setDefault("auto");
addPropertyMaker("display-align", m);
l.setPercentBase(LengthBase.BLOCK_WIDTH);
l.setDefault("auto");
addPropertyMaker("width", l);
+
+/*LF*/ // block-progression-unit (**CUSTOM EXTENSION**)
+/*LF*/ l = new LengthProperty.Maker(PR_X_BLOCK_PROGRESSION_UNIT);
+/*LF*/ l.setInherited(false);
+/*LF*/ l.setDefault("0pt");
+/*LF*/ addPropertyMaker("block-progression-unit", l);
}
private void createBlockAndLineProperties() {
elem.addProperties(CommonBorderPaddingBackgroundProperties);
elem.addProperties(CommonMarginPropertiesBlock);
elem.addProperty(Constants.PR_BLOCK_PROGRESSION_DIMENSION);
+ elem.addProperty(Constants.PR_X_BLOCK_PROGRESSION_UNIT);
elem.addProperty(Constants.PR_PAGE_BREAK_AFTER);
elem.addProperty(Constants.PR_PAGE_BREAK_BEFORE);
elem.addProperty(Constants.PR_BREAK_AFTER);
--- /dev/null
+/*
+ * 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;
+ }
+ }
+
+ private class BlockSequence extends KnuthSequence {
+ static final int ANY_PAGE = 0;
+ static final int ODD_PAGE = 1;
+ static final int EVEN_PAGE = 2;
+
+ private int startOn;
+
+ public BlockSequence(int iStartOn) {
+ super();
+ startOn = iStartOn;
+ }
+
+ 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 LayoutContext createLayoutContext() {
+ return new LayoutContext(0);
+ }
+
+ public void doLayout(int flowBPD) {
+ LayoutContext childLC = createLayoutContext();
+
+ //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 = BlockSequence.ANY_PAGE;
+ 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 == BlockSequence.ANY_PAGE) ? "any page"
+ : (blockList.startOn == BlockSequence.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;
+
+ KnuthSequence effectiveList;
+ if (alignment == Constants.EN_JUSTIFY) {
+ /* ALLINEAMENTO GIUSTIFICATO */
+ effectiveList = justifyBoxes(blockList, alg, flowBPD);
+ } else {
+ /* ALLINEAMENTO NON GIUSTIFICATO */
+ 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,
+ KnuthSequence originalList, KnuthSequence 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,
+ KnuthSequence originalList, KnuthSequence effectiveList) {
+ LayoutContext childLC;
+ // add areas
+ ListIterator effectiveListIterator = effectiveList.listIterator();
+ int startElementIndex = 0;
+ int endElementIndex = 0;
+ for (int p = 0; p < partCount; p++) {
+ int displayAlign = getCurrentDisplayAlign();
+
+ PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(p);
+ endElementIndex = pbp.getLeafPos();
+ System.out.println("PLM> pagina: " + (p + 1)
+ + ", break alla posizione " + endElementIndex);
+
+ // 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;
+ }
+ }
+ protected abstract void finishPart();
+
+ protected abstract LinkedList getNextKnuthElements(LayoutContext context, int alignment);
+
+ /**
+ * 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) {
+ 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 = BlockSequence.ANY_PAGE;
+ break;
+ case Constants.EN_ODD_PAGE:
+ System.err.println("PLM> break - ODD PAGE");
+ nextSequenceStartsOn = BlockSequence.ODD_PAGE;
+ break;
+ case Constants.EN_EVEN_PAGE:
+ System.err.println("PLM> break - EVEN PAGE");
+ nextSequenceStartsOn = BlockSequence.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> lunghezza grezza della riga = "
+ + 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 KnuthSequence 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(" variazione obbligatoria al numero di righe!");
+ ((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("solo spazi: "
+ + (adjustedDiff == thisBreak.difference
+ || thisBreak.bpdAdjust == 0 ? "ok"
+ : "ERRORE"));
+ } 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("linee e spazi: "
+ + (adjustedDiff == thisBreak.difference
+ || thisBreak.bpdAdjust == 0 ? "ok"
+ : "ERRORE"));
+
+ }
+ }
+
+ // create a new sequence: the new elements will contain the
+ // Positions
+ // which will be used in the addAreas() phase
+ KnuthSequence effectiveList = new KnuthSequence();
+ 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(BlockSequence blockList) {
+ ListIterator tempIter = blockList.listIterator();
+
+ KnuthElement temp;
+ System.out.println(" ");
+ while (tempIter.hasNext()) {
+ temp = (KnuthElement) tempIter.next();
+ String segno = temp.isAuxiliary() ? "+ " : "- ";
+ if (temp.isBox()) {
+ System.out.println(segno + tempIter.previousIndex()
+ + ") <box> " + temp.getW());
+ } else if (temp.isGlue()) {
+ System.out.println(segno + tempIter.previousIndex()
+ + ") <glue> " + temp.getW() + " + "
+ + ((KnuthGlue) temp).getY() + " - "
+ + ((KnuthGlue) temp).getZ());
+ } else {
+ System.out
+ .println(segno
+ + tempIter.previousIndex()
+ + ") <"
+ + (((KnuthPenalty) temp).getP() == KnuthElement.INFINITE ? "PENALTY"
+ : "penalty") + "> " + temp.getW());
+ }
+ }
+ System.out.println(" ");
+ }
+
+ /**
+ * Logs the contents of an effective block list for debugging purposes
+ * @param effectiveList block list to log
+ * @todo combine with logBlocklist()
+ */
+ private void logEffectiveList(KnuthSequence effectiveList) {
+ ListIterator tempIter;
+ KnuthElement temp;
+ System.out.println("Lista effettiva");
+ System.out.println(" ");
+ tempIter = effectiveList.listIterator();
+ System.out.println(" ");
+ while (tempIter.hasNext()) {
+ temp = (KnuthElement) tempIter.next();
+ String segno = temp.isAuxiliary() ? "+ " : "- ";
+ if (temp.isBox()) {
+ System.out.println(segno + tempIter.previousIndex()
+ + ") <box> - - " + ((KnuthBox) temp).getW());
+ } else if (temp.isGlue()) {
+ System.out
+ .println(segno
+ + tempIter.previousIndex()
+ + ") <glue> "
+ + (((KnuthGlue) temp).getW() - ((KnuthGlue) temp)
+ .getZ())
+ + " - "
+ + ((KnuthGlue) temp).getW()
+ + " - "
+ + (((KnuthGlue) temp).getW() + ((KnuthGlue) temp)
+ .getY()));
+ } else {
+ System.out
+ .println(segno
+ + tempIter.previousIndex()
+ + ") <"
+ + (((KnuthPenalty) temp).getP() == KnuthElement.INFINITE ? "PENALTY"
+ : "penalty") + "> ");
+ }
+ }
+ System.out.println(" ");
+ }
+
+ private int adjustBlockSpaces(LinkedList spaceList, int difference, int total) {
+ /*LF*/ System.out.println("AdjustBlockSpaces: ripartire " + difference + " / " + total + " su " + spaceList.size() + " spazi fra blocchi");
+ 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("disponibile = " + 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: ripartire " + difference + " / " + total + " su " + lineList.size() + " elementi");
+
+// 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;
+ }
+
+
+}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;
* interface which are declared abstract in AbstractLayoutManager.
* ---------------------------------------------------------*/
+ public LinkedList getNextKnuthElements(LayoutContext context,
+ int alignment) {
+ log.warn("null implementation of getNextKnuthElements() called!");
+ setFinished(true);
+ return null;
+ }
+
+ public KnuthElement addALetterSpaceTo(KnuthElement element) {
+ log.warn("null implementation of addALetterSpaceTo() called!");
+ return element;
+ }
+
+ public void getWordChars(StringBuffer sbChars, Position pos) {
+ log.warn("null implementation of getWordChars() called!");
+ }
+
+ public void hyphenate(Position pos, HyphContext hc) {
+ log.warn("null implementation of hyphenate called!");
+ }
+
+ public boolean applyChanges(List oldList) {
+ log.warn("null implementation of applyChanges() called!");
+ return false;
+ }
+
+ public LinkedList getChangedKnuthElements(List oldList,
+ /*int flaggedPenalty,*/
+ int alignment) {
+ log.warn("null implementation of getChangeKnuthElement() called!");
+ return null;
+ }
+
+ public int getWordSpaceIPD() {
+ log.warn("null implementation of getWordSpaceIPD() called!");
+ return 0;
+ }
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(org.apache.fop.area.Area)
*/
--- /dev/null
+/*
+ * Copyright 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.Iterator;
+import java.util.LinkedList;
+
+public class AreaAdditionUtil {
+
+ private static class StackingIter extends PositionIterator {
+ StackingIter(Iterator parentIter) {
+ super(parentIter);
+ }
+
+ protected LayoutManager getLM(Object nextObj) {
+ return ((Position) nextObj).getLM();
+ }
+
+ protected Position getPos(Object nextObj) {
+ return ((Position) nextObj);
+ }
+ }
+
+ public static void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
+ LayoutManager childLM = null;
+ LayoutContext lc = new LayoutContext(0);
+ LayoutManager firstLM = null;
+ LayoutManager lastLM = null;
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ LinkedList positionList = new LinkedList();
+ Position pos;
+ while (parentIter.hasNext()) {
+ pos = (Position)parentIter.next();
+ if (pos instanceof NonLeafPosition) {
+ // pos was created by a child of this FlowLM
+ positionList.add(((NonLeafPosition) pos).getPosition());
+ lastLM = ((NonLeafPosition) pos).getPosition().getLM();
+ if (firstLM == null) {
+ firstLM = lastLM;
+ }
+ } else {
+ // pos was created by this LM, so it must be ignored
+ }
+ }
+
+ StackingIter childPosIter = new StackingIter(positionList.listIterator());
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // Add the block areas to Area
+ lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
+ lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
+ // set space before for the first LM, in order to implement
+ // display-align = center or after
+ lc.setSpaceBefore((childLM == firstLM ? layoutContext.getSpaceBefore() : 0));
+ // set space after for each LM, in order to implement
+ // display-align = distribute
+ lc.setSpaceAfter(layoutContext.getSpaceAfter());
+ lc.setStackLimit(layoutContext.getStackLimit());
+ childLM.addAreas(childPosIter, lc);
+ }
+ }
+
+}
package org.apache.fop.layoutmgr;
+import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.awt.Point;
import java.awt.geom.Rectangle2D;
import org.apache.fop.area.Block;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.Trait;
+import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
import org.apache.fop.area.CTM;
/**
* LayoutManager for a block-container FO.
*/
-public class BlockContainerLayoutManager extends BlockStackingLayoutManager {
+public class BlockContainerLayoutManager extends BlockStackingLayoutManager
+ implements BlockLevelLayoutManager {
private BlockContainer fobj;
private BlockViewport viewportBlockArea;
private int vpContentIPD;
private int vpContentBPD;
private int usedBPD;
-
+
// When viewport should grow with the content.
private boolean autoHeight = true;
//TODO space-before|after: handle space-resolution rules
private MinOptMax foBlockSpaceBefore;
private MinOptMax foBlockSpaceAfter;
+
+ private boolean bBreakBeforeServed = false;
+ private boolean bSpaceBeforeServed = false;
+
+ /*LF*/
+ /** Only used to store the original list when createUnitElements is called */
+ //TODO Maybe pull up as protected member if also used in this class (JM)
+ private LinkedList storedList = null;
+
/**
* Create a new block container layout manager.
height = fobj.getBlockProgressionDimension().getOptimum().getLength();
width = fobj.getInlineProgressionDimension().getOptimum().getLength();
}
+
+/*LF*/ bpUnit = 0; //layoutProps.blockProgressionUnit;
+/*LF*/ if (bpUnit == 0) {
+/*LF*/ // use optimum space values
+/*LF*/ adjustedSpaceBefore = fobj.getCommonMarginBlock().spaceBefore.getSpace().getOptimum().getLength().getValue();
+/*LF*/ adjustedSpaceAfter = fobj.getCommonMarginBlock().spaceAfter.getSpace().getOptimum().getLength().getValue();
+/*LF*/ } else {
+/*LF*/ // use minimum space values
+/*LF*/ adjustedSpaceBefore = fobj.getCommonMarginBlock().spaceBefore.getSpace().getMinimum().getLength().getValue();
+/*LF*/ adjustedSpaceAfter = fobj.getCommonMarginBlock().spaceAfter.getSpace().getMinimum().getLength().getValue();
+/*LF*/ }
}
/** @return the content IPD */
return (abProps.absolutePosition == EN_FIXED);
}
+ /**
+ * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
+ */
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+ if (isAbsoluteOrFixed()) {
+ return getNextKnuthElementsAbsolute(context, alignment);
+ }
+
+ autoHeight = false;
+ boolean rotated = (fobj.getReferenceOrientation() % 180 != 0); //vals[0] == 0.0;
+ referenceIPD = context.getRefIPD();
+ int maxbpd = context.getStackLimit().opt;
+ int allocBPD, allocIPD;
+ if (height.getEnum() != EN_AUTO) {
+ allocBPD = height.getValue(); //this is the content-height
+ allocBPD += getBPIndents();
+ } else {
+ allocBPD = maxbpd;
+ autoHeight = true;
+ }
+ if (width.getEnum() != EN_AUTO) {
+ allocIPD = width.getValue(); //this is the content-width
+ allocIPD += getIPIndents();
+ } else {
+ allocIPD = referenceIPD;
+ }
+
+ vpContentBPD = allocBPD - getBPIndents();
+ vpContentIPD = allocIPD - getIPIndents();
+
+ double contentRectOffsetX = 0;
+ contentRectOffsetX += fobj.getCommonMarginBlock().startIndent.getValue();
+ double contentRectOffsetY = 0;
+ //contentRectOffsetY += fobj.getCommonMarginBlock().startIndent.getValue();
+ //contentRectOffsetY += getSpaceBefore();
+ contentRectOffsetY += fobj.getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
+ contentRectOffsetY += fobj.getCommonBorderPaddingBackground().getPaddingBefore(false);
+
+ Rectangle2D rect = new Rectangle2D.Double(
+ contentRectOffsetX, contentRectOffsetY,
+ vpContentIPD, vpContentBPD);
+ relDims = new FODimension(0, 0);
+ absoluteCTM = CTM.getCTMandRelDims(fobj.getReferenceOrientation(),
+ fobj.getWritingMode(), rect, relDims);
+
+ MinOptMax stackLimit = new MinOptMax(relDims.bpd);
+
+ LinkedList returnedList = null;
+ LinkedList contentList = new LinkedList();
+ LinkedList returnList = new LinkedList();
+ Position returnPosition = new NonLeafPosition(this, null);
+
+ if (!bBreakBeforeServed) {
+ try {
+ if (addKnuthElementsForBreakBefore(returnList, returnPosition,
+ fobj.getBreakBefore())) {
+ return returnList;
+ }
+ } finally {
+ bBreakBeforeServed = true;
+ }
+ }
+
+ if (!bSpaceBeforeServed) {
+ addKnuthElementsForSpaceBefore(returnList, returnPosition, alignment,
+ fobj.getCommonMarginBlock().spaceBefore);
+ bSpaceBeforeServed = true;
+ }
+
+ addKnuthElementForBorderPaddingBefore(returnList, returnPosition,
+ fobj.getCommonBorderPaddingBackground());
+
+ if (autoHeight) {
+ BlockLevelLayoutManager curLM; // currently active LM
+ BlockLevelLayoutManager prevLM = null; // previously active LM
+ while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
+ LayoutContext childLC = new LayoutContext(0);
+ // curLM is a ?
+ childLC.setStackLimit(MinOptMax.subtract(context
+ .getStackLimit(), stackLimit));
+ childLC.setRefIPD(relDims.ipd);
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ if (returnedList.size() == 1
+ && ((KnuthElement) returnedList.getFirst()).isPenalty()
+ && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this block has break-before
+ if (returnList.size() == 0) {
+ // the first child (or its first child ...) has
+ // break-before;
+ // all this block, including space before, will be put in
+ // the
+ // following page
+ bSpaceBeforeServed = false;
+ }
+ contentList.addAll(returnedList);
+
+ // "wrap" the Position inside each element
+ // moving the elements from contentList to returnList
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ } else {
+ if (prevLM != null) {
+ // there is a block handled by prevLM
+ // before the one handled by curLM
+ if (mustKeepTogether()
+ || prevLM.mustKeepWithNext()
+ || curLM.mustKeepWithPrevious()) {
+ // add an infinite penalty to forbid a break between
+ // blocks
+ contentList.add(new KnuthPenalty(0,
+ KnuthElement.INFINITE, false,
+ new Position(this), false));
+ } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+ // add a null penalty to allow a break between blocks
+ contentList.add(new KnuthPenalty(0, 0, false,
+ new Position(this), false));
+ } else {
+ // the last element in contentList is a glue;
+ // it is a feasible breakpoint, there is no need to add
+ // a penalty
+ }
+ }
+ contentList.addAll(returnedList);
+ if (returnedList.size() == 0) {
+ //Avoid NoSuchElementException below (happens with empty blocks)
+ continue;
+ }
+ if (((KnuthElement) returnedList.getLast()).isPenalty()
+ && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this block has break-after
+ if (curLM.isFinished()) {
+ // there is no other content in this block;
+ // it's useless to add space after before a page break
+ setFinished(true);
+ }
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ }
+ }
+ prevLM = curLM;
+ }
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ } else {
+ MinOptMax range = new MinOptMax(relDims.ipd);
+ BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
+ breaker.doLayout(relDims.bpd);
+ boolean contentOverflows = (breaker.deferredAlg.getPageBreaks().size() > 1);
+
+ Position bcPosition = new BlockContainerPosition(this, breaker);
+ returnList.add(new KnuthBox(vpContentBPD, bcPosition, false));
+ //TODO Handle min/opt/max for block-progression-dimension
+ /* These two elements will be used to add stretchability to the above box
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, returnPosition, false));
+ returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ */
+
+ if (contentOverflows) {
+ log.warn("Contents overflow block-container viewport: clipping");
+ if (fobj.getOverflow() == EN_HIDDEN) {
+ clip = true;
+ } else if (fobj.getOverflow() == EN_ERROR_IF_OVERFLOW) {
+ //TODO Throw layout exception
+ clip = true;
+ }
+ }
+ }
+ addKnuthElementsForBorderPaddingAfter(returnList, returnPosition,
+ fobj.getCommonBorderPaddingBackground());
+ addKnuthElementsForSpaceAfter(returnList, returnPosition, alignment,
+ fobj.getCommonMarginBlock().spaceAfter);
+ addKnuthElementsForBreakAfter(returnList, returnPosition, fobj.getBreakAfter());
+
+ setFinished(true);
+ return returnList;
+ }
+
+ private LinkedList getNextKnuthElementsAbsolute(LayoutContext context, int alignment) {
+ MinOptMax stackSize = new MinOptMax();
+ autoHeight = false;
+
+ Point offset = getAbsOffset();
+ int allocBPD, allocIPD;
+ if (height.getEnum() != EN_AUTO) {
+ allocBPD = height.getValue(); //this is the content-height
+ allocBPD += getBPIndents();
+ } else {
+ allocBPD = 0;
+ if (abProps.bottom.getEnum() != EN_AUTO) {
+ if (isFixed()) {
+ allocBPD = (int)getPageViewport().getViewArea().getHeight();
+ } else {
+ allocBPD = context.getStackLimit().opt;
+ }
+ allocBPD -= offset.y;
+ if (abProps.bottom.getEnum() != EN_AUTO) {
+ allocBPD -= abProps.bottom.getValue();
+ }
+ } else {
+ autoHeight = true;
+ }
+ }
+ if (width.getEnum() != EN_AUTO) {
+ allocIPD = width.getValue(); //this is the content-width
+ allocIPD += getIPIndents();
+ } else {
+ if (isFixed()) {
+ allocIPD = (int)getPageViewport().getViewArea().getWidth();
+ } else {
+ allocIPD = context.getRefIPD();
+ }
+ if (abProps.left.getEnum() != EN_AUTO) {
+ allocIPD -= abProps.left.getValue();
+ }
+ if (abProps.right.getEnum() != EN_AUTO) {
+ allocIPD -= abProps.right.getValue();
+ }
+ }
+
+ vpContentBPD = allocBPD - getBPIndents();
+ vpContentIPD = allocIPD - getIPIndents();
+
+ double contentRectOffsetX = offset.getX();
+ contentRectOffsetX += fobj.getCommonMarginBlock().startIndent.getValue();
+ double contentRectOffsetY = offset.getY();
+ contentRectOffsetY += getSpaceBefore();
+ contentRectOffsetY += fobj.getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
+ contentRectOffsetY += fobj.getCommonBorderPaddingBackground().getPaddingBefore(false);
+
+ Rectangle2D rect = new Rectangle2D.Double(
+ contentRectOffsetX, contentRectOffsetY,
+ vpContentIPD, vpContentBPD);
+ relDims = new FODimension(0, 0);
+ absoluteCTM = CTM.getCTMandRelDims(
+ fobj.getReferenceOrientation(),
+ fobj.getWritingMode(),
+ rect, relDims);
+
+ MinOptMax range = new MinOptMax(relDims.ipd);
+ BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
+ breaker.doLayout(relDims.bpd);
+ boolean contentOverflows = (breaker.deferredAlg.getPageBreaks().size() > 1);
+ usedBPD = relDims.bpd - breaker.getDifferenceOfFirstPart();
+
+ Position bcPosition = new BlockContainerPosition(this, breaker);
+ LinkedList returnList = new LinkedList();
+ returnList.add(new KnuthBox(0, bcPosition, false));
+
+ //TODO Maybe check for page overflow when autoHeight=true
+ if (!autoHeight & (contentOverflows/*usedBPD > relDims.bpd*/)) {
+ log.warn("Contents overflow block-container viewport: clipping");
+ if (fobj.getOverflow() == EN_HIDDEN) {
+ clip = true;
+ } else if (fobj.getOverflow() == EN_ERROR_IF_OVERFLOW) {
+ //TODO Throw layout exception
+ clip = true;
+ }
+ }
+
+ setFinished(true);
+ return returnList;
+ }
+
+ private class BlockContainerPosition extends NonLeafPosition {
+
+ private BlockContainerBreaker breaker;
+
+ public BlockContainerPosition(LayoutManager lm, BlockContainerBreaker breaker) {
+ super(lm, null);
+ this.breaker = breaker;
+ }
+
+ public BlockContainerBreaker getBreaker() {
+ return this.breaker;
+ }
+
+ }
+
+ private class BlockContainerBreaker extends AbstractBreaker {
+
+ private BlockContainerLayoutManager bclm;
+ private MinOptMax ipd;
+
+ //Info for deferred adding of areas
+ private PageBreakingAlgorithm deferredAlg;
+ private KnuthSequence deferredOriginalList;
+ private KnuthSequence deferredEffectiveList;
+
+ public BlockContainerBreaker(BlockContainerLayoutManager bclm, MinOptMax ipd) {
+ this.bclm = bclm;
+ this.ipd = ipd;
+ }
+
+ public int getDifferenceOfFirstPart() {
+ PageBreakPosition pbp = (PageBreakPosition)this.deferredAlg.getPageBreaks().getFirst();
+ return pbp.difference;
+ }
+
+ protected LayoutManager getTopLevelLM() {
+ return bclm;
+ }
+
+ protected LayoutContext createLayoutContext() {
+ LayoutContext lc = super.createLayoutContext();
+ lc.setRefIPD(ipd.opt);
+ return lc;
+ }
+
+ protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+ LayoutManager curLM; // currently active LM
+ LinkedList returnList = new LinkedList();
+
+ while ((curLM = getChildLM()) != null) {
+ LayoutContext childLC = new LayoutContext(0);
+ childLC.setStackLimit(context.getStackLimit());
+ childLC.setRefIPD(context.getRefIPD());
+
+ LinkedList returnedList = null;
+ if (!curLM.isFinished()) {
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ }
+ if (returnedList != null) {
+ bclm.wrapPositionElements(returnedList, returnList);
+ //returnList.addAll(returnedList);
+ }
+ }
+ setFinished(true);
+ return returnList;
+ }
+
+ protected int getCurrentDisplayAlign() {
+ return fobj.getDisplayAlign();
+ }
+
+ protected boolean hasMoreContent() {
+ return !isFinished();
+ }
+
+ protected void addAreas(PositionIterator posIter, LayoutContext context) {
+ AreaAdditionUtil.addAreas(posIter, context);
+ }
+
+ protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
+ KnuthSequence originalList, KnuthSequence effectiveList) {
+ //Defer adding of areas until addAreas is called by the parent LM
+ this.deferredAlg = alg;
+ this.deferredOriginalList = originalList;
+ this.deferredEffectiveList = effectiveList;
+ }
+
+ protected void finishPart() {
+ //nop for bclm
+ }
+
+ protected LayoutManager getCurrentChildLM() {
+ return curChildLM;
+ }
+
+ public void addContainedAreas() {
+ //Rendering all parts (not just the first) at once for the case where the parts that
+ //overflow should be visible.
+ //TODO Check if this has any unwanted side-effects. Feels a bit like a hack.
+ addAreas(this.deferredAlg,
+ /*1*/ this.deferredAlg.getPageBreaks().size(),
+ this.deferredOriginalList, this.deferredEffectiveList);
+ }
+
+ }
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getNextBreakPoss(org.apache.fop.layoutmgr.LayoutContext)
*/
* @see org.apache.fop.layoutmgr.LayoutManager#addAreas(org.apache.fop.layoutmgr.PositionIterator, org.apache.fop.layoutmgr.LayoutContext)
*/
public void addAreas(PositionIterator parentIter,
+ LayoutContext layoutContext) {
+ getParentArea(null);
+
+ // if this will create the first block area in a page
+ // and display-align is bottom or center, add space before
+ if (layoutContext.getSpaceBefore() > 0) {
+ addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+ }
+
+ addID(fobj.getId());
+ //addMarkers(true, bp1.isFirstArea(), bp1.isLastArea());
+ addMarkers(true, true, false);
+
+ LayoutManager childLM = null;
+ LayoutManager lastLM = null;
+ LayoutContext lc = new LayoutContext(0);
+ // set space after in the LayoutContext for children
+ if (layoutContext.getSpaceAfter() > 0) {
+ lc.setSpaceAfter(layoutContext.getSpaceAfter());
+ }
+ BlockContainerPosition bcpos = null;
+ PositionIterator childPosIter;
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ LinkedList positionList = new LinkedList();
+ Position pos;
+ boolean bSpaceBefore = false;
+ boolean bSpaceAfter = false;
+ while (parentIter.hasNext()) {
+ pos = (Position) parentIter.next();
+ /* LF *///System.out.println("pos = " + pos.getClass().getName());
+ Position innerPosition = ((NonLeafPosition) pos).getPosition();
+ if (pos instanceof BlockContainerPosition) {
+ if (bcpos != null) {
+ throw new IllegalStateException("Only one BlockContainerPosition allowed");
+ }
+ bcpos = (BlockContainerPosition)pos;
+ //Add child areas inside the reference area
+ //bcpos.getBreaker().addContainedAreas();
+ } else if (innerPosition == null) {
+ // pos was created by this BCLM and was inside an element
+ // representing space before or after
+ // this means the space was not discarded
+ if (positionList.size() == 0) {
+ // pos was in the element representing space-before
+ bSpaceBefore = true;
+ /* LF *///System.out.println(" space-before");
+ } else {
+ // pos was in the element representing space-after
+ bSpaceAfter = true;
+ /* LF *///System.out.println(" space-after");
+ }
+ } else if (innerPosition.getLM() == this
+ && !(innerPosition instanceof MappingPosition)) {
+ // pos was created by this BlockLM and was inside a penalty
+ // allowing or forbidding a page break
+ // nothing to do
+ /* LF *///System.out.println(" penalty");
+ } else {
+ // innerPosition was created by another LM
+ positionList.add(innerPosition);
+ lastLM = innerPosition.getLM();
+ /* LF *///System.out.println(" " +
+ // innerPosition.getClass().getName());
+ }
+ }
+
+ if (bcpos == null) {
+
+ if (bpUnit == 0) {
+ // the Positions in positionList were inside the elements
+ // created by the LineLM
+ childPosIter = new StackingIter(positionList.listIterator());
+ } else {
+ // the Positions in positionList were inside the elements
+ // created by the BCLM in the createUnitElements() method
+ //if (((Position) positionList.getLast()) instanceof
+ // LeafPosition) {
+ // // the last item inside positionList is a LeafPosition
+ // // (a LineBreakPosition, more precisely); this means that
+ // // the whole paragraph is on the same page
+ // System.out.println("paragrafo intero");
+ // childPosIter = new KnuthPossPosIter(storedList, 0,
+ // storedList.size());
+ //} else {
+ // // the last item inside positionList is a Position;
+ // // this means that the paragraph has been split
+ // // between consecutive pages
+ LinkedList splitList = new LinkedList();
+ int splitLength = 0;
+ int iFirst = ((MappingPosition) positionList.getFirst()).getFirstIndex();
+ int iLast = ((MappingPosition) positionList.getLast()).getLastIndex();
+ // copy from storedList to splitList all the elements from
+ // iFirst to iLast
+ ListIterator storedListIterator = storedList.listIterator(iFirst);
+ while (storedListIterator.nextIndex() <= iLast) {
+ KnuthElement element = (KnuthElement) storedListIterator
+ .next();
+ // some elements in storedList (i.e. penalty items) were created
+ // by this BlockLM, and must be ignored
+ if (element.getLayoutManager() != this) {
+ splitList.add(element);
+ splitLength += element.getW();
+ lastLM = element.getLayoutManager();
+ }
+ }
+ //System.out.println("addAreas riferito a storedList da " +
+ // iFirst + " a " + iLast);
+ //System.out.println("splitLength= " + splitLength
+ // + " (" + neededUnits(splitLength) + " unita') "
+ // + (neededUnits(splitLength) * bpUnit - splitLength) + " spazi");
+ // add space before and / or after the paragraph
+ // to reach a multiple of bpUnit
+ if (bSpaceBefore && bSpaceAfter) {
+ foBlockSpaceBefore = new SpaceVal(fobj.getCommonMarginBlock().spaceBefore).getSpace();
+ foBlockSpaceAfter = new SpaceVal(fobj.getCommonMarginBlock().spaceAfter).getSpace();
+ adjustedSpaceBefore = (neededUnits(splitLength
+ + foBlockSpaceBefore.min
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength) / 2;
+ adjustedSpaceAfter = neededUnits(splitLength
+ + foBlockSpaceBefore.min
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength - adjustedSpaceBefore;
+ } else if (bSpaceBefore) {
+ adjustedSpaceBefore = neededUnits(splitLength
+ + foBlockSpaceBefore.min)
+ * bpUnit - splitLength;
+ } else {
+ adjustedSpaceAfter = neededUnits(splitLength
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength;
+ }
+ //System.out.println("spazio prima = " + adjustedSpaceBefore
+ // + " spazio dopo = " + adjustedSpaceAfter + " totale = " +
+ // (adjustedSpaceBefore + adjustedSpaceAfter + splitLength));
+ childPosIter = new KnuthPossPosIter(splitList, 0, splitList
+ .size());
+ //}
+ }
+
+ // if adjusted space before
+ if (bSpaceBefore) {
+ addBlockSpacing(0, new MinOptMax(adjustedSpaceBefore));
+ }
+
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // set last area flag
+ lc.setFlags(LayoutContext.LAST_AREA,
+ (layoutContext.isLastArea() && childLM == lastLM));
+ /*LF*/lc.setStackLimit(layoutContext.getStackLimit());
+ // Add the line areas to Area
+ childLM.addAreas(childPosIter, lc);
+ }
+ } else {
+ // if adjusted space before
+ if (bSpaceBefore) {
+ addBlockSpacing(0, new MinOptMax(adjustedSpaceBefore));
+ }
+ //Add child areas inside the reference area
+ bcpos.getBreaker().addContainedAreas();
+ }
+
+ int bIndents = fobj.getCommonBorderPaddingBackground().getBPPaddingAndBorder(false);
+
+ addMarkers(false, false, true);
+
+ flush();
+
+ // if adjusted space after
+ if (bSpaceAfter) {
+ addBlockSpacing(0, new MinOptMax(adjustedSpaceAfter));
+ }
+
+ viewportBlockArea = null;
+ referenceArea = null;
+ }
+
+ public void addAreasOLDOLDOLD(PositionIterator parentIter,
LayoutContext layoutContext) {
getParentArea(null);
//Handle display-align now that the used BPD can be determined
usedBPD = referenceArea.getAllocBPD();
+ /* done by the breaker now by inserting additional boxes
if (!autoHeight & (usedBPD > 0)) {
if (fobj.getDisplayAlign() == EN_CENTER) {
viewportBlockArea.setCTM(viewportBlockArea.getCTM().multiply(
viewportBlockArea.setCTM(viewportBlockArea.getCTM().multiply(
new CTM().translate(0, (relDims.bpd - usedBPD))));
}
- }
+ }*/
// Fake a 0 height for absolute positioned blocks.
int saveBPD = viewportBlockArea.getBPD();
viewportBlockArea.setBPD(saveBPD);
}
}
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
+ */
+ public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(org.apache.fop.layoutmgr.KnuthGlue)
+ */
+ public void discardSpace(KnuthGlue spaceGlue) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+ */
+ public boolean mustKeepTogether() {
+ return !fobj.getKeepTogether().getWithinPage().isAuto();
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+ */
+ public boolean mustKeepWithPrevious() {
+ return !fobj.getKeepWithPrevious().getWithinPage().isAuto();
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+ */
+ public boolean mustKeepWithNext() {
+ return !fobj.getKeepWithNext().getWithinPage().isAuto();
+ }
}
package org.apache.fop.layoutmgr;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.ListIterator;
import java.util.List;
/**
* LayoutManager for a block FO.
*/
-public class BlockLayoutManager extends BlockStackingLayoutManager {
+public class BlockLayoutManager extends BlockStackingLayoutManager
+ implements BlockLevelLayoutManager {
private static final int FINISHED_LEAF_POS = -2;
protected List childBreaks = new java.util.ArrayList();
private boolean isfirst = true;
+
+ /*LF*/
+ /** Only used to store the original list when createUnitElements is called */
+ private LinkedList storedList = null;
+
+ private boolean bBreakBeforeServed = false;
+ private boolean bSpaceBeforeServed = false;
+
+ private LineLayoutManager childLLM = null;
/**
* Creates a new BlockLayoutManager.
protected void initProperties() {
foBlockSpaceBefore = new SpaceVal(fobj.getCommonMarginBlock().spaceBefore).getSpace();
prevFoBlockSpaceAfter = foBlockSpaceAfter;
+/*LF*/ bpUnit = 0; //layoutProps.blockProgressionUnit;
+/*LF*/ if (bpUnit == 0) {
+/*LF*/ // use optimum space values
+/*LF*/ adjustedSpaceBefore = fobj.getCommonMarginBlock().spaceBefore.getSpace().getOptimum().getLength().getValue();
+/*LF*/ adjustedSpaceAfter = fobj.getCommonMarginBlock().spaceAfter.getSpace().getOptimum().getLength().getValue();
+/*LF*/ } else {
+/*LF*/ // use minimum space values
+/*LF*/ adjustedSpaceBefore = fobj.getCommonMarginBlock().spaceBefore.getSpace().getMinimum().getLength().getValue();
+/*LF*/ adjustedSpaceAfter = fobj.getCommonMarginBlock().spaceAfter.getSpace().getMinimum().getLength().getValue();
+/*LF*/ }
}
/**
return iIndents;
}
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+ /* LF *///System.err.println("BLM.getNextKnuthElements> keep-together = "
+ // + layoutProps.keepTogether.getType());
+ /* LF *///System.err.println(" keep-with-previous = " +
+ // layoutProps.keepWithPrevious.getType());
+ /* LF *///System.err.println(" keep-with-next = " +
+ // layoutProps.keepWithNext.getType());
+ BlockLevelLayoutManager curLM; // currently active LM
+ BlockLevelLayoutManager prevLM = null; // previously active LM
+
+ referenceIPD = context.getRefIPD();
+ int iIndents = fobj.getCommonMarginBlock().startIndent.getValue()
+ + fobj.getCommonMarginBlock().endIndent.getValue();
+ int bIndents = fobj.getCommonBorderPaddingBackground().getBPPaddingAndBorder(false);
+ int ipd = referenceIPD - iIndents;
+
+ MinOptMax stackSize = new MinOptMax();
+
+ // Set context for percentage property values.
+ fobj.setLayoutDimension(PercentBase.BLOCK_IPD, ipd);
+ fobj.setLayoutDimension(PercentBase.BLOCK_BPD, -1);
+
+ LinkedList returnedList = null;
+ LinkedList contentList = new LinkedList();
+ LinkedList returnList = new LinkedList();
+ Position returnPosition = new NonLeafPosition(this, null);
+
+ if (!bBreakBeforeServed) {
+ try {
+ if (addKnuthElementsForBreakBefore(returnList, returnPosition,
+ fobj.getBreakBefore())) {
+ return returnList;
+ }
+ } finally {
+ bBreakBeforeServed = true;
+ }
+ }
+
+ if (!bSpaceBeforeServed) {
+ addKnuthElementsForSpaceBefore(returnList, returnPosition, alignment,
+ fobj.getCommonMarginBlock().spaceBefore);
+ bSpaceBeforeServed = true;
+ }
+
+ addKnuthElementForBorderPaddingBefore(returnList, returnPosition,
+ fobj.getCommonBorderPaddingBackground());
+
+ while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
+ LayoutContext childLC = new LayoutContext(0);
+ if (curLM instanceof LineLayoutManager) {
+ // curLM is a LineLayoutManager
+ // set stackLimit for lines
+ childLC.setStackLimit(new MinOptMax(ipd/*
+ * - iIndents -
+ * iTextIndent
+ */));
+ childLC.setRefIPD(ipd);
+ } else {
+ // curLM is a ?
+ childLC.setStackLimit(MinOptMax.subtract(context
+ .getStackLimit(), stackSize));
+ childLC.setRefIPD(referenceIPD);
+ }
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ if (returnedList.size() == 1
+ && ((KnuthElement) returnedList.getFirst()).isPenalty()
+ && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this block has break-before
+ if (returnList.size() == 0) {
+ // the first child (or its first child ...) has
+ // break-before;
+ // all this block, including space before, will be put in
+ // the
+ // following page
+ bSpaceBeforeServed = false;
+ }
+ contentList.addAll(returnedList);
+
+ /* extension: conversione di tutta la sequenza fin'ora ottenuta */
+ if (bpUnit > 0) {
+ storedList = contentList;
+ contentList = createUnitElements(contentList);
+ }
+ /* end of extension */
+
+ // "wrap" the Position inside each element
+ // moving the elements from contentList to returnList
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ } else {
+ if (prevLM != null) {
+ // there is a block handled by prevLM
+ // before the one handled by curLM
+ if (mustKeepTogether()
+ || prevLM.mustKeepWithNext()
+ || curLM.mustKeepWithPrevious()) {
+ // add an infinite penalty to forbid a break between
+ // blocks
+ contentList.add(new KnuthPenalty(0,
+ KnuthElement.INFINITE, false,
+ new Position(this), false));
+ } else if (!((KnuthElement) contentList.getLast()).isGlue()) {
+ // add a null penalty to allow a break between blocks
+ contentList.add(new KnuthPenalty(0, 0, false,
+ new Position(this), false));
+ } else {
+ // the last element in contentList is a glue;
+ // it is a feasible breakpoint, there is no need to add
+ // a penalty
+ }
+ }
+ contentList.addAll(returnedList);
+ if (returnedList.size() == 0) {
+ //Avoid NoSuchElementException below (happens with empty blocks)
+ continue;
+ }
+ if (((KnuthElement) returnedList.getLast()).isPenalty()
+ && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this block has break-after
+ if (curLM.isFinished()) {
+ // there is no other content in this block;
+ // it's useless to add space after before a page break
+ setFinished(true);
+ }
+
+ /* extension: conversione di tutta la sequenza fin'ora ottenuta */
+ if (bpUnit > 0) {
+ storedList = contentList;
+ contentList = createUnitElements(contentList);
+ }
+ /* end of extension */
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ }
+ }
+ prevLM = curLM;
+ }
+
+ /* Extension: conversione di tutta la sequenza fin'ora ottenuta */
+ if (bpUnit > 0) {
+ storedList = contentList;
+ contentList = createUnitElements(contentList);
+ }
+ /* end of extension */
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ addKnuthElementsForBorderPaddingAfter(returnList, returnPosition,
+ fobj.getCommonBorderPaddingBackground());
+ addKnuthElementsForSpaceAfter(returnList, returnPosition, alignment,
+ fobj.getCommonMarginBlock().spaceAfter);
+ addKnuthElementsForBreakAfter(returnList, returnPosition, fobj.getBreakAfter());
+
+ setFinished(true);
+
+ return returnList;
+ }
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getNextBreakPoss(org.apache.fop.layoutmgr.LayoutContext)
*/
- public BreakPoss getNextBreakPoss(LayoutContext context) {
+ public BreakPoss getNextBreakPossOLDOLDOLD(LayoutContext context) {
LayoutManager curLM; // currently active LM
//int refipd = context.getRefIPD();
return breakPoss;
}
+ protected LinkedList createUnitElements(LinkedList oldList) {
+ //System.out.println(" ");
+ //System.out.println("Inizio conversione: " + oldList.size() + " elementi, spazio minimo prima= " + layoutProps.spaceBefore.getSpace().min
+ // + " spazio minimo dopo= " + layoutProps.spaceAfter.getSpace().min);
+ // add elements at the beginning and at the end of oldList
+ // representing minimum spaces
+ LayoutManager lm = ((KnuthElement)oldList.getFirst()).getLayoutManager();
+ boolean bAddedBoxBefore = false;
+ boolean bAddedBoxAfter = false;
+ if (adjustedSpaceBefore > 0) {
+ oldList.addFirst(new KnuthBox(adjustedSpaceBefore,
+ new Position(lm), true));
+ bAddedBoxBefore = true;
+ }
+ if (adjustedSpaceAfter > 0) {
+ oldList.addLast(new KnuthBox(adjustedSpaceAfter,
+ new Position(lm), true));
+ bAddedBoxAfter = true;
+ }
+
+ MinOptMax totalLength = new MinOptMax(0);
+ MinOptMax totalUnits = new MinOptMax(0);
+ LinkedList newList = new LinkedList();
+
+ //System.out.println(" ");
+ //System.out.println(" Prima scansione");
+ // scan the list once to compute total min, opt and max length
+ ListIterator oldListIterator = oldList.listIterator();
+ while (oldListIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) oldListIterator.next();
+ if (element.isBox()) {
+/*LF*/ totalLength.add(new MinOptMax(element.getW()));
+/*LF*/ //System.out.println("box " + element.getW());
+/*LF*/ } else if (element.isGlue()) {
+/*LF*/ totalLength.min -= ((KnuthGlue) element).getZ();
+/*LF*/ totalLength.max += ((KnuthGlue) element).getY();
+/*LF*/ //leafValue = ((LeafPosition) element.getPosition()).getLeafPos();
+/*LF*/ //System.out.println("glue " + element.getW() + " + " + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ());
+/*LF*/ } else {
+/*LF*/ //System.out.println((((KnuthPenalty)element).getP() == KnuthElement.INFINITE ? "PENALTY " : "penalty ") + element.getW());
+ }
+ }
+ // compute the total amount of "units"
+ totalUnits = new MinOptMax(neededUnits(totalLength.min),
+ neededUnits(totalLength.opt),
+ neededUnits(totalLength.max));
+ //System.out.println(" totalLength= " + totalLength);
+ //System.out.println(" unita'= " + totalUnits);
+
+ //System.out.println(" ");
+ //System.out.println(" Seconda scansione");
+ // scan the list once more, stopping at every breaking point
+ // in order to compute partial min, opt and max length
+ // and create the new elements
+ oldListIterator = oldList.listIterator();
+ boolean bPrevIsBox = false;
+ MinOptMax lengthBeforeBreak = new MinOptMax(0);
+ MinOptMax lengthAfterBreak = (MinOptMax) totalLength.clone();
+ MinOptMax unitsBeforeBreak;
+ MinOptMax unitsAfterBreak;
+ MinOptMax unsuppressibleUnits = new MinOptMax(0);
+ int firstIndex = 0;
+ int lastIndex = -1;
+ while (oldListIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) oldListIterator.next();
+ lastIndex ++;
+ if (element.isBox()) {
+ lengthBeforeBreak.add(new MinOptMax(element.getW()));
+ lengthAfterBreak.subtract(new MinOptMax(element.getW()));
+ bPrevIsBox = true;
+ } else if (element.isGlue()) {
+ lengthBeforeBreak.min -= ((KnuthGlue) element).getZ();
+ lengthAfterBreak.min += ((KnuthGlue) element).getZ();
+ lengthBeforeBreak.max += ((KnuthGlue) element).getY();
+ lengthAfterBreak.max -= ((KnuthGlue) element).getY();
+ bPrevIsBox = false;
+ } else {
+ lengthBeforeBreak.add(new MinOptMax(element.getW()));
+ bPrevIsBox = false;
+ }
+
+ // create the new elements
+ if (element.isPenalty() && ((KnuthPenalty) element).getP() < KnuthElement.INFINITE
+ || element.isGlue() && bPrevIsBox
+ || !oldListIterator.hasNext()) {
+ // suppress elements after the breaking point
+ int iStepsForward = 0;
+ while (oldListIterator.hasNext()) {
+ KnuthElement el = (KnuthElement) oldListIterator.next();
+ iStepsForward++;
+ if (el.isGlue()) {
+ // suppressed glue
+ lengthAfterBreak.min += ((KnuthGlue) el).getZ();
+ lengthAfterBreak.max -= ((KnuthGlue) el).getY();
+ } else if (el.isPenalty()) {
+ // suppressed penalty, do nothing
+ } else {
+ // box, end of suppressions
+ break;
+ }
+ }
+ // compute the partial amount of "units" before and after the break
+ unitsBeforeBreak = new MinOptMax(neededUnits(lengthBeforeBreak.min),
+ neededUnits(lengthBeforeBreak.opt),
+ neededUnits(lengthBeforeBreak.max));
+ unitsAfterBreak = new MinOptMax(neededUnits(lengthAfterBreak.min),
+ neededUnits(lengthAfterBreak.opt),
+ neededUnits(lengthAfterBreak.max));
+
+ // rewind the iterator and lengthAfterBreak
+ for (int i = 0; i < iStepsForward; i++) {
+ KnuthElement el = (KnuthElement) oldListIterator.previous();
+ if (el.isGlue()) {
+ lengthAfterBreak.min -= ((KnuthGlue) el).getZ();
+ lengthAfterBreak.max += ((KnuthGlue) el).getY();
+ }
+ }
+
+ // compute changes in length, stretch and shrink
+ int uLengthChange = unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt;
+ int uStretchChange = (unitsBeforeBreak.max + unitsAfterBreak.max - totalUnits.max)
+ - (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt);
+ int uShrinkChange = (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt)
+ - (unitsBeforeBreak.min + unitsAfterBreak.min - totalUnits.min);
+
+ // compute the number of normal, stretch and shrink unit
+ // that must be added to the new sequence
+ int uNewNormal = unitsBeforeBreak.opt - unsuppressibleUnits.opt;
+ int uNewStretch = (unitsBeforeBreak.max - unitsBeforeBreak.opt)
+ - (unsuppressibleUnits.max - unsuppressibleUnits.opt);
+ int uNewShrink = (unitsBeforeBreak.opt - unitsBeforeBreak.min)
+ - (unsuppressibleUnits.opt - unsuppressibleUnits.min);
+
+/*LF*/ //System.out.println("(" + unsuppressibleUnits.min + "-" + unsuppressibleUnits.opt + "-" + unsuppressibleUnits.max + ") "
+/*LF*/ // + " -> " + unitsBeforeBreak.min + "-" + unitsBeforeBreak.opt + "-" + unitsBeforeBreak.max
+/*LF*/ // + " + " + unitsAfterBreak.min + "-" + unitsAfterBreak.opt + "-" + unitsAfterBreak.max
+/*LF*/ // + (uLengthChange != 0 ? " [length " + uLengthChange + "] " : "")
+/*LF*/ // + (uStretchChange != 0 ? " [stretch " + uStretchChange + "] " : "")
+/*LF*/ // + (uShrinkChange != 0 ? " [shrink " + uShrinkChange + "]" : "")
+/*LF*/ // );
+
+ // create the MappingPosition which will be stored in the new elements
+ // correct firstIndex and lastIndex
+ int firstIndexCorrection = 0;
+ int lastIndexCorrection = 0;
+ if (bAddedBoxBefore) {
+ if (firstIndex != 0) {
+ firstIndexCorrection ++;
+ }
+ lastIndexCorrection ++;
+ }
+ if (bAddedBoxAfter && lastIndex == (oldList.size() - 1)) {
+ lastIndexCorrection ++;
+ }
+ MappingPosition mappingPos = new MappingPosition(this,
+ firstIndex - firstIndexCorrection,
+ lastIndex - lastIndexCorrection);
+
+ // new box
+ newList.add(new KnuthBox((uNewNormal - uLengthChange) * bpUnit,
+ mappingPos,
+ false));
+ unsuppressibleUnits.add(new MinOptMax(uNewNormal - uLengthChange));
+ //System.out.println(" box " + (uNewNormal - uLengthChange));
+
+ // new infinite penalty, glue and box, if necessary
+ if (uNewStretch - uStretchChange > 0
+ || uNewShrink - uShrinkChange > 0) {
+ int iStretchUnits = (uNewStretch - uStretchChange > 0 ? (uNewStretch - uStretchChange) : 0);
+ int iShrinkUnits = (uNewShrink - uShrinkChange > 0 ? (uNewShrink - uShrinkChange) : 0);
+ newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ mappingPos,
+ false));
+ newList.add(new KnuthGlue(0,
+ iStretchUnits * bpUnit,
+ iShrinkUnits * bpUnit,
+ LINE_NUMBER_ADJUSTMENT,
+ mappingPos,
+ false));
+ //System.out.println(" PENALTY");
+ //System.out.println(" glue 0 " + iStretchUnits + " " + iShrinkUnits);
+ unsuppressibleUnits.max += iStretchUnits;
+ unsuppressibleUnits.min -= iShrinkUnits;
+ if (!oldListIterator.hasNext()) {
+ newList.add(new KnuthBox(0,
+ mappingPos,
+ false));
+ //System.out.println(" box 0");
+ }
+ }
+
+ // new breaking sequence
+ if (uStretchChange != 0
+ || uShrinkChange != 0) {
+ // new infinite penalty, glue, penalty and glue
+ newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ mappingPos,
+ false));
+ newList.add(new KnuthGlue(0,
+ uStretchChange * bpUnit,
+ uShrinkChange * bpUnit,
+ LINE_NUMBER_ADJUSTMENT,
+ mappingPos,
+ false));
+ newList.add(new KnuthPenalty(uLengthChange * bpUnit,
+ 0, false, element.getPosition(), false));
+ newList.add(new KnuthGlue(0,
+ - uStretchChange * bpUnit,
+ - uShrinkChange * bpUnit,
+ LINE_NUMBER_ADJUSTMENT,
+ mappingPos,
+ false));
+ //System.out.println(" PENALTY");
+ //System.out.println(" glue 0 " + uStretchChange + " " + uShrinkChange);
+ //System.out.println(" penalty " + uLengthChange + " * unit");
+ //System.out.println(" glue 0 " + (- uStretchChange) + " " + (- uShrinkChange));
+ } else if (oldListIterator.hasNext()){
+ // new penalty
+ newList.add(new KnuthPenalty(uLengthChange * bpUnit,
+ 0, false,
+ mappingPos,
+ false));
+ //System.out.println(" penalty " + uLengthChange + " * unit");
+ }
+ // update firstIndex
+ firstIndex = lastIndex + 1;
+ }
+
+ if (element.isPenalty()) {
+ lengthBeforeBreak.add(new MinOptMax(-element.getW()));
+ }
+
+ }
+
+ // remove elements at the beginning and at the end of oldList
+ // representing minimum spaces
+ if (adjustedSpaceBefore > 0) {
+ oldList.removeFirst();
+ }
+ if (adjustedSpaceAfter > 0) {
+ oldList.removeLast();
+ }
+
+ // if space-before.conditionality is "discard", correct newList
+ if (fobj.getCommonMarginBlock().spaceBefore.getSpace().isDiscard()) {
+ // remove the wrong element
+ KnuthBox wrongBox = (KnuthBox) newList.removeFirst();
+ // if this paragraph is at the top of a page, the space before
+ // must be ignored; compute the length change
+ int decreasedLength = (neededUnits(totalLength.opt)
+ - neededUnits(totalLength.opt - adjustedSpaceBefore))
+ * bpUnit;
+ // insert the correct elements
+ newList.addFirst(new KnuthBox(wrongBox.getW() - decreasedLength,
+ wrongBox.getPosition(), false));
+ newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT,
+ wrongBox.getPosition(), false));
+ //System.out.println(" rimosso box " + neededUnits(wrongBox.getW()));
+ //System.out.println(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
+ //System.out.println(" aggiunto box " + neededUnits(wrongBox.getW() - decreasedLength));
+ }
+
+ // if space-after.conditionality is "discard", correct newList
+ if (fobj.getCommonMarginBlock().spaceAfter.getSpace().isDiscard()) {
+ // remove the wrong element
+ KnuthBox wrongBox = (KnuthBox) newList.removeLast();
+ // if the old sequence is box(h) penalty(inf) glue(x,y,z) box(0)
+ // (it cannot be parted and has some stretch or shrink)
+ // the wrong box is the first one, not the last one
+ LinkedList preserveList = new LinkedList();
+ if (wrongBox.getW() == 0) {
+ preserveList.add(wrongBox);
+ preserveList.addFirst((KnuthGlue) newList.removeLast());
+ preserveList.addFirst((KnuthPenalty) newList.removeLast());
+ wrongBox = (KnuthBox) newList.removeLast();
+ }
+
+ // if this paragraph is at the bottom of a page, the space after
+ // must be ignored; compute the length change
+ int decreasedLength = (neededUnits(totalLength.opt)
+ - neededUnits(totalLength.opt - adjustedSpaceAfter))
+ * bpUnit;
+ // insert the correct box
+ newList.addLast(new KnuthBox(wrongBox.getW() - decreasedLength,
+ wrongBox.getPosition(), false));
+ // add preserved elements
+ if (preserveList.size() > 0) {
+ newList.addAll(preserveList);
+ }
+ // insert the correct glue
+ newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT,
+ wrongBox.getPosition(), false));
+ //System.out.println(" rimosso box " + neededUnits(wrongBox.getW()));
+ //System.out.println(" aggiunto box " + neededUnits(wrongBox.getW() - decreasedLength));
+ //System.out.println(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
+ }
+
+ return newList;
+ }
+/*LF*/
+
+ public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> " + adj);
+/*LF*/ //System.out.println(" lastElement e' " + (lastElement.isPenalty() ? "penalty" : (lastElement.isGlue() ? "glue" : "box" )));
+/*LF*/ //System.out.println(" position e' " + lastElement.getPosition().getClass().getName());
+/*LF*/ //System.out.println(" " + (bpUnit > 0 ? "unit" : ""));
+ Position innerPosition = ((NonLeafPosition) lastElement.getPosition()).getPosition();
+
+ if (innerPosition == null && lastElement.isGlue()) {
+ // this adjustment applies to space-before or space-after of this block
+ if (((KnuthGlue) lastElement).getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
+ // this adjustment applies to space-before
+ adjustedSpaceBefore += adj;
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> spazio prima: " + adj);
+ } else {
+ // this adjustment applies to space-after
+ adjustedSpaceAfter += adj;
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> spazio dopo: " + adj);
+ }
+ return adj;
+ } else if (innerPosition instanceof MappingPosition) {
+ // this block has block-progression-unit > 0: the adjustment can concern
+ // - the space-before or space-after of this block,
+ // - the line number of a descendant of this block
+ if (lastElement.isGlue()) {
+ // lastElement is a glue
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> bpunit con glue");
+ ListIterator storedListIterator = storedList.listIterator(((MappingPosition) innerPosition).getFirstIndex());
+ int newAdjustment = 0;
+ while (storedListIterator.nextIndex() <= ((MappingPosition) innerPosition).getLastIndex()) {
+ KnuthElement storedElement = (KnuthElement) storedListIterator.next();
+ if (storedElement.isGlue()) {
+ newAdjustment += ((BlockLevelLayoutManager) storedElement.getLayoutManager()).negotiateBPDAdjustment(adj - newAdjustment, storedElement);
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> (progressivo) righe: " + newAdjustment);
+ }
+ }
+ newAdjustment = (newAdjustment > 0 ? bpUnit * neededUnits(newAdjustment)
+ : - bpUnit * neededUnits(- newAdjustment));
+ return newAdjustment;
+ } else {
+ // lastElement is a penalty: this means that the paragraph
+ // has been split between consecutive pages:
+ // this may involve a change in the number of lines
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> bpunit con penalty");
+ KnuthPenalty storedPenalty = (KnuthPenalty)
+ storedList.get(((MappingPosition) innerPosition).getLastIndex());
+ if (storedPenalty.getW() > 0) {
+ // the original penalty has width > 0
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> chiamata passata");
+ return ((BlockLevelLayoutManager) storedPenalty.getLayoutManager())
+ .negotiateBPDAdjustment(storedPenalty.getW(), (KnuthElement) storedPenalty);
+ } else {
+ // the original penalty has width = 0
+ // the adjustment involves only the spaces before and after
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> chiamata gestita");
+ return adj;
+ }
+ }
+ } else if (innerPosition.getLM() != this) {
+ // this adjustment concerns another LM
+ NonLeafPosition savedPos = (NonLeafPosition) lastElement.getPosition();
+ lastElement.setPosition(innerPosition);
+ int returnValue = ((BlockLevelLayoutManager) lastElement.getLayoutManager()).negotiateBPDAdjustment(adj, lastElement);
+ lastElement.setPosition(savedPos);
+/*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> righe: " + returnValue);
+ return returnValue;
+ } else {
+ // this should never happen
+ System.err.println("BlockLayoutManager.negotiateBPDAdjustment(): unexpected Position");
+ return 0;
+ }
+ }
+
+ public void discardSpace(KnuthGlue spaceGlue) {
+/*LF*/ //System.out.println(" BLM.discardSpace> " + spaceGlue.getPosition().getClass().getName());
+ Position innerPosition = ((NonLeafPosition) spaceGlue.getPosition()).getPosition();
+
+/*LF*/ if (innerPosition == null || innerPosition.getLM() == this) {
+ // if this block has block-progression-unit > 0, innerPosition can be
+ // a MappingPosition
+ // spaceGlue represents space before or space after of this block
+ if (spaceGlue.getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
+ // space-before must be discarded
+ adjustedSpaceBefore = 0;
+ } else {
+ // space-after must be discarded
+ adjustedSpaceAfter = 0;
+ //TODO Why are both cases handled in the same way?
+ }
+/*LF*/ } else {
+ // this element was not created by this BlockLM
+ NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
+ spaceGlue.setPosition(innerPosition);
+ ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
+ spaceGlue.setPosition(savedPos);
+ }
+ }
+
+ public LinkedList getChangedKnuthElements(List oldList, /*int flaggedPenalty,*/ int alignment) {
+/*LF*/ //System.out.println("");
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> inizio: oldList.size() = " + oldList.size());
+ ListIterator oldListIterator = oldList.listIterator();
+ KnuthElement returnedElement;
+ KnuthElement currElement = null;
+ KnuthElement prevElement = null;
+ LinkedList returnedList = new LinkedList();
+ LinkedList returnList = new LinkedList();
+ int fromIndex = 0;
+
+ // "unwrap" the Positions stored in the elements
+ KnuthElement oldElement = null;
+ while (oldListIterator.hasNext()) {
+ oldElement = (KnuthElement)oldListIterator.next();
+ Position innerPosition = ((NonLeafPosition) oldElement.getPosition()).getPosition();
+/*LF*/ //System.out.println(" BLM> unwrapping: " + (oldElement.isBox() ? "box " : (oldElement.isGlue() ? "glue " : "penalty")) + " creato da " + oldElement.getLayoutManager().getClass().getName());
+/*LF*/ //System.out.println(" BLM> unwrapping: " + oldElement.getPosition().getClass().getName());
+ if (innerPosition != null) {
+ // oldElement was created by a descendant of this BlockLM
+ oldElement.setPosition(innerPosition);
+ } else {
+ // thisElement was created by this BlockLM
+ // modify its position in order to recognize it was not created
+ // by a child
+ oldElement.setPosition(new Position(this));
+ }
+ }
+
+ // create the iterator
+ List workList;
+ if (bpUnit == 0) {
+ workList = oldList;
+ } else {
+ // the storedList must be used instead of oldList;
+ // find the index of the first element of returnedList
+ // corresponding to the first element of oldList
+ oldListIterator = oldList.listIterator();
+ KnuthElement el = (KnuthElement) oldListIterator.next();
+ while (!(el.getPosition() instanceof MappingPosition)) {
+ el = (KnuthElement) oldListIterator.next();
+ }
+ int iFirst = ((MappingPosition) el.getPosition()).getFirstIndex();
+
+ // find the index of the last element of returnedList
+ // corresponding to the last element of oldList
+ oldListIterator = oldList.listIterator(oldList.size());
+ el = (KnuthElement) oldListIterator.previous();
+ while (!(el.getPosition() instanceof MappingPosition)) {
+ el = (KnuthElement) oldListIterator.previous();
+ }
+ int iLast = ((MappingPosition) el.getPosition()).getLastIndex();
+
+/*LF*/ //System.out.println(" si usa storedList da " + iFirst + " a " + iLast + " compresi su " + storedList.size() + " elementi totali");
+ workList = storedList.subList(iFirst, iLast + 1);
+ }
+ ListIterator workListIterator = workList.listIterator();
+
+/*LF*/ //System.out.println("");
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> workList.size() = " + workList.size() + " da 0 a " + (workList.size() - 1));
+
+ while (workListIterator.hasNext()) {
+ currElement = (KnuthElement) workListIterator.next();
+/*LF*/ //System.out.println("elemento n. " + workListIterator.previousIndex() + " nella workList");
+ if (prevElement != null
+ && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
+ // prevElement is the last element generated by the same LM
+ BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager)
+ prevElement.getLayoutManager();
+ BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
+ currElement.getLayoutManager();
+ boolean bSomethingAdded = false;
+ if (prevLM != this) {
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + workListIterator.previousIndex() + " su " + prevLM.getClass().getName());
+ returnedList.addAll(prevLM.getChangedKnuthElements(workList.subList(fromIndex, workListIterator.previousIndex()),
+ /*flaggedPenalty,*/ alignment));
+ bSomethingAdded = true;
+ } else {
+ // prevLM == this
+ // do nothing
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> elementi propri, ignorati, da " + fromIndex + " a " + workListIterator.previousIndex() + " su " + prevLM.getClass().getName());
+ }
+ fromIndex = workListIterator.previousIndex();
+
+ // there is another block after this one
+ if (bSomethingAdded
+ && (this.mustKeepTogether()
+ || prevLM.mustKeepWithNext()
+ || currLM.mustKeepWithPrevious())) {
+ // add an infinite penalty to forbid a break between blocks
+ returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, new Position(this), false));
+ } else if (bSomethingAdded && !((KnuthElement) returnedList.getLast()).isGlue()) {
+ // add a null penalty to allow a break between blocks
+ returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+ }
+ }
+ prevElement = currElement;
+ }
+ if (currElement != null) {
+ BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
+ currElement.getLayoutManager();
+ if (currLM != this) {
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + oldList.size() + " su " + currLM.getClass().getName());
+ returnedList.addAll(currLM.getChangedKnuthElements(workList.subList(fromIndex, workList.size()),
+ /*flaggedPenalty,*/ alignment));
+ } else {
+ // currLM == this
+ // there are no more elements to add
+ // remove the last penalty added to returnedList
+ if (returnedList.size() > 0) {
+ returnedList.removeLast();
+ }
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> elementi propri, ignorati, da " + fromIndex + " a " + workList.size());
+ }
+ }
+
+ // append elements representing space-before
+ boolean spaceBeforeIsConditional = fobj.getCommonMarginBlock().spaceBefore.getSpace().isDiscard();
+ if (bpUnit > 0
+ || adjustedSpaceBefore != 0) {
+ if (!spaceBeforeIsConditional) {
+ // add elements to prevent the glue to be discarded
+ returnList.add(new KnuthBox(0,
+ new NonLeafPosition(this, null), false));
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ new NonLeafPosition(this, null), false));
+ }
+ if (bpUnit > 0) {
+ returnList.add(new KnuthGlue(0, 0, 0,
+ SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
+ } else {
+ returnList.add(new KnuthGlue(adjustedSpaceBefore, 0, 0,
+ SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
+ }
+ }
+
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> intermedio: returnedList.size() = " + returnedList.size());
+
+/* estensione: conversione complessiva */
+/*LF*/ if (bpUnit > 0) {
+/*LF*/ storedList = returnedList;
+/*LF*/ returnedList = createUnitElements(returnedList);
+/*LF*/ }
+/* estensione */
+
+ // "wrap" the Position stored in each element of returnedList
+ // and add elements to returnList
+ ListIterator listIter = returnedList.listIterator();
+ while (listIter.hasNext()) {
+ returnedElement = (KnuthElement)listIter.next();
+ returnedElement.setPosition(new NonLeafPosition(this, returnedElement.getPosition()));
+ returnList.add(returnedElement);
+ }
+
+ // append elements representing space-after
+ boolean spaceAfterIsConditional = fobj.getCommonMarginBlock().spaceAfter.getSpace().isDiscard();
+ if (bpUnit > 0
+ || adjustedSpaceAfter != 0) {
+ if (!spaceAfterIsConditional) {
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ new NonLeafPosition(this, null), false));
+ }
+ if (bpUnit > 0) {
+ returnList.add(new KnuthGlue(0, 0, 0,
+ SPACE_AFTER_ADJUSTMENT, new NonLeafPosition(this, null),
+ (!spaceAfterIsConditional) ? false : true));
+ } else {
+ returnList.add(new KnuthGlue(adjustedSpaceAfter, 0, 0,
+ SPACE_AFTER_ADJUSTMENT, new NonLeafPosition(this, null),
+ (!spaceAfterIsConditional) ? false : true));
+ }
+ if (!spaceAfterIsConditional) {
+ returnList.add(new KnuthBox(0,
+ new NonLeafPosition(this, null), true));
+ }
+ }
+
+/*LF*/ //System.out.println(" BLM.getChangedKnuthElements> fine: returnList.size() = " + returnList.size());
+ return returnList;
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
+ */
+ public boolean mustKeepTogether() {
+ return !fobj.getKeepTogether().getWithinPage().isAuto();
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious()
+ */
+ public boolean mustKeepWithPrevious() {
+ return !fobj.getKeepWithPrevious().getWithinPage().isAuto();
+ }
+
+ /**
+ * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext()
+ */
+ public boolean mustKeepWithNext() {
+ return !fobj.getKeepWithNext().getWithinPage().isAuto();
+ }
+
+ //TODO this method is no longer used
+ public BreakPoss getNextBreakPoss(LayoutContext context) {
+ setFinished(true);
+ return null;
+ }
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#addAreas(org.apache.fop.layoutmgr.PositionIterator, org.apache.fop.layoutmgr.LayoutContext)
*/
- public void addAreas(PositionIterator parentIter,
+ public void addAreasOLDOLDOLD(PositionIterator parentIter,
LayoutContext layoutContext) {
getParentArea(null);
}
}
+ public void addAreas(PositionIterator parentIter,
+ LayoutContext layoutContext) {
+ /* LF *///System.out.println(" BLM.addAreas>");
+ getParentArea(null);
+
+ // if this will create the first block area in a page
+ // and display-align is bottom or center, add space before
+ if (layoutContext.getSpaceBefore() > 0) {
+ addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+ }
+
+ addID(fobj.getId());
+ //addMarkers(true, bp1.isFirstArea(), bp1.isLastArea());
+ addMarkers(true, true, false);
+
+ LayoutManager childLM = null;
+ LayoutManager lastLM = null;
+ LayoutContext lc = new LayoutContext(0);
+ /* LF */// set space after in the LayoutContext for children
+ /* LF */if (layoutContext.getSpaceAfter() > 0) {
+ /* LF */lc.setSpaceAfter(layoutContext.getSpaceAfter());
+ /* LF */}
+ /* LF */PositionIterator childPosIter;
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ LinkedList positionList = new LinkedList();
+ Position pos;
+ boolean bSpaceBefore = false;
+ boolean bSpaceAfter = false;
+ while (parentIter.hasNext()) {
+ pos = (Position) parentIter.next();
+ /* LF *///System.out.println("pos = " + pos.getClass().getName());
+ Position innerPosition = ((NonLeafPosition) pos).getPosition();
+ if (innerPosition == null) {
+ // pos was created by this BlockLM and was inside an element
+ // representing space before or after
+ // this means the space was not discarded
+ if (positionList.size() == 0) {
+ // pos was in the element representing space-before
+ bSpaceBefore = true;
+ /* LF *///System.out.println(" spazio prima");
+ } else {
+ // pos was in the element representing space-after
+ bSpaceAfter = true;
+ /* LF *///System.out.println(" spazio dopo");
+ }
+ } else if (innerPosition.getLM() == this
+ && !(innerPosition instanceof MappingPosition)) {
+ // pos was created by this BlockLM and was inside a penalty
+ // allowing or forbidding a page break
+ // nothing to do
+ /* LF *///System.out.println(" penalty");
+ } else {
+ // innerPosition was created by another LM
+ positionList.add(innerPosition);
+ lastLM = innerPosition.getLM();
+ /* LF *///System.out.println(" " +
+ // innerPosition.getClass().getName());
+ }
+ }
+
+ if (bpUnit == 0) {
+ // the Positions in positionList were inside the elements
+ // created by the LineLM
+ childPosIter = new StackingIter(positionList.listIterator());
+ } else {
+ // the Positions in positionList were inside the elements
+ // created by the BlockLM in the createUnitElements() method
+ //if (((Position) positionList.getLast()) instanceof
+ // LeafPosition) {
+ // // the last item inside positionList is a LeafPosition
+ // // (a LineBreakPosition, more precisely); this means that
+ // // the whole paragraph is on the same page
+ // System.out.println("paragrafo intero");
+ // childPosIter = new KnuthPossPosIter(storedList, 0,
+ // storedList.size());
+ //} else {
+ // // the last item inside positionList is a Position;
+ // // this means that the paragraph has been split
+ // // between consecutive pages
+ LinkedList splitList = new LinkedList();
+ int splitLength = 0;
+ int iFirst = ((MappingPosition) positionList.getFirst()).getFirstIndex();
+ int iLast = ((MappingPosition) positionList.getLast()).getLastIndex();
+ // copy from storedList to splitList all the elements from
+ // iFirst to iLast
+ ListIterator storedListIterator = storedList.listIterator(iFirst);
+ while (storedListIterator.nextIndex() <= iLast) {
+ KnuthElement element = (KnuthElement) storedListIterator
+ .next();
+ // some elements in storedList (i.e. penalty items) were created
+ // by this BlockLM, and must be ignored
+ if (element.getLayoutManager() != this) {
+ splitList.add(element);
+ splitLength += element.getW();
+ lastLM = element.getLayoutManager();
+ }
+ }
+ //System.out.println("addAreas riferito a storedList da " +
+ // iFirst + " a " + iLast);
+ //System.out.println("splitLength= " + splitLength
+ // + " (" + neededUnits(splitLength) + " unita') "
+ // + (neededUnits(splitLength) * bpUnit - splitLength) + " spazi");
+ // add space before and / or after the paragraph
+ // to reach a multiple of bpUnit
+ if (bSpaceBefore && bSpaceAfter) {
+ foBlockSpaceBefore = new SpaceVal(fobj.getCommonMarginBlock().spaceBefore).getSpace();
+ foBlockSpaceAfter = new SpaceVal(fobj.getCommonMarginBlock().spaceAfter).getSpace();
+ adjustedSpaceBefore = (neededUnits(splitLength
+ + foBlockSpaceBefore.min
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength) / 2;
+ adjustedSpaceAfter = neededUnits(splitLength
+ + foBlockSpaceBefore.min
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength - adjustedSpaceBefore;
+ } else if (bSpaceBefore) {
+ adjustedSpaceBefore = neededUnits(splitLength
+ + foBlockSpaceBefore.min)
+ * bpUnit - splitLength;
+ } else {
+ adjustedSpaceAfter = neededUnits(splitLength
+ + foBlockSpaceAfter.min)
+ * bpUnit - splitLength;
+ }
+ //System.out.println("spazio prima = " + adjustedSpaceBefore
+ // + " spazio dopo = " + adjustedSpaceAfter + " totale = " +
+ // (adjustedSpaceBefore + adjustedSpaceAfter + splitLength));
+ childPosIter = new KnuthPossPosIter(splitList, 0, splitList
+ .size());
+ //}
+ }
+
+ // if adjusted space before
+ if (bSpaceBefore) {
+ addBlockSpacing(0, new MinOptMax(adjustedSpaceBefore));
+ }
+
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // set last area flag
+ lc.setFlags(LayoutContext.LAST_AREA,
+ (layoutContext.isLastArea() && childLM == lastLM));
+ /*LF*/lc.setStackLimit(layoutContext.getStackLimit());
+ // Add the line areas to Area
+ childLM.addAreas(childPosIter, lc);
+ }
+
+ int bIndents = fobj.getCommonBorderPaddingBackground().getBPPaddingAndBorder(false);
+
+ addMarkers(false, false, true);
+
+ flush();
+
+ // if adjusted space after
+ if (bSpaceAfter) {
+ addBlockSpacing(0, new MinOptMax(adjustedSpaceAfter));
+ }
+
+ curBlockArea = null;
+ }
+
/**
* Return an Area which can contain the passed childArea. The childArea
* may not yet have any content, but it has essential traits set.
--- /dev/null
+/*
+ * 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;
+
+/**
+ * The interface for LayoutManagers which generate block areas
+ */
+public interface BlockLevelLayoutManager extends LayoutManager {
+
+ static final int NO_ADJUSTMENT = -1;
+ static final int SPACE_BEFORE_ADJUSTMENT = 0;
+ static final int SPACE_AFTER_ADJUSTMENT = 1;
+ static final int LINE_NUMBER_ADJUSTMENT = 2;
+ static final int LINE_HEIGHT_ADJUSTMENT = 3;
+
+ int negotiateBPDAdjustment(int adj, KnuthElement lastElement);
+
+ void discardSpace(KnuthGlue spaceGlue);
+
+ /**
+ * @return true if this element must be kept together
+ */
+ boolean mustKeepTogether();
+
+ /**
+ * @return true if this element must be kept with the previous element.
+ */
+ boolean mustKeepWithPrevious();
+
+ /**
+ * @return true if this element must be kept with the next element.
+ */
+ boolean mustKeepWithNext();
+
+}
package org.apache.fop.layoutmgr;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.area.Block;
+import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonMarginBlock;
+import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.traits.MinOptMax;
/**
//protected LayoutManager curChildLM = null; AbstractLayoutManager also defines this!
protected BlockParent parentArea = null;
+ /*LF*/
+ /** Value of the block-progression-unit (non-standard property) */
+ protected int bpUnit = 0;
+ /** space-before value adjusted for block-progression-unit handling */
+ protected int adjustedSpaceBefore = 0;
+ /** space-after value adjusted for block-progression-unit handling */
+ protected int adjustedSpaceAfter = 0;
+ /*LF*/
+
public BlockStackingLayoutManager(FObj node) {
super(node);
}
}
}
+ /**
+ * @param len length in millipoints to span with bp units
+ * @return the minimum integer n such that n * bpUnit >= len
+ */
+ protected int neededUnits(int len) {
+ return (int) Math.ceil((float)len / bpUnit);
+ }
+
+ /**
+ * Creates Knuth elements for before border padding and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param borderAndPadding border and padding to work with
+ */
+ protected void addKnuthElementForBorderPaddingBefore(LinkedList returnList,
+ Position returnPosition, CommonBorderPaddingBackground borderAndPadding) {
+ //Border and Padding (before)
+ //TODO Handle conditionality
+ int bpBefore = borderAndPadding.getBorderBeforeWidth(false)
+ + borderAndPadding.getPaddingBefore(false);
+ if (bpBefore > 0) {
+ returnList.add(new KnuthBox(bpBefore, returnPosition, true));
+ }
+ }
+
+ /**
+ * Creates Knuth elements for after border padding and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param borderAndPadding border and padding to work with
+ */
+ protected void addKnuthElementsForBorderPaddingAfter(LinkedList returnList,
+ Position returnPosition, CommonBorderPaddingBackground borderAndPadding) {
+ //Border and Padding (after)
+ //TODO Handle conditionality
+ int bpAfter = borderAndPadding.getBorderAfterWidth(false)
+ + borderAndPadding.getPaddingAfter(false);
+ if (bpAfter > 0) {
+ returnList.add(new KnuthBox(bpAfter, returnPosition, true));
+ }
+ }
+
+ /**
+ * Creates Knuth elements for break-before and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param breakBefore break-before value
+ * @return true if an element has been added due to a break-before.
+ */
+ protected boolean addKnuthElementsForBreakBefore(LinkedList returnList,
+ Position returnPosition, int breakBefore) {
+ if (breakBefore == EN_PAGE
+ || breakBefore == EN_EVEN_PAGE
+ || breakBefore == EN_ODD_PAGE) {
+ // return a penalty element, representing a forced page break
+ returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false,
+ breakBefore, returnPosition, false));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Creates Knuth elements for break-after and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param breakAfter break-after value
+ * @return true if an element has been added due to a break-after.
+ */
+ protected boolean addKnuthElementsForBreakAfter(LinkedList returnList,
+ Position returnPosition, int breakAfter) {
+ if (breakAfter == EN_PAGE
+ || breakAfter == EN_EVEN_PAGE
+ || breakAfter == EN_ODD_PAGE) {
+ // add a penalty element, representing a forced page break
+ returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false,
+ breakAfter, returnPosition, false));
+ /* LF *///System.out.println("BLM - break after!!");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Creates Knuth elements for space-before and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param alignment vertical alignment
+ * @param spaceBefore the space-before property
+ */
+ protected void addKnuthElementsForSpaceBefore(LinkedList returnList,
+ Position returnPosition, int alignment, SpaceProperty spaceBefore) {
+ // append elements representing space-before
+ if (bpUnit > 0
+ || !(spaceBefore.getMinimum().getLength().getValue() == 0
+ && spaceBefore.getMaximum().getLength().getValue() == 0)) {
+ if (!spaceBefore.getSpace().isDiscard()) {
+ // add elements to prevent the glue to be discarded
+ returnList.add(new KnuthBox(0, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
+ false, returnPosition, false));
+ }
+ if (bpUnit > 0) {
+ returnList.add(new KnuthGlue(0, 0, 0,
+ BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
+ returnPosition, true));
+ } else if (alignment == EN_JUSTIFY) {
+ returnList.add(new KnuthGlue(
+ spaceBefore.getOptimum().getLength().getValue(),
+ spaceBefore.getMaximum().getLength().getValue()
+ - spaceBefore.getOptimum().getLength().getValue(),
+ spaceBefore.getOptimum().getLength().getValue()
+ - spaceBefore.getMinimum().getLength().getValue(),
+ BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
+ returnPosition, true));
+ } else {
+ returnList.add(new KnuthGlue(
+ spaceBefore.getOptimum().getLength().getValue(),
+ 0, 0, BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
+ returnPosition, true));
+ }
+ }
+ }
+
+ /**
+ * Creates Knuth elements for space-after and adds them to the return list.
+ * @param returnList return list to add the additional elements to
+ * @param returnPosition applicable return position
+ * @param alignment vertical alignment
+ * @param spaceAfter the space-after property
+ */
+ protected void addKnuthElementsForSpaceAfter(LinkedList returnList, Position returnPosition,
+ int alignment, SpaceProperty spaceAfter) {
+ // append elements representing space-after
+ if (bpUnit > 0
+ || !(spaceAfter.getMinimum().getLength().getValue() == 0
+ && spaceAfter.getMaximum().getLength().getValue() == 0)) {
+ if (!spaceAfter.getSpace().isDiscard()) {
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
+ false, returnPosition, false));
+ }
+ if (bpUnit > 0) {
+ returnList.add(new KnuthGlue(0, 0, 0,
+ BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT,
+ returnPosition, true));
+ } else if (alignment == EN_JUSTIFY) {
+ returnList.add(new KnuthGlue(
+ spaceAfter.getOptimum().getLength().getValue(),
+ spaceAfter.getMaximum().getLength().getValue()
+ - spaceAfter.getOptimum().getLength().getValue(),
+ spaceAfter.getOptimum().getLength().getValue()
+ - spaceAfter.getMinimum().getLength().getValue(),
+ BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, returnPosition,
+ (!spaceAfter.getSpace().isDiscard()) ? false : true));
+ } else {
+ returnList.add(new KnuthGlue(
+ spaceAfter.getOptimum().getLength().getValue(), 0, 0,
+ BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, returnPosition,
+ (!spaceAfter.getSpace().isDiscard()) ? false : true));
+ }
+ if (!spaceAfter.getSpace().isDiscard()) {
+ returnList.add(new KnuthBox(0, returnPosition, true));
+ }
+ }
+ }
+
+ protected static class StackingIter extends PositionIterator {
+ StackingIter(Iterator parentIter) {
+ super(parentIter);
+ }
+
+ protected LayoutManager getLM(Object nextObj) {
+ return ((Position) nextObj).getLM();
+ }
+
+ protected Position getPos(Object nextObj) {
+ return ((Position) nextObj);
+ }
+ }
+
+ protected static class MappingPosition extends Position {
+ private int iFirstIndex;
+ private int iLastIndex;
+
+ public MappingPosition(LayoutManager lm, int first, int last) {
+ super(lm);
+ iFirstIndex = first;
+ iLastIndex = last;
+ }
+
+ public int getFirstIndex() {
+ return iFirstIndex;
+ }
+
+ public int getLastIndex() {
+ return iLastIndex;
+ }
+ }
+
+ /**
+ * "wrap" the Position inside each element moving the elements from
+ * SourceList to targetList
+ * @param sourceList source list
+ * @param targetList target list receiving the wrapped position elements
+ */
+ protected void wrapPositionElements(List sourceList, List targetList) {
+ ListIterator listIter = sourceList.listIterator();
+ while (listIter.hasNext()) {
+ KnuthElement tempElement;
+ tempElement = (KnuthElement) listIter.next();
+ //if (tempElement.getLayoutManager() != this) {
+ tempElement.setPosition(new NonLeafPosition(this,
+ tempElement.getPosition()));
+ //}
+ targetList.add(tempElement);
+ }
+ }
+
}
--- /dev/null
+/*
+ * 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.ListIterator;
+
+public abstract class BreakingAlgorithm {
+
+ private final int KNUTH_ALGORITHM = 0;
+ private final int FIRST_FIT_ALGORITHM = 1;
+
+ // this class represent a feasible breaking point
+ public class KnuthNode {
+ // index of the breakpoint represented by this node
+ public int position;
+
+ // number of the line ending at this breakpoint
+ public int line;
+
+ // fitness class of the line ending at his breakpoint
+ public int fitness;
+
+ // accumulated width of the KnuthElements
+ public int totalWidth;
+
+ // accumulated stretchability of the KnuthElements
+ public int totalStretch;
+
+ // accumulated shrinkability of the KnuthElements
+ public int totalShrink;
+
+ // adjustment ratio if the line ends at this breakpoint
+ public double adjustRatio;
+
+/*LF*/ public int availableShrink;
+/*LF*/ public int availableStretch;
+
+ // difference between target and actual line width
+ public int difference;
+
+ // minimum total demerits up to this breakpoint
+ public double totalDemerits;
+
+ // best node for the preceding breakpoint
+ public KnuthNode previous;
+
+ public KnuthNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink,
+ double adjustRatio, int availableShrink, int availableStretch, int difference,
+ double totalDemerits, KnuthNode previous) {
+ this.position = position;
+ this.line = line;
+ this.fitness = fitness;
+ this.totalWidth = totalWidth;
+ this.totalStretch = totalStretch;
+ this.totalShrink = totalShrink;
+ this.adjustRatio = adjustRatio;
+/*LF*/ this.availableShrink = availableShrink;
+/*LF*/ this.availableStretch = availableStretch;
+ this.difference = difference;
+ this.totalDemerits = totalDemerits;
+ this.previous = previous;
+ }
+ }
+
+ // this class stores information about how the nodes
+ // which could start a line
+ // ending at the current element
+ private class BestRecords {
+ private static final double INFINITE_DEMERITS = 1E11;
+
+ private double bestDemerits[] = {
+ INFINITE_DEMERITS, INFINITE_DEMERITS,
+ INFINITE_DEMERITS, INFINITE_DEMERITS
+ };
+ private KnuthNode bestNode[] = {null, null, null, null};
+ private double bestAdjust[] = {0.0, 0.0, 0.0, 0.0};
+ private int bestDifference[] = {0, 0, 0, 0};
+/*LF*/ private int bestAvailableShrink[] = {0, 0, 0, 0};
+/*LF*/ private int bestAvailableStretch[] = {0, 0, 0, 0};
+ private int bestIndex = -1;
+
+ public BestRecords() {
+ }
+
+ public void addRecord(double demerits, KnuthNode node, double adjust,
+ int availableShrink, int availableStretch, int difference, int fitness) {
+ if (demerits > bestDemerits[fitness]) {
+ //log.error("New demerits value greter than the old one");
+ }
+ bestDemerits[fitness] = demerits;
+ bestNode[fitness] = node;
+ bestAdjust[fitness] = adjust;
+/*LF*/ bestAvailableShrink[fitness] = availableShrink;
+/*LF*/ bestAvailableStretch[fitness] = availableStretch;
+ bestDifference[fitness] = difference;
+ if (bestIndex == -1 || demerits < bestDemerits[bestIndex]) {
+ bestIndex = fitness;
+ }
+ }
+
+ public boolean hasRecords() {
+ return (bestIndex != -1);
+ }
+
+ public boolean notInfiniteDemerits(int fitness) {
+ return (bestDemerits[fitness] != INFINITE_DEMERITS);
+ }
+
+ public double getDemerits(int fitness) {
+ return bestDemerits[fitness];
+ }
+
+ public KnuthNode getNode(int fitness) {
+ return bestNode[fitness];
+ }
+
+ public double getAdjust(int fitness) {
+ return bestAdjust[fitness];
+ }
+
+/*LF*/ public int getAvailableShrink(int fitness) {
+/*LF*/ return bestAvailableShrink[fitness];
+/*LF*/ }
+
+/*LF*/ public int getAvailableStretch(int fitness) {
+/*LF*/ return bestAvailableStretch[fitness];
+/*LF*/ }
+
+ public int getDifference(int fitness) {
+ return bestDifference[fitness];
+ }
+
+ public double getMinDemerits() {
+ if (bestIndex != -1) {
+ return getDemerits(bestIndex);
+ } else {
+ // anyway, this should never happen
+ return INFINITE_DEMERITS;
+ }
+ }
+ }
+
+ // parameters of Knuth's algorithm:
+ // penalty value for flagged penalties
+ private int flaggedPenalty = 50;
+ // demerit for consecutive lines ending at flagged penalties
+ private int repeatedFlaggedDemerit = 50;
+ // demerit for consecutive lines belonging to incompatible fitness classes
+ private int incompatibleFitnessDemerit = 50;
+ // suggested modification to the "optimum" number of lines
+ private int looseness = 0;
+
+ private static final int INFINITE_RATIO = 1000;
+ private static int MAX_DEMERITS_INCREASE = 1000;
+
+ protected LinkedList activeList = null;
+ protected LinkedList auxActiveList = null;
+// private LinkedList inactiveList = null;
+ private LinkedList auxInactiveList = null;
+ protected KnuthNode lastDeactivatedNode = null;
+ private KnuthNode lastTooLong;
+ private KnuthNode lastTooShort;
+ private KnuthNode lastDeactivated;
+
+ protected int alignment;
+ protected int alignmentLast;
+ protected boolean bFirst;
+
+ public BreakingAlgorithm(int align, int alignLast,
+ boolean first) {
+ alignment = align;
+ alignmentLast = alignLast;
+ bFirst = first;
+ }
+
+ public abstract void updateData1(int total, double demerits) ;
+
+ public abstract void updateData2(KnuthNode bestActiveNode,
+ KnuthSequence sequence,
+ int total) ;
+
+ public int findBreakingPoints(KnuthSequence par, int lineWidth,
+ double threshold, boolean force,
+ boolean hyphenationAllowed) {
+
+ findBreakingPoints(KNUTH_ALGORITHM, par, 0, lineWidth, threshold, force, hyphenationAllowed);
+
+ boolean bForced = false;
+ int optLineNumber;
+ if (activeList.size() > 0) {
+ // there is at least one set of breaking points
+ // select one or more active nodes, removing the others from the list
+ optLineNumber = filterActiveList();
+/* a causa delle modifiche di Finn Bock, non c'e' piu' bisogno di usare first fit */
+// } else if (force) {
+// // no set of breaking points, but must find one
+// // use a different algorithm
+///*LF*/ System.out.println("si ricorre all'algoritmo first fit dalla riga " + lastDeactivatedNode.line + " elemento " + (lastDeactivatedNode.position == 0 ? 0 :lastDeactivatedNode.position + 1));
+// findBreakingPoints(FIRST_FIT_ALGORITHM, par, lastDeactivatedNode.position == 0 ? 0 :lastDeactivatedNode.position + 1, lineWidth, threshold, force, hyphenationAllowed);
+// activeList.add(auxActiveList.getLast());
+// optLineNumber = ((KnuthNode) auxActiveList.getLast()).line;
+// bForced = true;
+ } else {
+ // no set of breaking points, do nothing
+ return 0;
+ }
+
+ // now, activeList is not empty:
+ // if bForced == true, there is ONLY one node in activeList
+ // if bForced == false, there is AT LEAST one node in activeList
+/*LF*/ //System.out.println("BA> ora activeList.size() = " + activeList.size());
+ ListIterator activeListIterator = activeList.listIterator();
+ while (activeListIterator.hasNext()) {
+ KnuthNode activeNode = (KnuthNode)activeListIterator.next();
+ int totalLines;
+ if (bForced) {
+ updateData1(optLineNumber, 0);
+ totalLines = optLineNumber;
+ auxActiveList.clear();
+ auxInactiveList.clear();
+ } else {
+ updateData1(activeNode.line, activeNode.totalDemerits);
+ totalLines = activeNode.line;
+ }
+ calculateBreakPoints(activeNode, par, totalLines);
+ }
+
+ activeList.clear();
+// inactiveList.clear();
+ return optLineNumber;
+ }
+
+/* ---------------------------- */
+ public int firstFit(KnuthSequence par, int lineWidth,
+ double threshold, boolean force) {
+ lastDeactivatedNode = new KnuthNode(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null);
+
+ findBreakingPoints(FIRST_FIT_ALGORITHM, par, 0, lineWidth, threshold, force, true);
+
+/*LF*/ activeList = new LinkedList();
+///*LF*/ inactiveList = new LinkedList();
+ activeList.add(auxActiveList.getLast());
+ int optLineNumber = ((KnuthNode) auxActiveList.getLast()).line;
+
+ // now, activeList is not empty:
+ // if bForced == true, there is ONLY one node in activeList
+ // if bForced == false, there is AT LEAST one node in activeList
+/*LF*/ //System.out.println("BA> ora activeList.size() = " + activeList.size());
+ ListIterator activeListIterator = activeList.listIterator();
+ while (activeListIterator.hasNext()) {
+ KnuthNode activeNode = (KnuthNode)activeListIterator.next();
+ int totalLines;
+ updateData1(optLineNumber, 0);
+ totalLines = optLineNumber;
+ auxActiveList.clear();
+ auxInactiveList.clear();
+ calculateBreakPoints(activeNode, par, totalLines);
+ }
+
+ activeList.clear();
+// inactiveList.clear();
+ return optLineNumber;
+ }
+/* ---------------------------- */
+
+ private void findBreakingPoints(int algorithm,
+ KnuthSequence par, int firstIndex,
+ int lineWidth,
+ double threshold, boolean force,
+ boolean hyphenationAllowed) {
+ int totalWidth = 0;
+ int totalStretch = 0;
+ int totalShrink = 0;
+
+ // reset lastTooShort and lastTooLong, as they could be not null
+ // because of previous calls to findBreakingPoints
+ lastTooShort = lastTooLong = null;
+
+ // current element in the paragraph
+ KnuthElement thisElement = null;
+ // previous element in the paragraph is a KnuthBox
+ boolean previousIsBox = false;
+
+/*LF*/ // index of the first KnuthBox in the sequence
+/*LF*/ int firstBoxIndex = firstIndex;
+/*LF*/ while (alignment != org.apache.fop.fo.Constants.EN_CENTER
+/*LF*/ && ! ((KnuthElement) par.get(firstBoxIndex)).isBox()) {
+/*LF*/ firstBoxIndex++;
+/*LF*/ }
+/*LF*/
+ // create an active node representing the starting point
+ if (algorithm == KNUTH_ALGORITHM) {
+ activeList = new LinkedList();
+/*LF*/ activeList.add(new KnuthNode(firstBoxIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
+// inactiveList = new LinkedList();
+ } else {
+ auxActiveList = new LinkedList();
+/*LF*/ auxActiveList.add(new KnuthNode(lastDeactivatedNode.position, lastDeactivatedNode.line, 1,
+ 0, 0, 0,
+ lastDeactivatedNode.adjustRatio,
+ 0, 0, lastDeactivatedNode.difference,
+ 0, lastDeactivatedNode.previous));
+ auxInactiveList = new LinkedList();
+ }
+
+ KnuthNode lastForced = (KnuthNode) activeList.getFirst();
+ // main loop
+/*LF*/ ListIterator paragraphIterator = par.listIterator(firstBoxIndex);
+/*LF*/ //System.out.println("");
+/*LF*/ //System.out.println("inizio main loop");
+ while (paragraphIterator.hasNext()) {
+ thisElement = (KnuthElement) paragraphIterator.next();
+/*LF*/ //System.out.println("main loop, elemento " + paragraphIterator.previousIndex());
+ if (thisElement.isBox()) {
+ // a KnuthBox object is not a legal line break
+ totalWidth += thisElement.getW();
+ previousIsBox = true;
+ } else if (thisElement.isGlue()) {
+ // a KnuthGlue object is a legal line break
+ // only if the previous object is a KnuthBox
+ if (previousIsBox) {
+ if (algorithm == KNUTH_ALGORITHM) {
+ considerLegalBreak(par, lineWidth, thisElement,
+ totalWidth, totalStretch, totalShrink,
+ threshold);
+ } else {
+ considerLegalBreak2(par, lineWidth, thisElement,
+ totalWidth, totalStretch, totalShrink,
+ threshold);
+ }
+ }
+ totalWidth += thisElement.getW();
+ totalStretch += ((KnuthGlue) thisElement).getY();
+ totalShrink += ((KnuthGlue) thisElement).getZ();
+ previousIsBox = false;
+ } else {
+ // a KnuthPenalty is a legal line break
+ // only if its penalty is not infinite;
+ // if hyphenationAllowed is false, ignore flagged penalties
+ if (((KnuthPenalty) thisElement).getP()
+ < KnuthElement.INFINITE
+ && (hyphenationAllowed || !((KnuthPenalty) thisElement).isFlagged())) {
+ if (algorithm == KNUTH_ALGORITHM) {
+ considerLegalBreak(par, lineWidth, thisElement,
+ totalWidth, totalStretch, totalShrink,
+ threshold);
+ } else {
+ considerLegalBreak2(par, lineWidth, thisElement,
+ totalWidth, totalStretch, totalShrink,
+ threshold);
+ }
+ }
+ previousIsBox = false;
+ }
+ /* *** inizio modifiche proposte da Finn Bock *** */
+ if (activeList.size() == 0) {
+ if (!force) {
+ return;
+ }
+/*LF*/ //System.out.println(" ");
+/*LF*/ //System.out.println(" lastTooShort.position= " + (lastTooShort == null ? -1 : lastTooShort.position) + " lastTooLong.position= " + (lastTooLong == null ? -1 : lastTooLong.position));
+ if (lastTooShort == null || lastForced.position == lastTooShort.position) {
+ lastForced = lastTooLong;
+ } else {
+ lastForced = lastTooShort;
+ }
+
+/*LF*/ //System.out.println(" Restarting: position= " + lastForced.position);
+/*LF*/ //System.out.println(" ");
+ lastForced.totalDemerits = 0;
+ activeList.add(lastForced);
+ totalWidth = lastForced.totalWidth;
+ totalStretch = lastForced.totalStretch;
+ totalShrink = lastForced.totalShrink;
+ lastTooShort = lastTooLong = null;
+ while (paragraphIterator.nextIndex() > (lastForced.position + 1)) {
+ paragraphIterator.previous();
+ }
+ }
+ /* *** fine modifiche proposte da Finn Bock *** */
+ }
+ }
+
+ private void considerLegalBreak2(LinkedList par, int lineWidth,
+ KnuthElement element,
+ int totalWidth, int totalStretch,
+ int totalShrink, double threshold) {
+ //System.out.println("(" + par.indexOf(element) + ")");
+ KnuthNode startNode = (KnuthNode) auxActiveList.getFirst();
+ KnuthNode endNode = auxActiveList.size() > 1 ? (KnuthNode) auxActiveList.getLast() : null;
+
+ // these are the new values that must be computed
+ // in order to define a new active node
+ int newWidth;
+ int newStretch;
+ int newShrink;
+ int newDifference;
+ double newRatio;
+
+ // compute width, stretch and shrink of the new node
+ newWidth = totalWidth;
+ newStretch = totalStretch;
+ newShrink = totalShrink;
+ ListIterator tempIterator = par.listIterator(par.indexOf(element));
+ while (tempIterator.hasNext()) {
+ KnuthElement tempElement = (KnuthElement)tempIterator.next();
+ if (tempElement.isBox()) {
+ break;
+ } else if (tempElement.isGlue()) {
+ newWidth += ((KnuthGlue) tempElement).getW();
+ newStretch += ((KnuthGlue) tempElement).getY();
+ newShrink += ((KnuthGlue) tempElement).getZ();
+ } else if (((KnuthPenalty) tempElement).getP()
+ == -KnuthElement.INFINITE
+ && tempElement != element) {
+ break;
+ }
+ }
+
+ if (endNode == null
+ || totalWidth + (element.isPenalty() ? element.getW() : 0) - startNode.totalWidth <= lineWidth
+ || alignment == org.apache.fop.fo.Constants.EN_JUSTIFY
+ && totalWidth + (element.isPenalty() ? element.getW() : 0)- startNode.totalWidth - (totalShrink - startNode.totalShrink) <= lineWidth) {
+ // add content to the same line
+
+ // compute difference and ratio
+ int actualWidth = totalWidth - startNode.totalWidth;
+ if (element.isPenalty()) {
+ actualWidth += element.getW();
+ }
+ newDifference = lineWidth - actualWidth;
+ int available = newDifference >= 0 ? totalStretch - startNode.totalStretch
+ : totalShrink - startNode.totalShrink;
+ newRatio = available != 0 ? (float) newDifference / available
+ : 0;
+
+ if (endNode != null) {
+ auxActiveList.removeLast();
+ }
+ auxActiveList.add(new KnuthNode(par.indexOf(element), startNode.line + 1, 0,
+ newWidth, newStretch, newShrink,
+ newRatio, 0, 0, newDifference, 0.0,
+ startNode));
+ //System.out.println("da " + startNode.position + " a " + par.indexOf(element));
+ //System.out.println("difference = " + newDifference + " available = " + available + " ratio = " + newRatio);
+ //System.out.println(" ");
+ } else {
+ // start a new line
+
+ // compute difference and ratio
+ int actualWidth = totalWidth - endNode.totalWidth;
+ if (element.isPenalty()) {
+ actualWidth += element.getW();
+ }
+ newDifference = lineWidth - actualWidth;
+ int available = newDifference >= 0 ? totalStretch - endNode.totalStretch
+ : totalShrink - endNode.totalShrink;
+ newRatio = available != 0 ? (float) newDifference / available
+ : 0;
+
+ auxInactiveList.add(auxActiveList.removeFirst());
+ auxActiveList.add(new KnuthNode(par.indexOf(element), endNode.line + 1, 0,
+ newWidth, newStretch, newShrink,
+ newRatio, 0, 0, newDifference, 0.0,
+ endNode));
+ //System.out.println("da " + endNode.position + " a " + par.indexOf(element));
+ //System.out.println("difference = " + newDifference + " available = " + available + " ratio = " + newRatio);
+ //System.out.println(" ");
+ }
+ }
+
+
+ private void considerLegalBreak(LinkedList par, int lineWidth,
+ KnuthElement element,
+ int totalWidth, int totalStretch,
+ int totalShrink, double threshold) {
+ KnuthNode activeNode = null;
+
+ ListIterator activeListIterator = activeList.listIterator();
+ if (activeListIterator.hasNext()) {
+ activeNode = (KnuthNode)activeListIterator.next();
+ } else {
+ activeNode = null;
+ }
+
+ lastDeactivated = null;
+ lastTooLong = null;
+
+ while (activeNode != null) {
+ BestRecords best = new BestRecords();
+
+ // these are the new values that must be computed
+ // in order to define a new active node
+ int newLine = 0;
+ int newFitnessClass = 0;
+ int newWidth = 0;
+ int newStretch = 0;
+ int newShrink = 0;
+ double newIPDAdjust = 0;
+ double newDemerits = 0;
+
+ while (activeNode != null) {
+ // compute the line number
+ newLine = activeNode.line + 1;
+
+ // compute the adjustment ratio
+ int actualWidth = totalWidth - activeNode.totalWidth;
+ if (element.isPenalty()) {
+ actualWidth += element.getW();
+ }
+ int neededAdjustment = lineWidth - actualWidth;
+ int maxAdjustment = 0;
+/*LF*/ int availableShrink = totalShrink - activeNode.totalShrink;
+/*LF*/ int availableStretch = totalStretch - activeNode.totalStretch;
+ if (neededAdjustment > 0) {
+ maxAdjustment = availableStretch;
+ if (maxAdjustment > 0) {
+ newIPDAdjust
+ = (double) neededAdjustment / maxAdjustment;
+ } else {
+ newIPDAdjust = INFINITE_RATIO;
+ }
+ } else if (neededAdjustment < 0) {
+ maxAdjustment = availableShrink;
+ if (maxAdjustment > 0) {
+ newIPDAdjust
+ = (double) neededAdjustment / maxAdjustment;
+ } else {
+ newIPDAdjust = -INFINITE_RATIO;
+ }
+/*LF*/ } else {
+/*LF*/ // neededAdjustment == 0
+/*LF*/ newIPDAdjust = 0;
+ }
+
+ /* calcola demeriti e fitness class in ogni caso, poi,
+ * a seconda che il coefficiente sia o meno nel range permesso,
+ * aggiorna i record o i migliori nodi disattivati
+ */
+ // compute demerits and fitness class
+ if (element.isPenalty()
+ && ((KnuthPenalty) element).getP() >= 0) {
+ newDemerits
+ = Math.pow((1
+ + 100 * Math.pow(Math.abs(newIPDAdjust), 3)
+ + ((KnuthPenalty) element).getP()), 2);
+ } else if (element.isPenalty()
+ && ((KnuthPenalty)element).getP()
+ > - KnuthElement.INFINITE) {
+ /*> -INFINITE_RATIO) { ??? */
+ newDemerits
+ = Math.pow((1
+ + 100 * Math.pow(Math.abs(newIPDAdjust), 3)), 2)
+ - Math.pow(((KnuthPenalty) element).getP(), 2);
+ } else {
+ newDemerits
+ = Math.pow((1
+ + 100 * Math.pow(Math.abs(newIPDAdjust), 3)), 2);
+ }
+ if (element.isPenalty()
+ && ((KnuthPenalty) element).isFlagged()
+ && ((KnuthElement) par.get(activeNode.position)).isPenalty()
+ && ((KnuthPenalty) par.get(activeNode.position)).isFlagged()) {
+ // add demerit for consecutive breaks at flagged penalties
+ newDemerits += repeatedFlaggedDemerit;
+ }
+ if (newIPDAdjust < -0.5) {
+ newFitnessClass = 0;
+ } else if (newIPDAdjust <= 0.5) {
+ newFitnessClass = 1;
+ } else if (newIPDAdjust <= 1) {
+ newFitnessClass = 2;
+ } else {
+ newFitnessClass = 3;
+ }
+ if (Math.abs(newFitnessClass - activeNode.fitness) > 1) {
+ // add demerit for consecutive breaks
+ // with very different fitness classes
+ newDemerits += incompatibleFitnessDemerit;
+ }
+ newDemerits += activeNode.totalDemerits;
+
+/*LF*/ //System.out.println(" possibile soluzione, da " + activeNode.position + " a " + par.indexOf(element));
+ if ((-1 <= newIPDAdjust) && (newIPDAdjust <= threshold)) {
+/*LF*/ //System.out.println(" possibile soluzione buona");
+ if (newDemerits < best.getDemerits(newFitnessClass)) {
+ // updates best demerits data
+ best.addRecord(newDemerits, activeNode, newIPDAdjust,
+ availableShrink, availableStretch, neededAdjustment, newFitnessClass);
+/*LF*/ lastTooShort = null;
+ }
+ } else {
+ // la linea e' troppo piena o troppo vuota
+ if (newIPDAdjust <= -1) {
+/*LF*/ //System.out.println(" possibile soluzione lunga");
+ if (lastTooLong == null || newDemerits < lastTooLong.totalDemerits) {
+/*LF*/ //System.out.println(" aggiornato lastTooLong, da " + activeNode.position + " a " + par.indexOf(element));
+ lastTooLong = new KnuthNode(par.indexOf(element), newLine, newFitnessClass,
+ totalWidth, totalStretch, totalShrink,
+ newIPDAdjust, availableShrink, availableStretch, neededAdjustment, newDemerits, activeNode);
+ }
+ } else {
+/*LF*/ //System.out.println(" possibile soluzione corta");
+/*LF*/ //if (lastTooShort != null) {
+/*LF*/ // System.out.println(" vecchia soluzione corta da " + lastTooShort.previous.position + " a " + lastTooShort.position);
+/*LF*/ //}
+ if (lastTooShort == null || newDemerits <= lastTooShort.totalDemerits) {
+/*LF*/ //System.out.println(" aggiornato lastTooShort, da " + activeNode.position + " a " + par.indexOf(element));
+ lastTooShort = new KnuthNode(par.indexOf(element), newLine, newFitnessClass,
+ totalWidth, totalStretch, totalShrink,
+ newIPDAdjust, availableShrink, availableStretch, neededAdjustment, newDemerits, activeNode);
+ }
+ }
+ }
+ /* disattivazione di un nodo */
+ if (newIPDAdjust < -1
+ || (element.isPenalty()
+ && ((KnuthPenalty)element).getP()
+ == -KnuthElement.INFINITE)
+/*LF*/ && !(activeNode.position
+ == par.indexOf(element))) {
+ // deactivate activeNode
+ KnuthNode tempNode
+ = (KnuthNode)activeListIterator.previous();
+ int iCallNext = 0;
+ while (tempNode != activeNode) {
+ // this is not the node we meant to remove!
+ tempNode = (KnuthNode)activeListIterator.previous();
+ iCallNext ++;
+ }
+ activeListIterator.remove();
+ for (int i = 0; i < iCallNext; i++) {
+ activeListIterator.next();
+ }
+ }
+
+ if (activeListIterator.hasNext()) {
+ activeNode = (KnuthNode) activeListIterator.next();
+ } else {
+ activeNode = null;
+ break;
+ }
+ if (activeNode.line >= newLine) {
+ break;
+ }
+ } // end of the inner while
+
+ if (best.hasRecords()) {
+ // compute width, stratchability and shrinkability
+ newWidth = totalWidth;
+ newStretch = totalStretch;
+ newShrink = totalShrink;
+ ListIterator tempIterator
+ = par.listIterator(par.indexOf(element));
+ while (tempIterator.hasNext()) {
+ KnuthElement tempElement
+ = (KnuthElement)tempIterator.next();
+ if (tempElement.isBox()) {
+ break;
+ } else if (tempElement.isGlue()) {
+ newWidth += ((KnuthGlue) tempElement).getW();
+ newStretch += ((KnuthGlue) tempElement).getY();
+ newShrink += ((KnuthGlue) tempElement).getZ();
+ } else if (((KnuthPenalty) tempElement).getP()
+ == -KnuthElement.INFINITE
+ && tempElement != element) {
+ break;
+ }
+ }
+
+ // add nodes to the active nodes list
+ for (int i = 0; i <= 3; i++) {
+ if (best.notInfiniteDemerits(i)
+ && best.getDemerits(i)
+ <= (best.getMinDemerits()
+ + incompatibleFitnessDemerit)) {
+ // the nodes in activeList must be ordered
+ // by line number and position;
+ // so:
+ // 1) advance in the list until the end,
+ // or a node with a higher line number, is reached
+/*LF*/ int iStepsForward = 0;
+/*LF*/ KnuthNode tempNode;
+/*LF*/ while (activeListIterator.hasNext()) {
+/*LF*/ iStepsForward ++;
+/*LF*/ tempNode = (KnuthNode) activeListIterator.next();
+/*LF*/ if (tempNode.line > (best.getNode(i).line + 1)) {
+/*LF*/ activeListIterator.previous();
+/*LF*/ iStepsForward --;
+/*LF*/ break;
+/*LF*/ }
+/*LF*/ }
+ // 2) add the new node
+ activeListIterator.add
+ (new KnuthNode(par.indexOf(element),
+ best.getNode(i).line + 1, i,
+ newWidth, newStretch, newShrink,
+ best.getAdjust(i),
+ best.getAvailableShrink(i), best.getAvailableStretch(i),
+ best.getDifference(i),
+ best.getDemerits(i),
+ best.getNode(i)));
+ // 3) go back
+/*LF*/ for (int j = 0;
+/*LF*/ j <= iStepsForward;
+/*LF*/ j ++) {
+/*LF*/ activeListIterator.previous();
+/*LF*/ }
+ }
+ }
+ }
+ if (activeNode == null) {
+ break;
+ }
+ } // end of the outer while
+ }
+
+ protected abstract int filterActiveList() ;
+
+ private void calculateBreakPoints(KnuthNode node, KnuthSequence par,
+ int total) {
+ KnuthNode bestActiveNode = node;
+ // use bestActiveNode to determine the optimum breakpoints
+ for (int i = node.line; i > 0; i--) {
+ updateData2(bestActiveNode, par, total);
+ bestActiveNode = bestActiveNode.previous;
+ }
+ }
+}
// node is a fo:Character
if (letterSpaceIPD.min == letterSpaceIPD.max) {
// constant letter space, only return a box
- returnList.add(new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false));
} else {
// at the moment the character is supposed to have no letter spaces,
// but returning this sequence allows us to change only one element
// if addALetterSpaceTo() is called
- returnList.add(new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false));
returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
returnList.add(new KnuthGlue(0, 0, 0,
new LeafPosition(this, -1), true));
- returnList.add(new KnuthBox(0, 0, 0, 0,
+ returnList.add(new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
}
if (letterSpaceIPD.min == letterSpaceIPD.max) {
// constant letter space, return a new box
- return new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ return new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false);
} else {
if (letterSpaceIPD.min == letterSpaceIPD.max
|| areaInfo.iLScount == 0) {
// constant letter space, or no letter space
- returnList.add(new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false));
if (areaInfo.bHyphenated) {
} else {
// adjustable letter space
returnList.add
- (new KnuthBox(areaInfo.ipdArea.opt
+ (new KnuthInlineBox(areaInfo.ipdArea.opt
- areaInfo.iLScount * letterSpaceIPD.opt,
areaInfo.lead, areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false));
areaInfo.iLScount * letterSpaceIPD.max - letterSpaceIPD.opt,
areaInfo.iLScount * letterSpaceIPD.opt - letterSpaceIPD.min,
new LeafPosition(this, -1), true));
- returnList.add(new KnuthBox(0, 0, 0, 0,
+ returnList.add(new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
if (areaInfo.bHyphenated) {
returnList.add
while (contentIter.hasNext()) {
KnuthElement element = (KnuthElement) contentIter.next();
if (element.isBox()) {
- KnuthBox box = (KnuthBox) element;
+ KnuthInlineBox box = (KnuthInlineBox) element;
if (box.getLead() > lineLead) {
lineLead = box.getLead();
}
return contentList;
}
- public KnuthElement addALetterSpaceTo(KnuthElement element) {
- return element;
+ public List addALetterSpaceTo(List oldList) {
+ return oldList;
}
public void getWordChars(StringBuffer sbChars, Position pos) {
}
public LinkedList getChangedKnuthElements(List oldList,
- int flaggedPenalty,
+ /*int flaggedPenalty,*/
int alignment) {
return null;
}
import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
+
import org.apache.fop.traits.MinOptMax;
/**
* This LM is responsible for getting columns of the appropriate size
* and filling them with block-level areas generated by its children.
*/
-public class FlowLayoutManager extends BlockStackingLayoutManager {
-
+public class FlowLayoutManager extends BlockStackingLayoutManager
+ implements BlockLevelLayoutManager {
private Flow fobj;
/** List of break possibilities */
*/
private int numSubsequentOverflows = 0;
+/*LF*/
+ private static class StackingIter extends PositionIterator {
+ StackingIter(Iterator parentIter) {
+ super(parentIter);
+ }
+
+ protected LayoutManager getLM(Object nextObj) {
+ return ((Position) nextObj).getLM();
+ }
+
+ protected Position getPos(Object nextObj) {
+ return ((Position) nextObj);
+ }
+ }
+/*LF*/
+
/**
* This is the top level layout manager.
* It is created by the PageSequence FO.
fobj = node;
}
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#getNextBreakPoss(LayoutContext)
- */
+ /*
public BreakPoss getNextBreakPoss(LayoutContext context) {
// currently active LM
new LeafPosition(this, blockBreaks.size() - 1));
}
return null;
+ }*/
+
+
+//TODO Reintroduce emergency counter (generate error to avoid endless loop)
+//TODO Reintroduce layout dimensions
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+ // currently active LM
+ BlockLevelLayoutManager curLM;
+ BlockLevelLayoutManager prevLM = null;
+ MinOptMax stackSize = new MinOptMax();
+ LinkedList returnedList;
+ LinkedList returnList = new LinkedList();
+
+ while ((curLM = ((BlockLevelLayoutManager) getChildLM())) != null) {
+ if (curLM.generatesInlineAreas()) {
+ log.error("inline area not allowed under flow - ignoring");
+ curLM.setFinished(true);
+ continue;
+ }
+
+ // Set up a LayoutContext
+ MinOptMax bpd = context.getStackLimit();
+ BreakPoss bp;
+ bp = null;
+
+ LayoutContext childLC = new LayoutContext(0);
+ boolean breakPage = false;
+ childLC.setStackLimit(MinOptMax.subtract(bpd, stackSize));
+ childLC.setRefIPD(context.getRefIPD());
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+/*LF*/ //System.out.println("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
+
+ // "wrap" the Position inside each element
+ LinkedList tempList = returnedList;
+ KnuthElement tempElement;
+ returnedList = new LinkedList();
+ ListIterator listIter = tempList.listIterator();
+ while (listIter.hasNext()) {
+ tempElement = (KnuthElement)listIter.next();
+ tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
+ returnedList.add(tempElement);
+ }
+
+ if (returnedList.size() == 1
+ && ((KnuthElement)returnedList.getFirst()).isPenalty()
+ && ((KnuthPenalty)returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this flow has break-before
+ returnList.addAll(returnedList);
+ return returnList;
+ } else {
+ if (returnList.size() > 0) {
+ // there is a block before this one
+ if (prevLM.mustKeepWithNext()
+ || curLM.mustKeepWithPrevious()) {
+ // add an infinite penalty to forbid a break between blocks
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, new Position(this), false));
+ } else if (!((KnuthElement) returnList.getLast()).isGlue()) {
+ // add a null penalty to allow a break between blocks
+ returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+ }
+ }
+/*LF*/ if (returnedList.size() > 0) { // controllare!
+ returnList.addAll(returnedList);
+ if (((KnuthElement)returnedList.getLast()).isPenalty()
+ && ((KnuthPenalty)returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
+ // a descendant of this flow has break-after
+/*LF*/ //System.out.println("FLM - break after!!");
+ return returnList;
+ }
+/*LF*/ }
+ }
+ prevLM = curLM;
+ }
+
+ setFinished(true);
+
+ if (returnList.size() > 0) {
+ return returnList;
+ } else {
+ return null;
+ }
+ }
+
+ public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+/*LF*/ System.out.println(" FLM.negotiateBPDAdjustment> " + adj);
+
+/*LF*/ if (lastElement.getPosition() instanceof NonLeafPosition) {
+ // this element was not created by this FlowLM
+ NonLeafPosition savedPos = (NonLeafPosition)lastElement.getPosition();
+ lastElement.setPosition(savedPos.getPosition());
+ int returnValue = ((BlockLevelLayoutManager) lastElement.getLayoutManager()).negotiateBPDAdjustment(adj, lastElement);
+ lastElement.setPosition(savedPos);
+/*LF*/ System.out.println(" FLM.negotiateBPDAdjustment> gestito " + returnValue);
+ return returnValue;
+/*LF*/ } else {
+/*LF*/ return 0;
+/*LF*/ }
+ }
+
+ public void discardSpace(KnuthGlue spaceGlue) {
+/*LF*/ System.out.println(" FLM.discardSpace> ");
+
+/*LF*/ if (spaceGlue.getPosition() instanceof NonLeafPosition) {
+ // this element was not created by this FlowLM
+ NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
+ spaceGlue.setPosition(savedPos.getPosition());
+ ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
+ spaceGlue.setPosition(savedPos);
+/*LF*/ }
+ }
+
+ public boolean mustKeepTogether() {
+ return false;
+ }
+
+ public boolean mustKeepWithPrevious() {
+ return false;
+ }
+
+ public boolean mustKeepWithNext() {
+ return false;
+ }
+
+ public LinkedList getChangedKnuthElements(List oldList, /*int flaggedPenalty,*/ int alignment) {
+ ListIterator oldListIterator = oldList.listIterator();
+ KnuthElement returnedElement;
+ LinkedList returnedList = new LinkedList();
+ LinkedList returnList = new LinkedList();
+ KnuthElement prevElement = null;
+ KnuthElement currElement = null;
+ int fromIndex = 0;
+
+/*LF*/ //System.out.println("");
+/*LF*/ //System.out.println("FLM.getChangedKnuthElements> prima dell'unwrap, oldList.size() = " + oldList.size() + " da 0 a " + (oldList.size() - 1));
+ // "unwrap" the Positions stored in the elements
+ KnuthElement oldElement;
+ while (oldListIterator.hasNext()) {
+ oldElement = (KnuthElement)oldListIterator.next();
+ if (oldElement.getPosition() instanceof NonLeafPosition) {
+ // oldElement was created by a descendant of this FlowLM
+ oldElement.setPosition(((NonLeafPosition)oldElement.getPosition()).getPosition());
+ } else {
+ // thisElement was created by this FlowLM, remove it
+ oldListIterator.remove();
+ }
+ }
+ // reset the iterator
+ oldListIterator = oldList.listIterator();
+
+/*LF*/ //System.out.println("FLM.getChangedKnuthElements> dopo l'unwrap, oldList.size() = " + oldList.size() + " da 0 a " + (oldList.size() - 1));
+
+ while (oldListIterator.hasNext()) {
+ currElement = (KnuthElement) oldListIterator.next();
+/*LF*/ //System.out.println("elemento n. " + oldListIterator.previousIndex() + " nella oldList");
+ if (prevElement != null
+ && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
+ // prevElement is the last element generated by the same LM
+ BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager)
+ prevElement.getLayoutManager();
+ BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
+ currElement.getLayoutManager();
+/*LF*/ //System.out.println("FLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + oldListIterator.previousIndex());
+ returnedList.addAll(prevLM.getChangedKnuthElements(oldList.subList(fromIndex, oldListIterator.previousIndex()),
+ /*flaggedPenalty,*/ alignment));
+ fromIndex = oldListIterator.previousIndex();
+
+ // there is another block after this one
+ if (prevLM.mustKeepWithNext()
+ || currLM.mustKeepWithPrevious()) {
+ // add an infinite penalty to forbid a break between blocks
+ returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, new Position(this), false));
+ } else if (!((KnuthElement) returnedList.getLast()).isGlue()) {
+ // add a null penalty to allow a break between blocks
+ returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+ }
+ }
+ prevElement = currElement;
+ }
+ if (currElement != null) {
+ BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
+ currElement.getLayoutManager();
+/*LF*/ //System.out.println("FLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + oldList.size());
+ returnedList.addAll(currLM.getChangedKnuthElements(oldList.subList(fromIndex, oldList.size()),
+ /*flaggedPenalty,*/ alignment));
+ }
+
+ // "wrap" the Position stored in each element of returnedList
+ // and add elements to returnList
+ ListIterator listIter = returnedList.listIterator();
+ while (listIter.hasNext()) {
+ returnedElement = (KnuthElement)listIter.next();
+ if (returnedElement.getLayoutManager() != this) {
+ returnedElement.setPosition(new NonLeafPosition(this, returnedElement.getPosition()));
+ }
+ returnList.add(returnedElement);
+ }
+
+ return returnList;
}
/**
* @see org.apache.fop.layoutmgr.LayoutManager#addAreas(PositionIterator, LayoutContext)
*/
public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
-
- LayoutManager childLM;
+ AreaAdditionUtil.addAreas(parentIter, layoutContext);
+ /*
+ LayoutManager childLM = null;
LayoutContext lc = new LayoutContext(0);
+ LayoutManager firstLM = null;
+ LayoutManager lastLM = null;
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ LinkedList positionList = new LinkedList();
+ Position pos;
while (parentIter.hasNext()) {
- LeafPosition lfp = (LeafPosition) parentIter.next();
- // Add the block areas to Area
- PositionIterator breakPosIter = new BreakPossPosIter(
- blockBreaks, iStartPos, lfp.getLeafPos() + 1);
- iStartPos = lfp.getLeafPos() + 1;
- while ((childLM = breakPosIter.getNextChildLM()) != null) {
- childLM.addAreas(breakPosIter, lc);
+ pos = (Position)parentIter.next();
+ if (pos instanceof NonLeafPosition) {
+ // pos was created by a child of this FlowLM
+ positionList.add(((NonLeafPosition) pos).getPosition());
+ lastLM = ((NonLeafPosition) pos).getPosition().getLM();
+ if (firstLM == null) {
+ firstLM = lastLM;
+ }
+ } else {
+ // pos was created by this FlowLM, so it must be ignored
}
}
+ StackingIter childPosIter = new StackingIter(positionList.listIterator());
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // Add the block areas to Area
+ lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
+ lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
+ // set space before for the first LM, in order to implement
+ // display-align = center or after
+ lc.setSpaceBefore((childLM == firstLM ? layoutContext.getSpaceBefore() : 0));
+ // set space after for each LM, in order to implement
+ // display-align = distribute
+ lc.setSpaceAfter(layoutContext.getSpaceAfter());
+ lc.setStackLimit(layoutContext.getStackLimit());
+ childLM.addAreas(childPosIter, lc);
+ }*/
+
flush();
}
return null;
}
+ /*
public KnuthElement addALetterSpaceTo(KnuthElement element) {
NonLeafPosition savedPos = (NonLeafPosition) element.getPosition();
element.setPosition(savedPos.getPosition());
returnList.add(returnedElement);
}
return returnList;
- }
+ }*/
}
/*
- * Copyright 2004 The Apache Software Foundation.
+ * 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.
package org.apache.fop.layoutmgr;
-import java.util.LinkedList;
import java.util.List;
/**
*/
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
+ * to the word fragment represented by the given elements,
+ * and returning the corrected elements
*
- * @param element the element which must be given one more letter space
- * @return the new element replacing the old one
+ * @param oldList the elements which must be given one more letter space
+ * @return the new elements replacing the old ones
*/
- KnuthElement addALetterSpaceTo(KnuthElement element);
+ List addALetterSpaceTo(List oldList);
/**
* Get the word chars corresponding to the given position
*/
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);
}
import java.util.LinkedList;
import java.util.Iterator;
+import java.util.List;
import java.util.ListIterator;
import java.util.HashMap;
import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.SpaceProperty;
+import org.apache.fop.traits.InlineProps;
import org.apache.fop.traits.SpaceVal;
import org.apache.fop.area.Area;
import org.apache.fop.area.inline.InlineArea;
* which stack children in the inline direction, such as Inline or
* Line. It should not be instantiated directly.
*/
-public class InlineStackingLayoutManager extends AbstractLayoutManager {
+public class InlineStackingLayoutManager extends AbstractLayoutManager
+ implements InlineLevelLayoutManager {
private static class StackingIter extends PositionIterator {
private Area currentArea; // LineArea or InlineParent
private BreakPoss prevBP;
- protected LayoutContext childLC ;
+ protected LayoutContext childLC;
private LayoutManager lastChildLM = null; // Set when return last breakposs
private boolean bAreaCreated = false;
// Current child layout context
protected LayoutContext getContext() {
- return childLC ;
+ return childLC;
}
protected void addSpace(Area parentArea, MinOptMax spaceRange,
}
}
}
+
+ 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);
+ 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 List addALetterSpaceTo(List oldList) {
+ // old list contains only a box, or the sequence: box penalty glue box
+
+ ListIterator oldListIterator = oldList.listIterator();
+ KnuthElement element = null;
+ // "unwrap" the Position stored in each element of oldList
+ while (oldListIterator.hasNext()) {
+ element = (KnuthElement) oldListIterator.next();
+ element.setPosition(((NonLeafPosition)element.getPosition()).getPosition());
+ }
+
+ oldList = ((InlineLevelLayoutManager)
+ element.getLayoutManager()).addALetterSpaceTo(oldList);
+
+ // "wrap" againg the Position stored in each element of oldList
+ oldListIterator = oldList.listIterator();
+ while (oldListIterator.hasNext()) {
+ element = (KnuthElement) oldListIterator.next();
+ element.setPosition(new NonLeafPosition(this, element.getPosition()));
+ }
+
+ return oldList;
+ }
+
+ 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;
+ }
}
--- /dev/null
+/*
+ * 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 org.apache.fop.traits.MinOptMax;
+
+public class KnuthBlockBox extends KnuthBox {
+
+ private MinOptMax ipdRange;
+ private int bpd;
+
+ public KnuthBlockBox(int w, MinOptMax range, int bpdim, Position pos, boolean bAux) {
+ super(w, pos, bAux);
+ ipdRange = (MinOptMax) range.clone();
+ bpd = bpdim;
+ }
+
+ public MinOptMax getIPDRange() {
+ return (MinOptMax) ipdRange.clone();
+ }
+
+ public int getBPD() {
+ return bpd;
+ }
+}
\ No newline at end of file
* positioning, and the methods used to get them.
*/
public class KnuthBox extends KnuthElement {
- private int lead;
- private int total;
- private int middle;
/**
* Create a new KnuthBox.
*
* @param w the width of this box
- * @param l the height of this box above the main baseline
- * @param t the total height of this box
- * @param m the height of this box above and below the middle baseline
* @param pos the Position stored in this box
* @param bAux is this box auxiliary?
*/
- public KnuthBox(int w, int l, int t, int m, Position pos, boolean bAux) {
+ public KnuthBox(int w, Position pos, boolean bAux) {
super(w, pos, bAux);
- lead = l;
- total = t;
- middle = m;
}
public boolean isBox() {
return true;
}
- /**
- * Return the height of this box above the main baseline.
- */
- public int getLead() {
- return lead;
- }
-
- /**
- * Return the total height of this box.
- */
- public int getTotal() {
- return total;
- }
-
- /**
- * Return the height of this box above and below the middle baseline.
- */
- public int getMiddle() {
- return middle;
- }
}
* to get these values.
*/
public class KnuthGlue extends KnuthElement {
+
private int stretchability;
private int shrinkability;
+ private int adjustmentClass = -1;
/**
* Create a new KnuthGlue.
shrinkability = z;
}
+ public KnuthGlue(int w, int y, int z,
+ int iAdjClass, Position pos, boolean bAux) {
+ super(w, pos, bAux);
+ stretchability = y;
+ shrinkability = z;
+ adjustmentClass = iAdjClass;
+ }
+
public boolean isGlue() {
return true;
}
public int getZ() {
return shrinkability;
}
+
+ public int getAdjustmentClass() {
+ return adjustmentClass;
+ }
+
}
--- /dev/null
+/*
+ * 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;
+
+public class KnuthInlineBox extends KnuthBox {
+
+ private int lead;
+ private int total;
+ private int middle;
+
+ /**
+ * Create a new KnuthBox.
+ *
+ * @param w the width of this box
+ * @param l the height of this box above the main baseline
+ * @param t the total height of this box
+ * @param m the height of this box above and below the middle baseline
+ * @param pos the Position stored in this box
+ * @param bAux is this box auxiliary?
+ */
+ public KnuthInlineBox(int w, int l, int t, int m, Position pos, boolean bAux) {
+ super(w, pos, bAux);
+ lead = l;
+ total = t;
+ middle = m;
+ }
+
+ /**
+ * @return the height of this box above the main baseline.
+ */
+ public int getLead() {
+ return lead;
+ }
+
+ /**
+ * @return the total height of this box.
+ */
+ public int getTotal() {
+ return total;
+ }
+
+ /**
+ * @return the height of this box above and below the middle baseline.
+ */
+ public int getMiddle() {
+ return middle;
+ }
+}
\ No newline at end of file
*/
/* $Id$ */
+
package org.apache.fop.layoutmgr;
-import java.util.ArrayList;
+import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The paragraph of KnuthElements.
*/
- private ArrayList par;
+ private List par;
/**
* The width of a line.
protected static Log log = LogFactory.getLog(KnuthParagraph.class);
- public KnuthParagraph(ArrayList par) {
+ public KnuthParagraph(List par) {
this.best = new BestRecords();
this.par = par;
}
* be chosen as breaking points for consecutive lines.
*/
public class KnuthPenalty extends KnuthElement {
+
private int penalty;
private boolean bFlagged;
+ private int breakClass = -1;
/**
* Create a new KnuthPenalty.
bFlagged = f;
}
+ public KnuthPenalty(int w, int p, boolean f,
+ int iBreakClass, Position pos, boolean bAux) {
+ super(w, pos, bAux);
+ penalty = p;
+ bFlagged = f;
+ breakClass = iBreakClass;
+ }
+
public boolean isPenalty() {
return true;
}
public boolean isForcedBreak() {
return penalty == -KnuthElement.INFINITE;
}
+
+ public int getBreakClass() {
+ return breakClass;
+ }
+
}
--- /dev/null
+
+package org.apache.fop.layoutmgr;
+
+import java.util.LinkedList;
+
+public class KnuthSequence extends LinkedList {
+ // number of KnuthElements added by the LineLayoutManager
+ public int ignoreAtStart = 0;
+ public int ignoreAtEnd = 0;
+
+ public KnuthSequence() {
+ }
+
+ public void startSequence() {
+ }
+
+ public KnuthSequence endSequence() {
+ // remove glue and penalty item at the end of the paragraph
+ while (this.size() > ignoreAtStart
+ && !((KnuthElement)this.get(this.size() - 1)).isBox()) {
+ this.remove(this.size() - 1);
+ }
+ if (this.size() > ignoreAtStart) {
+ // add the elements representing the space at the end of the last line
+ // and the forced break
+/*LF*/ this.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, null, false));
+/*LF*/ this.add(new KnuthGlue(0, 10000000, 0, null, false));
+ this.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
+ ignoreAtEnd = 3;
+ return this;
+ } else {
+ this.clear();
+ return null;
+ }
+ }
+}
private int iLineHeight;
private int iBaseline;
private int iMiddleShift;
+ private int iTopShift; /*LF*/
+ private int iBottomShift; /*LF*/
+ private int iSpaceBefore; /*LF*/
+ private int iSpaceAfter; /*LF*/
public LayoutContext(LayoutContext parentLC) {
this.flags = parentLC.flags;
this.iLineHeight = parentLC.iLineHeight;
this.iBaseline = parentLC.iBaseline;
this.iMiddleShift = parentLC.iMiddleShift;
+/*LF*/ this.iTopShift = parentLC.iTopShift;
+/*LF*/ this.iBottomShift = parentLC.iBottomShift;
+/*LF*/ this.iSpaceBefore = parentLC.iSpaceBefore;
+/*LF*/ this.iSpaceAfter = parentLC.iSpaceAfter;
// Copy other fields as necessary. Use clone???
}
return iBaseline + iMiddleShift;
}
+ public void setTopShift(int ts) {
+ iTopShift = ts;
+ }
+
+ public int getTopBaseline() {
+ return iBaseline + iTopShift;
+ }
+
+ public void setBottomShift(int bs) {
+ iBottomShift = bs;
+ }
+
+ public int getBottomBaseline() {
+ return iBaseline + iBottomShift;
+ }
+
+ public int getSpaceBefore() {
+ return iSpaceBefore;
+ }
+
+ public void setSpaceBefore(int sp) {
+ iSpaceBefore = sp;
+ }
+
+ public int getSpaceAfter() {
+ return iSpaceAfter;
+ }
+
+ public void setSpaceAfter(int sp) {
+ iSpaceAfter = sp;
+ }
+
public String toString() {
return "Layout Context:" +
"\nStack Limit: \t" + (getStackLimit() == null ? "null" : getStackLimit().toString()) +
package org.apache.fop.layoutmgr;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
* @param newLMs the list of LMs to be added
*/
void addChildLMs(List newLMs);
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+
+ public static final int FLAGGED_PENALTY = 50;
+
}
lead, total, middle);
// node is a fo:Leader
- returnList.add(new KnuthBox(0, areaInfo.lead, areaInfo.total,
+ returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
areaInfo.middle,
new LeafPosition(this, -1), true));
returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
areaInfo.ipdArea.opt - areaInfo.ipdArea.min,
new LeafPosition(this, 0), false));
- returnList.add(new KnuthBox(0, areaInfo.lead, areaInfo.total,
+ returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
areaInfo.middle,
new LeafPosition(this, -1), true));
LinkedList returnList = new LinkedList();
- returnList.add(new KnuthBox(0, areaInfo.lead, areaInfo.total,
+ returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
areaInfo.middle,
new LeafPosition(this, -1), true));
returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
areaInfo.ipdArea.opt - areaInfo.ipdArea.min,
new LeafPosition(this, 0), false));
- returnList.add(new KnuthBox(0, areaInfo.lead, areaInfo.total,
+ returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
areaInfo.middle,
new LeafPosition(this, -1), true));
super(node);
}
+ /**
+ * Create a Leaf node layout mananger.
+ */
+ public LeafNodeLayoutManager() {
+ }
+
/**
* get the inline area.
* @param context the context used to create the area
curArea.setOffset(context.getMiddleBaseline() - bpd / 2);
break;
case EN_TOP:
- //curArea.setOffset(0);
+ curArea.setOffset(context.getTopBaseline());
break;
case EN_BOTTOM:
- curArea.setOffset(context.getLineHeight() - bpd);
+ curArea.setOffset(context.getBottomBaseline() - bpd);
break;
case EN_BASELINE:
default:
// node is a fo:ExternalGraphic, fo:InstreamForeignObject,
// fo:PageNumber or fo:PageNumberCitation
- returnList.add(new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
areaInfo.total, areaInfo.middle,
new LeafPosition(this, 0), false));
setFinished(true);
return returnList;
}
- public void getWordChars(StringBuffer sbChars, Position bp) {
+ public List addALetterSpaceTo(List oldList) {
+ // return the unchanged elements
+ return oldList;
}
- public KnuthElement addALetterSpaceTo(KnuthElement element) {
- // return the unchanged box object
- return new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
- areaInfo.total, areaInfo.middle,
- new LeafPosition(this, 0), false);
+ public void getWordChars(StringBuffer sbChars, Position pos) {
}
public void hyphenate(Position pos, HyphContext hc) {
}
public LinkedList getChangedKnuthElements(List oldList,
- int flaggedPenalty,
+ /*int flaggedPenalty,*/
int alignment) {
if (isFinished()) {
return null;
// fobj is a fo:ExternalGraphic, fo:InstreamForeignObject,
// fo:PageNumber or fo:PageNumberCitation
- returnList.add(new KnuthBox(areaInfo.ipdArea.opt, areaInfo.lead,
- areaInfo.total, areaInfo.middle,
- new LeafPosition(this, 0), true));
+ returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+ areaInfo.total, areaInfo.middle,
+ new LeafPosition(this, 0), true));
setFinished(true);
return returnList;
* creates a line area to contain the inline areas added by the
* child layout managers.
*/
-public class LineLayoutManager extends InlineStackingLayoutManager {
+public class LineLayoutManager extends InlineStackingLayoutManager
+ implements BlockLevelLayoutManager {
+
private Block fobj;
- /**
- * Create a new Line Layout Manager.
- * This is used by the block layout manager to create
- * line managers for handling inline areas flowing into line areas.
- *
- * @param lh the default line height
- * @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, int ms) {
- super(node);
- fobj = node;
- // the child FObj are owned by the parent BlockLM
- // this LM has all its childLMs preloaded
- fobjIter = null;
- lineHeight = lh;
- lead = l;
- follow = f;
- middleShift = ms;
- initialize(); // Normally done when started by parent!
- }
-
/**
* @see org.apache.fop.layoutmgr.AbstractLayoutManager#initProperties()
*/
private static class LineBreakPosition extends LeafPosition {
// int iPos;
int iParIndex; // index of the Paragraph this Position refers to
+/*LF*/ int availableShrink;
+/*LF*/ int availableStretch;
+/*LF*/ int difference;
double dAdjust; // Percentage to adjust (stretch or shrink)
double ipdAdjust; // Percentage to adjust (stretch or shrink)
int startIndent;
int lineHeight;
+/*LF*/ int lineWidth;
int baseline;
+/*LF*/ int topShift;
+/*LF*/ int bottomShift;
LineBreakPosition(LayoutManager lm, int index, int iBreakIndex,
- double ipdA, double adjust, int ind, int lh, int bl) {
+ int shrink, int stretch, int diff,
+ double ipdA, double adjust, int ind,
+ int lh, int lw, int bl, int ts, int bs) {
super(lm, iBreakIndex);
- // iPos = iBreakIndex;
+/*LF*/ availableShrink = shrink;
+/*LF*/ availableStretch = stretch;
+/*LF*/ difference = diff;
iParIndex = index;
ipdAdjust = ipdA;
dAdjust = adjust;
startIndent = ind;
lineHeight = lh;
+/*LF*/ lineWidth = lw;
baseline = bl;
+/*LF*/ topShift = ts;
+/*LF*/ bottomShift = bs;
}
}
/** Break positions returned by inline content. */
- private List vecInlineBreaks = new ArrayList();
+ private List vecInlineBreaks = new java.util.ArrayList();
private BreakPoss prevBP = null; // Last confirmed break position
private int bTextAlignment = EN_JUSTIFY;
private int bTextAlignmentLast;
private int effectiveAlignment;
private Length textIndent;
+ private int iIndents = 0;
private CommonHyphenation hyphProps;
+ //private LayoutProps layoutProps; /*LF*/
private int lineHeight;
private int lead;
// offset of the middle baseline with respect to the main baseline
private int middleShift;
- private ArrayList knuthParagraphs = null;
- private ArrayList breakpoints = null;
+ private List knuthParagraphs = null;
+ private List breakpoints = null;
private int iReturnedLBP = 0;
private int iStartElement = 0;
private int iEndElement = 0;
// penalty value for flagged penalties
private int flaggedPenalty = 50;
+ private LineLayoutPossibilities lineLayouts;
+ private List lineLayoutsList;
+ private int iLineWidth = 0; /*LF*/
+
// 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
}
// this class represents a paragraph
- public class Paragraph extends ArrayList {
- // number of KnuthElements added by the LineLayoutManager
- public int ignoreAtStart = 0;
- public int ignoreAtEnd = 0;
- // minimum space at the end of the last line (in millipoints)
- public int lineFillerWidth;
-
- public void startParagraph(int lineWidth) {
+ private class Paragraph extends KnuthSequence {
+ // space at the end of the last line (in millipoints)
+ private MinOptMax lineFiller;
+ private int textAlignment;
+ private int textAlignmentLast;
+ private int textIndent;
+ private int lineWidth;
+ // the LM which created the paragraph
+ private LineLayoutManager layoutManager;
+
+ public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
+ int indent) {
+ super();
+ layoutManager = llm;
+ textAlignment = alignment;
+ textAlignmentLast = alignmentLast;
+ textIndent = indent;
+ }
+
+ public void startParagraph(int lw) {
+ lineWidth = lw;
+ startSequence();
+ }
+
+ public void startSequence() {
// set the minimum amount of empty space at the end of the
// last line
if (bTextAlignment == EN_CENTER) {
- lineFillerWidth = 0;
+ lineFiller = new MinOptMax(0);
} else {
- lineFillerWidth = (int)(lineWidth / 12);
+ lineFiller = new MinOptMax(0, (int)(lineWidth / 12), lineWidth);
}
// add auxiliary elements at the beginning of the paragraph
// add the element representing text indentation
// at the beginning of the first paragraph
if (knuthParagraphs.size() == 0
- && textIndent.getValue() != 0) {
- this.add(new KnuthBox(textIndent.getValue(), 0, 0, 0,
+ && fobj.getTextIndent().getValue() != 0) {
+ this.add(new KnuthInlineBox(fobj.getTextIndent().getValue(), 0, 0, 0,
null, false));
ignoreAtStart ++;
}
}
public void endParagraph() {
+ KnuthSequence finishedPar = this.endSequence();
+ if (finishedPar != null) {
+ knuthParagraphs.add(finishedPar);
+ }
+ }
+
+ public KnuthSequence endSequence() {
// remove glue and penalty item at the end of the paragraph
while (this.size() > ignoreAtStart
- && !((KnuthElement) this.get(this.size() - 1)).isBox()) {
+ && !((KnuthElement)this.get(this.size() - 1)).isBox()) {
this.remove(this.size() - 1);
}
if (this.size() > ignoreAtStart) {
// add the elements representing the space
// at the end of the last line
// and the forced break
- this.add(new KnuthPenalty(0, KnuthElement.INFINITE,
+ this.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, null, false));
- this.add(new KnuthGlue(lineFillerWidth, 10000000, 0,
- null, false));
+ this.add(new KnuthGlue(lineFiller.opt,
+ lineFiller.max - lineFiller.opt,
+ lineFiller.opt - lineFiller.min, null, false));
this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
false, null, false));
ignoreAtEnd = 3;
false, null, false));
ignoreAtEnd = 1;
}
- knuthParagraphs.add(this);
+ return this;
+ } else {
+ this.clear();
+ return null;
}
}
- public KnuthElement getLast() {
- int idx = size();
- if (idx == 0) {
- return null;
+ }
+
+ private class LineBreakingAlgorithm extends BreakingAlgorithm {
+ private LineLayoutManager thisLLM;
+ private int pageAlignment;
+ private int activePossibility;
+ private int addedPositions;
+ private int textIndent;
+ private int fillerMinWidth;
+ private int lineHeight;
+ private int lead;
+ private int follow;
+ private int middleshift;
+ private int maxDiff;
+ private static final double MAX_DEMERITS = 10e6;
+
+ public LineBreakingAlgorithm (int pageAlign,
+ int textAlign, int textAlignLast,
+ int indent, int fillerWidth,
+ int lh, int ld, int fl, int ms, boolean first,
+ LineLayoutManager llm) {
+ super(textAlign, textAlignLast, first);
+ pageAlignment = pageAlign;
+ textIndent = indent;
+ fillerMinWidth = fillerWidth;
+ lineHeight = lh;
+ lead = ld;
+ follow = fl;
+ middleshift = ms;
+ thisLLM = llm;
+ activePossibility = -1;
+ maxDiff = fobj.getWidows() >= fobj.getOrphans()
+ ? fobj.getWidows()
+ : fobj.getOrphans();
+ }
+
+ public void updateData1(int number, double demerits) {
+ lineLayouts.addPossibility(number, demerits);
+ //System.out.println("Possibilita' di layout in " + number + " linee; break alle posizioni:");
+ }
+
+ public void updateData2(KnuthNode bestActiveNode,
+ KnuthSequence par,
+ int total) {
+ // compute indent and adjustment ratio, according to
+ // the value of text-align and text-align-last
+ int indent = 0;
+ int difference = (bestActiveNode.line < total) ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth;
+ int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
+ indent += (textAlign == Constants.EN_CENTER) ?
+ difference / 2 :
+ (textAlign == Constants.EN_END) ? difference : 0;
+ indent += (bestActiveNode.line == 1 && bFirst) ?
+ textIndent : 0;
+ double ratio = (textAlign == Constants.EN_JUSTIFY
+ || bestActiveNode.adjustRatio < 0) ? bestActiveNode.adjustRatio : 0;
+
+ // add nodes at the beginning of the list, as they are found
+ // backwards, from the last one to the first one
+
+ // the first time this method is called, initialize activePossibility
+ // O SEMPLICEMENTE INIZIALIZZARE activePossibility A 0 NELLA DICHIARAZIONE?
+ if (activePossibility == -1) {
+ activePossibility = 0;
+ addedPositions = 0;
}
- return (KnuthElement) get(idx - 1);
+
+ if (addedPositions == lineLayouts.getLineNumber(activePossibility)) {
+ activePossibility ++;
+ addedPositions = 0;
+/*LF*/ //System.out.println(" ");
+ }
+
+/*LF*/ //System.out.println("LLM> (" + (lineLayouts.getLineNumber(activePossibility) - addedPositions) + ") difference = " + difference + " ratio = " + ratio);
+ lineLayouts.addBreakPosition(makeLineBreakPosition(par,
+ (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1: 0),
+ bestActiveNode.position,
+ bestActiveNode.availableShrink - (addedPositions > 0 ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min), bestActiveNode.availableStretch, difference, ratio, indent),
+ activePossibility);
+ addedPositions ++;
+ }
+
+ /* reinizializza le variabili in modo da comportarsi come se
+ * non ci fosse stato un tentativo precedente
+ */
+ public void resetAlgorithm() {
+ activePossibility = -1;
+ }
+
+ private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
+ int firstElementIndex,
+ int lastElementIndex,
+ int availableShrink, int availableStretch, int difference,
+ double ratio,
+ int indent) {
+ // line height calculation
+
+ int halfLeading = (lineHeight - lead - follow) / 2;
+ // height before the main baseline
+ /*LF*/ int lineLead = lead;
+ // maximum size of top and bottom alignment
+ /*LF*/ int maxtb = follow;
+ // max size of middle alignment before and after the middle baseline
+ int middlefollow = maxtb;
+
+/*LF*/ // if line-stacking-strategy is "font-height", the line height
+/*LF*/ // is not affected by its content
+/*LF*/ if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) {
+ ListIterator inlineIterator
+ = par.listIterator(firstElementIndex);
+ for (int j = firstElementIndex;
+ j <= lastElementIndex;
+ j++) {
+ KnuthElement element = (KnuthElement) inlineIterator.next();
+ if (element.isBox()) {
+ if (((KnuthInlineBox) element).getLead() > lineLead) {
+ lineLead = ((KnuthInlineBox) element).getLead();
+ }
+ if (((KnuthInlineBox) element).getTotal() > maxtb) {
+ maxtb = ((KnuthInlineBox) element).getTotal();
+ }
+ if (((KnuthInlineBox) element).getMiddle() > lineLead + middleShift) {
+ lineLead += ((KnuthInlineBox) element).getMiddle()
+ - lineLead - middleShift;
+ }
+ if (((KnuthInlineBox) element).getMiddle() > middlefollow - middleShift) {
+ middlefollow += ((KnuthInlineBox) element).getMiddle()
+ - middlefollow + middleShift;
+ }
+ }
+ }
+
+ if (maxtb - lineLead > middlefollow) {
+ middlefollow = maxtb - lineLead;
+ }
+/*LF*/ }
+
+ /*LF*/ //lineLead += halfLeading;
+ /*LF*/ //middlefollow += lineHeight - lead - follow - halfLeading;
+
+/*LF*/ constantLineHeight = lineLead + middlefollow + (lineHeight - lead - follow);
+/*LF*/ //System.out.println("teorica: " + lineHeight + " reale: " + (lineLead + middlefollow + (lineHeight - lead - follow)) + " halfleading = " + halfLeading + " e " + (lineHeight - lead - follow - halfLeading));
+
+ return new LineBreakPosition(thisLLM,
+ knuthParagraphs.indexOf(par),
+ lastElementIndex,
+ availableShrink, availableStretch, difference, ratio, 0, indent,
+ lineLead + middlefollow + (lineHeight - lead - follow), iLineWidth,
+ lineLead + halfLeading,
+ - lineLead, middlefollow);
}
- public KnuthElement removeLast() {
- int idx = size();
- if (idx == 0) {
- return null;
+ public int findBreakingPoints(Paragraph par, int lineWidth,
+ double threshold, boolean force,
+ boolean hyphenationAllowed) {
+ return super.findBreakingPoints(par, lineWidth, threshold, force, hyphenationAllowed);
+ }
+
+ protected int filterActiveList() {
+ KnuthNode bestActiveNode = null;
+
+ if (pageAlignment == EN_JUSTIFY) {
+ // leave all active nodes in the activeList
+ // and find the optimum line number
+ ListIterator activeListIterator = activeList.listIterator();
+ KnuthNode tempNode = null;
+ //System.out.println("LBA.filterActiveList> " + activeList.size() + " possibilita'");
+ while (activeListIterator.hasNext()) {
+ tempNode = (KnuthNode)activeListIterator.next();
+ //System.out.println(" + linee= " + tempNode.line + " demeriti= " + tempNode.totalDemerits);
+ if (bestActiveNode == null
+ || tempNode.totalDemerits < bestActiveNode.totalDemerits) {
+ bestActiveNode = tempNode;
+ }
+ }
+
+ // scan activeList once again and remove some nodes
+ activeListIterator = activeList.listIterator();
+ tempNode = null;
+ //System.out.println("LBA.filterActiveList> cernita");
+ while (activeListIterator.hasNext()) {
+ tempNode = (KnuthNode)activeListIterator.next();
+ //if (Math.abs(tempNode.line - bestActiveNode.line) > maxDiff) {
+ //if (false) {
+ if (tempNode.line != bestActiveNode.line
+ && tempNode.totalDemerits > MAX_DEMERITS) {
+ //System.out.println(" XXX linee= " + tempNode.line + " demeriti= " + tempNode.totalDemerits);
+ activeListIterator.remove();
+ } else {
+ //System.out.println(" ok linee= " + tempNode.line + " demeriti= " + tempNode.totalDemerits);
+ }
+ }
+ } else {
+ // leave only bestActiveNode in the activeList
+ KnuthNode tempNode = null;
+ //System.out.println("LBA.filterActiveList> " + activeList.size() + " possibilita'");
+ while (activeList.size() > 0) {
+ tempNode = (KnuthNode)activeList.removeFirst();
+ //System.out.println(" + linee= " + tempNode.line + " demeriti= " + tempNode.totalDemerits);
+ if (bestActiveNode == null
+ || tempNode.totalDemerits < bestActiveNode.totalDemerits) {
+ bestActiveNode = tempNode;
+ }
+ }
+ activeList.add(bestActiveNode);
}
- return (KnuthElement) remove(idx - 1);
+ //System.out.println(" migliore " + bestActiveNode.line);
+ return bestActiveNode.line;
}
}
+/*LF*/
+ private int constantLineHeight = 12000;
+/*LF*/
+
+ /**
+ * Create a new Line Layout Manager.
+ * This is used by the block layout manager to create
+ * line managers for handling inline areas flowing into line areas.
+ *
+ * @param lh the default line height
+ * @param l the default lead, from top to baseline
+ * @param f the default follow, from baseline to bottom
+ */
+ public LineLayoutManager(Block block, int lh, int l, int f, int ms) {
+ super(block);
+ fobj = block;
+ // the child FObj are owned by the parent BlockLM
+ // this LM has all its childLMs preloaded
+ fobjIter = null;
+ lineHeight = lh;
+ lead = l;
+ follow = f;
+/*LF*/ middleShift = ms;
+ initialize(); // Normally done when started by parent!
+ }
/**
* Call child layout managers to generate content.
* @param context the layout context for finding breaks
* @return the next break position
*/
+ // this method is no longer used
public BreakPoss getNextBreakPoss(LayoutContext context) {
+ setFinished(true);
+ return null;
+ }
+
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
// Get a break from currently active child LM
// Set up constraints for inline level managers
InlineLevelLayoutManager curLM ; // currently active LM
// here starts Knuth's algorithm
KnuthElement thisElement = null;
LinkedList returnedList = null;
+ iLineWidth = context.getStackLimit().opt;
// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
boolean bPrevWasKnuthBox = false;
KnuthBox prevBox = null;
- Paragraph knuthPar = new Paragraph();
+ Paragraph knuthPar = new Paragraph(this,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue());
knuthPar.startParagraph(availIPD.opt);
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
if ((returnedList
if (thisElement.isBox() && !thisElement.isAuxiliary()
&& bPrevWasKnuthBox) {
prevBox = (KnuthBox) knuthPar.removeLast();
+ LinkedList oldList = new LinkedList();
// 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.add(((InlineLevelLayoutManager)
- prevBox.getLayoutManager())
- .addALetterSpaceTo(prevBox));
+ oldList.add(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.add(auxPenalty);
- knuthPar.add(((InlineLevelLayoutManager)
- prevBox.getLayoutManager())
- .addALetterSpaceTo(prevBox));
- knuthPar.add(auxBox);
+ oldList.add(prevBox);
+ oldList.addFirst((KnuthGlue) knuthPar.removeLast());
+ oldList.addFirst((KnuthPenalty) knuthPar.removeLast());
}
+ // adding a letter space could involve, according to the text
+ // represented by oldList, replacing a glue element or adding
+ // new elements
+ knuthPar.addAll(((InlineLevelLayoutManager)
+ prevBox.getLayoutManager())
+ .addALetterSpaceTo(oldList));
}
// look at the last element
if (knuthPar.size() == 0) {
//only a forced linefeed on this line
//-> compensate with a zero width box
- knuthPar.add(new KnuthBox(0, 0, 0, 0,
+ knuthPar.add(new KnuthInlineBox(0, 0, 0, 0,
null, false));
}
knuthPar.endParagraph();
- knuthPar = new Paragraph();
+ knuthPar = new Paragraph(this,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue());
knuthPar.startParagraph(availIPD.opt);
bPrevWasKnuthBox = false;
}
}
//PHASE 2: Create line breaks
-
+ return findOptimalLineBreakingPoints(alignment);
+ /*
LineBreakPosition lbp = null;
if (breakpoints == null) {
// find the optimal line breaking points for each paragraph
currPar = (Paragraph) paragraphsIterator.previous();
findBreakingPoints(currPar, context.getStackLimit().opt);
}
- }
+ }*/
//PHASE 3: Return lines
+ /*
// get a break point from the list
lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
if (iReturnedLBP == breakpoints.size()) {
curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
return curLineBP;
+ */
}
/**
* into lines
* @param lineWidth the desired length ot the lines
*/
+ /*
private void findBreakingPoints(Paragraph par, int lineWidth) {
// maximum adjustment ratio permitted
float maxAdjustment = 1;
j++) {
KnuthElement element = (KnuthElement) inlineIterator.next();
if (element.isBox()) {
- if (((KnuthBox) element).getLead() > lineLead) {
- lineLead = ((KnuthBox) element).getLead();
+ KnuthInlineBox box = (KnuthInlineBox)element;
+ if (box.getLead() > lineLead) {
+ lineLead = box.getLead();
}
- if (((KnuthBox) element).getTotal() > maxtb) {
- maxtb = ((KnuthBox) element).getTotal();
+ if (box.getTotal() > maxtb) {
+ maxtb = box.getTotal();
}
- if (((KnuthBox) element).getMiddle() > lineLead + middleShift) {
- lineLead += ((KnuthBox) element).getMiddle()
+ if (box.getMiddle() > lineLead + middleShift) {
+ lineLead += box.getMiddle()
- lineLead - middleShift;
}
- if (((KnuthBox) element).getMiddle() > middlefollow - middleShift) {
- middlefollow += ((KnuthBox) element).getMiddle()
+ if (box.getMiddle() > middlefollow - middleShift) {
+ middlefollow += box.getMiddle()
- middlefollow + middleShift;
}
}
ratio, 0, indent,
lineLead + middlefollow,
lineLead));
+ }*/
+
+
+ private LinkedList findOptimalLineBreakingPoints(int alignment) {
+
+ // find the optimal line breaking points for each paragraph
+ ListIterator paragraphsIterator
+ = knuthParagraphs.listIterator(knuthParagraphs.size());
+ Paragraph currPar = null;
+/*LF*/ LineBreakingAlgorithm alg;
+/*LF*/ lineLayoutsList = new ArrayList(knuthParagraphs.size());
+ while (paragraphsIterator.hasPrevious()) {
+/*LF*/ lineLayouts = new LineLayoutPossibilities();
+ currPar = (Paragraph) paragraphsIterator.previous();
+ double maxAdjustment = 1;
+ int iBPcount = 0;
+ alg = new LineBreakingAlgorithm(alignment,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue(), currPar.lineFiller.opt,
+ lineHeight, lead, follow, middleShift,
+ (knuthParagraphs.indexOf(currPar) == 0),
+ this);
+
+ if (hyphProps.hyphenate == EN_TRUE) {
+ findHyphenationPoints(currPar);
+ }
+
+ // first try
+ boolean bHyphenationAllowed = false;
+ iBPcount = alg.findBreakingPoints(currPar,
+ iLineWidth,
+ maxAdjustment, false, bHyphenationAllowed);
+ if (iBPcount == 0 || alignment == EN_JUSTIFY) {
+ // if the first try found a set of breaking points, save them
+ if (iBPcount > 0) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(false);
+ } else {
+ // the first try failed
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
+ }
+
+ // now try something different
+ log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
+ if (hyphProps.hyphenate == EN_TRUE) {
+ // consider every hyphenation point as a legal break
+ bHyphenationAllowed = true;
+ } else {
+ // try with a higher threshold
+ maxAdjustment = 5;
+ }
+
+ if ((iBPcount
+ = alg.findBreakingPoints(currPar,
+ iLineWidth,
+ maxAdjustment, false, bHyphenationAllowed)) == 0) {
+ // the second try failed too, try with a huge threshold
+ // and force the algorithm to find
+ // a set of breaking points
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+ + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
+ maxAdjustment = 20;
+ iBPcount
+ = alg.findBreakingPoints(currPar,
+ iLineWidth,
+ maxAdjustment, true, bHyphenationAllowed);
+ }
+
+ // use non-hyphenated breaks, when possible
+ lineLayouts.restorePossibilities();
+
+ /* *** *** estensione *** *** */
+ if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
+/*LF*/ //System.out.println("LLM.getNextKnuthElements> soluzioni con piu' righe? " + lineLayouts.canUseMoreLines());
+/*LF*/ //System.out.println(" soluzioni con meno righe? " + lineLayouts.canUseLessLines());
+ if (!lineLayouts.canUseMoreLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with shorter lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 0.95);
+ iBPcount
+ = alg.findBreakingPoints(currPar,
+ iLineWidth,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+ if (!lineLayouts.canUseLessLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with longer lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 1.05);
+ iBPcount
+ = alg.findBreakingPoints(currPar,
+ iLineWidth,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+/*LF*/ //System.out.println("LLM.getNextKnuthElements> ora, soluzioni con piu' righe? " + lineLayouts.canUseMoreLines());
+/*LF*/ //System.out.println(" ora, soluzioni con meno righe? " + lineLayouts.canUseLessLines());
+ }
+ /* *** *** estensione *** *** */
+ }
+/*LF*/ lineLayoutsList.add(0, lineLayouts);
+ }
+
+
+/*LF*/ setFinished(true);
+
+ //Post-process the line breaks found
+ return postProcessLineBreaks(alignment);
+ }
+
+ private LinkedList postProcessLineBreaks(int alignment) {
+
+ LinkedList returnList = new LinkedList();
+
+ for (int p = 0; p < knuthParagraphs.size(); p ++) {
+ // null penalty between paragraphs
+ if (p > 0
+ && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
+ returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+ }
+
+ lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
+
+ if (alignment == EN_JUSTIFY) {
+ /* ALLINEAMENTO GIUSTIFICATO, elementi con Position simboliche */
+ Position returnPosition = new LeafPosition(this, p);
+ /*LF*/ createElements(returnList, lineLayouts, returnPosition);
+ /* inizio commento
+ if (layoutProps.orphans + layoutProps.widows <= lineLayouts.getMinLineNumber()
+ && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
+ // the lines of this paragraph can be parted;
+ // for example, if widows = orphans = 2
+ // and the paragraph has 8(-1,+2) lines:
+ // line
+ // line
+ // ---- the page can end here ----
+ // line
+ // ---- or here ----
+ // line
+ // ---- or here ----
+ // line
+ // ---- or here ----
+ // [optional line, if more than 8 are needed]
+ // ---- or here ----
+ // [optional line, if more than 8 are needed]
+ // ---- or here ----
+ // line [optionally disappearing]
+ // ---- or here
+ // line
+ // line
+
+ // the first (layoutProps.orphans) lines
+ returnList.add(new KnuthBox(layoutProps.orphans * constantLineHeight, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+
+ // non-optional lines
+ for (int i = 0;
+ i < (lineLayouts.getMinLineNumber() - layoutProps.orphans - layoutProps.widows);
+ i ++) {
+ returnList.add(new KnuthBox(1 * constantLineHeight, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+ }
+
+ // optional lines
+ for (int i = 0;
+ i < (lineLayouts.getMaxLineNumber() - lineLayouts.getOptLineNumber());
+ i ++) {
+ returnList.add(new KnuthBox(0, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, returnPosition, false));
+ returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ returnList.add(new KnuthBox(0, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+ }
+
+ // optionally disappearing lines
+ for (int i = 0;
+ i < (lineLayouts.getOptLineNumber() - lineLayouts.getMinLineNumber());
+ i ++) {
+ returnList.add(new KnuthBox(1 * constantLineHeight, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, returnPosition, false));
+ returnList.add(new KnuthGlue(0, 0, 1 * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ returnList.add(new KnuthBox(0, returnPosition, false));
+ returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+ }
+
+ // the last (layoutProps.widows) lines
+ // the boolean parameter is true, so it's easy to see where a sequence
+ // representing a paragraph ends
+ returnList.add(new KnuthBox(layoutProps.widows * constantLineHeight, returnPosition, true));
+ } else if (layoutProps.orphans + layoutProps.widows <= lineLayouts.getMaxLineNumber()
+ && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
+ // the lines can be parted according to the line number
+ int optLines;
+ int moreLines;
+ int lessLines;
+ if (layoutProps.orphans + layoutProps.widows <= lineLayouts.getOptLineNumber()) {
+ optLines = lineLayouts.getMinLineNumber();
+ moreLines = lineLayouts.getMaxLineNumber() - optLines;
+ lessLines = 0;
+ } else {
+ optLines = lineLayouts.getOptLineNumber();
+ moreLines = lineLayouts.getMaxLineNumber() - optLines;
+ lessLines = optLines - lineLayouts.getMinLineNumber();
+ }
+
+ returnList.add(new KnuthBox((optLines - layoutProps.widows) * constantLineHeight,
+ returnPosition, false));
+ returnList.add(new KnuthPenalty((layoutProps.orphans + layoutProps.widows - optLines) * constantLineHeight,
+ 0, false, returnPosition, false));
+ for (int i = 0;
+ i < (optLines + moreLines - layoutProps.orphans - layoutProps.widows);
+ i ++) {
+ returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ returnList.add(new KnuthBox(0,
+ returnPosition, false));
+ returnList.add(new KnuthPenalty((layoutProps.orphans + layoutProps.widows - optLines) * constantLineHeight,
+ 0, false, returnPosition, false));
+ }
+ returnList.add(new KnuthGlue(0, (layoutProps.orphans + layoutProps.widows - optLines) * constantLineHeight, lessLines * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ // the boolean parameter is true, so it's easy to see where a sequence
+ // representing a paragraph ends
+ returnList.add(new KnuthBox(layoutProps.widows * constantLineHeight,
+ returnPosition, true));
+ } else {
+ // the lines of this paragraph cannot be parted;
+ int optLines = lineLayouts.getOptLineNumber();
+ int moreLines = lineLayouts.getMaxLineNumber() - optLines;
+ int lessLines = optLines - lineLayouts.getMinLineNumber();
+
+ returnList.add(new KnuthBox(optLines * constantLineHeight,
+ returnPosition , (moreLines != 0 || lessLines != 0) ? false : true));
+ if (moreLines != 0 || lessLines != 0) {
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ returnPosition, false));
+ returnList.add(new KnuthGlue(0, moreLines * constantLineHeight, lessLines * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ // the boolean parameter is true, so it's easy to see where a sequence
+ // representing a paragraph ends
+ returnList.add(new KnuthBox(0, returnPosition, true));
+ }
+ }
+ fine commento */
+ } else {
+ /* ALLINEAMENTO NON GIUSTIFICATO, elementi con Position effettive */
+ Position returnPosition = new LeafPosition(this, p);
+ for (int i = 0;
+ i < lineLayouts.getChosenLineNumber();
+ i ++) {
+ if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
+ && i >= fobj.getOrphans()
+ && i <= lineLayouts.getChosenLineNumber() - fobj.getWidows()) {
+ // null penalty allowing a page break between lines
+ returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+ }
+ returnList.add(new KnuthBox(1 * constantLineHeight,
+ lineLayouts.getChosenPosition(i), false));
+ }
+ }
+ }
+
+/*LF*/ return returnList;
+ }
+
+
+ /*LF inizio nuova procedura di creazione degli elementi */
+ private void createElements(List list, LineLayoutPossibilities lineLayouts,
+ Position elementPosition) {
+ /* number of normal, inner lines */
+ int nInnerLines = 0;
+ /* number of lines that can be used in order to fill more space */
+ int nOptionalLines = 0;
+ /* number of lines that can be used in order to fill more space
+ only if the paragraph is not parted */
+ int nConditionalOptionalLines = 0;
+ /* number of lines that can be omitted in order to fill less space */
+ int nEliminableLines = 0;
+ /* number of lines that can be omitted in order to fill less space
+ only if the paragraph is not parted */
+ int nConditionalEliminableLines = 0;
+ /* number of the first unbreakable lines */
+ int nFirstLines = fobj.getOrphans();
+ /* number of the last unbreakable lines */
+ int nLastLines = fobj.getWidows();
+ /* sub-sequence used to separate the elements representing different lines */
+ List breaker = new LinkedList();
+
+/* commentare via per testare layout particolari */
+ if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMinLineNumber()) {
+ nInnerLines = lineLayouts.getMinLineNumber() - (fobj.getOrphans() + fobj.getWidows());
+ nOptionalLines = lineLayouts.getMaxLineNumber() - lineLayouts.getOptLineNumber();
+ nEliminableLines = lineLayouts.getOptLineNumber() - lineLayouts.getMinLineNumber();
+ } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getOptLineNumber()) {
+ nOptionalLines = lineLayouts.getMaxLineNumber() - lineLayouts.getOptLineNumber();
+ nEliminableLines = lineLayouts.getOptLineNumber() - (fobj.getOrphans() + fobj.getWidows());
+ nConditionalEliminableLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getMinLineNumber();
+ } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMaxLineNumber()) {
+ nOptionalLines = lineLayouts.getMaxLineNumber() - (fobj.getOrphans() + fobj.getWidows());
+ nConditionalOptionalLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getOptLineNumber();
+ nConditionalEliminableLines = lineLayouts.getOptLineNumber() - lineLayouts.getMinLineNumber();
+ nFirstLines -= nConditionalOptionalLines;
+ } else {
+ nConditionalOptionalLines = lineLayouts.getMaxLineNumber() - lineLayouts.getOptLineNumber();
+ nConditionalEliminableLines = lineLayouts.getOptLineNumber() - lineLayouts.getMinLineNumber();
+ nFirstLines = lineLayouts.getOptLineNumber();
+ nLastLines = 0;
+ }
+/* commentare via per testare layout particolari */
+
+/* inizio caso particolare da testare
+ nInnerLines = 0;
+ nOptionalLines = 1;
+ nConditionalOptionalLines = 2;
+ nEliminableLines = 0;
+ nConditionalEliminableLines = 0;
+ nFirstLines = 1;
+ nLastLines = 3;
+ fine caso particolare da testare */
+
+ if (nLastLines != 0
+ && (nConditionalOptionalLines > 0 || nConditionalEliminableLines > 0)) {
+ breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+ breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight,
+ -nConditionalEliminableLines * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+ breaker.add(new KnuthPenalty(nConditionalOptionalLines * constantLineHeight,
+ 0, false, elementPosition, false));
+ breaker.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
+ nConditionalEliminableLines * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+ } else if (nLastLines != 0) {
+ breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false));
+ }
+
+/*LF*/ //System.out.println("first=" + nFirstLines + " inner=" + nInnerLines
+ // + " optional=" + nOptionalLines + " eliminable=" + nEliminableLines
+ // + " last=" + nLastLines
+ // + " (condOpt=" + nConditionalOptionalLines + " condEl=" + nConditionalEliminableLines + ")");
+
+ // creation of the elements:
+ // first group of lines
+ list.add(new KnuthBox(nFirstLines * constantLineHeight, elementPosition,
+ (nLastLines == 0
+ && nConditionalOptionalLines == 0
+ && nConditionalEliminableLines == 0 ? true : false)));
+ if (nConditionalOptionalLines > 0
+ || nConditionalEliminableLines > 0) {
+ list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+ list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
+ nConditionalEliminableLines * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+ list.add(new KnuthBox(0, elementPosition,
+ (nLastLines == 0 ? true : false)));
+ }
+
+ // optional lines
+ for (int i = 0; i < nOptionalLines; i++) {
+ list.addAll(breaker);
+ list.add(new KnuthBox(0, elementPosition, false));
+ list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+ list.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+ LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+ list.add(new KnuthBox(0, elementPosition, false));
+ }
+
+ // eliminable lines
+ for (int i = 0; i < nEliminableLines; i++) {
+ list.addAll(breaker);
+ list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
+ list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+ list.add(new KnuthGlue(0, 0, 1 * constantLineHeight,
+ LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+ list.add(new KnuthBox(0, elementPosition, false));
+ }
+
+ // inner lines
+ for (int i = 0; i < nInnerLines; i++) {
+ list.addAll(breaker);
+ list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
+ }
+
+ // last group of lines
+ if (nLastLines > 0) {
+ list.addAll(breaker);
+ list.add(new KnuthBox(nLastLines * constantLineHeight,
+ elementPosition, true));
+ }
}
+/*LF fine nuova procedura di creazione degli elementi*/
+ public boolean mustKeepTogether() {
+ return false;
+ }
+
+ public boolean mustKeepWithPrevious() {
+ return false;
+ }
+
+ public boolean mustKeepWithNext() {
+ return false;
+ }
+
+ public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+ LeafPosition pos = (LeafPosition)lastElement.getPosition();
+ int totalAdj = adj;
+ //if (lastElement.isPenalty()) {
+ // totalAdj += lastElement.getW();
+ //}
+ //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight);
+ int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight + (adj > 0 ? - 0.4 : 0.4));
+/*LF*/ //System.out.println(" LLM> variazione calcolata = " + ((double) totalAdj / constantLineHeight) + " variazione applicata = " + lineNumberDifference);
+ lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(pos.getLeafPos());
+ lineNumberDifference = lineLayouts.applyLineNumberAdjustment(lineNumberDifference);
+ return lineNumberDifference * constantLineHeight;
+ }
+
+ public void discardSpace(KnuthGlue spaceGlue) {
+ }
+ public LinkedList getChangedKnuthElements(List oldList, int alignment) {
+ LinkedList returnList = new LinkedList();
+ for (int p = 0;
+ p < knuthParagraphs.size();
+ p ++) {
+ lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
+/*LF*/ //System.out.println("demeriti definitivi: " + lineLayouts.getChosenDemerits());
+ for (int i = 0;
+ i < lineLayouts.getChosenLineNumber();
+ i ++) {
+ if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
+ && i >= fobj.getOrphans()
+ && i <= lineLayouts.getChosenLineNumber() - fobj.getWidows()) {
+ // null penalty allowing a page break between lines
+ returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+ }
+ LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
+/*LF*/ //System.out.println("LLM.getChangedKnuthElements> lineWidth= " + lbp.lineWidth + " difference= " + lbp.difference);
+/*LF*/ //System.out.println(" shrink= " + lbp.availableShrink + " stretch= " + lbp.availableStretch);
+
+ /* nello shrink dell'ultima riga va ignorato quello dovuto al lineFiller */
+ /* ma e' meglio fare queste direttamente quando si creano le
+ linebreakposition, cosi' non c'e' bisogno di distinguere
+ a questo punto ne' quando si ricalcola */
+ /*int fillerShrink = ((Paragraph)knuthParagraphs.get(p)).lineFiller.opt - ((Paragraph)knuthParagraphs.get(p)).lineFiller.min;*/
+/*LF*/ //System.out.println("linewidth= " + lbp.lineWidth + " difference= " + lbp.difference + " indent= " + lbp.startIndent);
+ MinOptMax contentIPD;
+ if (alignment == EN_JUSTIFY) {
+ contentIPD = new MinOptMax(
+ lbp.lineWidth - lbp.difference - lbp.availableShrink,
+ lbp.lineWidth - lbp.difference,
+ lbp.lineWidth - lbp.difference + lbp.availableStretch);
+ } else if (alignment == EN_CENTER) {
+ contentIPD = new MinOptMax(lbp.lineWidth - 2 * lbp.startIndent);
+ } else if (alignment == EN_END) {
+ contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent);
+ } else {
+ contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent);
+ }
+ returnList.add(new KnuthBlockBox(1 * constantLineHeight,
+ contentIPD,
+ (lbp.ipdAdjust != 0 ? lbp.lineWidth - lbp.difference : 0),
+ lbp, false));
+ }
+ }
+ return returnList;
+ }
/**
* find hyphenation points for every word int the current paragraph
= currUpdate.inlineLM.getChangedKnuthElements
(currPar.subList(fromIndex + iAddedElements,
toIndex + iAddedElements),
- flaggedPenalty, effectiveAlignment);
+ /*flaggedPenalty,*/ effectiveAlignment);
// remove the old elements
currPar.subList(fromIndex + iAddedElements,
toIndex + iAddedElements).clear();
setFinished(false);
iReturnedLBP--;
}
- while ((LineBreakPosition) breakpoints.get(iReturnedLBP)
+ while ((LineBreakPosition) lineLayouts.getChosenPosition(iReturnedLBP)
!= (LineBreakPosition) resetPos) {
iReturnedLBP--;
}
*/
public void addAreas(PositionIterator parentIter,
LayoutContext context) {
- addAreas(parentIter, 0.0);
-
- //vecInlineBreaks.clear();
- prevBP = null;
- }
-
- // Generate and add areas to parent area
- // Set size etc
- // dSpaceAdjust should reference extra space in the BPD
- /**
- * Add the areas with the associated space adjustment.
- *
- * @param parentIter the iterator of breaks positions
- * @param dSpaceAdjust the space adjustment
- */
- public void addAreas(PositionIterator parentIter, double dSpaceAdjust) {
LayoutManager childLM;
LayoutContext lc = new LayoutContext(0);
int iCurrParIndex;
while (parentIter.hasNext()) {
- ListIterator paragraphIterator = null;
- KnuthElement tempElement = null;
- // the TLM which created the last KnuthElement in this line
- LayoutManager lastLM = null;
-
- LineBreakPosition lbp = (LineBreakPosition) parentIter.next();
- LineArea lineArea = new LineArea();
- lineArea.setStartIndent(lbp.startIndent);
- lineArea.setBPD(lbp.lineHeight);
- lc.setBaseline(lbp.baseline);
- lc.setLineHeight(lbp.lineHeight);
- lc.setMiddleShift(middleShift);
- setCurrentArea(lineArea);
-
- iCurrParIndex = lbp.iParIndex;
- Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex);
- iEndElement = lbp.getLeafPos();
-
- // ignore the first elements added by the LineLayoutManager
- iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-
- // ignore the last elements added by the LineLayoutManager
- iEndElement -= (iEndElement == (currPar.size() - 1))
- ? currPar.ignoreAtEnd : 0;
-
- // ignore the last element in the line if it is a KnuthGlue object
- paragraphIterator = currPar.listIterator(iEndElement);
- tempElement = (KnuthElement) paragraphIterator.next();
- if (tempElement.isGlue()) {
- iEndElement --;
- // this returns the same KnuthElement
- paragraphIterator.previous();
- tempElement = (KnuthElement) paragraphIterator.previous();
- }
- lastLM = tempElement.getLayoutManager();
-
- // ignore KnuthGlue and KnuthPenalty objects
- // at the beginning of the line
- paragraphIterator = currPar.listIterator(iStartElement);
- tempElement = (KnuthElement) paragraphIterator.next();
- while (!tempElement.isBox() && paragraphIterator.hasNext()) {
+ Position pos = (Position) parentIter.next();
+ if (pos instanceof LineBreakPosition) {
+ ListIterator paragraphIterator = null;
+ KnuthElement tempElement = null;
+ // the TLM which created the last KnuthElement in this line
+ LayoutManager lastLM = null;
+
+ LineBreakPosition lbp = (LineBreakPosition) pos;
+ LineArea lineArea = new LineArea();
+ lineArea.setStartIndent(lbp.startIndent);
+ lineArea.setBPD(lbp.lineHeight);
+ lc.setBaseline(lbp.baseline);
+ lc.setLineHeight(lbp.lineHeight);
+ lc.setMiddleShift(middleShift);
+/*LF*/ lc.setTopShift(lbp.topShift);
+/*LF*/ lc.setBottomShift(lbp.bottomShift);
+
+ iCurrParIndex = lbp.iParIndex;
+ Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex);
+ iEndElement = lbp.getLeafPos();
+
+ // ignore the first elements added by the LineLayoutManager
+ iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
+
+ // ignore the last elements added by the LineLayoutManager
+ iEndElement -= (iEndElement == (currPar.size() - 1))
+ ? currPar.ignoreAtEnd : 0;
+
+ // ignore the last element in the line if it is a KnuthGlue object
+ paragraphIterator = currPar.listIterator(iEndElement);
tempElement = (KnuthElement) paragraphIterator.next();
- iStartElement ++;
- }
-
- // Add the inline areas to lineArea
- PositionIterator inlinePosIter
- = new KnuthPossPosIter(currPar, iStartElement,
- iEndElement + 1);
-
- iStartElement = lbp.getLeafPos() + 1;
- if (iStartElement == currPar.size()) {
- // advance to next paragraph
- iStartElement = 0;
- }
-
- lc.setSpaceAdjust(lbp.dAdjust);
- lc.setIPDAdjust(lbp.ipdAdjust);
- lc.setLeadingSpace(new SpaceSpecifier(true));
- lc.setTrailingSpace(new SpaceSpecifier(false));
- lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
- setChildContext(lc);
- while ((childLM = inlinePosIter.getNextChildLM()) != null) {
- lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
- childLM.addAreas(inlinePosIter, lc);
- lc.setLeadingSpace(lc.getTrailingSpace());
+ if (tempElement.isGlue()) {
+ iEndElement --;
+ // this returns the same KnuthElement
+ paragraphIterator.previous();
+ tempElement = (KnuthElement) paragraphIterator.previous();
+ }
+ lastLM = tempElement.getLayoutManager();
+
+ // ignore KnuthGlue and KnuthPenalty objects
+ // at the beginning of the line
+ paragraphIterator = currPar.listIterator(iStartElement);
+ tempElement = (KnuthElement) paragraphIterator.next();
+ while (!tempElement.isBox() && paragraphIterator.hasNext()) {
+ tempElement = (KnuthElement) paragraphIterator.next();
+ iStartElement ++;
+ }
+
+ // Add the inline areas to lineArea
+ PositionIterator inlinePosIter
+ = new KnuthPossPosIter(currPar, iStartElement,
+ iEndElement + 1);
+
+ iStartElement = lbp.getLeafPos() + 1;
+ if (iStartElement == currPar.size()) {
+ // advance to next paragraph
+ iStartElement = 0;
+ }
+
+ lc.setSpaceAdjust(lbp.dAdjust);
+ lc.setIPDAdjust(lbp.ipdAdjust);
+ lc.setLeadingSpace(new SpaceSpecifier(true));
lc.setTrailingSpace(new SpaceSpecifier(false));
+ lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+
+/* *** *** extension *** *** */
+ if (false && bTextAlignment == EN_JUSTIFY) {
+ // re-compute space adjust ratio
+ int updatedDifference = context.getStackLimit().opt - lbp.lineWidth + lbp.difference;
+ double updatedRatio = 0.0;
+ if (updatedDifference > 0) {
+ updatedRatio = (float) updatedDifference / lbp.availableStretch;
+ } else if (updatedDifference < 0) {
+ updatedRatio = (float) updatedDifference / lbp.availableShrink;
+ }
+ lc.setIPDAdjust(updatedRatio);
+/*LF*/ //System.out.println("LLM.addAreas> vecchia differenza= " + lbp.difference + " differenza ricalcolata= " + updatedDifference);
+/*LF*/ //System.out.println(" vecchio coeff= " + lbp.ipdAdjust + " differenza ricalcolata= " + updatedRatio);
+ } else if (false && bTextAlignment == EN_CENTER) {
+ // re-compute indent
+ int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth) / 2;
+ lineArea.setStartIndent(updatedIndent);
+ } else if (false && bTextAlignment == EN_END) {
+ // re-compute indent
+ int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth);
+ lineArea.setStartIndent(updatedIndent);
+ }
+/* *** *** extension *** *** */
+
+ setCurrentArea(lineArea); // spostata da prima
+ setChildContext(lc);
+ while ((childLM = inlinePosIter.getNextChildLM()) != null) {
+ lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
+ childLM.addAreas(inlinePosIter, lc);
+ lc.setLeadingSpace(lc.getTrailingSpace());
+ lc.setTrailingSpace(new SpaceSpecifier(false));
+ }
+
+ // when can this be null?
+ // if display-align is distribute, add space after
+ if (context.getSpaceAfter() > 0
+ && (!context.isLastArea() || parentIter.hasNext())) {
+ lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
+ }
+ parentLM.addChildArea(lineArea);
+ } else {
+ // pos was the Position inside a penalty item, nothing to do
}
- // when can this be null?
- if (lc.getTrailingSpace() != null) {
- addSpace(lineArea, lc.getTrailingSpace().resolve(true),
- lc.getSpaceAdjust());
- }
- parentLM.addChildArea(lineArea);
}
setCurrentArea(null); // ?? necessary
}
--- /dev/null
+
+package org.apache.fop.layoutmgr;
+
+import java.util.ArrayList;
+
+public class LineLayoutPossibilities {
+
+ private class Possibility {
+ private int lineNumber;
+ private double demerits;
+ private ArrayList breakPositions;
+
+ private Possibility(int ln, double dem) {
+ lineNumber = ln;
+ demerits = dem;
+ breakPositions = new ArrayList(ln);
+ }
+
+ private int getLineNumber() {
+ return lineNumber;
+ }
+
+ private double getDemerits() {
+ return demerits;
+ }
+
+ private void addBreakPosition(Position pos) {
+ // Positions are always added with index 0 because
+ // they are created backward, from the last one to
+ // the first one
+ breakPositions.add(0, pos);
+ }
+
+ private Position getBreakPosition(int i) {
+ return (Position)breakPositions.get(i);
+ }
+ }
+
+ private ArrayList possibilitiesList;
+ private ArrayList savedPossibilities;
+ private int minimumIndex;
+ private int optimumIndex;
+ private int maximumIndex;
+ private int chosenIndex;
+ private int savedOptLineNumber;
+
+ public LineLayoutPossibilities() {
+ possibilitiesList = new ArrayList();
+ savedPossibilities = new ArrayList();
+ optimumIndex = -1;
+ }
+
+ public void addPossibility(int ln, double dem) {
+ possibilitiesList.add(new Possibility(ln, dem));
+ if (possibilitiesList.size() == 1) {
+ // first Possibility added
+ minimumIndex = 0;
+ optimumIndex = 0;
+ maximumIndex = 0;
+ chosenIndex = 0;
+ } else {
+ if (dem < ((Possibility)possibilitiesList.get(optimumIndex)).getDemerits()) {
+ optimumIndex = possibilitiesList.size() - 1;
+ chosenIndex = optimumIndex;
+ }
+ if (ln < ((Possibility)possibilitiesList.get(minimumIndex)).getLineNumber()) {
+ minimumIndex = possibilitiesList.size() - 1;
+ }
+ if (ln > ((Possibility)possibilitiesList.get(maximumIndex)).getLineNumber()) {
+ maximumIndex = possibilitiesList.size() - 1;
+ }
+ }
+ }
+
+ /* save in a different array the computed Possibilities,
+ * so possibilitiesList is ready to store different Possibilities
+ */
+ public void savePossibilities(boolean bSaveOptLineNumber) {
+ if (bSaveOptLineNumber) {
+ savedOptLineNumber = getOptLineNumber();
+ } else {
+ savedOptLineNumber = 0;
+ }
+ savedPossibilities = possibilitiesList;
+ possibilitiesList = new ArrayList();
+ }
+
+ /* replace the Possibilities stored in possibilitiesList with
+ * the ones stored in savedPossibilities and having the same line number
+ */
+ public void restorePossibilities() {
+ int index = 0;
+ while (savedPossibilities.size() > 0) {
+ Possibility restoredPossibility = (Possibility) savedPossibilities.remove(0);
+ if (restoredPossibility.getLineNumber() < getMinLineNumber()) {
+ // if the line number of restoredPossibility is less than the minimum one,
+ // add restoredPossibility at the beginning of the list
+ possibilitiesList.add(0, restoredPossibility);
+ // update minimumIndex
+ minimumIndex = 0;
+ // shift the other indexes;
+ optimumIndex ++;
+ maximumIndex ++;
+ chosenIndex ++;
+ } else if (restoredPossibility.getLineNumber() > getMaxLineNumber()) {
+ // if the line number of restoredPossibility is greater than the maximum one,
+ // add restoredPossibility at the end of the list
+ possibilitiesList.add(possibilitiesList.size(), restoredPossibility);
+ // update maximumIndex
+ maximumIndex = possibilitiesList.size() - 1;
+ index = maximumIndex;
+ } else {
+ // find the index of the Possibility that will be replaced
+ while (index < maximumIndex
+ && getLineNumber(index) < restoredPossibility.getLineNumber()) {
+ index ++;
+ }
+ if (getLineNumber(index) == restoredPossibility.getLineNumber()) {
+ possibilitiesList.set(index, restoredPossibility);
+ } else {
+ // this should not happen
+/*LF*/ System.out.println("ERRORE: LineLayoutPossibilities restorePossibilities(), min= " + getMinLineNumber() + " max= " + getMaxLineNumber() + " restored= " + restoredPossibility.getLineNumber());
+ return;
+ }
+ }
+ // update optimumIndex and chosenIndex
+ if (savedOptLineNumber == 0 && getDemerits(optimumIndex) > restoredPossibility.getDemerits()
+ || savedOptLineNumber != 0 && restoredPossibility.getLineNumber() == savedOptLineNumber) {
+ optimumIndex = index;
+ chosenIndex = optimumIndex;
+ }
+ }
+/*LF*/ //System.out.println(">> minLineNumber = " + getMinLineNumber() + " optLineNumber = " + getOptLineNumber() + " maxLineNumber() = " + getMaxLineNumber());
+ }
+
+ public void addBreakPosition(Position pos, int i) {
+ ((Possibility)possibilitiesList.get(i)).addBreakPosition(pos);
+ }
+
+ public boolean canUseMoreLines() {
+ return (getOptLineNumber() < getMaxLineNumber());
+ }
+
+ public boolean canUseLessLines() {
+ return (getMinLineNumber() < getOptLineNumber());
+ }
+
+ public int getMinLineNumber() {
+ return getLineNumber(minimumIndex);
+ }
+
+ public int getOptLineNumber() {
+ return getLineNumber(optimumIndex);
+ }
+
+ public int getMaxLineNumber() {
+ return getLineNumber(maximumIndex);
+ }
+
+ public int getChosenLineNumber() {
+ return getLineNumber(chosenIndex);
+ }
+
+ public int getLineNumber(int i) {
+ return ((Possibility)possibilitiesList.get(i)).getLineNumber();
+ }
+
+ public double getChosenDemerits() {
+ return getDemerits(chosenIndex);
+ }
+
+ public double getDemerits(int i) {
+ return ((Possibility)possibilitiesList.get(i)).getDemerits();
+ }
+
+ public int getPossibilitiesNumber() {
+ return possibilitiesList.size();
+ }
+
+ public Position getChosenPosition(int i) {
+ return ((Possibility)possibilitiesList.get(chosenIndex)).getBreakPosition(i);
+ }
+
+ public int applyLineNumberAdjustment(int adj) {
+ if (adj >= (getMinLineNumber() - getChosenLineNumber())
+ && adj <= (getMaxLineNumber() - getChosenLineNumber())
+ && getLineNumber(chosenIndex + adj) == getChosenLineNumber() + adj) {
+ chosenIndex += adj;
+ System.out.println("chosenLineNumber= " + (getChosenLineNumber() - adj) + " variazione= " + adj
+ + " => chosenLineNumber= " + getLineNumber(chosenIndex));
+ return adj;
+ } else {
+ // this should not happen!
+ System.out.println("Cannot apply the desired line number adjustment");
+ return 0;
+ }
+ }
+
+ public void printAll() {
+ System.out.println("++++++++++");
+ System.out.println(" " + possibilitiesList.size() + " possibilita':");
+ for (int i = 0; i < possibilitiesList.size(); i ++) {
+ System.out.println(" " + ((Possibility)possibilitiesList.get(i)).getLineNumber()
+ + (i == optimumIndex ? " *" : "")
+ + (i == minimumIndex ? " -" : "")
+ + (i == maximumIndex ? " +" : ""));
+ }
+ System.out.println("++++++++++");
+ }
+}
--- /dev/null
+/*
+ * 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 org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
+
+class PageBreakingAlgorithm extends BreakingAlgorithm {
+ private LayoutManager topLevelLM;
+ private LinkedList pageBreaks = null;
+
+ public PageBreakingAlgorithm(LayoutManager topLevelLM,
+ int alignment, int alignmentLast) {
+ super(alignment, alignmentLast, true);
+ this.topLevelLM = topLevelLM;
+ }
+
+ public LinkedList getPageBreaks() {
+ return pageBreaks;
+ }
+
+ public void insertPageBreakAsFirst(PageBreakPosition pageBreak) {
+ if (pageBreaks == null) {
+ pageBreaks = new LinkedList();
+ }
+ pageBreaks.addFirst(pageBreak);
+ }
+
+ public void updateData1(int total, double demerits) {
+ }
+
+ public void updateData2(KnuthNode bestActiveNode,
+ KnuthSequence sequence,
+ int total) {
+ //int difference = (bestActiveNode.line < total) ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth;
+ int difference = bestActiveNode.difference;
+ int blockAlignment = (bestActiveNode.line < total) ? alignment : alignmentLast;
+ double ratio = (blockAlignment == org.apache.fop.fo.Constants.EN_JUSTIFY
+ || bestActiveNode.adjustRatio < 0) ? bestActiveNode.adjustRatio : 0;
+
+
+ // add nodes at the beginning of the list, as they are found
+ // backwards, from the last one to the first one
+ System.out.println("BBA> difference= " + difference + " ratio= " + ratio
+ + " posizione= " + bestActiveNode.position);
+ insertPageBreakAsFirst(new PageBreakPosition(this.topLevelLM,
+ bestActiveNode.position, ratio, difference));
+ }
+
+ protected int filterActiveList() {
+ // leave only bestActiveNode in the activeList
+ KnuthNode tempNode = null;
+ KnuthNode bestActiveNode = null;
+ System.out.println("PBA.filterActiveList> " + activeList.size() + " possibilita'");
+ while (activeList.size() > 0) {
+ tempNode = (KnuthNode)activeList.removeFirst();
+ System.out.println(" + linee= " + tempNode.line + " demeriti= " + tempNode.totalDemerits);
+ if (bestActiveNode == null
+ || tempNode.totalDemerits < bestActiveNode.totalDemerits) {
+ bestActiveNode = tempNode;
+ }
+ }
+ activeList.add(bestActiveNode);
+ System.out.println(" migliore " + bestActiveNode.line);
+ return bestActiveNode.line;
+ }
+
+}
\ No newline at end of file
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonMarginBlock;
+import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.awt.Rectangle;
import java.util.Iterator;
}
}
+
private int startPageNum = 0;
private int currentPageNum = 0;
private String pageNumberString;
*/
private SimplePageMaster currentSimplePageMaster;
+ /**
+ * The collection of StaticContentLayoutManager objects that are associated
+ * with this Page Sequence, keyed by flow-name.
+ */
+ //private HashMap staticContentLMs = new HashMap(4);
+
+ private FlowLayoutManager childFLM = null;
+
/**
* Constructor - activated by AreaTreeHandler for each
* fo:page-sequence in the input FO stream
*
- * @param pageseq the page-sequence formatting object
+ * @param pageSeq the page-sequence formatting object
*/
public PageSequenceLayoutManager(PageSequence pageSeq) {
super(pageSeq);
LineArea title = null;
if (pageSeq.getTitleFO() != null) {
- ContentLayoutManager clm =
- new ContentLayoutManager(pageSeq.getTitleFO(), this);
+ ContentLayoutManager clm = new ContentLayoutManager(pageSeq
+ .getTitleFO(), this);
title = (LineArea) clm.getParentArea(null); // can improve
}
log.debug("Starting layout");
makeNewPage(false, false);
+ isFirstPage = true;
flowIPD = curFlow.getIPD();
- BreakPoss bp;
- LayoutContext childLC = new LayoutContext(0);
- while (!isFinished()) {
- if ((bp = getNextBreakPoss(childLC)) != null) {
- addAreas((BlockBreakPosition)bp.getPosition());
- // add static areas and resolve any new id areas
- // finish page and add to area tree
- finishPage();
- currentPageNum++;
- pageNumberString = pageSeq.makeFormattedPageNumber(currentPageNum);
- }
- }
+ PageBreaker breaker = new PageBreaker(this);
+ breaker.doLayout(flowBPD);
+
// TODO: Don't decrement currentPageNum when no pages are generated
currentPageNum--;
finishPage();
- pageSeq.getRoot().notifyPageSequenceFinished(currentPageNum, (currentPageNum - startPageNum) + 1);
+ pageSeq.getRoot().notifyPageSequenceFinished(currentPageNum,
+ (currentPageNum - startPageNum) + 1);
log.debug("Ending layout");
}
+ private class PageBreaker extends AbstractBreaker {
+
+ private PageSequenceLayoutManager pslm;
+
+ public PageBreaker(PageSequenceLayoutManager pslm) {
+ this.pslm = pslm;
+ }
+
+ protected LayoutManager getTopLevelLM() {
+ return pslm;
+ }
+
+ protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+ return pslm.getNextKnuthElements(context, alignment);
+ }
+
+ protected int getCurrentDisplayAlign() {
+ return currentSimplePageMaster.getRegion(Constants.FO_REGION_BODY).getDisplayAlign();
+ }
+
+ protected boolean hasMoreContent() {
+ return !isFinished();
+ }
+
+ protected void addAreas(PositionIterator posIter, LayoutContext context) {
+ getCurrentChildLM().addAreas(posIter, context);
+ }
+
+ protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
+ KnuthSequence originalList, KnuthSequence effectiveList) {
+ //Directly add areas after finding the breaks
+ addAreas(alg, partCount, originalList, effectiveList);
+ }
+
+ protected void finishPart() {
+ // add static areas and resolve any new id areas
+ // finish page and add to area tree
+ finishPage();
+ currentPageNum++;
+ pageNumberString = pageSeq
+ .makeFormattedPageNumber(currentPageNum);
+ }
+
+ protected LayoutManager getCurrentChildLM() {
+ return childFLM;
+ }
+
+ }
+
/** @see org.apache.fop.layoutmgr.LayoutManager#isBogus() */
public boolean isBogus() {
return false;
* @param context the layout context for finding breaks
* @return the break for the page
*/
- public BreakPoss getNextBreakPoss(LayoutContext context) {
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
LayoutManager curLM; // currently active LM
while ((curLM = getChildLM()) != null) {
- BreakPoss bp = null;
+/*LF*/ LinkedList returnedList = null;
+/*LF*/ if (childFLM == null && (curLM instanceof FlowLayoutManager)) {
+/*LF*/ childFLM = (FlowLayoutManager)curLM;
+/*LF*/ } else {
+/*LF*/ if (curLM != childFLM) {
+/*LF*/ System.out.println("PLM> figlio sconosciuto (invalid child LM)");
+/*LF*/ }
+/*LF*/ }
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(new MinOptMax(flowBPD));
if (!curLM.isFinished()) {
pageSeq.setLayoutDimension(PercentBase.REFERENCE_AREA_IPD, flowIPD);
pageSeq.setLayoutDimension(PercentBase.REFERENCE_AREA_BPD, flowBPD);
- bp = curLM.getNextBreakPoss(childLC);
+/*LF*/ returnedList = curLM.getNextKnuthElements(childLC, alignment);
}
- if (bp != null) {
- return new BreakPoss(
- new BlockBreakPosition(curLM, bp));
+ if (returnedList != null) {
+ return returnedList;
}
}
setFinished(true);
return null;
}
- /**
- * Add the areas to the current page.
- * Given the page break position this adds the areas to the current
- * page.
- *
- * @param bbp the block break position
- */
- public void addAreas(BlockBreakPosition bbp) {
- List list = new java.util.ArrayList();
- list.add(bbp.breakps);
- bbp.getLM().addAreas(new BreakPossPosIter(list, 0,
- 1), null);
- }
-
/**
* Add an ID reference to the current page.
* When adding areas the area adds its ID reference.
}
else {
/* IF we are on the kind of page we need, we'll need a new page. */
- if (currentPageNum%2 != 0) {
+ if (currentPageNum % 2 != 0) {
// Current page is odd
return (breakValue == Constants.EN_ODD_PAGE);
}
else {
return (breakValue == Constants.EN_ODD_PAGE);
}
- }
- else {
+ } else {
return true;
}
}
* LayoutManager for text (a sequence of characters) which generates one
* or more inline areas.
*/
-public class TextLayoutManager extends AbstractLayoutManager
- implements InlineLevelLayoutManager {
+public class TextLayoutManager extends LeafNodeLayoutManager {
/**
* Store information about each potential text area.
* @param node The FOText object to be rendered
*/
public TextLayoutManager(FOText node) {
+ super();
foText = node;
textArray = new char[node.endIndex - node.startIndex];
textArea.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2);
break;
case EN_TOP:
- textArea.setOffset(fs.getAscender());
+ textArea.setOffset(context.getTopBaseline() + fs.getAscender());
break;
case EN_BOTTOM:
- textArea.setOffset(context.getLineHeight() - bpd + fs.getAscender());
+ textArea.setOffset(context.getBottomBaseline() - bpd + fs.getAscender());
break;
case EN_BASELINE:
default:
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
returnList.add
- (new KnuthBox(0, 0, 0, 0,
+ (new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
returnList.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
(short) 1, (short) 0,
wordSpaceIPD, false));
returnList.add
- (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 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,
- - 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ - 3 * wordSpaceIPD.opt, 0,
new LeafPosition(this, -1), true));
iNextStart ++;
break;
for (; iTempStart < textArray.length
&& textArray[iTempStart] != SPACE
&& textArray[iTempStart] != NBSPACE
- && textArray[iTempStart] != NEWLINE;
+ && textArray[iTempStart] != NEWLINE
+ && !(iTempStart > iNextStart
+ && alignment == EN_JUSTIFY
+ && BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0);
iTempStart++) {
wordIPD.add(fs.getCharWidth(textArray[iTempStart]));
}
- wordIPD.add(MinOptMax.multiply(letterSpaceIPD, (iTempStart - iThisStart - 1)));
+ int iLetterSpaces = iTempStart - iThisStart - 1;
+ wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
vecAreaInfo.add
(new AreaInfo(iThisStart, iTempStart, (short) 0,
- (short) (iTempStart - iThisStart - 1),
+ (short) iLetterSpaces,
wordIPD, false));
if (letterSpaceIPD.min == letterSpaceIPD.max) {
// constant letter space; simply return a box
// whose width includes letter spaces
returnList.add
- (new KnuthBox(wordIPD.opt, lead, total, middle,
+ (new KnuthInlineBox(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,
+ (new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
lead, total, middle,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
returnList.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
returnList.add
- (new KnuthGlue((iTempStart - iThisStart - 1) * letterSpaceIPD.opt,
- (iTempStart - iThisStart - 1) * (letterSpaceIPD.max - letterSpaceIPD.opt),
- (iTempStart - iThisStart - 1) * (letterSpaceIPD.opt - letterSpaceIPD.min),
+ (new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
+ iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
+ iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
new LeafPosition(this, -1), true));
returnList.add
- (new KnuthBox(0, lead, total, middle,
- new LeafPosition(this, -1), true));
- iNextStart = iTempStart;
+ (new KnuthInlineBox(0, lead, total, middle,
+ new LeafPosition(this, -1), true));
}
+ // if the last character is '-' or '/', it could be used as a line end;
+ // add a flagged penalty element and glue element representing a suppressible
+ // letter space if the next character is not a space
+ if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0
+ && iTempStart < textArray.length
+ && textArray[iTempStart] != SPACE
+ && textArray[iTempStart] != NBSPACE) {
+ returnList.add
+ (new KnuthPenalty(0, LayoutManager.FLAGGED_PENALTY, true,
+ new LeafPosition(this, -1), false));
+ returnList.add
+ (new KnuthGlue(letterSpaceIPD.opt,
+ letterSpaceIPD.max - letterSpaceIPD.opt,
+ letterSpaceIPD.opt - letterSpaceIPD.min,
+ new LeafPosition(this, -1), false));
+ // update the information in the AreaInfo, adding one more letter space
+ AreaInfo ai = (AreaInfo) vecAreaInfo.get(vecAreaInfo.size() - 1);
+ ai.iLScount ++;
+ }
+ iNextStart = iTempStart;
}
} // end of while
setFinished(true);
}
}
- public KnuthElement addALetterSpaceTo(KnuthElement element) {
- LeafPosition pos = (LeafPosition) element.getPosition();
+ public List addALetterSpaceTo(List oldList) {
+ // old list contains only a box, or the sequence: box penalty glue box;
+ // look at the Position stored in the first element in oldList
+ // which is always a box
+ ListIterator oldListIterator = oldList.listIterator();
+ LeafPosition pos = (LeafPosition) ((KnuthBox) oldListIterator.next()).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, lead, total, middle, pos, false);
+ if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0) {
+ // the last character could be used as a line break
+ // append new elements to oldList
+ oldListIterator = oldList.listIterator(oldList.size());
+ oldListIterator.add(new KnuthPenalty(0, LayoutManager.FLAGGED_PENALTY, true,
+ new LeafPosition(this, -1), false));
+ oldListIterator.add(new KnuthGlue(letterSpaceIPD.opt,
+ letterSpaceIPD.max - letterSpaceIPD.opt,
+ letterSpaceIPD.opt - letterSpaceIPD.min,
+ new LeafPosition(this, -1), false));
+ } else if (letterSpaceIPD.min == letterSpaceIPD.max) {
+ // constant letter space: replace the box
+ oldListIterator.set(new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle, pos, false));
} else {
- return new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
- ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
- ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
- new LeafPosition(this, -1), true);
+ // adjustable letter space: replace the glue
+ oldListIterator.next(); // this would return the penalty element
+ oldListIterator.next(); // this would return the glue element
+ oldListIterator.set(new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
+ ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
+ ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
+ new LeafPosition(this, -1), true));
}
+ return oldList;
}
public void hyphenate(Position pos, HyphContext hc) {
}
public LinkedList getChangedKnuthElements(List oldList,
- int flaggedPenalty,
+ /*int flaggedPenalty,*/
int alignment) {
if (isFinished()) {
return null;
AreaInfo ai = (AreaInfo) vecAreaInfo.get(iReturnedIndex);
if (ai.iWScount == 0) {
// ai refers either to a word or a word fragment
+
+ // if the last character is '-' or '/' and the next character is not a space
+ // one of the letter spaces must be represented using a penalty and a glue,
+ // and its width must be subtracted
+ if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
+ && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
+ ai.ipdArea.add(new MinOptMax(-letterSpaceIPD.min, -letterSpaceIPD.opt, -letterSpaceIPD.max));
+ }
if (letterSpaceIPD.min == letterSpaceIPD.max) {
returnList.add
- (new KnuthBox(ai.ipdArea.opt, lead, total, middle,
+ (new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle,
new LeafPosition(this, iReturnedIndex), false));
} else {
returnList.add
- (new KnuthBox(ai.ipdArea.opt
+ (new KnuthInlineBox(ai.ipdArea.opt
- ai.iLScount * letterSpaceIPD.opt,
lead, total, middle,
new LeafPosition(this, iReturnedIndex), false));
ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
new LeafPosition(this, -1), true));
returnList.add
- (new KnuthBox(0, 0, 0, 0,
+ (new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
}
if (ai.bHyphenated) {
returnList.add
- (new KnuthPenalty(hyphIPD, flaggedPenalty, true,
+ (new KnuthPenalty(hyphIPD, LayoutManager.FLAGGED_PENALTY, true,
new LeafPosition(this, -1), false));
}
+ // if the last character is '-' or '/', it could be used as a line end;
+ // add a flagged penalty element and a glue element representing a suppressible
+ // letter space if the next character is not a space
+ if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
+ && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
+ returnList.add
+ (new KnuthPenalty(0, LayoutManager.FLAGGED_PENALTY, true,
+ new LeafPosition(this, -1), false));
+ returnList.add
+ (new KnuthGlue(letterSpaceIPD.opt,
+ letterSpaceIPD.max - letterSpaceIPD.opt,
+ letterSpaceIPD.opt - letterSpaceIPD.min,
+ new LeafPosition(this, -1), false));
+ }
iReturnedIndex ++;
} else {
// ai refers to a space
+ if (textArray[ai.iStartIndex] == NBSPACE) {
+ returnList.add
+ (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+ new LeafPosition(this, -1),
+ false));
+ }
switch (alignment) {
case EN_CENTER :
returnList.add
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
returnList.add
- (new KnuthBox(0, 0, 0, 0,
+ (new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
returnList.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
/*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-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.
package org.apache.fop.traits;
+import org.apache.fop.datatypes.KeepValue;
import org.apache.fop.fo.Constants;
/**
public int breakBefore; // enum constant BreakBefore.xxx
public int breakAfter; // enum constant BreakAfter.xxx
+ public KeepValue keepWithPrevious; /*LF*/
+ public KeepValue keepWithNext; /*LF*/
+ public KeepValue keepTogether; /*LF*/
+ public int orphans; /*LF*/
+ public int widows; /*LF*/
+ public int blockProgressionUnit; /*LF*/
+ public int lineStackingStrategy; /*LF*/
public boolean bIsSpan;
public SpaceVal spaceBefore;
public SpaceVal spaceAfter;