]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Page breaking process now respects changing available BPD (not IPD) over multiple...
authorJeremias Maerki <jeremias@apache.org>
Wed, 15 Jun 2005 09:08:35 +0000 (09:08 +0000)
committerJeremias Maerki <jeremias@apache.org>
Wed, 15 Jun 2005 09:08:35 +0000 (09:08 +0000)
PageSequenceMaster allows backtracking.
PageViewports are delivered through a PageViewportProvider class which caches PVs and handles cases where the breaking algorithm allocates PVs that turn out to be unused later (because of hard breaks which may cause blank pages, for example).

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

13 files changed:
src/java/org/apache/fop/area/PageViewport.java
src/java/org/apache/fop/fo/pagination/ConditionalPageMasterReference.java
src/java/org/apache/fop/fo/pagination/PageSequence.java
src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java
src/java/org/apache/fop/fo/pagination/RepeatablePageMasterAlternatives.java
src/java/org/apache/fop/fo/pagination/RepeatablePageMasterReference.java
src/java/org/apache/fop/fo/pagination/SinglePageMasterReference.java
src/java/org/apache/fop/fo/pagination/SubSequenceSpecifier.java
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java

index cb7b524cf2707358f10a7a50012991130f20079f..4fedd05c6b21e2bae55744f52b459365393d9053 100644 (file)
@@ -49,6 +49,7 @@ public class PageViewport implements Resolvable, Cloneable {
     private boolean clip = false;
     private String pageNumberString = null;
     private SimplePageMaster spm = null;
+    private boolean blank;
 
     // list of id references and the rectangle on the page
     private Map idReferences = null;
@@ -76,9 +77,12 @@ public class PageViewport implements Resolvable, Cloneable {
     /**
      * Create a page viewport.
      * @param spm SimplePageMaster indicating the page and region dimensions
+     * @param pageStr String representation of the page number
+     * @param blank true if this is a blank page
      */
-    public PageViewport(SimplePageMaster spm, String pageStr) {
+    public PageViewport(SimplePageMaster spm, String pageStr, boolean blank) {
         this.spm = spm;
+        this.blank = blank;
         int pageWidth = spm.getPageWidth().getValue();
         int pageHeight = spm.getPageHeight().getValue();
         pageNumberString = pageStr;
@@ -237,6 +241,12 @@ public class PageViewport implements Resolvable, Cloneable {
         if (marks == null) {
             return;
         }
+        if (log.isDebugEnabled()) {
+            log.debug("--" + marks.keySet() + ": " 
+                    + (starting ? "starting" : "ending") 
+                    + (isfirst ? ", first" : "") 
+                    + (islast ? ", last" : ""));
+        }
         
         // at the start of the area, register is-first and any areas
         if (starting) {
@@ -348,10 +358,24 @@ public class PageViewport implements Resolvable, Cloneable {
                 }
             break;
         }
-        log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name + "at position " + posName); 
+        if (log.isTraceEnabled()) {
+            log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name 
+                    + " at position " + posName); 
+        }
         return mark;    
     }
 
+    /** Dumps the current marker data to the logger. */
+    public void dumpMarkers() {
+        if (log.isTraceEnabled()) {
+            log.trace("FirstAny: " + this.markerFirstAny);
+            log.trace("FirstStart: " + this.markerFirstStart);
+            log.trace("LastAny: " + this.markerLastAny);
+            log.trace("LastEnd: " + this.markerLastEnd);
+            log.trace("LastStart: " + this.markerLastStart);
+        }
+    }
+    
     /**
      * Save the page contents to an object stream.
      * The map of unresolved references are set on the page so that
@@ -425,6 +449,11 @@ public class PageViewport implements Resolvable, Cloneable {
         return spm;
     }
     
+    /** @return True if this is a blank page. */
+    public boolean isBlank() {
+        return this.blank;
+    }
+    
     /**
      * Convenience method to get BodyRegion of this PageViewport
      * @return BodyRegion object
index 3d737065a3a303f61360ab2c20ebc3215720aa8d..dd2e8ee35ec799a2414a3bc31ef333213109e1dc 100644 (file)
@@ -43,8 +43,6 @@ public class ConditionalPageMasterReference extends FObj {
     private int blankOrNotBlank;
     // End of property values
     
-    private RepeatablePageMasterAlternatives repeatablePageMasterAlternatives;
-
     /**
      * @see org.apache.fop.fo.FONode#FONode(FONode)
      */
@@ -70,17 +68,19 @@ public class ConditionalPageMasterReference extends FObj {
      * @see org.apache.fop.fo.FONode#startOfNode
      */
     protected void startOfNode() throws FOPException {
-        this.repeatablePageMasterAlternatives =
-            (RepeatablePageMasterAlternatives) parent;
-        this.repeatablePageMasterAlternatives.addConditionalPageMasterReference(this);
+        getConcreteParent().addConditionalPageMasterReference(this);
     }
 
+    private RepeatablePageMasterAlternatives getConcreteParent() {
+        return (RepeatablePageMasterAlternatives) parent;
+    }
+    
     /**
      * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
      * XSL Content Model: empty
      */
     protected void validateChildNode(Locator loc, String nsURI, String localName) 
-        throws ValidationException {
+           throws ValidationException {
        invalidChildError(loc, nsURI, localName);
     }
 
index dec8676d2d9960a797fdc16710ce4e606b586718..27a3b5b7a2eb6579b4bc8b5c8408e49740fdcaa8 100644 (file)
@@ -433,25 +433,44 @@ public class PageSequence extends FObj {
     }
 
     /**
-     * Public accessor for determining the page master to use for any given
-     * page within this page sequence
-     * @param pageCount = the page number of the page to be created
-     * @param bIsFirstPage = indicator whether this page is the first page of the
+     * Public accessor for determining the next page master to use within this page sequence.
+     * @param page the page number of the page to be created
+     * @param bIsFirstPage indicator whether this page is the first page of the
      *      page sequence
-     * @param bIsBlank indicator whether the page will be blank
+     * @param bIsBlank indicator whether the page will be blank
      * @return the SimplePageMaster to use for this page
+     * @throws FOPException if there's a problem determining the page master
      */
-    public SimplePageMaster getSimplePageMasterToUse(int pageCount, boolean bIsFirstPage, 
-        boolean bIsBlank) throws FOPException {
+    public SimplePageMaster getNextSimplePageMaster(int page, 
+            boolean bIsFirstPage,  
+            boolean bIsBlank) throws FOPException {
 
         if (pageSequenceMaster == null) {
             return simplePageMaster;
         }
-        boolean isOddPage = ((pageCount % 2) == 1);
+        boolean isOddPage = ((page % 2) == 1);
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("getNextSimplePageMaster(page=" + page
+                    + " isOdd=" + isOddPage 
+                    + " isFirst=" + bIsFirstPage 
+                    + " isBlank=" + bIsBlank + ")");
+        }
         return pageSequenceMaster.getNextSimplePageMaster(isOddPage, 
             bIsFirstPage, bIsBlank);
     }
 
+    /**
+     * Used to set the "cursor position" for the page masters to the previous item.
+     * @return true if there is a previous item, false if the current one was the first one.
+     */
+    public boolean goToPreviousSimplePageMaster() {
+        if (pageSequenceMaster == null) {
+            return true;
+        } else {
+            return pageSequenceMaster.goToPreviousSimplePageMaster();
+        }
+    }
+
     /**
      * Retrieves the string representation of a page number applicable
      * for this page sequence
index 2aad43894192dabee3788c6d36b55693b7f79bd8..32e86562241935e6b9319468614737d448d8be00 100644 (file)
@@ -83,8 +83,8 @@ public class PageSequenceMaster extends FObj {
      */
     protected void endOfNode() throws FOPException {
         if (childNodes == null) {
-           missingChildElementError("(single-page-master-reference|" +
-            "repeatable-page-master-reference|repeatable-page-master-alternatives)+");
+            missingChildElementError("(single-page-master-reference|"
+                    + "repeatable-page-master-reference|repeatable-page-master-alternatives)+");
         }
     }
 
@@ -121,7 +121,7 @@ public class PageSequenceMaster extends FObj {
     private SubSequenceSpecifier getNextSubSequence() {
         currentSubSequenceNumber++;
         if (currentSubSequenceNumber >= 0
-            && currentSubSequenceNumber < subSequenceSpecifiers.size()) {
+                && currentSubSequenceNumber < subSequenceSpecifiers.size()) {
             return (SubSequenceSpecifier)subSequenceSpecifiers
               .get(currentSubSequenceNumber);
         }
@@ -139,6 +139,26 @@ public class PageSequenceMaster extends FObj {
         }
     }
 
+    /**
+     * Used to set the "cursor position" for the page masters to the previous item.
+     * @return true if there is a previous item, false if the current one was the first one.
+     */
+    public boolean goToPreviousSimplePageMaster() {
+        if (currentSubSequence != null) {
+            boolean success = currentSubSequence.goToPrevious();
+            if (!success) {
+                if (currentSubSequenceNumber > 0) {
+                    currentSubSequenceNumber--;
+                    currentSubSequence = (SubSequenceSpecifier)subSequenceSpecifiers
+                        .get(currentSubSequenceNumber);
+                } else {
+                    currentSubSequence = null;
+                }
+            }
+        }
+        return (currentSubSequence != null);
+    }
+    
     /**
      * Returns the next simple-page-master.
      * @param isOddPage True if the next page number is odd
index 546107929acf50a8382a807e357d5fa0f9dcfbba..64288457ab74959f03de68304adacb2e5913a9b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -19,7 +19,7 @@
 package org.apache.fop.fo.pagination;
 
 // Java
-import java.util.ArrayList;
+import java.util.List;
 
 import org.xml.sax.Locator;
 
@@ -46,7 +46,7 @@ public class RepeatablePageMasterAlternatives extends FObj
 
     private int numberConsumed = 0;
 
-    private ArrayList conditionalPageMasterRefs;
+    private List conditionalPageMasterRefs;
 
     /**
      * @see org.apache.fop.fo.FONode#FONode(FONode)
@@ -66,7 +66,7 @@ public class RepeatablePageMasterAlternatives extends FObj
      * @see org.apache.fop.fo.FONode#startOfNode
      */
     protected void startOfNode() throws FOPException {
-        conditionalPageMasterRefs = new ArrayList();
+        conditionalPageMasterRefs = new java.util.ArrayList();
 
         if (parent.getName().equals("fo:page-sequence-master")) {
             PageSequenceMaster pageSequenceMaster = (PageSequenceMaster)parent;
@@ -99,9 +99,7 @@ public class RepeatablePageMasterAlternatives extends FObj
         }
     }
 
-    /**
-     * Return the "maximum-repeats" property.
-     */
+    /** @return the "maximum-repeats" property. */
     public int getMaximumRepeats() {
         if (maximumRepeats.getEnum() == EN_NO_LIMIT) {
             return INFINITE;
@@ -151,20 +149,27 @@ public class RepeatablePageMasterAlternatives extends FObj
         this.conditionalPageMasterRefs.add(cpmr);
     }
 
-    /**
-     * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
-     */
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
     public void reset() {
         this.numberConsumed = 0;
     }
 
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+    public boolean goToPrevious() {
+        if (numberConsumed == 0) {
+            return false;
+        } else {
+            numberConsumed--;
+            return true;
+        }
+    }
+    
+    /** @see org.apache.fop.fo.FONode#getName() */
     public String getName() {
         return "fo:repeatable-page-master-alternatives";
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getNameId()
-     */
+    /** @see org.apache.fop.fo.FObj#getNameId() */
     public int getNameId() {
         return FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES;
     }
index efe3b16e18cf1de5c5700203a1e025e9ce4fb13e..8f714aac92272caecf7dfb21bfd7f92c0a8fde60 100644 (file)
@@ -43,7 +43,6 @@ public class RepeatablePageMasterReference extends FObj
     
     private static final int INFINITE = -1;
 
-    private PageSequenceMaster pageSequenceMaster;
     private int numberConsumed = 0;
 
     /**
@@ -103,9 +102,7 @@ public class RepeatablePageMasterReference extends FObj
         return masterReference;
     }
 
-    /**
-     * Return the "maximum-repeats" property.
-     */
+    /** @return the "maximum-repeats" property. */
     public int getMaximumRepeats() {
         if (maximumRepeats.getEnum() == EN_NO_LIMIT) {
             return INFINITE;
@@ -120,23 +117,28 @@ public class RepeatablePageMasterReference extends FObj
         }
     }
 
-    /**
-     * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
-     */
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
     public void reset() {
         this.numberConsumed = 0;
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getName()
-     */
+    
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+    public boolean goToPrevious() {
+        if (numberConsumed == 0) {
+            return false;
+        } else {
+            numberConsumed--;
+            return true;
+        }
+    }
+    
+    /** @see org.apache.fop.fo.FObj#getName() */
     public String getName() {
         return "fo:repeatable-page-master-reference";
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getNameId()
-     */
+    /** @see org.apache.fop.fo.FObj#getNameId() */
     public int getNameId() {
         return FO_REPEATABLE_PAGE_MASTER_REFERENCE;
     }
index 68a08259a28ea952243e6e1cf4291d2ea1c4d3f1..1d2a7cd6a5be163c1b79e6f7245e67c819e5c126 100644 (file)
@@ -80,9 +80,7 @@ public class SinglePageMasterReference extends FObj
        invalidChildError(loc, nsURI, localName);
     }
 
-    /**
-     * @see org.apache.fop.fo.pagination.SubSequenceSpecifier
-     */
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier */
     public String getNextPageMasterName(boolean isOddPage,
                                         boolean isFirstPage,
                                         boolean isEmptyPage) {
@@ -94,20 +92,29 @@ public class SinglePageMasterReference extends FObj
         }
     }
 
-    /**
-     * @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset()
-     */
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#reset() */
     public void reset() {
         this.state = FIRST;
     }
+    
+    
 
+    /** @see org.apache.fop.fo.pagination.SubSequenceSpecifier#goToPrevious() */
+    public boolean goToPrevious() {
+        if (state == FIRST) {
+            return false;
+        } else {
+            this.state = FIRST;
+            return true;
+        }
+    }
+    
+    /** @see org.apache.fop.fo.FONode#getName() */
     public String getName() {
         return "fo:single-page-master-reference";
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getNameId()
-     */
+    /** @see org.apache.fop.fo.FObj#getNameId() */
     public int getNameId() {
         return FO_SINGLE_PAGE_MASTER_REFERENCE;
     }
index 67b5cc3035c0f4a3e7d225b9560aeea53f708b83..39609bb051e4487b9894077168a999930ab6fb53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -45,5 +45,11 @@ public interface SubSequenceSpecifier {
      */
     void reset();
 
+    /**
+     * Used to set the "cursor position" to the previous item.
+     * @return true if there is a previous item, false if the current one was the first one.
+     */
+    boolean goToPrevious();
+    
 }
 
index 0a0c1eeb28e37b890241729bd21f1e886238f6df..99dff32ba43982923ff6051c24ffec1791c1ee18 100644 (file)
@@ -105,6 +105,16 @@ public abstract class AbstractBreaker {
     protected abstract LayoutManager getTopLevelLM();
     protected abstract LayoutManager getCurrentChildLM();
     
+    /**
+     * Returns the PageViewportProvider if any. PageBreaker overrides this method because each
+     * page may have a different available BPD which needs to be accessible to the breaking
+     * algorithm.
+     * @return the applicable PageViewportProvider, or null if not applicable
+     */
+    protected PageSequenceLayoutManager.PageViewportProvider getPageViewportProvider() {
+        return null;
+    }
+    
     /*
      * This method is to contain the logic to determine the LM's
      * getNextKnuthElements() implementation(s) that are to be called. 
@@ -171,6 +181,7 @@ public abstract class AbstractBreaker {
             log.debug("PLM> start of algorithm (" + this.getClass().getName() 
                     + "), flow BPD =" + flowBPD);
             PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
+                    getPageViewportProvider(),
                     alignment, alignmentLast, footnoteSeparatorLength);
             int iOptPageNumber;
 
@@ -184,8 +195,9 @@ public abstract class AbstractBreaker {
             }
 
             //iOptPageNumber = alg.firstFit(effectiveList, flowBPD, 1, true);
-            iOptPageNumber = alg.findBreakingPoints(effectiveList, flowBPD, 1,
-                    true, true);
+            alg.setConstantLineWidth(flowBPD);
+            iOptPageNumber = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
+                    1, true, true);
             log.debug("PLM> iOptPageNumber= " + iOptPageNumber
                     + " pageBreaks.size()= " + alg.getPageBreaks().size());
 
@@ -413,8 +425,9 @@ public abstract class AbstractBreaker {
      */
     private BlockSequence justifyBoxes(BlockSequence blockList, PageBreakingAlgorithm alg, int availableBPD) {
         int iOptPageNumber;
-        iOptPageNumber = alg.findBreakingPoints(blockList, availableBPD, 1,
-                true, true);
+        alg.setConstantLineWidth(availableBPD);
+        iOptPageNumber = alg.findBreakingPoints(blockList, /*availableBPD,*/
+                1, true, true);
         log.debug("PLM> iOptPageNumber= " + iOptPageNumber);
 
         // 
index e7098e33001515e001a2df4455d5b24f29d2df93..1da5ee4d7ee95a74b3a2472bedeba1995a26daae 100644 (file)
@@ -58,9 +58,10 @@ public abstract class BreakingAlgorithm {
     protected KnuthSequence par;
     
     /**
-     * The width of a line.
+     * The width of a line (or height of a column in page-breaking mode).
+     * -1 indicates that the line widths are different for each line.
      */
-    protected int lineWidth = 0;
+    protected int lineWidth = -1;
     private boolean force =  false;
 
     protected KnuthNode lastDeactivatedNode = null;
@@ -287,13 +288,17 @@ public abstract class BreakingAlgorithm {
                                      KnuthSequence sequence,
                                      int total) ;
 
-    public int findBreakingPoints(KnuthSequence par, int lineWidth,
+    public void setConstantLineWidth(int lineWidth) {
+        this.lineWidth = lineWidth;
+    }
+    
+    public int findBreakingPoints(KnuthSequence par, /*int lineWidth,*/
                                   double threshold, boolean force,
                                   boolean hyphenationAllowed) {
         this.par = par;
         this.threshold = threshold;
         this.force = force;
-        this.lineWidth = lineWidth;
+        //this.lineWidth = lineWidth;
         initialize();
 
         activeLines = new KnuthNode[20];
@@ -567,7 +572,7 @@ public abstract class BreakingAlgorithm {
         if (element.isPenalty()) {
             actualWidth += element.getW();
         }
-        return lineWidth - actualWidth;
+        return getLineWidth() - actualWidth;
     }
 
     /**
@@ -768,6 +773,18 @@ public abstract class BreakingAlgorithm {
         return positions[line].position;
     }
 
+    protected int getLineWidth(int line) {
+        if (this.lineWidth < 0) {
+            throw new IllegalStateException("lineWidth must be set");
+        } else {
+            return this.lineWidth;
+        }
+    }
+    
+    protected int getLineWidth() {
+        return this.lineWidth;
+    }
+    
     /**
      * Return a string representation of a MinOptMax in the form of a 
      * "width+stretch-shrink". Useful only for debugging.
index 13befec2ccb65a39f3ac01f1379a81db855d42ed..7fe0c3e295c5666508862d198ff3c308ce6a4c22 100644 (file)
@@ -418,10 +418,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             }
         }
 
-        public int findBreakingPoints(Paragraph par, int lineWidth,
+        public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
                                       double threshold, boolean force,
                                       boolean hyphenationAllowed) {
-            return super.findBreakingPoints(par, lineWidth, threshold, force, hyphenationAllowed);
+            return super.findBreakingPoints(par, /*lineWidth,*/ 
+                    threshold, force, hyphenationAllowed);
         }
 
         protected int filterActiveNodes() {
@@ -832,8 +833,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
     
             // first try
             boolean bHyphenationAllowed = false;
+            alg.setConstantLineWidth(iLineWidth);
             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
@@ -857,7 +858,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager
     
                 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
@@ -867,7 +867,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                     maxAdjustment = 20;
                     iBPcount
                         = alg.findBreakingPoints(currPar,
-                                                 iLineWidth,
                                                  maxAdjustment, true, bHyphenationAllowed);
                 }
     
@@ -887,13 +886,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                         // 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;
+                        iBPcount = alg.findBreakingPoints(currPar,
+                                 maxAdjustment, true, bHyphenationAllowed);
+                        // use normal lines, when possible
+                        lineLayouts.restorePossibilities();
+                        iLineWidth = savedLineWidth;
                     }
                     if (!lineLayouts.canUseLessLines()) {
                         alg.resetAlgorithm();
@@ -901,13 +898,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                         // 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;
+                        alg.setConstantLineWidth(iLineWidth);
+                        iBPcount = alg.findBreakingPoints(currPar,
+                                maxAdjustment, true, bHyphenationAllowed);
+                        // use normal lines, when possible
+                        lineLayouts.restorePossibilities();
+                        iLineWidth = savedLineWidth;
                     }
                     //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
                     //System.out.println("                          now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
index e48675c954b6a6f66872a1b8bcfb4da156366598..0f00a96855810fd460236141673792d429eeaafc 100644 (file)
@@ -22,12 +22,14 @@ 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;
 
 class PageBreakingAlgorithm extends BreakingAlgorithm {
     private LayoutManager topLevelLM;
+    private PageSequenceLayoutManager.PageViewportProvider pvProvider;
     private LinkedList pageBreaks = null;
 
     private ArrayList footnotesList = null;
@@ -62,10 +64,12 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
     private boolean storedValue = false;
 
     public PageBreakingAlgorithm(LayoutManager topLevelLM,
+                                 PageSequenceLayoutManager.PageViewportProvider pvProvider,
                                  int alignment, int alignmentLast,
                                  MinOptMax fnSeparatorLength) {
         super(alignment, alignmentLast, true);
         this.topLevelLM = topLevelLM;
+        this.pvProvider = pvProvider;
         best = new BestPageRecords();
         footnoteSeparatorLength = (MinOptMax) fnSeparatorLength.clone();
         // add some stretch, to avoid a restart for every page containing footnotes
@@ -274,7 +278,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
                 // this page contains some footnote citations
                 // add the footnote separator width
                 actualWidth += footnoteSeparatorLength.opt;
-                if (actualWidth + allFootnotes <= lineWidth) {
+                if (actualWidth + allFootnotes <= getLineWidth()) {
                     // there is enough space to insert all footnotes:
                     // add the whole allFootnotes length
                     actualWidth += allFootnotes;
@@ -284,7 +288,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
                 } else if (((bCanDeferOldFootnotes = canDeferOldFootnotes((KnuthPageNode) activeNode, elementIndex))
                             || bNewFootnotes)
                            && (footnoteSplit = getFootnoteSplit((KnuthPageNode) activeNode,
-                                                                lineWidth - actualWidth,
+                                                                getLineWidth() - actualWidth,
                                                                 bCanDeferOldFootnotes)) > 0) {
                     // it is allowed to break or even defer footnotes if either:
                     //  - there are new footnotes in the last piece of content, and
@@ -313,7 +317,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
         } else {
             // there are no footnotes
         }
-        return lineWidth - actualWidth;
+        return getLineWidth(activeNode.line) - actualWidth;
     }
 
     private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) {
@@ -594,7 +598,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
         insertedFootnotesLength = lastNode.totalFootnotes;
         footnoteListIndex = lastNode.footnoteListIndex;
         footnoteElementIndex = lastNode.footnoteElementIndex;
-        int availableBPD = lineWidth;
+        int availableBPD = getLineWidth();
         int split = 0;
         KnuthPageNode prevNode = lastNode;
 
@@ -627,7 +631,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
                 removeNode(prevNode.line, prevNode);
 
                 prevNode = node;
-                availableBPD = lineWidth;
+                availableBPD = getLineWidth();
             }
         }
         // create the last node
@@ -741,4 +745,19 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
     public LinkedList getFootnoteList(int index) {
         return (LinkedList) footnotesList.get(index);
     }
+    
+    /** @see org.apache.fop.layoutmgr.BreakingAlgorithm#getLineWidth(int) */
+    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(); 
+        } else {
+            bpd = super.getLineWidth(line);
+        }
+        return bpd;
+    }
+    
 }
index 843d13e113db6e87f4a371647df6b8dd2abdfdf7..07e6dfdd8e59f06b5788012da8f78fe65dbb1cb9 100644 (file)
@@ -63,6 +63,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
      */
     private PageSequence pageSeq;
 
+    private PageViewportProvider pvProvider;
+    
     /** 
      * Current page-viewport-area being filled by
      * the PSLM.
@@ -90,6 +92,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         super(pseq);
         this.areaTreeHandler = ath;
         this.pageSeq = pseq;
+        this.pvProvider = new PageViewportProvider(this.pageSeq);
     }
 
     /**
@@ -121,7 +124,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         areaTreeHandler.getAreaTreeModel().startPageSequence(title);
         log.debug("Starting layout");
 
-        curPV = makeNewPage(false, true, false);
+        curPV = makeNewPage(false, false);
 
         Flow mainFlow = pageSeq.getMainFlow();
         childFLM = getLayoutManagerMaker().
@@ -160,6 +163,11 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             return null;  // unneeded for PSLM
         }
         
+        /** @see org.apache.fop.layoutmgr.AbstractBreaker#getPageViewportProvider() */
+        protected PageSequenceLayoutManager.PageViewportProvider getPageViewportProvider() {
+            return pvProvider;
+        }
+        
         protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
             LinkedList contentList = null;
             
@@ -263,6 +271,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                         handleBreakTrait(bIsFirstPage ? list.getStartOn() : Constants.EN_PAGE);
                     }
                 }
+                pvProvider.setStartPageOfNextElementList(currentPageNum);
             }
             // add static areas and resolve any new id areas
             // finish page and add to area tree
@@ -425,32 +434,15 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
         }
     }
 
-    private PageViewport makeNewPage(boolean bIsBlank, boolean bIsFirst, boolean bIsLast) {
+    private PageViewport makeNewPage(boolean bIsBlank, boolean bIsLast) {
         if (curPV != null) {
             finishPage();
         }
 
         currentPageNum++;
-        String pageNumberString = pageSeq.makeFormattedPageNumber(currentPageNum);
 
-        try {
-            // create a new page
-            SimplePageMaster spm = pageSeq.getSimplePageMasterToUse(
-                currentPageNum, bIsFirst, bIsBlank);
-            
-            Region body = spm.getRegion(FO_REGION_BODY);
-            if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) {
-              // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to
-              // any region), but we don't support it yet.
-              throw new FOPException("Flow '" + pageSeq.getMainFlow().getFlowName()
-                 + "' does not map to the region-body in page-master '"
-                 + spm.getMasterName() + "'.  FOP presently "
-                 + "does not support this.");
-            }
-            curPV = new PageViewport(spm, pageNumberString);
-        } catch (FOPException fopex) {
-            throw new IllegalArgumentException("Cannot create page: " + fopex.getMessage());
-        }
+        curPV = pvProvider.getPageViewport(bIsBlank,
+                currentPageNum, PageViewportProvider.RELTO_PAGE_SEQUENCE);
 
         if (log.isDebugEnabled()) {
             log.debug("[" + curPV.getPageNumberString() + (bIsBlank ? "*" : "") + "]");
@@ -475,6 +467,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
     }
 
     private void finishPage() {
+        curPV.dumpMarkers();
         // Layout side regions
         layoutSideRegion(FO_REGION_BEFORE); 
         layoutSideRegion(FO_REGION_AFTER);
@@ -504,17 +497,17 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             if (curPV.getCurrentSpan().hasMoreFlows()) {
                 curPV.getCurrentSpan().moveToNextFlow();
             } else {
-                curPV = makeNewPage(false, false, false);
+                curPV = makeNewPage(false, false);
             }
             return;
         }
         log.debug("handling break-before after page " + currentPageNum 
             + " breakVal=" + breakVal);
         if (needBlankPageBeforeNew(breakVal)) {
-            curPV = makeNewPage(true, false, false);
+            curPV = makeNewPage(true, false);
         }
         if (needNewPage(breakVal)) {
-            curPV = makeNewPage(false, false, false);
+            curPV = makeNewPage(false, false);
         }
     }
 
@@ -556,4 +549,89 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             return true;
         }
     }
+    
+    
+    public class PageViewportProvider {
+        
+        public static final int RELTO_PAGE_SEQUENCE = 0;
+        public static final int RELTO_CURRENT_ELEMENT_LIST = 1;
+        
+        private int startPageOfPageSequence;
+        private int startPageOfCurrentElementList;
+        private List cachedPageViewports = new java.util.ArrayList();
+        
+        public PageViewportProvider(PageSequence ps) {
+            this.startPageOfPageSequence = ps.getStartingPageNumber();
+        }
+        
+        public void setStartPageOfNextElementList(int startPage) {
+            log.debug("start page of the next element list is: " + startPage);
+            this.startPageOfCurrentElementList = startPage;
+        }
+        
+        public PageViewport getPageViewport(boolean bIsBlank, int index, int relativeTo) {
+            if (relativeTo == RELTO_PAGE_SEQUENCE) {
+                return getPageViewport(bIsBlank, index);
+            } else if (relativeTo == RELTO_CURRENT_ELEMENT_LIST) {
+                int effIndex = startPageOfCurrentElementList + index;
+                effIndex += startPageOfPageSequence;
+                return getPageViewport(bIsBlank, effIndex);
+            } else {
+                throw new IllegalArgumentException(
+                        "Illegal value for relativeTo: " + relativeTo);
+            }
+        }
+        
+        private PageViewport getPageViewport(boolean bIsBlank, int index) {
+            //System.out.println("getPageViewport(" + index + " " + bIsBlank);
+            log.debug("getPageViewport(" + index + " " + bIsBlank);
+            int intIndex = index - startPageOfPageSequence;
+            if (bIsBlank) {
+                log.debug("blank page requested: " + index);
+            }
+            while (intIndex >= cachedPageViewports.size()) {
+                //System.out.println("Caching " + index);
+                log.debug("Caching " + index);
+                cacheNextPageViewport(index, bIsBlank);
+            }
+            PageViewport pv = (PageViewport)cachedPageViewports.get(intIndex);
+            if (pv.isBlank() != bIsBlank) {
+                log.debug("blank condition doesn't match. Replacing PageViewport.");
+                while (intIndex < cachedPageViewports.size()) {
+                    this.cachedPageViewports.remove(cachedPageViewports.size() - 1);
+                    if (!pageSeq.goToPreviousSimplePageMaster()) {
+                        log.warn("goToPreviousSimplePageMaster() on the first page called!");
+                    }
+                }
+                cacheNextPageViewport(index, bIsBlank);
+                //throw new IllegalStateException("blank condition doesn't match. Check code!");
+            }
+            return pv;
+        }
+        
+        private void cacheNextPageViewport(int index, boolean bIsBlank) {
+            try {
+                String pageNumberString = pageSeq.makeFormattedPageNumber(index);
+                SimplePageMaster spm = pageSeq.getNextSimplePageMaster(
+                        index, (startPageOfPageSequence == index), bIsBlank);
+                    
+                Region body = spm.getRegion(FO_REGION_BODY);
+                if (!pageSeq.getMainFlow().getFlowName().equals(body.getRegionName())) {
+                    // this is fine by the XSL Rec (fo:flow's flow-name can be mapped to
+                    // any region), but we don't support it yet.
+                    throw new FOPException("Flow '" + pageSeq.getMainFlow().getFlowName()
+                        + "' does not map to the region-body in page-master '"
+                        + spm.getMasterName() + "'.  FOP presently "
+                        + "does not support this.");
+                }
+                PageViewport pv = new PageViewport(spm, pageNumberString, bIsBlank);
+                cachedPageViewports.add(pv);
+            } catch (FOPException e) {
+                //TODO Maybe improve. It'll mean to propagate this exception up several
+                //methods calls.
+                throw new IllegalStateException(e.getMessage());
+            }
+        }
+        
+    }
 }