Browse Source

Block Knuth sequences in inline content are properly joined, taking

keeps into account.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@360073 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_92-beta
Simon Pepping 18 years ago
parent
commit
7dfb879efc

+ 16
- 92
src/java/org/apache/fop/layoutmgr/BlockKnuthSequence.java View File

@@ -57,109 +57,33 @@ public class BlockKnuthSequence extends KnuthSequence {
return !sequence.isInlineSequence() && !isClosed;
}

/**
* this and sequence are supposed to belong to the same LayoutManager,
* which is stored in the positions of the elements in the sequences
* @param sequence The sequence following this
* @return whether this and the following sequence must be kept together
*/
private boolean mustKeepWithNext(BlockKnuthSequence sequence) {
/* // TODO read keep together correctly
// for now, return false
return BlockKnuthSequence.mustKeepTogether(this, sequence);
*/ return false;
}

/**
* the two sequences are supposed to belong to the same LayoutManager,
* which is stored in the positions of the elements in the sequences
* @param sequence1 The leading sequence
* @param sequence2 The following sequence
* @return whether the two sequences must be kept together
/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthList#appendSequence(org.apache.fop.layoutmgr.KnuthSequence,)
*/
public static boolean mustKeepTogether(BlockKnuthSequence sequence1,
BlockKnuthSequence sequence2) {
ListElement element1 = (ListElement) sequence1.get(sequence1.size() - 1);
LayoutManager lm1 = (LayoutManager) element1.getLayoutManager();
ListElement element2 = (ListElement) sequence2.get(0);
LayoutManager lm2 = (LayoutManager) element2.getLayoutManager();
if (!lm1.equals(lm2)) {
throw new IllegalStateException
("The two sequences must belong to the same LayoutManager");
}
if (lm1 instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) lm1).mustKeepTogether()) {
return true;
}
Position pos1 = element1.getPosition();
if (pos1 != null) {
pos1 = pos1.getPosition();
if (pos1 != null) {
lm1 = pos1.getLM();
if (lm1 instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) lm1).mustKeepWithNext()) {
return true;
}
}
}
Position pos2 = element1.getPosition();
if (pos2 != null) {
pos2 = pos2.getPosition();
if (pos2 != null) {
lm2 = pos2.getLM();
if (lm2 instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) lm2).mustKeepWithPrevious()) {
return true;
}
}
}
public boolean appendSequence(KnuthSequence sequence) {
// log.debug("Cannot append a sequence without a BreakElement");
return false;
/* From BlockStackingLM.getChangedKnuthElements
// there is another block after this one
if (bSomethingAdded
&& (this.mustKeepTogether()
|| prevLM.mustKeepWithNext()
|| currLM.mustKeepWithPrevious())) {
// add an infinite penalty to forbid a break between blocks
returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new Position(this), false));
} else if (bSomethingAdded && !((KnuthElement) returnedList.getLast()).isGlue()) {
// add a null penalty to allow a break between blocks
returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
}
*/ }

}
/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthList#appendSequence(org.apache.fop.layoutmgr.KnuthSequence, org.apache.fop.layoutmgr.LayoutManager)
* @see KnuthList#appendSequence(KnuthSequence, boolean, BreakElement)
*/
/**
* this and sequence are supposed to belong to the same LayoutManager,
* which is stored in the positions of the elements in the sequences
*/
public boolean appendSequence(KnuthSequence sequence, LayoutManager lm) {
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
if (!canAppendSequence(sequence)) {
return false;
}
/* // TODO disable because InlineLM.addAreas expects only NonLeafPostions; why?
if (!mustKeepWithNext((BlockKnuthSequence) sequence)) {
add(new KnuthPenalty(0, 0, false, new Position(lm), false));
if (keepTogether) {
breakElement.setPenaltyValue(KnuthElement.INFINITE);
add(breakElement);
} else if (!((ListElement) getLast()).isGlue()) {
breakElement.setPenaltyValue(0);
add(breakElement);
}
*/ addAll(sequence);
addAll(sequence);
return true;
}

/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthList#appendSequenceOrClose(org.apache.fop.layoutmgr.KnuthSequence, org.apache.fop.layoutmgr.LayoutManager)
*/
public boolean appendSequenceOrClose(KnuthSequence sequence, LayoutManager lm) {
if (!appendSequence(sequence, lm)) {
endSequence();
return false;
} else {
return true;
}
}
/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthSequence#endSequence()
*/

+ 9
- 6
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

@@ -27,6 +27,7 @@ import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fonts.Font;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
import org.apache.fop.traits.MinOptMax;
@@ -198,13 +199,15 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
* @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
*/
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
// TODO Keeps will have to be more sophisticated sooner or later
// TODO This is a quick fix for the fact that the parent is not always a BlockLevelLM;
// eventually mustKeepTogether() must be moved up to the LM interface
return (getParent() instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| !getBlockFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockFO().getKeepTogether().getWithinColumn().isAuto();
return (!getBlockFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockFO().getKeepTogether().getWithinColumn().isAuto()
|| (getParent() instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| (getParent() instanceof InlineLayoutManager
&& ((InlineLayoutManager) getParent()).mustKeepTogether()));
}

/**
@@ -212,7 +215,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
*/
public boolean mustKeepWithPrevious() {
return !getBlockFO().getKeepWithPrevious().getWithinPage().isAuto()
|| !getBlockFO().getKeepWithPrevious().getWithinColumn().isAuto();
|| !getBlockFO().getKeepWithPrevious().getWithinColumn().isAuto();
}

/**

+ 15
- 8
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -29,6 +29,7 @@ import org.apache.fop.area.Block;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
import org.apache.fop.traits.MinOptMax;

@@ -309,9 +310,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
if (mustKeepTogether()
|| context.isKeepWithNextPending()
|| childLC.isKeepWithPreviousPending()) {
//Clear keep pending flag
// Clear keep pending flag
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
// add an infinite penalty to forbid a break between
// blocks
contentList.add(new BreakElement(
@@ -368,11 +368,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
return returnList;
}*/
}
if (childLC.isKeepWithNextPending()) {
//Clear and propagate
childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
}
// propagate and clear
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, childLC.isKeepWithNextPending());
childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
prevLM = curLM;
}

@@ -617,6 +616,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
}
fromIndex = workListIterator.previousIndex();

/*
* TODO: why are KnuthPenalties added here,
* while in getNextKE they were changed to BreakElements?
*/
// there is another block after this one
if (bSomethingAdded
&& (this.mustKeepTogether()
@@ -732,8 +735,12 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
/**
* @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether()
*/
// default action: ask parentLM
public boolean mustKeepTogether() {
return false;
return ((getParent() instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| (getParent() instanceof InlineLayoutManager
&& ((InlineLayoutManager) getParent()).mustKeepTogether()));
}

/**

+ 12
- 14
src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java View File

@@ -26,7 +26,8 @@ import org.apache.fop.layoutmgr.inline.KnuthInlineBox;


/**
*
* Represents a list of inline Knuth elements.
* If closed, it represents all elements of a Knuth paragraph.
*/
public class InlineKnuthSequence extends KnuthSequence {

@@ -63,9 +64,9 @@ public class InlineKnuthSequence extends KnuthSequence {
}

/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthSequence#appendSequence(org.apache.fop.layoutmgr.KnuthSequence, org.apache.fop.layoutmgr.LayoutManager)
* @see org.apache.fop.layoutmgr.KnuthSequence#appendSequence(org.apache.fop.layoutmgr.KnuthSequence)
*/
public boolean appendSequence(KnuthSequence sequence, LayoutManager lm) {
public boolean appendSequence(KnuthSequence sequence) {
if (!canAppendSequence(sequence)) {
return false;
}
@@ -82,17 +83,14 @@ public class InlineKnuthSequence extends KnuthSequence {
}

/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthSequence#appendSequenceOrClose(org.apache.fop.layoutmgr.KnuthSequence, org.apache.fop.layoutmgr.LayoutManager)
* @see KnuthSequence#appendSequence(KnuthSequence, boolean, BreakElement)
*/
public boolean appendSequenceOrClose(KnuthSequence sequence, LayoutManager lm) {
if (!appendSequence(sequence, lm)) {
endSequence();
return false;
} else {
return true;
}
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
return appendSequence(sequence);
}

/* (non-Javadoc)
* @see org.apache.fop.layoutmgr.KnuthSequence#endSequence()
*/
@@ -108,9 +106,9 @@ public class InlineKnuthSequence extends KnuthSequence {
KnuthBox prevBox = (KnuthBox) getLast();
if (prevBox.isAuxiliary()
&& (size() < 4
|| !getElement(size()-2).isGlue()
|| !getElement(size()-3).isPenalty()
|| !getElement(size()-4).isBox()
|| !getElement(size() - 2).isGlue()
|| !getElement(size() - 3).isPenalty()
|| !getElement(size() - 4).isBox()
)
) {
// Not the sequence we are expecting

+ 37
- 6
src/java/org/apache/fop/layoutmgr/KnuthSequence.java View File

@@ -65,22 +65,53 @@ public abstract class KnuthSequence extends ArrayList {

/**
* Append sequence to this sequence if it can be appended.
* TODO In principle the LayoutManager can also be retrieved from the elements in the sequence.
* @param sequence The sequence that is to be appended.
* @param lm The LayoutManager for the Position that may have to be created.
* @param keepTogether Whether the two sequences must be kept together.
* @param breakElement The BreakElement that may be inserted between the two sequences.
* @return whether the sequence was succesfully appended to this sequence.
*/
public abstract boolean appendSequence(KnuthSequence sequence, LayoutManager lm);
public abstract boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement);
/**
* Append sequence to this sequence if it can be appended.
* @param sequence The sequence that is to be appended.
* @return whether the sequence was succesfully appended to this sequence.
*/
public abstract boolean appendSequence(KnuthSequence sequence);
/**
* Append sequence to this sequence if it can be appended.
* If that is not possible, close this sequence.
* TODO In principle the LayoutManager can also be retrieved from the elements in the sequence.
* @param sequence The sequence that is to be appended.
* @param lm The LayoutManager for the Position that may have to be created.
* @return whether the sequence was succesfully appended to this sequence.
*/
public abstract boolean appendSequenceOrClose(KnuthSequence sequence, LayoutManager lm);
public boolean appendSequenceOrClose(KnuthSequence sequence) {
if (!appendSequence(sequence)) {
endSequence();
return false;
} else {
return true;
}
}
/**
* Append sequence to this sequence if it can be appended.
* If that is not possible, close this sequence.
* @param sequence The sequence that is to be appended.
* @param keepTogether Whether the two sequences must be kept together.
* @param breakElement The BreakElement that may be inserted between the two sequences.
* @return whether the sequence was succesfully appended to this sequence.
*/
public boolean appendSequenceOrClose(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
if (!appendSequence(sequence, keepTogether, breakElement)) {
endSequence();
return false;
} else {
return true;
}
}
/**
* Wrap the Positions of the elements of this sequence in a Position for LayoutManager lm.

+ 43
- 6
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java View File

@@ -35,6 +35,8 @@ import org.apache.fop.fo.properties.CommonMarginInline;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fonts.Font;
import org.apache.fop.layoutmgr.BlockKnuthSequence;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthSequence;
@@ -196,6 +198,24 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
}
}

/**
* @return true if this element must be kept together
*/
// TODO Use the keep-together property on Inline as well
public boolean mustKeepTogether() {
return mustKeepTogether(this.getParent());
}

private boolean mustKeepTogether(LayoutManager lm) {
if (lm instanceof BlockLevelLayoutManager) {
return ((BlockLevelLayoutManager) lm).mustKeepTogether();
} else if (lm instanceof InlineLayoutManager) {
return ((InlineLayoutManager) lm).mustKeepTogether();
} else {
return mustKeepTogether(lm.getParent());
}
}

/** @see org.apache.fop.layoutmgr.LayoutManager */
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
LayoutManager curLM;
@@ -267,6 +287,9 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
}
// get KnuthElements from curLM
returnedList = curLM.getNextKnuthElements(childLC, alignment);
if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
}
if (returnedList == null) {
// curLM returned null because it finished;
// just iterate once more to see if there is another child
@@ -276,6 +299,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
continue;
}
if (curLM instanceof InlineLevelLayoutManager) {
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
// "wrap" the Position stored in each element of returnedList
ListIterator seqIter = returnedList.listIterator();
while (seqIter.hasNext()) {
@@ -283,7 +307,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
sequence.wrapPositions(this);
}
if (lastSequence != null && lastSequence.appendSequenceOrClose
((KnuthSequence) returnedList.get(0), this)) {
((KnuthSequence) returnedList.get(0))) {
returnedList.remove(0);
}
// add border and padding to the first complete sequence of this LM
@@ -293,13 +317,21 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
}
returnList.addAll(returnedList);
} else { // A block LM
// TODO For now avoid having two different block LMs in a single sequence
if (curLM != lastChildLM && lastSequence != null) {
lastSequence.endSequence();
}
BlockKnuthSequence sequence = new BlockKnuthSequence(returnedList);
sequence.wrapPositions(this);
if (lastSequence == null || !lastSequence.appendSequenceOrClose(sequence, this)) {
boolean appended = false;
if (lastSequence != null) {
if (lastSequence.canAppendSequence(sequence)) {
BreakElement bk = new BreakElement(new Position(this), 0, context);
boolean keepTogether = (mustKeepTogether()
|| context.isKeepWithNextPending()
|| childLC.isKeepWithPreviousPending());
appended = lastSequence.appendSequenceOrClose(sequence, keepTogether, bk);
} else {
lastSequence.endSequence();
}
}
if (!appended) {
// add border and padding to the first complete sequence of this LM
if (!borderAdded) {
addKnuthElementsForBorderPaddingStart(sequence);
@@ -307,6 +339,11 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
}
returnList.add(sequence);
}
// propagate and clear
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING,
childLC.isKeepWithNextPending());
childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
}
lastSequence = (KnuthSequence) returnList.getLast();
lastChildLM = curLM;

+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -1312,7 +1312,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether
*/
public boolean mustKeepTogether() {
return false;
return ((BlockLevelLayoutManager) getParent()).mustKeepTogether();
}

/**

+ 66
- 0
test/layoutengine/standard-testcases/inline_block_nested_6.xml View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 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.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks the value of the penalties between
KnuthBlockBoxes in inline context, with and without keep conditions.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>

<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block><fo:inline>Before
<fo:block id="b1" background-color="silver"><fo:inline>Before1
<fo:block id="b11" background-color="grey">A1=B1,</fo:block>
<fo:block id="b12">C1=D1.</fo:block>after1</fo:inline></fo:block>
<fo:block id="b2" background-color="lightgrey" keep-together.within-page="always"><fo:inline>Before2
<fo:block id="b21" background-color="grey">A2=B2,</fo:block>
<fo:block id="b22">C2=D2.</fo:block>after2</fo:inline></fo:block>
<fo:block id="b3" background-color="silver"><fo:inline>Before3
<fo:block id="b31" keep-with-next.within-page="always" background-color="grey">A3=B3,</fo:block>
<fo:block id="b32">C3=D3.</fo:block>after3</fo:inline></fo:block>after</fo:inline></fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<element-list category="breaker">
<skip>5</skip>
<!-- penalty between blocks b11 and b12, set by InlineLM in b1 -->
<penalty w="0" p="0"/>
<skip>6</skip>
<!-- penalty between blocks b21 and b22, set by InlineLM in b2 -->
<!-- keep-together.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>6</skip>
<!-- penalty between blocks b31 and b32, set by InlineLM in b3 -->
<!-- keep-with-next.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>5</skip>
<skip>3</skip>
</element-list>
</checks>
</testcase>

Loading…
Cancel
Save