Skip to content

Commit f845c29

Browse files
committed
Process MIN_HEIGHT on tables correctly
Extend all row-heights equally if table's height is bigger than needed. Notice that we extend rows on the last page Resolves DEVSIX-1072
1 parent 6e908cd commit f845c29

File tree

4 files changed

+65
-61
lines changed

4 files changed

+65
-61
lines changed

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

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
734734
}
735735
}
736736
// Correct occupied areas of all added cells
737-
correctCellsOccupiedAreas(splits, row, targetOverflowRowIndex);
737+
correctCellsOccupiedAreas(splits, row, targetOverflowRowIndex, blockMinHeight, layoutBox, bottomTableBorderWidth, row == rows.size() - 1);
738738
}
739739
// process footer with collapsed borders
740740
if ((split || processAsLast || row == rows.size() - 1) && null != footerRenderer) {
@@ -1048,6 +1048,19 @@ public LayoutResult layout(LayoutContext layoutContext) {
10481048
verticalBorders.add(new ArrayList<Border>());
10491049
}
10501050
verticalBorders.add(rightVerticalBorders);
1051+
1052+
if (null != blockMinHeight && blockMinHeight > occupiedArea.getBBox().getHeight() + bottomTableBorderWidth) {
1053+
float blockBottom = Math.max(occupiedArea.getBBox().getBottom() - ((float) blockMinHeight - occupiedArea.getBBox().getHeight() - bottomTableBorderWidth), layoutBox.getBottom() + bottomTableBorderWidth);
1054+
if (0 != heights.size()) {
1055+
heights.set(heights.size() - 1, heights.get(heights.size() - 1) + occupiedArea.getBBox().getBottom() - blockBottom);
1056+
} else {
1057+
heights.add((occupiedArea.getBBox().getBottom() - blockBottom) + topTableBorderWidth / 2 + bottomTableBorderWidth / 2);
1058+
}
1059+
1060+
occupiedArea.getBBox()
1061+
.increaseHeight(occupiedArea.getBBox().getBottom() - blockBottom)
1062+
.setY(blockBottom);
1063+
}
10511064
}
10521065

10531066
// Apply bottom and top border
@@ -1087,20 +1100,6 @@ public LayoutResult layout(LayoutContext layoutContext) {
10871100
extendLastRow(rows.get(rows.size() - 1), layoutBox);
10881101
}
10891102

1090-
if (null != blockMinHeight && blockMinHeight > occupiedArea.getBBox().getHeight()) {
1091-
float blockBottom = Math.max(occupiedArea.getBBox().getBottom() - ((float) blockMinHeight - occupiedArea.getBBox().getHeight()), layoutBox.getBottom());
1092-
if (0 != heights.size()) {
1093-
heights.set(heights.size() - 1, heights.get(heights.size() - 1) + occupiedArea.getBBox().getBottom() - blockBottom);
1094-
} else {
1095-
heights.add((occupiedArea.getBBox().getBottom() - blockBottom) + occupiedArea.getBBox().getHeight() / 2);
1096-
}
1097-
1098-
occupiedArea.getBBox()
1099-
.increaseHeight(occupiedArea.getBBox().getBottom() - blockBottom)
1100-
.setY(blockBottom);
1101-
}
1102-
1103-
11041103
if (isPositioned()) {
11051104
float y = (float) this.getPropertyAsFloat(Property.Y);
11061105
float relativeY = isFixedLayout() ? 0 : layoutBox.getY();
@@ -2007,31 +2006,43 @@ private void fixFooterBorders(List<Border> tableBottomBorders, int colNum, int r
20072006
}
20082007
}
20092008

2010-
private void correctCellsOccupiedAreas(LayoutResult[] splits, int row, int[] targetOverflowRowIndex) {
2011-
// Correct occupied areas of all added cells
2012-
for (int k = 0; k <= row; k++) {
2013-
CellRenderer[] currentRow = rows.get(k);
2014-
if (k < row || (row + 1 == heights.size())) {
2015-
for (int col = 0; col < currentRow.length; col++) {
2016-
CellRenderer cell = (k < row || null == splits[col]) ? currentRow[col] : (CellRenderer) splits[col].getSplitRenderer();
2017-
if (cell == null) {
2018-
continue;
2019-
}
2020-
float height = 0;
2021-
int rowspan = (int) cell.getPropertyAsInteger(Property.ROWSPAN);
2022-
for (int l = k; l > ((k == row + 1) ? targetOverflowRowIndex[col] : k) - rowspan && l >= 0; l--) {
2023-
height += (float) heights.get(l);
2024-
}
2025-
// Correcting cell bbox only. We don't need #move() here.
2026-
// This is because of BlockRenderer's specificity regarding occupied area.
2027-
float shift = height - cell.getOccupiedArea().getBBox().getHeight();
2028-
Rectangle bBox = cell.getOccupiedArea().getBBox();
2029-
bBox.moveDown(shift);
2030-
bBox.setHeight(height);
2031-
cell.applyVerticalAlignment();
2009+
private void correctCellsOccupiedAreas(LayoutResult[] splits, int row, int[] targetOverflowRowIndex, Float blockMinHeight, Rectangle layoutBox, float bottomTableBorderWidth, boolean isLastRenderer) {
2010+
float additionalCellHeight = 0;
2011+
if (isLastRenderer) {
2012+
if (null != blockMinHeight && blockMinHeight > occupiedArea.getBBox().getHeight() + bottomTableBorderWidth / 2) {
2013+
additionalCellHeight = Math.min(layoutBox.getHeight() - bottomTableBorderWidth / 2, blockMinHeight - occupiedArea.getBBox().getHeight() - bottomTableBorderWidth / 2) / heights.size();
2014+
for (int i = 0; i < heights.size(); i++) {
2015+
heights.set(i, heights.get(i) + additionalCellHeight);
20322016
}
20332017
}
20342018
}
2019+
float cumulativeShift = 0;
2020+
// Correct occupied areas of all added cells
2021+
for (int k = 0; k < heights.size(); k++) {
2022+
CellRenderer[] currentRow = rows.get(k);
2023+
for (int col = 0; col < currentRow.length; col++) {
2024+
CellRenderer cell = (k < row || null == splits[col]) ? currentRow[col] : (CellRenderer) splits[col].getSplitRenderer();
2025+
if (cell == null) {
2026+
continue;
2027+
}
2028+
float height = 0;
2029+
int rowspan = (int) cell.getPropertyAsInteger(Property.ROWSPAN);
2030+
for (int l = k; l > ((k == row + 1) ? targetOverflowRowIndex[col] : k) - rowspan && l >= 0; l--) {
2031+
height += (float) heights.get(l);
2032+
}
2033+
// Correcting cell bbox only. We don't need #move() here.
2034+
// This is because of BlockRenderer's specificity regarding occupied area.
2035+
float shift = height - cell.getOccupiedArea().getBBox().getHeight();
2036+
Rectangle bBox = cell.getOccupiedArea().getBBox();
2037+
bBox.moveDown(shift);
2038+
bBox.setHeight(height);
2039+
cell.move(0, - (cumulativeShift - (rowspan - 1) * additionalCellHeight));
2040+
cell.applyVerticalAlignment();
2041+
}
2042+
cumulativeShift += additionalCellHeight;
2043+
}
2044+
occupiedArea.getBBox().moveDown(cumulativeShift).increaseHeight(cumulativeShift);
2045+
layoutBox.decreaseHeight(cumulativeShift);
20352046
}
20362047

20372048
private void prepareBuildingBordersArrays(CellRenderer cell, Border[] tableBorders, int colNum, int row, int col) {
@@ -2328,7 +2339,7 @@ private float getTableWidth() {
23282339

23292340
protected TableRenderer saveCellsProperties() {
23302341
CellRenderer[] currentRow;
2331-
int colN = ((Table)getModelElement()).getNumberOfColumns();
2342+
int colN = ((Table) getModelElement()).getNumberOfColumns();
23322343
for (int row = 0; row < rows.size(); row++) {
23332344
currentRow = rows.get(row);
23342345
for (int col = 0; col < colN; col++) {
@@ -2342,7 +2353,7 @@ protected TableRenderer saveCellsProperties() {
23422353

23432354
protected TableRenderer restoreCellsProperties() {
23442355
CellRenderer[] currentRow;
2345-
int colN = ((Table)getModelElement()).getNumberOfColumns();
2356+
int colN = ((Table) getModelElement()).getNumberOfColumns();
23462357
for (int row = 0; row < rows.size(); row++) {
23472358
currentRow = rows.get(row);
23482359
for (int col = 0; col < colN; col++) {

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

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ This file is part of the iText (R) project.
5353
import com.itextpdf.kernel.utils.CompareTool;
5454
import com.itextpdf.layout.border.Border;
5555
import com.itextpdf.layout.border.SolidBorder;
56-
import com.itextpdf.layout.element.AreaBreak;
57-
import com.itextpdf.layout.element.Cell;
58-
import com.itextpdf.layout.element.Image;
59-
import com.itextpdf.layout.element.Paragraph;
60-
import com.itextpdf.layout.element.Table;
61-
import com.itextpdf.layout.element.Text;
56+
import com.itextpdf.layout.element.*;
6257
import com.itextpdf.layout.property.HorizontalAlignment;
6358
import com.itextpdf.layout.property.Property;
6459
import com.itextpdf.layout.property.UnitValue;
@@ -73,7 +68,6 @@ This file is part of the iText (R) project.
7368
import org.junit.Test;
7469
import org.junit.experimental.categories.Category;
7570

76-
import java.io.FileNotFoundException;
7771
import java.io.IOException;
7872

7973
@Category(IntegrationTest.class)
@@ -871,8 +865,7 @@ public void bigRowspanTest05() throws IOException, InterruptedException {
871865
.addCell(new Cell(2, 1).add(new Paragraph("cell 1, 1 and 2\n" + longTextContent)))
872866
.addCell(new Cell().add(new Paragraph("cell 2, 1\n" + textContent)))
873867
.addCell(new Cell().add(new Paragraph("cell 3, 1\n" + textContent)))
874-
.addCell(new Cell().add(new Paragraph("cell 3, 2\n" + textContent)))
875-
;
868+
.addCell(new Cell().add(new Paragraph("cell 3, 2\n" + textContent)));
876869

877870
doc.add(table);
878871
doc.close();
@@ -1195,9 +1188,9 @@ public void tableWithSetHeightProperties01() throws IOException, InterruptedExce
11951188

11961189
String textByron =
11971190
"When a man hath no freedom to fight for at home,\n" +
1198-
" Let him combat for that of his neighbours;\n" +
1199-
"Let him think of the glories of Greece and of Rome,\n" +
1200-
" And get knocked on the head for his labours.\n";
1191+
" Let him combat for that of his neighbours;\n" +
1192+
"Let him think of the glories of Greece and of Rome,\n" +
1193+
" And get knocked on the head for his labours.\n";
12011194

12021195

12031196
doc.add(new Paragraph("Default layout:"));
@@ -1239,7 +1232,7 @@ public void tableWithSetHeightProperties01() throws IOException, InterruptedExce
12391232
doc.add(table);
12401233
doc.add(new AreaBreak());
12411234

1242-
doc.add(new Paragraph("Some cells' heights are setted:"));
1235+
doc.add(new Paragraph("Some cells' heights are set:"));
12431236
table = new Table(3)
12441237
.addCell(new Cell().add(textByron).setBorder(new SolidBorder(Color.GREEN, 1)))
12451238
.addCell(new Cell(1, 2).add(textByron).setBorder(new SolidBorder(Color.YELLOW, 3)).setHeight(300))
@@ -1342,7 +1335,7 @@ public void tableWithSetHeightProperties02() throws IOException, InterruptedExce
13421335
doc.add(new AreaBreak());
13431336

13441337

1345-
doc.add(new Paragraph("Some cells' heights are setted:"));
1338+
doc.add(new Paragraph("Some cells' heights are set:"));
13461339
table = new Table(3)
13471340
.addCell(new Cell().add(textByron).setBorder(new SolidBorder(Color.GREEN, 1)))
13481341
.addCell(new Cell(1, 2).add(textByron).setBorder(new SolidBorder(Color.YELLOW, 3)).setMinHeight(300))
@@ -1371,19 +1364,19 @@ public void emptyTableTest01() throws IOException, InterruptedException {
13711364
Document doc = new Document(pdfDoc);
13721365

13731366
doc.add(new Table(1)
1374-
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1375-
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1376-
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1377-
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1378-
.addCell(new Cell().add("Hello"))
1367+
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1368+
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1369+
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1370+
.addCell(new Cell().setPadding(0).setMargin(0).setBorder(Border.NO_BORDER))
1371+
.addCell(new Cell().add("Hello"))
13791372
);
13801373
doc.add(new Table(1).setBorder(new SolidBorder(Color.ORANGE, 2)).addCell("Is my occupied area correct?"));
13811374
doc.add(new AreaBreak());
13821375

13831376

13841377
doc.add(new Table(1)
1385-
.setBorderTop(new SolidBorder(Color.ORANGE, 50))
1386-
.setBorderBottom(new SolidBorder(Color.MAGENTA, 100))
1378+
.setBorderTop(new SolidBorder(Color.ORANGE, 50))
1379+
.setBorderBottom(new SolidBorder(Color.MAGENTA, 100))
13871380
);
13881381
doc.add(new Table(1).setBorder(new SolidBorder(Color.ORANGE, 2)).addCell("Is my occupied area correct?"));
13891382
doc.add(new AreaBreak());
@@ -1407,7 +1400,7 @@ public void tableWithCustomRendererTest01() throws IOException, InterruptedExcep
14071400

14081401
Table table = new Table(2);
14091402
table.setBorder(new SolidBorder(Color.GREEN, 100));
1410-
1403+
14111404
for (int i = 0; i < 10; i++) {
14121405
table.addCell(new Cell().add("Cell No." + i));
14131406
}

0 commit comments

Comments
 (0)