Skip to content

Commit a8f9bf5

Browse files
committed
Update table layout algorithms
DEVSIX-1252
1 parent 4890f99 commit a8f9bf5

File tree

4 files changed

+80
-59
lines changed

4 files changed

+80
-59
lines changed

io/src/main/java/com/itextpdf/io/font/FontEncoding.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ public class FontEncoding implements Serializable {
8585

8686
protected FontEncoding() {
8787
unicodeToCode = new IntHashtable(256);
88-
codeToUnicode = new int[256];
89-
ArrayUtil.fillWithValue(codeToUnicode, -1);
88+
codeToUnicode = ArrayUtil.fillWithValue(new int[256], -1);
9089
unicodeDifferences = new IntHashtable(256);
9190
fontSpecific = false;
9291
}

io/src/main/java/com/itextpdf/io/util/ArrayUtil.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,18 @@ public static int hashCode(byte[] a) {
8383
return result;
8484
}
8585

86-
public static void fillWithValue(int[] a, int value) {
86+
public static int[] fillWithValue(int[] a, int value) {
8787
for (int i = 0; i < a.length; i++) {
8888
a[i] = value;
8989
}
90+
return a;
91+
}
92+
93+
public static float[] fillWithValue(float[] a, float value) {
94+
for (int i = 0; i < a.length; i++) {
95+
a[i] = value;
96+
}
97+
return a;
9098
}
9199

92100
public static <T> void fillWithValue(T[] a, T value) {

layout/src/main/java/com/itextpdf/layout/element/Table.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,17 +260,19 @@ private static boolean hasOnlyPercents(UnitValue[] columnWidths) {
260260
private static UnitValue[] normalizeColumnWidths(float[] pointColumnWidths) {
261261
UnitValue[] normalized = new UnitValue[pointColumnWidths.length];
262262
for (int i = 0; i < normalized.length; i++) {
263-
normalized[i] = UnitValue.createPointValue(pointColumnWidths[i]);
263+
if (pointColumnWidths[i] >= 0) {
264+
normalized[i] = UnitValue.createPointValue(pointColumnWidths[i]);
265+
}
264266
}
265267
return normalized;
266268
}
267269

268270
private static UnitValue[] normalizeColumnWidths(UnitValue[] unitColumnWidths) {
269271
UnitValue[] normalized = new UnitValue[unitColumnWidths.length];
270272
for (int i = 0; i < unitColumnWidths.length; i++) {
271-
normalized[i] = unitColumnWidths[i] != null
273+
normalized[i] = unitColumnWidths[i] != null && unitColumnWidths[i].getValue() >= 0
272274
? new UnitValue(unitColumnWidths[i])
273-
: UnitValue.createPointValue(-1);
275+
: null;
274276
}
275277
return normalized;
276278
}

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

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ This file is part of the iText (R) project.
4343
package com.itextpdf.layout.renderer;
4444

4545
import com.itextpdf.io.LogMessageConstant;
46+
import com.itextpdf.io.util.ArrayUtil;
4647
import com.itextpdf.layout.border.Border;
4748
import com.itextpdf.layout.element.Table;
4849
import com.itextpdf.layout.minmaxwidth.MinMaxWidthUtils;
@@ -94,11 +95,12 @@ float[] autoLayout(float[] minWidths, float[] maxWidths) {
9495

9596
//region Process cells
9697

97-
boolean[] minColumns = new boolean[numberOfColumns];
9898
for (CellInfo cell : cells) {
99-
//NOTE in automatic layout algorithm percents have higher priority
100-
UnitValue cellWidth = cell.getWidth();
101-
if (cellWidth != null && cellWidth.getValue() >= 0) {
99+
// For automatic layout algorithm percents have higher priority
100+
// value must be > 0, while for fixed layout >= 0
101+
UnitValue cellWidth = getCellWidth(cell.getCell(), false);
102+
if (cellWidth != null) {
103+
assert cellWidth.getValue() > 0;
102104
if (cellWidth.isPercentValue()) {
103105
//cellWidth has percent value
104106
if (cell.getColspan() == 1) {
@@ -132,50 +134,57 @@ float[] autoLayout(float[] minWidths, float[] maxWidths) {
132134
}
133135
} else {
134136
//cellWidth has point value
135-
if (cell.getCol() == 1) {
137+
if (cell.getColspan() == 1) {
136138
if (!widths[cell.getCol()].isPercent) {
137-
widths[cell.getCol()].setPoints(cellWidth.getValue()).setFixed(true);
138-
if (widths[cell.getCol()].hasCollision()) {
139-
minColumns[cell.getCol()] = true;
139+
if (widths[cell.getCol()].min <= cellWidth.getValue()) {
140+
widths[cell.getCol()].setPoints(cellWidth.getValue()).setFixed(true);
141+
} else {
142+
widths[cell.getCol()].setPoints(widths[cell.getCol()].min);
140143
}
141144
}
142145
} else {
143146
int flexibleCols = 0;
144-
float colspanRemain = cellWidth.getValue();
147+
float remainWidth = cellWidth.getValue();
145148
for (int i = cell.getCol(); i < cell.getCol() + cell.getColspan(); i++) {
146149
if (!widths[i].isPercent) {
147-
colspanRemain -= widths[i].width;
148-
if (!widths[i].isFixed){
150+
remainWidth -= widths[i].width;
151+
if (!widths[i].isFixed) {
149152
flexibleCols++;
150153
}
151154
} else {
152-
colspanRemain = -1;
155+
// if any col has percent value, we cannot predict remaining width.
156+
remainWidth = 0;
153157
break;
154158
}
155159
}
156-
if (colspanRemain > 0) {
160+
if (remainWidth > 0) {
161+
int[] flexibleColIndexes = ArrayUtil.fillWithValue(new int[cell.getColspan()], -1);
157162
if (flexibleCols > 0) {
158163
// check min width in columns
159164
for (int i = cell.getCol(); i < cell.getCol() + cell.getColspan(); i++) {
160-
if (widths[i].isFlexible() && widths[i].checkCollision(colspanRemain / flexibleCols)) {
161-
widths[i].setPoints(widths[i].min).setFixed(true);
162-
colspanRemain -= widths[i].min;
165+
if (!widths[i].isFlexible())
166+
continue;
167+
if (widths[i].min > widths[i].width + remainWidth / flexibleCols) {
168+
widths[i].resetPoints(widths[i].min);
169+
remainWidth -= widths[i].min - widths[i].width;
163170
flexibleCols--;
164-
if (colspanRemain <= 0 || flexibleCols <= 0) {
171+
if (flexibleCols == 0 || remainWidth <= 0) {
165172
break;
166173
}
174+
} else {
175+
flexibleColIndexes[i - cell.getCol()] = i;
167176
}
168177
}
169-
if (colspanRemain > 0 && flexibleCols > 0) {
170-
for (int k = cell.getCol(); k < cell.getCol() + cell.getColspan(); k++) {
171-
if (widths[k].isFlexible()) {
172-
widths[k].addPoints(colspanRemain / flexibleCols).setFixed(true);
178+
if (flexibleCols > 0 && remainWidth > 0) {
179+
for (int i = 0; i < flexibleColIndexes.length; i++) {
180+
if (flexibleColIndexes[i] >= 0) {
181+
widths[flexibleColIndexes[i]].addPoints(remainWidth / flexibleCols).setFixed(true);
173182
}
174183
}
175184
}
176185
} else {
177186
for (int i = cell.getCol(); i < cell.getCol() + cell.getColspan(); i++) {
178-
widths[i].addPoints(colspanRemain / cell.getColspan());
187+
widths[i].addPoints(remainWidth / cell.getColspan());
179188
}
180189
}
181190
}
@@ -200,12 +209,6 @@ float[] autoLayout(float[] minWidths, float[] maxWidths) {
200209
}
201210
}
202211
}
203-
for (int col = 0; col < minColumns.length; col++) {
204-
if (minColumns[col] && !widths[col].isPercent && widths[col].isFixed && widths[col].hasCollision()) {
205-
minSum += widths[col].min - widths[col].width;
206-
widths[col].setPoints(widths[col].min);
207-
}
208-
}
209212

210213
//endregion
211214

@@ -445,11 +448,16 @@ float[] fixedLayout() {
445448
if (columnWidths[i] == -1) {
446449
CellRenderer cell = firtsRow[i];
447450
if (cell != null) {
448-
Float cellWidth = cell.retrieveUnitValue(tableWidth, Property.WIDTH);
449-
if (cellWidth != null && cellWidth >= 0) {
451+
UnitValue cellWidth = getCellWidth(cell, true);
452+
if (cellWidth != null) {
453+
assert cellWidth.getValue() >= 0;
454+
float width = cellWidth.getValue();
455+
if (cellWidth.isPercentValue()) {
456+
width = tableWidth * width / 100;
457+
}
450458
int colspan = cell.getModelElement().getColspan();
451459
for (int j = 0; j < colspan; j++) {
452-
columnWidths[i + j] = (float) cellWidth / colspan;
460+
columnWidths[i + j] = width / colspan;
453461
}
454462
remainWidth -= columnWidths[i];
455463
processedColumns++;
@@ -618,11 +626,13 @@ private static class ColumnWidthData {
618626

619627
ColumnWidthData setPoints(float width) {
620628
assert !isPercent;
629+
assert this.min <= width;
621630
this.width = Math.max(this.width, width);
622631
return this;
623632
}
624633

625634
ColumnWidthData resetPoints(float width) {
635+
assert this.min <= width;
626636
this.width = width;
627637
this.isPercent = false;
628638
return this;
@@ -673,12 +683,12 @@ boolean hasCollision() {
673683
/**
674684
* Check collusion between min value and available point width.
675685
*
676-
* @param availableWidth additional available point width.
686+
* @param additional additional available point width.
677687
* @return true, if {@link #min} greater than ({@link #width} + additionalWidth).
678688
*/
679-
boolean checkCollision(float availableWidth) {
689+
boolean checkCollision(float additional) {
680690
assert !isPercent;
681-
return min > width + availableWidth;
691+
return min > width + additional;
682692
}
683693

684694
@Override
@@ -692,6 +702,27 @@ public String toString() {
692702
}
693703
}
694704

705+
//TODO DEVSIX-1174, box-sizing property
706+
UnitValue getCellWidth(CellRenderer cell, boolean zeroIsValid) {
707+
UnitValue widthValue = cell.<UnitValue>getProperty(Property.WIDTH);
708+
if (widthValue == null || widthValue.getValue() < 0) return null;
709+
if (!zeroIsValid && widthValue.getValue() == 0) return null;
710+
if (widthValue == null || widthValue.isPercentValue()) {
711+
return widthValue;
712+
} else {
713+
Border[] borders = cell.getBorders();
714+
if (borders[1] != null) {
715+
widthValue.setValue(widthValue.getValue() + borders[1].getWidth() / 2);
716+
}
717+
if (borders[3] != null) {
718+
widthValue.setValue(widthValue.getValue() + borders[3].getWidth() / 2);
719+
}
720+
float[] paddings = cell.getPaddings();
721+
widthValue.setValue(widthValue.getValue() + paddings[1] + paddings[3]);
722+
return widthValue;
723+
}
724+
}
725+
695726
private static class CellInfo implements Comparable<CellInfo> {
696727
static final byte HEADER = 1;
697728
static final byte BODY = 2;
@@ -725,25 +756,6 @@ int getRowspan() {
725756
return cell.getModelElement().getRowspan();
726757
}
727758

728-
//TODO DEVSIX-1057, DEVSIX-1021
729-
UnitValue getWidth() {
730-
UnitValue widthValue = cell.<UnitValue>getProperty(Property.WIDTH);
731-
if (widthValue == null || widthValue.isPercentValue()) {
732-
return widthValue;
733-
} else {
734-
Border[] borders = cell.getBorders();
735-
if (borders[1] != null) {
736-
widthValue.setValue(widthValue.getValue() + borders[1].getWidth() / 2);
737-
}
738-
if (borders[3] != null) {
739-
widthValue.setValue(widthValue.getValue() + borders[3].getWidth() / 2);
740-
}
741-
float[] paddings = cell.getPaddings();
742-
widthValue.setValue(widthValue.getValue() + paddings[1] + paddings[3]);
743-
return widthValue;
744-
}
745-
}
746-
747759
@Override
748760
public int compareTo(CellInfo o) {
749761
if (getColspan() == 1 ^ o.getColspan() == 1) {

0 commit comments

Comments
 (0)