On Mon, 26 Mar 2007, Luca Furini wrote:

I'm attaching a diff file showing the changes ....

Well, *now* I'm attaching bla bla :-)

Regards
    Luca
Index: src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java     
(revision 521755)
+++ src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java     
(working copy)
@@ -91,6 +91,21 @@
                 addSeparator();
             }
         }
+        
+        /**
+         * 
+         */
+        public void handleDeferredFootnotes(int requestedLastIndex) {
+               boolean separatorAlreadyAdded = (alreadyInserted.getLength() > 
0);
+               // check if we must add more footnotes
+               while (lastInsertedIndex < requestedLastIndex) {
+                       next();
+               }
+               // if needed, add the separator
+               if (!separatorAlreadyAdded && alreadyInserted.getLength() > 0) {
+                       addSeparator();
+               }
+        }
 
         /**
          * If the current page is a float-only page, handles the splitting of 
the last
Index: src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java    (revision 
521755)
+++ src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java    (working copy)
@@ -545,6 +545,17 @@
                     log.debug("Could not find a set of breaking points " + 
threshold);
                     return 0;
                 }
+                // lastDeactivated was a "good" break, while lastTooShort and 
lastTooLong 
+                // were "bad" breaks since the beginning;
+                // if it is not the node we just restarted from, 
lastDeactivated can 
+                // replace either lastTooShort or lastTooLong
+                if (lastDeactivated != null && lastDeactivated != lastForced) {
+                    if (lastDeactivated.adjustRatio > 0) {
+                        lastTooShort = lastDeactivated;
+                    } else {
+                        lastTooLong = lastDeactivated;
+                    }
+                }
                 if (lastTooShort == null || lastForced.position == 
lastTooShort.position) {
                     if (isPartOverflowRecoveryActivated()) {
                         if (this.lastRecovered == null) {
Index: src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java     
(revision 521755)
+++ src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java     
(working copy)
@@ -1285,7 +1285,12 @@
                     (new KnuthGlue(lineStartBAP, 0, 0,
                                    new LeafPosition(this, -1), false));
             } else {
+                // the first penalty is necessary in order to avoid the glue 
to be a feasible break
+                // while we are ignoring hyphenated breaks
                 hyphenElements.add
+                    (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                            new LeafPosition(this, -1), false));
+                hyphenElements.add
                     (new KnuthGlue(0, 3 * 
LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
                             new LeafPosition(this, -1), false));
                 hyphenElements.add
Index: src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java        
(revision 521755)
+++ src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java        
(working copy)
@@ -77,7 +77,7 @@
     /**
      * Are footnotes-only pages allowed?
      */
-    public static final boolean FOOTNOTES_ONLY_PAGES_ALLOWED = true;
+    public static final boolean FOOTNOTES_ONLY_PAGES_ALLOWED = false;
 
     /**
      * Additional demerits for an underfull page, which however has an 
acceptable fill ratio.
@@ -115,6 +115,14 @@
     private BeforeFloatsRecord beforeFloatsRecord;
     private FootnotesRecord.FootnotesProgress footnotesProgress;
     private BeforeFloatsRecord.BeforeFloatsProgress beforeFloatsProgress;
+    // number of new footnotes met since the last feasible break
+    private int newFootnotesCount = 0;
+    // the method noBreakBetween(int, int) uses these variables 
+    // to store parameters and result of the last call, in order
+    // to reuse them and take less time
+    private int storedPrevBreakIndex = -1;
+    private int storedBreakIndex = -1;
+    private boolean storedValue = false;
 
     private ActiveNodeRecorder activeNodeRecorder = new ActiveNodeRecorder();
     
@@ -682,6 +690,7 @@
         if (box instanceof KnuthBlockBox
                 && ((KnuthBlockBox) box).hasFootnoteAnchors()) {
             footnotesRecord.add(((KnuthBlockBox) 
box).getFootnoteElementLists());
+               newFootnotesCount += ((KnuthBlockBox) 
box).getFootnoteElementLists().size();
         }
         if (box instanceof KnuthBlockBox
                 && ((KnuthBlockBox) box).hasFloatAnchors()) {
@@ -701,6 +710,8 @@
                         && ((KnuthBlockBox) 
resetElement).hasFootnoteAnchors()) {
                     footnotesRecord.reset(((KnuthBlockBox) 
resetElement).getFootnoteElementLists());
                 }
+                // reset newFootnotesCount
+                newFootnotesCount = 0;
                 if (resetElement instanceof KnuthBlockBox
                         && ((KnuthBlockBox) resetElement).hasFloatAnchors()) {
                     beforeFloatsRecord.reset(((KnuthBlockBox) 
resetElement).getFloatElementLists());
@@ -731,6 +742,12 @@
                 footnotesProgress.setPrevious(node.footnotesProgress);
                 beforeFloatsProgress.setPrevious(node.beforeFloatsProgress);
                 footnotesProgress.handleSplit();
+                
footnotesProgress.handleDeferredFootnotes(findMininumFootnoteIndex(
+                               node.position,
+                               elementIdx,
+                               newFootnotesCount, 
+                               node.footnotesProgress.getLastInsertedIndex(), 
+                               node.footnotesProgress.getNbOfDeferred()));
                 beforeFloatsProgress.handleSplit();
                 normalContentProgress.insertedDims.set(totalShrink - 
node.totalShrink,
                         totalWidth - node.totalWidth, totalStretch - 
node.totalStretch);
@@ -752,9 +769,81 @@
             }
             addBreaks(line, elementIdx);
         }
+        // reset newFootnotesCount
+        newFootnotesCount = 0;
     }
 
-    // TODO vh: refactor
+    /**
+     * Compute the minimum footnote index that is acceptable for a break:
+     * this should prevent footnotes to be unnecessarily deferred.
+     */
+    private int findMininumFootnoteIndex(int prevBreakIndex, int 
currBreakIndex, int newFootnotesCount, int lastInsertedIndex, int 
deferredFootnotesCount) {
+               int minimumIndex = lastInsertedIndex;
+               if (thereIsABreakBetween(prevBreakIndex, currBreakIndex)) {
+                       // we must enforce a more strict constraint, to limit 
deferred footnotes:
+                       // we want at least a bit of the first new note (if 
any), 
+                       // otherwise a bit of the last one
+                       minimumIndex += deferredFootnotesCount - 
newFootnotesCount;
+               }
+       /*log.debug("content from " + prevBreakIndex + " to " + currBreakIndex 
+                       + " lastInsertedIndex=" + lastInsertedIndex 
+                       + " deferredFCount=" + deferredFootnotesCount 
+                       + " newFCount=" + newFootnotesCount + " 
MininumFootnoteIndex " + minimumIndex);*/
+               return minimumIndex;
+       }
+
+    /**
+     * Returns true if there may be a breakpoint between the two given 
elements.
+     * @param prevBreakIndex index of the element from the currently 
considered active
+     * node
+     * @param breakIndex index of the currently considered breakpoint
+     * @return true if a element between the two can be a breakpoint
+     */
+    private boolean thereIsABreakBetween(int prevBreakIndex, int breakIndex) {
+        // this method stores the parameters and the return value from 
previous calls
+        // in order to avoid scanning the element list unnecessarily:
+        //  - if there is no break between element #i and element #j
+        //    there will not be a break between #(i+h) and #j too
+        //  - if there is a break between element #i and element #j
+        //    there will be a break between #(i-h) and #(j+k) too
+        if (storedPrevBreakIndex != -1
+            && ((prevBreakIndex >= storedPrevBreakIndex
+                 && breakIndex == storedBreakIndex
+                 && !storedValue)
+                || (prevBreakIndex <= storedPrevBreakIndex
+                    && breakIndex >= storedBreakIndex
+                    && storedValue))) {
+            // use the stored value, do nothing
+        } else {
+            // compute the new value
+            int index;
+            // ignore suppressed elements
+            for (index = prevBreakIndex + 1;
+                    index < par.size() && !par.getElement(index).isBox();
+                    index++) {
+                //nop
+            }
+            // find the next break
+            for (;
+                 index < breakIndex;
+                 index++) {
+                if (index == par.size()
+                       || par.getElement(index).isGlue() && 
par.getElement(index - 1).isBox()
+                    || par.getElement(index).isPenalty() 
+                       && ((KnuthElement) par.getElement(index)).getP() < 
KnuthElement.INFINITE) {
+                    // break found (or end of sequence reached)
+                    break;
+                }
+            }
+            // update stored parameters and value
+            storedPrevBreakIndex = prevBreakIndex;
+            storedBreakIndex = breakIndex;
+            storedValue = (index < breakIndex);
+        }
+        return storedValue;
+    }
+
+       // TODO vh: refactor
     // It may happen that several successive float-only pages are created; in 
such cases
     // the progress informations must be saved as they'll still be used after 
this method
     // call
Index: 
test/layoutengine/standard-testcases/block-container_content_size_percentage.xml
===================================================================
--- 
test/layoutengine/standard-testcases/block-container_content_size_percentage.xml
    (revision 521755)
+++ 
test/layoutengine/standard-testcases/block-container_content_size_percentage.xml
    (working copy)
@@ -61,9 +61,9 @@
     <!-- from the spec: If that dimension is not specified explicitly (i.e., 
it depends on 
          content's blockprogression-dimension), the value is interpreted as 
"auto". -->
     <!-- The 10% are ignored in this case. -->
-    <eval expected="28800" xpath="//flow/block[2]/@bpd"/> <!-- 2 lines -->
+    <eval expected="43200" xpath="//flow/block[2]/@bpd"/> <!-- 3 lines -->
     <eval expected="100000" xpath="//flow/block[2]/@ipd"/>
-    <eval expected="28800" xpath="//flow/block[2]/block[1]/block[1]/@bpd"/>
+    <eval expected="43200" xpath="//flow/block[2]/block[1]/block[1]/@bpd"/>
     <eval expected="50000" xpath="//flow/block[2]/block[1]/block[1]/@ipd"/>
 
     <!-- absolute -->
@@ -76,9 +76,11 @@
     <!-- from the spec: If that dimension is not specified explicitly (i.e., 
it depends on 
          content's blockprogression-dimension), the value is interpreted as 
"auto". -->
     <!-- The 10% are ignored in this case. -->
-    <eval expected="43200" xpath="//flow/block[4]/@bpd"/> <!-- 3 lines -->
+    <eval expected="57600" xpath="//flow/block[4]/@bpd"/> <!-- 4 lines -->
     <eval expected="100000" xpath="//flow/block[4]/@ipd"/>
-    <eval expected="43200" xpath="//flow/block[4]/block[1]/block[1]/@bpd"/>
+    <eval expected="28800" xpath="//flow/block[4]/block[1]/block[1]/@bpd"/> 
<!-- the first 2 lines ... -->
     <eval expected="50000" xpath="//flow/block[4]/block[1]/block[1]/@ipd"/>
+    <eval expected="28800" xpath="//flow/block[4]/block[1]/block[2]/@bpd"/> 
<!-- ... and the other 2 lines -->
+    <eval expected="50000" xpath="//flow/block[4]/block[1]/block[2]/@ipd"/>
   </checks>
 </testcase>

Reply via email to