Skip to content

Commit 18520bf

Browse files
rototordanfickle
authored andcommitted
Implement -fs-page-break-min-height (#31)
* Implement -fs-pagebreak-min-height. This CSS property allows to force a page break before an element if not the specified space is left on the current page. CSS orphans and page-break-inside:avoid are nice, but dont work always, especially with complex tables. This CSS property allows to workaround many page break problems. Also adds a sample document which demonstrates the effect of this property. Also the TestcaseRunner now prints onto the System.out were the output PDF was written. * Small typo fix.
1 parent a3ae526 commit 18520bf

File tree

8 files changed

+2336
-7
lines changed

8 files changed

+2336
-7
lines changed

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ public final class CSSName implements Comparable {
272272
NOT_INHERITED,
273273
new PrimitivePropertyBuilders.FSCheckboxStyle()
274274
);
275-
275+
276276
/**
277277
* Unique CSSName instance for CSS2 property.
278278
*/
@@ -405,6 +405,19 @@ public final class CSSName implements Comparable {
405405
new PrimitivePropertyBuilders.FSNamedDestination()
406406
);
407407

408+
/**
409+
* Perform a page break before this element, if not at least the specified space is
410+
* left on the current page.
411+
*/
412+
public final static CSSName FS_PAGE_BREAK_MIN_HEIGHT =
413+
addProperty(
414+
"-fs-page-break-min-height",
415+
PRIMITIVE,
416+
"0",
417+
INHERITS,
418+
new PrimitivePropertyBuilders.FSPageBreakMinHeight()
419+
);
420+
408421
/**
409422
* Unique CSSName instance for CSS2 property.
410423
*/
@@ -1316,7 +1329,7 @@ public final class CSSName implements Comparable {
13161329
true,
13171330
new PrimitivePropertyBuilders.BorderBottomLeftRadius()
13181331
);
1319-
1332+
13201333
/**
13211334
* Unique CSSName instance for CSS2 property.
13221335
*/
@@ -1418,7 +1431,7 @@ public final class CSSName implements Comparable {
14181431
NOT_INHERITED,
14191432
new BackgroundPropertyBuilder()
14201433
);
1421-
1434+
14221435

14231436
/**
14241437
* Unique CSSName instance for CSS3 property.

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,9 @@ public static class MinHeight extends NonNegativeLengthLike {
12561256
public static class MinWidth extends NonNegativeLengthLike {
12571257
}
12581258

1259+
public static class FSPageBreakMinHeight extends NonNegativeLengthLike {
1260+
}
1261+
12591262
public static class Orphans extends PlainInteger {
12601263
protected boolean isNegativeValuesAllowed() {
12611264
return false;

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/CalculatedStyle.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,10 @@ public int getColSpan() {
11291129
return result > 0 ? result : 1;
11301130
}
11311131

1132+
public float getFSPageBreakMinHeight(CssContext c){
1133+
return getFloatPropertyProportionalTo(CSSName.FS_PAGE_BREAK_MIN_HEIGHT, 0, c);
1134+
}
1135+
11321136
public Length asLength(CssContext c, CSSName cssName) {
11331137
Length result = new Length();
11341138

openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/BlockBoxing.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ private static void repositionBox(LayoutContext c, BlockBox child, int trimmedPa
331331
}
332332
if (c.isPrint()) {
333333
boolean pageClear = child.isNeedPageClear() ||
334-
child.getStyle().isForcePageBreakBefore();
334+
child.getStyle().isForcePageBreakBefore() ||
335+
child.isPageBreakNeededBecauseOfMinHeight(c);
335336
boolean needNewPageContext = child.checkPageContext(c);
336337

337338
if (needNewPageContext && trimmedPageCount != NO_PAGE_TRIM) {

openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/LayoutUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public static FloatLayoutResult layoutFloated(
105105
private static void positionFloatOnPage(
106106
final LayoutContext c, LineBox currentLine, BlockBox block,
107107
boolean movedVertically) {
108-
if (block.getStyle().isForcePageBreakBefore()) {
108+
if (block.getStyle().isForcePageBreakBefore() || block.isPageBreakNeededBecauseOfMinHeight(c)) {
109109
block.forcePageBreakBefore(c, block.getStyle().getIdent(CSSName.PAGE_BREAK_BEFORE), false);
110110
block.calcCanvasLocation();
111111
resetAndFloatBlock(c, currentLine, block);

openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,9 +550,27 @@ public void positionAbsolute(CssContext cssCtx, int direction) {
550550
calcChildLocations();
551551
}
552552

553+
/**
554+
* Using the css:
555+
*
556+
* -fs-page-break-min-height: 5cm;
557+
*
558+
* on a block element you can force a pagebreak before this block, if not
559+
* enough space (e.g. 5cm in this case) is remaining on the current page for the block.
560+
*
561+
* @return true if a pagebreak is needed before this block because
562+
* there is not enough space left on the current page.
563+
*/
564+
public boolean isPageBreakNeededBecauseOfMinHeight(LayoutContext context){
565+
float minHeight = getStyle().getFSPageBreakMinHeight(context);
566+
PageBox page = context.getRootLayer().getFirstPage(context, this);
567+
return page != null && getAbsY() + minHeight > page.getBottom();
568+
}
569+
570+
553571
public void positionAbsoluteOnPage(LayoutContext c) {
554572
if (c.isPrint() &&
555-
(getStyle().isForcePageBreakBefore() || isNeedPageClear())) {
573+
(getStyle().isForcePageBreakBefore() || isNeedPageClear() || isPageBreakNeededBecauseOfMinHeight(c))) {
556574
forcePageBreakBefore(c, getStyle().getIdent(CSSName.PAGE_BREAK_BEFORE), false);
557575
calcCanvasLocation();
558576
calcChildLocations();

openhtmltopdf-examples/src/main/java/com/openhtmltopdf/testcases/TestcaseRunner.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public static void main(String[] args) throws Exception {
2929
*/
3030
runTestCase("RepeatedTableSample");
3131

32+
/*
33+
* This sample demonstrates the -fs-pagebreak-min-height css property
34+
*/
35+
runTestCase("FSPageBreakMinHeightSample");
36+
3237
/* Add additional test cases here. */
3338
}
3439

@@ -37,7 +42,8 @@ public static void runTestCase(String testCaseFile) throws Exception {
3742
.getResourceAsStream("/testcases/" + testCaseFile + ".html"));
3843
String html = new String(htmlBytes, Charsets.UTF_8);
3944
String outDir = System.getProperty("OUT_DIRECTORY", ".");
40-
FileOutputStream outputStream = new FileOutputStream(outDir + "/" + testCaseFile + ".pdf");
45+
String testCaseOutputFile = outDir + "/" + testCaseFile + ".pdf";
46+
FileOutputStream outputStream = new FileOutputStream(testCaseOutputFile);
4147

4248
try {
4349
PdfRendererBuilder builder = new PdfRendererBuilder();
@@ -50,5 +56,6 @@ public static void runTestCase(String testCaseFile) throws Exception {
5056
} finally {
5157
outputStream.close();
5258
}
59+
System.out.println("Wrote " + testCaseOutputFile);
5360
}
5461
}

0 commit comments

Comments
 (0)