Skip to content

Commit d8aab03

Browse files
IdamkinIitext-teamcity
authored andcommitted
Fix bug with lost content on table's split
The content was lost because we were replacing row's content in the overflow render and that affects original renderer because overflow renderer was using sub list of table rows. Now we use wrapper that make copy of row (once) on cell replacement. DEVSIX-1320 Autoported commit. Original commit hash: [f45a9c4]
1 parent d3469fa commit d8aab03

File tree

4 files changed

+72
-33
lines changed

4 files changed

+72
-33
lines changed

itext.tests/itext.layout.tests/itext/layout/TableTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1815,7 +1815,7 @@ public virtual void FixedPositionTest01() {
18151815
/// <exception cref="System.IO.IOException"/>
18161816
/// <exception cref="System.Exception"/>
18171817
[NUnit.Framework.Test]
1818-
[NUnit.Framework.Ignore("DEVSIX-1320")]
1818+
[LogMessage(iText.IO.LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)]
18191819
public virtual void NestedTableLostContent() {
18201820
// When the test was created, only first line of text was displayed on the first page
18211821
String testName = "nestedTableLostContent.pdf";
Binary file not shown.

itext/itext.layout/itext/layout/renderer/TableRenderer.cs

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
605605
marginsCollapseHandler.EndMarginsCollapse(layoutBox);
606606
}
607607
iText.Layout.Renderer.TableRenderer[] splitResult = Split(row, hasContent, cellWithBigRowspanAdded);
608+
TableRenderer.OverflowRowsWrapper overflowRows = new TableRenderer.OverflowRowsWrapper(splitResult[1]);
608609
// delete #layout() related properties
609610
if (null != headerRenderer || null != footerRenderer) {
610611
if (null != headerRenderer || tableModel.IsEmpty()) {
@@ -626,25 +627,28 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
626627
if (splits[col].GetStatus() != LayoutResult.NOTHING && (hasContent || cellWithBigRowspanAdded)) {
627628
childRenderers.Add(cellSplit);
628629
}
629-
LayoutArea cellOccupiedArea = splitResult[1].rows[0][col].GetOccupiedArea();
630+
LayoutArea cellOccupiedArea = currentRow[col].GetOccupiedArea();
630631
if (hasContent || cellWithBigRowspanAdded || splits[col].GetStatus() == LayoutResult.NOTHING) {
631632
CellRenderer cellOverflow = (CellRenderer)splits[col].GetOverflowRenderer();
632-
splitResult[1].rows[0][col] = null;
633-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col] = (CellRenderer)cellOverflow.SetParent(splitResult
634-
[1]);
633+
CellRenderer originalCell = currentRow[col];
634+
currentRow[col] = null;
635+
rows[targetOverflowRowIndex[col]][col] = originalCell;
636+
overflowRows.SetCell(0, col, null);
637+
overflowRows.SetCell(targetOverflowRowIndex[col] - row, col, (CellRenderer)cellOverflow.SetParent(splitResult
638+
[1]));
635639
}
636640
else {
637-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col] = (CellRenderer)splitResult[1].rows[0][col].SetParent
638-
(splitResult[1]);
641+
overflowRows.SetCell(targetOverflowRowIndex[col] - row, col, (CellRenderer)currentRow[col].SetParent(splitResult
642+
[1]));
639643
}
640-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col].occupiedArea = cellOccupiedArea;
644+
overflowRows.GetCell(targetOverflowRowIndex[col] - row, col).occupiedArea = cellOccupiedArea;
641645
}
642646
else {
643-
if (splitResult[1].rows[0][col] != null) {
647+
if (currentRow[col] != null) {
644648
if (hasContent) {
645-
rowspans[col] = ((Cell)splitResult[1].rows[0][col].GetModelElement()).GetRowspan();
649+
rowspans[col] = ((Cell)currentRow[col].GetModelElement()).GetRowspan();
646650
}
647-
bool isBigRowspannedCell = 1 != ((Cell)splitResult[1].rows[0][col].GetModelElement()).GetRowspan();
651+
bool isBigRowspannedCell = 1 != ((Cell)currentRow[col].GetModelElement()).GetRowspan();
648652
if (hasContent || isBigRowspannedCell) {
649653
columnsWithCellToBeEnlarged[col] = true;
650654
}
@@ -659,40 +663,43 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
659663
}
660664
for (col = 0; col < numberOfColumns; col++) {
661665
if (columnsWithCellToBeEnlarged[col]) {
662-
LayoutArea cellOccupiedArea = splitResult[1].rows[0][col].GetOccupiedArea();
666+
LayoutArea cellOccupiedArea = currentRow[col].GetOccupiedArea();
663667
if (1 == minRowspan) {
664668
// Here we use the same cell, but create a new renderer which doesn't have any children,
665669
// therefore it won't have any content.
666-
Cell overflowCell = ((Cell)splitResult[1].rows[0][col].GetModelElement()).Clone(true);
670+
Cell overflowCell = ((Cell)currentRow[col].GetModelElement()).Clone(true);
667671
// we will change properties
668-
splitResult[1].rows[0][col].isLastRendererForModelElement = false;
669-
childRenderers.Add(splitResult[1].rows[0][col]);
670-
splitResult[1].rows[0][col] = null;
671-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col] = (CellRenderer)overflowCell.GetRenderer().SetParent
672-
(this);
673-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col].DeleteProperty(Property.HEIGHT);
674-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col].DeleteProperty(Property.MIN_HEIGHT);
675-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col].DeleteProperty(Property.MAX_HEIGHT);
672+
CellRenderer originalCellRenderer = currentRow[col];
673+
currentRow[col].isLastRendererForModelElement = false;
674+
childRenderers.Add(currentRow[col]);
675+
currentRow[col] = null;
676+
rows[targetOverflowRowIndex[col]][col] = originalCellRenderer;
677+
overflowRows.SetCell(0, col, null);
678+
overflowRows.SetCell(targetOverflowRowIndex[col] - row, col, (CellRenderer)overflowCell.GetRenderer().SetParent
679+
(this));
680+
overflowRows.GetCell(targetOverflowRowIndex[col] - row, col).DeleteProperty(Property.HEIGHT);
681+
overflowRows.GetCell(targetOverflowRowIndex[col] - row, col).DeleteProperty(Property.MIN_HEIGHT);
682+
overflowRows.GetCell(targetOverflowRowIndex[col] - row, col).DeleteProperty(Property.MAX_HEIGHT);
676683
}
677684
else {
678-
childRenderers.Add(splitResult[1].rows[0][col]);
685+
childRenderers.Add(currentRow[col]);
679686
// shift all cells in the column up
680687
int i = row;
681688
for (; i < row + minRowspan && i + 1 < rows.Count && splitResult[1].rows[i + 1 - row][col] != null; i++) {
682-
splitResult[1].rows[i - row][col] = splitResult[1].rows[i + 1 - row][col];
683-
splitResult[1].rows[i + 1 - row][col] = null;
689+
overflowRows.SetCell(i - row, col, splitResult[1].rows[i + 1 - row][col]);
690+
overflowRows.SetCell(i + 1 - row, col, null);
684691
}
685692
// the number of cells behind is less then minRowspan-1
686693
// so we should process the last cell in the column as in the case 1 == minRowspan
687694
if (i != row + minRowspan - 1 && null != rows[i][col]) {
688695
Cell overflowCell = ((Cell)rows[i][col].GetModelElement());
689-
splitResult[1].rows[i - row][col].isLastRendererForModelElement = false;
690-
splitResult[1].rows[i - row][col] = null;
691-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col] = (CellRenderer)overflowCell.GetRenderer().SetParent
692-
(this);
696+
overflowRows.GetCell(i - row, col).isLastRendererForModelElement = false;
697+
overflowRows.SetCell(i - row, col, null);
698+
overflowRows.SetCell(targetOverflowRowIndex[col] - row, col, (CellRenderer)overflowCell.GetRenderer().SetParent
699+
(this));
693700
}
694701
}
695-
splitResult[1].rows[targetOverflowRowIndex[col] - row][col].occupiedArea = cellOccupiedArea;
702+
overflowRows.GetCell(targetOverflowRowIndex[col] - row, col).occupiedArea = cellOccupiedArea;
696703
}
697704
}
698705
}
@@ -719,9 +726,12 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
719726
foreach (KeyValuePair<int, int?> entry in rowMoves) {
720727
// Move the cell back to its row if there was no actual split
721728
if (null == splitResult[1].rows[(int)entry.Value - splitResult[0].rows.Count][entry.Key]) {
722-
splitResult[1].rows[(int)entry.Value - splitResult[0].rows.Count][entry.Key] = splitResult[1].rows[row - splitResult
723-
[0].rows.Count][entry.Key];
724-
splitResult[1].rows[row - splitResult[0].rows.Count][entry.Key] = null;
729+
CellRenderer originalCellRenderer = rows[row][entry.Key];
730+
CellRenderer overflowCellRenderer = splitResult[1].rows[row - splitResult[0].rows.Count][entry.Key];
731+
rows[(int)entry.Value][entry.Key] = originalCellRenderer;
732+
rows[row][entry.Key] = null;
733+
overflowRows.SetCell((int)entry.Value - splitResult[0].rows.Count, entry.Key, overflowCellRenderer);
734+
overflowRows.SetCell(row - splitResult[0].rows.Count, entry.Key, null);
725735
}
726736
}
727737
if ((IsKeepTogether() && 0 == lastFlushedRowBottomBorder.Count) && !true.Equals(GetPropertyAsBoolean(Property
@@ -1592,5 +1602,34 @@ public CellRendererInfo(CellRenderer cellRenderer, int column, int finishRow) {
15921602
this.finishRowInd = finishRow;
15931603
}
15941604
}
1605+
1606+
/// <summary>Utility class that copies overflow renderer rows on cell replacement so it won't affect original renderer
1607+
/// </summary>
1608+
private class OverflowRowsWrapper {
1609+
private TableRenderer overflowRenderer;
1610+
1611+
private Dictionary<int, bool?> isRowReplaced = new Dictionary<int, bool?>();
1612+
1613+
private bool isReplaced = false;
1614+
1615+
public OverflowRowsWrapper(TableRenderer overflowRenderer) {
1616+
this.overflowRenderer = overflowRenderer;
1617+
}
1618+
1619+
public virtual CellRenderer GetCell(int row, int col) {
1620+
return overflowRenderer.rows[row][col];
1621+
}
1622+
1623+
public virtual CellRenderer SetCell(int row, int col, CellRenderer newCell) {
1624+
if (!isReplaced) {
1625+
overflowRenderer.rows = new List<CellRenderer[]>(overflowRenderer.rows);
1626+
isReplaced = true;
1627+
}
1628+
if (!true.Equals(isRowReplaced.Get(row))) {
1629+
overflowRenderer.rows[row] = (CellRenderer[])overflowRenderer.rows[row].Clone();
1630+
}
1631+
return overflowRenderer.rows[row][col] = newCell;
1632+
}
1633+
}
15951634
}
15961635
}

port-hash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
404045c23bb7d2ecf1fbcc8bf9c66073f253456d
1+
f45a9c43a848e9ee0f68439c8342aa1cf87f0529

0 commit comments

Comments
 (0)