Skip to content

Commit

Permalink
Fix interpretation of nested blocks with volume-keep-priority (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
bertfrees authored and kalaspuffar committed Sep 16, 2019
1 parent 54733b2 commit ba216aa
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 72 deletions.
54 changes: 25 additions & 29 deletions src/org/daisy/dotify/formatter/impl/core/FormatterCoreImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ public class FormatterCoreImpl extends Stack<Block> implements FormatterCore, Bl
private final boolean discardIdentifiers;
private Table table;
protected final FormatterCoreContext fc;
//The code where this variable is used is not very nice, but it will do to get the feature running
private Boolean endStart = null;

// TODO: fix recursive keep problem
// TODO: Implement floating elements
public FormatterCoreImpl(FormatterCoreContext fc) {
Expand Down Expand Up @@ -105,10 +104,6 @@ public void startBlock(BlockProperties p, String blockId) {
if (table!=null) {
throw new IllegalStateException("A table is open.");
}
if (endStart!=null && endStart == true) {
getCurrentBlock().setAvoidVolumeBreakAfterPriority(getCurrentVolumeKeepPriority());
}
endStart = null;
String lb = "";
String rb = "";
if (p.getTextBorderStyle()!=null) {
Expand All @@ -134,6 +129,9 @@ public void startBlock(BlockProperties p, String blockId) {
margins(new BlockMargin(new Margin(Type.LEFT, leftMarginComps), new Margin(Type.RIGHT, rightMarginComps), fc.getSpaceCharacter())).
outerSpaceBefore(p.getMargin().getTopSpacing()).
underlineStyle(p.getUnderlineStyle());
// We don't get the volume keep priority from block properties, because it could have been inherited from an ancestor
AncestorContext ac = new AncestorContext(p, inheritVolumeKeepPriority(p.getVolumeKeepPriority()));
setPrecedingVolumeKeepAfterPriority(ac.getVolumeKeepPriority());
Block c = newBlock(blockId, rdp.build());
if (propsContext.size()>0 && propsContext.peek().getBlockProperties().getListType()!=FormattingTypes.ListStyle.NONE) {
String listLabel = p.getListItemLabel();
Expand Down Expand Up @@ -176,10 +174,8 @@ public void startBlock(BlockProperties p, String blockId) {
}
c.setKeepWithNextSheets(p.getKeepWithNextSheets());
c.setVerticalPosition(p.getVerticalPosition());
AncestorContext ac = new AncestorContext(p, inheritVolumeKeepPriority(p.getVolumeKeepPriority()));
// We don't get the volume keep priority from block properties, because it could have been inherited from an ancestor
c.setAvoidVolumeBreakInsidePriority(ac.getVolumeKeepPriority());
c.setAvoidVolumeBreakAfterPriority(ac.getVolumeKeepPriority());
c.setAvoidVolumeBreakAfterPriority(-1); // value will be overwritten later
propsContext.push(ac);
Block bi = getCurrentBlock();
RowDataProperties.Builder builder = new RowDataProperties.Builder(bi.getRowDataProperties());
Expand All @@ -202,8 +198,24 @@ private Integer getCurrentVolumeKeepPriority() {
return propsContext.isEmpty()?null:propsContext.peek().getVolumeKeepPriority();
}

private Integer getParentVolumeKeepPriority() {
return propsContext.size()<2?null:propsContext.get(propsContext.size()-2).getVolumeKeepPriority();
// Set volume-break-after priority of the preceding block to volume-break-inside of the current
// block if the new value is higher (lower priority). If the preceding block is empty, do the
// same with the block before it, etc. This is done because it's the RowGroup objects that will
// carry the priority information to the PageSequenceBuilder/SheetDataSource, and the priority
// information of empty blocks will be ignored.
private void setPrecedingVolumeKeepAfterPriority(Integer currentPriority) {
int i = size();
while (i > 0) {
Block b = get(i - 1);
Integer pr = b.getAvoidVolumeBreakAfterPriority();
if (currentPriority == null || (pr != null && currentPriority > pr)) {
b.setAvoidVolumeBreakAfterPriority(currentPriority);
}
if (!b.isEmpty()) {
break;
}
i--;
}
}

@Override
Expand All @@ -214,11 +226,6 @@ public void endBlock() {
if (listItem!=null) {
addChars("", new TextProperties.Builder(null).build());
}
if (endStart == null) {
endStart = true;
} else {
endStart = false;
}
{
AncestorContext ac = propsContext.pop();
BlockProperties p = ac.getBlockProperties();
Expand All @@ -234,21 +241,10 @@ public void endBlock() {
outerSpaceAfter(bi.getRowDataProperties().getOuterSpaceAfter()+p.getMargin().getBottomSpacing());
bi.setKeepWithPreviousSheets(p.getKeepWithPreviousSheets());
bi.setRowDataProperties(builder.build());
//set the volume keep after for the closing block to the parent priority
bi.setAvoidVolumeBreakAfterPriority(getCurrentVolumeKeepPriority());
if (bi.isEmpty()) {
// if this group doesn't have data, then
// apply this blocks volume break after priority to the previous block
// if that block's break after priority is equal to this block's break
// inside priority.
Block preceding = size()>1?get(size()-2):null;
if (preceding!=null && preceding.getAvoidVolumeBreakAfterPriority()==bi.getAvoidVolumeBreakInsidePriority()) {
preceding.setAvoidVolumeBreakAfterPriority(bi.getAvoidVolumeBreakAfterPriority());
}
}
}
leftMarginComps.pop();
rightMarginComps.pop();
setPrecedingVolumeKeepAfterPriority(getCurrentVolumeKeepPriority());
if (propsContext.size()>0) {
AncestorContext ac = propsContext.peek();
BlockProperties p = ac.getBlockProperties();
Expand All @@ -275,7 +271,7 @@ public void endBlock() {
c.setKeepWithNext(next);
// We don't get the volume keep priority from the BlockProperties, as it could have been inherited from an ancestor
c.setAvoidVolumeBreakInsidePriority(getCurrentVolumeKeepPriority());
c.setAvoidVolumeBreakAfterPriority(getParentVolumeKeepPriority());
c.setAvoidVolumeBreakAfterPriority(-1); // value will be overwritten later
}
//firstRow = true;
}
Expand Down
117 changes: 74 additions & 43 deletions test/org/daisy/dotify/formatter/impl/core/FormatterCoreImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,46 @@ public void testBlockPropertiesHierarchy() {
assertEquals(expectedOuter, formatter.get(2).getRowDataProperties());
}

// The following tests are to verify that:
//
// 1) Blocks inherit their volume-break-inside value from their parent
//
// 2) Blocks get their volume-break-after value from the following block with the
// volume-break-inside value and that does not come after the first following non-empty
// block. If there is no following non-empty block, the block's volume-break-after value will
// be null.
//
// Note that if an volume-break-inside is absent (null) it is as if the block has a high value.

@Test
public void testVolumeKeepProperties_01() {
//Setup
FormatterCoreImpl formatter = new FormatterCoreImpl(context);
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build());
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build());
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(3).build());
formatter.addChars(" ", UND_TEXT_PROPERTIES); // adds a segment to this block to remain in sync with previous test result
formatter.endBlock();
formatter.addChars(" ", UND_TEXT_PROPERTIES); // adds a segment to this block to remain in sync with previous test result
formatter.endBlock();
formatter.addChars(" ", UND_TEXT_PROPERTIES); // adds a segment to this block to remain in sync with previous test result
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build()); // start block 1
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build()); // start block 2
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(3).build()); // start block 3
formatter.addChars(" ", UND_TEXT_PROPERTIES);
formatter.endBlock(); // end block 3
formatter.addChars(" ", UND_TEXT_PROPERTIES);
formatter.endBlock(); // end block 2
formatter.addChars(" ", UND_TEXT_PROPERTIES);
formatter.endBlock(); // end block 1

//Test
assertEquals(5, formatter.size());
// in block 1 before block 2: empty
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakInsidePriority());
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakAfterPriority());
assertEquals(3, (int)formatter.get(0).getAvoidVolumeBreakAfterPriority());
// in block 2 before block 3: empty
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakAfterPriority());
assertEquals(3, (int)formatter.get(1).getAvoidVolumeBreakAfterPriority());
// in block 3
assertEquals(3, (int)formatter.get(2).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(2).getAvoidVolumeBreakAfterPriority());
// in block 2 after block 3
assertEquals(2, (int)formatter.get(3).getAvoidVolumeBreakInsidePriority());
assertEquals(1, (int)formatter.get(3).getAvoidVolumeBreakAfterPriority());
// in block 1 after block 2
assertEquals(1, (int)formatter.get(4).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(4).getAvoidVolumeBreakAfterPriority());
}
Expand All @@ -97,19 +113,22 @@ public void testVolumeKeepProperties_01() {
public void testVolumeKeepProperties_02() {
//Setup
FormatterCoreImpl formatter = new FormatterCoreImpl(context);
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build());
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build());
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(3).build());
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build()); // start block 1
formatter.endBlock(); // end block 1
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build()); // start block 2
formatter.endBlock(); // end block 2
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(3).build()); // start block 3
formatter.endBlock(); // end block 3

//Test
assertEquals(3, formatter.size());
// in block 1: empty
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(0).getAvoidVolumeBreakAfterPriority());
// in block 2: empty
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(1).getAvoidVolumeBreakAfterPriority());
// in block 3: empty
assertEquals(3, (int)formatter.get(2).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(2).getAvoidVolumeBreakAfterPriority());

Expand All @@ -119,31 +138,38 @@ public void testVolumeKeepProperties_02() {
public void testVolumeKeepProperties_03() {
//Setup
FormatterCoreImpl formatter = new FormatterCoreImpl(context);
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build());
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build());
formatter.startBlock(new BlockProperties.Builder().build());
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().build());
formatter.endBlock();
formatter.addChars(" ", UND_TEXT_PROPERTIES); // adds a segment to this block to remain in sync with previous test result
formatter.endBlock();
formatter.addChars(" ", UND_TEXT_PROPERTIES); // adds a segment to this block to remain in sync with previous test result
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build()); // start block 1
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build()); // start block 2
formatter.startBlock(new BlockProperties.Builder().build()); // start block 3
formatter.endBlock(); // end block 3
formatter.startBlock(new BlockProperties.Builder().build()); // start block 4
formatter.endBlock(); // end block 4
formatter.addChars(" ", UND_TEXT_PROPERTIES);
formatter.endBlock(); // end block 2
formatter.addChars(" ", UND_TEXT_PROPERTIES);
formatter.endBlock(); // end block 1

//Test
assertEquals(7, formatter.size());
// in block 1 before block 2: empty
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakInsidePriority());
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakAfterPriority());
assertEquals(2, (int)formatter.get(0).getAvoidVolumeBreakAfterPriority());
// in block 2 before block 3: empty
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakAfterPriority());
// in block 3: empty
assertEquals(2, (int)formatter.get(2).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(2).getAvoidVolumeBreakAfterPriority());
// in block 2 between block 3 and 4: empty
assertEquals(2, (int)formatter.get(3).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(3).getAvoidVolumeBreakAfterPriority());
// in block 4: empty
assertEquals(2, (int)formatter.get(4).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(4).getAvoidVolumeBreakAfterPriority());
// in block 2 after block 4
assertEquals(2, (int)formatter.get(5).getAvoidVolumeBreakInsidePriority());
assertEquals(1, (int)formatter.get(5).getAvoidVolumeBreakAfterPriority());
// in block 1 after block 2
assertEquals(1, (int)formatter.get(6).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(6).getAvoidVolumeBreakAfterPriority());
}
Expand All @@ -152,31 +178,36 @@ public void testVolumeKeepProperties_03() {
public void testVolumeKeepProperties_04() {
//Setup
FormatterCoreImpl formatter = new FormatterCoreImpl(context);
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build());
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build());
formatter.startBlock(new BlockProperties.Builder().build());
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().build());
formatter.endBlock(); // this empty block will affect the volume keep priority
formatter.endBlock(); // this empty block will affect the volume keep priority
formatter.endBlock();
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(1).build()); // start block 1
formatter.startBlock(new BlockProperties.Builder().volumeKeepPriority(2).build()); // start block 2
formatter.startBlock(new BlockProperties.Builder().build()); // start block 3
formatter.endBlock(); // end block 3
formatter.startBlock(new BlockProperties.Builder().build()); // start block 4
formatter.endBlock(); // end block 4
formatter.endBlock(); // end block 2
formatter.endBlock(); // end block 1

//Test
assertEquals(7, formatter.size());
// in block 1 before block 2: empty
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakInsidePriority());
assertEquals(1, (int)formatter.get(0).getAvoidVolumeBreakAfterPriority());
assertEquals(null, formatter.get(0).getAvoidVolumeBreakAfterPriority());
// in block 2 before block 3: empty
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(1).getAvoidVolumeBreakAfterPriority());
assertEquals(null, formatter.get(1).getAvoidVolumeBreakAfterPriority());
// in block 3: empty
assertEquals(2, (int)formatter.get(2).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(2).getAvoidVolumeBreakAfterPriority());
assertEquals(null, formatter.get(2).getAvoidVolumeBreakAfterPriority());
// in block 2 between block 3 and 4: empty
assertEquals(2, (int)formatter.get(3).getAvoidVolumeBreakInsidePriority());
assertEquals(2, (int)formatter.get(3).getAvoidVolumeBreakAfterPriority());
assertEquals(null, formatter.get(3).getAvoidVolumeBreakAfterPriority());
// in block 4: empty
assertEquals(2, (int)formatter.get(4).getAvoidVolumeBreakInsidePriority());
// this block gets its value from the following blocks break after priority, since it is empty
assertEquals(1, (int)formatter.get(4).getAvoidVolumeBreakAfterPriority());
assertEquals(null, formatter.get(4).getAvoidVolumeBreakAfterPriority());
// in block 2 after block 4: empty
assertEquals(2, (int)formatter.get(5).getAvoidVolumeBreakInsidePriority());
// this block gets its value from the following blocks break after priority, since it is empty
assertEquals(null, formatter.get(5).getAvoidVolumeBreakAfterPriority());
// in block 1 after block 2: empty
assertEquals(1, (int)formatter.get(6).getAvoidVolumeBreakInsidePriority());
assertEquals(null, formatter.get(6).getAvoidVolumeBreakAfterPriority());
}
Expand Down

0 comments on commit ba216aa

Please sign in to comment.