From 4d7e55d0304f35f839449d088639833b664b6f06 Mon Sep 17 00:00:00 2001 From: Emmeran Seehuber Date: Wed, 13 Jul 2016 17:50:38 +0200 Subject: [PATCH] Add visibility:-fs-table-paginate-repeated-visible for paginated tables. This allows to render some elements on the continuation of a repeated table header on a new page. E.g. a span containing the word "continued". For this to work the table must have -fs-table-paginate: paginate; set. Using visibility the element is always correctly layouted, but only painted after the table is broken into a new page. --- .../css/constants/IdentValue.java | 1 + .../property/PrimitivePropertyBuilders.java | 5 ++- .../css/style/CalculatedStyle.java | 41 ++++++++++++++++++- .../com/openhtmltopdf/newtable/TableBox.java | 11 ++++- .../openhtmltopdf/newtable/TableCellBox.java | 4 +- .../render/AbstractOutputDevice.java | 4 +- .../com/openhtmltopdf/render/BlockBox.java | 4 +- .../java/com/openhtmltopdf/render/Box.java | 2 +- .../openhtmltopdf/render/InlineLayoutBox.java | 4 +- .../com/openhtmltopdf/render/LineBox.java | 2 +- 10 files changed, 62 insertions(+), 16 deletions(-) diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/IdentValue.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/IdentValue.java index 8ae6a0cab..71b638f13 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/IdentValue.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/IdentValue.java @@ -103,6 +103,7 @@ public class IdentValue implements FSDerivedValue { public final static IdentValue FONT_WEIGHT_900 = addValue("900"); public final static IdentValue FS_CONTENT_PLACEHOLDER = addValue("-fs-content-placeholder"); public final static IdentValue FS_INITIAL_VALUE = addValue("-fs-initial-value"); + public final static IdentValue FS_TABLE_PAGINATE_REPEATED_VISIBLE = addValue("-fs-table-paginate-repeated-visible"); public final static IdentValue GEORGIAN = addValue("georgian"); public final static IdentValue GROOVE = addValue("groove"); public final static IdentValue HEBREW = addValue("hebrew"); diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java index 9f4592f99..a9b71374a 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java @@ -1515,10 +1515,11 @@ protected BitSet getAllowed() { } public static class Visibility extends SingleIdent { - // visible | hidden | collapse | inherit + // visible | hidden | collapse | inherit | -fs-table-paginate-repeated-visible private static final BitSet ALLOWED = setFor( new IdentValue[] { - IdentValue.VISIBLE, IdentValue.HIDDEN, IdentValue.COLLAPSE }); + IdentValue.VISIBLE, IdentValue.HIDDEN, IdentValue.COLLAPSE, + IdentValue.FS_TABLE_PAGINATE_REPEATED_VISIBLE }); protected BitSet getAllowed() { return ALLOWED; diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/CalculatedStyle.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/CalculatedStyle.java index 08a3930ce..33b3a58bb 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/CalculatedStyle.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/CalculatedStyle.java @@ -43,8 +43,11 @@ import com.openhtmltopdf.css.style.derived.NumberValue; import com.openhtmltopdf.css.style.derived.RectPropertySet; import com.openhtmltopdf.css.value.FontSpecification; +import com.openhtmltopdf.newtable.TableBox; +import com.openhtmltopdf.render.Box; import com.openhtmltopdf.render.FSFont; import com.openhtmltopdf.render.FSFontMetrics; +import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.util.XRLog; import com.openhtmltopdf.util.XRRuntimeException; @@ -1026,8 +1029,42 @@ public boolean isListItem() { return isIdent(CSSName.DISPLAY, IdentValue.LIST_ITEM); } - public boolean isVisible() { - return isIdent(CSSName.VISIBILITY, IdentValue.VISIBLE); + /** + * Determine if the element is visible. This is normaly the case + * if visibility == visible. Only when visibilty is + * -fs-table-paginate-repeated-visible and we are in a repeated table header + * the element will also be visible. This allows to only show an element in the table header + * after a page break. + * @param renderingContext null or the current renderingContext. If null, + * then the -fs-table-paginate-repeated-visible logic + * will not work. + * @param thisElement the element for which the visibility should be determined. Only required if + * -fs-table-paginate-repeated-visible is specified. + * @return true if the element is visible + */ + public boolean isVisible(RenderingContext renderingContext, Box thisElement) { + IdentValue val = getIdent(CSSName.VISIBILITY); + if (val == IdentValue.VISIBLE) + return true; + if (renderingContext != null) { + if (val == IdentValue.FS_TABLE_PAGINATE_REPEATED_VISIBLE) { + /* + * We need to find the parent TableBox which has a + * ContentLimitContainer and can be repeated. + */ + Box parentElement = thisElement.getParent(); + while (parentElement != null + && !(parentElement.getStyle().isTable() + && ((TableBox) parentElement).hasContentLimitContainer())) + parentElement = parentElement.getDocumentParent(); + + if (parentElement != null) { + TableBox tableBox = (TableBox) parentElement; + return !tableBox.isTableRenderedOnFirstPage(renderingContext); + } + } + } + return false; } public boolean isForcePageBreakBefore() { diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableBox.java index 9f8aa309c..aece4c0ed 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableBox.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableBox.java @@ -398,7 +398,7 @@ public void analyzePageBreaks(LayoutContext c, ContentLimitContainer container) public void paintBackground(RenderingContext c) { if (_contentLimitContainer == null) { super.paintBackground(c); - } else if (getStyle().isVisible()) { + } else if (getStyle().isVisible(c, this)) { c.getOutputDevice().paintBackground( c, getStyle(), getContentLimitedBorderEdge(c), getPaintingBorderEdge(c), getStyle().getBorder(c)); @@ -408,7 +408,7 @@ c, getStyle(), getContentLimitedBorderEdge(c), getPaintingBorderEdge(c), public void paintBorder(RenderingContext c) { if (_contentLimitContainer == null) { super.paintBorder(c); - } else if (getStyle().isVisible()) { + } else if (getStyle().isVisible(c, this)) { c.getOutputDevice().paintBorder(c, getStyle(), getContentLimitedBorderEdge(c), getBorderSides()); } } @@ -866,6 +866,13 @@ public boolean hasContentLimitContainer() { return _contentLimitContainer != null; } + /** + * @return true if the table is rendered on its first page. false if the table is rendered after a page break + */ + public boolean isTableRenderedOnFirstPage(RenderingContext context){ + return hasContentLimitContainer() && _contentLimitContainer.getInitialPageNo() == context.getPageNo(); + } + public int getExtraSpaceTop() { return _extraSpaceTop; } diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableCellBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableCellBox.java index 56238814d..f6fa42878 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableCellBox.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableCellBox.java @@ -260,7 +260,7 @@ private boolean isPaintBackgroundsAndBorders() { } public void paintBackground(RenderingContext c) { - if (isPaintBackgroundsAndBorders() && getStyle().isVisible()) { + if (isPaintBackgroundsAndBorders() && getStyle().isVisible(c, this)) { Rectangle bounds; if (c.isPrint() && getTable().getStyle().isPaginateTable()) { bounds = getContentLimitedBorderEdge(c); @@ -315,7 +315,7 @@ bounds, getTable().getColumnBounds(c, getCol()), public void paintBorder(RenderingContext c) { if (isPaintBackgroundsAndBorders() && ! hasCollapsedPaintingBorder()) { // Collapsed table borders are painted separately - if (c.isPrint() && getTable().getStyle().isPaginateTable() && getStyle().isVisible()) { + if (c.isPrint() && getTable().getStyle().isPaginateTable() && getStyle().isVisible(c, this)) { Rectangle bounds = getContentLimitedBorderEdge(c); if (bounds != null) { c.getOutputDevice().paintBorder(c, getStyle(), bounds, getBorderSides()); diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/AbstractOutputDevice.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/AbstractOutputDevice.java index 07ed7591f..485c955d8 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/AbstractOutputDevice.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/AbstractOutputDevice.java @@ -167,7 +167,7 @@ public void paintCollapsedBorder( } public void paintBorder(RenderingContext c, Box box) { - if (! box.getStyle().isVisible()) { + if (! box.getStyle().isVisible(c, box)) { return; } @@ -200,7 +200,7 @@ public void paintBackground( } public void paintBackground(RenderingContext c, Box box) { - if (! box.getStyle().isVisible()) { + if (! box.getStyle().isVisible(c, box)) { return; } diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java index 76f1940f7..5f3dccb31 100755 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java @@ -256,7 +256,7 @@ public String dump(LayoutContext c, String indent, int which) { } public void paintListMarker(RenderingContext c) { - if (! getStyle().isVisible()) { + if (! getStyle().isVisible(c, this)) { return; } @@ -281,7 +281,7 @@ public Rectangle getPaintingClipEdge(CssContext cssCtx) { } public void paintInline(RenderingContext c) { - if (! getStyle().isVisible()) { + if (! getStyle().isVisible(c, this)) { return; } diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/Box.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/Box.java index 6807eb5e2..649784392 100755 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/Box.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/Box.java @@ -691,7 +691,7 @@ public Box find(CssContext cssCtx, int absX, int absY, boolean findAnonymous) { } Rectangle edge = getContentAreaEdge(getAbsX(), getAbsY(), cssCtx); - return edge.contains(absX, absY) && getStyle().isVisible() ? this : null; + return edge.contains(absX, absY) && getStyle().isVisible(null, this) ? this : null; } public boolean isRoot() { diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/InlineLayoutBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/InlineLayoutBox.java index c1e316dbf..b9403e31d 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/InlineLayoutBox.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/InlineLayoutBox.java @@ -251,7 +251,7 @@ public void paintSelection(RenderingContext c) { } public void paintInline(RenderingContext c) { - if (! getStyle().isVisible()) { + if (! getStyle().isVisible(c, this)) { return; } @@ -785,7 +785,7 @@ public Box find(CssContext cssCtx, int absX, int absY, boolean findAnonymous) { } Rectangle edge = getContentAreaEdge(getAbsX(), getAbsY(), cssCtx); - result = edge.contains(absX, absY) && getStyle().isVisible() ? this : null; + result = edge.contains(absX, absY) && getStyle().isVisible(null, this) ? this : null; if (! findAnonymous && result != null && getElement() == null) { return getParent().getParent(); diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/LineBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/LineBox.java index 485d68fb9..867fc62c9 100755 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/LineBox.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/LineBox.java @@ -109,7 +109,7 @@ public Rectangle getMarginEdge(CssContext cssCtx, int tx, int ty) { } public void paintInline(RenderingContext c) { - if (! getParent().getStyle().isVisible()) { + if (! getParent().getStyle().isVisible(c, this)) { return; }