From 4c95edb7b3c509db668d816e73a96d5f9ce1df91 Mon Sep 17 00:00:00 2001 From: iText Software Date: Fri, 31 May 2024 07:30:44 +0000 Subject: [PATCH 1/2] Update port-hash Remove failOnError config for JavaDoc plugin Autoported commit. Original commit hash: [5805b4e15] Manual files: pom.xml --- port-hash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port-hash b/port-hash index 0a2ff3da82..e50c9d7913 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -4ff74af36d0040767aca1496420dc580beaa1305 +5805b4e1512e640cf44d87df9d728c8cbe5b311a From b15d4e0d22d0d16cb7defda4663c89f9bdabfeb0 Mon Sep 17 00:00:00 2001 From: Dmitry Chubrick Date: Fri, 31 May 2024 12:18:48 +0000 Subject: [PATCH 2/2] Implement basic version of grid track sizing algroithm DEVSIX-8324 Autoported commit. Original commit hash: [aca706e52] --- .../itext/layout/element/GridContainerTest.cs | 162 ++++-- .../gridcontainer/GridContainerLayoutTest.cs | 15 +- .../itext/layout/properties/GridValueTest.cs | 42 +- .../layout/properties/SizingValueTest.cs | 57 -- .../itext/layout/renderer/GridUnitTest.cs | 90 ++-- .../cmp_basicAutoRowsTest.pdf | Bin 1818 -> 1583 bytes ..._basicThreeColumnsWithPtAndPercentTest.pdf | Bin 1445 -> 1470 bytes .../cmp_bigCellMinContentTest.pdf | Bin 1445 -> 1445 bytes .../cmp_columnFlowWithBigCellsTest.pdf | Bin 1283 -> 1278 bytes .../cmp_fewBigCellsWithGapTest.pdf | Bin 1274 -> 1274 bytes .../GridContainerTest/cmp_frColumnsTest.pdf | Bin 0 -> 1496 bytes .../GridContainerTest/cmp_frInRowsTest.pdf | Bin 0 -> 1201 bytes .../itext/layout/properties/GridValue.cs | 206 +++++--- .../itext/layout/properties/SizingValue.cs | 159 ------ .../itext/layout/renderer/Grid.cs | 190 ++----- .../itext/layout/renderer/GridCell.cs | 27 + .../layout/renderer/GridContainerRenderer.cs | 58 +- .../itext/layout/renderer/GridSizer.cs | 334 +++--------- .../itext/layout/renderer/GridTrackSizer.cs | 499 ++++++++++++++++++ .../itext/layout/renderer/GridView.cs | 3 +- port-hash | 2 +- 21 files changed, 949 insertions(+), 895 deletions(-) delete mode 100644 itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_frColumnsTest.pdf create mode 100644 itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_frInRowsTest.pdf delete mode 100644 itext/itext.layout/itext/layout/properties/SizingValue.cs create mode 100644 itext/itext.layout/itext/layout/renderer/GridTrackSizer.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 index b6d97a18c6..215d5976cb 100644 --- a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs @@ -50,9 +50,9 @@ public virtual void BasicThreeColumnsTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); + templateColumns.Add(GridValue.CreatePointValue(150.0f)); + templateColumns.Add(GridValue.CreatePointValue(150.0f)); + templateColumns.Add(GridValue.CreatePointValue(150.0f)); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -73,8 +73,7 @@ public virtual void BasicAutoColumnsTest() { 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, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f - ))); + grid.SetProperty(Property.GRID_AUTO_COLUMNS, GridValue.CreatePointValue(150.0f)); for (int i = 0; i < 5; ++i) { grid.Add(new Paragraph("Test" + i).SetBorder(border)); } @@ -91,8 +90,7 @@ public virtual void BasicAutoRowsTest() { 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, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f) - )); + grid.SetProperty(Property.GRID_AUTO_ROWS, GridValue.CreatePointValue(70.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 " + @@ -109,9 +107,9 @@ public virtual void BasicThreeColumnsWithCustomColumnIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnIndexesTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -137,10 +135,10 @@ public virtual void ThreeColumnsWithAdjacentWideCellsTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithAdjacentWideCellsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithAdjacentWideCellsTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); GridContainer grid = new GridContainer(); @@ -173,9 +171,9 @@ public virtual void BasicThreeColumnsWithCustomRowIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomRowIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -201,9 +199,9 @@ public virtual void BasicThreeColumnsWithCustomColumnAndRowIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -230,9 +228,9 @@ public virtual void BasicThreeColumnsWithReversedIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithReversedIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithReversedIndexesTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -267,9 +265,9 @@ public virtual void BasicThreeColumnsWithoutColumnEndTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithoutColumnEndTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithoutColumnEndTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -302,9 +300,9 @@ public virtual void FixedColumnRowGoesFirstTest() { String filename = DESTINATION_FOLDER + "fixedColumnRowGoesFirstTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_fixedColumnRowGoesFirstTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -347,9 +345,9 @@ public virtual void FixedColumnRowGoesFirstTest() { public virtual void OverlapWithExistingColumnTest() { String filename = DESTINATION_FOLDER + "overlapWithExistingColumnTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -377,14 +375,13 @@ public virtual void OverlapWithExistingColumnTest() { } [NUnit.Framework.Test] - [NUnit.Framework.Ignore("TODO DEVSIX-8324")] public virtual void BasicThreeColumnsWithPtAndPercentTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithPtAndPercentTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithPtAndPercentTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.PERCENT, 15.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.PERCENT, 50.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePercentValue(15.0f)); + templateColumns.Add(GridValue.CreatePercentValue(50.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -403,9 +400,9 @@ public virtual void ThirdColumnNotLayoutedTest() { String filename = DESTINATION_FOLDER + "thirdColumnNotLayoutedTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_thirdColumnNotLayoutedTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); + templateColumns.Add(GridValue.CreatePointValue(200.0f)); + templateColumns.Add(GridValue.CreatePointValue(200.0f)); + templateColumns.Add(GridValue.CreatePointValue(200.0f)); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -424,9 +421,9 @@ public virtual void ThreeColumnsWithSquareAndVerticalCellsTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithSquareAndVerticalCellsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -458,9 +455,9 @@ public virtual void ThreeColumnsWithSquareCellAndCellWithExplicitHeightTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetBackgroundColor(ColorConstants.GREEN); @@ -489,9 +486,9 @@ public virtual void ThreeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTe String filename = DESTINATION_FOLDER + "threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; IList templateColumns = new List(); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); - templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); + templateColumns.Add(GridValue.CreatePointValue(100.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -522,8 +519,11 @@ public virtual void BigCellMinContentTest() { String filename = DESTINATION_FOLDER + "bigCellMinContentTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_bigCellMinContentTest.pdf"; SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateMinContentValue()); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, templateColumns); 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)); @@ -538,14 +538,13 @@ public virtual void ColumnRowGapTest() { String filename = DESTINATION_FOLDER + "columnRowGapTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_columnRowGapTest.pdf"; IList template = new List(); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreatePointValue(50.0f)); + template.Add(GridValue.CreatePointValue(50.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, template); grid.SetProperty(Property.GRID_TEMPLATE_ROWS, template); - grid.SetProperty(Property.GRID_AUTO_ROWS, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 70.0f)) - ); + grid.SetProperty(Property.GRID_AUTO_ROWS, GridValue.CreatePointValue(70.0f)); grid.SetProperty(Property.COLUMN_GAP, 20.0f); grid.SetProperty(Property.ROW_GAP, 20.0f); grid.Add(new Paragraph("One").SetBackgroundColor(ColorConstants.CYAN)); @@ -566,9 +565,9 @@ public virtual void FewBigCellsWithGapTest() { String filename = DESTINATION_FOLDER + "fewBigCellsWithGapTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_fewBigCellsWithGapTest.pdf"; IList template = new List(); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreatePointValue(50.0f)); + template.Add(GridValue.CreatePointValue(50.0f)); + template.Add(GridValue.CreatePointValue(50.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, template); @@ -605,9 +604,9 @@ public virtual void ColumnFlowWithBigCellsTest() { String filename = DESTINATION_FOLDER + "columnFlowWithBigCellsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_columnFlowWithBigCellsTest.pdf"; IList template = new List(); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); - template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreatePointValue(50.0f)); + template.Add(GridValue.CreatePointValue(50.0f)); + template.Add(GridValue.CreatePointValue(50.0f)); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetProperty(Property.GRID_FLOW, GridFlow.COLUMN); @@ -640,5 +639,52 @@ public virtual void ColumnFlowWithBigCellsTest() { NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" )); } + + [NUnit.Framework.Test] + public virtual void FrInRowsTest() { + String filename = DESTINATION_FOLDER + "frInRowsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_frInRowsTest.pdf"; + IList template = new List(); + template.Add(GridValue.CreateFlexValue(1f)); + template.Add(GridValue.CreateFlexValue(3f)); + using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { + GridContainer grid = new GridContainer(); + grid.SetProperty(Property.GRID_TEMPLATE_ROWS, template); + grid.SetProperty(Property.ROW_GAP, 20.0f); + grid.Add(new Paragraph("One").SetBackgroundColor(ColorConstants.CYAN)); + grid.Add(new Paragraph("Two").SetBackgroundColor(ColorConstants.CYAN)); + grid.Add(new Paragraph("Tree").SetBackgroundColor(ColorConstants.CYAN)); + document.Add(grid); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, cmpName, DESTINATION_FOLDER, "diff_" + )); + } + + [NUnit.Framework.Test] + public virtual void FrColumnsTest() { + String filename = DESTINATION_FOLDER + "frColumnsTest.pdf"; + String cmpName = SOURCE_FOLDER + "cmp_frColumnsTest.pdf"; + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateFlexValue(1f)); + templateColumns.Add(GridValue.CreateAutoValue()); + templateColumns.Add(GridValue.CreateFlexValue(3f)); + 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); + grid.Add(new Paragraph("Test1").SetBorder(border)); + grid.Add(new Paragraph("Test2").SetBorder(border)); + grid.Add(new Paragraph("Test3").SetBorder(border)); + Paragraph test4 = new Paragraph("Test4Test4Test4Test4Test4 Test4 Test4 Test4 Test4 Test4 Test4 Test4").SetBorder + (border); + test4.SetProperty(Property.GRID_COLUMN_START, 1); + test4.SetProperty(Property.GRID_COLUMN_END, 3); + grid.Add(test4); + grid.Add(new Paragraph("Test5").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/element/gridcontainer/GridContainerLayoutTest.cs b/itext.tests/itext.layout.tests/itext/layout/element/gridcontainer/GridContainerLayoutTest.cs index 7b8df40040..39a4644d6b 100644 --- a/itext.tests/itext.layout.tests/itext/layout/element/gridcontainer/GridContainerLayoutTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/element/gridcontainer/GridContainerLayoutTest.cs @@ -148,9 +148,8 @@ public virtual void EmptyGridContainerTest() { GridContainer gridcontainer0 = new GridContainer(); gridcontainer0.SetProperty(Property.COLUMN_GAP_BORDER, null); gridcontainer0.SetBackgroundColor(ColorConstants.RED); - gridcontainer0.SetProperty(Property.GRID_TEMPLATE_COLUMNS, JavaUtil.ArraysAsList(GridValue.CreateUnitValue - (new UnitValue(1, 150.0f)), GridValue.CreateUnitValue(new UnitValue(1, 150.0f)), GridValue.CreateUnitValue - (new UnitValue(1, 150.0f)))); + gridcontainer0.SetProperty(Property.GRID_TEMPLATE_COLUMNS, JavaUtil.ArraysAsList(GridValue.CreatePointValue + (150.0f), GridValue.CreatePointValue(150.0f), GridValue.CreatePointValue(150.0f))); gridcontainer0.SetProperty(Property.COLUMN_GAP, 12.0f); document.Add(gridcontainer0); document.Close(); @@ -166,9 +165,8 @@ public virtual void OverflowGridContainerTest() { Document document = new Document(pdfDocument); GridContainer gridcontainer0 = CreateGridBoxWithText(); gridcontainer0.SetBackgroundColor(ColorConstants.MAGENTA); - gridcontainer0.SetProperty(Property.GRID_TEMPLATE_ROWS, JavaUtil.ArraysAsList(GridValue.CreateUnitValue(new - UnitValue(1, 500.0f)), GridValue.CreateUnitValue(new UnitValue(1, 500.0f)), GridValue.CreateUnitValue( - new UnitValue(1, 500.0f)))); + gridcontainer0.SetProperty(Property.GRID_TEMPLATE_ROWS, JavaUtil.ArraysAsList(GridValue.CreatePointValue(500.0f + ), GridValue.CreatePointValue(500.0f), GridValue.CreatePointValue(500.0f))); gridcontainer0.Add(new iText.Layout.Element.Image(ImageDataFactory.Create(SOURCE_FOLDER + "rock_texture.jpg" )).SetHeight(150)); document.Add(gridcontainer0); @@ -195,9 +193,8 @@ public virtual void NothingResultTest() { private GridContainer CreateGridBoxWithText() { GridContainer gridcontainer0 = new GridContainer(); gridcontainer0.SetProperty(Property.COLUMN_GAP_BORDER, null); - gridcontainer0.SetProperty(Property.GRID_TEMPLATE_COLUMNS, JavaUtil.ArraysAsList(GridValue.CreateUnitValue - (new UnitValue(1, 150.0f)), GridValue.CreateUnitValue(new UnitValue(1, 150.0f)), GridValue.CreateUnitValue - (new UnitValue(1, 150.0f)))); + gridcontainer0.SetProperty(Property.GRID_TEMPLATE_COLUMNS, JavaUtil.ArraysAsList(GridValue.CreatePointValue + (150.0f), GridValue.CreatePointValue(150.0f), GridValue.CreatePointValue(150.0f))); gridcontainer0.SetProperty(Property.COLUMN_GAP, 12.0f); Div div1 = new Div(); div1.SetBackgroundColor(ColorConstants.YELLOW); diff --git a/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs b/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs index dadd65f328..02ea55f377 100644 --- a/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs @@ -26,33 +26,37 @@ namespace iText.Layout.Properties { [NUnit.Framework.Category("UnitTest")] public class GridValueTest : ExtendedITextTest { [NUnit.Framework.Test] - public virtual void SizingValueTest() { - GridValue value = GridValue.CreateSizeValue(SizingValue.CreateUnitValue(UnitValue.CreatePointValue(1.3f))); - NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); - NUnit.Framework.Assert.AreEqual(1.3f, (float)value.GetAbsoluteValue(), 0.00001); - value = GridValue.CreateSizeValue(SizingValue.CreateUnitValue(UnitValue.CreatePercentValue(30))); - NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - NUnit.Framework.Assert.AreEqual(30, value.GetSizingValue().GetUnitValue().GetValue(), 0.00001); + public virtual void UnitValueTest() { + GridValue value = GridValue.CreatePointValue(3.2f); + NUnit.Framework.Assert.IsTrue(value.IsPointValue()); + NUnit.Framework.Assert.AreEqual(3.2f, value.GetValue(), 0.00001); + value = GridValue.CreatePercentValue(30f); + NUnit.Framework.Assert.IsTrue(value.IsPercentValue()); + NUnit.Framework.Assert.AreEqual(30, value.GetValue(), 0.00001); } [NUnit.Framework.Test] - public virtual void UnitValueTest() { - GridValue value = GridValue.CreateUnitValue(UnitValue.CreatePointValue(1.3f)); - NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); - NUnit.Framework.Assert.AreEqual(1.3f, (float)value.GetAbsoluteValue(), 0.00001); - value = GridValue.CreateUnitValue(UnitValue.CreatePercentValue(30)); - NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - NUnit.Framework.Assert.AreEqual(30, value.GetSizingValue().GetUnitValue().GetValue(), 0.00001); + public virtual void MinMaxContentTest() { + GridValue value = GridValue.CreateMinContentValue(); + NUnit.Framework.Assert.IsTrue(value.IsMinContentValue()); + NUnit.Framework.Assert.IsNull(value.GetValue()); + value = GridValue.CreateMaxContentValue(); + NUnit.Framework.Assert.IsTrue(value.IsMaxContentValue()); + NUnit.Framework.Assert.IsNull(value.GetValue()); + } + + [NUnit.Framework.Test] + public virtual void AutoTest() { + GridValue value = GridValue.CreateAutoValue(); + NUnit.Framework.Assert.IsTrue(value.IsAutoValue()); + NUnit.Framework.Assert.IsNull(value.GetValue()); } [NUnit.Framework.Test] public virtual void FlexValueTest() { GridValue value = GridValue.CreateFlexValue(1.5f); - NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.FLEX, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - NUnit.Framework.Assert.AreEqual(1.5f, (float)value.GetFlexValue(), 0.00001); + NUnit.Framework.Assert.IsTrue(value.IsFlexibleValue()); + NUnit.Framework.Assert.AreEqual(1.5f, (float)value.GetValue(), 0.00001); } } } diff --git a/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs b/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs deleted file mode 100644 index d1bbf1a13e..0000000000 --- a/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* -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.Test; - -namespace iText.Layout.Properties { - [NUnit.Framework.Category("UnitTest")] - public class SizingValueTest : ExtendedITextTest { - [NUnit.Framework.Test] - public virtual void UnitValueTest() { - SizingValue value = SizingValue.CreateUnitValue(UnitValue.CreatePointValue(3.2f)); - NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.UNIT, value.GetType()); - NUnit.Framework.Assert.AreEqual(3.2f, value.GetUnitValue().GetValue(), 0.00001); - NUnit.Framework.Assert.AreEqual(3.2f, (float)value.GetAbsoluteValue(), 0.00001); - value = SizingValue.CreateUnitValue(UnitValue.CreatePercentValue(30)); - NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.UNIT, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - NUnit.Framework.Assert.AreEqual(30, value.GetUnitValue().GetValue(), 0.00001); - } - - [NUnit.Framework.Test] - public virtual void MinMaxContentTest() { - SizingValue value = SizingValue.CreateMinContentValue(); - NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.MIN_CONTENT, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - value = SizingValue.CreateMaxContentValue(); - NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.MAX_CONTENT, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - } - - [NUnit.Framework.Test] - public virtual void AutoTest() { - SizingValue value = SizingValue.CreateAutoValue(); - NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.AUTO, value.GetType()); - NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); - } - } -} 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 ac0ff8ff4c..2c328c4e23 100644 --- a/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/renderer/GridUnitTest.cs @@ -20,7 +20,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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 System; using iText.Layout.Element; using iText.Layout.Properties; using iText.Test; @@ -29,32 +29,45 @@ namespace iText.Layout.Renderer { [NUnit.Framework.Category("UnitTest")] public class GridUnitTest : ExtendedITextTest { [NUnit.Framework.Test] - public virtual void GetClosestTopNeighborTest() { + public virtual void GetUniqueCellsTest() { Grid grid = new Grid(3, 3, GridFlow.ROW); 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); + 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); - NUnit.Framework.Assert.AreEqual(grid.GetRows()[0][0], grid.GetClosestTopNeighbor(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.GridOrder.ROW).Count); } [NUnit.Framework.Test] - public virtual void GetClosestLeftNeighborTest() { + public virtual void GetUniqueCellsInColumnTest() { Grid grid = new Grid(3, 3, GridFlow.ROW); 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); + IRenderer twoRenderer = new TextRenderer(new Text("Two")); + twoRenderer.SetProperty(Property.GRID_ROW_START, 2); + twoRenderer.SetProperty(Property.GRID_ROW_END, 4); + GridCell cell = new GridCell(twoRenderer); grid.AddCell(cell); - NUnit.Framework.Assert.AreEqual(grid.GetRows()[0][0], grid.GetClosestLeftNeighbor(cell)); + grid.AddCell(new GridCell(new TextRenderer(new Text("Three")))); + grid.AddCell(new GridCell(new TextRenderer(new Text("Four")))); + NUnit.Framework.Assert.AreEqual(1, grid.GetUniqueCellsInTrack(Grid.GridOrder.COLUMN, 1).Count); } [NUnit.Framework.Test] - public virtual void GetUniqueCellsTest() { + public virtual void InvalidColumnForGetColCellsTest() { + Grid grid = new Grid(3, 3, GridFlow.ROW); + NUnit.Framework.Assert.Catch(typeof(IndexOutOfRangeException), () => grid.GetUniqueCellsInTrack(Grid.GridOrder + .COLUMN, 4)); + NUnit.Framework.Assert.Catch(typeof(IndexOutOfRangeException), () => grid.GetUniqueCellsInTrack(Grid.GridOrder + .COLUMN, -1)); + NUnit.Framework.Assert.DoesNotThrow(() => grid.GetUniqueCellsInTrack(Grid.GridOrder.COLUMN, 2)); + } + + [NUnit.Framework.Test] + public virtual void GetUniqueCellsInRowTest() { Grid grid = new Grid(3, 3, GridFlow.ROW); grid.AddCell(new GridCell(new TextRenderer(new Text("One")))); IRenderer twoRenderer = new TextRenderer(new Text("Two")); @@ -64,50 +77,17 @@ public virtual void GetUniqueCellsTest() { 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.GridOrder.ROW).Count); + NUnit.Framework.Assert.AreEqual(2, grid.GetUniqueCellsInTrack(Grid.GridOrder.ROW, 0).Count); } [NUnit.Framework.Test] - public virtual void IncreaseRowHeightTest() { + public virtual void InvalidRowForGetRowCellsTest() { Grid grid = new Grid(3, 3, GridFlow.ROW); - 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, GridFlow.ROW); - 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.Assert.Catch(typeof(IndexOutOfRangeException), () => grid.GetUniqueCellsInTrack(Grid.GridOrder + .ROW, 4)); + NUnit.Framework.Assert.Catch(typeof(IndexOutOfRangeException), () => grid.GetUniqueCellsInTrack(Grid.GridOrder + .ROW, -1)); + NUnit.Framework.Assert.DoesNotThrow(() => grid.GetUniqueCellsInTrack(Grid.GridOrder.ROW, 2)); } [NUnit.Framework.Test] 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 index bb5ebfa7252efb9687ed2ca7d9beee051d5d5b52..ab70be9a92ae98aecac0120fefb1b7ec8eef6e7d 100644 GIT binary patch delta 935 zcmbQmx1MK$Nxi9oxt(2cNl|KIE?32z*2$;)ZX58pe*ed%xBS3?t&dgww!1E0oyWCA zeu0-yTWj3KWP|zfr~2M3^PTAHU$>yz(qF0s4phObQ2pA?}3 zCcz34h1-}~mU)Zm{_$v-#*n0+%>}~tl_7Ot5KpR=5Fa*+QZy7th4 z!cYA9e(C2^PCS`&KY3Q-ZNBzSwq%zHOG;%0k573x<-Cf}jZd>4xISo?iK?ia{-R#^ znUT9()8wE9PyU~LY_4Xx zm)1OAwt7$4)j#)bW3Fue-xZT9_W1vs#Qkr$6CZ7u)>Fs)TFvItWHsjPn#Kl(hNebF z7TN~J>IMetn)<%^DK3d6sTwX;Mg~SE2Bt6to7q_G7#$2OEKL*)KtLf+feXwqFf=eS zM;9|NH!{KyGqtds+`_8DVqj@(Ie87MRK2;8sdNl7!bOf@tzOindVOEOL}Of<1HNincU zOEEVzPO(f&NwzdfGdD>wN=mk{FfcVTO)@YvNlP&_F*HauHcSEZYv11y|3fyTf1cz)3Jv2q1%_oX)Wb< z$ek1gM;es9)n>((!v@b&D0Gv|No7n4YIxlp3%)u^I&LX5>*-?-0C+`jv@SaSQl#~howl{xC9zbM}Q{qdPVncu9Wy}iZt(Qhv8?cBVm?Dmg; zKArp9{oh;<{`l0|v1QTa%1ZU*A3}3)J-XbVcu8#LMb_Uxzij`}^6dWe%fDwF2ngf8 z#&_31F}+4^mBx|dJesTj2FqzkPAOuXwXl5G$6M{1{epZtOEb@A#3cXn7JIan#ZBC+ z{FuGs^5`pkm3~PHnzPLg-dtFJR(TH7W9~;=W!wLBS|lF`dg^n3#BOFInlHFN_*q>y)C4OQ)^K;t36!7&<-fDWl^;uU~<4ce1g*2(L>HJ-WcF_43}0 z9#6Alr^>8SQOs7F%-+#5<&o;MfNz|!&4rab$qzj3{yz94@+mrb5>x!t&#RUntEhi^ z_QG?^a}CRHwXO@^cCvelAzw_6kpbV=V>6Yxl1#2GzGs!{wj_Syx$QFqd79QtzkaNG z;{CM9V1cJ)_ZREgJkdPpu*9mad##h!k3C7JyP7>}&4N3=EA<*q)~}EB67US1ET{h0 z{rlQ^d_DUoB~5rO>!$B4e(c5vX6vIODzT!H_3FZx&OO!Cl030>%Cgr@uI%fLp30;I zP3LWXDElze`=1v@SD>#C~D{qo{#V?X0c$tx>s z&K+53Y0`V?Y@@N@!G(UCvJPcLJ?(dx+A?c>@&fnACNsjmv)h%nB(9ijb;suRVwYJL zdVhKe&DteXpRXo$F8%ThW}bBn>zU)MZI8A@x^W$N-6Fp$vMp=gfoBJSX1X zp7{xh>^3)MvUhLYp7kg%J1@+)CS~on!XNimeFTfiAAM{-`)GdHTSdP6(Wd|8SC{oG z=7qhjQ>)vY^@n-&G4s{Wk~QCp{$bz$qf?11H7^B}>L)uht=BX%HZ(RgFfrCPFjhA( zP}kJ=%};SjEJ@XHu`)6+GBGfPDcCH{Y{%$eXlP`qU;qLNc?w)$hJm4xnGw2}fu*TA zhM0ws$>fX}zVXon3KBQEFl?SH+y#DX0C881T4$|JkLJC_L%dO6zEq8_HjW6DA16 ze)v&;QPKC0$EB-RvYyBMzIP=4Sag2#-#T-_w~w0d`fyxy{H1UAovFz1t?QiA%yR43 zKRa3@*!*{EQ9H9R330F5UwyK_~cVoWT!E=Vy_(`ED z|M`P$C)Zv7Q&nhq>+97!YxC{*|Ev3J;J;cDt7rytIRHiSL#YV7r2!l`8;F%&b%ae(Tw(O zjQq?~*caFc2^9#jtuW~0Ypd7X?zBA79cs7ufpr5Yq>lhB&UZ5Io`Lr60s^(dhXOC6D6#jjcumO z>MXmt`|t7_^8RAMUsuH>hAi*db1`nI@p_fM4_DVS`#XDD-aW?jlQRgLbQ#UMWSJ< zd74qOS+YfniCK!Vfq9aVQF2n6fw_UPfuV`HMN&$dxsh>lqJf!VN|K>vib1k@N@|j+ zg|V4QnqiV*ibZOQg+Y>$u~DjVa^a}0Kls#5dZ)H delta 767 zcmdnTy_9=`X}!6Don3KBQEFl?SH+y#$p`&d6nWa-+pxOt?ODomy2AA0ZqEJ%*-1|} zy!w4Sv0C0DFg_^I^ zRdru`{|!^N-goIq=UAHlt4}#JW0ycmzOLdL*TsBCpH5^?<7U#Rmrgwq9Kf&dCVl1M ztohrIM#sOd`x=a*%%OHKD)2~x{5 zIUE*VW#o^VyT{So*L}|{&sWyBLfYrCpJ});qhM~}Ezx;wbLQP{2;0GRY#vGSSS?AT=$~)Xcyl(agZmJlQlYEy>a()ilL0Da|a= z(9|S3InB&4#mLe;#n>##DAm9sDLFMI(J;lt$S}py(jv*+#K6oVE!8kJF~!i_#Msz0 z$uhFq$uuKsRZ E0Hnwjxc~qF 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 index 729637d666153adf09fe42e6db7a3b0004eaf29b..3db103dfd541a230226dd5e43e3394f235e12c47 100644 GIT binary patch delta 297 zcmc)E!3hFE3Bz%#;%&6OxTtFdwM vNx5Zkr3ec^;jKfpHkam}kh!~>cB#lVmts0k5ES62E-l&8`$h_z@Hsl4RSTyU$6o@^FG$#Z{{=1IhtF=d3g$^WC6@s3(Au)F6_4lS#F2x7b6``_5c6? diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_columnFlowWithBigCellsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_columnFlowWithBigCellsTest.pdf index ac2c3821561f0833dda5b5fb870c75ea67f083e1..627c2192a9ca790f44ecf9cbbbb55040ba47e575 100644 GIT binary patch delta 616 zcmZqX`o}rJtlrqpuDGNqH8Gc~VovX*-F$}>L>#{V7VX&;BB%Qz>r$Uou$^O6VMg$x ztLLX*3bAr<=3qW~^5jl)o(92<$G04?5W2CiWA6;5#S0pxc?zZ#tk7|um?KkSliH(L z*?xCxaP`lYAgd4gO07#R+*sWzeV$0|Ap@o65kxqn3-Cpq*@xK7^N7eBpIezq#7F~rkN$C7$%vgq?j1hCz)6pB_^4h vB_$b~rWz#~B?D>0Buh)9G~<+1JDNK|0q6$2PMExj#goH?OI6j?-;E0Zy9>;u delta 600 zcmeyz*~~S;tlq-TuDGNqH8Gc~VovX*jeJc80uJAQclGVMlI`8SM$I6L=PwKQBZfwe zUq9s%beL6_yu9$_>C@QTViP!{VmVK3ka($*u{dRJGt;^YhfW?+RCY6p?zv$2(95v8 z`R>xP>fa4l`X1a@F$rXw=_c0dqWswR+g%pl9S2qRt}N~j4DyK%G$+HKLtO#njW~Ua05@K)}t?7hge#Lt!A5+?_DjvmUFA> z<+n#;UQRtF|8i+&=)L*bL3eb%UY@`D=JDT5Ij^TTPv&Oa$!1_-WN2tQ`4poxl)3pe zqa&lOse%CrDC8+{ff)t{=0+A6VkSn$7-B}229q~gGBimtPck)6wMEYp&V%~Q-$ mlPt}ES}hIC)9NklYzEQ^EI>C{PF~C6$zjQ*s_N?R#svV|IMLz& diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_fewBigCellsWithGapTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_fewBigCellsWithGapTest.pdf index e29fb94c54ba229940c29a4b29402664bec19f5e..1a3e593ae5b1ab5d92be7f23bd82efa0f7d66d01 100644 GIT binary patch delta 517 zcmeyx`HORcOT8oaAq5fk55Iql$h}UoTK+n=`E7(tUCW)Q_Fm7mc6H|x%w{M)a{Tf6 z@qanK103bY%@jm5XH*xKN4l+Plsac{!13_9qM1D}Znb~&XjS;dH9I(c+b_PQ-wsAT zy0lb8dD281wx2!|zO3%|(s4Z1lyWvp^Lk8@U!+~)o&_r&DSORv*}1Cz7RT}IMetn)<%^DK3d6sTwX;Mg~SE2Bt<31)HBS z9%QUfGe}7>G%-%GFiJ5tPO>yhGBhxb~D85$Z|m?m2oC#IO1Sy&{eCYoECrlh7CTPCI%npj$zq$HcBm?s(} r8X6f|0If1lwn#HINHIw>G`37OPEE6{H@34GNGGrW-C#U(7^3xb=buM)Dls(besD+8(GF zz6|E-bWutQIB{lD?bbj};UziKs{Or(vo zroBqsI>S>pP3)-NSLP7O9qrhRLR;Nfw4_25AO{ z28I@iDFznF7N$u_sU~Sa(~=X@j1vwhEt5@*5=~Q6>(lIP2GR*EKsTgKUda*&008Z{5&!@I diff --git a/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_frColumnsTest.pdf b/itext.tests/itext.layout.tests/resources/itext/layout/GridContainerTest/cmp_frColumnsTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0bc2ff32284a47109c4c140ed4cdde8833ef703b GIT binary patch literal 1496 zcmc&!Yitx%6fQ_2-K_X%l$VsNw)SN^ciuC$-LT#5(s$SG(iPh#&g|S>2DUTp%xql< zJ^(2gn?7g@q2bXgt;GOhj4?pdpe4~n6RM#8s6}J(@x#U^ZL0W~SqqCb@vrB{%)MvM zIrlr~`|hNB-JV=LkF}+LId$=pjRp{?;$~Yx0p^h-2GTH3L@%R3PbEGI>?Lw*&L6%K5bXk2Srz_H@cC*M9#d zl=?~ak0T#3zLaeRb+}V};9&$0RCUX#TePPOkW{D}S#0`QZ)c^WV&V(bs?V{@1qE>KBLFj_tkVJm25A zX>+8n{SD#kw!)*ab@#!k<(`RwS{qWNdA`h*#V?iM*`+E5QVbnf-21RfB*{XN8moim zmgZ@|QA7jg6*Myj5b+Qn($%OIM7pICGuwLMfU&+gOvC(|-1x5w{;f^OEE7f!hXuz1 zL7Ex!Vsn{dGGtY8n_|m!KT1G?f;0(nk|Jm#2a*{OW@KTNs`TFhUQLyvL8N8MeiSoK z0hg*Fz~#X_I=80E>8&ZL_JjIN=X!4iXhE889$23RjuQ~VTMEVj2qBAYg4~kMjl? znkH!w0ylgdHJvPRy90BiD@9+z~krRdy$D%z$Sf@Z{t=6S-Fo?cw-vHbPc(N)|^rE053Ptgt=+T*&Hd?`}bJ(4E`@Q$R_q{h8&L&e) zu2W&cZ{Iz6&PV_PS3kjYce5$G6kv}{l~90_*l_4{q>XoNUE!%D$UydE^S_(Da`}Sf%nN6(R9=d-%64D;D zww{@ve|hj?`P|;sriJyErlph75O;lNdHL}Av$pb`w$Iw*f!L``=>6B(JqI##cfYUi zYrov{ z6%$0Iz;>M^QL!W0#Y0|%k^nhD5IA@U3hfZKN7y0P{5K%$xn{+{UWZ-4)nE}MTn_`a z6Lw0`d?udF_YW7qct^Z1I|!z+=aYov5pau#5JqWA5HEW(J_dcBTPcIgNTk7)YjCAS z_;o32RV7e>N^Y?Mrc%@k>p?!I8nOMjG>rq>Ky0r=ro?uN?5OR;9pBzO=PPJc*rhck6xd25{z}LP_{%1VGRkIp;?N= zVQ7eg33=1BOkTl)U public class GridValue { - /// The type of the value. - private GridValue.GridValueType type; + private static readonly iText.Layout.Properties.GridValue MIN_CONTENT_VALUE = new iText.Layout.Properties.GridValue + (GridValue.SizingValueType.MIN_CONTENT); - /// The flexible value. - private float? flex; + private static readonly iText.Layout.Properties.GridValue MAX_CONTENT_VALUE = new iText.Layout.Properties.GridValue + (GridValue.SizingValueType.MAX_CONTENT); - /// The sizing value. - private SizingValue sizingValue; + private static readonly iText.Layout.Properties.GridValue AUTO_VALUE = new iText.Layout.Properties.GridValue + (GridValue.SizingValueType.AUTO); + + private GridValue.SizingValueType type; + + private float? value; - /// - /// Creates a new empty instance of - /// - /// class. - /// private GridValue() { } - // do nothing + // Do nothing + private GridValue(GridValue.SizingValueType type) { + this.type = type; + } + /// /// Creates an instance of /// - /// with - /// - /// value. + /// with point value. /// - /// the sizing value + /// the point value /// the grid value instance - public static iText.Layout.Properties.GridValue CreateSizeValue(SizingValue sizingValue) { + public static iText.Layout.Properties.GridValue CreatePointValue(float value) { iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); - result.sizingValue = sizingValue; - result.type = GridValue.GridValueType.SIZING; + result.type = GridValue.SizingValueType.POINT; + result.value = value; return result; } /// /// Creates an instance of /// - /// with - /// - /// inside of - /// - /// value. + /// with percent value. /// - /// the unit value + /// the percent value /// the grid value instance - public static iText.Layout.Properties.GridValue CreateUnitValue(UnitValue unitValue) { + public static iText.Layout.Properties.GridValue CreatePercentValue(float value) { iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); - result.sizingValue = SizingValue.CreateUnitValue(unitValue); - result.type = GridValue.GridValueType.SIZING; + result.type = GridValue.SizingValueType.PERCENT; + result.value = value; return result; } /// /// Creates an instance of /// - /// with flex value. + /// with min-content value. + /// + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateMinContentValue() { + return MIN_CONTENT_VALUE; + } + + /// + /// Creates an instance of + /// + /// with max-content value. /// - /// the flex value /// the grid value instance - public static iText.Layout.Properties.GridValue CreateFlexValue(float flex) { + public static iText.Layout.Properties.GridValue CreateMaxContentValue() { + return MAX_CONTENT_VALUE; + } + + /// + /// Creates an instance of + /// + /// with auto value. + /// + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateAutoValue() { + return AUTO_VALUE; + } + + /// + /// Creates an instance of + /// + /// with flexible value. + /// + /// the flexible value + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateFlexValue(float value) { iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); - result.flex = flex; - result.type = GridValue.GridValueType.FLEX; + result.type = GridValue.SizingValueType.FLEX; + result.value = value; return result; } - /// Checks whether the value is absolute. + /// Checks whether the value is absolute. /// /// /// @@ -100,59 +127,94 @@ public static iText.Layout.Properties.GridValue CreateFlexValue(float flex) { /// /// otherwise /// - public virtual bool IsAbsoluteValue() { - return type == GridValue.GridValueType.SIZING && sizingValue.IsAbsoluteValue(); + public virtual bool IsPointValue() { + return type == GridValue.SizingValueType.POINT; } - /// Gets absolute value, if exists. + /// Checks whether the value is percent. /// - /// absolute value, or - /// - /// if value is relative + /// + /// + /// if percent, + /// + /// otherwise /// - public virtual float? GetAbsoluteValue() { - if (IsAbsoluteValue()) { - return sizingValue.GetAbsoluteValue(); - } - return null; + public virtual bool IsPercentValue() { + return type == GridValue.SizingValueType.PERCENT; } - /// Gets type of value. - /// the type of the value - public virtual GridValue.GridValueType GetType() { - return type; + /// Checks whether the value is auto. + /// + /// + /// + /// if auto, + /// + /// otherwise + /// + public virtual bool IsAutoValue() { + return type == GridValue.SizingValueType.AUTO; } - /// Gets the flex value. + /// Checks whether the value is min-content. /// - /// the flex value of - /// - /// if another value type is stored + /// + /// + /// if min-content, + /// + /// otherwise /// - public virtual float? GetFlexValue() { - return flex; + public virtual bool IsMinContentValue() { + return type == GridValue.SizingValueType.MIN_CONTENT; } - /// Gets the sizing value. + /// Checks whether the value is max-content. /// - /// the instance of - /// - /// or + /// + /// + /// if max-content, + /// + /// otherwise + /// + public virtual bool IsMaxContentValue() { + return type == GridValue.SizingValueType.MAX_CONTENT; + } + + /// Checks whether the value is flexible. + /// + /// + /// + /// if flexible, + /// + /// otherwise + /// + public virtual bool IsFlexibleValue() { + return type == GridValue.SizingValueType.FLEX; + } + + /// Gets value, if exists. + /// + /// the value, or /// - /// if another value type is stored + /// if there is no value /// - public virtual SizingValue GetSizingValue() { - return sizingValue; - } - - /// Enum of grid value types. - public enum GridValueType { - /// - /// Type which presents - /// - /// value. - /// - SIZING, + public virtual float? GetValue() { + return value; + } + + /// Enum of sizing value types. + private enum SizingValueType { + /// Type which presents absolute point value. + POINT, + /// Type which presents relative percent value. + PERCENT, + /// Type which presents relative auto value. + AUTO, + /// Type which presents relative min content value. + MIN_CONTENT, + /// Type which presents relative max content value. + MAX_CONTENT, + /// Type which presents relative fit content function value. + FIT_CONTENT, /// Type which presents relative flexible value. FLEX } diff --git a/itext/itext.layout/itext/layout/properties/SizingValue.cs b/itext/itext.layout/itext/layout/properties/SizingValue.cs deleted file mode 100644 index 9bdc0a661e..0000000000 --- a/itext/itext.layout/itext/layout/properties/SizingValue.cs +++ /dev/null @@ -1,159 +0,0 @@ -/* -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 . -*/ -namespace iText.Layout.Properties { - /// A specialized class that holds a sizing value and the type it is measured in. - /// - /// A specialized class that holds a sizing value and the type it is measured in. - /// - /// For more information see https://www.w3.org/TR/css-sizing-3/#sizing-values. - /// - public class SizingValue { - /// The type of the value. - private SizingValue.SizingValueType type; - - /// The unit value. - private UnitValue unitValue; - - /// - /// Creates a new empty instance of - /// - /// class. - /// - private SizingValue() { - } - - // do nothing - /// - /// Creates an instance of - /// - /// with - /// - /// value. - /// - /// the unit value - /// the sizing value instance - public static iText.Layout.Properties.SizingValue CreateUnitValue(UnitValue unitValue) { - iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); - result.type = SizingValue.SizingValueType.UNIT; - result.unitValue = unitValue; - return result; - } - - /// - /// Creates an instance of - /// - /// with min-content value. - /// - /// the sizing value instance - public static iText.Layout.Properties.SizingValue CreateMinContentValue() { - iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); - result.type = SizingValue.SizingValueType.MIN_CONTENT; - return result; - } - - /// - /// Creates an instance of - /// - /// with max-content value. - /// - /// the sizing value instance - public static iText.Layout.Properties.SizingValue CreateMaxContentValue() { - iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); - result.type = SizingValue.SizingValueType.MAX_CONTENT; - return result; - } - - /// - /// Creates an instance of - /// - /// with auto value. - /// - /// the sizing value instance - public static iText.Layout.Properties.SizingValue CreateAutoValue() { - iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); - result.type = SizingValue.SizingValueType.AUTO; - return result; - } - - /// Checks whether the value is absolute. - /// - /// - /// - /// if absolute, - /// - /// otherwise - /// - public virtual bool IsAbsoluteValue() { - return type == SizingValue.SizingValueType.UNIT && unitValue.IsPointValue(); - } - - /// Gets absolute value, if exists. - /// - /// absolute value, or - /// - /// if value is relative - /// - public virtual float? GetAbsoluteValue() { - if (IsAbsoluteValue()) { - return unitValue.GetValue(); - } - return null; - } - - /// Gets the type of the value. - /// the type of the value - public virtual SizingValue.SizingValueType GetType() { - return type; - } - - /// Gets unit value. - /// - /// the - /// - /// or - /// - /// if another value type is stored - /// - public virtual UnitValue GetUnitValue() { - return unitValue; - } - - /// Enum of sizing value types. - public enum SizingValueType { - /// - /// Type which presents - /// - /// value, can be both relative (percentage) and absolute (points). - /// - UNIT, - /// Type which presents relative auto value. - AUTO, - /// Type which presents relative min content value. - MIN_CONTENT, - /// Type which presents relative max content value. - MAX_CONTENT, - /// Type which presents relative fit content function value. - FIT_CONTENT - } - } -} diff --git a/itext/itext.layout/itext/layout/renderer/Grid.cs b/itext/itext.layout/itext/layout/renderer/Grid.cs index 6089a10303..be35702145 100644 --- a/itext/itext.layout/itext/layout/renderer/Grid.cs +++ b/itext/itext.layout/itext/layout/renderer/Grid.cs @@ -42,8 +42,6 @@ internal class Grid { private float minHeight = 0.0f; - private float minWidth = 0.0f; - /// Creates a new grid instance. /// initial number of row for the grid /// initial number of columns for the grid @@ -59,8 +57,8 @@ internal Grid(int initialRowsCount, int initialColumnsCount, GridFlow flow) { /// /// resulting layout height of a grid. internal virtual float GetHeight() { - for (int i = rows.Length - 1; i >= 0; --i) { - for (int j = 0; j < rows[0].Length; ++j) { + for (int i = GetNumberOfRows() - 1; i >= 0; --i) { + for (int j = 0; j < GetNumberOfColumns(); ++j) { if (rows[i][j] != null) { return Math.Max(rows[i][j].GetLayoutArea().GetTop(), minHeight); } @@ -69,81 +67,50 @@ internal virtual float GetHeight() { 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 GridCell[][] 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 wide 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. But if there will be a neighbor before column start of such a cell method will - /// return such a neighbor. - /// - /// cell for which to find a 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.Length; ++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; + /// Gets the current number of rows of grid. + /// the number of rows + internal virtual int GetNumberOfRows() { + return rows.Length; + } + + /// Gets the current number of rows of grid. + /// the number of columns + internal virtual int GetNumberOfColumns() { + return rows[0].Length; } /// - /// 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 tall 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. + /// Gets unique cells in the specified row or column depends on passed + /// . /// - /// - /// 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 tall 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. But if there will be a neighbor before row start of such a cell method will - /// return such a neighbor. - /// - /// cell for which to find a 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].Length; ++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]; + /// the order which will be used to extract cells + /// the track index from which cells will be extracted + /// collection of unique cells in a row or column + internal virtual ICollection GetUniqueCellsInTrack(Grid.GridOrder order, int trackIndex) { + ICollection result = new LinkedHashSet(); + if (Grid.GridOrder.COLUMN == order) { + foreach (GridCell[] row in rows) { + GridCell cell = row[trackIndex]; + if (cell != null) { + result.Add(cell); } } - if (bigNeighbor != null && bigNeighbor.GetRowStart() == y - i) { - return bigNeighbor; + return result; + } + else { + foreach (GridCell cell in rows[trackIndex]) { + if (cell != null) { + result.Add(cell); + } } + return result; } - return null; } /// Get all unique cells in the grid. @@ -161,8 +128,8 @@ internal virtual GridCell GetClosestTopNeighbor(GridCell value) { internal virtual ICollection GetUniqueGridCells(Grid.GridOrder iterationOrder) { ICollection result = new LinkedHashSet(); if (Grid.GridOrder.COLUMN.Equals(iterationOrder)) { - for (int j = 0; j < rows[0].Length; ++j) { - for (int i = 0; i < rows.Length; ++i) { + for (int j = 0; j < GetNumberOfColumns(); ++j) { + for (int i = 0; i < GetNumberOfRows(); ++i) { if (rows[i][j] != null) { result.Add(rows[i][j]); } @@ -180,83 +147,6 @@ internal virtual ICollection GetUniqueGridCells(Grid.GridOrder iterati 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.Length; ++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; - } - } - - /// Get max top (layout area y + height of a cell) in a row with index = y, for all elements in a row before given x. - /// - /// index of a row to find max top value - /// index of element in a row before which to search for max top value - /// max top value, all cells which do not end in the given row are not counted. - internal virtual float GetMaxRowTop(int y, int x) { - GridCell[] 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; - } - - /// - /// Get max right (layout area x + width of a cell) in a column with index = x, - /// for all elements in a column before given y. - /// - /// index of element in a column before which to search for max right value - /// index of a column to find max right value - /// max right value, all cells which do not end in the given column are not counted. - 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 bottom left corner (x, y). /// cell to and in the grid internal virtual void AddCell(GridCell cell) { @@ -272,21 +162,17 @@ internal virtual void SetMinHeight(float minHeight) { this.minHeight = minHeight; } - internal virtual void SetMinWidth(float minWidth) { - this.minWidth = minWidth; - } - /// Resize grid if needed, so it would have given number of rows/columns. /// new grid height /// new grid width internal virtual void EnsureGridSize(int height, int width) { - if (height <= rows.Length && width <= rows[0].Length) { + if (height <= GetNumberOfRows() && width <= GetNumberOfColumns()) { return; } - GridCell[][] resizedRows = height > rows.Length ? new GridCell[height][] : rows; - int gridWidth = Math.Max(width, rows[0].Length); + GridCell[][] resizedRows = height > GetNumberOfRows() ? new GridCell[height][] : rows; + int gridWidth = Math.Max(width, GetNumberOfColumns()); for (int i = 0; i < resizedRows.Length; ++i) { - if (i < rows.Length) { + if (i < GetNumberOfRows()) { if (width <= rows[i].Length) { resizedRows[i] = rows[i]; } diff --git a/itext/itext.layout/itext/layout/renderer/GridCell.cs b/itext/itext.layout/itext/layout/renderer/GridCell.cs index 9cc6ccaa55..f4d18b2562 100644 --- a/itext/itext.layout/itext/layout/renderer/GridCell.cs +++ b/itext/itext.layout/itext/layout/renderer/GridCell.cs @@ -64,6 +64,24 @@ internal virtual int GetRowEnd() { return gridArea.GetTop(); } + internal virtual int GetStart(Grid.GridOrder order) { + if (Grid.GridOrder.COLUMN == order) { + return GetColumnStart(); + } + else { + return GetRowStart(); + } + } + + internal virtual int GetEnd(Grid.GridOrder order) { + if (Grid.GridOrder.COLUMN == order) { + return GetColumnEnd(); + } + else { + return GetRowEnd(); + } + } + internal virtual int GetGridHeight() { return gridArea.GetHeight(); } @@ -72,6 +90,15 @@ internal virtual int GetGridWidth() { return gridArea.GetWidth(); } + internal virtual int GetGridSpan(Grid.GridOrder order) { + if (Grid.GridOrder.COLUMN == order) { + return GetGridWidth(); + } + else { + return GetGridHeight(); + } + } + internal virtual IRenderer GetValue() { return value; } diff --git a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs index a06ca2cf9b..e4a3d5eab1 100644 --- a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs @@ -123,7 +123,6 @@ private AbstractRenderer CreateOverflowRenderer(IList children) { private GridContainerRenderer.GridLayoutResult LayoutGrid(LayoutContext layoutContext, Rectangle actualBBox , Grid grid) { GridContainerRenderer.GridLayoutResult layoutResult = new GridContainerRenderer.GridLayoutResult(); - EnsureTemplateValuesFit(grid, actualBBox); foreach (GridCell cell in grid.GetUniqueGridCells(Grid.GridOrder.ROW)) { // Calculate cell layout context by getting actual x and y on parent layout area for it LayoutContext cellContext = GetCellLayoutContext(layoutContext, actualBBox, cell); @@ -167,12 +166,6 @@ private GridContainerRenderer.GridLayoutResult LayoutGrid(LayoutContext layoutCo 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) { @@ -251,60 +244,31 @@ private float SafelyRetrieveFloatProperty(int property) { } //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 ) { IList templateColumns = renderer.GetProperty>(Property.GRID_TEMPLATE_COLUMNS); IList templateRows = renderer.GetProperty>(Property.GRID_TEMPLATE_ROWS); - GridValue columnAutoWidth = renderer.GetProperty(Property.GRID_AUTO_COLUMNS); - GridValue rowAutoHeight = renderer.GetProperty(Property.GRID_AUTO_ROWS); - float? columnGap = renderer.GetProperty(Property.COLUMN_GAP); - float? rowGap = renderer.GetProperty(Property.ROW_GAP); GridFlow flow = renderer.GetProperty(Property.GRID_FLOW) == null ? GridFlow.ROW : (GridFlow)(renderer .GetProperty(Property.GRID_FLOW)); foreach (IRenderer child in renderer.GetChildRenderers()) { child.SetParent(renderer); } + // 8. Placing Grid Items Grid grid = Grid.Builder.ForItems(renderer.GetChildRenderers()).Columns(templateColumns == null ? 1 : templateColumns .Count).Rows(templateRows == null ? 1 : templateRows.Count).Flow(flow).Build(); - GridSizer gridSizer = new GridSizer(grid, templateRows, templateColumns, rowAutoHeight, columnAutoWidth, columnGap - , rowGap); - 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); + GridValue columnAutoWidth = renderer.GetProperty(Property.GRID_AUTO_COLUMNS); + GridValue rowAutoHeight = renderer.GetProperty(Property.GRID_AUTO_ROWS); + float? columnGapProp = renderer.GetProperty(Property.COLUMN_GAP); + float? rowGapProp = renderer.GetProperty(Property.ROW_GAP); + float columnGap = columnGapProp == null ? 0f : (float)columnGapProp; + float rowGap = rowGapProp == null ? 0f : (float)rowGapProp; + // 12. Grid Layout Algorithm + GridSizer gridSizer = new GridSizer(grid, templateColumns, templateRows, columnAutoWidth, rowAutoHeight, columnGap + , rowGap, actualBBox); + gridSizer.SizeGrid(); return grid; } - //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 (GridValue template in templateRows) { - if (template.IsAbsoluteValue()) { - explicitContainerHeight += (float)template.GetAbsoluteValue(); - } - } - } - grid.SetMinHeight(explicitContainerHeight); - } - - private static void SetGridContainerMinimalWidth(Grid grid, IList templateColumns) { - float explicitContainerWidth = 0.0f; - if (templateColumns != null) { - foreach (GridValue template in templateColumns) { - if (template.IsAbsoluteValue()) { - explicitContainerWidth += (float)template.GetAbsoluteValue(); - } - } - } - grid.SetMinWidth(explicitContainerWidth); - } - private sealed class GridLayoutResult { private readonly IList splitRenderers = new List(); diff --git a/itext/itext.layout/itext/layout/renderer/GridSizer.cs b/itext/itext.layout/itext/layout/renderer/GridSizer.cs index ed1ca80d72..052f9922a1 100644 --- a/itext/itext.layout/itext/layout/renderer/GridSizer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridSizer.cs @@ -20,315 +20,119 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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; -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. - /// + // 12.1. Grid Sizing Algorithm 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 GridValue rowAutoHeight; + private readonly IList templateRows; private readonly GridValue columnAutoWidth; - //TODO DEVSIX-8326 here should be a list/map of different resolvers - private readonly GridSizer.SizeResolver sizeResolver; + private readonly GridValue rowAutoHeight; private readonly float columnGap; private readonly float rowGap; - internal GridSizer(Grid grid, IList templateRows, IList templateColumns, GridValue rowAutoHeight - , GridValue columnAutoWidth, float? columnGap, float? rowGap) { + private readonly Rectangle actualBBox; + + internal GridSizer(Grid grid, IList templateColumns, IList templateRows, GridValue columnAutoWidth + , GridValue rowAutoHeight, float columnGap, float rowGap, Rectangle actualBBox) { this.grid = grid; - this.templateRows = templateRows; this.templateColumns = templateColumns; - this.rowAutoHeight = rowAutoHeight; + this.templateRows = templateRows; this.columnAutoWidth = columnAutoWidth; - this.sizeResolver = new GridSizer.MinContentResolver(grid); - this.columnGap = columnGap == null ? 0.0f : (float)columnGap; - this.rowGap = rowGap == null ? 0.0f : (float)rowGap; - } - - //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.GridOrder.COLUMN)) { - cell.GetLayoutArea().SetX(CalculateCellX(cell)); - cell.GetLayoutArea().SetWidth(CalculateCellWidth(cell)); - } - foreach (GridCell cell in grid.GetUniqueGridCells(Grid.GridOrder.ROW)) { - cell.GetLayoutArea().SetY(CalculateCellY(cell)); - cell.GetLayoutArea().SetHeight(CalculateCellHeight(cell)); - } + this.rowAutoHeight = rowAutoHeight; + this.columnGap = columnGap; + this.rowGap = rowGap; + this.actualBBox = actualBBox; } - /// Calculate cell left upper corner y position. - /// cell to calculate starting position - /// left upper corner y value - private float CalculateCellY(GridCell cell) { - float y = 0.0f; - int currentRow = 0; - if (templateRows != null) { - for (; currentRow < Math.Min(templateRows.Count, cell.GetRowStart()); ++currentRow) { - y += (float)templateRows[currentRow].GetAbsoluteValue(); - y += rowGap; - } - if (currentRow == cell.GetRowStart()) { - return y; - } - } - if (rowAutoHeight != null) { - for (; currentRow < cell.GetRowStart(); ++currentRow) { - y += (float)rowAutoHeight.GetAbsoluteValue(); - y += rowGap; - } - return y; - } - GridCell topNeighbor = grid.GetClosestTopNeighbor(cell); - if (topNeighbor != null) { - return topNeighbor.GetLayoutArea().GetTop() + rowGap; - } - return 0.0f; + public virtual void SizeGrid() { + // 1. First, the track sizing algorithm is used to resolve the sizes of the grid columns. + ResolveGridColumns(); + // 2. Next, the track sizing algorithm resolves the sizes of the grid rows. + ResolveGridRows(); } - /// 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].GetAbsoluteValue(); - x += columnGap; - } - if (currentColumn == cell.GetColumnStart()) { - return x; - } - } - if (columnAutoWidth != null) { - for (; currentColumn < cell.GetColumnStart(); ++currentColumn) { - x += (float)columnAutoWidth.GetAbsoluteValue(); - x += columnGap; - } - 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(); + private void ResolveGridRows() { + IList rowsValues = new List(); + for (int i = 0; i < grid.GetNumberOfRows(); i++) { + if (templateRows != null && i < templateRows.Count) { + rowsValues.Add(templateRows[i]); } else { - x = leftNeighbor.GetLayoutArea().GetRight(); - } - x += columnGap; - } - 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].GetAbsoluteValue(); + if (rowAutoHeight != null) { + rowsValues.Add(rowAutoHeight); } else { - if (rowAutoHeight != null) { - ++counter; - cellHeight += (float)rowAutoHeight.GetAbsoluteValue(); - } + rowsValues.Add(GridValue.CreateAutoValue()); } } - if (counter > 1) { - cellHeight += rowGap * (counter - 1); - } - 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.GetAbsoluteValue(); - } - cellHeight = sizeResolver.ResolveHeight(cell, cellHeight); - } - else { - cellHeight = (float)templateRows[cell.GetRowStart()].GetAbsoluteValue(); - } - 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 += (float)templateColumns[i].GetAbsoluteValue(); - } - else { - if (columnAutoWidth != null) { - ++counter; - cellWidth += (float)columnAutoWidth.GetAbsoluteValue(); - } - } - } - if (counter > 1) { - cellWidth += columnGap * (counter - 1); - } - 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.GetAbsoluteValue(); + // TODO DEVSIX-8384 during grid sizing algorithm take into account grid container constraints + GridTrackSizer gridTrackSizer = new GridTrackSizer(grid, rowsValues, rowGap, -1, Grid.GridOrder.ROW); + IList rows = gridTrackSizer.SizeTracks(); + foreach (GridCell cell in grid.GetUniqueGridCells(Grid.GridOrder.ROW)) { + float y = 0.0f; + for (int currentRow = 0; currentRow < cell.GetRowStart(); ++currentRow) { + y += (float)rows[currentRow]; + y += rowGap; } - cellWidth = sizeResolver.ResolveWidth(cell, cellWidth); - } - else { - //process absolute template values - cellWidth = (float)templateColumns[cell.GetColumnStart()].GetAbsoluteValue(); - } - return cellWidth; - } - - /// - /// The - /// SizeResolver - /// is used to calculate cell width and height on layout area. - /// - protected internal abstract class SizeResolver { - protected internal Grid grid; - - /// - /// Create a new - /// SizeResolver - /// instance for the given - /// Grid - /// instance. - /// - /// grid which cells sizes will be resolved - 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; + cell.GetLayoutArea().SetY(y); + float cellHeight = 0.0f; + for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { + cellHeight += (float)rows[i]; } - return inifiniteHeighLayoutResult.GetOccupiedArea().GetBBox().GetHeight(); + cellHeight += (cell.GetGridHeight() - 1) * rowGap; + cell.GetLayoutArea().SetHeight(cellHeight); } - - /// 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; + // calculating explicit height to ensure that even empty rows which covered by template would be considered + float minHeight = 0.0f; + foreach (float? row in rows) { + minHeight += (float)row; } + grid.SetMinHeight(minHeight); } - /// - /// The - /// MinContentResolver - /// is used to calculate cell width and height on layout area by calculating their - /// min required size. - /// - 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(); + private void ResolveGridColumns() { + IList colsValues = new List(); + for (int i = 0; i < grid.GetNumberOfColumns(); i++) { + if (templateColumns != null && i < templateColumns.Count) { + colsValues.Add(templateColumns[i]); } else { - grid.AlignRow(cell.GetRowEnd() - 1, cellHeight + cell.GetLayoutArea().GetY()); + if (columnAutoWidth != null) { + colsValues.Add(columnAutoWidth); + } + else { + colsValues.Add(GridValue.CreateFlexValue(1f)); + } } - 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(); + GridTrackSizer gridTrackSizer = new GridTrackSizer(grid, colsValues, columnGap, actualBBox.GetWidth(), Grid.GridOrder + .COLUMN); + IList columns = gridTrackSizer.SizeTracks(); + foreach (GridCell cell in grid.GetUniqueGridCells(Grid.GridOrder.COLUMN)) { + float x = 0.0f; + for (int currentColumn = 0; currentColumn < cell.GetColumnStart(); ++currentColumn) { + x += (float)columns[currentColumn]; + x += columnGap; } - else { - grid.AlignColumn(cell.GetColumnEnd() - 1, cellWidth + cell.GetLayoutArea().GetX()); + cell.GetLayoutArea().SetX(x); + float cellWidth = 0.0f; + for (int i = cell.GetColumnStart(); i < cell.GetColumnEnd(); ++i) { + cellWidth += (float)columns[i]; } - return cellWidth; + cellWidth += (cell.GetGridWidth() - 1) * columnGap; + cell.GetLayoutArea().SetWidth(cellWidth); } } } diff --git a/itext/itext.layout/itext/layout/renderer/GridTrackSizer.cs b/itext/itext.layout/itext/layout/renderer/GridTrackSizer.cs new file mode 100644 index 0000000000..498960d28b --- /dev/null +++ b/itext/itext.layout/itext/layout/renderer/GridTrackSizer.cs @@ -0,0 +1,499 @@ +/* +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; +using iText.Kernel.Geom; +using iText.Layout.Layout; +using iText.Layout.Properties; + +namespace iText.Layout.Renderer { + // 12.3. Track Sizing Algorithm + internal class GridTrackSizer { + private const float EPSILON = 0.001f; + + private readonly Grid grid; + + private readonly IList tracks; + + private readonly float availableSpace; + + private readonly Grid.GridOrder order; + + private readonly ICollection cachedUniqueGridCells; + + internal GridTrackSizer(Grid grid, IList values, float gap, float availableSpace, Grid.GridOrder + order) { + this.grid = grid; + // Cache the result of the getUniqueGridCells to speed up calculations + this.cachedUniqueGridCells = grid.GetUniqueGridCells(order); + tracks = new List(values.Count); + foreach (GridValue value in values) { + GridTrackSizer.Track track = new GridTrackSizer.Track(); + track.value = value; + tracks.Add(track); + } + if (availableSpace < 0) { + foreach (GridTrackSizer.Track track in tracks) { + if (track.value.IsPercentValue()) { + // 7.2.1. Track Sizes: If the size of the grid container depends on the + // size of its tracks, then the must be treated as auto + track.value = GridValue.CreateAutoValue(); + } + } + } + // Grid sizing algorithm says "Gutters are treated as empty fixed-size tracks for the purpose of the algorithm." + // But relative gaps haven't supported yet, it is why to make algorithm simpler, available space just reduced by gaps. + this.availableSpace = availableSpace - ((values.Count - 1) * gap); + this.order = order; + } + + internal virtual IList SizeTracks() { + // First step (12.4. Initialize Track Sizes) + InitializeTrackSizes(); + // Second step (12.5. Resolve Intrinsic Track Sizes) + ResolveIntrinsicTrackSizes(); + // Third step (12.6. Maximize Tracks) + MaximizeTracks(); + // Fourth step (12.7. Expand Flexible Tracks) + ExpandFlexibleTracks(); + // Fifth step (12.8. Stretch auto Tracks) + // Skip for now + IList result = new List(tracks.Count); + foreach (GridTrackSizer.Track track in tracks) { + result.Add(track.baseSize); + } + return result; + } + + private void MaximizeTracks() { + float? freeSpace = GetFreeSpace(); + if (freeSpace != null) { + float leftSpace = (float)freeSpace; + while (leftSpace > EPSILON) { + int unfrozenTracks = 0; + foreach (GridTrackSizer.Track track in tracks) { + if (JavaUtil.FloatCompare(track.baseSize, track.growthLimit) < 0) { + unfrozenTracks++; + } + } + if (unfrozenTracks == 0) { + break; + } + float diff = leftSpace / unfrozenTracks; + foreach (GridTrackSizer.Track track in tracks) { + if (JavaUtil.FloatCompare(track.baseSize, track.growthLimit) < 0) { + float trackDiff = Math.Min(track.growthLimit, track.baseSize + diff) - track.baseSize; + track.baseSize += trackDiff; + leftSpace -= trackDiff; + } + } + } + } + else { + foreach (GridTrackSizer.Track track in tracks) { + if (JavaUtil.FloatCompare(track.baseSize, track.growthLimit) < 0) { + track.baseSize = track.growthLimit; + } + } + } + } + + private void ExpandFlexibleTracks() { + bool thereIsFlexibleTrack = false; + foreach (GridTrackSizer.Track track in tracks) { + if (track.value.IsFlexibleValue()) { + thereIsFlexibleTrack = true; + break; + } + } + if (!thereIsFlexibleTrack) { + return; + } + float frSize = 0; + if (availableSpace >= 0) { + // If the free space is zero or if sizing the grid container under a min-content constraint: + float freeSpace = (float)GetFreeSpace(); + if (freeSpace < EPSILON) { + return; + } + // Otherwise, if the free space is a definite length: + frSize = FindFrSize(tracks, availableSpace); + } + else { + // Otherwise, if the free space is an indefinite length: + foreach (GridTrackSizer.Track track in tracks) { + if (track.value.IsFlexibleValue()) { + frSize = Math.Max(frSize, (float)(track.baseSize / track.value.GetValue())); + } + } + foreach (GridCell cell in cachedUniqueGridCells) { + bool atLeastOneFlexTrack = false; + IList affectedTracks = GetAffectedTracks(cell); + foreach (GridTrackSizer.Track track in affectedTracks) { + if (track.value.IsFlexibleValue()) { + atLeastOneFlexTrack = true; + } + } + if (!atLeastOneFlexTrack) { + continue; + } + float maxContribution = CalculateMaxContribution(cell, order); + frSize = Math.Max(frSize, FindFrSize(affectedTracks, maxContribution)); + } + } + foreach (GridTrackSizer.Track track in tracks) { + if (track.value.IsFlexibleValue()) { + float newBaseSize = frSize * (float)track.value.GetValue(); + if (newBaseSize > track.baseSize) { + track.baseSize = newBaseSize; + } + } + } + } + + private IList GetAffectedTracks(GridCell cell) { + IList affectedTracks = new List(); + for (int i = cell.GetStart(order); i < cell.GetEnd(order); i++) { + affectedTracks.Add(tracks[i]); + } + return affectedTracks; + } + + private float? GetFreeSpace() { + if (availableSpace < 0) { + return null; + } + float freeSpace = availableSpace; + foreach (GridTrackSizer.Track track in tracks) { + freeSpace -= track.baseSize; + } + return freeSpace; + } + + private static float FindFrSize(IList affectedTracks, float spaceToFill) { + // 12.7.1. Find the Size of an fr + float frSize = 0; + bool allFlexTracksSatisfied = false; + bool[] ignoreTracks = new bool[affectedTracks.Count]; + while (!allFlexTracksSatisfied) { + float leftoverSpace = spaceToFill; + float flexFactorSum = 0; + for (int i = 0; i < affectedTracks.Count; i++) { + GridTrackSizer.Track track = affectedTracks[i]; + if (track.value.IsFlexibleValue() && !ignoreTracks[i]) { + flexFactorSum += (float)track.value.GetValue(); + } + else { + leftoverSpace -= track.baseSize; + } + } + flexFactorSum = flexFactorSum < 1 ? 1 : flexFactorSum; + float hyphFrSize = leftoverSpace / flexFactorSum; + allFlexTracksSatisfied = true; + for (int i = 0; i < affectedTracks.Count; i++) { + GridTrackSizer.Track track = affectedTracks[i]; + if (track.value.IsFlexibleValue() && !ignoreTracks[i]) { + if (hyphFrSize * track.value.GetValue() < track.baseSize) { + ignoreTracks[i] = true; + allFlexTracksSatisfied = false; + } + } + } + if (allFlexTracksSatisfied) { + frSize = hyphFrSize; + } + } + return frSize; + } + + private void ResolveIntrinsicTrackSizes() { + // 1. Shim baseline-aligned items so their intrinsic size contributions reflect their baseline alignment. + // Not sure whether we need to do anything in first point + // 2. Size tracks to fit non-spanning items. + for (int i = 0; i < tracks.Count; i++) { + GridTrackSizer.Track track = tracks[i]; + // TODO DEVSIX-8384 percent value can be resolvable for height if height of grid container is specified + if (track.value.IsPointValue() || track.value.IsPercentValue()) { + continue; + } + ICollection cells = grid.GetUniqueCellsInTrack(order, i); + // -> For max-content minimums: + if (track.value.IsMaxContentValue()) { + float maxContribution = 0; + foreach (GridCell cell in cells) { + // non-spanning items only + if (cell.GetGridSpan(order) == 1) { + float contribution = CalculateMaxContribution(cell, order); + maxContribution = Math.Max(maxContribution, contribution); + } + } + track.baseSize = maxContribution; + } + // -> For min-content minimums: + // -> For auto minimums: (also the case if track specified by fr value) + if (track.value.IsAutoValue() || track.value.IsFlexibleValue() || track.value.IsMinContentValue()) { + float maxContribution = 0; + foreach (GridCell cell in cells) { + // non-spanning items only + if (cell.GetGridSpan(order) == 1) { + float contribution = CalculateMinContribution(cell, order); + maxContribution = Math.Max(maxContribution, contribution); + } + } + track.baseSize = maxContribution; + } + // -> For min-content maximums: + if (track.value.IsMinContentValue() && track.baseSize > EPSILON) { + track.growthLimit = track.baseSize; + } + // -> For max-content maximums: + // Treat auto as max-content for max track sizing function + if (track.value.IsAutoValue() || track.value.IsMaxContentValue()) { + float maxContribution = 0; + foreach (GridCell cell in cells) { + // non-spanning items only + if (cell.GetGridSpan(order) == 1) { + float contribution = CalculateMaxContribution(cell, order); + maxContribution = Math.Max(maxContribution, contribution); + } + } + if (maxContribution > EPSILON) { + track.growthLimit = maxContribution; + } + } + // if a track’s growth limit is now less than its base size + if (track.growthLimit > 0 && track.baseSize > EPSILON && track.baseSize > track.growthLimit) { + track.growthLimit = track.baseSize; + } + } + // 3. Increase sizes to accommodate spanning items crossing content-sized tracks. + int maxSpanCell = 0; + foreach (GridCell cell in cachedUniqueGridCells) { + maxSpanCell = Math.Max(maxSpanCell, cell.GetGridSpan(order)); + } + for (int span = 2; span <= maxSpanCell; span++) { + foreach (GridCell cell in cachedUniqueGridCells) { + if (cell.GetGridSpan(order) == span) { + bool flexTracksExist = false; + IList affectedTracks = GetAffectedTracks(cell); + foreach (GridTrackSizer.Track track in affectedTracks) { + if (track.value.IsFlexibleValue()) { + flexTracksExist = true; + } + } + if (flexTracksExist) { + continue; + } + float contribution = CalculateMinContribution(cell, order); + // 3.1 For intrinsic minimums: + // 3.2 For content-based minimums: + // 3.3 For max-content minimums: + DistributeExtraSpace(affectedTracks, true, contribution); + } + } + } + // 3.4 If at this point any track’s growth limit is now less than its base size: + // 3.5 For intrinsic maximums: + // 3.6 For max-content maximums: + // 4. Increase sizes to accommodate spanning items crossing flexible tracks: + foreach (GridCell cell in cachedUniqueGridCells) { + bool atLeastOneFlexTrack = false; + IList affectedTracks = new List(); + for (int i = cell.GetStart(order); i < cell.GetEnd(order); i++) { + if (tracks[i].value.IsFlexibleValue()) { + atLeastOneFlexTrack = true; + affectedTracks.Add(tracks[i]); + } + } + if (!atLeastOneFlexTrack) { + continue; + } + float contribution = CalculateMinContribution(cell, order); + DistributeExtraSpaceWithFlexTracks(affectedTracks, contribution); + } + // 5. If any track still has an infinite growth limit + foreach (GridTrackSizer.Track track in tracks) { + if (track.growthLimit < 0) { + track.growthLimit = track.baseSize; + } + } + } + + private void DistributeExtraSpaceWithFlexTracks(IList tracks, float sizeContribution + ) { + // 1. Find the space to distribute: + float trackSizes = 0; + float sumFraction = 0; + foreach (GridTrackSizer.Track track in tracks) { + trackSizes += track.baseSize; + if (track.value.IsFlexibleValue()) { + sumFraction += (float)track.value.GetValue(); + } + } + float space = Math.Max(0, sizeContribution - trackSizes); + // 2. Distribute space up to limits: + while (space > EPSILON) { + float distributedSpace = space / sumFraction; + bool allFrozen = true; + foreach (GridTrackSizer.Track track in tracks) { + if (track.value.IsFlexibleValue()) { + float? added = DistributeSpaceToTrack(track, distributedSpace); + if (added != null) { + space -= (float)added; + allFrozen = false; + } + } + } + if (allFrozen) { + break; + } + } + } + + // 3. Distribute space to non-affected tracks: skipped + // 4. Distribute space beyond limits: skipped + private void DistributeExtraSpace(IList tracks, bool affectsBase, float sizeContribution + ) { + // 1. Find the space to distribute: + float trackSizes = 0; + int numberOfAffectedTracks = 0; + foreach (GridTrackSizer.Track track in tracks) { + trackSizes += affectsBase ? track.baseSize : track.growthLimit; + if (!track.value.IsPointValue() && !track.value.IsPercentValue()) { + numberOfAffectedTracks++; + } + } + float space = Math.Max(0, sizeContribution - trackSizes); + // 2. Distribute space up to limits: + while (space > EPSILON) { + float distributedSpace = space / numberOfAffectedTracks; + bool allFrozen = true; + foreach (GridTrackSizer.Track track in tracks) { + if (!track.value.IsPointValue() && !track.value.IsPercentValue()) { + float? added = DistributeSpaceToTrack(track, distributedSpace); + if (added != null) { + space -= (float)added; + allFrozen = false; + } + } + } + if (allFrozen) { + break; + } + } + } + + // 3. Distribute space to non-affected tracks: skipped + // 4. Distribute space beyond limits: skipped + private void InitializeTrackSizes() { + foreach (GridTrackSizer.Track track in tracks) { + // A fixed sizing function + // TODO DEVSIX-8384 percent value can be resolvable for height if height of grid container is specified + if (track.value.IsPointValue() || track.value.IsPercentValue()) { + if (track.value.IsPointValue()) { + track.baseSize = (float)track.value.GetValue(); + } + else { + track.baseSize = (float)track.value.GetValue() / 100 * availableSpace; + } + track.growthLimit = track.baseSize; + } + else { + track.baseSize = 0; + track.growthLimit = -1; + } + } + } + + private static float? DistributeSpaceToTrack(GridTrackSizer.Track track, float distributedSpace) { + if (track.growthLimit < 0 || distributedSpace + track.baseSize <= track.growthLimit) { + track.baseSize += distributedSpace; + return distributedSpace; + } + else { + if (JavaUtil.FloatCompare(track.growthLimit, track.baseSize) != 0) { + float addedToLimit = track.growthLimit - track.baseSize; + track.baseSize += addedToLimit; + return addedToLimit; + } + } + return null; + } + + private static float CalculateMinContribution(GridCell cell, Grid.GridOrder order) { + if (Grid.GridOrder.COLUMN == order) { + if (cell.GetValue() is AbstractRenderer) { + AbstractRenderer abstractRenderer = (AbstractRenderer)cell.GetValue(); + return abstractRenderer.GetMinMaxWidth().GetMinWidth(); + } + } + else { + cell.GetValue().SetProperty(Property.FILL_AVAILABLE_AREA, false); + LayoutContext layoutContext = new LayoutContext(new LayoutArea(1, new Rectangle(cell.GetLayoutArea().GetWidth + (), AbstractRenderer.INF))); + LayoutResult inifiniteHeighLayoutResult = cell.GetValue().Layout(layoutContext); + if (inifiniteHeighLayoutResult.GetStatus() == LayoutResult.NOTHING || inifiniteHeighLayoutResult.GetStatus + () == LayoutResult.PARTIAL) { + return 0; + } + return inifiniteHeighLayoutResult.GetOccupiedArea().GetBBox().GetHeight(); + } + return 0; + } + + private static float CalculateMaxContribution(GridCell cell, Grid.GridOrder gridOrder) { + if (Grid.GridOrder.COLUMN == gridOrder) { + if (cell.GetValue() is AbstractRenderer) { + AbstractRenderer abstractRenderer = (AbstractRenderer)cell.GetValue(); + return abstractRenderer.GetMinMaxWidth().GetMaxWidth(); + } + } + else { + cell.GetValue().SetProperty(Property.FILL_AVAILABLE_AREA, false); + // https://drafts.csswg.org/css-sizing-3/#auto-box-sizes: + // min-content block size - For block containers, tables, and + // inline boxes, this is equivalent to the max-content block size. + LayoutContext layoutContext = new LayoutContext(new LayoutArea(1, new Rectangle(cell.GetLayoutArea().GetWidth + (), AbstractRenderer.INF))); + LayoutResult inifiniteHeighLayoutResult = cell.GetValue().Layout(layoutContext); + if (inifiniteHeighLayoutResult.GetStatus() == LayoutResult.NOTHING || inifiniteHeighLayoutResult.GetStatus + () == LayoutResult.PARTIAL) { + cell.SetValueFitOnCellArea(false); + return 0; + } + return inifiniteHeighLayoutResult.GetOccupiedArea().GetBBox().GetHeight(); + } + return 0; + } + + private class Track { + internal float baseSize; + + // consider -1 as an infinity value + internal float growthLimit; + + internal GridValue value; + } + } +} diff --git a/itext/itext.layout/itext/layout/renderer/GridView.cs b/itext/itext.layout/itext/layout/renderer/GridView.cs index ceb8ee5c2c..660ea7a4fa 100644 --- a/itext/itext.layout/itext/layout/renderer/GridView.cs +++ b/itext/itext.layout/itext/layout/renderer/GridView.cs @@ -115,9 +115,10 @@ internal virtual GridView.Pos Reset(int y, int x, int rightMargin, int bottomMar /// height of the cell /// true if cell is fit, false otherwise internal virtual bool Fit(int width, int height) { + GridCell[][] rows = grid.GetRows(); for (int i = cursor.x; i < cursor.x + width; ++i) { for (int j = cursor.y; j < cursor.y + height; ++j) { - if (grid.GetRows()[j][i] != null) { + if (rows[j][i] != null) { return false; } } diff --git a/port-hash b/port-hash index e50c9d7913..e0884ab23e 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -5805b4e1512e640cf44d87df9d728c8cbe5b311a +aca706e52404f21ae3c591197cf5d07672bb27b4