From f5e524b0b29ee477cbde63f8a946e80ee1134348 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 27 Mar 2014 20:49:11 +0000 Subject: [PATCH] Handle middle-of-the-page case without using a glue. Using a glue may cause a spurious empty page if the multi-switch is at the end of the flow, with no satisfying way of fixing that. Patch by Seifeddine Dridi git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_WhitespaceManagement@1582469 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/layoutmgr/BestFitLayoutUtils.java | 12 ++-- .../apache/fop/layoutmgr/BestFitPenalty.java | 2 + .../fop/layoutmgr/MultiCaseLayoutManager.java | 32 +--------- .../layoutmgr/MultiSwitchLayoutManager.java | 58 +------------------ .../fop/layoutmgr/PageBreakingAlgorithm.java | 27 +++++---- ...ulti-switch_best-fit_multiple-variants.xml | 11 ++-- 6 files changed, 33 insertions(+), 109 deletions(-) diff --git a/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java b/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java index c59c9d607..148a83eba 100644 --- a/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java +++ b/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java @@ -40,10 +40,12 @@ public final class BestFitLayoutUtils { public List getPositionList() { List positions = new LinkedList(); - if (knuthList != null) { + if (knuthList != null && !knuthList.isEmpty()) { SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1); - for (ListElement elem : knuthList) { - positions.add(elem.getPosition()); + for (ListElement el : knuthList) { + if (el.getPosition() != null) { + positions.add(el.getPosition()); + } } } return positions; @@ -75,10 +77,6 @@ public final class BestFitLayoutUtils { // when they are at the end of the Knuth list. knuthList.add(new KnuthBox(0, new Position(lm), false)); knuthList.add(bestFitPenalty); - Variant firstVariant = bestFitPenalty.getVariants().get(0); - BestFitPosition pos = new BestFitPosition(lm); - pos.setKnuthList(firstVariant.knuthList); - knuthList.add(new KnuthGlue(firstVariant.width, 0, 0, pos, false)); knuthList.add(new KnuthBox(0, new Position(lm), false)); return knuthList; } diff --git a/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java b/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java index 334a36900..692cc19cb 100644 --- a/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java +++ b/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java @@ -35,10 +35,12 @@ public class BestFitPenalty extends KnuthPenalty { public final List knuthList; public final int width; + public int penaltyIndex; public Variant(List knuthList, int width) { this.knuthList = knuthList; this.width = width; + this.penaltyIndex = -1; } public KnuthElement toPenalty() { diff --git a/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java b/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java index bc3e61b8e..9469a2fb8 100644 --- a/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java @@ -18,14 +18,10 @@ package org.apache.fop.layoutmgr; import org.apache.fop.area.Area; -import org.apache.fop.area.Block; -import org.apache.fop.area.LineArea; import org.apache.fop.fo.FObj; public class MultiCaseLayoutManager extends BlockStackingLayoutManager { - private Block curBlockArea; - public MultiCaseLayoutManager(FObj node) { super(node); } @@ -47,36 +43,12 @@ public class MultiCaseLayoutManager extends BlockStackingLayoutManager { @Override public Area getParentArea(Area childArea) { - if (curBlockArea == null) { - curBlockArea = new Block(); - curBlockArea.setIPD(super.getContentAreaIPD()); - // Set up dimensions - // Must get dimensions from parent area - /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea); - setCurrentArea(curBlockArea); - } - return curBlockArea; + return parentLayoutManager.getParentArea(childArea); } @Override public void addChildArea(Area childArea) { - if (curBlockArea != null) { - if (childArea instanceof LineArea) { - curBlockArea.addLineArea((LineArea) childArea); - } else { - curBlockArea.addBlock((Block) childArea); - } - } - } - - /** - * Force current area to be added to parent area. - */ - @Override - protected void flush() { - if (getCurrentArea() != null) { - super.flush(); - } + parentLayoutManager.addChildArea(childArea); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java b/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java index 8ef901a56..a2b0e90b0 100644 --- a/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java @@ -22,14 +22,10 @@ import java.util.LinkedList; import java.util.List; import org.apache.fop.area.Area; -import org.apache.fop.area.Block; -import org.apache.fop.area.LineArea; import org.apache.fop.fo.FObj; public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { - private Block curBlockArea; - public MultiSwitchLayoutManager(FObj node) { super(node); } @@ -55,61 +51,14 @@ public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { return BestFitLayoutUtils.getKnuthList(this, childrenLists); } - @Override - public Keep getKeepTogether() { - return Keep.KEEP_AUTO; - } - - @Override - public Keep getKeepWithNext() { - return Keep.KEEP_AUTO; - } - - @Override - public Keep getKeepWithPrevious() { - return Keep.KEEP_AUTO; - } - - @Override - public int getContentAreaIPD() { - if (curBlockArea != null) { - return curBlockArea.getIPD(); - } - return super.getContentAreaIPD(); - } - @Override public Area getParentArea(Area childArea) { - if (curBlockArea == null) { - curBlockArea = new Block(); - curBlockArea.setIPD(super.getContentAreaIPD()); - setCurrentArea(curBlockArea); - // Set up dimensions - // Must get dimensions from parent area - /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea); - } - return curBlockArea; + return parentLayoutManager.getParentArea(childArea); } @Override public void addChildArea(Area childArea) { - if (curBlockArea != null) { - if (childArea instanceof LineArea) { - curBlockArea.addLineArea((LineArea) childArea); - } else { - curBlockArea.addBlock((Block) childArea); - } - } - } - - /** - * Force current area to be added to parent area. - */ - @Override - protected void flush() { - if (curBlockArea != null) { - parentLayoutManager.addChildArea(getCurrentArea()); - } + parentLayoutManager.addChildArea(childArea); } @Override @@ -121,9 +70,6 @@ public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { AreaAdditionUtil.addAreas(this, newPosIter, context); flush(); - // TODO removing the following line forces the generated area - // to be rendered twice in some cases... - curBlockArea = null; } } diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java index a5ed077d8..8c587bcc6 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java @@ -99,9 +99,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { private int currentKeepContext = Constants.EN_AUTO; private KnuthNode lastBeforeKeepContextSwitch; - /** Holds the variant of a dynamic content that must be attached to the next page node */ - private Variant variant; - /** * Construct a page breaking algorithm. * @param topLevelLM the top level layout manager @@ -156,7 +153,10 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { /** Index of the last inserted element of the last inserted footnote. */ public int footnoteElementIndex; + /** Current active variant attached to this node */ public final Variant variant; + /** Pending variant to be assigned to all descending nodes */ + public Variant pendingVariant; public KnuthPageNode(int position, int line, int fitness, @@ -201,7 +201,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { bestTotalFootnotesLength[fitness] = totalFootnotesLength; bestFootnoteListIndex[fitness] = footnoteListIndex; bestFootnoteElementIndex[fitness] = footnoteElementIndex; - bestVariant[fitness] = variant; + bestVariant[fitness] = ((KnuthPageNode) node).pendingVariant; } public int getInsertedFootnotesLength(int fitness) { @@ -223,6 +223,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { public Variant getVariant(int fitness) { return bestVariant[fitness]; } + } /** {@inheritDoc} */ @@ -315,7 +316,8 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { insertedFootnotesLength, totalFootnotesLength, footnoteListIndex, footnoteElementIndex, adjustRatio, availableShrink, availableStretch, - difference, totalDemerits, previous, variant); + difference, totalDemerits, previous, + (previous != null) ? ((KnuthPageNode)previous).pendingVariant : null); } /** {@inheritDoc} */ @@ -525,12 +527,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { int actualWidth = totalWidth - pageNode.totalWidth; int footnoteSplit; boolean canDeferOldFN; - variant = null; if (element.isPenalty()) { if (element instanceof BestFitPenalty) { - actualWidth += handleBestFitPenalty(activeNode, (BestFitPenalty) element, elementIndex); + actualWidth += handleBestFitPenalty(pageNode, (BestFitPenalty) element, elementIndex); } else { actualWidth += element.getWidth(); + if (pageNode.pendingVariant != null) { + actualWidth += ((KnuthPageNode) activeNode).pendingVariant.width; + } } } if (footnotesPending) { @@ -591,13 +595,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { } } - private int handleBestFitPenalty(KnuthNode activeNode, BestFitPenalty penalty, int elementIndex) { + private int handleBestFitPenalty(KnuthPageNode activeNode, BestFitPenalty penalty, int elementIndex) { for (Variant var : penalty.getVariants()) { int difference = computeDifference(activeNode, var.toPenalty(), elementIndex); double r = computeAdjustmentRatio(activeNode, difference); if (r >= -1.0) { - variant = var; - return variant.width; + var.penaltyIndex = elementIndex; + activeNode.pendingVariant = var; + return var.width; } } return 0; @@ -1018,7 +1023,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { // Check if the given node has an attached variant of a dynamic content KnuthPageNode pageNode = (KnuthPageNode) bestActiveNode; if (pageNode.variant != null) { - BestFitPenalty penalty = (BestFitPenalty) par.get(pageNode.position); + BestFitPenalty penalty = (BestFitPenalty) par.get(pageNode.variant.penaltyIndex); penalty.setActiveVariant(pageNode.variant); } int difference = bestActiveNode.difference; diff --git a/test/layoutengine/standard-testcases/multi-switch_best-fit_multiple-variants.xml b/test/layoutengine/standard-testcases/multi-switch_best-fit_multiple-variants.xml index bb0715fa0..11b3cfe7d 100644 --- a/test/layoutengine/standard-testcases/multi-switch_best-fit_multiple-variants.xml +++ b/test/layoutengine/standard-testcases/multi-switch_best-fit_multiple-variants.xml @@ -106,13 +106,13 @@ - + - + @@ -122,8 +122,9 @@ - - - + + + + -- 2.39.5