/* * 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. * 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; 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.FObj; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.layoutmgr.inline.LineLayoutManager; import org.apache.fop.traits.MinOptMax; /** * Base LayoutManager class for all areas which stack their child * areas in the block-progression direction, such as Flow, Block, ListBlock. */ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager implements BlockLevelLayoutManager { /** * Reference to FO whose areas it's managing or to the traits * of the FO. */ //protected LayoutManager curChildLM = null; AbstractLayoutManager also defines this! protected BlockParent parentArea = null; /** 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; /** Only used to store the original list when createUnitElements is called */ protected LinkedList storedList = null; /** FO node */ protected FObj fobj; /** Indicates whether break before has been served or not */ protected boolean bBreakBeforeServed = false; /** Indicates whether space before has been served or not */ protected boolean bSpaceBeforeServed = false; /** Reference IPD available */ protected int referenceIPD = 0; /** * Holds the (one-time use) fo:block space-before * and -after properties. Large fo:blocks are split * into multiple Area. Blocks to accomodate the subsequent * regions (pages) they are placed on. space-before * is applied at the beginning of the first * Block and space-after at the end of the last Block * used in rendering the fo:block. */ protected MinOptMax foSpaceBefore = null; /** see foSpaceBefore */ protected MinOptMax foSpaceAfter = null; private int lastGeneratedPosition = -1; private int smallestPosNumberChecked = Integer.MAX_VALUE; private Position auxiliaryPosition; private int contentAreaIPD = 0; /** * @param the fo this LM deals with */ public BlockStackingLayoutManager(FObj node) { super(node); setGeneratesBlockArea(true); fobj = node; } /** * @return current area being filled */ protected BlockParent getCurrentArea() { return this.parentArea; } /** * Set the current area being filled. * @param parentArea the current area to be filled */ protected void setCurrentArea(BlockParent parentArea) { this.parentArea = parentArea; } protected MinOptMax resolveSpaceSpecifier(Area nextArea) { SpaceSpecifier spaceSpec = new SpaceSpecifier(false); // Area prevArea = getCurrentArea().getLast(); // if (prevArea != null) { // spaceSpec.addSpace(prevArea.getSpaceAfter()); // } // spaceSpec.addSpace(nextArea.getSpaceBefore()); return spaceSpec.resolve(false); } /** * Add a block spacer for space before and space after a block. * This adds an empty Block area that acts as a block space. * * @param adjust the adjustment value * @param minoptmax the min/opt/max value of the spacing */ public void addBlockSpacing(double adjust, MinOptMax minoptmax) { if (minoptmax == null) { return; } int sp = minoptmax.opt; if (adjust > 0) { sp = sp + (int)(adjust * (minoptmax.max - minoptmax.opt)); } else { sp = sp + (int)(adjust * (minoptmax.opt - minoptmax.min)); } if (sp != 0) { Block spacer = new Block(); spacer.setBPD(sp); parentLM.addChildArea(spacer); } } /** * Add the childArea to the passed area. * Called by child LayoutManager when it has filled one of its areas. * The LM should already have an Area in which to put the child. * See if the area will fit in the current area. * If so, add it. Otherwise initiate breaking. * @param childArea the area to add: will be some block-stacked Area. * @param parentArea the area in which to add the childArea */ protected void addChildToArea(Area childArea, BlockParent parentArea) { // This should be a block-level Area (Block in the generic sense) if (!(childArea instanceof Block)) { //log.error("Child not a Block in BlockStackingLM!"); } MinOptMax spaceBefore = resolveSpaceSpecifier(childArea); parentArea.addBlock((Block) childArea); flush(); // hand off current area to parent } /** * Add the childArea to the current area. * Called by child LayoutManager when it has filled one of its areas. * The LM should already have an Area in which to put the child. * See if the area will fit in the current area. * If so, add it. Otherwise initiate breaking. * @param childArea the area to add: will be some block-stacked Area. */ public void addChildArea(Area childArea) { addChildToArea(childArea, getCurrentArea()); } /** * Force current area to be added to parent area. */ protected void flush() { if (getCurrentArea() != null) { parentLM.addChildArea(getCurrentArea()); } } /** * Adds a Position to the Position participating in the first|last determination by assigning * it a unique position index. * @param pos the Position * @return the same Position but with a position index */ protected Position notifyPos(Position pos) { if (pos.getIndex() >= 0) { throw new IllegalStateException("Position already got its index"); } lastGeneratedPosition++; pos.setIndex(lastGeneratedPosition); return pos; } /** * Indicates whether the given Position is the first area-generating Position of this LM. * @param pos the Position (must be one with a position index) * @return True if it is the first Position */ public boolean isFirst(Position pos) { //log.trace("isFirst() smallestPosNumberChecked=" + smallestPosNumberChecked + " " + pos); if (pos.getIndex() < 0) { throw new IllegalArgumentException("Only Positions with an index can be checked"); } if (pos.getIndex() == this.smallestPosNumberChecked) { return true; } else if (pos.getIndex() < this.smallestPosNumberChecked) { this.smallestPosNumberChecked = pos.getIndex(); return true; } else { return false; } } /** * Indicates whether the given Position is the last area-generating Position of this LM. * @param pos the Position (must be one with a position index) * @return True if it is the last Position */ public boolean isLast(Position pos) { //log.trace("isLast() lastGenPos=" + lastGeneratedPosition + " " + pos); if (pos.getIndex() < 0) { throw new IllegalArgumentException("Only Positions with an index can be checked"); } return (pos.getIndex() == this.lastGeneratedPosition && isFinished()); } /** @return a cached auxiliary Position instance used for things like spaces. */ protected Position getAuxiliaryPosition() { if (this.auxiliaryPosition == null) { this.auxiliaryPosition = new NonLeafPosition(this, null); } return this.auxiliaryPosition; } /** * @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); } /** * @see LayoutManager#getNextKnuthElements(LayoutContext, int) */ 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 = 0; int bIndents = 0; if (fobj instanceof org.apache.fop.fo.flow.Block) { org.apache.fop.fo.flow.Block block = (org.apache.fop.fo.flow.Block)fobj; iIndents = block.getCommonMarginBlock().startIndent.getValue(this) + block.getCommonMarginBlock().endIndent.getValue(this); bIndents = block.getCommonBorderPaddingBackground().getBPPaddingAndBorder(false, this); } int ipd = referenceIPD - iIndents; MinOptMax stackSize = new MinOptMax(); // Set context for percentage property values. setContentAreaIPD(ipd); LinkedList returnedList = null; LinkedList contentList = new LinkedList(); LinkedList returnList = new LinkedList(); if (!bBreakBeforeServed) { try { if (addKnuthElementsForBreakBefore(returnList)) { return returnList; } } finally { bBreakBeforeServed = true; } } if (!bSpaceBeforeServed) { addKnuthElementsForSpaceBefore(returnList, alignment); bSpaceBeforeServed = true; } addKnuthElementsForBorderPaddingBefore(returnList); 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.setStackLimit(context.getStackLimit()); childLC.setRefIPD(referenceIPD); } // get elements from curLM returnedList = curLM.getNextKnuthElements(childLC, alignment); if (contentList.size() == 0 && childLC.isKeepWithPreviousPending()) { context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); } if (returnedList != null && 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() || context.isKeepWithNextPending() || childLC.isKeepWithPreviousPending()) { //Clear keep pending flag context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); // 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 } } if (returnedList == null || returnedList.size() == 0) { //Avoid NoSuchElementException below (happens with empty blocks) continue; } contentList.addAll(returnedList); 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; } /* if (allocatedSpace.min > context.getStackLimit().max) { log.debug("Allocated space exceeds stack limit, returning early."); return returnList; }*/ } if (childLC.isKeepWithNextPending()) { //Clear and propagate childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); } 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(); if (contentList.size() > 0) { wrapPositionElements(contentList, returnList); } else { //Empty fo:block, zero-length box makes sure the IDs are registered. returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true)); } addKnuthElementsForBorderPaddingAfter(returnList); addKnuthElementsForSpaceAfter(returnList, alignment); addKnuthElementsForBreakAfter(returnList); if (mustKeepWithNext()) { context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); } if (mustKeepWithPrevious()) { context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); } setFinished(true); return returnList; } /** * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement) */ 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 MappingPosition mappingPos = (MappingPosition)innerPosition; if (lastElement.isGlue()) { // lastElement is a glue /*LF*/ //System.out.println(" BLM.negotiateBPDAdjustment> bpunit con glue"); ListIterator storedListIterator = storedList.listIterator( mappingPos.getFirstIndex()); int newAdjustment = 0; while (storedListIterator.nextIndex() <= mappingPos.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(mappingPos.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 log.error("BlockLayoutManager.negotiateBPDAdjustment(): unexpected Position"); return 0; } } /** * @see BlockLevelLayoutManager#discardSpace(KnuthGlue) */ public void discardSpace(KnuthGlue spaceGlue) { //System.out.println(" BLM.discardSpace> " + spaceGlue.getPosition().getClass().getName()); Position innerPosition = ((NonLeafPosition) spaceGlue.getPosition()).getPosition(); 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; foSpaceBefore = new MinOptMax(0); } else { // space-after must be discarded adjustedSpaceAfter = 0; foSpaceAfter = new MinOptMax(0); //TODO Why are both cases handled in the same way? } } 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); } } /** * @see LayoutManager#getChangedKnuthElements(List, int) */ public LinkedList getChangedKnuthElements(List oldList, 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(); //System.out.println(" BLM> unwrapping: " // + (oldElement.isBox() ? "box " : (oldElement.isGlue() ? "glue " : "penalty")) // + " creato da " + oldElement.getLayoutManager().getClass().getName()); //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(); //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(); //System.out.println(""); //System.out.println(" BLM.getChangedKnuthElements> workList.size() = " // + workList.size() + " da 0 a " + (workList.size() - 1)); while (workListIterator.hasNext()) { currElement = (KnuthElement) workListIterator.next(); //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) { //System.out.println(" BLM.getChangedKnuthElements> chiamata da " // + fromIndex + " a " + workListIterator.previousIndex() + " su " // + prevLM.getClass().getName()); returnedList.addAll(prevLM.getChangedKnuthElements(workList.subList( fromIndex, workListIterator.previousIndex()), alignment)); bSomethingAdded = true; } else { // prevLM == this // do nothing //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) { //System.out.println(" BLM.getChangedKnuthElements> chiamata da " + fromIndex // + " a " + oldList.size() + " su " + currLM.getClass().getName()); returnedList.addAll(currLM.getChangedKnuthElements( workList.subList(fromIndex, workList.size()), alignment)); } else { // currLM == this // there are no more elements to add // remove the last penalty added to returnedList if (returnedList.size() > 0) { returnedList.removeLast(); } //System.out.println(" BLM.getChangedKnuthElements> elementi propri, ignorati, da " // + fromIndex + " a " + workList.size()); } } // append elements representing space-before boolean spaceBeforeIsConditional = true; if (fobj instanceof org.apache.fop.fo.flow.Block) { spaceBeforeIsConditional = ((org.apache.fop.fo.flow.Block)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)); } } //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 = true; if (fobj instanceof org.apache.fop.fo.flow.Block) { spaceAfterIsConditional = ((org.apache.fop.fo.flow.Block)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)); } } //System.out.println(" BLM.getChangedKnuthElements> finished: returnList.size() = " // + returnList.size()); return returnList; } /** * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether() */ public boolean mustKeepTogether() { return false; } /** * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious() */ public boolean mustKeepWithPrevious() { return false; } /** * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext() */ public boolean mustKeepWithNext() { return false; } /** * Creates Knuth elements for before border padding and adds them to the return list. * @param returnList return list to add the additional elements to */ protected void addKnuthElementsForBorderPaddingBefore(LinkedList returnList/*, Position returnPosition*/) { //Border and Padding (before) CommonBorderPaddingBackground borderAndPadding = null; if (fobj instanceof org.apache.fop.fo.flow.Block) { borderAndPadding = ((org.apache.fop.fo.flow.Block)fobj) .getCommonBorderPaddingBackground(); } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { borderAndPadding = ((org.apache.fop.fo.flow.BlockContainer)fobj) .getCommonBorderPaddingBackground(); } if (borderAndPadding != null) { //TODO Handle conditionality int bpBefore = borderAndPadding.getBorderBeforeWidth(false) + borderAndPadding.getPaddingBefore(false, this); if (bpBefore > 0) { returnList.add(new KnuthBox(bpBefore, getAuxiliaryPosition(), 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 */ protected void addKnuthElementsForBorderPaddingAfter(LinkedList returnList/*, Position returnPosition*/) { //Border and Padding (after) CommonBorderPaddingBackground borderAndPadding = null; if (fobj instanceof org.apache.fop.fo.flow.Block) { borderAndPadding = ((org.apache.fop.fo.flow.Block)fobj) .getCommonBorderPaddingBackground(); } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { borderAndPadding = ((org.apache.fop.fo.flow.BlockContainer)fobj) .getCommonBorderPaddingBackground(); } if (borderAndPadding != null) { //TODO Handle conditionality int bpAfter = borderAndPadding.getBorderAfterWidth(false) + borderAndPadding.getPaddingAfter(false, this); if (bpAfter > 0) { returnList.add(new KnuthBox(bpAfter, getAuxiliaryPosition(), true)); } } } /** * Creates Knuth elements for break-before and adds them to the return list. * @param returnList return list to add the additional elements to * @return true if an element has been added due to a break-before. */ protected boolean addKnuthElementsForBreakBefore(LinkedList returnList/*, Position returnPosition*/) { int breakBefore = -1; if (fobj instanceof org.apache.fop.fo.flow.Block) { breakBefore = ((org.apache.fop.fo.flow.Block) fobj).getBreakBefore(); } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { breakBefore = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakBefore(); } else if (fobj instanceof org.apache.fop.fo.flow.Table) { breakBefore = ((org.apache.fop.fo.flow.Table) fobj).getBreakBefore(); } if (breakBefore == EN_PAGE || breakBefore == EN_COLUMN || 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, getAuxiliaryPosition(), 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 * @return true if an element has been added due to a break-after. */ protected boolean addKnuthElementsForBreakAfter(LinkedList returnList/*, Position returnPosition*/) { int breakAfter = -1; if (fobj instanceof org.apache.fop.fo.flow.Block) { breakAfter = ((org.apache.fop.fo.flow.Block) fobj).getBreakAfter(); } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { breakAfter = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakAfter(); } else if (fobj instanceof org.apache.fop.fo.flow.Table) { breakAfter = ((org.apache.fop.fo.flow.Table) fobj).getBreakAfter(); } if (breakAfter == EN_PAGE || breakAfter == EN_COLUMN || 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, getAuxiliaryPosition(), false)); 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 alignment vertical alignment */ protected void addKnuthElementsForSpaceBefore(LinkedList returnList/*, Position returnPosition*/, int alignment) { SpaceProperty spaceBefore = null; if (fobj instanceof org.apache.fop.fo.flow.Block) { spaceBefore = ((org.apache.fop.fo.flow.Block)fobj) .getCommonMarginBlock().spaceBefore; } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { spaceBefore = ((org.apache.fop.fo.flow.BlockContainer)fobj) .getCommonMarginBlock().spaceBefore; } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { spaceBefore = ((org.apache.fop.fo.flow.ListBlock)fobj) .getCommonMarginBlock().spaceBefore; } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { spaceBefore = ((org.apache.fop.fo.flow.ListItem)fobj) .getCommonMarginBlock().spaceBefore; } // append elements representing space-before if (bpUnit > 0 || spaceBefore != null && !(spaceBefore.getMinimum(this).getLength().getValue(this) == 0 && spaceBefore.getMaximum(this).getLength().getValue(this) == 0)) { if (spaceBefore != null && !spaceBefore.getSpace().isDiscard()) { // add elements to prevent the glue to be discarded returnList.add(new KnuthBox(0, getAuxiliaryPosition(), false)); returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, getAuxiliaryPosition(), false)); } if (bpUnit > 0) { returnList.add(new KnuthGlue(0, 0, 0, BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT, getAuxiliaryPosition(), true)); } else /*if (alignment == EN_JUSTIFY)*/ { returnList.add(new KnuthGlue( spaceBefore.getOptimum(this).getLength().getValue(this), spaceBefore.getMaximum(this).getLength().getValue(this) - spaceBefore.getOptimum(this).getLength().getValue(this), spaceBefore.getOptimum(this).getLength().getValue(this) - spaceBefore.getMinimum(this).getLength().getValue(this), BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT, getAuxiliaryPosition(), true)); } /*else { returnList.add(new KnuthGlue( spaceBefore.getOptimum().getLength().getValue(this), 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 alignment vertical alignment */ protected void addKnuthElementsForSpaceAfter(LinkedList returnList/*, Position returnPosition*/, int alignment) { SpaceProperty spaceAfter = null; if (fobj instanceof org.apache.fop.fo.flow.Block) { spaceAfter = ((org.apache.fop.fo.flow.Block)fobj) .getCommonMarginBlock().spaceAfter; } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) { spaceAfter = ((org.apache.fop.fo.flow.BlockContainer)fobj) .getCommonMarginBlock().spaceAfter; } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) { spaceAfter = ((org.apache.fop.fo.flow.ListBlock)fobj) .getCommonMarginBlock().spaceAfter; } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) { spaceAfter = ((org.apache.fop.fo.flow.ListItem)fobj) .getCommonMarginBlock().spaceAfter; } // append elements representing space-after if (bpUnit > 0 || spaceAfter != null && !(spaceAfter.getMinimum(this).getLength().getValue(this) == 0 && spaceAfter.getMaximum(this).getLength().getValue(this) == 0)) { if (spaceAfter != null && !spaceAfter.getSpace().isDiscard()) { returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, getAuxiliaryPosition(), false)); } if (bpUnit > 0) { returnList.add(new KnuthGlue(0, 0, 0, BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, getAuxiliaryPosition(), true)); } else /*if (alignment == EN_JUSTIFY)*/ { returnList.add(new KnuthGlue( spaceAfter.getOptimum(this).getLength().getValue(this), spaceAfter.getMaximum(this).getLength().getValue(this) - spaceAfter.getOptimum(this).getLength().getValue(this), spaceAfter.getOptimum(this).getLength().getValue(this) - spaceAfter.getMinimum(this).getLength().getValue(this), BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, getAuxiliaryPosition(), (!spaceAfter.getSpace().isDiscard()) ? false : true)); } /*else { returnList.add(new KnuthGlue( spaceAfter.getOptimum().getLength().getValue(this), 0, 0, BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, returnPosition, (!spaceAfter.getSpace().isDiscard()) ? false : true)); }*/ if (spaceAfter != null && !spaceAfter.getSpace().isDiscard()) { returnList.add(new KnuthBox(0, getAuxiliaryPosition(), true)); } } } protected LinkedList createUnitElements(LinkedList oldList) { //System.out.println(" "); //System.out.println("Start conversion: " + oldList.size() // + " elements, space-before.min=" + layoutProps.spaceBefore.getSpace().min // + " space-after.min=" + 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()) { totalLength.add(new MinOptMax(element.getW())); //System.out.println("box " + element.getW()); } else if (element.isGlue()) { totalLength.min -= ((KnuthGlue) element).getZ(); totalLength.max += ((KnuthGlue) element).getY(); //leafValue = ((LeafPosition) element.getPosition()).getLeafPos(); //System.out.println("glue " + element.getW() + " + " // + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ()); } else { //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); //System.out.println("(" // + unsuppressibleUnits.min + "-" + unsuppressibleUnits.opt + "-" // + unsuppressibleUnits.max + ") " // + " -> " + unitsBeforeBreak.min + "-" + unitsBeforeBreak.opt + "-" // + unitsBeforeBreak.max // + " + " + unitsAfterBreak.min + "-" + unitsAfterBreak.opt + "-" // + unitsAfterBreak.max // + (uLengthChange != 0 ? " [length " + uLengthChange + "] " : "") // + (uStretchChange != 0 ? " [stretch " + uStretchChange + "] " : "") // + (uShrinkChange != 0 ? " [shrink " + uShrinkChange + "]" : "")); // 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 boolean correctFirstElement = false; if (fobj instanceof org.apache.fop.fo.flow.Block) { correctFirstElement = ((org.apache.fop.fo.flow.Block)fobj) .getCommonMarginBlock().spaceBefore.getSpace().isDiscard(); } if (correctFirstElement) { // 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 boolean correctLastElement = false; if (fobj instanceof org.apache.fop.fo.flow.Block) { correctLastElement = ((org.apache.fop.fo.flow.Block)fobj) .getCommonMarginBlock().spaceAfter.getSpace().isDiscard(); } if (correctLastElement) { // 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; } 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) { wrapPositionElements(sourceList, targetList, false); } /** * "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 * @param force if true, every Position is wrapper regardless of its LM of origin */ protected void wrapPositionElements(List sourceList, List targetList, boolean force) { ListIterator listIter = sourceList.listIterator(); while (listIter.hasNext()) { KnuthElement tempElement; tempElement = (KnuthElement) listIter.next(); if (force || tempElement.getLayoutManager() != this) { tempElement.setPosition(notifyPos(new NonLeafPosition(this, tempElement.getPosition()))); } targetList.add(tempElement); } } /** * Returns the IPD of the content area * @return the IPD of the content area */ public int getContentAreaIPD() { return contentAreaIPD; } protected void setContentAreaIPD(int contentAreaIPD) { this.contentAreaIPD = contentAreaIPD; } /** * Returns the BPD of the content area * @return the BPD of the content area */ public int getContentAreaBPD() { return -1; } }