Skip to content

Commit fb703bd

Browse files
committed
Fix wrong empty paragraphs rendering
Resolve DEVSIX-500
1 parent 3c0656f commit fb703bd

File tree

6 files changed

+105
-7
lines changed

6 files changed

+105
-7
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ public class LogMessageConstant {
6565
*/
6666
public static final String ONLY_ONE_OF_ARTBOX_OR_TRIMBOX_CAN_EXIST_IN_THE_PAGE = "Only one of artbox or trimbox can exist on the page. The trimbox will be deleted";
6767

68+
/**
69+
* Log message.
70+
*/
71+
public static final String RECTANGLE_HAS_NEGATIVE_OR_ZERO_SIZES = "The {0} rectangle has negative or zero sizes. It will not be displayed.";
72+
6873
/**
6974
* Log message.
7075
*/

layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.itextpdf.layout.renderer;
22

3+
import com.itextpdf.io.LogMessageConstant;
34
import com.itextpdf.kernel.color.Color;
45
import com.itextpdf.kernel.font.PdfFont;
56
import com.itextpdf.kernel.geom.Rectangle;
@@ -18,12 +19,16 @@
1819
import com.itextpdf.layout.layout.LayoutArea;
1920
import com.itextpdf.layout.layout.LayoutPosition;
2021

22+
import java.text.MessageFormat;
2123
import java.util.ArrayList;
2224
import java.util.Collections;
2325
import java.util.EnumMap;
2426
import java.util.List;
2527
import java.util.Map;
2628

29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
2732
/**
2833
* Defines the most common properties and behavior that are shared by most
2934
* {@link IRenderer} implementations. All default Renderers are subclasses of
@@ -52,7 +57,7 @@ public AbstractRenderer() {
5257

5358
/**
5459
* Creates a renderer for the specified layout element.
55-
*
60+
*
5661
* @param modelElement the layout element that will be drawn by this renderer
5762
*/
5863
public AbstractRenderer(IPropertyContainer modelElement) {
@@ -247,7 +252,7 @@ public void draw(DrawContext drawContext) {
247252
/**
248253
* Draws a background layer if it is defined by a key {@link Property#BACKGROUND}
249254
* in either the layout element or this {@link IRenderer} itself.
250-
*
255+
*
251256
* @param drawContext the context (canvas, document, etc) of this drawing operation.
252257
*/
253258
public void drawBackground(DrawContext drawContext) {
@@ -261,6 +266,11 @@ public void drawBackground(DrawContext drawContext) {
261266
drawContext.getCanvas().openTag(new CanvasArtifact());
262267
}
263268
Rectangle backgroundArea = applyMargins(bBox, false);
269+
if (backgroundArea.getWidth() <= 0 || backgroundArea.getHeight() <= 0) {
270+
Logger logger = LoggerFactory.getLogger(AbstractRenderer.class);
271+
logger.error(MessageFormat.format(LogMessageConstant.RECTANGLE_HAS_NEGATIVE_OR_ZERO_SIZES, "background"));
272+
return;
273+
}
264274
drawContext.getCanvas().saveState().setFillColor(background.getColor()).
265275
rectangle(backgroundArea.getX() - background.getExtraLeft(), backgroundArea.getY() - background.getExtraBottom(),
266276
backgroundArea.getWidth() + background.getExtraLeft() + background.getExtraRight(),
@@ -276,7 +286,7 @@ public void drawBackground(DrawContext drawContext) {
276286
/**
277287
* Performs the drawing operation for all {@link IRenderer children}
278288
* of this renderer.
279-
*
289+
*
280290
* @param drawContext the context (canvas, document, etc) of this drawing operation.
281291
*/
282292
public void drawChildren(DrawContext drawContext) {
@@ -289,7 +299,7 @@ public void drawChildren(DrawContext drawContext) {
289299
* Performs the drawing operation for the border of this renderer, if
290300
* defined by any of the {@link Property#BORDER} values in either the layout
291301
* element or this {@link IRenderer} itself.
292-
*
302+
*
293303
* @param drawContext the context (canvas, document, etc) of this drawing operation.
294304
*/
295305
public void drawBorder(DrawContext drawContext) {
@@ -306,6 +316,11 @@ public void drawBorder(DrawContext drawContext) {
306316
float leftWidth = borders[3] != null ? borders[3].getWidth() : 0;
307317

308318
Rectangle bBox = getBorderAreaBBox();
319+
if (bBox.getWidth() <= 0 || bBox.getHeight() <= 0) {
320+
Logger logger = LoggerFactory.getLogger(AbstractRenderer.class);
321+
logger.error(MessageFormat.format(LogMessageConstant.RECTANGLE_HAS_NEGATIVE_OR_ZERO_SIZES, "border"));
322+
return;
323+
}
309324
float x1 = bBox.getX();
310325
float y1 = bBox.getY();
311326
float x2 = bBox.getX() + bBox.getWidth();

layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.itextpdf.kernel.geom.Rectangle;
44
import com.itextpdf.layout.Property;
5+
import com.itextpdf.layout.border.Border;
56
import com.itextpdf.layout.element.Paragraph;
67
import com.itextpdf.layout.layout.LayoutArea;
78
import com.itextpdf.layout.layout.LayoutContext;
@@ -65,6 +66,20 @@ public LayoutResult layout(LayoutContext layoutContext) {
6566
currentRenderer.addChild(child);
6667
}
6768

69+
if (0 == childRenderers.size()) {
70+
anythingPlaced = true;
71+
currentRenderer = null;
72+
setProperty(Property.MARGIN_TOP, 0);
73+
setProperty(Property.MARGIN_RIGHT, 0);
74+
setProperty(Property.MARGIN_BOTTOM, 0);
75+
setProperty(Property.MARGIN_LEFT, 0);
76+
setProperty(Property.PADDING_TOP, 0);
77+
setProperty(Property.PADDING_RIGHT, 0);
78+
setProperty(Property.PADDING_BOTTOM, 0);
79+
setProperty(Property.PADDING_LEFT, 0);
80+
setProperty(Property.BORDER, Border.NO_BORDER);
81+
}
82+
6883
float lastYLine = layoutBox.getY() + layoutBox.getHeight();
6984
Property.Leading leading = getProperty(Property.LEADING);
7085
float leadingValue = 0;

layout/src/test/java/com/itextpdf/layout/DefaultLayoutTest.java

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
package com.itextpdf.layout;
22

3-
import com.itextpdf.kernel.geom.PageSize;
3+
import com.itextpdf.io.LogMessageConstant;
44
import com.itextpdf.kernel.color.Color;
5+
import com.itextpdf.kernel.geom.PageSize;
56
import com.itextpdf.kernel.pdf.PdfDocument;
67
import com.itextpdf.kernel.pdf.PdfWriter;
78
import com.itextpdf.kernel.utils.CompareTool;
8-
import com.itextpdf.test.annotations.type.IntegrationTest;
9+
import com.itextpdf.layout.border.SolidBorder;
910
import com.itextpdf.layout.element.AreaBreak;
1011
import com.itextpdf.layout.element.Paragraph;
1112
import com.itextpdf.layout.element.Text;
1213
import com.itextpdf.test.ExtendedITextTest;
13-
14+
import com.itextpdf.test.annotations.LogMessage;
15+
import com.itextpdf.test.annotations.LogMessages;
16+
import com.itextpdf.test.annotations.type.IntegrationTest;
1417

1518
import java.io.FileOutputStream;
1619
import java.io.IOException;
1720

1821
import org.junit.Assert;
1922
import org.junit.BeforeClass;
23+
import org.junit.Ignore;
2024
import org.junit.Test;
2125
import org.junit.experimental.categories.Category;
2226

@@ -66,4 +70,63 @@ public void rendererTest01() throws IOException, InterruptedException {
6670
Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
6771
}
6872

73+
@Test
74+
@LogMessages(messages = {
75+
@LogMessage(messageTemplate = LogMessageConstant.RECTANGLE_HAS_NEGATIVE_OR_ZERO_SIZES)
76+
})
77+
public void emptyParagraphsTest01() throws IOException, InterruptedException {
78+
String outFileName = destinationFolder + "emptyParagraphsTest01.pdf";
79+
String cmpFileName = sourceFolder + "cmp_emptyParagraphsTest01.pdf";
80+
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)));
81+
82+
Document document = new Document(pdfDocument);
83+
84+
// the next 3 lines should not cause any effect
85+
document.add(new Paragraph());
86+
document.add(new Paragraph().setBackgroundColor(Color.GREEN));
87+
document.add(new Paragraph().setBorder(new SolidBorder(Color.BLUE, 3)));
88+
89+
document.add(new Paragraph("Hello! I'm the first paragraph added to the document. Am i right?"));
90+
document.add(new Paragraph().setHeight(50));
91+
document.add(new Paragraph("Hello! I'm the second paragraph added to the document. Am i right?"));
92+
93+
document.close();
94+
95+
Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
96+
}
97+
98+
@Test
99+
@Ignore
100+
public void emptyParagraphsTest02() throws IOException, InterruptedException {
101+
String outFileName = destinationFolder + "emptyParagraphsTest02.pdf";
102+
String cmpFileName = sourceFolder + "cmp_emptyParagraphsTest02.pdf";
103+
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)));
104+
105+
Document document = new Document(pdfDocument);
106+
107+
document.add(new Paragraph("\n\n\n"));
108+
document.add(new Paragraph("a\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nb\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nc\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nd\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ne"));
109+
110+
document.close();
111+
112+
Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
113+
}
114+
115+
@Test
116+
@Ignore
117+
public void emptyParagraphsTest03() throws IOException, InterruptedException {
118+
String outFileName = destinationFolder + "emptyParagraphsTest03.pdf";
119+
// String cmpFileName = sourceFolder + "cmp_emptyParagraphsTest03.pdf";
120+
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)));
121+
122+
Document document = new Document(pdfDocument);
123+
124+
document.add(new Paragraph("c\nb"));
125+
// document.add(new Paragraph("a a\nb"));
126+
127+
document.close();
128+
129+
// Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
130+
}
131+
69132
}

0 commit comments

Comments
 (0)