Skip to content

Commit 7a057c9

Browse files
author
Dmitry Radchuk
committed
Add negative indexes support in grid layout
DEVSIX-8423
1 parent e0488e9 commit 7a057c9

File tree

13 files changed

+363
-292
lines changed

13 files changed

+363
-292
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ private void updateMinHeightForAbsolutelyPositionedRenderer(IRenderer renderer,
26212621
}
26222622

26232623
renderer.setProperty(Property.MIN_HEIGHT, UnitValue.createPointValue((float) resolvedMinHeight));
2624+
renderer.setProperty(Property.HEIGHT, UnitValue.createPointValue((float) resolvedMinHeight));
26242625
}
26252626
}
26262627

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

Lines changed: 208 additions & 72 deletions
Large diffs are not rendered by default.

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

Lines changed: 21 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ This file is part of the iText (R) project.
3131
*/
3232
class GridCell {
3333
private final IRenderer value;
34-
private int gridX;
35-
private int gridY;
36-
private final int spanColumn;
37-
private final int spanRow;
34+
private int columnStart;
35+
private int rowStart;
36+
private final int columnSpan;
37+
private final int rowSpan;
3838
private final Rectangle layoutArea = new Rectangle(0.0f, 0.0f, 0.0f,0.0f);
3939

4040
/**
@@ -44,36 +44,34 @@ class GridCell {
4444

4545
/**
4646
* Create a grid cell and init value renderer position on a grid based on its properties.
47-
*
4847
* @param value item renderer
48+
* @param x column number at which this cell starts (column numbers start from 0)
49+
* @param y row number at which this cell starts (row numbers from 0)
50+
* @param width number of columns spanned by this cell.
51+
* @param height number of rows spanned by this cell.
4952
*/
50-
GridCell(IRenderer value) {
53+
GridCell(IRenderer value, int x, int y, int width, int height) {
5154
this.value = value;
52-
final int[] rowPlacement = initAxisPlacement(value.<Integer>getProperty(Property.GRID_ROW_START),
53-
value.<Integer>getProperty(Property.GRID_ROW_END), value.<Integer>getProperty(Property.GRID_ROW_SPAN));
54-
gridY = rowPlacement[0];
55-
spanRow = rowPlacement[1];
56-
57-
final int[] columnPlacement = initAxisPlacement(value.<Integer>getProperty(Property.GRID_COLUMN_START),
58-
value.<Integer>getProperty(Property.GRID_COLUMN_END), value.<Integer>getProperty(Property.GRID_COLUMN_SPAN));
59-
gridX = columnPlacement[0];
60-
spanColumn = columnPlacement[1];
55+
this.columnStart = x;
56+
this.rowStart = y;
57+
this.columnSpan = width;
58+
this.rowSpan = height;
6159
}
6260

6361
int getColumnStart() {
64-
return gridX;
62+
return columnStart;
6563
}
6664

6765
int getColumnEnd() {
68-
return gridX + spanColumn;
66+
return columnStart + columnSpan;
6967
}
7068

7169
int getRowStart() {
72-
return gridY;
70+
return rowStart;
7371
}
7472

7573
int getRowEnd() {
76-
return gridY + spanRow;
74+
return rowStart + rowSpan;
7775
}
7876

7977
int getStart(GridOrder order) {
@@ -93,11 +91,11 @@ int getEnd(GridOrder order) {
9391
}
9492

9593
int getGridHeight() {
96-
return spanRow;
94+
return rowSpan;
9795
}
9896

9997
int getGridWidth() {
100-
return spanColumn;
98+
return columnSpan;
10199
}
102100

103101
int getGridSpan(GridOrder order) {
@@ -117,8 +115,8 @@ Rectangle getLayoutArea() {
117115
}
118116

119117
void setPos(int y, int x) {
120-
this.gridY = y;
121-
this.gridX = x;
118+
this.rowStart = y;
119+
this.columnStart = x;
122120
}
123121

124122
float[] getRowSizes() {
@@ -128,50 +126,4 @@ float[] getRowSizes() {
128126
void setRowSizes(float[] rowSizes) {
129127
this.rowSizes = rowSizes;
130128
}
131-
132-
/**
133-
* Init axis placement values
134-
* if start > end values are swapped
135-
*
136-
* @param start x/y pos of cell on a grid
137-
* @param end x/y + width/height pos of cell on a grid
138-
* @param span vertical or horizontal span of the cell on a grid
139-
* @return row/column start + vertical/horizontal span values as a pair, where first value is start, second is span
140-
*/
141-
private int[] initAxisPlacement(Integer start, Integer end, Integer span) {
142-
int[] result = new int[] {0, 1};
143-
if (start != null && end != null) {
144-
int intStart = (int) start;
145-
int intEnd = (int) end;
146-
if (intStart < intEnd) {
147-
result[0] = intStart;
148-
result[1] = intEnd - intStart;
149-
} else if (intStart == intEnd) {
150-
result[0] = intStart;
151-
} else {
152-
result[0] = intEnd;
153-
result[1] = intStart - intEnd;
154-
}
155-
} else if (start != null) {
156-
result[0] = (int) start;
157-
if (span != null) {
158-
result[1] = (int) span;
159-
}
160-
// span default value 1 was set up on the result array initialization
161-
} else if (end != null) {
162-
int intEnd = (int) end;
163-
if (span == null) {
164-
result[0] = end <= 1 ? 1 : ((int) end) - 1;
165-
// span default value 1 was set up on the result array initialization
166-
} else {
167-
int intSpan = (int) span;
168-
result[1] = intSpan;
169-
result[0] = Math.max(intEnd - intSpan, 1);
170-
}
171-
} else if (span != null) {
172-
result[1] = (int) span;
173-
}
174-
result[0] -= 1;
175-
return result;
176-
}
177129
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ private static Grid constructGrid(GridContainerRenderer renderer, Rectangle actu
311311

312312
// 8. Placing Grid Items
313313
Grid grid = Grid.Builder.forItems(renderer.getChildRenderers())
314-
.columns(templateColumns == null ? 1 : templateColumns.size())
315-
.rows(templateRows == null ? 1 : templateRows.size())
314+
.columns(templateColumns == null ? 0 : templateColumns.size())
315+
.rows(templateRows == null ? 0 : templateRows.size())
316316
.flow(flow).build();
317317

318318
// Collapse any empty repeated tracks if auto-fit was used

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ public float getContainerHeight() {
9595
private void resolveGridRows() {
9696
List<GridValue> rowsValues = new ArrayList<>();
9797
for (int i = 0; i < grid.getNumberOfRows(); i++) {
98-
if (templateRows != null && i < templateRows.size()) {
99-
rowsValues.add(templateRows.get(i));
98+
if (templateRows != null
99+
&& i - grid.getRowOffset() < templateRows.size()
100+
&& i - grid.getRowOffset() >= 0) {
101+
rowsValues.add(templateRows.get(i - grid.getRowOffset()));
100102
} else if (rowAutoHeight != null) {
101103
rowsValues.add(rowAutoHeight);
102104
} else {
@@ -172,8 +174,10 @@ private float sum(List<Float> trackSizes) {
172174
private void resolveGridColumns() {
173175
List<GridValue> colsValues = new ArrayList<>();
174176
for (int i = 0; i < grid.getNumberOfColumns(); i++) {
175-
if (templateColumns != null && i < templateColumns.size()) {
176-
colsValues.add(templateColumns.get(i));
177+
if (templateColumns != null
178+
&& i - grid.getColumnOffset() < templateColumns.size()
179+
&& i - grid.getColumnOffset() >= 0) {
180+
colsValues.add(templateColumns.get(i - grid.getColumnOffset()));
177181
} else if (columnAutoWidth != null) {
178182
colsValues.add(columnAutoWidth);
179183
} else {

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ public Pos next() {
8585
Pos reset(int y, int x, int rightMargin, int bottomMargin) {
8686
this.cursor.setY(y);
8787
this.cursor.setX(x);
88+
if (x == -1 && y == -1) {
89+
if (rightMargin > grid.getNumberOfColumns() - this.cursor.x
90+
+ (Grid.GridOrder.COLUMN.equals(iterationOrder) ? 1 : 0)) {
91+
this.cursor.setX(0);
92+
}
93+
if (bottomMargin > grid.getNumberOfRows() - this.cursor.y
94+
+ (Grid.GridOrder.ROW.equals(iterationOrder) ? 1 : 0)) {
95+
this.cursor.setY(0);
96+
}
97+
}
8898
this.rightMargin = rightMargin - 1;
8999
this.bottomMargin = bottomMargin - 1;
90100
this.restrictXGrow = x != -1;
@@ -143,13 +153,13 @@ void increaseDefaultCursor(Pos cellSizes) {
143153

144154
void increaseDefaultAxis() {
145155
if (restrictYGrow) {
146-
grid.ensureGridSize(-1, grid.getRows()[0].length + 1);
156+
grid.resize(-1, grid.getRows()[0].length + 1);
147157
} else if (restrictXGrow) {
148-
grid.ensureGridSize(grid.getRows().length + 1, -1);
158+
grid.resize(grid.getRows().length + 1, -1);
149159
} else if (Grid.GridOrder.ROW.equals(iterationOrder)) {
150-
grid.ensureGridSize(grid.getRows().length + 1, -1);
160+
grid.resize(grid.getRows().length + 1, -1);
151161
} else if (Grid.GridOrder.COLUMN.equals(iterationOrder)) {
152-
grid.ensureGridSize(-1, grid.getRows()[0].length + 1);
162+
grid.resize(-1, grid.getRows()[0].length + 1);
153163
}
154164
hasNext = true;
155165
}

layout/src/test/java/com/itextpdf/layout/element/GridContainerTest.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,53 @@ public void basicThreeColumnsTest() throws IOException, InterruptedException {
8787
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
8888
}
8989

90+
@Test
91+
public void basicTwoColumnsTest() throws IOException, InterruptedException {
92+
String filename = DESTINATION_FOLDER + "basicTwoColumnsTest.pdf";
93+
String cmpName = SOURCE_FOLDER + "cmp_basicTwoColumnsTest.pdf";
94+
95+
java.util.List<TemplateValue> templateColumns = new ArrayList<>();
96+
templateColumns.add(new PointValue(150.0f));
97+
templateColumns.add(new PointValue(150.0f));
98+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
99+
100+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
101+
GridContainer grid = new GridContainer();
102+
grid.setProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns);
103+
grid.add(new Paragraph("One").setBorder(border));
104+
grid.add(new Paragraph("Two").setBorder(border));
105+
Paragraph paragraph3 = new Paragraph("One").setBorder(border);
106+
paragraph3.setProperty(Property.GRID_COLUMN_SPAN, 2);
107+
grid.add(paragraph3);
108+
document.add(grid);
109+
}
110+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
111+
}
112+
113+
@Test
114+
public void basicTwoRowsTest() throws IOException, InterruptedException {
115+
String filename = DESTINATION_FOLDER + "basicTwoRowsTest.pdf";
116+
String cmpName = SOURCE_FOLDER + "cmp_basicTwoRowsTest.pdf";
117+
118+
java.util.List<TemplateValue> templateRows = new ArrayList<>();
119+
templateRows.add(new PointValue(150.0f));
120+
templateRows.add(new PointValue(150.0f));
121+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
122+
123+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
124+
GridContainer grid = new GridContainer();
125+
grid.setProperty(Property.GRID_TEMPLATE_ROWS, templateRows);
126+
grid.setProperty(Property.GRID_FLOW, GridFlow.COLUMN);
127+
grid.add(new Paragraph("One").setBorder(border));
128+
grid.add(new Paragraph("Two").setBorder(border));
129+
Paragraph paragraph3 = new Paragraph("One").setBorder(border);
130+
paragraph3.setProperty(Property.GRID_ROW_SPAN, 2);
131+
grid.add(paragraph3);
132+
document.add(grid);
133+
}
134+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
135+
}
136+
90137
@Test
91138
public void basicAutoColumnsTest() throws IOException, InterruptedException {
92139
String filename = DESTINATION_FOLDER + "basicAutoColumnsTest.pdf";
@@ -154,6 +201,68 @@ public void basicThreeColumnsWithCustomColumnIndexesTest() throws IOException, I
154201
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
155202
}
156203

204+
@Test
205+
public void basicThreeColumnsOutOfBoundsWithNoCellsTest() throws IOException, InterruptedException {
206+
String filename = DESTINATION_FOLDER + "basicThreeColumnsOutOfBoundsWithNoCellsTest.pdf";
207+
String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsOutOfBoundsWithNoCellsTest.pdf";
208+
209+
java.util.List<TemplateValue> templateColumns = new ArrayList<>();
210+
templateColumns.add(new PointValue(100.0f));
211+
templateColumns.add(new PointValue(100.0f));
212+
templateColumns.add(new PointValue(100.0f));
213+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
214+
215+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
216+
GridContainer grid = new GridContainer();
217+
grid.setProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns);
218+
Paragraph paragraph1 = new Paragraph("One").setBorder(border);
219+
paragraph1.setProperty(Property.GRID_COLUMN_START, -2);
220+
paragraph1.setProperty(Property.GRID_COLUMN_END, -1);
221+
grid.add(paragraph1);
222+
grid.add(new Paragraph("Two").setBorder(border));
223+
Paragraph paragraph3 = new Paragraph("Three").setBorder(border);
224+
paragraph3.setProperty(Property.GRID_COLUMN_START, -4);
225+
paragraph3.setProperty(Property.GRID_COLUMN_END, 3);
226+
grid.add(paragraph3);
227+
grid.add(new Paragraph("Four").setBorder(border));
228+
document.add(grid);
229+
}
230+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
231+
}
232+
233+
@Test
234+
public void basicThreeColumnsWithNegativeCustomColumnIndexesTest() throws IOException, InterruptedException {
235+
String filename = DESTINATION_FOLDER + "basicThreeColumnsWithNegativeCustomColumnIndexesTest.pdf";
236+
String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithNegativeCustomColumnIndexesTest.pdf";
237+
238+
java.util.List<TemplateValue> templateColumns = new ArrayList<>();
239+
templateColumns.add(new PointValue(100.0f));
240+
templateColumns.add(new PointValue(100.0f));
241+
templateColumns.add(new PointValue(100.0f));
242+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
243+
244+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
245+
GridContainer grid = new GridContainer();
246+
grid.setProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns);
247+
Paragraph paragraph1 = new Paragraph("One").setBorder(border);
248+
paragraph1.setProperty(Property.GRID_COLUMN_START, -2);
249+
paragraph1.setProperty(Property.GRID_COLUMN_END, -1);
250+
grid.add(paragraph1);
251+
grid.add(new Paragraph("Two").setBorder(border));
252+
Paragraph paragraph3 = new Paragraph("Three").setBorder(border);
253+
paragraph3.setProperty(Property.GRID_COLUMN_START, -7);
254+
paragraph3.setProperty(Property.GRID_COLUMN_END, 3);
255+
grid.add(paragraph3);
256+
grid.add(new Paragraph("Four").setBorder(border));
257+
grid.add(new Paragraph("Five").setBorder(border));
258+
grid.add(new Paragraph("Six").setBorder(border));
259+
grid.add(new Paragraph("Seven").setBorder(border));
260+
grid.add(new Paragraph("Eight").setBorder(border));
261+
document.add(grid);
262+
}
263+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
264+
}
265+
157266
@Test
158267
public void threeColumnsWithAdjacentWideCellsTest() throws IOException, InterruptedException {
159268
String filename = DESTINATION_FOLDER + "threeColumnsWithAdjacentWideCellsTest.pdf";

0 commit comments

Comments
 (0)