]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
breaks supported on tables, table-row and table-cell content now. Cheap approach...
authorJeremias Maerki <jeremias@apache.org>
Wed, 22 Jun 2005 14:59:54 +0000 (14:59 +0000)
committerJeremias Maerki <jeremias@apache.org>
Wed, 22 Jun 2005 14:59:54 +0000 (14:59 +0000)
Improved page break handling to support the different break classes even if no new block sequence is started.

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

src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/EffRow.java
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableStepper.java

index 99dff32ba43982923ff6051c24ffec1791c1ee18..b6f2eda247d741cad11b57322993f28f53c02865 100644 (file)
@@ -127,7 +127,7 @@ public abstract class AbstractBreaker {
         return (blockLists.size() == 0);
     }
     
-    protected void startPart(BlockSequence list, boolean bIsFirstPage) {
+    protected void startPart(BlockSequence list, int breakClass) {
         //nop
     }
     
@@ -183,7 +183,7 @@ public abstract class AbstractBreaker {
             PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
                     getPageViewportProvider(),
                     alignment, alignmentLast, footnoteSeparatorLength);
-            int iOptPageNumber;
+            int iOptPageCount;
 
             BlockSequence effectiveList;
             if (alignment == Constants.EN_JUSTIFY) {
@@ -194,16 +194,16 @@ public abstract class AbstractBreaker {
                 effectiveList = blockList;
             }
 
-            //iOptPageNumber = alg.firstFit(effectiveList, flowBPD, 1, true);
+            //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
             alg.setConstantLineWidth(flowBPD);
-            iOptPageNumber = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
-                    1, true, true);
-            log.debug("PLM> iOptPageNumber= " + iOptPageNumber
+            iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
+                        1, true, true);
+            log.debug("PLM> iOptPageCount= " + iOptPageCount
                     + " pageBreaks.size()= " + alg.getPageBreaks().size());
 
             
             //*** Phase 3: Add areas ***
-            doPhase3(alg, iOptPageNumber, blockList, effectiveList);
+            doPhase3(alg, iOptPageCount, blockList, effectiveList);
         }
     }
 
@@ -233,20 +233,38 @@ public abstract class AbstractBreaker {
         int endElementIndex = 0;
         for (int p = 0; p < partCount; p++) {
             PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(p);
-            endElementIndex = pbp.getLeafPos();
-            log.debug("PLM> part: " + (p + 1)
-                    + ", break at position " + endElementIndex);
 
-            startPart(effectiveList, (p == 0));
-            
-            int displayAlign = getCurrentDisplayAlign();
+            //Check the last break position for forced breaks
+            int lastBreakClass;
+            if (p == 0) {
+                lastBreakClass = effectiveList.getStartOn();
+            } else {
+                KnuthElement lastBreakElement = effectiveList.getElement(endElementIndex);
+                if (lastBreakElement.isPenalty()) {
+                    KnuthPenalty pen = (KnuthPenalty)lastBreakElement;
+                    lastBreakClass = pen.getBreakClass();
+                } else {
+                    lastBreakClass = Constants.EN_AUTO;
+                }
+            }
             
+            //the end of the new part
+            endElementIndex = pbp.getLeafPos();
+
             // ignore the first elements added by the
             // PageSequenceLayoutManager
             startElementIndex += (startElementIndex == 0) 
                     ? effectiveList.ignoreAtStart
                     : 0;
 
+            log.debug("PLM> part: " + (p + 1)
+                    + ", start at pos " + startElementIndex
+                    + ", break at pos " + endElementIndex);
+
+            startPart(effectiveList, lastBreakClass);
+            
+            int displayAlign = getCurrentDisplayAlign();
+            
             // ignore the last elements added by the
             // PageSequenceLayoutManager
             endElementIndex -= (endElementIndex == (originalList.size() - 1)) 
index e36f22c9ba586a6868dd633fabec9b334a40dcd8..fa65dfda93357e6cc122f2126eab28dd5e2211a8 100644 (file)
@@ -822,6 +822,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             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 
@@ -849,6 +851,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             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
index 049811461b7440375b4a04e7989e063ad664bcbf..59f07bf9363260bcd59f8564efab55c459b83807 100644 (file)
@@ -261,7 +261,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
             addAreas(alg, partCount, originalList, effectiveList);
         }
         
-        protected void startPart(BlockSequence list, boolean bIsFirstPage) {
+        protected void startPart(BlockSequence list, int breakClass) {
             if (curPV == null) {
                 throw new IllegalStateException("curPV must not be null");
             } else {
@@ -276,7 +276,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                         // the current BlockSequence, it could have a break
                         // condition that must be satisfied;
                         // otherwise, we may simply need a new page
-                        handleBreakTrait(bIsFirstPage ? list.getStartOn() : Constants.EN_PAGE);
+                        handleBreakTrait(breakClass);
                     }
                 }
                 pvProvider.setStartPageOfNextElementList(currentPageNum);
index ddb2a47cb9e137800f629ba831fc860b57bceac1..1e0befa99b6403a0a58ad2bc59716a4f4942b8e1 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.fop.fo.flow.TableRow;
 import org.apache.fop.traits.MinOptMax;
 
 /**
@@ -63,6 +64,11 @@ public class EffRow {
         return this.bodyType;
     }
     
+    /** @return the table-row FO for this EffRow, or null if there is no table-row. */
+    public TableRow getTableRow() {
+        return getGridUnit(0).getRow();
+    }
+    
     /** @return the calculated height for this EffRow. */
     public MinOptMax getHeight() {
         return this.height;
index 0381b4eddb11cd8328aa628d39e89e380d3776ec..4ac1343092bc1dc4df7a6de534bd51f0479a19a6 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.area.Block;
 import org.apache.fop.area.Trait;
+import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.flow.Table;
 import org.apache.fop.fo.flow.TableBody;
 import org.apache.fop.fo.flow.TableRow;
@@ -63,6 +64,7 @@ public class TableContentLayoutManager {
     private LinkedList footerList;
     private int headerNetHeight = 0;
     private int footerNetHeight = 0;
+    private boolean firstBreakBeforeServed = false;
 
     private int startXOffset;
     private int usedBPD;
@@ -130,7 +132,7 @@ public class TableContentLayoutManager {
         KnuthBox headerAsFirst = null;
         KnuthBox headerAsSecondToLast = null;
         KnuthBox footerAsLast = null;
-        if (headerIter != null) {
+        if (headerIter != null && headerList == null) {
             this.headerList = getKnuthElementsForRowIterator(
                     headerIter, context, alignment, TableRowIterator.HEADER);
             ElementListUtils.removeLegalBreaks(this.headerList);
@@ -148,7 +150,7 @@ public class TableContentLayoutManager {
                 headerAsSecondToLast = box;
             }
         }
-        if (footerIter != null) {
+        if (footerIter != null && footerList == null) {
             this.footerList = getKnuthElementsForRowIterator(
                     footerIter, context, alignment, TableRowIterator.FOOTER);
             ElementListUtils.removeLegalBreaks(this.footerList);
@@ -190,11 +192,39 @@ public class TableContentLayoutManager {
         LinkedList returnList = new LinkedList();
         EffRow[] rowGroup = null;
         while ((rowGroup = iter.getNextRowGroup()) != null) {
+            //Check for break-before on the table-row at the start of the row group
+            TableRow rowFO = rowGroup[0].getTableRow(); 
+            if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
+                log.info("break-before found");
+                if (returnList.size() > 0) {
+                    KnuthElement last = (KnuthElement)returnList.getLast();
+                    if (last.isPenalty()) {
+                        KnuthPenalty pen = (KnuthPenalty)last;
+                        pen.setP(-KnuthPenalty.INFINITE);
+                        pen.setBreakClass(rowFO.getBreakBefore());
+                    }
+                } else {
+                    if (!firstBreakBeforeServed) {
+                        returnList.add(new KnuthPenalty(0, -KnuthPenalty.INFINITE, 
+                                false, rowFO.getBreakBefore(), new Position(getTableLM()), true));
+                        iter.backToPreviousRow();
+                        firstBreakBeforeServed = true;
+                        break;
+                    }
+                }
+            }
+            firstBreakBeforeServed = true;
+            
+            //Border resolution
             if (!isSeparateBorderModel()) {
                 resolveNormalBeforeAfterBordersForRowGroup(rowGroup, iter);
             }
+            
+            //Element list creation
             createElementsForRowGroup(context, alignment, bodyType, 
                         returnList, rowGroup);
+            
+            //Handle keeps
             if (context.isKeepWithNextPending()) {
                 log.debug("child LM (row group) signals pending keep-with-next");
             }
@@ -205,7 +235,24 @@ public class TableContentLayoutManager {
                     KnuthElement last = (KnuthElement)returnList.getLast();
                     if (last.isPenalty()) {
                         KnuthPenalty pen = (KnuthPenalty)last;
-                        pen.setP(KnuthPenalty.INFINITE);
+                        //Only honor keep if there's no forced break
+                        if (!pen.isForcedBreak()) {
+                            pen.setP(KnuthPenalty.INFINITE);
+                        }
+                    }
+                }
+            }
+            
+            //Check for break-after on the table-row at the end of the row group
+            rowFO = rowGroup[rowGroup.length - 1].getTableRow(); 
+            if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
+                log.info("break-after found");
+                if (returnList.size() > 0) {
+                    KnuthElement last = (KnuthElement)returnList.getLast();
+                    if (last.isPenalty()) {
+                        KnuthPenalty pen = (KnuthPenalty)last;
+                        pen.setP(-KnuthPenalty.INFINITE);
+                        pen.setBreakClass(rowFO.getBreakAfter());
                     }
                 }
             }
@@ -215,7 +262,11 @@ public class TableContentLayoutManager {
             //Remove last penalty
             KnuthElement last = (KnuthElement)returnList.getLast();
             if (last.isPenalty()) {
-                returnList.removeLast();
+                KnuthPenalty pen = (KnuthPenalty)last;
+                if (!pen.isForcedBreak()) {
+                    //Only remove if we don't signal a forced break
+                    returnList.removeLast();
+                }
             }
         }
         return returnList;
@@ -395,8 +446,24 @@ public class TableContentLayoutManager {
                         //Get the element list for the cell contents
                         LinkedList elems = primary.getCellLM().getNextKnuthElements(
                                                 childLC, alignment);
-                        primary.setElements(elems);
+                        //Temporary? Multiple calls in case of break conditions.
+                        //TODO Revisit when table layout is restartable
+                        while (!primary.getCellLM().isFinished()) {
+                            LinkedList additionalElems = primary.getCellLM().getNextKnuthElements(
+                                    childLC, alignment);
+                            elems.addAll(additionalElems);
+                        }
                         ElementListObserver.observe(elems, "table-cell", primary.getCell().getId());
+
+                        if (((KnuthElement)elems.getLast()).isPenalty()
+                                && ((KnuthPenalty)elems.getLast()).getP() 
+                                        == -KnuthElement.INFINITE) {
+                            // a descendant of this block has break-after
+                            log.warn("Descendant of table-cell signals break: " 
+                                    + primary.getCellLM().isFinished());
+                        }
+                        
+                        primary.setElements(elems);
                         
                         if (childLC.isKeepWithNextPending()) {
                             log.debug("child LM signals pending keep-with-next");
index babdaa34bd31b909e3e57760791ccd7697e59111..bb9a40a71365e377ecbeb46b4ee4de8ab0fca8d4 100644 (file)
@@ -116,12 +116,20 @@ public class TableLayoutManager extends BlockStackingLayoutManager
         return iIndents;
     }
     
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
-     */
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         
-        //Body curLM; // currently active LM
+        LinkedList returnList = new LinkedList();
+        
+        if (!bBreakBeforeServed) {
+            try {
+                if (addKnuthElementsForBreakBefore(returnList)) {
+                    return returnList;
+                }
+            } finally {
+                bBreakBeforeServed = true;
+            }
+        }
 
         referenceIPD = context.getRefIPD();
         if (fobj.getInlineProgressionDimension().getOptimum().getEnum() != EN_AUTO) {
@@ -169,7 +177,6 @@ public class TableLayoutManager extends BlockStackingLayoutManager
 
         LinkedList returnedList = null;
         LinkedList contentList = new LinkedList();
-        LinkedList returnList = new LinkedList();
         //Position returnPosition = new NonLeafPosition(this, null);
         //Body prevLM = null;
 
@@ -179,7 +186,9 @@ public class TableLayoutManager extends BlockStackingLayoutManager
                                  stackSize));
         childLC.setRefIPD(context.getRefIPD());
 
-        contentLM = new TableContentLayoutManager(this);
+        if (contentLM == null) {
+            contentLM = new TableContentLayoutManager(this);
+        }
         returnedList = contentLM.getNextKnuthElements(childLC, alignment);
         if (childLC.isKeepWithNextPending()) {
             log.debug("TableContentLM signals pending keep-with-next");
@@ -261,6 +270,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager
             }
         }
         wrapPositionElements(contentList, returnList);
+        addKnuthElementsForBreakAfter(returnList);
         setFinished(true);
         return returnList;
     }
index 4b09fce356ddf72c9100d15657eb71722f5473bb..2fe38e79a4edf74296da0d297a20f108f05d6e8b 100644 (file)
@@ -24,6 +24,8 @@ import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.flow.TableRow;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthBox;
@@ -57,6 +59,7 @@ public class TableStepper {
     private int[] borderAfter;
     private boolean rowBacktrackForLastStep;
     private boolean[] keepWithNextSignals;
+    private boolean[] forcedBreaks;
     
     /**
      * Main constructor
@@ -77,9 +80,23 @@ public class TableStepper {
         borderBefore = new int[columnCount];
         borderAfter = new int[columnCount];
         keepWithNextSignals = new boolean[columnCount];
+        forcedBreaks = new boolean[columnCount];
         Arrays.fill(end, -1);
     }
     
+    private void clearBreakCondition() {
+        Arrays.fill(forcedBreaks, false);
+    }
+    
+    private boolean isBreakCondition() {
+        for (int i = 0; i < forcedBreaks.length; i++) {
+            if (forcedBreaks[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
     private EffRow getActiveRow() {
         return rowGroup[activeRow];
     }
@@ -147,6 +164,7 @@ public class TableStepper {
             widths[column] = 0;
             startRow[column] = activeRow;
             keepWithNextSignals[column] = false;
+            forcedBreaks[column] = false;
         } else if (gu.isPrimary()) {
             PrimaryGridUnit pgu = (PrimaryGridUnit)gu;
             boolean makeBoxForWholeRow = false;
@@ -184,6 +202,7 @@ public class TableStepper {
             widths[column] = 0;
             startRow[column] = activeRow;
             keepWithNextSignals[column] = false;
+            forcedBreaks[column] = false;
         }
     }
     
@@ -303,6 +322,10 @@ public class TableStepper {
             if (signalKeepWithNext || getTableLM().mustKeepTogether()) {
                 p = KnuthPenalty.INFINITE;
             }
+            if (isBreakCondition()) {
+                p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
+                clearBreakCondition();
+            }
             returnList.add(new KnuthPenalty(effPenaltyLen, p, false, penaltyPos, false));
 
             log.debug("step=" + step + " (+" + increase + ")"
@@ -321,11 +344,20 @@ public class TableStepper {
             //we have to signal the still pending last keep-with-next using the LayoutContext.
             context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
         }
+        if (isBreakCondition()) {
+            ((KnuthPenalty)returnList.getLast()).setP(-KnuthPenalty.INFINITE);
+        }
         lastTCPos.setFlag(TableContentPosition.LAST_IN_ROWGROUP, true);
         return returnList;
     }
     
     private int getNextStep(int lastStep) {
+        //Check for forced break conditions
+        /*
+        if (isBreakCondition()) {
+            return -1;
+        }*/
+        
         int[] backupWidths = new int[start.length];
         System.arraycopy(widths, 0, backupWidths, 0, backupWidths.length);
 
@@ -349,6 +381,11 @@ public class TableStepper {
 
         if (rowPendingIndicator == 0) {
             if (activeRow < rowGroup.length - 1) {
+                TableRow rowFO = getActiveRow().getTableRow();
+                if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
+                    log.warn("break-after ignored on table-row because of row spanning "
+                            + "in progress (See XSL 1.0, 7.19.1)");
+                }
                 activeRow++;
                 log.debug("===> new row: " + activeRow);
                 initializeElementLists();
@@ -357,6 +394,11 @@ public class TableStepper {
                         backupWidths[i] = 0;
                     }
                 }
+                rowFO = getActiveRow().getTableRow();
+                if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
+                    log.warn("break-before ignored on table-row because of row spanning "
+                            + "in progress (See XSL 1.0, 7.19.2)");
+                }
             }
         }
 
@@ -370,7 +412,11 @@ public class TableStepper {
                 end[i]++;
                 KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
                 if (el.isPenalty()) {
-                    if (el.getP() < KnuthElement.INFINITE) {
+                    if (el.getP() <= -KnuthElement.INFINITE) {
+                        log.warn("FORCED break encountered!");
+                        forcedBreaks[i] = true;
+                        break;
+                    } else if (el.getP() < KnuthElement.INFINITE) {
                         //First legal break point
                         break;
                     }