Skip to content

Commit

Permalink
Fix empty row elimination logic
Browse files Browse the repository at this point in the history
DEVSIX-6095

Autoported commit.
Original commit hash: [25cfbd9d0]
  • Loading branch information
vitali-pr committed Apr 16, 2024
1 parent 16d6743 commit 4b105e0
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 58 deletions.
30 changes: 21 additions & 9 deletions itext.tests/itext.layout.tests/itext/layout/TableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1696,7 +1696,6 @@ public virtual void TableWithEmptyLastRowTest() {
}

[NUnit.Framework.Test]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING)]
public virtual void TableWithEmptyRowsBetweenFullRowsTest() {
String testName = "tableWithEmptyRowsBetweenFullRowsTest.pdf";
String outFileName = destinationFolder + testName;
Expand All @@ -1716,8 +1715,6 @@ public virtual void TableWithEmptyRowsBetweenFullRowsTest() {
}

[NUnit.Framework.Test]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, Count = 2
)]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE)]
public virtual void TableWithEmptyRowAfterJustOneCellTest() {
String testName = "tableWithEmptyRowAfterJustOneCellTest.pdf";
Expand All @@ -1739,8 +1736,6 @@ public virtual void TableWithEmptyRowAfterJustOneCellTest() {
}

[NUnit.Framework.Test]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, Count = 39
)]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE)]
public virtual void TableWithAlternatingRowsTest() {
String testName = "tableWithAlternatingRowsTest.pdf";
Expand Down Expand Up @@ -1782,8 +1777,27 @@ public virtual void ColoredTableWithColoredCellsTest() {
}

[NUnit.Framework.Test]
[LogMessage(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING, Count = 2
)]
public virtual void TableWithEmptyRowsAndSpansTest() {
String testName = "tableWithEmptyRowsAndSpansTest.pdf";
String outFileName = destinationFolder + testName;
String cmpFileName = sourceFolder + "cmp_" + testName;
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
Document doc = new Document(pdfDoc);
Table table = new Table(UnitValue.CreatePercentArray(new float[] { 30, 30, 30 }));
table.AddCell(new Cell().Add(new Paragraph("Hello")));
table.AddCell(new Cell().Add(new Paragraph("Lovely")));
table.AddCell(new Cell().Add(new Paragraph("World")));
StartSeveralEmptyRows(table);
table.AddCell(new Cell(2, 2).Add(new Paragraph("Hello")));
table.AddCell(new Cell().Add(new Paragraph("Lovely")));
table.AddCell(new Cell().Add(new Paragraph("World")));
doc.Add(table);
doc.Close();
NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, destinationFolder
, testName + "_diff"));
}

[NUnit.Framework.Test]
public virtual void TableWithEmptyRowsAndSeparatedBordersTest() {
String testName = "tableWithEmptyRowsAndSeparatedBordersTest.pdf";
String outFileName = destinationFolder + testName;
Expand All @@ -1804,8 +1818,6 @@ public virtual void TableWithEmptyRowsAndSeparatedBordersTest() {
}

[NUnit.Framework.Test]
// TODO DEVSIX-6020:Border-collapsing doesn't work in case startNewRow has been called
[LogMessage(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING)]
public virtual void TableWithCollapsedBordersTest() {
String testName = "tableWithCollapsedBordersTest.pdf";
String outFileName = destinationFolder + testName;
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,10 @@ protected internal override void BuildBordersArrays(CellRenderer cell, int row,
}
while (j > 0 && rows.Count != nextCellRow && (j + (int)rows[nextCellRow][j].GetPropertyAsInteger(Property.
COLSPAN) != col || (int)nextCellRow - rows[(int)nextCellRow][j].GetPropertyAsInteger(Property.ROWSPAN)
+ 1 + rowspansToDeduct[j] != row));
+ 1 != row));
// process only valid cells which hasn't been processed yet
if (j >= 0 && nextCellRow != rows.Count && nextCellRow > row) {
CellRenderer nextCell = rows[nextCellRow][j];
nextCell.SetProperty(Property.ROWSPAN, ((int)nextCell.GetPropertyAsInteger(Property.ROWSPAN)) - rowspansToDeduct
[j]);
int nextCellColspan = (int)nextCell.GetPropertyAsInteger(Property.COLSPAN);
for (int i = j; i < j + nextCellColspan; i++) {
rowspansToDeduct[i] = 0;
}
BuildBordersArrays(nextCell, nextCellRow, true);
}
}
Expand Down Expand Up @@ -309,12 +303,6 @@ protected internal override void BuildBordersArrays(CellRenderer cell, int row,
}
if (nextCellRow != rows.Count) {
CellRenderer nextCell = rows[nextCellRow][col + currCellColspan];
nextCell.SetProperty(Property.ROWSPAN, ((int)nextCell.GetPropertyAsInteger(Property.ROWSPAN)) - rowspansToDeduct
[col + currCellColspan]);
int nextCellColspan = (int)nextCell.GetPropertyAsInteger(Property.COLSPAN);
for (int i = col + currCellColspan; i < col + currCellColspan + nextCellColspan; i++) {
rowspansToDeduct[i] = 0;
}
BuildBordersArrays(nextCell, nextCellRow, true);
}
}
Expand Down
101 changes: 66 additions & 35 deletions itext/itext.layout/itext/layout/renderer/TableBorders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ protected internal abstract iText.Layout.Renderer.TableBorders ApplyCellIndents(
protected internal abstract float GetCellVerticalAddition(float[] indents);

// endregion
[System.ObsoleteAttribute(@"Remove rowspansToDeduct parameter which is not used anymore.")]
protected internal abstract void BuildBordersArrays(CellRenderer cell, int row, int col, int[] rowspansToDeduct
);

Expand All @@ -166,34 +167,24 @@ protected internal abstract iText.Layout.Renderer.TableBorders UpdateBordersOnNe
// endregion
protected internal virtual iText.Layout.Renderer.TableBorders ProcessAllBordersAndEmptyRows() {
CellRenderer[] currentRow;
int[] rowspansToDeduct = new int[numberOfColumns];
int numOfRowsToRemove = 0;
if (!rows.IsEmpty()) {
for (int row = startRow - largeTableIndexOffset; row <= finishRow - largeTableIndexOffset; row++) {
currentRow = rows[row];
bool hasCells = false;
for (int col = 0; col < numberOfColumns; col++) {
if (null != currentRow[col]) {
int colspan = (int)currentRow[col].GetPropertyAsInteger(Property.COLSPAN);
if (rowspansToDeduct[col] > 0) {
int rowspan = (int)currentRow[col].GetPropertyAsInteger(Property.ROWSPAN) - rowspansToDeduct[col];
if (rowspan < 1) {
ILogger logger = ITextLogManager.GetLogger(typeof(TableRenderer));
logger.LogWarning(iText.IO.Logs.IoLogMessageConstant.UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING);
rowspan = 1;
}
currentRow[col].SetProperty(Property.ROWSPAN, rowspan);
if (0 != numOfRowsToRemove) {
RemoveRows(row - numOfRowsToRemove, numOfRowsToRemove);
row -= numOfRowsToRemove;
numOfRowsToRemove = 0;
}
if (0 != numOfRowsToRemove) {
// Decrease rowspans if necessary
UpdateRowspanForNextNonEmptyCellInEachColumn(numOfRowsToRemove, row);
// Remove empty rows
RemoveRows(row - numOfRowsToRemove, numOfRowsToRemove);
row -= numOfRowsToRemove;
numOfRowsToRemove = 0;
}
BuildBordersArrays(currentRow[col], row, col, rowspansToDeduct);
BuildBordersArrays(currentRow[col], row, col, null);
hasCells = true;
for (int i = 0; i < colspan; i++) {
rowspansToDeduct[col + i] = 0;
}
int colspan = (int)currentRow[col].GetPropertyAsInteger(Property.COLSPAN);
col += colspan - 1;
}
else {
Expand All @@ -204,17 +195,14 @@ protected internal virtual iText.Layout.Renderer.TableBorders ProcessAllBordersA
}
if (!hasCells) {
if (row == rows.Count - 1) {
RemoveRows(row - rowspansToDeduct[0], rowspansToDeduct[0]);
RemoveRows(row - numOfRowsToRemove, numOfRowsToRemove);
// delete current row
rows.JRemoveAt(row - rowspansToDeduct[0]);
rows.JRemoveAt(row - numOfRowsToRemove);
SetFinishRow(finishRow - 1);
ILogger logger = ITextLogManager.GetLogger(typeof(TableRenderer));
logger.LogWarning(iText.IO.Logs.IoLogMessageConstant.LAST_ROW_IS_NOT_COMPLETE);
}
else {
for (int i = 0; i < numberOfColumns; i++) {
rowspansToDeduct[i]++;
}
numOfRowsToRemove++;
}
}
Expand All @@ -226,17 +214,6 @@ protected internal virtual iText.Layout.Renderer.TableBorders ProcessAllBordersA
return this;
}

private void RemoveRows(int startRow, int numOfRows) {
for (int row = startRow; row < startRow + numOfRows; row++) {
rows.JRemoveAt(startRow);
horizontalBorders.JRemoveAt(startRow + 1);
for (int j = 0; j <= numberOfColumns; j++) {
verticalBorders[j].JRemoveAt(startRow + 1);
}
}
SetFinishRow(finishRow - numOfRows);
}

// region init
protected internal virtual iText.Layout.Renderer.TableBorders InitializeBorders() {
IList<Border> tempBorders;
Expand Down Expand Up @@ -419,6 +396,60 @@ public virtual float[] GetCellBorderIndents(int row, int col, int rowspan, int c
}
return indents;
}

// endregion
private void RemoveRows(int startRow, int numOfRows) {
for (int row = startRow; row < startRow + numOfRows; row++) {
rows.JRemoveAt(startRow);
horizontalBorders.JRemoveAt(startRow + 1);
for (int j = 0; j <= numberOfColumns; j++) {
verticalBorders[j].JRemoveAt(startRow + 1);
}
}
SetFinishRow(finishRow - numOfRows);
}

private void UpdateRowspanForNextNonEmptyCellInEachColumn(int numOfRowsToRemove, int row) {
// We go by columns in a current row which is not empty. For each column we look for
// a non-empty cell going up by rows (going down in a table). For each such cell we
// collect data to be able to analyze its rowspan.
// Iterate by columns
int c = 0;
while (c < numberOfColumns) {
int r = row;
CellRenderer[] cr = null;
// Look for non-empty cell in a column
while (r < rows.Count && (cr == null || cr[c] == null)) {
cr = rows[r];
++r;
}
// Found a cell
if (cr != null && cr[c] != null) {
CellRenderer cell = cr[c];
int origRowspan = (int)cell.GetPropertyAsInteger(Property.ROWSPAN);
int spansToRestore = 0;
// Here we analyze whether current cell's rowspan touches a non-empty row before
// numOfRowsToRemove. If it doesn't touch it we will need to 'restore' a few
// rowspans which is a difference between the current (non-empty) row and the row
// where we found non-empty cell for this column
if (row - numOfRowsToRemove < r - origRowspan) {
spansToRestore = r - row - 1;
}
int rowspan = origRowspan;
rowspan = rowspan - numOfRowsToRemove;
if (rowspan < 1) {
rowspan = 1;
}
rowspan += spansToRestore;
rowspan = Math.Min(rowspan, origRowspan);
cell.SetProperty(Property.ROWSPAN, rowspan);
int colspan = (int)cell.GetPropertyAsInteger(Property.COLSPAN);
c += colspan;
}
else {
++c;
}
}
}
}
}
2 changes: 1 addition & 1 deletion port-hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
daafb56864e655e3de3fbf76865c017b57edb51d
a57e64266d366bfcf87f8c3045b77a96db1cf373

0 comments on commit 4b105e0

Please sign in to comment.