Skip to content

Commit 3193c19

Browse files
committed
Support row\column span values for cell in the grid
DEVSIX-8363
1 parent 1102018 commit 3193c19

File tree

7 files changed

+108
-141
lines changed

7 files changed

+108
-141
lines changed

layout/src/main/java/com/itextpdf/layout/properties/Property.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ public final class Property {
121121
public static final int FULL = 25;
122122
public static final int GRID_COLUMN_END = 147;
123123
public static final int GRID_COLUMN_START = 148;
124+
public static final int GRID_COLUMN_SPAN = 155;
124125
public static final int GRID_ROW_END = 149;
125126
public static final int GRID_ROW_START = 150;
127+
public static final int GRID_ROW_SPAN = 156;
126128
public static final int GRID_TEMPLATE_COLUMNS = 145;
127129
public static final int GRID_TEMPLATE_ROWS = 146;
128130
public static final int GRID_AUTO_ROWS = 151;
@@ -234,7 +236,7 @@ public final class Property {
234236
* related to textual operations. Indicates whether or not this type of property is inheritable.
235237
*/
236238
private static final boolean[] INHERITED_PROPERTIES;
237-
private static final int MAX_INHERITED_PROPERTY_ID = 154;
239+
private static final int MAX_INHERITED_PROPERTY_ID = 156;
238240

239241
static {
240242
INHERITED_PROPERTIES = new boolean[MAX_INHERITED_PROPERTY_ID + 1];

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

Lines changed: 52 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ This file is part of the iText (R) project.
3131
*/
3232
class GridCell {
3333
private final IRenderer value;
34-
private final IntRectangle gridArea;
35-
private Rectangle layoutArea = new Rectangle(0.0f, 0.0f, 0.0f,0.0f);
36-
private boolean isValueFitOnCellArea = true;
34+
private int gridX;
35+
private int gridY;
36+
private final int spanColumn;
37+
private final int spanRow;
38+
private final Rectangle layoutArea = new Rectangle(0.0f, 0.0f, 0.0f,0.0f);
3739

3840
/**
3941
* Create a grid cell and init value renderer position on a grid based on its properties.
@@ -42,30 +44,31 @@ class GridCell {
4244
*/
4345
GridCell(IRenderer value) {
4446
this.value = value;
45-
final int[] rowValues = initRowColumnsValues(value.<Integer>getProperty(Property.GRID_ROW_START),
46-
value.<Integer>getProperty(Property.GRID_ROW_END));
47-
int height = rowValues[0] == 0 ? 1 : rowValues[1] - rowValues[0];
48-
49-
final int[] columnValues = initRowColumnsValues(value.<Integer>getProperty(Property.GRID_COLUMN_START),
50-
value.<Integer>getProperty(Property.GRID_COLUMN_END));
51-
int width = columnValues[0] == 0 ? 1 : columnValues[1] - columnValues[0];
52-
gridArea = new IntRectangle(columnValues[0] - 1, rowValues[0] - 1, width, height);
47+
final int[] rowPlacement = initAxisPlacement(value.<Integer>getProperty(Property.GRID_ROW_START),
48+
value.<Integer>getProperty(Property.GRID_ROW_END), value.<Integer>getProperty(Property.GRID_ROW_SPAN));
49+
gridY = rowPlacement[0];
50+
spanRow = rowPlacement[1];
51+
52+
final int[] columnPlacement = initAxisPlacement(value.<Integer>getProperty(Property.GRID_COLUMN_START),
53+
value.<Integer>getProperty(Property.GRID_COLUMN_END), value.<Integer>getProperty(Property.GRID_COLUMN_SPAN));
54+
gridX = columnPlacement[0];
55+
spanColumn = columnPlacement[1];
5356
}
5457

5558
int getColumnStart() {
56-
return gridArea.getLeft();
59+
return gridX;
5760
}
5861

5962
int getColumnEnd() {
60-
return gridArea.getRight();
63+
return gridX + spanColumn;
6164
}
6265

6366
int getRowStart() {
64-
return gridArea.getBottom();
67+
return gridY;
6568
}
6669

6770
int getRowEnd() {
68-
return gridArea.getTop();
71+
return gridY + spanRow;
6972
}
7073

7174
int getStart(GridOrder order) {
@@ -85,11 +88,11 @@ int getEnd(GridOrder order) {
8588
}
8689

8790
int getGridHeight() {
88-
return gridArea.getHeight();
91+
return spanRow;
8992
}
9093

9194
int getGridWidth() {
92-
return gridArea.getWidth();
95+
return spanColumn;
9396
}
9497

9598
int getGridSpan(GridOrder order) {
@@ -104,119 +107,56 @@ IRenderer getValue() {
104107
return value;
105108
}
106109

107-
boolean isValueFitOnCellArea() {
108-
return isValueFitOnCellArea;
109-
}
110-
111110
Rectangle getLayoutArea() {
112111
return layoutArea;
113112
}
114113

115-
IntRectangle getGridArea() {
116-
return gridArea;
117-
}
118-
119-
void setLayoutArea(Rectangle layoutArea) {
120-
this.layoutArea = layoutArea;
121-
}
122-
123-
void setValueFitOnCellArea(boolean valueFitOnCellArea) {
124-
isValueFitOnCellArea = valueFitOnCellArea;
125-
}
126-
127114
void setPos(int y, int x) {
128-
this.gridArea.setY(y);
129-
this.gridArea.setX(x);
115+
this.gridY = y;
116+
this.gridX = x;
130117
}
131118

132119
/**
133-
* init row/column start/end value
120+
* Init axis placement values
134121
* if start > end values are swapped
135-
* if only start or end are specified - other value is initialized so cell would have height/width = 1
136122
*
137123
* @param start x/y pos of cell on a grid
138124
* @param end x/y + width/height pos of cell on a grid
139-
* @return row/column start/end values as a pair, where first value is start, second is end
125+
* @param span vertical or horizontal span of the cell on a grid
126+
* @return row/column start + vertical/horizontal span values as a pair, where first value is start, second is span
140127
*/
141-
private int[] initRowColumnsValues(Integer start, Integer end) {
142-
int[] result = new int[] {0, 0};
128+
private int[] initAxisPlacement(Integer start, Integer end, Integer span) {
129+
int[] result = new int[] {0, 1};
143130
if (start != null && end != null) {
144-
result[0] = (int)start;
145-
result[1] = (int)end;
146-
if (start > end) {
147-
result[0] = (int)end;
148-
result[1] = (int)start;
131+
int intStart = (int) start;
132+
int intEnd = (int) end;
133+
if (intStart < intEnd) {
134+
result[0] = intStart;
135+
result[1] = intEnd - intStart;
136+
} else {
137+
result[0] = intEnd;
138+
result[1] = intStart - intEnd;
149139
}
150140
} else if (start != null) {
151-
result[0] = (int)start;
152-
result[1] = (int)start + 1;
141+
result[0] = (int) start;
142+
if (span != null) {
143+
result[1] = (int) span;
144+
}
145+
// span default value 1 was set up on the result array initialization
153146
} else if (end != null) {
154-
result[0] = end <= 1 ? 1 : ((int)end) - 1;
155-
result[1] = end <= 1 ? 2 : (int)end;
147+
int intEnd = (int) end;
148+
if (span == null) {
149+
result[0] = end <= 1 ? 1 : ((int) end) - 1;
150+
// span default value 1 was set up on the result array initialization
151+
} else {
152+
int intSpan = (int) span;
153+
result[1] = intSpan;
154+
result[0] = Math.max(intEnd - intSpan, 1);
155+
}
156+
} else if (span != null) {
157+
result[1] = (int) span;
156158
}
159+
result[0] -= 1;
157160
return result;
158161
}
159-
160-
/**
161-
* This class represents an integer rectangle.
162-
* x,y - represents a bottom left corner of this rectangle.
163-
*/
164-
static class IntRectangle {
165-
private int x;
166-
private int y;
167-
private int width;
168-
private int height;
169-
170-
public IntRectangle(int x, int y, int width, int height) {
171-
this.x = x;
172-
this.y = y;
173-
this.width = width;
174-
this.height = height;
175-
}
176-
177-
public int getLeft() {
178-
return x;
179-
}
180-
181-
public int getRight() {
182-
return x + width;
183-
}
184-
185-
public int getTop() {
186-
return y + height;
187-
}
188-
189-
public int getBottom() {
190-
return y;
191-
}
192-
193-
public int getWidth() {
194-
return width;
195-
}
196-
197-
public int getHeight() {
198-
return height;
199-
}
200-
201-
public void setX(int x) {
202-
this.x = x;
203-
}
204-
205-
public void setY(int y) {
206-
this.y = y;
207-
}
208-
209-
public void setWidth(int width) {
210-
this.width = width;
211-
}
212-
213-
public void setHeight(int height) {
214-
this.height = height;
215-
}
216-
217-
@Override
218-
public String toString() {
219-
return "Rectangle: start(" + x + ',' + y + ") ," + width + 'x' + height;
220-
}
221-
}
222162
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,6 @@ private static float calculateMaxContribution(GridCell cell, GridOrder gridOrder
481481
LayoutResult inifiniteHeighLayoutResult = cell.getValue().layout(layoutContext);
482482
if (inifiniteHeighLayoutResult.getStatus() == LayoutResult.NOTHING
483483
|| inifiniteHeighLayoutResult.getStatus() == LayoutResult.PARTIAL) {
484-
cell.setValueFitOnCellArea(false);
485484
return 0;
486485
}
487486
return inifiniteHeighLayoutResult.getOccupiedArea().getBBox().getHeight();

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,4 +711,57 @@ public void frColumnsTest() throws IOException, InterruptedException {
711711
}
712712
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
713713
}
714+
715+
@Test
716+
public void columnSpanTest() throws IOException, InterruptedException {
717+
String filename = DESTINATION_FOLDER + "columnSpanTest.pdf";
718+
String cmpName = SOURCE_FOLDER + "cmp_columnSpanTest.pdf";
719+
720+
java.util.List<GridValue> templateColumns = new ArrayList<>();
721+
templateColumns.add(GridValue.createPointValue(100.0f));
722+
templateColumns.add(GridValue.createPointValue(100.0f));
723+
templateColumns.add(GridValue.createPointValue(100.0f));
724+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
725+
726+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
727+
GridContainer grid = new GridContainer();
728+
grid.setProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns);
729+
Paragraph paragraph1 = new Paragraph("One").setBorder(border);
730+
paragraph1.setProperty(Property.GRID_COLUMN_START, 1);
731+
paragraph1.setProperty(Property.GRID_COLUMN_SPAN, 2);
732+
grid.add(paragraph1);
733+
grid.add(new Paragraph("Two").setBorder(border));
734+
grid.add(new Paragraph("Three").setBorder(border));
735+
grid.add(new Paragraph("Four").setBorder(border));
736+
document.add(grid);
737+
}
738+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
739+
}
740+
741+
@Test
742+
public void rowSpanTest() throws IOException, InterruptedException {
743+
String filename = DESTINATION_FOLDER + "rowSpanTest.pdf";
744+
String cmpName = SOURCE_FOLDER + "cmp_rowSpanTest.pdf";
745+
746+
java.util.List<GridValue> template = new ArrayList<>();
747+
template.add(GridValue.createPointValue(100.0f));
748+
template.add(GridValue.createPointValue(100.0f));
749+
template.add(GridValue.createPointValue(100.0f));
750+
SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1);
751+
752+
try (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) {
753+
GridContainer grid = new GridContainer();
754+
grid.setProperty(Property.GRID_TEMPLATE_COLUMNS, template);
755+
grid.setProperty(Property.GRID_TEMPLATE_ROWS, template);
756+
Paragraph paragraph1 = new Paragraph("One").setBorder(border);
757+
paragraph1.setProperty(Property.GRID_ROW_SPAN, 2);
758+
paragraph1.setProperty(Property.GRID_ROW_END, 3);
759+
grid.add(paragraph1);
760+
grid.add(new Paragraph("Two").setBorder(border));
761+
grid.add(new Paragraph("Three").setBorder(border));
762+
grid.add(new Paragraph("Four").setBorder(border));
763+
document.add(grid);
764+
}
765+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_"));
766+
}
714767
}

layout/src/test/java/com/itextpdf/layout/renderer/GridUnitTest.java

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -223,31 +223,4 @@ public void columnWithFixedTallCellPackingTest() {
223223
Assert.assertEquals(cell5, grid.getRows()[2][1]);
224224
Assert.assertEquals(cell6, grid.getRows()[0][2]);
225225
}
226-
227-
@Test
228-
public void columnWithTallAndWideCellPackingTest() {
229-
Grid grid = new Grid(3, 3, GridFlow.COLUMN);
230-
GridCell cell1 = new GridCell(new TextRenderer(new Text("One")));
231-
GridCell tallCell = new GridCell(new TextRenderer(new Text("Two")));
232-
tallCell.getGridArea().setHeight(2);
233-
GridCell cell3 = new GridCell(new TextRenderer(new Text("Three")));
234-
GridCell cell4 = new GridCell(new TextRenderer(new Text("Four")));
235-
cell4.getGridArea().setWidth(2);
236-
GridCell cell5 = new GridCell(new TextRenderer(new Text("Five")));
237-
GridCell cell6 = new GridCell(new TextRenderer(new Text("Six")));
238-
grid.addCell(cell1);
239-
grid.addCell(tallCell);
240-
grid.addCell(cell3);
241-
grid.addCell(cell4);
242-
grid.addCell(cell5);
243-
grid.addCell(cell6);
244-
Assert.assertEquals(cell1, grid.getRows()[0][0]);
245-
Assert.assertEquals(tallCell, grid.getRows()[1][0]);
246-
Assert.assertEquals(tallCell, grid.getRows()[2][0]);
247-
Assert.assertEquals(cell3, grid.getRows()[0][1]);
248-
Assert.assertEquals(cell4, grid.getRows()[1][1]);
249-
Assert.assertEquals(cell4, grid.getRows()[1][2]);
250-
Assert.assertEquals(cell5, grid.getRows()[2][1]);
251-
Assert.assertEquals(cell6, grid.getRows()[0][2]);
252-
}
253226
}

0 commit comments

Comments
 (0)