From 6126bfc58c6ffaba179d675a93d425cfea0aa445 Mon Sep 17 00:00:00 2001 From: Dmitry Chubrick Date: Fri, 17 May 2024 22:05:03 +0000 Subject: [PATCH 1/2] Support CSS grid layout * Supported basic scenarios and essential properties, such as grid-auto\template-columns\rows * Only absolute values are supported, default sizing is min-content DEVSIX-8064 Autoported commit. Original commit hash: [b7150dce2] --- .../itext/layout/element/GridContainerTest.cs | 511 ++++++++++++++++++ .../itext/layout/renderer/GridCellUnitTest.cs | 84 +++ .../itext/layout/renderer/GridUnitTest.cs | 143 +++++ .../cmp_basicAutoColumnsTest.pdf | Bin 0 -> 1461 bytes .../cmp_basicAutoRowsTest.pdf | Bin 0 -> 5387 bytes .../cmp_basicThreeColumnsTest.pdf | Bin 0 -> 1442 bytes ...lumnsWithCustomColumnAndRowIndexesTest.pdf | Bin 0 -> 1465 bytes ...hreeColumnsWithCustomColumnIndexesTest.pdf | Bin 0 -> 1410 bytes ...icThreeColumnsWithCustomRowIndexesTest.pdf | Bin 0 -> 1392 bytes .../cmp_basicThreeColumnsWithFrAndPtTest.pdf | Bin 0 -> 1746 bytes .../cmp_basicThreeColumnsWithFrTest.pdf | Bin 0 -> 955 bytes ..._basicThreeColumnsWithPtAndPercentTest.pdf | Bin 0 -> 1499 bytes ...sicThreeColumnsWithReversedIndexesTest.pdf | Bin 0 -> 1456 bytes ..._basicThreeColumnsWithoutColumnEndTest.pdf | Bin 0 -> 1444 bytes .../cmp_bigCellMinContentTest.pdf | Bin 0 -> 1445 bytes .../cmp_fixedColumnRowGoesFirstTest.pdf | Bin 0 -> 1678 bytes .../cmp_thirdColumnNotLayoutedTest.pdf | Bin 0 -> 1429 bytes ..._threeColumnsWithAdjacentWideCellsTest.pdf | Bin 0 -> 1468 bytes ...eColumnsWithSquareAndVerticalCellsTest.pdf | Bin 0 -> 1498 bytes ...quareCellAndCellWithExplicitHeightTest.pdf | Bin 0 -> 1506 bytes ...CellWithSeveralNeighboursToTheLeftTest.pdf | Bin 0 -> 1476 bytes .../itext/layout/element/GridContainer.cs | 23 + .../LayoutExceptionMessageConstant.cs | 2 + .../itext/layout/properties/Property.cs | 18 +- .../itext/layout/renderer/Grid.cs | 394 ++++++++++++++ .../itext/layout/renderer/GridCell.cs | 163 ++++++ .../layout/renderer/GridContainerRenderer.cs | 371 +++++++++++++ .../itext/layout/renderer/GridSizer.cs | 260 +++++++++ port-hash | 2 +- 29 files changed, 1969 insertions(+), 2 deletions(-) create mode 100644 itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs create mode 100644 itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs create mode 100644 itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoColumnsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoRowsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomColumnIndexesTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrAndPtTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithPtAndPercentTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithReversedIndexesTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithoutColumnEndTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_bigCellMinContentTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_fixedColumnRowGoesFirstTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_thirdColumnNotLayoutedTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithAdjacentWideCellsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf create mode 100644 itext/itext.layout/itext/layout/element/GridContainer.cs create mode 100644 itext/itext.layout/itext/layout/renderer/Grid.cs create mode 100644 itext/itext.layout/itext/layout/renderer/GridCell.cs create mode 100644 itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs create mode 100644 itext/itext.layout/itext/layout/renderer/GridSizer.cs diff --git a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs new file mode 100644 index 0000000000..7c74856d93 --- /dev/null +++ b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs @@ -0,0 +1,511 @@ +using System; +using System.Collections.Generic; +using iText.Kernel.Colors; +using iText.Kernel.Pdf; +using iText.Kernel.Utils; +using iText.Layout; +using iText.Layout.Borders; +using iText.Layout.Exceptions; +using iText.Layout.Properties; +using iText.Test; + +namespace iText.Layout.Element { + [NUnit.Framework.Category("IntegrationTest")] + public class GridContainerTest : ExtendedITextTest { + public static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + .CurrentContext.TestDirectory) + "/resources/itext/layout/GridContainerTest/"; + + public static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory + + "/test/itext/layout/GridContainerTest/"; + + [NUnit.Framework.OneTimeSetUp] + public static void BeforeClass() { + CreateDestinationFolder(DESTINATION_FOLDER); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + for (int i = 0; i < 5; ++i) { + grid.Add(new Paragraph("Test" + i).SetBorder(border)); + } + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicAutoColumnsTest() { + String filename = DESTINATION_FOLDER + "basicAutoColumnsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicAutoColumnsTest.pdf"; + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_AUTO_COLUMNS, new UnitValue(UnitValue.POINT, 150.0f)); + for (int i = 0; i < 5; ++i) { + grid.Add(new Paragraph("Test" + i).SetBorder(border)); + } + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicAutoRowsTest() { + String filename = DESTINATION_FOLDER + "basicAutoRowsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicAutoRowsTest.pdf"; + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_AUTO_ROWS, new UnitValue(UnitValue.POINT, 100.0f)); + grid.Add(new Paragraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, " + + "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute " + "irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " + + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim " + + "id est laborum.").SetBorder(border)); + grid.Add(new Paragraph("test").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithCustomColumnIndexesTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnIndexesTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnIndexesTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One").SetBorder(border); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border)); + Paragraph paragraph3 = new Paragraph("Three").SetBorder(border); + paragraph3.SetProperty(Property.GRID_COLUMN_START, 2); + paragraph3.SetProperty(Property.GRID_COLUMN_END, 4); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void ThreeColumnsWithAdjacentWideCellsTest() { + String filename = DESTINATION_FOLDER + "threeColumnsWithAdjacentWideCellsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithAdjacentWideCellsTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + Paragraph paragraph2 = new Paragraph("Two"); + paragraph2.SetProperty(Property.GRID_COLUMN_START, 3); + paragraph2.SetProperty(Property.GRID_COLUMN_END, 5); + paragraph2.SetBorder(border); + grid.Add(paragraph2); + Paragraph paragraph3 = new Paragraph("Three"); + paragraph3.SetProperty(Property.GRID_COLUMN_START, 2); + paragraph3.SetProperty(Property.GRID_COLUMN_END, 4); + paragraph3.SetBorder(border); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithCustomRowIndexesTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomRowIndexesTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One").SetBorder(border); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border)); + Paragraph paragraph3 = new Paragraph("Three").SetBorder(border); + paragraph3.SetProperty(Property.GRID_ROW_START, 3); + paragraph3.SetProperty(Property.GRID_ROW_END, 4); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithCustomColumnAndRowIndexesTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border)); + grid.Add(new Paragraph("Three").SetBorder(border)); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithReversedIndexesTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithReversedIndexesTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithReversedIndexesTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 3); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 1); + paragraph1.SetProperty(Property.GRID_ROW_START, 3); + paragraph1.SetProperty(Property.GRID_ROW_END, 1); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + Paragraph paragraph2 = new Paragraph("Two"); + paragraph2.SetProperty(Property.GRID_ROW_START, 3); + paragraph2.SetProperty(Property.GRID_ROW_END, 1); + paragraph2.SetBorder(border); + grid.Add(paragraph2); + Paragraph paragraph3 = new Paragraph("Three"); + paragraph3.SetProperty(Property.GRID_COLUMN_START, 3); + paragraph3.SetProperty(Property.GRID_COLUMN_END, 1); + paragraph3.SetBorder(border); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithoutColumnEndTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithoutColumnEndTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithoutColumnEndTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_ROW_END, 2); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + Paragraph paragraph2 = new Paragraph("Two"); + paragraph2.SetProperty(Property.GRID_ROW_START, 2); + paragraph2.SetBorder(border); + grid.Add(paragraph2); + Paragraph paragraph3 = new Paragraph("Three"); + paragraph3.SetProperty(Property.GRID_COLUMN_START, 3); + paragraph3.SetBorder(border); + grid.Add(paragraph3); + Paragraph paragraph4 = new Paragraph("Four"); + paragraph4.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph4.SetBorder(border); + grid.Add(paragraph4); + grid.Add(new Paragraph("Five").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void FixedColumnRowGoesFirstTest() { + String filename = DESTINATION_FOLDER + "fixedColumnRowGoesFirstTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_fixedColumnRowGoesFirstTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + Paragraph paragraph2 = new Paragraph("Two\nTwo"); + paragraph2.SetProperty(Property.GRID_ROW_START, 1); + paragraph2.SetProperty(Property.GRID_ROW_END, 3); + paragraph2.SetBorder(border); + grid.Add(paragraph2); + grid.Add(new Paragraph("Three").SetBorder(border)); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + Paragraph paragraph6 = new Paragraph("Six"); + paragraph6.SetProperty(Property.GRID_COLUMN_START, 3); + paragraph6.SetBorder(border); + grid.Add(paragraph6); + Paragraph paragraph7 = new Paragraph("Seven"); + paragraph7.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph7.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph7.SetBorder(border); + grid.Add(paragraph7); + Paragraph paragraph8 = new Paragraph("Eight\nEight"); + paragraph8.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph8.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph8.SetProperty(Property.GRID_ROW_START, 4); + paragraph8.SetProperty(Property.GRID_ROW_END, 6); + paragraph8.SetBorder(border); + grid.Add(paragraph8); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void OverlapWithExistingColumnTest() { + String filename = DESTINATION_FOLDER + "overlapWithExistingColumnTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("Two"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 2); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 2); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + grid.Add(new Paragraph("Three").SetBorder(border)); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + Paragraph paragraph2 = new Paragraph("One"); + paragraph2.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph2.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph2.SetProperty(Property.GRID_ROW_START, 1); + paragraph2.SetProperty(Property.GRID_ROW_END, 3); + paragraph2.SetBorder(border); + grid.Add(paragraph2); + Exception e = NUnit.Framework.Assert.Catch(typeof(ArgumentException), () => document.Add(grid)); + NUnit.Framework.Assert.AreEqual(LayoutExceptionMessageConstant.INVALID_CELL_INDEXES, e.Message); + } + } + + //TODO DEVSIX-8324 + [NUnit.Framework.Test] + public virtual void BasicThreeColumnsWithPtAndPercentTest() { + String filename = DESTINATION_FOLDER + "basicThreeColumnsWithPtAndPercentTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithPtAndPercentTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.PERCENT, 15.0f)); + templateColumns.Add(new UnitValue(UnitValue.PERCENT, 50.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + for (int i = 0; i < 5; ++i) { + grid.Add(new Paragraph("Test" + i).SetBorder(border)); + } + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void ThirdColumnNotLayoutedTest() { + String filename = DESTINATION_FOLDER + "thirdColumnNotLayoutedTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_thirdColumnNotLayoutedTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + for (int i = 0; i < 5; ++i) { + grid.Add(new Paragraph("Test" + i).SetBorder(border)); + } + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void ThreeColumnsWithSquareAndVerticalCellsTest() { + String filename = DESTINATION_FOLDER + "threeColumnsWithSquareAndVerticalCellsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + paragraph1.SetBorder(border); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border)); + Paragraph paragraph3 = new Paragraph("Three"); + paragraph3.SetProperty(Property.GRID_ROW_START, 2); + paragraph3.SetProperty(Property.GRID_ROW_END, 4); + paragraph3.SetBorder(border); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border)); + grid.Add(new Paragraph("Five").SetBorder(border)); + grid.Add(new Paragraph("Six").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void ThreeColumnsWithSquareCellAndCellWithExplicitHeightTest() { + String filename = DESTINATION_FOLDER + "threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + paragraph1.SetBorder(border).SetBackgroundColor(ColorConstants.RED); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + grid.Add(new Paragraph("Three").SetBorder(border).SetBackgroundColor(ColorConstants.RED).SetHeight(100.0f) + ); + grid.Add(new Paragraph("Four").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + grid.Add(new Paragraph("Five").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void ThreeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest() { + String filename = DESTINATION_FOLDER + "threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); + Paragraph paragraph1 = new Paragraph("One"); + paragraph1.SetProperty(Property.GRID_COLUMN_START, 1); + paragraph1.SetProperty(Property.GRID_COLUMN_END, 3); + paragraph1.SetProperty(Property.GRID_ROW_START, 1); + paragraph1.SetProperty(Property.GRID_ROW_END, 3); + paragraph1.SetBorder(border).SetBackgroundColor(ColorConstants.RED); + grid.Add(paragraph1); + grid.Add(new Paragraph("Two").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + Paragraph paragraph3 = new Paragraph("Three"); + paragraph3.SetProperty(Property.GRID_ROW_START, 2); + paragraph3.SetProperty(Property.GRID_ROW_END, 4); + paragraph3.SetBorder(border).SetBackgroundColor(ColorConstants.RED); + grid.Add(paragraph3); + grid.Add(new Paragraph("Four").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + grid.Add(new Paragraph("Five").SetBorder(border).SetBackgroundColor(ColorConstants.RED)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void BigCellMinContentTest() { + String filename = DESTINATION_FOLDER + "bigCellMinContentTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_bigCellMinContentTest.pdf"; + SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.Add(new Paragraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore" + ).SetBorder(border)); + grid.Add(new Paragraph("test").SetBorder(border)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + } +} diff --git a/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs b/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs new file mode 100644 index 0000000000..e7f88fa316 --- /dev/null +++ b/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs @@ -0,0 +1,84 @@ +using iText.Layout.Element; +using iText.Layout.Properties; +using iText.Test; + +namespace iText.Layout.Renderer { + [NUnit.Framework.Category("UnitTest")] + public class GridCellUnitTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void CellWithOnlyGridRowStartTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_ROW_START, 3); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(2, cell.GetRowStart()); + NUnit.Framework.Assert.AreEqual(3, cell.GetRowEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithOnlyGridRowEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_ROW_END, 5); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(3, cell.GetRowStart()); + NUnit.Framework.Assert.AreEqual(4, cell.GetRowEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithGridRowStartAndEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_ROW_START, 2); + renderer.SetProperty(Property.GRID_ROW_END, 4); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(1, cell.GetRowStart()); + NUnit.Framework.Assert.AreEqual(3, cell.GetRowEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithOnlyGridColumnStartTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_COLUMN_START, 3); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(2, cell.GetColumnStart()); + NUnit.Framework.Assert.AreEqual(3, cell.GetColumnEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithOnlyGridColumnEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_COLUMN_END, 8); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(6, cell.GetColumnStart()); + NUnit.Framework.Assert.AreEqual(7, cell.GetColumnEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithGridColumnStartAndEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_COLUMN_START, 4); + renderer.SetProperty(Property.GRID_COLUMN_END, 7); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(3, cell.GetColumnStart()); + NUnit.Framework.Assert.AreEqual(6, cell.GetColumnEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithReversedColumnStartAndEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_COLUMN_START, 7); + renderer.SetProperty(Property.GRID_COLUMN_END, 4); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(3, cell.GetColumnStart()); + NUnit.Framework.Assert.AreEqual(6, cell.GetColumnEnd()); + } + + [NUnit.Framework.Test] + public virtual void CellWithReversedRowStartAndEndTest() { + IRenderer renderer = new TextRenderer(new Text("test")); + renderer.SetProperty(Property.GRID_ROW_START, 4); + renderer.SetProperty(Property.GRID_ROW_END, 2); + GridCell cell = new GridCell(renderer); + NUnit.Framework.Assert.AreEqual(1, cell.GetRowStart()); + NUnit.Framework.Assert.AreEqual(3, cell.GetRowEnd()); + } + } +} diff --git a/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs b/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs new file mode 100644 index 0000000000..64ebf25dcf --- /dev/null +++ b/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs @@ -0,0 +1,143 @@ +using iText.Kernel.Geom; +using iText.Layout.Element; +using iText.Layout.Properties; +using iText.Test; + +namespace iText.Layout.Renderer { + [NUnit.Framework.Category("UnitTest")] + public class GridUnitTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void GetClosestTopNeighborTest() { + Grid grid = new Grid(3, 3, false); + grid.AddCell(new GridCell(new TextRenderer(new Text("One")))); + grid.AddCell(new GridCell(new TextRenderer(new Text("Three")))); + IRenderer value = new TextRenderer(new Text("Two")); + value.SetProperty(Property.GRID_COLUMN_START, 2); + value.SetProperty(Property.GRID_ROW_START, 2); + GridCell cell = new GridCell(value); + grid.AddCell(cell); + NUnit.Framework.Assert.AreEqual(grid.GetRows()[0][0], grid.GetClosestTopNeighbor(cell)); + } + + [NUnit.Framework.Test] + public virtual void GetClosestLeftNeighborTest() { + Grid grid = new Grid(3, 3, false); + grid.AddCell(new GridCell(new TextRenderer(new Text("One")))); + IRenderer value = new TextRenderer(new Text("Two")); + value.SetProperty(Property.GRID_COLUMN_START, 2); + value.SetProperty(Property.GRID_ROW_START, 2); + GridCell cell = new GridCell(value); + grid.AddCell(cell); + NUnit.Framework.Assert.AreEqual(grid.GetRows()[0][0], grid.GetClosestLeftNeighbor(cell)); + } + + [NUnit.Framework.Test] + public virtual void GetUniqueCellsTest() { + Grid grid = new Grid(3, 3, false); + grid.AddCell(new GridCell(new TextRenderer(new Text("One")))); + IRenderer twoRenderer = new TextRenderer(new Text("Two")); + twoRenderer.SetProperty(Property.GRID_COLUMN_START, 2); + twoRenderer.SetProperty(Property.GRID_COLUMN_END, 4); + GridCell cell = new GridCell(twoRenderer); + grid.AddCell(cell); + grid.AddCell(new GridCell(new TextRenderer(new Text("Three")))); + grid.AddCell(new GridCell(new TextRenderer(new Text("Four")))); + NUnit.Framework.Assert.AreEqual(4, grid.GetUniqueGridCells(Grid.ROW_ORDER).Count); + } + + [NUnit.Framework.Test] + public virtual void IncreaseRowHeightTest() { + Grid grid = new Grid(3, 3, false); + GridCell cell1 = new GridCell(new TextRenderer(new Text("One"))); + cell1.SetLayoutArea(new Rectangle(50.0f, 50.0f)); + GridCell cell2 = new GridCell(new TextRenderer(new Text("Two"))); + cell2.SetLayoutArea(new Rectangle(50.0f, 50.0f)); + GridCell cell3 = new GridCell(new TextRenderer(new Text("Three"))); + cell3.SetLayoutArea(new Rectangle(50.0f, 50.0f)); + grid.AddCell(cell1); + grid.AddCell(cell2); + grid.AddCell(cell3); + grid.AlignRow(0, 100.0f); + NUnit.Framework.Assert.AreEqual(100.0f, grid.GetRows()[0][0].GetLayoutArea().GetHeight(), 0.00001f); + NUnit.Framework.Assert.AreEqual(100.0f, grid.GetRows()[0][1].GetLayoutArea().GetHeight(), 0.00001f); + NUnit.Framework.Assert.AreEqual(100.0f, grid.GetRows()[0][2].GetLayoutArea().GetHeight(), 0.00001f); + } + + [NUnit.Framework.Test] + public virtual void IncreaseColumnWidthTest() { + Grid grid = new Grid(3, 3, false); + GridCell cell1 = new GridCell(new TextRenderer(new Text("One"))); + cell1.SetLayoutArea(new Rectangle(100.0f, 50.0f)); + GridCell cell2 = new GridCell(new TextRenderer(new Text("Two"))); + cell2.SetLayoutArea(new Rectangle(30.0f, 50.0f)); + GridCell cell3 = new GridCell(new TextRenderer(new Text("Three"))); + cell3.SetLayoutArea(new Rectangle(50.0f, 50.0f)); + GridCell cell4 = new GridCell(new TextRenderer(new Text("Three"))); + cell4.SetLayoutArea(new Rectangle(100.0f, 50.0f)); + GridCell cell5 = new GridCell(new TextRenderer(new Text("Three"))); + cell5.SetLayoutArea(new Rectangle(50.0f, 50.0f)); + grid.AddCell(cell1); + grid.AddCell(cell2); + grid.AddCell(cell3); + grid.AddCell(cell4); + grid.AddCell(cell5); + grid.AlignColumn(1, 150.0f); + NUnit.Framework.Assert.AreEqual(100.0f, grid.GetRows()[0][0].GetLayoutArea().GetWidth(), 0.00001f); + NUnit.Framework.Assert.AreEqual(150.0f, grid.GetRows()[0][1].GetLayoutArea().GetWidth(), 0.00001f); + NUnit.Framework.Assert.AreEqual(150.0f, grid.GetRows()[1][1].GetLayoutArea().GetWidth(), 0.00001f); + NUnit.Framework.Assert.AreEqual(50.0f, grid.GetRows()[0][2].GetLayoutArea().GetWidth(), 0.00001f); + } + + [NUnit.Framework.Test] + public virtual void SparsePackingTest() { + Grid grid = new Grid(3, 3, false); + GridCell cell1 = new GridCell(new TextRenderer(new Text("One"))); + grid.AddCell(cell1); + IRenderer renderer = new TextRenderer(new Text("Two")); + renderer.SetProperty(Property.GRID_COLUMN_START, 1); + renderer.SetProperty(Property.GRID_COLUMN_END, 6); + GridCell wideCell = new GridCell(renderer); + grid.AddCell(wideCell); + GridCell cell3 = new GridCell(new TextRenderer(new Text("Three"))); + GridCell cell4 = new GridCell(new TextRenderer(new Text("Four"))); + GridCell cell5 = new GridCell(new TextRenderer(new Text("Five"))); + GridCell cell6 = new GridCell(new TextRenderer(new Text("Six"))); + grid.AddCell(cell3); + grid.AddCell(cell4); + grid.AddCell(cell5); + grid.AddCell(cell6); + NUnit.Framework.Assert.AreEqual(cell1, grid.GetRows()[0][0]); + NUnit.Framework.Assert.AreEqual(wideCell, grid.GetRows()[1][0]); + NUnit.Framework.Assert.AreEqual(cell3, grid.GetRows()[2][0]); + NUnit.Framework.Assert.AreEqual(cell4, grid.GetRows()[2][1]); + NUnit.Framework.Assert.AreEqual(cell5, grid.GetRows()[2][2]); + NUnit.Framework.Assert.AreEqual(cell6, grid.GetRows()[2][3]); + } + + [NUnit.Framework.Test] + public virtual void DensePackingTest() { + Grid grid = new Grid(3, 3, true); + GridCell cell1 = new GridCell(new TextRenderer(new Text("One"))); + grid.AddCell(cell1); + IRenderer renderer = new TextRenderer(new Text("Two")); + renderer.SetProperty(Property.GRID_COLUMN_START, 1); + renderer.SetProperty(Property.GRID_COLUMN_END, 6); + GridCell wideCell = new GridCell(renderer); + grid.AddCell(wideCell); + GridCell cell3 = new GridCell(new TextRenderer(new Text("Three"))); + GridCell cell4 = new GridCell(new TextRenderer(new Text("Four"))); + GridCell cell5 = new GridCell(new TextRenderer(new Text("Five"))); + GridCell cell6 = new GridCell(new TextRenderer(new Text("Six"))); + grid.AddCell(cell3); + grid.AddCell(cell4); + grid.AddCell(cell5); + grid.AddCell(cell6); + NUnit.Framework.Assert.AreEqual(cell1, grid.GetRows()[0][0]); + NUnit.Framework.Assert.AreEqual(cell3, grid.GetRows()[0][1]); + NUnit.Framework.Assert.AreEqual(cell4, grid.GetRows()[0][2]); + NUnit.Framework.Assert.AreEqual(cell5, grid.GetRows()[0][3]); + NUnit.Framework.Assert.AreEqual(cell6, grid.GetRows()[0][4]); + NUnit.Framework.Assert.AreEqual(wideCell, grid.GetRows()[1][0]); + } + } +} diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoColumnsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoColumnsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f3001b3e2a42fee8acd8c1e0d44885862aed5ae3 GIT binary patch literal 1461 zcmc&!ZA=_R7&ca7a}9(OZAodaqwxx7ft~%{MZENY16ts?-knkfr28?4+t6LIw^y$i zLq$NNEonmv+LCBOP)iyEp~e=fQv66X1=_S}i_yf|w8qqrA8m~hsm@+$PfOxo=g02s z?DM|!zR&Z_xPxWo1!N)baDRVk_KbrC5E$|{M{zMxuC-XmB+6SP3zZ?oP!Um$^k(Zh zKntAL8?#I#ZFeLF;(H$td=4}H^M|M0%oo22u6O+%E>G32S2`1EZ!Nr@*?y(S2%+-P z*&9zZ_0ltmYYSfI!Jm#F3wUSeuOF+?4o-2K*B-q&QB9ob|3>fsDn6q&9=>nJ*H^M{ zd0Log`fIG{)r>V;z%LuJCZBW#P8|xv;SH|yKVF>6S$ne0^U0W-x_Z_6@Z*I)$LDV- zZO<6jj$ZlsSNZJZ=HcsaUf%nT{Py%%ylQaT+1H&@!anPJ@PqV3#wwzjVm&YfL|JNJL~XxASn&B`q5)V=k!dsaS>pU!t~JKm8OSl!dZJPjhw z-6O*K%e%T>%I)x6$R7W$b=`&YIMB8K_xxLd9Y>DjpZj4`RaM{6rS4!?opYkMXK-2i z%H)=y9GTeqU~u?}b7s-ZO_Ft})+hY+*x04N^6!#7NXb{K<+e5E!bF2udc#04fOyp_maj6%?~AfTQgf2{`+o7Y`z0 zYTK7&i0o`dI88J1dhK%TB4`}3=%iBY6iYMoGVG+hvLXsn3}i_bQnU!U^^nemFxNxW z80vomf~KLy6=ddV5tOjr2c?FIfKUhv*@AGu7YtX{MnFTJuOe6tb|5o`H*D~LLllIt zz}^!0TFsp?1S(7;-U*Ilk}$Y+VtNh%!p$>NTNzpWA(P0p~hPg z$?8%e2@^#f5bzG%j^TtQYmmfNx(g?e z|G-(Mq_rT^zCt#Zf%;-eQdr2Ve3TZVd^D;?ITcEXS7b=ah$TgcXb}l2!%HHIM3tmC zK~N}2^NhqQ5~r{#M?zkrWtNS~0?SDhlo2Em%?KDmqG*(3kSsHl$k057NQ^>>EF&V8 zWf)$jy#Id%jl@PhY5@C4gouz~U~QAru-1kEkM(pXEnQ$cy5QfAcEl{nw30%LEWV}P I{@QZK-!DDj;s5{u literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoRowsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicAutoRowsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ea32d765091d58c3a05cda18169da98ba4e92b51 GIT binary patch literal 5387 zcmc(jc_38#9>B9T?$m9FOQM`K3SrJUGh=2-m@z|T$zC^*NSDU<0+}Y18Wn|sy`mm0R*)_94yHkCSC?;E% zT@zy)ZQvHm*E8*KbpJUbWOf5vi=+9%-mK034=3S{*dwv~Paa4}GHPJu`*Wu6IcN?n zD!>FxPLf8%MBhm&d%^g#RAG~n|HbM#q8z=GlO(U&BDSXatv&Xxcc_sOIcwle!~3*Z zjt_C^mBx16588SM+Fyg^!nSg4sn5I{sX^_16?83+wW6Y`re=@Qkim^@jSj1>K%tRA zn~Tq6c@=h%)5|)CivD#Vb*RWczA?+q;c~Oo!EAa-aMV6m?d>_CG5nY%2Qe#eW9Hu4 zZ?#sXG4}0HMwwNqj!*bQ>*5o2Yq5xs_r*QvH<>$0!)~<|38jcoDgk7!b|W|;JOP^_ z3ik%lOEQfNP)V>a!G$eGbpTkd;)X~>p<*r~kwHQKEjvMgh3q#g^dNYM1wmt0@K_&= zpv(9pR#q}|WJXZYfBZdLa1`6rrfKnj8f$PvgK67=JWG$~6-%o{b+~dB-I>>ihCb!b zaOFOpd@?gjl8IFZZ1O$==76E5X+FNeQim~6*MND#2u}*h%EJ`LaTA?q(`hLyU4FQ% zbyrurpsm%F_wLQosySKR-59TXxn=CUx25R;t9uMrZ29dMY)0&r#E{-%>XL+M3n~3S z%q+3lY5$gm>AAMI{fTm|<(sT$GrfzW@ccWzi(A&dThJF3XTSTP5<9ul)h?7Z#kU&Q zqHM49tMwYBg#OP=>x4TS=8UC68Ft85Dl#WcC>2Ns{%^5Bv~RFr<3SY5%b$*y?0L0*pKq7DWJkx%nC&ZF5+~0vOSKvp6Za$@sw%?asX4e%$0f^{PgM8sU7e$(GylyVh5IKumuqZ@zGl2* zx+}G~*E_z-(tf40oAt_dJMMq7R`w4|84H6p?1rx}x23Q&80Gr94(NVAKN3 z46fMfO7%;*eo?_VXq)5}bEm|#`R-h!3sw>n`dyRMM$czwL#JovMeQ0;)n5N0c3Z1p zt9QVuKGRiNDQSC|zhYD_+dK)=d+n*mOFk{~D!P-E*Xtok)9ut*nqR!l+f(a;-XN4}dRs7S?*U7@fTSpgoUsNav8U?6nTHTi{78-9^e6z%LaNc_x?sdOqWw`0q zYp{jog-aBe#3bZ^wHAC8y&1xq4DG;dNV*9=kC$)7FJ2qcO0qHoP zfK2T>k4WzhX`p~I%vI;F{}^i>)Uvz0S$f-*WVSUeomssA1!Pr69Yg_bv0xSG9(dm{j99U)Sgw-R#V67BWKT=c{Mk;qx{Z<z~PIX^HUr(jVXYjw2W{?~i15X##_walj2U-Hbq zk*$aT?v#`vlW8y=b9mX|2PVriZe4ZV*sPHFa^4`F4&r7NNqVq1b~&{dJ@mO49Q~uu z!L34@Td(ysabT+6>zj?`I`{y3bQZ0%4!qD7_buiH8$06 zhfU{jHi_M})m|KWVrv#xu>B<|ei5nFua;$y3Cv!zI4z_yJ5bnO8oVomJ7A(`b-e8E z8|#S9^0XFn&I(DnupNKOeR>Irlt@K3(ikcsb2%m&ka`{4HJe3@8$>-SpJYyEO=FzokFY zpFNnl^Qv|9;T6t=vW@EJ?lG#5=;F11Jg94L?($T4L~|}9yDsmtf}d}`wZ;Q+^pC^_NV_Ie>%oMgU7P?*N2j(iklsW zj0I=U>D27M5Ywq-H0NE6&TgOc?)R1SPoxwS@{L>C`*Ra&m34i#d!z`M+4W^-i@h#< zQ1Qn{OI94+z~6uOH6?;OGc8EnyM)t6WjQNucBoNvT^MwHF5}es(sK`1cP^?vW7%Qa z{Tj16!cJ)%?~Yfu<@Y+FPy0wK(6L@B5DA&+*l)yK2!k*QBtv8nCelD?0Z5z=g7b|D zP9ol4E4YY7yihJ8HWGLs;nGsTRwPCMsyS#*Hgk8TySOh|?g981(d}IvfiOfYK{xa< z1`eSq4m6W(3DASZ>m>+aFBXLc1I}K?!(;4-=TSD_O1@0V@`2ZuEoBFa{D+lC^dk(m z1d)x;ge6E|7$OyL*#wpleXSu7`V&?Ngmj@q@b%g~lp~c5(6U7#`KNsH9$t4ucCZzN zqN6$l5*!3PiMPDv0%T>y4UlCrH$dJvqbHe<(UW}a2cXXy&}S8SjJW}@T*deEe)4-8 z-Y{H@@Ub8Old-6az8ruBnM@=DeBg_W1XIxMWd|VqDkFjDR^P}V5Ve1_3?!1#*5Df% zD6@97j6{^#JX!`)EXM2$l4vNX(RvVMF-8VbX=Chz$ds`%7=1VL?RvCv_Mkvx?hSo{ z$J`qX!RWIw+CG>nn=ZbQkx3|((J~?|!#7$6(@10dLbMpGMsG)c^nh literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..94d54a87744cf1a5c27797b9044d17db5dff65fa GIT binary patch literal 1442 zcmc&!Yitx%6t+szWTFI>8WKairLFBkw)4F6sN1EF-O_5eEZdjZhuoRDQ>HC5&CD#> z`btQsVn`zuCqy)sOiB?S-B9B5zkV>SbNgIud0bf+9&a8!1n)uiI!0kTYQcd$j4wIc_Iuwts1ti(o(vmUU# z5DeOmh0z8gvA1hSr0R3(;jUk$aPOHz+3^BjL$>zTj;v2W=J6%tvwhsk*A`Z+?LNxw zpPZf^^d0PeZ{}8{=kk$(g5@9Pzx>lcc-p`F)RxxqTUTlek34xTf7iwM#~0Pcr+!=#lit@-B}oS#*11L18V?`|P&i13!>;U#)$kt)Mw~+0y1qO^G`* z{NW#u?JN0xrZ01izHQ5%sr3is!QKb1ew0`)6g`wNVO`z&^Yn#v!vzm6`*d<3lkQRI z(ZT5GFPHkiEwBIn`jvj}A4? z4otmho@;`q&cCvBBKCIRnH!0-t>4`~`1NjL?0DtWJ0nk|R}8(`SJ+(Af07hi^}R(G z&W&ZAsXi>NLqkJ1_n$p+XYnTe#2>ZWU)>WJ+l&{TeqJe3n=`_JW+$w4r}g}~_ye|W zT-llSD9(y(m0O2nH>P84^(SZ3d@JiZ32dly%)2X3DK4d0scAUaaBSeI7$YNC)lrF= zXrSCJlpqi}riqLq%f$dD35j9bj9Ut}J-uCT??VIL`xkTvS!3xN=0&LK?7(iA790$E z>3B)7uE$*4l)7!<=%x{J+a@nmz)%cFK^jsFD^cPKip`~{Tpt-R)&B-WEmMsv*vivu zaKbqTN=*v`F`vqZ{_3jYXm$DO8qk-cNvPJ{N9nExWnqSF<51p z@eWW`=S$^Er*id*u;-{qR#l1|)NZz>I%($xuO+Kfqc7vy8tm$u$WOgZ+goQPN0s`UI zI5z+fAq#;9?%D+C2Ji+j?%709m}i5co4|cIj+5ruDB5kM`*4Ev51eBmy&YTLdr=Vr z4FM=d>7c>!aNRfG3r4WZXj=_{BON=Z?8iiO+ z=CLBP3N7<4P}4XGxy}f(jHa@hfK>@Yj70=_4U3q;A{1rBNi+k4|9=KeWQC!bz`GJL sGG>~tw#j9+{t^c6!%5^MTiWk+wEy27P1p{yoTShaD-t<5;niitU%~X`G5`Po literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f7aceda0ba43dfbe6c2ff0b7e46805ba3c624903 GIT binary patch literal 1465 zcmc&!Yitx%7}b^^bbwT718S?iR##e^?c90qz_O+7_7zII*}iETnBBS4j@g}Q=TR17 zA!?BbK9a^r(FW6$*Z>I$(Fj3;f@l*Tw208ALTez6u^3}h4K)h!&RST6#J}DjGxvUT zzVDv(ag$%MZB3a0f!n%yeN~E<}?SK)X z&u3Z&lA=Vczx%DPsy>5{l-#^ckW$*UV`;nHE3RfAd?Cr5y8Li`(vJ7e9b>j;zFXIp z{^ynb7jsr!nyJs|?ykFhV}RQpls^u1pRX%uU>jQI=YKwU;LEIW{LP`?XGa^446m~1ezQ+K zQSjaMzL5h5 zX~}aHCo^}BaQh~QzlQx~8IxyD!j9q2Y0~=r|;ZOx-rZ$aHLgvz-?O zc;}lB53<%!qYqT5-PVC{nKtC}IdmKn49-|^Q!#dnrRtg=yD7)NhK4i?IVe&z$5M12 zWL87CI+xt2%l{1s7`kkSk&&a;qL_6Q6zc{8o_v_kxofHl12yHc+KhY}&9Fl>lsXb;OW z*bYdBj37f<-~|VWM3&<*o`nn>Rv1O36c5jck|HCPlSPpZg(QlnSOn!Tk|l~p6eWZ> zOj%)ND#V5n^hlKCk$wL^gI2OaQ*_{5i69x&b*ycCTBB}9K)`ys;+A$hj&}ds(S&J9 Rh7}iDrX=1Sv6;17J%(jcoGI#FXJ3n<~k+k(sXj z@VY}WdZ;9Gf2gXnqRrl4)>A%o{k>9E_Uvu?G0?K3`uJPpqYJ*kx{@7JQvUL910NlJ z@kiy0)2;i4r=kLCUsI8uDf>S0Q1I-}8`(h=J@QPXdHuXxcSNw35`&u;7yk6WG>w)! zQ@g%o?W1p|M%JRC3rA1AQaW++SmT+cZ=A!EOYzeA^6@}t?cgWFy**RvrW`-ixAvZj zufCp`+?u<)aqOpo><_ae7pEL!`MpoY=T25XeeT?))a7?>nb4(!V|&U5>t2rVH+{#= z-Og|N{K=a4Hw--myF#Vw>tDSzI(hWKn%NunJ$kC-u@9D;ly4uH`~B89#|&)+S$F3# z5iBwiH4TRujtxAPl6*7MbXsfnrl4yQg#bB-I`{;&+!%lgAxUPNc}r!s$ETa^y#ye7 z-@@+V+bq3nRfV>`ZswNBvT)dI$7=$+87s1gy0kmGX~bMv_+#4;L_tUd0uffAvK8Vj z5N@gDn@#P%0}__07>(N)UV8LsSgBg?nzM#Ql7t9ENX?RY48MTNq%0B^Cb2mcko%)HBoz(1&KcFJQj z+3|Nqp}S&Auf;MP1QO@YxUzsq2qqu{uJ|P67WNh}uKHx+%HbLxA+9E_@dX8Gl@AK5 zb0zT~agIgx9J9RtL1PT0LPTYR3Npk*Lj*G^C@TVzAQW+$VwH$8LYPWHAp>!cW}u1$ z#*mgKB2*P9iCA@Qh$SisnoO}GNJ-|5h|-JJfOtL@Q9_e7?Gt GdhRdBYQyFL literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1e431d4af2caa8df42d19bdc62b4b0b3a93751e1 GIT binary patch literal 1392 zcmc&!YiJx*6!wp(Q)^A6LbcQz>6&cP&D?qI%t+X}*+({R9_#L6t=p{Jow<{aZfC;G zY_psCAXF5^h@>{fSPj-!gGEqFL|erYu%hVFh8BZCFd-jNr z@0oMX{m%EDJDx;1>SJ0($}_)Eo}mN)fth=dYHOpTdfven9nB*Lhp}R+nC`+xzq1{1 zj2H;mj)l<c;q_0PD?PpbyJY>5t)H)bs;@4&VR-f9O*736*$G3R-`p@e zIW_w5FMl2hw7fbpHB{QNw5%R_c`qIu`S|qq_oIiS^}qhGbTE5rYxd2K^B+tU;X?Gs zn>y>g$pgc)8_N6cUzfJQu(h`Ps`vP3$JwjnkjQy6aAM$>gYFPb-^-a9_qq&Jk z$HrdRmkE^1udBE2zYR}YON+^eLaWB@-K8#GY#$wnoVc03eg4zNxy|Dn6Nle9f9=n6 zH(s-8)7P`VzqIajdHI1q?z`dLi;qPISNSMxs8t@_72%z)@gFh`2OEwJh$cz88>>2M zH;WnQZUtEY63_P031qo3fUSfiv27MC1=~bDH=Dc|;3wY#uF+{r-?5@Xx-@{@GW|FZ zAaDo>&dsO}LC6)^(M==l4nb4+P8PB}6c_=roD78)$TdRP=%u?&^}hoWmZ=sLY&Gd= zTy)+BA=AP@YK5(WFVz!Fq+-2ku&pWBk>~rJPJGz4Ch~W;oZuHYzbR%fk z`sID9kaGx2q$pE)R_LwOCG=k+%q+NiFmzm3?F>;f+4pxw1zjzrXkm?lK&0Frs|Ngn zzzIMDmwY003lIawWuL@}D|`ay0=OcMljRjY$hf0)MV!e0BhImqp2rrs{heWuX;Wo{ zWj`Zn41x&ph~))QQZdJ}SmZ=r5}6#wGcYG9j4TUSQg{{$NW(HGiBOfG!bnVx7kLpw zg+r2pG!1dsuSufJGk&)QQn;Mvmsmk$ksu>YRaJrW3k*~=fn}J$|Bs-L?ld$LkSmd- rlcwovTUn;`Aq?E#Amyoyw2w@*@81(m*$%RtiqMiIQ65jEH%k2l#yQ0m literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrAndPtTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrAndPtTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4cac268559c16e744a64dfbe5b90c0bbd1b6b926 GIT binary patch literal 1746 zcmc&!O-~a+7$#oCjUK&eGA1^FSav>lcMNGn3Q7QNwiOeR!*q8FYwB*D-6HTKj2Gj@ zi!sEQ7~{>vyC%j132HofK=}b4ym)h_7S=){o^%dv_wD=fJnuZu7Aob*A{ue6!k4cb z?=1!(Na{DO(NTLcYGzW|lTDGyvJ8??+A}g<%$9)bl}c%*q_}0RJRIIu*4E}7QiIg* zpZbcODt!6k199g1r?xh~ZA^bW`u2-DwqwaJV=MxVs8He4*`j^2$b3EfooXI##fx+n8voegtg=A$O>PN;I@F-reD?;fU zfIBI^Op~?>WNO&xYV(DFWBx1YW7kx4YhQ=jYD?-ii?UQQa101fR~)z$%KvsL{X-j{ zc9wFe@74Dsr}p!9^O3u}4UB)v8=2J}NSwjHCEj{>HkZSpzSoD3+}_We=QDSicYyp; z>f|>RTIgAn#AWS+!SXo_F@+3rgc(J67?J@92Zrp~B>ZziMI~W7kZLfh$(8Im7*CW0 z-Uu9F#p>m;O7+r}8n`hycCj)8mZeJdz#Bv0DTWXh%}6lTQmd&17gf@3fy;A4xja#h z)#x_us=p)Tagm8;vY00u^>?rIf=H#Yg?&jjmt__O!k&n=&!c$Jz81w}aT@JDSKIZ> z7{fG0ozIS=^1jA#-M-^VTU(IW(@~ht8w2~m$k_+xYW;;@)g7dH`HGSa3j%~JO}Kl2 z!x&+p0d`{C(br-Qh<9QLa?PkW23@XKvL}X^p1vmrk$#o*#t?+sX1y^;p~k-_hPh_E zC+4vId5mfk?c`-jL`|v8+jXi8=0_zVkh_FAL{iEe6gUmUId)yj8FqQy!$Js066x~L zs|Oye3xc@tu&!~5OT3@~1qrnlxrd~KDW@JLh&luk6b2q4A_zIA$f1b4$fKr8au#sL zgsh9w|3|Q3PsNP{7{B?ppClPDa`x?Nv?jG2v_c9U!xW8QioJfZ(oCqVBORpg*D4ey Iu1s1#0VwnO`~Uy| literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithFrTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..afea3cc23cc1b02a43b44cea68ed560ff097d5e9 GIT binary patch literal 955 zcmc&y&5qMB5C(C}Q}|NtR;Z2b*olLxNTsFAiv6j&6_;)gjy)+s-FW4=sLQkP0$g|% z4!i-p2zFJr%dW(gIXPdxnfYeE=}gCy9_eRM=jX5QKO&AWGUdl;Fo-Ah+JTKHYw2JN z%4mqspjo*ONEAiuEXbQ^`{l(mAI~Fb^d9oBP=Fl@jZEX9aV-kPXYo1cTD~^h1@@mj z=SVQRjHl9i4x&5C3|h0X3fjS-DB`)TZ=Ueycemh^R!|h7d1#qDXzA6t+B9RY{doL} zV#+YbIiZ{p`VuEc7$0@xbEE%Fm|CMZ3hZ$`hpqdDM#cgXecb20tBc|E>h0wmT^|om zrf29A*w#0^?xL?0W84cZ(eT#ZwSZ2n+1#Rw_uYe5a?l!vX!nEfrW#2n*JgDfho$UI z8JUgW5{ci{x?O}F&zAB1D%wNJ)j8X5(BaC9d z*+&=_;weTR)N@wWYp~&vPRD35fJ)^VFKHz*4P{0&)}^RQA~0ros)1|9GDXvju#Bad z%2LWfQjRtDzbGWK)QZv+ml#A!MafBylROnlmsOrq>`5Zel~j@fFqR0x6#&Uq3e+bQ z|6jo}K5Z(4!kNzEnK9nS-Sevc3@G*9b#`ag3s=_r`^uu$N$Yl|vW!HX&YR0g^c$Ak B1Udi! literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithPtAndPercentTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithPtAndPercentTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f73d88a6a0c751e8971bc3479695fbfc0df48e6f GIT binary patch literal 1499 zcmc&!T}&KR6qX9Mt{MSRF{$abVGAqWo&VXLx>?v|`D>wUcM%@|?aa~3c z8j)(HO$!m5v|usNrD=;`(x9oOq!rdy#cD8qH~rZ~0|ihZaa9Jp9mx@bDwL6&Age+*^h-QM3ZPh_Rss?y z9S%j6AzN*z@7UFLS{woK*$qRDxUe?)f`1|}f8DvxmdU(rWx>$WGsE_NEcp2TIK`r@ zzH&bH;j)D(q-W!Eu7x**gvNC};rl;Yeg5*#1w%+9o*G5=9r zQn2~e>e-3z7Y}V%`f719?&=BJgL|8UZAqi26FpNS9Z478_W8aXO6cwWZQ4tIAD7bK zUJ^6+%AFZtJai!R&Xuai62qJ3*L*zi=Nc14SC_r#;#|{n%3q$O)%l1vX@A? z_4Cof-l_d}J+YV&pT73#Ynxx*XQzq2AHO+rxP2o0B__qW^kWuE-~lg>TEJCnCnRvVzmFH@#jI>ls^>MTiAp{OcAr{9YdLSA59 zQhh0^Z7GHVHWDvKJglt606Y@ng^E-s`=O!>Ma$M-7@+lU4s9XDvQT|nh2kAGP%Bdb z9S*%6y$M3gSk_yXrYBX9M7O55H1{SP#YvRHC=@3cluAd5R1{4$A%znE-vJ(3;_LiS zP7{h@z1jz|BpCvm1+`FS-&Uu`mseB_%F>*6h+PYk-%9a?@%Df zm8H5Gu(iY#?G=mms)JCLM-f4l#j0#js)z>bqgV#!Vil;*2+4!N5L5*}i)4%1eGb#;mna;Zw{7^?x-9b9FK)gjwH692*w^M%5+`!9HO;Pn_|a0V{*lk zv-_T2yrE!2aPs4(vlILe3GJ!SiQe>q;1T6;U&mN?7B_t+e(j6Ntz?&XwQ6}kn(Iwh zj&vU#d++Axx9bD_a~E%NldV%}c(^-u&#}kCAME_Tf)rhueb@cS+&Wu6u%hqP&wZ7i z#HC-BJ-fUQfsNnbEmK3uqEmR!SkJ`oSL*AoXHQ%82Pmwo^E{B9!y8KRS7PWk)@=(o zocigtSk>g!Mq2|UM_%HAh}aNaBb&qrut^s`wu}~2!Ir~5iFRHLa68|;WYM*z*7UCo zwe8KAq={m$*J;OTf+G?0A}S#wu{A^Y5fK&m9%mtoAP*&mP1Rn9)M`VCYIswHh2Y{h_}jlHH|3 z+DsgwAP^`r>|TLj5(K)-F1Aeq=%ci4D|47R|A+=RsiHpmbuEwG8q z9e%bcYjJEke~$_uXz(C}SP`q7%t`_y$qXwpD8fP{KvqEzscuG=Ng*~&lDdf_7I{(N zA(BJ|V#uo)VUFP$H)JD%qPPV?mE?$|Vi~bG!pXcUDo9}?j3mh@0+9k0HLQw4m|L-6~SLhJ~I9I|?`wfF|o7@Jp4h#gsXKqr`E=SR>e=3@?Y}vGvL`ytN<>r>I HE2I7bzRv4L literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithoutColumnEndTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_basicThreeColumnsWithoutColumnEndTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..488436de400a4cbc9c05fc3f86ff0664076771dd GIT binary patch literal 1444 zcmc&!ZA=_R7>?RB?M5#uv5A^C6ALM%Id*1u=We&sYv4W#TIhv4+ah4xy`4Rl9=mjR z50Cz+QIS>yHKnZ)LZ}7P^aBtrtx3T)hEjvtU_vk|jj3${sj=E(8o!`%_oO|giGQ6R zyEE^;AJ6+d?`%#u5OSk@FO_rU>i7hO0R*~KOBEE*AvIwUgAOG`iv&namkGUzXmP6s zupYtZGcALNbyTYJ^#h-mjlhS4zuu;3G3!eEd#=jtGr{89OP*iV9c^7Q=TkdVKV>&; zONQPU|E;TKCpy*FcXIxOs1JSn&Hf#i_D;@(uQ$Kh{0y~W{nH(BbKk@-hf|kcs+znQ zxUsS%E01~VwRYE`{*#Z^jJ>k-g1hE^eryy)x-TDH*0^k1`?+`ZlY4LO*ovlZNLtrf z*GJ!v6f9le+E!S0lP_I;lyV7z{NU&h-Nt;IKeW4Ptfu7EBZ+zYM0%LI;&<#Z{LRk27< zRYLoS1q^tOsiwoCVfz3k?NUxmJ!!;<=_qbTJ1+!0&NrXE=%}IA-IF2OSWoOUapLni za2yb<9kDPtetR%1Ro4Rc;N%9@F_7UPh5}+RhnTgHT?65oJi1hu|JxyK=yEbfj9fKJ zQdU3k>jnXQKFr7NNLgVxQoK0|s&WfAhBtu*VwiTpsyuLvfe^Z#lAy5OXfz4fXz0m$ zP_`v6gB4}4I!%}hRHVD|i7^)Vhx2js9 zW~z73k)&ifEICP0`kAITlh>jD4qs99e9cSIUpCM0DLg@V9K**z{S z;K7*1Kmm7bUTgz)7SQh6cwV^2hIzZtB0mn>%q+4&WRKD!8xQ~CXBncJAcphDC<%bd z0+ukcgg7W+MwW>e5y+yLqIeh?BMCypNHK=xh(sXIh>Qn|tOR9*unduh!@T0*J(y)+ zOq61*#9~5-2O$B+1c)GkGQ(iZ@kroAFT+YWhM=r?prl|C*-#Zl@%{e@s_7C<(SdU% t%IR`lx3x`gBkE29ytbY>>5+Cj6Yc)@L{p|E8dh3pfrC^|PH=OG`U`j9=WYN1 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_bigCellMinContentTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_bigCellMinContentTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2bb93a1e234826b0587912b6d1aa8fb8cdc941c6 GIT binary patch literal 1445 zcmc&!eM}rh6t}4#=|&7xqF50IS_0PwcII~XcCUpCAIE1Y9LL3q2i4u%+3OnE#oax6 zrAAFlo0y2THfkbGi8YbXvuMFs`dt)jV@XJ;sm8X6g|x;5v__J%u_4Z$v{&22f1N*e zXWqQ`=DpwVHXkjl7=`yD4u@<&A z1BQnlk7*fL?4Y9idiSo^cEHrqxM%14gXu>XmR_oxJJ?s(3LeTgdUBRsU*NjV?8@Df z5|vN$Gn1E>?8;dF=ja3Pjb%Q*xwHvP+!|f-;7qFTN$5@){(1hXTd!{mc#YwjiPYY# zH`Emm2S3o8Ggc|}>u$C>)_k8{^vBREBV*$w<877UcN`g>x*H3X;KR>~caOB}UwQV$ zmK|ShiTkb}IG*VYZ1zTZQEpoNyTOb6m5s+v&Xy0KOB>kl@BO0shuDvE9sTFgbWYz?g?_9%dr$hy zzof+`=5}7#yKiMyL*tQmhax4Pcl96mHIr&gdBQdD!j>`L$un0omrc80JG#21?^J0M z?74Y4ce3-G}=5H8QG=R9~E`2d%57-lS)0PaG64JtLnAE5AQ?<@vQ=$5t%x zSHBdlZJOl|540RP-Zc8n{Os~r_qzVSvh|N13sP8<7r`epn=Cd-T7|AzShGxE6X~Zn zU|AK*^=J^1CFkaVz&hJ#pJ)&t;7qvqv8hLl5H@YfNwob#z-8}w$e;s;+Hqfoz}8Mo z(uA?cW0zwW!H|eWQ8=4-BL41m^xvT9#F=)#6c4s3ORK_`T;&^{8BbsAeu z45|%1(g_-#btG#=$y)6u%ta^?T~&yd*sh0@&NdW_jg^ZgwlSh>aC;ZF)R0J5YUF09 zTA1FbYGs`!UoFut<2J;+NphPAJK{vz7GDNJviO?Nl1s+R+z(5HrND(E( zhyoHZLu^PEn2;>9t`K5bkqco(5nTu~0u}{chCGsFmyG;vR)T0Zi>SQ3%El_{Z$4Sz AzyJUM literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_fixedColumnRowGoesFirstTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_fixedColumnRowGoesFirstTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9bace163a6f9d7dd0b70347c51797c831cb9891f GIT binary patch literal 1678 zcmc&!dr(wW7$3`$S!)#3l+-+xE1=?iKUQ!Nc0n8-BFpH=!pQaBvv6VAyWPF43#FNe z;sZy?M9`s!DKS84QcmQH@fBijK*?yR>H3PsAyZP*9`|n8X3q4l=Z|~O`Of$JeZTMM z)65Bx*fd6`zvT0F=_r5#X;Ho|IvPn3?Fy8U1UsidGvp-!BFWH^tKUj6x3N_;+QsfOPf%aa{q4si=|6ZyQ6c=frY;X z-)$Oue>d~{m3scix{lk|PVKU8Uzl{cs(f?e(`OFMa9?O)&W&fvZs0f3vlU>37!p2t zZmWH(cYf30$%YNfvSKZV77RUJ8}iJKr!KemEHQ35pB59d(%W^Y#~ah~<-L1y^wOF) z-NRf9mfYTuUOG6X;9KX$%C+5z`-YCn4!zVgX^<&$G!LLGU%tIzKCLP+Y8S&kog{O+v~?RUa}`Ep3L(^Dta+% z?(F3s&N#fn)Ogf#I`fr|A*IP*+*#EfQ&m&l;2Y=t{-_X@x4R_FGPUI+cO6kO^X?dz`Ujf%aF@D1xe-4s^1 zDs;TfzIjjQo>~Wc@;b^LZ}y3uzi#>Fa%1q>{;|ck-|E;DwS?Wjx9RhnZ+t>!HXkdw zo;0EZQU&-+Z8_{OUztLRtL+t|hi|1e&Wfs?1gv|e`xeYE4E9vp+w*s}cINlr={k6N zD_6N|ZQD+`v&p?Ke)M;Layh(4BuSZ->`pJUEQ?{d;ct-;vMEb!DOT!X`grX?E3ds#r4iyqdFURGH?BmH8G$s zsIt7>T%gt-7V=tD%_NX%2wt(eo*XiDWaGQ#i@SbE9&^`s|E50l!33qm__Yo?gaMMN zJB^fNfSe}Dp+JY?0vch{krXJ1T%6>wqUw<{P=F=zY$T17RULr)RnnnLDw28V(x|Ok zYd;Lo+MQ8dNQNvHKIS2#*a=lPxzK3T($SJ2REvQLF{u-vh?2vsPDr?UI*#HbN?|0% z5;%cRL5VOF4U0fhB;o%R(qu^};-MTaW@_q?1EsHEEPFH>b!_Ru2>*ftq9iu6#lAAoWj|q+<>wM z#Xw~af#q-;!_y?m za~Lgfynz;2T%d8t^DH4ihA=P&&c@O-EeIS%LDoiM9A+R?mSUV>;|wg#@F>e*G-|_f zk|jvWfC~nOW-)?fIFu(yp2jGQqIr}TP*vH+3C1U%K{hhmVUvJ166r{~B&ogiZ!Ka8 j1dQ5Gy`R#N8lxj0Wwg$vaI)fWG=?#RPOp!jlc4(xyvJJW literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_thirdColumnNotLayoutedTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_thirdColumnNotLayoutedTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..92cf005c109d1c0fe9fdfdc809df3b79df5ec31c GIT binary patch literal 1429 zcmc&!Yitx%6i!e?CyF){3<1ogX49>(ojY^qN$X;}kJ7;Qv26t`HQt@Mvy5(M%FMLx ziZzBPHZdtCq$E(1rhrzkkt&3URYR+$KadtJL1<&bBTxw@#veqng3hdkRhszM^JC`T zGv}Op&i8$Hd^O={fGHL!-=)iA;}j1dFcU9QrKNOKPdUV*qbcl=Fi}jE(CdhibT$LT zbHSkPSOhmy>AmecnX0egW09>r!#-|k@t@~Ci@?ru;1_9QnF``*0dK9YR7ZSt9NG7*P7|JPy2gDMz@xHzI*W6t*P&S zsP4I%nJ{~n7Rg_XE-tCBrR&iaYFufvhu9DJ}{JKp(w-vkP5{_^zkk?@jdV#5nVFMYP~qu}%#C8v+}_I4%527X*|vE%Fe zmh4#liE*=XTl@82l7$xr{Cs|Fk~zmn#p#=KIv0$*FfzRR%8Bv!nm2B+^TP8pH_nbW zocxym`18kY5ks8;+g*9&a5<7frr{97v4KZioQ@Gy$K__a5xQGm=7GeqO>_;m z+!(-SL*m3XTP=my9>s39_hNwHeG9rq*IRn?tP1s+7UGskl3>tl$7=$)88b==xk_+! z(+Imt@rPHjkmVrH2n+`y!>@p-5W>PDI%cZ>9Z+MLYO6vlzg|z$&W9jmS_DYNu$T|j zRh8A$t*NdDoBU-JHS0hdv26FiO-0}!3n2`6M}o2zD`OK-VVSKhpz7J8T(3;7S8oV= z28!%dA?)Cknal-yP|OTgj&0&$M6V&KHsa_CrXz-X6Lcdsk|zhmu#6 z$v(62=IVOz-vP{Qb@^cEwYq9IdThp<{?5pDmrF@oM57=ODR;&h0|L(@9%$f>PvqR` zJOjpEpCr0P@A2`1Jj=%+ci4O4T*_woMCl)Kj)nCUvAkbIWf(M;V#FejRfq&}f@MAG zu_9|o6ObZHvMOj$BNAp9kx?O*L=2H2A}k676GoObSyeSPAwXV+ilDKKs6q*82y>#K z@S=t!#7aD71>{yy5TmFX5(!F33X_mTMv=te|KC9qU1?}0@UBFhj+>^-ZFX6wze0fM f^6AS;I^Zcf@NY#^wu3DvOSH`Ll+PEbj#7UC(zM%- literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithAdjacentWideCellsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithAdjacentWideCellsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c08028d927d91a4b9e698417c9fc3520ff9d902c GIT binary patch literal 1468 zcmc&!ZA{!`9M9BEsRlO^mFbj6ATNu(_9;}LC2j9=?9C5D z6OfD#E)gfpYzZ^Qxy^wFMr4T#FL6N<37{@y%ms{!W15hNsIxuUPDkQbpET{$fB&z) z-|wj-;PE=~EEaKmdu?J8p#cW8&?`uGHtJOxOsJ#Y2El|LC~6W!i=bL-)&Y_yT`t4a zq0op#yAB)~FTRLvZdp2rq+Cr3Ep1OMPu-hW(0otjK~Lq!NjH8=4Kq6y7PCBlTVs^-YF<) zy-Rjw7ggS${@wF;>sx&r4kaEw_Av57-dIq3BJ#x!ZPi_U{h6mOUwC`)t!sY{-6SRs zxCT?l-gs`)rOHNWY}f1UCzJ2p4Kz5`c|5Ek%7$QiNPBT7_A!G*1JLB5Kfppj$qGh`E$PLksI7G;AeU(e?ue zjQ!1JEwoHm8rNkgYi@#8np)^`+3na(kXFQ+pxl;VOhr>YmY~u-I|z)RFdE}=f~IgH z6C=|wEG+}|Y0`f?1awUbi%?Hj%3#zy4cwXz0hfhk(avCTP9Rv|F9X%-Ir)Ji5P`a3 z6|Bwx?-Lk?Iqi}lr%7)%AjsFXa1$tgF(ck99`Ds2!dQbMHkDg2g$AuQ?rcM`HdwA; zKpP{p05(LRsfYrar&W?Wlq`N)m%%lvP;9AR}NjMbMliNFv3Hc!t=;dtwUoK;sMXxIPWK@D1{${MhbL@8RTX%@G!ZBW?@0c-K;h)LRME86*QMI(kO R=w^&)o}mzjBhT+e{sPrq?OOl< literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..95b938767a452b973957ed798a051a71a3bb9464 GIT binary patch literal 1498 zcmc&!YfKzf6pl@hxHV{kR;88PAKd`KW$wIoW*V{y?6NJw(uIYsxNLPEcVWox4$jQN zqOHUlTda+hwl<0cDG*}m!}v(k)O-IL`?cvh1o@DwSx&odUDSvZI-?HmGY+3o~>E@X?5}Uv8dV1sd_~i8O z&9~vsQ+Iwk*HdJof77KIgU_qw$I@1L2O!zPj!jD!w!J?!jQj zS0lU1=4K~@1vk!ZRlqyc#)Z9FZ#)v1n(vslPq@0XKA25AeVzR!KD7J6;U8Azcek8x zKj9P02EI6+)pmH`a^k|x?|K_gj`fFM46g9xc0&B>rN=w{uFUPjCzf|oXuRPm=h*85 zIRWNin)3GL8(l9H5ACR}4R}4Zc%Lx*`Ded*-}3p#K6(!lw)i)DteMaIiyAsMWJfMh zHqABjWqV+v|FwPZ*SMdX z44r&ndHM?f`In}Co|-$mfc^MqdL#YeMGJ~bi;Nj7lVK{wv{Q-dD5`6~WWNgYAW7zn zm3ROeTbiQ*OA$fL%d3VDAd)UsNK;~}h%{3tMzs0Cf!+M)Fa}nw%8?}*s#}|ok)|Fw z9A-IY5u_2ZC^x4eCtX&eE<+pl!a2BCl`V`f5;@TeQ|&4w{jw83)$of&B!8&}JS9ikj3`4S}_) z5^Dk#{=8JJc&b*j32hOIWLHjJ=fg^U%Grcsv9V%aLncPpIuve3x-9ZoNz}MbaxU-h-7uCkhqFM76=%N z(c|I(cA6$>5CV5?EN*aZ4iLR(<0ylj`)qcSU1Fo5A)EXBAimVb(*LmODldnTYQ8h2 zE)XcRlcIz(3=LV9qC^5x6b=cV69pEhaU8b`f7agG*9 zK}14`r3HyZg53`7JQET~k`QQt;RPs?A})n!T*4vCGa^YLiVR5vf;3Bo1V}ml{|bUw zX*8q&^GZ}rt_+vB%0$Wi`81P-fj5{jYj}; literal 0 HcmV?d00001 diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b231f9231cdcca01b929b8e81fd56fc0e5cc11eb GIT binary patch literal 1506 zcmc&!Yitx%6vjePx2VNhtx>|Yx}{aObLTzNtP7>@$F^&`T}WSXcINJ~bvsjLr)Ar0 zgefOFjx%n16lQo$mr%z0oXaIrYZZKJ`SiaA%Ar;H_3mVErq9P%z6v&Iwe9s%X`@fm{Jt1Xm(|YGG ziLT8`U;lS&vOfy%Ja138*iYDx_s+P!o?J3Acz-0l{`0B>&z;%u==VcUm2Wxu)xJX) zi)WH&s;c{bty$m3Q_I@j)rz?cSI=f zUE4i=?cAZ~i@WzlE?o;9SibVe)GYf&-|28x(G%XfWBuaf)9>s8{U1+vR3CZwWMm|v z6ZEVKC)1DHTK5-5dKWFc#}z`uS5|Hp$j^!+g9Wy~>OV>SHZ4zXzOebRq|CF+QaZoX ze#*Kpt?~W%SFBybO*`V=Jmv~cuWH&hZhm0#>wEv02rh2z|MBQ?Y3Raaqc|E`c6n;| zpG!E8H@UybiXeeR#TibeeUah@;*HK~P4<;l_^Tg>hgJ>#7c#a}#NY(F8IRsVr0YucL0tJ+2RYUz^Qz0yRi*h9IagO*dTtg02@2AX#|fIk@n;~p0>Tv;m|c>j=*>b>lb6wf&){HJ0N%816+TK`Rqy0A;rZnq(;8=-I3e*^ER@D6y z5k(gZ3986rf`B#YHO>#f&@@Q{54d6Da27=OfPB-&(>njgxW&d$xCo+2sH zElM=$<|UqH1>66RpbjgNJqj?cLFmy(?a_@ zo_o%@=X~FHuPx~F+X)AU*)GkDPhkvzK#eqE#l^T^jvGkB{c*uSJ``0&gjXUZW^4g8 zBwQ}t(2$V8S`NSY)|j#fX1C9`Ve5W)VBvU1{<-JI`ak~aN&4r`cYW@r8`oD zwJ#$%*u5|sbG-4{+U{Fb-}#eWMSYX;j-!eGgmJR={)Hosrh4zx(>-mQx}HoU;p zj0LX+hX%(k9-KZ`)t21)8~;twXx|Ht{lmkf?{&@`1BZTjHe;r%D>xeP1>7sjS`VD5 zF1b>^`q!&JZukqmMr{KKSV7y1-%d)Aam6Uh9{=qrYDqem~jRKDp=A#D$fw zojE;(2Ikru8#-g}EG+KM*-o%Mmu=FT+LFe(p_Qj+7qOC9U#>gQVZTSNWWLA;^EX{L z9=YJZZ+CXScRh7%gwNcbJ?ohZmQP_>p2zY=Ja!i44c}Y!p+Dn%b5_o&tBcc@3nmhI znNH{*BsWeTs(=SKud)qny_DN!PC@0~+?}5m_JQ^%Iwl5HF`3n#vwq#CYbXEAcyM;t zEet8*5;x||;*w5t>Qxm3DTWR#o z;4TYRf*nZH%>(NTK`#j*v|C34_cpCnN1#koo40}LmkQIh66sp4CiEpJQeAlkLx`)f zw6g`pQez%LM;1nSIg0N}w4+4K)7WF!d%}~SN5vl6ZAuSq`FbFuz>~U!TmSHFcNZ_`O<9U$U1IitnlQcWF z#$7g+FdJKDqj{6XWj08dQd(x?sk{6PO_1YAvtE=6AE+y)1;k2_V39~diKiu+V`-8@ z5s^YXWT8aRQJREKfs06xmv}NFP>jfli~u3eL5g(}r0L8=1;WWPY=nwRJjZdANYG@I z5k-=xM9PW82<2oL(<@3u1jZztM`jq!2!iYXub=_1P$U&tS0aRmRMq4*H4V!<5#UTd eZ7E6HEk)b^sc1|$1kFeh?c_+zW-AT&vA+PweeLW3 literal 0 HcmV?d00001 diff --git a/itext/itext.layout/itext/layout/element/GridContainer.cs b/itext/itext.layout/itext/layout/element/GridContainer.cs new file mode 100644 index 0000000000..e960184e73 --- /dev/null +++ b/itext/itext.layout/itext/layout/element/GridContainer.cs @@ -0,0 +1,23 @@ +using iText.Layout.Renderer; + +namespace iText.Layout.Element { + /// + /// A + /// + /// represents a container of the css grid object. + /// + public class GridContainer : Div { + /// + /// Creates a new + /// + /// instance. + /// + public GridContainer() + : base() { + } + + protected internal override IRenderer MakeNewRenderer() { + return new GridContainerRenderer(this); + } + } +} diff --git a/itext/itext.layout/itext/layout/exceptions/LayoutExceptionMessageConstant.cs b/itext/itext.layout/itext/layout/exceptions/LayoutExceptionMessageConstant.cs index 216beed61b..30fa21dd35 100644 --- a/itext/itext.layout/itext/layout/exceptions/LayoutExceptionMessageConstant.cs +++ b/itext/itext.layout/itext/layout/exceptions/LayoutExceptionMessageConstant.cs @@ -59,6 +59,8 @@ public sealed class LayoutExceptionMessageConstant { public const String INVALID_COLUMN_PROPERTIES = "Invalid column-count/column-width/column-gap properties, they're absent or have negative value"; + public const String INVALID_CELL_INDEXES = "Invalid grid-column/grid-row properties, cells overlapping"; + public const String INVALID_FONT_PROPERTY_VALUE = "Invalid FONT property value type."; public const String TAGGING_HINTKEY_SHOULD_HAVE_ACCES = "TaggingHintKey should have accessibility properties"; diff --git a/itext/itext.layout/itext/layout/properties/Property.cs b/itext/itext.layout/itext/layout/properties/Property.cs index 26560a4146..d9c92d3714 100644 --- a/itext/itext.layout/itext/layout/properties/Property.cs +++ b/itext/itext.layout/itext/layout/properties/Property.cs @@ -187,6 +187,22 @@ public sealed class Property { public const int FULL = 25; + public const int GRID_COLUMN_END = 147; + + public const int GRID_COLUMN_START = 148; + + public const int GRID_ROW_END = 149; + + public const int GRID_ROW_START = 150; + + public const int GRID_TEMPLATE_COLUMNS = 145; + + public const int GRID_TEMPLATE_ROWS = 146; + + public const int GRID_AUTO_ROWS = 151; + + public const int GRID_AUTO_COLUMNS = 152; + public const int HEIGHT = 27; public const int HORIZONTAL_ALIGNMENT = 28; @@ -382,7 +398,7 @@ public sealed class Property { /// private static readonly bool[] INHERITED_PROPERTIES; - private const int MAX_INHERITED_PROPERTY_ID = 144; + private const int MAX_INHERITED_PROPERTY_ID = 152; static Property() { INHERITED_PROPERTIES = new bool[MAX_INHERITED_PROPERTY_ID + 1]; diff --git a/itext/itext.layout/itext/layout/renderer/Grid.cs b/itext/itext.layout/itext/layout/renderer/Grid.cs new file mode 100644 index 0000000000..f756f995c3 --- /dev/null +++ b/itext/itext.layout/itext/layout/renderer/Grid.cs @@ -0,0 +1,394 @@ +using System; +using System.Collections.Generic; +using iText.Commons.Utils; +using iText.Layout.Exceptions; + +namespace iText.Layout.Renderer { + /// This class represents a grid of elements. + internal class Grid { + private readonly IList> rows = new List>(); + + private readonly Grid.CellPacker cellPacker; + + private float minHeight = 0.0f; + + private float minWidth = 0.0f; + + internal const int ROW_ORDER = 1; + + internal const int COLUMN_ORDER = 2; + + /// Creates a new grid instance. + /// initial number of row for the grid + /// initial number of columns for the grid + /// if true, dense packing will be used, otherwise sparse packing will be used + internal Grid(int initialRowsCount, int initialColumnsCount, bool densePacking) { + EnsureGridSize(initialRowsCount, initialColumnsCount); + cellPacker = new Grid.CellPacker(this, densePacking); + } + + /// + /// Get resulting layout height of the grid, if it's less than explicit (minimal) height of the grid + /// return the explicit one. + /// + /// resulting layout height of a grid. + internal virtual float GetHeight() { + for (int i = rows.Count - 1; i >= 0; --i) { + for (int j = 0; j < rows[0].Count; ++j) { + if (rows[i][j] != null) { + return Math.Max(rows[i][j].GetLayoutArea().GetTop(), minHeight); + } + } + } + return minHeight; + } + + /// Get min width of the grid, which is size of the grid covered by absolute template values. + /// min width of a grid. + internal virtual float GetMinWidth() { + return minWidth; + } + + /// Get internal matrix of cells. + /// matrix of cells. + internal virtual IList> GetRows() { + return rows; + } + + /// Get any cell adjacent to the left of a given cell. + /// + /// Get any cell adjacent to the left of a given cell. + /// If there is no a direct neighbor to the left, and other adjacent cells are big cells and their column end + /// is bigger than the column start of a given cell, method will still return such a neighbor, though it's not + /// actually a neighbor to the left. + /// + /// cell for which to find the neighbor + /// adjacent cell to the left if found one, null otherwise + internal virtual GridCell GetClosestLeftNeighbor(GridCell value) { + int x = value.GetColumnStart(); + GridCell bigNeighbor = null; + for (int i = 1; i <= x; ++i) { + for (int j = 0; j < rows.Count; ++j) { + if (rows[j][x - i] != null) { + if (rows[j][x - i].GetColumnEnd() > x) { + bigNeighbor = rows[j][x - i]; + continue; + } + return rows[j][x - i]; + } + } + if (bigNeighbor != null && bigNeighbor.GetColumnStart() == x - i) { + return bigNeighbor; + } + } + return null; + } + + /// + /// Get any cell adjacent to the top of a given cell + /// If there is no a direct neighbor to the top, and other adjacent cells are big cells and their row end + /// is bigger than the row start of a given cell, method will still return such a neighbor, though it's not + /// actually a neighbor to the top. + /// + /// cell for which to find the neighbor + /// adjacent cell to the top if found one, null otherwise + internal virtual GridCell GetClosestTopNeighbor(GridCell value) { + int y = value.GetRowStart(); + GridCell bigNeighbor = null; + for (int i = 1; i <= y; ++i) { + for (int j = 0; j < rows[0].Count; ++j) { + if (rows[y - i][j] != null) { + if (rows[y - i][j].GetRowEnd() > y) { + bigNeighbor = rows[y - i][j]; + continue; + } + return rows[y - i][j]; + } + } + if (bigNeighbor != null && bigNeighbor.GetRowStart() == y - i) { + return bigNeighbor; + } + } + return null; + } + + /// Get all unique cells in the grid. + /// + /// Get all unique cells in the grid. + /// Internally big cells (height * width > 1) are stored in multiple quantities + /// For example, cell with height = 2 and width = 2 will have 4 instances on a grid (width * height) to simplify + /// internal grid processing. This method counts such cells as one and returns a list of unique cells. + /// + /// + /// if Grid.ROW the order of cells is from left to right, top to bottom + /// if Grid.COLUMN the order of cells is from top to bottom, left to right + /// + /// collection of unique grid cells. + internal virtual ICollection GetUniqueGridCells(int iterationOrder) { + ICollection result = new LinkedHashSet(); + if (iterationOrder == ROW_ORDER) { + foreach (IList cellsRow in rows) { + foreach (GridCell cell in cellsRow) { + if (cell != null) { + result.Add(cell); + } + } + } + } + if (iterationOrder == COLUMN_ORDER) { + for (int j = 0; j < rows[0].Count; ++j) { + for (int i = 0; i < rows.Count; ++i) { + if (rows[i][j] != null) { + result.Add(rows[i][j]); + } + } + } + } + return result; + } + + /// align all cells in the specified row. + /// row to iterate + /// new pos on a grid at which row should end + internal virtual void AlignRow(int row, float value) { + GridCell previousCell = null; + foreach (GridCell cell in rows[row]) { + if (cell == null) { + continue; + } + // previousCell is used to avoid multiple area updating for items which spread through few cells + if (previousCell != cell && cell.GetLayoutArea().GetTop() < value) { + cell.GetLayoutArea().SetHeight(value - cell.GetLayoutArea().GetY()); + } + previousCell = cell; + } + } + + /// align all cells in the specified column. + /// column to iterate + /// new pos on a grid at which column should end + internal virtual void AlignColumn(int column, float value) { + GridCell previousCell = null; + for (int i = 0; i < rows.Count; ++i) { + GridCell cell = rows[i][column]; + if (cell == null) { + continue; + } + // previousCell is used to avoid multiple area updating for items which spread through few cells + if (previousCell != cell && cell.GetLayoutArea().GetRight() < value) { + cell.GetLayoutArea().SetWidth(value - cell.GetLayoutArea().GetX()); + } + previousCell = cell; + } + } + + internal virtual float GetMaxRowTop(int y, int x) { + IList row = rows[y]; + float maxTop = 0.0f; + for (int i = 0; i < x; ++i) { + if (row[i] == null || row[i].GetLayoutArea() == null) { + continue; + } + //process cells which end at the same row + if (row[i].GetLayoutArea().GetTop() > maxTop && row[i].GetRowEnd() == y + 1) { + maxTop = row[i].GetLayoutArea().GetTop(); + } + } + return maxTop; + } + + internal virtual float GetMaxColumnRight(int y, int x) { + float maxRight = 0.0f; + for (int i = 0; i < y; ++i) { + GridCell cell = rows[i][x]; + if (cell == null || cell.GetLayoutArea() == null) { + continue; + } + //process cells which ends in the same column + if (cell.GetLayoutArea().GetRight() > maxRight && cell.GetColumnEnd() == x + 1) { + maxRight = cell.GetLayoutArea().GetRight(); + } + } + return maxRight; + } + + /// Add cell in the grid, checking that it would fit and initializing it upper left corner (x, y). + /// cell to and in the grid + internal virtual void AddCell(GridCell cell) { + EnsureGridSize(cell.GetRowEnd(), cell.GetColumnEnd()); + SetStartingRowAndColumn(cell); + for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { + for (int j = cell.GetColumnStart(); j < cell.GetColumnEnd(); ++j) { + rows[i][j] = cell; + } + } + } + + public virtual void SetMinHeight(float minHeight) { + this.minHeight = minHeight; + } + + public virtual void SetMinWidth(float minWidth) { + this.minWidth = minWidth; + } + + private void SetStartingRowAndColumn(GridCell cell) { + if (cell.GetColumnStart() != -1 && cell.GetRowStart() != -1) { + // cells which take more than 1 grid cells vertically and horizontally can't be moved + for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { + for (int j = cell.GetColumnStart(); j < cell.GetColumnEnd(); ++j) { + if (rows[i][j] != null) { + throw new ArgumentException(LayoutExceptionMessageConstant.INVALID_CELL_INDEXES); + } + } + } + } + else { + if (cell.GetColumnStart() != -1) { + cellPacker.FitHorizontalCell(cell); + } + else { + if (cell.GetRowStart() != -1) { + cellPacker.FitVerticalCell(cell); + } + else { + cellPacker.FitSimpleCell(cell); + } + } + } + } + + /// Resize grid to ensure that right bottom corner of a cell will fit into the grid. + /// end row pos of a cell on a grid + /// end column pos of a cell on a grid + private void EnsureGridSize(int rowEnd, int columnEnd) { + int maxRowSize = -1; + for (int i = 0; i < Math.Max(rowEnd, rows.Count); i++) { + IList row; + if (i >= rows.Count) { + row = new List(); + rows.Add(row); + } + else { + row = rows[i]; + } + maxRowSize = Math.Max(maxRowSize, row.Count); + for (int j = row.Count; j < Math.Max(columnEnd, maxRowSize); j++) { + row.Add(null); + } + } + } + + //TODO DEVSIX-8323 Right now "row sparse" and "row dense" algorithms are implemented + // implement "column sparse" and "column dense" the only thing which changes is winding order of a grid. + // One will need to create a "view" on cellRows which is rotated 90 degrees to the right and also swap parameters + // for the ensureGridSize in such a case + private class CellPacker { + //Determines whether to use "dense" or "sparse" packing algorithm + private readonly bool densePacking; + + private int placementCursorX = 0; + + private int placementCursorY = 0; + + internal CellPacker(Grid _enclosing, bool densePacking) { + this._enclosing = _enclosing; + this.densePacking = densePacking; + } + + //TODO DEVSIX-8323 double check with https://drafts.csswg.org/css-grid/#grid-item-placement-algorithm + // they have 2 cases for such cells however I could not find a case for “sparse” and “dense” packing to + // be different + /// + /// init vertical (GridCell#getGridHeight() > 1) + /// GridCell upper left corner to fit it in the grid + /// + /// cell to fit + internal virtual void FitVerticalCell(GridCell cell) { + for (int j = 0; j < this._enclosing.rows[0].Count; ++j) { + bool found = true; + for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { + if (this._enclosing.rows[i][j] != null) { + found = false; + break; + } + } + if (found) { + cell.SetStartingRowAndColumn(cell.GetRowStart(), j); + return; + } + } + cell.SetStartingRowAndColumn(cell.GetRowStart(), this._enclosing.rows[0].Count); + this._enclosing.EnsureGridSize(-1, this._enclosing.rows[0].Count + 1); + } + + /// + /// init horizontal (GridCell#getColumnEnd() - GridCell#getColumnStart() > 1) + /// GridCell upper left corner to fit it in the grid + /// + /// cell to fit + internal virtual void FitHorizontalCell(GridCell cell) { + // All comments bellow are for the "sparse" packing, dense packing is much simpler and is achieved by + // disabling placement cursor + //Increment the cursor’s row position until a value is found where the grid item + // does not overlap any occupied grid cells (creating new rows in the implicit grid as necessary). + for (int i = this.GetPlacementCursorY(); i < this._enclosing.rows.Count; ++i, ++this.placementCursorY) { + //Set the column position of the cursor to the grid item’s column-start line. + // If this is less than the previous column position of the cursor, increment the row position by 1. + if (cell.GetColumnStart() < this.GetPlacementCursorX()) { + this.placementCursorX = cell.GetColumnStart(); + continue; + } + this.placementCursorX = cell.GetColumnStart(); + bool found = true; + for (int j = cell.GetColumnStart(); j < cell.GetColumnEnd(); ++j, ++this.placementCursorX) { + if (this._enclosing.rows[i][j] != null) { + found = false; + break; + } + } + if (found) { + //Set the item’s row-start line to the cursor’s row position + cell.SetStartingRowAndColumn(i, cell.GetColumnStart()); + return; + } + } + cell.SetStartingRowAndColumn(this._enclosing.rows.Count, cell.GetColumnStart()); + this._enclosing.EnsureGridSize(this._enclosing.rows.Count + 1, -1); + } + + /// + /// init simple (cell height = width = 1) + /// GridCell upper left corner to fit it in the grid + /// + /// cell to fit + internal virtual void FitSimpleCell(GridCell cell) { + //Algorithm the same as for horizontal cells except we're not checking for overlapping + //and just placing the cell to the first space place + for (int i = this.GetPlacementCursorY(); i < this._enclosing.rows.Count; ++i, ++this.placementCursorY) { + for (int j = this.GetPlacementCursorX(); j < this._enclosing.rows[i].Count; ++j, ++this.placementCursorX) { + if (this._enclosing.rows[i][j] == null) { + cell.SetStartingRowAndColumn(i, j); + return; + } + } + this.placementCursorX = 0; + } + cell.SetStartingRowAndColumn(this._enclosing.rows.Count, 0); + this._enclosing.EnsureGridSize(this._enclosing.rows.Count + 1, -1); + } + + //If it's dense packing, then it's enough to just disable placement cursors + // and search for a spare place for the cell from the start of the grid. + internal virtual int GetPlacementCursorX() { + return this.densePacking ? 0 : this.placementCursorX; + } + + internal virtual int GetPlacementCursorY() { + return this.densePacking ? 0 : this.placementCursorY; + } + + private readonly Grid _enclosing; + } + } +} diff --git a/itext/itext.layout/itext/layout/renderer/GridCell.cs b/itext/itext.layout/itext/layout/renderer/GridCell.cs new file mode 100644 index 0000000000..bd4b9cef5f --- /dev/null +++ b/itext/itext.layout/itext/layout/renderer/GridCell.cs @@ -0,0 +1,163 @@ +using System; +using iText.Kernel.Geom; +using iText.Layout.Properties; + +namespace iText.Layout.Renderer { + internal class GridCell { + private readonly IRenderer value; + + private readonly GridCell.IntRectangle gridArea; + + private Rectangle layoutArea = new Rectangle(0.0f, 0.0f, 0.0f, 0.0f); + + private bool isValueFitOnCellArea = true; + + /// Create a grid cell and init value renderer position on a grid based on its properties. + /// item renderer + internal GridCell(IRenderer value) { + this.value = value; + int[] rowValues = InitRowColumnsValues(value.GetProperty(Property.GRID_ROW_START), value.GetProperty + (Property.GRID_ROW_END)); + int height = rowValues[0] == 0 ? 1 : rowValues[1] - rowValues[0]; + int[] columnValues = InitRowColumnsValues(value.GetProperty(Property.GRID_COLUMN_START), value.GetProperty + (Property.GRID_COLUMN_END)); + int width = columnValues[0] == 0 ? 1 : columnValues[1] - columnValues[0]; + gridArea = new GridCell.IntRectangle(columnValues[0] - 1, rowValues[0] - 1, width, height); + } + + internal virtual int GetColumnStart() { + return gridArea.GetLeft(); + } + + internal virtual int GetColumnEnd() { + return gridArea.GetRight(); + } + + internal virtual int GetRowStart() { + return gridArea.GetBottom(); + } + + internal virtual int GetRowEnd() { + return gridArea.GetTop(); + } + + internal virtual int GetGridHeight() { + return gridArea.GetHeight(); + } + + internal virtual int GetGridWidth() { + return gridArea.GetWidth(); + } + + internal virtual IRenderer GetValue() { + return value; + } + + internal virtual bool IsValueFitOnCellArea() { + return isValueFitOnCellArea; + } + + internal virtual Rectangle GetLayoutArea() { + return layoutArea; + } + + internal virtual void SetLayoutArea(Rectangle layoutArea) { + this.layoutArea = layoutArea; + } + + internal virtual void SetValueFitOnCellArea(bool valueFitOnCellArea) { + isValueFitOnCellArea = valueFitOnCellArea; + } + + internal virtual void SetStartingRowAndColumn(int row, int column) { + this.gridArea.SetY(row); + this.gridArea.SetX(column); + } + + /// + /// init row/column start/end value + /// if start > end values are swapped + /// if only start or end are specified - other value is initialized so cell would have height/width = 1 + /// + /// x/y pos of cell on a grid + /// x/y + width/height pos of cell on a grid + /// + private int[] InitRowColumnsValues(int? start, int? end) { + int[] result = new int[] { 0, 0 }; + if (start != null && end != null) { + result[0] = (int)start; + result[1] = (int)end; + if (start > end) { + result[0] = (int)end; + result[1] = (int)start; + } + } + else { + if (start != null) { + result[0] = (int)start; + result[1] = (int)start + 1; + } + else { + if (end != null) { + result[0] = end <= 1 ? 1 : ((int)end) - 1; + result[1] = end <= 1 ? 2 : (int)end; + } + } + } + return result; + } + + private class IntRectangle { + private int x; + + private int y; + + private int width; + + private int height; + + public IntRectangle(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public virtual int GetLeft() { + return x; + } + + public virtual int GetRight() { + return x + width; + } + + public virtual int GetTop() { + return y + height; + } + + public virtual int GetBottom() { + return y; + } + + public virtual int GetWidth() { + return width; + } + + public virtual int GetHeight() { + return height; + } + + public virtual void SetX(int x) { + this.x = x; + } + + public virtual void SetY(int y) { + this.y = y; + } + + public override String ToString() { + return "Rectangle: start(" + x + ',' + y + ") ," + width + 'x' + height; + } + } + } +} diff --git a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs new file mode 100644 index 0000000000..4e1b1b4478 --- /dev/null +++ b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using iText.Commons.Utils; +using iText.Kernel.Geom; +using iText.Layout.Borders; +using iText.Layout.Element; +using iText.Layout.Layout; +using iText.Layout.Properties; + +namespace iText.Layout.Renderer { + /// Represents a renderer for a grid. + public class GridContainerRenderer : DivRenderer { + private bool isFirstLayout = true; + + /// Creates a Grid renderer from its corresponding layout object. + /// + /// the + /// + /// which this object should manage + /// + public GridContainerRenderer(GridContainer modelElement) + : base(modelElement) { + } + + /// + public override IRenderer GetNextRenderer() { + LogWarningIfGetNextRendererNotOverridden(typeof(iText.Layout.Renderer.GridContainerRenderer), this.GetType + ()); + return new iText.Layout.Renderer.GridContainerRenderer((GridContainer)modelElement); + } + + /// + public override LayoutResult Layout(LayoutContext layoutContext) { + //TODO DEVSIX-8331 enable continuous container, right now its not working properly out of the box because + // we don't need to enable it for every element in a grid, probably only to those which get + // split by a page + //this.setProperty(Property.TREAT_AS_CONTINUOUS_CONTAINER, Boolean.TRUE); + Rectangle actualBBox = layoutContext.GetArea().GetBBox().Clone(); + float? blockWidth = RetrieveWidth(actualBBox.GetWidth()); + if (blockWidth != null) { + actualBBox.SetWidth((float)blockWidth); + } + ContinuousContainer.SetupContinuousContainerIfNeeded(this); + ApplyPaddings(actualBBox, false); + ApplyBorderBox(actualBBox, false); + ApplyMargins(actualBBox, false); + Grid grid = ConstructGrid(this, actualBBox); + GridContainerRenderer.GridLayoutResult layoutResult = LayoutGrid(layoutContext, actualBBox, grid); + //TODO DEVSIX-8329 improve nothing processing, consider checking for cause of nothing here? + //TODO DEVSIX-8329 improve forced placement logic + if (layoutResult.GetSplitRenderers().IsEmpty()) { + if (true.Equals(this.GetProperty(Property.FORCED_PLACEMENT))) { + this.occupiedArea = CalculateContainerOccupiedArea(layoutContext, grid, true); + return new LayoutResult(LayoutResult.FULL, this.occupiedArea, this, null); + } + IRenderer cause = this; + if (!layoutResult.GetCauseOfNothing().IsEmpty()) { + cause = layoutResult.GetCauseOfNothing()[0]; + } + return new LayoutResult(LayoutResult.NOTHING, null, null, this, cause); + } + else { + if (layoutResult.GetOverflowRenderers().IsEmpty()) { + ContinuousContainer continuousContainer = this.GetProperty(Property.TREAT_AS_CONTINUOUS_CONTAINER_RESULT + ); + if (continuousContainer != null) { + continuousContainer.ReApplyProperties(this); + } + this.childRenderers.Clear(); + this.AddAllChildRenderers(layoutResult.GetSplitRenderers()); + this.occupiedArea = CalculateContainerOccupiedArea(layoutContext, grid, true); + return new LayoutResult(LayoutResult.FULL, this.occupiedArea, this, null); + } + else { + this.occupiedArea = CalculateContainerOccupiedArea(layoutContext, grid, false); + return new LayoutResult(LayoutResult.PARTIAL, this.occupiedArea, CreateSplitRenderer(layoutResult.GetSplitRenderers + ()), CreateOverflowRenderer(layoutResult.GetOverflowRenderers())); + } + } + } + + private AbstractRenderer CreateSplitRenderer(IList children) { + AbstractRenderer splitRenderer = (AbstractRenderer)GetNextRenderer(); + splitRenderer.parent = parent; + splitRenderer.modelElement = modelElement; + splitRenderer.occupiedArea = occupiedArea; + splitRenderer.isLastRendererForModelElement = false; + splitRenderer.SetChildRenderers(children); + splitRenderer.AddAllProperties(GetOwnProperties()); + ContinuousContainer.SetupContinuousContainerIfNeeded(splitRenderer); + return splitRenderer; + } + + private AbstractRenderer CreateOverflowRenderer(IList children) { + iText.Layout.Renderer.GridContainerRenderer overflowRenderer = (iText.Layout.Renderer.GridContainerRenderer + )GetNextRenderer(); + overflowRenderer.isFirstLayout = false; + overflowRenderer.parent = parent; + overflowRenderer.modelElement = modelElement; + overflowRenderer.AddAllProperties(GetOwnProperties()); + overflowRenderer.SetChildRenderers(children); + ContinuousContainer.ClearPropertiesFromOverFlowRenderer(overflowRenderer); + return overflowRenderer; + } + + //Process cells by doing actual layout on the calculated layout area + private GridContainerRenderer.GridLayoutResult LayoutGrid(LayoutContext layoutContext, Rectangle actualBBox + , Grid grid) { + GridContainerRenderer.GridLayoutResult layoutResult = new GridContainerRenderer.GridLayoutResult(); + EnsureTemplateValuesFit(grid, actualBBox); + //TODO DEVSIX-8329 improve forced placement logic, right now if we have a cell which could not be fitted on its + // area or returns nothing as layout result RootRenderer sets FORCED_PLACEMENT on this class instance. + // And basically every cell inherits this value and force placed, but we only need to force place cells + // which were not fitted originally. + foreach (GridCell cell in grid.GetUniqueGridCells(Grid.ROW_ORDER)) { + //If cell couldn't fit during cell layout area calculation than we need to put such cell straight to + //nothing result list + if (!cell.IsValueFitOnCellArea()) { + layoutResult.GetOverflowRenderers().Add(cell.GetValue()); + layoutResult.GetCauseOfNothing().Add(cell.GetValue()); + continue; + } + //Calculate cell layout context by getting actual x and y on parent layout area for it + LayoutContext cellContext = GetCellLayoutContext(layoutContext, actualBBox, cell); + //We need to check for forced placement here, because otherwise we would infinitely return partial result. + if (!true.Equals(this.GetProperty(Property.FORCED_PLACEMENT)) && !actualBBox.Contains(cellContext.GetArea + ().GetBBox())) { + layoutResult.GetOverflowRenderers().Add(cell.GetValue()); + continue; + } + IRenderer cellToRender = cell.GetValue(); + cellToRender.SetProperty(Property.FILL_AVAILABLE_AREA, true); + cellToRender.SetProperty(Property.COLLAPSING_MARGINS, false); + LayoutResult cellResult = cellToRender.Layout(cellContext); + if (cellResult.GetStatus() == LayoutResult.NOTHING) { + layoutResult.GetOverflowRenderers().Add(cellToRender); + layoutResult.GetCauseOfNothing().Add(cellResult.GetCauseOfNothing()); + } + else { + // PARTIAL + FULL result handling + layoutResult.GetSplitRenderers().Add(cellToRender); + if (cellResult.GetStatus() == LayoutResult.PARTIAL) { + layoutResult.GetOverflowRenderers().Add(cellResult.GetOverflowRenderer()); + } + } + } + return layoutResult; + } + + private void EnsureTemplateValuesFit(Grid grid, Rectangle actualBBox) { + if (grid.GetMinWidth() > actualBBox.GetWidth()) { + actualBBox.SetWidth(grid.GetMinWidth()); + } + } + + //Init cell layout context based on a parent context and calculated cell layout area from grid sizing algorithm. + private static LayoutContext GetCellLayoutContext(LayoutContext layoutContext, Rectangle actualBBox, GridCell + cell) { + LayoutArea tempArea = layoutContext.GetArea().Clone(); + Rectangle cellLayoutArea = cell.GetLayoutArea(); + tempArea.GetBBox().SetX(actualBBox.GetX() + cellLayoutArea.GetX()); + tempArea.GetBBox().SetY(actualBBox.GetY() + actualBBox.GetHeight() - cellLayoutArea.GetHeight() - cellLayoutArea + .GetY()); + tempArea.GetBBox().SetWidth(actualBBox.GetWidth()); + if (cellLayoutArea.GetWidth() > 0) { + tempArea.GetBBox().SetWidth(cellLayoutArea.GetWidth()); + } + tempArea.GetBBox().SetHeight(cellLayoutArea.GetHeight()); + return new LayoutContext(tempArea, layoutContext.GetMarginsCollapseInfo(), layoutContext.GetFloatRendererAreas + (), layoutContext.IsClippedHeight()); + } + + //calculate grid container occupied area based on its width/height properties and cell layout areas + private LayoutArea CalculateContainerOccupiedArea(LayoutContext layoutContext, Grid grid, bool isFull) { + LayoutArea area = layoutContext.GetArea().Clone(); + float totalHeight = UpdateOccupiedHeight(grid.GetHeight(), isFull); + area.GetBBox().SetHeight(totalHeight); + Rectangle initialBBox = layoutContext.GetArea().GetBBox(); + area.GetBBox().SetY(initialBBox.GetY() + initialBBox.GetHeight() - area.GetBBox().GetHeight()); + RecalculateHeightAndWidthAfterLayout(area.GetBBox(), isFull); + return area; + } + + //TODO DEVSIX-8330: Probably height also has to be calculated before layout and set into actual bbox + private void RecalculateHeightAndWidthAfterLayout(Rectangle bBox, bool isFull) { + float? height = RetrieveHeight(); + if (height != null) { + height = UpdateOccupiedHeight((float)height, isFull); + float heightDelta = bBox.GetHeight() - (float)height; + bBox.MoveUp(heightDelta); + bBox.SetHeight((float)height); + } + float? blockWidth = RetrieveWidth(bBox.GetWidth()); + if (blockWidth != null) { + bBox.SetWidth((float)blockWidth); + } + } + + //TODO DEVSIX-8330: Consider extracting this method and same from MulticolRenderer to a separate class + // or derive GridRenderer and MulticolRenderer from one class which will manage this and isFirstLayout field + private float UpdateOccupiedHeight(float initialHeight, bool isFull) { + if (isFull) { + initialHeight += SafelyRetrieveFloatProperty(Property.PADDING_BOTTOM); + initialHeight += SafelyRetrieveFloatProperty(Property.MARGIN_BOTTOM); + if (!this.HasOwnProperty(Property.BORDER) || this.GetProperty(Property.BORDER) == null) { + initialHeight += SafelyRetrieveFloatProperty(Property.BORDER_BOTTOM); + } + } + initialHeight += SafelyRetrieveFloatProperty(Property.PADDING_TOP); + initialHeight += SafelyRetrieveFloatProperty(Property.MARGIN_TOP); + if (!this.HasOwnProperty(Property.BORDER) || this.GetProperty(Property.BORDER) == null) { + initialHeight += SafelyRetrieveFloatProperty(Property.BORDER_TOP); + } + // isFirstLayout is necessary to handle the case when grid container laid out on more + // than 2 pages, and on the last page layout result is full, but there is no bottom border + float TOP_AND_BOTTOM = isFull && isFirstLayout ? 2 : 1; + //If container laid out on more than 3 pages, then it is a page where there are no bottom and top borders + if (!isFull && !isFirstLayout) { + TOP_AND_BOTTOM = 0; + } + initialHeight += SafelyRetrieveFloatProperty(Property.BORDER) * TOP_AND_BOTTOM; + return initialHeight; + } + + private float SafelyRetrieveFloatProperty(int property) { + Object value = this.GetProperty(property); + if (value is UnitValue) { + return ((UnitValue)value).GetValue(); + } + if (value is Border) { + return ((Border)value).GetWidth(); + } + return 0F; + } + + //Grid layout algorithm is based on a https://drafts.csswg.org/css-grid/#layout-algorithm + //It's not a 1 to 1 implementation and Grid Sizing Algorithm differs a little bit + //TODO DEVSIX-8324 Left actualBBox parameter since it will be needed for fr and % calculations + // if it is inline-grid, than it won't be needed. + private static Grid ConstructGrid(iText.Layout.Renderer.GridContainerRenderer renderer, Rectangle actualBBox + ) { + //TODO DEVSIX-8324 create a new class GridTemplateValue, which will store fr, pt, %, minmax, etc. values + //TODO DEVSIX-8324 Use this new class instead of Float and use it inside Grid Sizing Algorithm + //TODO DEVSIX-8324 Right now we're assuming that all template values are points, and there is no % and fr in this list + IList templateColumns = ProcessTemplateValues(renderer.GetProperty>(Property.GRID_TEMPLATE_COLUMNS + )); + IList templateRows = ProcessTemplateValues(renderer.GetProperty>(Property.GRID_TEMPLATE_ROWS + )); + float? columnAutoWidth = renderer.GetProperty(Property.GRID_AUTO_COLUMNS) == null ? null : (float? + )((UnitValue)renderer.GetProperty(Property.GRID_AUTO_COLUMNS)).GetValue(); + float? rowAutoHeight = renderer.GetProperty(Property.GRID_AUTO_ROWS) == null ? null : (float?)( + (UnitValue)renderer.GetProperty(Property.GRID_AUTO_ROWS)).GetValue(); + //Grid Item Placement Algorithm + int initialRowsCount = templateRows == null ? 1 : templateRows.Count; + int initialColumnsCount = templateColumns == null ? 1 : templateColumns.Count; + //Sort cells to first position anything that’s not auto-positioned, then process the items locked to a given row. + //It would be better to use tree set here, but not using it due to .NET porting issues + IList sortedCells = new List(); + foreach (IRenderer child in renderer.GetChildRenderers()) { + sortedCells.Add(new GridCell(child)); + } + JavaCollectionsUtil.Sort(sortedCells, new GridContainerRenderer.CellComparator()); + //Find a cell with a max column end to ensure it will fit on the grid + foreach (GridCell cell in sortedCells) { + if (cell != null) { + initialColumnsCount = Math.Max(initialColumnsCount, cell.GetColumnEnd()); + } + } + Grid grid = new Grid(initialRowsCount, initialColumnsCount, false); + foreach (GridCell cell in sortedCells) { + cell.GetValue().SetParent(renderer); + grid.AddCell(cell); + } + //TODO DEVSIX-8325 eliminate null rows/columns + // for rows it's easy: grid.getCellsRows().removeIf(row -> row.stream().allMatch(cell -> cell == null)); + // shrinkNullAxis(grid); + GridSizer gridSizer = new GridSizer(grid, templateRows, templateColumns, rowAutoHeight, columnAutoWidth); + gridSizer.SizeCells(); + //calculating explicit height to ensure that even empty rows which covered by template would be considered + //TODO DEVSIX-8324 improve those methods in future for working correctly with minmax/repeat/etc. + SetGridContainerMinimalHeight(grid, templateRows); + SetGridContainerMinimalWidth(grid, templateColumns); + return grid; + } + + //TODO DEVSIX-8324 This is temporary method, we should remove it and instead of having Property.GRID_TEMPLATE_... + // as a UnitValue and returning list of Float, we need a new class which will be passed to Grid Sizing Algorithm. + private static IList ProcessTemplateValues(IList template) { + if (template == null) { + return null; + } + return template.Select((value) => value.GetValue()).ToList(); + } + + //This method calculates container minimal height, because if number of cells is not enough to fill all specified + //rows by template than we need to set the height of the container higher than it's actual occupied height. + private static void SetGridContainerMinimalHeight(Grid grid, IList templateRows) { + float explicitContainerHeight = 0.0f; + if (templateRows != null) { + foreach (float? template in templateRows) { + explicitContainerHeight += (float)template; + } + } + grid.SetMinHeight(explicitContainerHeight); + } + + private static void SetGridContainerMinimalWidth(Grid grid, IList templateColumns) { + float explicitContainerWidth = 0.0f; + if (templateColumns != null) { + foreach (float? template in templateColumns) { + explicitContainerWidth += (float)template; + } + } + grid.SetMinWidth(explicitContainerWidth); + } + + /// + /// This comparator sorts cells so ones with both fixed row and column positions would go first, + /// then cells with fixed row and then cells without such properties. + /// + private sealed class CellComparator : IComparer { + public int Compare(GridCell lhs, GridCell rhs) { + int lhsModifiers = 0; + if (lhs.GetColumnStart() != -1 && lhs.GetRowStart() != -1) { + lhsModifiers = 2; + } + else { + if (lhs.GetRowStart() != -1) { + lhsModifiers = 1; + } + } + int rhsModifiers = 0; + if (rhs.GetColumnStart() != -1 && rhs.GetRowStart() != -1) { + rhsModifiers = 2; + } + else { + if (rhs.GetRowStart() != -1) { + rhsModifiers = 1; + } + } + //passing parameters in reversed order so ones with properties would come first + return JavaUtil.IntegerCompare(rhsModifiers, lhsModifiers); + } + } + + private sealed class GridLayoutResult { + private readonly IList splitRenderers = new List(); + + private readonly IList overflowRenderers = new List(); + + private readonly IList causeOfNothing = new List(); + + public GridLayoutResult() { + } + + //default constructor + public IList GetSplitRenderers() { + return splitRenderers; + } + + public IList GetOverflowRenderers() { + return overflowRenderers; + } + + public IList GetCauseOfNothing() { + return causeOfNothing; + } + } + } +} diff --git a/itext/itext.layout/itext/layout/renderer/GridSizer.cs b/itext/itext.layout/itext/layout/renderer/GridSizer.cs new file mode 100644 index 0000000000..319d9b18cb --- /dev/null +++ b/itext/itext.layout/itext/layout/renderer/GridSizer.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using iText.Kernel.Geom; +using iText.Layout.Layout; +using iText.Layout.Properties; + +namespace iText.Layout.Renderer { + /// This class is responsible for sizing grid elements and calculating their layout area for future layout process. + /// + internal class GridSizer { + private readonly Grid grid; + + //TODO DEVSIX-8326 since templates will have not only absoulute values, we're probably need to create + // separate fields, something like rowsHeights, columnsWidths which will store absolute/calculated values. + // replace all absolute value logic using this new fields + private readonly IList templateRows; + + private readonly IList templateColumns; + + private readonly float? rowAutoHeight; + + private readonly float? columnAutoWidth; + + //TODO DEVSIX-8326 here should be a list/map of different resolvers + private readonly GridSizer.SizeResolver sizeResolver; + + internal GridSizer(Grid grid, IList templateRows, IList templateColumns, float? rowAutoHeight + , float? columnAutoWidth) { + this.grid = grid; + this.templateRows = templateRows; + this.templateColumns = templateColumns; + this.rowAutoHeight = rowAutoHeight; + this.columnAutoWidth = columnAutoWidth; + this.sizeResolver = new GridSizer.MinContentResolver(grid); + } + + //Grid Sizing Algorithm + /// This method simulates positioning of cells on the grid, by calculating their occupied area. + /// + /// This method simulates positioning of cells on the grid, by calculating their occupied area. + /// If there was enough place to fit the renderer value of a cell on the grid, then such cell will be marked as + /// non-fit and will be added to nothing result during actual layout. + /// + internal virtual void SizeCells() { + //TODO DEVSIX-8326 if rowsAutoSize/columnsAutoSize == auto/fr/min-content/max-content we need to track the + // corresponding values of the elements and update auto height/width after calculating each cell layout area + // and if its changed than re-layout + //Grid Sizing Algorithm + foreach (GridCell cell in grid.GetUniqueGridCells(Grid.COLUMN_ORDER)) { + cell.GetLayoutArea().SetX(CalculateCellX(cell)); + cell.GetLayoutArea().SetWidth(CalculateCellWidth(cell)); + } + foreach (GridCell cell in grid.GetUniqueGridCells(Grid.ROW_ORDER)) { + cell.GetLayoutArea().SetY(CalculateCellY(cell)); + cell.GetLayoutArea().SetHeight(CalculateCellHeight(cell)); + } + } + + /// Calculate cell left upper corner y position. + /// cell to calculate starting position + /// left upper corner y value + private float CalculateCellY(GridCell cell) { + //For y we always know that there is a top neighbor at least in one column (because if not it means there + //is a null row) and all cells in a row above have the same top. + GridCell topNeighbor = grid.GetClosestTopNeighbor(cell); + if (topNeighbor != null) { + return topNeighbor.GetLayoutArea().GetTop(); + } + return 0.0f; + } + + /// Calculate cell left upper corner x position. + /// cell to calculate starting position + /// left upper corner x value + private float CalculateCellX(GridCell cell) { + float x = 0.0f; + int currentColumn = 0; + if (templateColumns != null) { + for (; currentColumn < Math.Min(templateColumns.Count, cell.GetColumnStart()); ++currentColumn) { + x += (float)templateColumns[currentColumn]; + } + if (currentColumn == cell.GetColumnStart()) { + return x; + } + } + if (columnAutoWidth != null) { + for (; currentColumn < cell.GetColumnStart(); ++currentColumn) { + x += (float)columnAutoWidth; + } + return x; + } + GridCell leftNeighbor = grid.GetClosestLeftNeighbor(cell); + if (leftNeighbor != null) { + if (leftNeighbor.GetColumnEnd() > cell.GetColumnStart()) { + x = leftNeighbor.GetLayoutArea().GetX() + leftNeighbor.GetLayoutArea().GetWidth() * ((float)(cell.GetColumnStart + () - leftNeighbor.GetColumnStart())) / leftNeighbor.GetGridWidth(); + } + else { + x = leftNeighbor.GetLayoutArea().GetRight(); + } + } + return x; + } + + //TODO DEVSIX-8327 Calculate fr units of rowsAutoSize here + //TODO DEVSIX-8327 currently the default behaviour when there is no templateRows or rowAutoHeight is + // css grid-auto-columns: min-content analogue, the default one should be 1fr + // (for rows they are somewhat similar, if there where no fr values in templateRows, then the + // size of all subsequent rows is the size of the highest row after templateRows + //TODO DEVSIX-8327 add a comment for this method and how it works (not done in the scope of previous ticket + // because logic will be changed after fr value implementation) + private float CalculateCellHeight(GridCell cell) { + float cellHeight = 0.0f; + //process cells with grid height > 1; + if (cell.GetGridHeight() > 1) { + int counter = 0; + for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { + if (templateRows != null && i < templateRows.Count) { + ++counter; + cellHeight += (float)templateRows[i]; + } + else { + if (rowAutoHeight != null) { + ++counter; + cellHeight += (float)rowAutoHeight; + } + } + } + if (counter == cell.GetGridHeight()) { + return cellHeight; + } + } + if (templateRows == null || cell.GetRowStart() >= templateRows.Count) { + //TODO DEVSIX-8324 if row auto height value is fr or min-content do not return here + if (rowAutoHeight != null) { + return (float)rowAutoHeight; + } + cellHeight = sizeResolver.ResolveHeight(cell, cellHeight); + } + else { + cellHeight = templateRows[cell.GetRowStart()]; + } + return cellHeight; + } + + //TODO DEVSIX-8327 currently the default behaviour when there is no templateColumns or columnAutoWidth is + // css grid-auto-columns: min-content analogue, the default one should be 1fr + private float CalculateCellWidth(GridCell cell) { + float cellWidth = 0.0f; + //process absolute values for wide cells + if (cell.GetGridWidth() > 1) { + int counter = 0; + for (int i = cell.GetColumnStart(); i < cell.GetColumnEnd(); ++i) { + if (templateColumns != null && i < templateColumns.Count) { + ++counter; + cellWidth += templateColumns[i]; + } + else { + if (columnAutoWidth != null) { + ++counter; + cellWidth += (float)columnAutoWidth; + } + } + } + if (counter == cell.GetGridWidth()) { + return cellWidth; + } + } + if (templateColumns == null || cell.GetColumnEnd() > templateColumns.Count) { + //TODO DEVSIX-8324 if row auto width value is fr or min-content do not return here + if (columnAutoWidth != null) { + return (float)columnAutoWidth; + } + cellWidth = sizeResolver.ResolveWidth(cell, cellWidth); + } + else { + //process absolute template values + cellWidth = templateColumns[cell.GetColumnStart()]; + } + return cellWidth; + } + + protected internal abstract class SizeResolver { + protected internal Grid grid; + + public SizeResolver(Grid grid) { + this.grid = grid; + } + + public abstract float ResolveHeight(GridCell cell, float explicitCellHeight); + + public abstract float ResolveWidth(GridCell cell, float explicitCellWidth); + + //TODO DEVSIX-8326 If we're getting LayoutResult = NOTHING (PARTIAL ? if it is even possible) / null occupied area + // from this method, we need to return current default sizing for a grid. + // For min-content - that's should be practically impossible but as a safe guard we can return height of any adjacent + // item in a row + // For fr (flex) unit - currently calculated flex value + // For other relative unit this should be investigated + // Basically this method will only be called for relative values of rowsAutoHeight and we need to carefully think + // what to return if we failed to layout a cell item in a given space + /// Calculate minimal cell height required for cell value to be laid out. + /// cell container in which cell value has to be laid out + /// required height for cell to be laid out + protected internal virtual float CalculateImplicitCellHeight(GridCell cell) { + cell.GetValue().SetProperty(Property.FILL_AVAILABLE_AREA, false); + LayoutResult inifiniteHeighLayoutResult = cell.GetValue().Layout(new LayoutContext(new LayoutArea(1, new Rectangle + (cell.GetLayoutArea().GetWidth(), AbstractRenderer.INF)))); + if (inifiniteHeighLayoutResult.GetStatus() == LayoutResult.NOTHING || inifiniteHeighLayoutResult.GetStatus + () == LayoutResult.PARTIAL) { + cell.SetValueFitOnCellArea(false); + return -1; + } + return inifiniteHeighLayoutResult.GetOccupiedArea().GetBBox().GetHeight(); + } + + /// Calculate minimal cell width required for cell value to be laid out. + /// cell container in which cell value has to be laid out + /// required width for cell to be laid out + protected internal virtual float CalculateMinRequiredCellWidth(GridCell cell) { + cell.GetValue().SetProperty(Property.FILL_AVAILABLE_AREA, false); + if (cell.GetValue() is AbstractRenderer) { + AbstractRenderer abstractRenderer = (AbstractRenderer)cell.GetValue(); + return abstractRenderer.GetMinMaxWidth().GetMinWidth(); + } + return -1; + } + } + + protected internal class MinContentResolver : GridSizer.SizeResolver { + public MinContentResolver(Grid grid) + : base(grid) { + } + + public override float ResolveHeight(GridCell cell, float cellHeight) { + float maxRowTop = grid.GetMaxRowTop(cell.GetRowStart(), cell.GetColumnStart()); + cellHeight = Math.Max(cellHeight, CalculateImplicitCellHeight(cell)); + if (maxRowTop >= cellHeight + cell.GetLayoutArea().GetY()) { + cellHeight = maxRowTop - cell.GetLayoutArea().GetY(); + } + else { + grid.AlignRow(cell.GetRowEnd() - 1, cellHeight + cell.GetLayoutArea().GetY()); + } + return cellHeight; + } + + public override float ResolveWidth(GridCell cell, float cellWidth) { + float maxColumnRight = grid.GetMaxColumnRight(cell.GetRowStart(), cell.GetColumnStart()); + cellWidth = Math.Max(cellWidth, CalculateMinRequiredCellWidth(cell)); + if (maxColumnRight >= cellWidth + cell.GetLayoutArea().GetX()) { + cellWidth = maxColumnRight - cell.GetLayoutArea().GetX(); + } + else { + grid.AlignColumn(cell.GetColumnEnd() - 1, cellWidth + cell.GetLayoutArea().GetX()); + } + return cellWidth; + } + } + } +} diff --git a/port-hash b/port-hash index f66af6e558..6cc5211386 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -9d5273b8cb8f3e98eb1734d93a47e79173b826c6 +b7150dce224d3428e36b76209651abe5934d19c9 From 70802d543466134a805a47422af699fb408c8f11 Mon Sep 17 00:00:00 2001 From: iText Software Date: Fri, 17 May 2024 22:07:39 +0000 Subject: [PATCH 2/2] Add missing copyright headers Autoported commit. Original commit hash: [d68b0e71f] --- .../itext/layout/element/GridContainerTest.cs | 22 +++++++++++++++++++ .../itext/layout/renderer/GridCellUnitTest.cs | 22 +++++++++++++++++++ .../itext/layout/renderer/GridUnitTest.cs | 22 +++++++++++++++++++ .../itext/layout/element/GridContainer.cs | 22 +++++++++++++++++++ .../itext/layout/renderer/Grid.cs | 22 +++++++++++++++++++ .../itext/layout/renderer/GridCell.cs | 22 +++++++++++++++++++ .../layout/renderer/GridContainerRenderer.cs | 22 +++++++++++++++++++ .../itext/layout/renderer/GridSizer.cs | 22 +++++++++++++++++++ port-hash | 2 +- 9 files changed, 177 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs index 7c74856d93..40e1c61f26 100644 --- a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using System.Collections.Generic; using iText.Kernel.Colors; diff --git a/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs b/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs index e7f88fa316..112679dc79 100644 --- a/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/renderer/GridCellUnitTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using iText.Layout.Element; using iText.Layout.Properties; using iText.Test; diff --git a/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs b/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs index 64ebf25dcf..9377b4bc9f 100644 --- a/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using iText.Kernel.Geom; using iText.Layout.Element; using iText.Layout.Properties; diff --git a/itext/itext.layout/itext/layout/element/GridContainer.cs b/itext/itext.layout/itext/layout/element/GridContainer.cs index e960184e73..846aae05f4 100644 --- a/itext/itext.layout/itext/layout/element/GridContainer.cs +++ b/itext/itext.layout/itext/layout/element/GridContainer.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using iText.Layout.Renderer; namespace iText.Layout.Element { diff --git a/itext/itext.layout/itext/layout/renderer/Grid.cs b/itext/itext.layout/itext/layout/renderer/Grid.cs index f756f995c3..62c31717e9 100644 --- a/itext/itext.layout/itext/layout/renderer/Grid.cs +++ b/itext/itext.layout/itext/layout/renderer/Grid.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using System.Collections.Generic; using iText.Commons.Utils; diff --git a/itext/itext.layout/itext/layout/renderer/GridCell.cs b/itext/itext.layout/itext/layout/renderer/GridCell.cs index bd4b9cef5f..72239a115e 100644 --- a/itext/itext.layout/itext/layout/renderer/GridCell.cs +++ b/itext/itext.layout/itext/layout/renderer/GridCell.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using iText.Kernel.Geom; using iText.Layout.Properties; diff --git a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs index 4e1b1b4478..b189525206 100644 --- a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using System.Collections.Generic; using System.Linq; diff --git a/itext/itext.layout/itext/layout/renderer/GridSizer.cs b/itext/itext.layout/itext/layout/renderer/GridSizer.cs index 319d9b18cb..6e168d4cef 100644 --- a/itext/itext.layout/itext/layout/renderer/GridSizer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridSizer.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using System.Collections.Generic; using iText.Kernel.Geom; diff --git a/port-hash b/port-hash index 6cc5211386..30dc4bde35 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -b7150dce224d3428e36b76209651abe5934d19c9 +d68b0e71fd64171f0f8181e8a7e5b7e040499ac5