]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Bugfix: IPD for footnote region now correct in multi-column layout.
authorJeremias Maerki <jeremias@apache.org>
Wed, 29 Jun 2005 13:15:43 +0000 (13:15 +0000)
committerJeremias Maerki <jeremias@apache.org>
Wed, 29 Jun 2005 13:15:43 +0000 (13:15 +0000)
Next step at multi-column layout:
- A multi-column section that needs column balancing is normally rendered until the next-to-last page. The rest of the element are re-broken by a special balancing page breaker.
- Multiple spans supported in area tree and through break handling.
- There are still problems with footnotes and column balancing.
- Main layout loop changed to render an element list right after it's broken. The block lists are not collected anymore and then rendered.
Bugfix: PageViewportProvider had a one-off (when accessing through "relative to current element list")

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@202368 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java

index 7b5a2eb5aedf622da1a988de8bbe3800013ba826..5b14e5dab841c47b21ded80736707dba5cd6aefb 100644 (file)
@@ -149,10 +149,22 @@ public abstract class AbstractBreaker {
     
     protected abstract void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp);
 
+    /**
+     * Creates the top-level LayoutContext for the breaker operation.
+     * @return the top-level LayoutContext
+     */
     protected LayoutContext createLayoutContext() {
         return new LayoutContext(0);
     }
     
+    /**
+     * Used to update the LayoutContext in subclasses prior to starting a new element list.
+     * @param context the LayoutContext to update
+     */
+    protected void updateLayoutContext(LayoutContext context) {
+        //nop
+    }
+    
     public void doLayout(int flowBPD) {
         LayoutContext childLC = createLayoutContext();
         childLC.setStackLimit(new MinOptMax(flowBPD));
@@ -175,53 +187,56 @@ public abstract class AbstractBreaker {
         //*** Phase 1: Get Knuth elements ***
         int nextSequenceStartsOn = Constants.EN_ANY;
         while (hasMoreContent()) {
+            blockLists.clear();
+
             nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn, blockLists);
-        }
 
-        //*** Phase 2: Alignment and breaking ***
-        log.debug("PLM> blockLists.size() = " + blockLists.size());
-        for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
-            blockList = (BlockSequence) blockLists.get(blockListIndex);
-            
-            //debug code start
-            if (log.isDebugEnabled()) {
-                log.debug("  blockListIndex = " + blockListIndex);
-                String pagina = (blockList.startOn == Constants.EN_ANY) ? "any page"
-                        : (blockList.startOn == Constants.EN_ODD_PAGE) ? "odd page"
-                                : "even page";
-                log.debug("  sequence starts on " + pagina);
-            }
-            ElementListObserver.observe(blockList, "breaker", null);
-            //debug code end
-
-            log.debug("PLM> start of algorithm (" + this.getClass().getName() 
-                    + "), flow BPD =" + flowBPD);
-            PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
-                    getPageViewportProvider(),
-                    alignment, alignmentLast, footnoteSeparatorLength,
-                    isPartOverflowRecoveryActivated());
-            int iOptPageCount;
-
-            BlockSequence effectiveList;
-            if (alignment == Constants.EN_JUSTIFY) {
-                /* justification */
-                effectiveList = justifyBoxes(blockList, alg, flowBPD);
-            } else {
-                /* no justification */
-                effectiveList = blockList;
-            }
+            //*** Phase 2: Alignment and breaking ***
+            log.debug("PLM> blockLists.size() = " + blockLists.size());
+            for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
+                blockList = (BlockSequence) blockLists.get(blockListIndex);
+                
+                //debug code start
+                if (log.isDebugEnabled()) {
+                    log.debug("  blockListIndex = " + blockListIndex);
+                    String pagina = (blockList.startOn == Constants.EN_ANY) ? "any page"
+                            : (blockList.startOn == Constants.EN_ODD_PAGE) ? "odd page"
+                                    : "even page";
+                    log.debug("  sequence starts on " + pagina);
+                }
+                ElementListObserver.observe(blockList, "breaker", null);
+                //debug code end
+
+                log.debug("PLM> start of algorithm (" + this.getClass().getName() 
+                        + "), flow BPD =" + flowBPD);
+                PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
+                        getPageViewportProvider(),
+                        alignment, alignmentLast, footnoteSeparatorLength,
+                        isPartOverflowRecoveryActivated());
+                int iOptPageCount;
+
+                BlockSequence effectiveList;
+                if (alignment == Constants.EN_JUSTIFY) {
+                    /* justification */
+                    effectiveList = justifyBoxes(blockList, alg, flowBPD);
+                } else {
+                    /* no justification */
+                    effectiveList = blockList;
+                }
 
-            //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
-            alg.setConstantLineWidth(flowBPD);
-            iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
-                        1, true, true);
-            log.debug("PLM> iOptPageCount= " + iOptPageCount
-                    + " pageBreaks.size()= " + alg.getPageBreaks().size());
+                //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
+                alg.setConstantLineWidth(flowBPD);
+                iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
+                            1, true, true);
+                log.debug("PLM> iOptPageCount= " + iOptPageCount
+                        + " pageBreaks.size()= " + alg.getPageBreaks().size());
 
-            
-            //*** Phase 3: Add areas ***
-            doPhase3(alg, iOptPageCount, blockList, effectiveList);
+                
+                //*** Phase 3: Add areas ***
+                doPhase3(alg, iOptPageCount, blockList, effectiveList);
+            }
         }
+
     }
 
     /**
@@ -356,6 +371,16 @@ public abstract class AbstractBreaker {
         }
     }
     
+    /**
+     * Handles span changes reported through the <code>LayoutContext</code>. 
+     * Only used by the PSLM and called by <code>getNextBlockList()</code>.
+     * @param childLC the LayoutContext
+     * @param nextSequenceStartsOn previous value for break handling
+     * @return effective value for break handling
+     */
+    protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) {
+        return nextSequenceStartsOn;
+    }
     /**
      * 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
@@ -363,7 +388,13 @@ public abstract class AbstractBreaker {
      * @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) {
+    protected int getNextBlockList(LayoutContext childLC, 
+            int nextSequenceStartsOn, 
+            List blockLists) {
+        updateLayoutContext(childLC);
+        //Make sure the span change signal is reset
+        childLC.signalSpanChange(Constants.NOT_SET);
+        
         LinkedList returnedList;
         BlockSequence blockList;
         if ((returnedList = getNextKnuthElements(childLC, alignment)) != null) {
@@ -371,6 +402,10 @@ public abstract class AbstractBreaker {
                 return nextSequenceStartsOn;
             }
             blockList = new BlockSequence(nextSequenceStartsOn);
+            
+            //Only implemented by the PSLM
+            nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn);
+            
             if (((KnuthElement) returnedList.getLast()).isPenalty()
                     && ((KnuthPenalty) returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
                 KnuthPenalty breakPenalty = (KnuthPenalty) returnedList
index b96d2ad78709a6bc6fa6a14c4a151f3a7bda85d3..a303630e7a9d325fa7d48f588ad6e0d3f6242bfb 100644 (file)
@@ -22,7 +22,6 @@ import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.ListIterator;
 
-import org.apache.fop.area.PageViewport;
 import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
 
 import org.apache.fop.traits.MinOptMax;
@@ -752,10 +751,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
     protected int getLineWidth(int line) {
         int bpd;
         if (pvProvider != null) {
-            PageViewport pv = pvProvider.getPageViewport(
-                    false, line, 
-                    PageSequenceLayoutManager.PageViewportProvider.RELTO_CURRENT_ELEMENT_LIST);
-            bpd = pv.getBodyRegion().getBPD(); 
+            bpd = pvProvider.getAvailableBPD(line);
         } else {
             bpd = super.getLineWidth(line);
         }
index 30f2ebbbd2c1b5ef0604a5bdc8da75b537581671..c64a307889022f306e1cc8eb542ddaeb4b6e781a 100644 (file)
@@ -18,6 +18,8 @@
 
 package org.apache.fop.layoutmgr;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.fop.apps.FOPException;
 
 import org.apache.fop.area.AreaTreeHandler;
@@ -52,6 +54,8 @@ import java.util.ListIterator;
  */
 public class PageSequenceLayoutManager extends AbstractLayoutManager {
 
+    private Log log = LogFactory.getLog(PageSequenceLayoutManager.class);
+
     /** 
      * AreaTreeHandler which activates the PSLM and controls
      * the rendering of its pages.
@@ -137,7 +141,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             makeFlowLayoutManager(this, mainFlow);
 
         PageBreaker breaker = new PageBreaker(this);
-        int flowBPD = (int) curPV.getBodyRegion().getBPD();
+        int flowBPD = (int) curPV.getBodyRegion().getRemainingBPD();
         breaker.doLayout(flowBPD);
         
         finishPage();
@@ -150,6 +154,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         
         private PageSequenceLayoutManager pslm;
         private boolean firstPart = true;
+        private boolean pageBreakHandled;
+        private boolean needColumnBalancing;
         
         private StaticContentLayoutManager footnoteSeparatorLM = null;
 
@@ -157,11 +163,10 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             this.pslm = pslm;
         }
         
-        protected LayoutContext createLayoutContext() {
-            LayoutContext lc = new LayoutContext(0);
+        /** @see org.apache.fop.layoutmgr.AbstractBreaker */
+        protected void updateLayoutContext(LayoutContext context) {
             int flowIPD = curPV.getCurrentSpan().getColumnWidth();
-            lc.setRefIPD(flowIPD);
-            return lc;
+            context.setRefIPD(flowIPD);
         }
         
         protected LayoutManager getTopLevelLM() {
@@ -173,6 +178,39 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             return pvProvider;
         }
         
+        /** @see org.apache.fop.layoutmgr.AbstractBreaker */
+        protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) {
+            needColumnBalancing = false;
+            if (childLC.getNextSpan() != Constants.NOT_SET) {
+                //Next block list will have a different span.
+                nextSequenceStartsOn = childLC.getNextSpan();
+                needColumnBalancing = (childLC.getNextSpan() == Constants.EN_ALL);
+            }
+            if (needColumnBalancing) {
+                log.debug("Column balancing necessary for the next element list!!!");
+            }
+            return nextSequenceStartsOn;
+        }
+
+        /** @see org.apache.fop.layoutmgr.AbstractBreaker */
+        protected int getNextBlockList(LayoutContext childLC, 
+                int nextSequenceStartsOn, 
+                List blockLists) {
+            if (!firstPart) {
+                // if this is the first page that will be created by
+                // the current BlockSequence, it could have a break
+                // condition that must be satisfied;
+                // otherwise, we may simply need a new page
+                handleBreakTrait(nextSequenceStartsOn);
+            }
+            firstPart = false;
+            pageBreakHandled = true;
+            pvProvider.setStartOfNextElementList(currentPageNum, 
+                    curPV.getCurrentSpan().getCurrentFlowIndex());
+            return super.getNextBlockList(childLC, nextSequenceStartsOn, blockLists);
+        }
+        
+        /** @see org.apache.fop.layoutmgr.AbstractBreaker */
         protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
             LinkedList contentList = null;
             
@@ -190,6 +228,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                         && ((KnuthBlockBox) element).hasAnchors()) {
                         // element represents a line with footnote citations
                         bFootnotesPresent = true;
+                        LayoutContext footnoteContext = new LayoutContext(context);
+                        footnoteContext.setRefIPD(getCurrentPV()
+                                .getRegionReference(Constants.FO_REGION_BODY).getIPD());
                         LinkedList footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs();
                         ListIterator footnoteBodyIterator = footnoteBodyLMs.listIterator();
                         // store the lists of elements representing the footnote bodies
@@ -199,7 +240,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                                 = (FootnoteBodyLayoutManager) footnoteBodyIterator.next();
                             fblm.setParent(childFLM);
                             ((KnuthBlockBox) element).addElementList(
-                                    fblm.getNextKnuthElements(context, alignment));
+                                    fblm.getNextKnuthElements(footnoteContext, alignment));
                         }
                     }
                 }
@@ -219,7 +260,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
 
                 // create a Block area that will contain the separator areas
                 separatorArea = new Block();
-                separatorArea.setIPD(context.getRefIPD());
+                separatorArea.setIPD(pslm.getCurrentPV()
+                            .getRegionReference(Constants.FO_REGION_BODY).getIPD());
                 // create a StaticContentLM for the footnote separator
                 footnoteSeparatorLM = (StaticContentLayoutManager)
                     getLayoutManagerMaker().makeStaticContentLayoutManager(
@@ -245,7 +287,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                         "xsl-footnote-separator");
                 // create a Block area that will contain the separator areas
                 separatorArea = new Block();
-                separatorArea.setIPD(curPV.getCurrentSpan().getColumnWidth());
+                separatorArea.setIPD(curPV.getRegionReference(Constants.FO_REGION_BODY).getIPD());
                 // create a StaticContentLM for the footnote separator
                 footnoteSeparatorLM = (StaticContentLayoutManager)
                     getLayoutManagerMaker().makeStaticContentLayoutManager(
@@ -258,30 +300,74 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         
         protected void doPhase3(PageBreakingAlgorithm alg, int partCount, 
                 BlockSequence originalList, BlockSequence effectiveList) {
-            //Directly add areas after finding the breaks
-            addAreas(alg, partCount, originalList, effectiveList);
+            if (needColumnBalancing) {
+                log.debug("Column balancing now!!!");
+                log.debug("===================================================");
+                int restartPoint = pvProvider.getStartingPartIndexForLastPage(partCount);
+                if (restartPoint > 0) {
+                    addAreas(alg, restartPoint, originalList, effectiveList);
+                }
+                
+                int newStartPos;
+                if (restartPoint > 0) {
+                    PageBreakPosition pbp = (PageBreakPosition)
+                            alg.getPageBreaks().get(restartPoint - 1);
+                    newStartPos = pbp.getLeafPos();
+                } else {
+                    newStartPos = 0;
+                }
+                log.debug("Restarting at " + restartPoint + ", new start position: " + newStartPos);
+                
+                //Restart last page
+                PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm(
+                        getTopLevelLM(),
+                        getPageViewportProvider(),
+                        alignment, Constants.EN_START, footnoteSeparatorLength,
+                        isPartOverflowRecoveryActivated(),
+                        getCurrentPV().getBodyRegion().getColumnCount());
+                //alg.setConstantLineWidth(flowBPD);
+                int iOptPageCount = algRestart.findBreakingPoints(effectiveList,
+                            newStartPos,
+                            1, true, true);
+                log.debug("restart: iOptPageCount= " + iOptPageCount
+                        + " pageBreaks.size()= " + algRestart.getPageBreaks().size());
+                if (iOptPageCount > getCurrentPV().getBodyRegion().getColumnCount()) {
+                    /* reenable when everything works
+                    throw new IllegalStateException(
+                            "Breaking algorithm must not produce more columns than available.");
+                    */
+                }
+                //Make sure we only add the areas we haven't added already
+                effectiveList.ignoreAtStart = newStartPos;
+                addAreas(algRestart, iOptPageCount, originalList, effectiveList);
+                log.debug("===================================================");
+            } else {
+                //Directly add areas after finding the breaks
+                addAreas(alg, partCount, originalList, effectiveList);
+            }
         }
         
         protected void startPart(BlockSequence list, int breakClass) {
+            log.info("startPart() breakClass=" + breakClass);
             if (curPV == null) {
                 throw new IllegalStateException("curPV must not be null");
-            } else {
+            }
+            if (!pageBreakHandled) {
+                
                 //firstPart is necessary because we need the first page before we start the 
                 //algorithm so we have a BPD and IPD. This may subject to change later when we
                 //start handling more complex cases.
                 if (!firstPart) {
-                    if (curPV.getCurrentSpan().hasMoreFlows()) {
-                        curPV.getCurrentSpan().moveToNextFlow();
-                    } else  {
-                        // if this is the first page that will be created by
-                        // the current BlockSequence, it could have a break
-                        // condition that must be satisfied;
-                        // otherwise, we may simply need a new page
-                        handleBreakTrait(breakClass);
-                    }
+                    // if this is the first page that will be created by
+                    // the current BlockSequence, it could have a break
+                    // condition that must be satisfied;
+                    // otherwise, we may simply need a new page
+                    handleBreakTrait(breakClass);
                 }
-                pvProvider.setStartPageOfNextElementList(currentPageNum);
+                pvProvider.setStartOfNextElementList(currentPageNum, 
+                        curPV.getCurrentSpan().getCurrentFlowIndex());
             }
+            pageBreakHandled = false;
             // add static areas and resolve any new id areas
             // finish page and add to area tree
             firstPart = false;
@@ -319,6 +405,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                 parentArea.setTop(topOffset);
                 parentArea.setSeparator(separatorArea);
             }
+            getCurrentPV().getCurrentSpan().notifyFlowsFinished();
         }
         
         protected LayoutManager getCurrentChildLM() {
@@ -510,7 +597,14 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
      * @param breakVal - value of break-before or break-after trait.
      */
     private void handleBreakTrait(int breakVal) {
-        if (breakVal == Constants.EN_COLUMN) {
+        if (breakVal == Constants.EN_ALL) {
+            //break due to span change in multi-column layout
+            curPV.createSpan(true);
+            return;
+        } else if (breakVal == Constants.EN_NONE) {
+            curPV.createSpan(false);
+            return;
+        } else if (breakVal == Constants.EN_COLUMN || breakVal == -1) {
             if (curPV.getCurrentSpan().hasMoreFlows()) {
                 curPV.getCurrentSpan().moveToNextFlow();
             } else {
@@ -577,6 +671,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
      */
     public class PageViewportProvider {
         
+        private Log log = LogFactory.getLog(PageViewportProvider.class);
+
         /** Indices are evaluated relative to the first page in the page-sequence. */
         public static final int RELTO_PAGE_SEQUENCE = 0;
         /** Indices are evaluated relative to the first page in the current element list. */
@@ -584,8 +680,13 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         
         private int startPageOfPageSequence;
         private int startPageOfCurrentElementList;
+        private int startColumnOfCurrentElementList;
         private List cachedPageViewports = new java.util.ArrayList();
         
+        //Cache to optimize getAvailableBPD() calls
+        private int lastRequestedIndex = -1;
+        private int lastReportedBPD = -1;
+        
         /**
          * Main constructor.
          * @param ps The page-sequence the provider operates on
@@ -598,12 +699,83 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
          * The page breaker notifies the provider about the page number an element list starts
          * on so it can later retrieve PageViewports relative to this first page.
          * @param startPage the number of the first page for the element list.
+         * @param startColumn the starting column number for the element list. 
+         */
+        public void setStartOfNextElementList(int startPage, int startColumn) {
+            log.debug("start of the next element list is:"
+                    + " page=" + startPage + " col=" + startColumn);
+            this.startPageOfCurrentElementList = startPage - startPageOfPageSequence + 1;
+            this.startColumnOfCurrentElementList = startColumn;
+            //Reset Cache
+            this.lastRequestedIndex = -1;
+            this.lastReportedBPD = -1;
+        }
+        
+        /**
+         * Returns the available BPD for the part/page indicated by the index parameter.
+         * The index is the part/page relative to the start of the current element list.
+         * This method takes multiple columns into account.
+         * @param index zero-based index of the requested part/page
+         * @return the available BPD
          */
-        public void setStartPageOfNextElementList(int startPage) {
-            log.debug("start page of the next element list is: " + startPage);
-            this.startPageOfCurrentElementList = startPage;
+        public int getAvailableBPD(int index) {
+            //Special optimization: There may be many equal calls by the BreakingAlgorithm
+            if (this.lastRequestedIndex == index) {
+                if (log.isTraceEnabled()) {
+                    log.trace("getAvailableBPD(" + index + ") -> (cached) " + lastReportedBPD);
+                }
+                return this.lastReportedBPD;
+            }
+            int c = index;
+            int pageIndex = 0;
+            int colIndex = startColumnOfCurrentElementList;
+            PageViewport pv = getPageViewport(
+                    false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
+            while (c > 0) {
+                colIndex++;
+                if (colIndex >= pv.getCurrentSpan().getColumnCount()) {
+                    colIndex = 0;
+                    pageIndex++;
+                    pv = getPageViewport(
+                            false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
+                }
+                c--;
+            }
+            this.lastRequestedIndex = index;
+            this.lastReportedBPD = pv.getBodyRegion().getRemainingBPD();
+            if (log.isTraceEnabled()) {
+                log.trace("getAvailableBPD(" + index + ") -> " + lastReportedBPD);
+            }
+            return this.lastReportedBPD;
         }
         
+        /**
+         * Returns the part index (0<x<partCount) which denotes the first part on the last page 
+         * generated by the current element list.
+         * @param partCount Number of parts determined by the breaking algorithm
+         * @return the requested part index
+         */
+        public int getStartingPartIndexForLastPage(int partCount) {
+            int result = 0;
+            int idx = 0;
+            int pageIndex = 0;
+            int colIndex = startColumnOfCurrentElementList;
+            PageViewport pv = getPageViewport(
+                    false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
+            while (idx < partCount) {
+                if ((idx < partCount - 1) && (colIndex >= pv.getCurrentSpan().getColumnCount())) {
+                    colIndex = 0;
+                    pageIndex++;
+                    pv = getPageViewport(
+                            false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
+                    result = idx;
+                }
+                colIndex++;
+                idx++;
+            }
+            return result;
+        }
+
         /**
          * Returns a PageViewport.
          * @param bIsBlank true if this page is supposed to be blank.
@@ -617,7 +789,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                 return getPageViewport(bIsBlank, index);
             } else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) {
                 int effIndex = startPageOfCurrentElementList + index;
-                effIndex += startPageOfPageSequence;
+                effIndex += startPageOfPageSequence - 1;
                 return getPageViewport(bIsBlank, effIndex);
             } else {
                 throw new IllegalArgumentException(