Skip to content

Commit 0e54494

Browse files
Suppport overflow property for page margin boxes, add new tests
DEVSIX-1563
1 parent a7f7dda commit 0e54494

34 files changed

+395
-71
lines changed

src/main/java/com/itextpdf/html2pdf/LogMessageConstant.java

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public final class LogMessageConstant {
5353
/** The Constant CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED. */
5454
public static final String CSS_PROPERTY_IN_PERCENTS_NOT_SUPPORTED = "Css property {0} in percents is not supported";
5555

56-
public static final String DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN = "Default value of the css property \"{0}\" is unknown.";
56+
public static final String DEFAULT_VALUE_OF_CSS_PROPERTY_UNKNOWN = "Default value of the css property \"{0}\" is unknown.";
5757

5858
/** The Constant ERROR_LOADING_FONT. */
5959
public static final String ERROR_LOADING_FONT = "Error while loading font";
@@ -69,16 +69,12 @@ public final class LogMessageConstant {
6969

7070
/** The Constant ERROR_WHILE_LAYOUT_OF_FORM_FIELD_WITH_TYPE. */
7171
public static final String ERROR_WHILE_LAYOUT_OF_FORM_FIELD_WITH_TYPE = "Error during layout of form filed with type {0}.";
72-
72+
/** The Constant HEIGHT_VALUE_IN_PERCENT_NOT_SUPPORTED. */
73+
public static final String HEIGHT_VALUE_IN_PERCENT_NOT_SUPPORTED = "Height value in percent not supported";
7374
/** The Constant INPUT_FIELD_DOES_NOT_FIT. */
7475
public static final String INPUT_FIELD_DOES_NOT_FIT = "Input field doesn't fit in outer object. It will be clipped";
75-
7676
/** The Constant INPUT_SUPPORTS_ONLY_POINT_WIDTH. */
7777
public static final String INPUT_SUPPORTS_ONLY_POINT_WIDTH = "Input field supports only point width";
78-
79-
/** The Constant HEIGHT_VALUE_IN_PERCENT_NOT_SUPPORTED. */
80-
public static final String HEIGHT_VALUE_IN_PERCENT_NOT_SUPPORTED = "Height value in percent not supported";
81-
8278
/** The Constant INPUT_TYPE_IS_NOT_SUPPORTED. */
8379
public static final String INPUT_TYPE_IS_NOT_SUPPORTED = "Input type {0} is not supported";
8480

@@ -90,79 +86,55 @@ public final class LogMessageConstant {
9086

9187
/** The Constant NOT_SUPPORTED_LIST_STYLE_TYPE. */
9288
public static final String NOT_SUPPORTED_LIST_STYLE_TYPE = "Not supported list style type: {0}";
93-
94-
/** The Constant NO_IPROPERTYCONTAINER_RESULT_FOR_THE_TAG. */
95-
public static final String NO_IPROPERTYCONTAINER_RESULT_FOR_THE_TAG = "Tag worker does not produce IPropertyContainer for \"{0}\" tag. An outline for \"{0}\" tag will not be created.";
96-
9789
/** The Constant NO_CONSUMER_FOUND_FOR_CONTENT. */
9890
public static final String NO_CONSUMER_FOUND_FOR_CONTENT = "No consumer found for content";
99-
10091
/** The Constant NO_CSS_APPLIER_FOUND_FOR_TAG. */
10192
public static final String NO_CSS_APPLIER_FOUND_FOR_TAG = "No css applier found for tag {0}";
102-
93+
/** The Constant NO_IPROPERTYCONTAINER_RESULT_FOR_THE_TAG. */
94+
public static final String NO_IPROPERTYCONTAINER_RESULT_FOR_THE_TAG = "Tag worker does not produce IPropertyContainer for \"{0}\" tag. An outline for \"{0}\" tag will not be created.";
10395
/** The Constant NO_WORKER_FOUND_FOR_TAG. */
10496
public static final String NO_WORKER_FOUND_FOR_TAG = "No worker found for tag {0}";
10597

10698
/** The Constant PADDING_VALUE_IN_PERCENT_NOT_SUPPORTED. */
10799
public static final String PADDING_VALUE_IN_PERCENT_NOT_SUPPORTED = "Padding value in percents not supported";
108-
100+
public static final String PAGE_MARGIN_BOX_CONTENT_CANNOT_BE_DRAWN = "Page margin box {0} content cannot be drawn.";
109101
/** The Constant PAGE_SIZE_VALUE_IS_INVALID. */
110102
public static final String PAGE_SIZE_VALUE_IS_INVALID = "Page size value {0} is invalid.";
111-
112-
/** The Constant QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION. */
113-
public static final String QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "The quote is not closed in css expression: {0}";
114-
115103
/** The Constant QUOTES_PROPERTY_INVALID. */
116104
public static final String QUOTES_PROPERTY_INVALID = "Quote property \"{0}\" is invalid. It should contain even number of <string> values.";
117-
105+
/** The Constant QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION. */
106+
public static final String QUOTE_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "The quote is not closed in css expression: {0}";
118107
/** The Constant RULE_IS_NOT_SUPPORTED. */
119108
public static final String RULE_IS_NOT_SUPPORTED = "The rule @{0} is unsupported. All selectors in this rule will be ignored.";
120-
121109
/** The Constant TEXT_DECORATION_BLINK_NOT_SUPPORTED. */
122110
public static final String TEXT_DECORATION_BLINK_NOT_SUPPORTED = "text-decoration: blink not supported";
123-
124111
/** The Constant TEXT_WAS_NOT_PROCESSED. */
125112
public static final String TEXT_WAS_NOT_PROCESSED = "Text was not processed: {0}";
126-
127113
/** The Constant UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE. */
128114
public static final String UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE = "Unable to process external css file";
129-
130115
/** The Constant UNABLE_TO_RESOLVE_COUNTER. */
131116
public static final String UNABLE_TO_RESOLVE_COUNTER = "Unable to resolve counter \"{0}\"";
132-
133117
/** The Constant UNABLE_TO_RESOLVE_FONT. */
134118
public static final String UNABLE_TO_RESOLVE_FONT = "Unable to resolve font: {0}. The default one will be used instead";
135-
119+
/** The Constant UNABLE_TO_RETRIEVE_FONT. */
120+
public static final String UNABLE_TO_RETRIEVE_FONT = "Unable to retrieve font:\n {0}";
136121
/** The Constant UNABLE_TO_RETRIEVE_IMAGE_FROM_BASE64_SOURCE. */
137122
public static final String UNABLE_TO_RETRIEVE_IMAGE_FROM_BASE64_SOURCE = "Unable to retrieve image from given base64 source string";
138-
139123
/** The Constant UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI. */
140124
public static final String UNABLE_TO_RETRIEVE_IMAGE_WITH_GIVEN_BASE_URI = "Unable to retrieve image with given base URI ({0}) and image source path ({1})";
141-
142-
/** The Constant UNABLE_TO_RETRIEVE_FONT. */
143-
public static final String UNABLE_TO_RETRIEVE_FONT = "Unable to retrieve font:\n {0}";
144-
145125
/** The Constant UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI. */
146126
public static final String UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI = "Unable to retrieve stream with given base URI ({0}) and source path ({1})";
147-
148127
/** The Constant UNKNOWN_ABSOLUTE_METRIC_LENGTH_PARSED. */
149128
public static final String UNKNOWN_ABSOLUTE_METRIC_LENGTH_PARSED = "Unknown absolute metric length parsed \"{0}\".";
150-
151129
/** The Constant UNKNOWN_MARGIN_BOX_CHILD. */
152130
public static final String UNKNOWN_MARGIN_BOX_CHILD = "Unknown margin box child";
153-
154131
public static final String UNSUPPORTED_PSEUDO_CSS_SELECTOR = "Unsupported pseudo css selector: {0}";
155-
156-
public static final String URL_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "url function is not properly closed in expression:{0}";
157-
158132
public static final String URL_IS_EMPTY_IN_CSS_EXPRESSION = "url function is empty in expression:{0}";
159-
133+
public static final String URL_IS_NOT_CLOSED_IN_CSS_EXPRESSION = "url function is not properly closed in expression:{0}";
160134
/** The Constant WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES. */
161135
public static final String WAS_NOT_ABLE_TO_DEFINE_BACKGROUND_CSS_SHORTHAND_PROPERTIES = "Was not able to define one of the background CSS shorthand properties: {0}";
162-
163136
/** The Constant WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT. */
164137
public static final String WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT = "Worker of type {0} unable to process it's text content";
165-
166138
/** The Constant WORKER_UNABLE_TO_PROCESS_OTHER_WORKER. */
167139
public static final String WORKER_UNABLE_TO_PROCESS_OTHER_WORKER = "Worker of type {0} unable to process {1}";
168140

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/PageContextProcessor.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ This file is part of the iText (R) project.
5151
import com.itextpdf.html2pdf.css.apply.util.BackgroundApplierUtil;
5252
import com.itextpdf.html2pdf.css.apply.util.BorderStyleApplierUtil;
5353
import com.itextpdf.html2pdf.css.apply.util.FontStyleApplierUtil;
54+
import com.itextpdf.html2pdf.css.apply.util.OutlineApplierUtil;
5455
import com.itextpdf.html2pdf.css.apply.util.VerticalAlignmentApplierUtil;
5556
import com.itextpdf.html2pdf.css.page.PageMarginBoxContextNode;
5657
import com.itextpdf.html2pdf.css.util.CssUtils;
@@ -59,6 +60,7 @@ This file is part of the iText (R) project.
5960
import com.itextpdf.html2pdf.html.node.IElementNode;
6061
import com.itextpdf.html2pdf.html.node.INode;
6162
import com.itextpdf.html2pdf.html.node.ITextNode;
63+
import com.itextpdf.io.util.MessageFormatUtil;
6264
import com.itextpdf.kernel.geom.PageSize;
6365
import com.itextpdf.kernel.geom.Rectangle;
6466
import com.itextpdf.kernel.pdf.PdfPage;
@@ -75,13 +77,15 @@ This file is part of the iText (R) project.
7577
import com.itextpdf.layout.layout.LayoutArea;
7678
import com.itextpdf.layout.layout.LayoutContext;
7779
import com.itextpdf.layout.layout.LayoutResult;
80+
import com.itextpdf.layout.property.OverflowPropertyValue;
7881
import com.itextpdf.layout.property.Property;
7982
import com.itextpdf.layout.property.UnitValue;
8083
import com.itextpdf.layout.renderer.DocumentRenderer;
8184
import com.itextpdf.layout.renderer.DrawContext;
8285
import com.itextpdf.layout.renderer.IRenderer;
8386
import com.itextpdf.html2pdf.jsoup.nodes.Element;
8487
import com.itextpdf.html2pdf.jsoup.parser.Tag;
88+
import org.slf4j.Logger;
8589
import org.slf4j.LoggerFactory;
8690

8791
import java.util.Arrays;
@@ -366,7 +370,14 @@ private void drawMarginBoxes(PdfPage page, DocumentRenderer documentRenderer) {
366370
renderer.setParent(documentRenderer);
367371
LayoutResult result = renderer.layout(new LayoutContext(new LayoutArea(page.getDocument().getPageNumber(page), marginBoxRectangles[i])));
368372
IRenderer rendererToDraw = result.getStatus() == LayoutResult.FULL ? renderer : result.getSplitRenderer();
369-
rendererToDraw.setParent(documentRenderer).draw(new DrawContext(page.getDocument(), new PdfCanvas(page)));
373+
if (rendererToDraw != null) {
374+
rendererToDraw.setParent(documentRenderer).draw(new DrawContext(page.getDocument(), new PdfCanvas(page)));
375+
} else {
376+
// marginBoxElements have overflow property set to HIDDEN, therefore it is not expected to neither get
377+
// LayoutResult other than FULL nor get no split renderer (result NOTHING) even if result is not FULL
378+
Logger logger = LoggerFactory.getLogger(PageContextProcessor.class);
379+
logger.error(MessageFormatUtil.format(LogMessageConstant.PAGE_MARGIN_BOX_CONTENT_CANNOT_BE_DRAWN, PageContextProperties.pageMarginBoxNames.get(i)));
380+
}
370381
}
371382
}
372383
}
@@ -470,6 +481,24 @@ private void createMarginBoxesElements(List<PageMarginBoxContextNode> resolvedPa
470481
BorderStyleApplierUtil.applyBorders(boxStyles, context, marginBox);
471482
VerticalAlignmentApplierUtil.applyVerticalAlignmentForCells(boxStyles, context, marginBox);
472483

484+
// Set overflow to HIDDEN if it's not explicitly set in css in order to avoid overlapping with page content.
485+
String overflow = CssConstants.OVERFLOW_VALUES.contains(boxStyles.get(CssConstants.OVERFLOW)) ? boxStyles.get(CssConstants.OVERFLOW) : null;
486+
String overflowX = CssConstants.OVERFLOW_VALUES.contains(boxStyles.get(CssConstants.OVERFLOW_X)) ? boxStyles.get(CssConstants.OVERFLOW_X) : overflow;
487+
if (overflowX == null || CssConstants.HIDDEN.equals(overflowX)) {
488+
marginBox.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.HIDDEN);
489+
} else {
490+
marginBox.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.VISIBLE);
491+
}
492+
String overflowY = CssConstants.OVERFLOW_VALUES.contains(boxStyles.get(CssConstants.OVERFLOW_Y)) ? boxStyles.get(CssConstants.OVERFLOW_Y) : overflow;
493+
if (overflowY == null || CssConstants.HIDDEN.equals(overflowY)) {
494+
marginBox.setProperty(Property.OVERFLOW_Y, OverflowPropertyValue.HIDDEN);
495+
} else {
496+
marginBox.setProperty(Property.OVERFLOW_Y, OverflowPropertyValue.VISIBLE);
497+
}
498+
499+
// TODO outlines are currently not supported for page margin boxes, because of the outlines handling specificity (they are handled on renderer's parent level)
500+
OutlineApplierUtil.applyOutlines(boxStyles, context, marginBox);
501+
473502
float em = CssUtils.parseAbsoluteLength(boxStyles.get(CssConstants.FONT_SIZE));
474503
float rem = context.getCssContext().getRootFontSize();
475504
float[] boxMargins = parseBoxProps(boxStyles, em, rem, 0, calculateContainingBlockSizesForMarginBox(marginBoxInd),
@@ -481,7 +510,14 @@ private void createMarginBoxesElements(List<PageMarginBoxContextNode> resolvedPa
481510
marginBox.setPaddings(boxPaddings[0], boxPaddings[1], boxPaddings[2], boxPaddings[3]);
482511
marginBox.setProperty(Property.FONT_PROVIDER, context.getFontProvider());
483512
marginBox.setProperty(Property.FONT_SET, context.getTempFonts());
484-
marginBox.setFillAvailableArea(true);
513+
514+
float[] boxBorders = getBordersWidth(marginBox);
515+
float marginBorderPaddingWidth = boxMargins[1] + boxMargins[3] + boxBorders[1] + boxBorders[3] + boxPaddings[1] + boxPaddings[3];
516+
float marginBorderPaddingHeight = boxMargins[0] + boxMargins[2] + boxBorders[0] + boxBorders[2] + boxPaddings[0] + boxPaddings[2];
517+
518+
// TODO DEVSIX-1050: improve width/height calculation according to "5.3. Computing Page-margin Box Dimensions", take into account height and width properties
519+
marginBox.setWidth(marginBoxRectangles[marginBoxInd].getWidth() - marginBorderPaddingWidth);
520+
marginBox.setHeight(marginBoxRectangles[marginBoxInd].getHeight() - marginBorderPaddingHeight);
485521

486522
if (marginBoxContentNode.childNodes().isEmpty()) {
487523
// margin box node shall not be added to resolvedPageMarginBoxes if it's kids were not resolved from content
@@ -683,4 +719,34 @@ private static Float parseBoxValue(String valString, float em, float rem, float
683719

684720
return null;
685721
}
722+
723+
private static float[] getBordersWidth(IPropertyContainer container) {
724+
Border border = container.<Border>getProperty(Property.BORDER);
725+
Border topBorder = container.<Border>getProperty(Property.BORDER_TOP);
726+
Border rightBorder = container.<Border>getProperty(Property.BORDER_RIGHT);
727+
Border bottomBorder = container.<Border>getProperty(Property.BORDER_BOTTOM);
728+
Border leftBorder = container.<Border>getProperty(Property.BORDER_LEFT);
729+
730+
Border[] borders = {topBorder, rightBorder, bottomBorder, leftBorder};
731+
732+
if (!container.hasProperty(Property.BORDER_TOP)) {
733+
borders[0] = border;
734+
}
735+
if (!container.hasProperty(Property.BORDER_RIGHT)) {
736+
borders[1] = border;
737+
}
738+
if (!container.hasProperty(Property.BORDER_BOTTOM)) {
739+
borders[2] = border;
740+
}
741+
if (!container.hasProperty(Property.BORDER_LEFT)) {
742+
borders[3] = border;
743+
}
744+
745+
return new float[] {
746+
borders[0] != null ? borders[0].getWidth() : 0,
747+
borders[1] != null ? borders[1].getWidth() : 0,
748+
borders[2] != null ? borders[2].getWidth() : 0,
749+
borders[3] != null ? borders[3].getWidth() : 0,
750+
};
751+
}
686752
}

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/PageContextProperties.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
This file is part of the iText (R) project.
33
Copyright (c) 1998-2017 iText Group NV
44
Authors: Bruno Lowagie, Paulo Soares, et al.
5-
5+
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU Affero General Public License version 3
88
as published by the Free Software Foundation with the addition of the
99
following permission added to Section 15 as permitted in Section 7(a):
1010
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
1111
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
1212
OF THIRD PARTY RIGHTS
13-
13+
1414
This program is distributed in the hope that it will be useful, but
1515
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1616
or FITNESS FOR A PARTICULAR PURPOSE.
@@ -20,23 +20,23 @@ This file is part of the iText (R) project.
2020
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2121
Boston, MA, 02110-1301 USA, or download the license from the following URL:
2222
http://itextpdf.com/terms-of-use/
23-
23+
2424
The interactive user interfaces in modified source and object code versions
2525
of this program must display Appropriate Legal Notices, as required under
2626
Section 5 of the GNU Affero General Public License.
27-
27+
2828
In accordance with Section 7(b) of the GNU Affero General Public License,
2929
a covered work must retain the producer line in every PDF that is created
3030
or manipulated using iText.
31-
31+
3232
You can be released from the requirements of the license by purchasing
3333
a commercial license. Buying such a license is mandatory as soon as you
3434
develop commercial activities involving the iText software without
3535
disclosing the source code of your own applications.
3636
These activities include: offering paid services to customers as an ASP,
3737
serving PDFs on the fly in a web application, shipping iText with a closed
3838
source product.
39-
39+
4040
For more information, please contact iText Software Corp. at this
4141
address: sales@itextpdf.com
4242
*/
@@ -62,7 +62,7 @@ class PageContextProperties {
6262
/**
6363
* List containing possible names for page margin boxes.
6464
*/
65-
private static final List<String> pageMarginBoxNames = Arrays.asList(
65+
static final List<String> pageMarginBoxNames = Arrays.asList(
6666
CssRuleName.TOP_LEFT_CORNER,
6767
CssRuleName.TOP_LEFT,
6868
CssRuleName.TOP_CENTER,

src/test/java/com/itextpdf/html2pdf/css/OverflowTest.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,31 @@ public static void beforeClass() {
6868

6969
@Test
7070
public void overflowTest04() throws IOException, InterruptedException {
71-
HtmlConverter.convertToPdf(new File(sourceFolder + "overflowTest04.html"), new File(destinationFolder + "overflowTest04.pdf"));
72-
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "overflowTest04.pdf", sourceFolder + "cmp_overflowTest04.pdf", destinationFolder, "diff04_"));
71+
runTest("overflowTest04", "diff04_");
7372
}
7473

7574
@Test
7675
public void overflowTest06() throws IOException, InterruptedException {
77-
HtmlConverter.convertToPdf(new File(sourceFolder + "overflowTest06.html"), new File(destinationFolder + "overflowTest06.pdf"));
78-
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "overflowTest06.pdf", sourceFolder + "cmp_overflowTest06.pdf", destinationFolder, "diff06_"));
76+
runTest("overflowTest06", "diff06_");
7977
}
8078

8179
@Test
8280
public void overflowTest07() throws IOException, InterruptedException {
83-
HtmlConverter.convertToPdf(new File(sourceFolder + "overflowTest07.html"), new File(destinationFolder + "overflowTest07.pdf"));
84-
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "overflowTest07.pdf", sourceFolder + "cmp_overflowTest07.pdf", destinationFolder, "diff07_"));
81+
runTest("overflowTest07", "diff07_");
8582
}
8683

8784
@Test
88-
public void overflowTest08() throws IOException, InterruptedException {
89-
HtmlConverter.convertToPdf(new File(sourceFolder + "overflowTest08.html"), new File(destinationFolder + "overflowTest08.pdf"));
90-
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "overflowTest08.pdf", sourceFolder + "cmp_overflowTest08.pdf", destinationFolder, "diff08_"));
85+
public void overflowAndAlignment01() throws IOException, InterruptedException {
86+
runTest("overflowAndAlignment01", "diffAlign01_");
87+
}
88+
89+
@Test
90+
public void overflowAndAlignment02() throws IOException, InterruptedException {
91+
runTest("overflowAndAlignment02", "diffAlign02_");
92+
}
93+
94+
public void runTest(String testName, String diff) throws IOException, InterruptedException {
95+
HtmlConverter.convertToPdf(new File(sourceFolder + testName + ".html"), new File(destinationFolder + testName + ".pdf"));
96+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + testName + ".pdf", sourceFolder + "cmp_" + testName + ".pdf", destinationFolder, diff));
9197
}
9298
}

0 commit comments

Comments
 (0)