From 20ea8bf315d5acae4116ef2dc554e94c2c462c38 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 22 Jul 2009 11:20:24 +0000 Subject: [PATCH] Hacked support for changing IPD in block-container. Only normally positioned block-containers with automatic height have been tested. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ChangingIPDHack@796670 13f79535-47bb-0310-9956-ffa450edef68 --- .../BlockContainerLayoutManager.java | 306 ++++++++++++++++++ .../flow_changing-ipd_block-container_1.xml | 101 ++++++ .../flow_changing-ipd_block-container_2.xml | 89 +++++ 3 files changed, 496 insertions(+) create mode 100644 test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml create mode 100644 test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index b6dd4d082..d6c04401d 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -24,6 +24,7 @@ import java.awt.geom.Rectangle2D; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Stack; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -397,6 +398,311 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager return returnList; } + /** {@inheritDoc} */ + public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, + Position restartPosition, LayoutManager restartAtLM) { + resetSpaces(); + if (isAbsoluteOrFixed()) { + return getNextKnuthElementsAbsolute(context, alignment); + } + + autoHeight = false; + //boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0); + int maxbpd = context.getStackLimitBP().opt; + int allocBPD; + if (height.getEnum() == EN_AUTO + || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) { + //auto height when height="auto" or "if that dimension is not specified explicitly + //(i.e., it depends on content's block-progression-dimension)" (XSL 1.0, 7.14.1) + allocBPD = maxbpd; + autoHeight = true; + if (getBlockContainerFO().getReferenceOrientation() == 0) { + //Cannot easily inline element list when ref-or="180" + inlineElementList = true; + } + } else { + allocBPD = height.getValue(this); //this is the content-height + allocBPD += getBPIndents(); + } + vpContentBPD = allocBPD - getBPIndents(); + + referenceIPD = context.getRefIPD(); + if (width.getEnum() == EN_AUTO) { + updateContentAreaIPDwithOverconstrainedAdjust(); + } else { + int contentWidth = width.getValue(this); + updateContentAreaIPDwithOverconstrainedAdjust(contentWidth); + } + + double contentRectOffsetX = 0; + contentRectOffsetX += getBlockContainerFO() + .getCommonMarginBlock().startIndent.getValue(this); + double contentRectOffsetY = 0; + contentRectOffsetY += getBlockContainerFO() + .getCommonBorderPaddingBackground().getBorderBeforeWidth(false); + contentRectOffsetY += getBlockContainerFO() + .getCommonBorderPaddingBackground().getPaddingBefore(false, this); + + updateRelDims(contentRectOffsetX, contentRectOffsetY, autoHeight); + + int availableIPD = referenceIPD - getIPIndents(); + if (getContentAreaIPD() > availableIPD) { + BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( + getBlockContainerFO().getUserAgent().getEventBroadcaster()); + eventProducer.objectTooWide(this, getBlockContainerFO().getName(), + getContentAreaIPD(), context.getRefIPD(), + getBlockContainerFO().getLocator()); + } + + MinOptMax stackLimit = new MinOptMax(relDims.bpd); + + List returnedList; + List contentList = new LinkedList(); + List returnList = new LinkedList(); + + if (!breakBeforeServed) { + breakBeforeServed = true; + if (!context.suppressBreakBefore()) { + if (addKnuthElementsForBreakBefore(returnList, context)) { + return returnList; + } + } + } + + if (!firstVisibleMarkServed) { + addKnuthElementsForSpaceBefore(returnList, alignment); + context.updateKeepWithPreviousPending(getKeepWithPreviousStrength()); + } + + addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); + firstVisibleMarkServed = true; + + if (autoHeight && inlineElementList) { + //Spaces, border and padding to be repeated at each break + addPendingMarks(context); + + BlockLevelLayoutManager curLM; // currently active LM + BlockLevelLayoutManager prevLM = null; // previously active LM + + LayoutContext childLC = new LayoutContext(0); + if (lmStack.isEmpty()) { + assert restartAtLM != null && restartAtLM.getParent() == this; + curLM = (BlockLevelLayoutManager) restartAtLM; + curLM.reset(); + setCurrentChildLM(curLM); + + childLC.copyPendingMarksFrom(context); + childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); + childLC.setRefIPD(relDims.ipd); + childLC.setWritingMode(getBlockContainerFO().getWritingMode()); + if (curLM == this.childLMs.get(0)) { + childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); + //Handled already by the parent (break collapsing, see above) + } + + // get elements from curLM + returnedList = curLM.getNextKnuthElements(childLC, alignment); + } else { + curLM = (BlockLevelLayoutManager) lmStack.pop(); + setCurrentChildLM(curLM); + + childLC.copyPendingMarksFrom(context); + childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); + childLC.setRefIPD(relDims.ipd); + childLC.setWritingMode(getBlockContainerFO().getWritingMode()); + if (curLM == this.childLMs.get(0)) { + childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); + //Handled already by the parent (break collapsing, see above) + } + + // get elements from curLM + returnedList = curLM.getNextKnuthElements(childLC, alignment, lmStack, + restartPosition, restartAtLM); + } + if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { + //Propagate keep-with-previous up from the first child + context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); + childLC.clearKeepWithPreviousPending(); + } + if (returnedList.size() == 1 + && ((ListElement)returnedList.get(0)).isForcedBreak()) { + // a descendant of this block has break-before + /* + if (returnList.size() == 0) { + // the first child (or its first child ...) has + // break-before; + // all this block, including space before, will be put in + // the + // following page + bSpaceBeforeServed = false; + }*/ + contentList.addAll(returnedList); + + // "wrap" the Position inside each element + // moving the elements from contentList to returnList + returnedList = new LinkedList(); + wrapPositionElements(contentList, returnList); + + return returnList; + } else { + if (prevLM != null) { + // there is a block handled by prevLM + // before the one handled by curLM + addInBetweenBreak(contentList, context, childLC); + } + contentList.addAll(returnedList); + if (!returnedList.isEmpty()) { + if (((ListElement) ListUtil.getLast(returnedList)) + .isForcedBreak()) { + // a descendant of this block has break-after + if (curLM.isFinished()) { + // there is no other content in this block; + // it's useless to add space after before a page break + setFinished(true); + } + + returnedList = new LinkedList(); + wrapPositionElements(contentList, returnList); + + return returnList; + } + } + } + // propagate and clear + context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); + childLC.clearKeepsPending(); + prevLM = curLM; + + while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { + curLM.reset(); + childLC = new LayoutContext(0); + childLC.copyPendingMarksFrom(context); + // curLM is a ? + childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); + childLC.setRefIPD(relDims.ipd); + childLC.setWritingMode(getBlockContainerFO().getWritingMode()); + if (curLM == this.childLMs.get(0)) { + childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); + //Handled already by the parent (break collapsing, see above) + } + + // get elements from curLM + returnedList = curLM.getNextKnuthElements(childLC, alignment); + if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { + //Propagate keep-with-previous up from the first child + context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); + childLC.clearKeepWithPreviousPending(); + } + if (returnedList.size() == 1 + && ((ListElement)returnedList.get(0)).isForcedBreak()) { + // a descendant of this block has break-before + /* + if (returnList.size() == 0) { + // the first child (or its first child ...) has + // break-before; + // all this block, including space before, will be put in + // the + // following page + bSpaceBeforeServed = false; + }*/ + contentList.addAll(returnedList); + + // "wrap" the Position inside each element + // moving the elements from contentList to returnList + returnedList = new LinkedList(); + wrapPositionElements(contentList, returnList); + + return returnList; + } else { + if (prevLM != null) { + // there is a block handled by prevLM + // before the one handled by curLM + addInBetweenBreak(contentList, context, childLC); + } + contentList.addAll(returnedList); + if (returnedList.isEmpty()) { + //Avoid NoSuchElementException below (happens with empty blocks) + continue; + } + if (((ListElement) ListUtil.getLast(returnedList)) + .isForcedBreak()) { + // a descendant of this block has break-after + if (curLM.isFinished()) { + // there is no other content in this block; + // it's useless to add space after before a page break + setFinished(true); + } + + returnedList = new LinkedList(); + wrapPositionElements(contentList, returnList); + + return returnList; + } + } + // propagate and clear + context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); + childLC.clearKeepsPending(); + prevLM = curLM; + } + + returnedList = new LinkedList(); + wrapPositionElements(contentList, returnList); + + } else { + MinOptMax range = new MinOptMax(relDims.ipd); + BlockContainerBreaker breaker = new BlockContainerBreaker(this, range); + breaker.doLayout(relDims.bpd, autoHeight); + boolean contentOverflows = breaker.isOverflow(); + if (autoHeight) { + //Update content BPD now that it is known + int newHeight = breaker.deferredAlg.totalWidth; + boolean switchedProgressionDirection + = (getBlockContainerFO().getReferenceOrientation() % 180 != 0); + if (switchedProgressionDirection) { + setContentAreaIPD(newHeight); + } else { + vpContentBPD = newHeight; + } + updateRelDims(contentRectOffsetX, contentRectOffsetY, false); + } + + Position bcPosition = new BlockContainerPosition(this, breaker); + returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false)); + //TODO Handle min/opt/max for block-progression-dimension + /* These two elements will be used to add stretchability to the above box + returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, + false, returnPosition, false)); + returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0, + LINE_NUMBER_ADJUSTMENT, returnPosition, false)); + */ + + if (contentOverflows) { + BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( + getBlockContainerFO().getUserAgent().getEventBroadcaster()); + boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW); + eventProducer.viewportOverflow(this, getBlockContainerFO().getName(), + breaker.getOverflowAmount(), needClip(), canRecover, + getBlockContainerFO().getLocator()); + } + } + addKnuthElementsForBorderPaddingAfter(returnList, true); + addKnuthElementsForSpaceAfter(returnList, alignment); + + //All child content is processed. Only break-after can occur now, so... + context.clearPendingMarks(); + addKnuthElementsForBreakAfter(returnList, context); + + context.updateKeepWithNextPending(getKeepWithNextStrength()); + + setFinished(true); + return returnList; + } + + /** {@inheritDoc} */ + public boolean isRestartable() { + return true; + } + private List getNextKnuthElementsAbsolute(LayoutContext context, int alignment) { autoHeight = false; diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml new file mode 100644 index 000000000..82b757d46 --- /dev/null +++ b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml @@ -0,0 +1,101 @@ + + + + + +

+ This test checks that block-container elements correctly support an IPD change. +

+ +
+ + + + + + + + + + + + + + + + + + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + + In olden times when wishing still helped + one, there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. In olden times when wishing still helped one, there lived a king + whose daughters were all beautiful, but the youngest was so beautiful that the sun + itself, which has seen so much, was astonished whenever it shone in her + face. + + In olden times + when wishing still helped one, there lived a king whose daughters were all beautiful, + but the youngest was so beautiful that the sun itself, which has seen so much, was + astonished whenever it shone in her face. + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml new file mode 100644 index 000000000..7a2bb9b19 --- /dev/null +++ b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml @@ -0,0 +1,89 @@ + + + + + +

+ This test checks that a change of IPD between two blocks surrounded by a block-container is + correctly handled. +

+ +
+ + + + + + + + + + + + + + + + + + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + In olden times when wishing still helped + one, there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + In olden times when wishing still helped one, + there lived a king whose daughters were all beautiful, but the youngest was so + beautiful that the sun itself, which has seen so much, was astonished whenever it + shone in her face. + + + + + + + + + + + + + + + + +
-- 2.39.5