Browse Source

Merge remote-tracking branch 'origin/2022.02'

# Conflicts:
#	QuestPDF.Examples/RowExamples.cs
#	QuestPDF.UnitTests/RowTests.cs
#	QuestPDF/Elements/Row.cs
#	QuestPDF/Fluent/RowExtensions.cs
#	QuestPDF/QuestPDF.csproj
#	QuestPDF/Resources/ReleaseNotes.txt
Marcin Ziąbek 3 years ago
parent
commit
3649607bd9
71 changed files with 1501 additions and 1343 deletions
  1. 3 3
      QuestPDF.Examples/ChartExamples.cs
  2. 37 0
      QuestPDF.Examples/ColumnExamples.cs
  3. 5 5
      QuestPDF.Examples/ComplexLayoutBenchmark.cs
  4. 2 2
      QuestPDF.Examples/ContinousPage.cs
  5. 2 2
      QuestPDF.Examples/DebuggingTesting.cs
  6. 4 4
      QuestPDF.Examples/DefaultTextStyleExample.cs
  7. 4 4
      QuestPDF.Examples/DefaultTextStyleExamples.cs
  8. 7 7
      QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs
  9. 46 46
      QuestPDF.Examples/ElementExamples.cs
  10. 3 3
      QuestPDF.Examples/EnsureSpaceExample.cs
  11. 4 4
      QuestPDF.Examples/FrameExample.cs
  12. 5 5
      QuestPDF.Examples/ImageExamples.cs
  13. 1 1
      QuestPDF.Examples/InlinedExamples.cs
  14. 57 0
      QuestPDF.Examples/LineExamples.cs
  15. 1 1
      QuestPDF.Examples/LoremPicsumExample.cs
  16. 6 6
      QuestPDF.Examples/Padding.cs
  17. 20 21
      QuestPDF.Examples/RowExamples.cs
  18. 42 0
      QuestPDF.Examples/ScaleToFitExamples.cs
  19. 2 2
      QuestPDF.Examples/ShowOnceExample.cs
  20. 3 3
      QuestPDF.Examples/SkipOnceExample.cs
  21. 48 0
      QuestPDF.Examples/StopPaging.cs
  22. 28 28
      QuestPDF.Examples/TextBenchmark.cs
  23. 1 1
      QuestPDF.Examples/TextExamples.cs
  24. 21 21
      QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs
  25. 9 9
      QuestPDF.ReportSample/Layouts/PhotoTemplate.cs
  26. 11 11
      QuestPDF.ReportSample/Layouts/SectionTemplate.cs
  27. 16 16
      QuestPDF.ReportSample/Layouts/StandardReport.cs
  28. 8 8
      QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs
  29. 1 1
      QuestPDF.ReportSample/Tests.cs
  30. 54 165
      QuestPDF.UnitTests/ColumnTests.cs
  31. 76 73
      QuestPDF.UnitTests/DecorationTests.cs
  32. 54 54
      QuestPDF.UnitTests/GridTests.cs
  33. 0 268
      QuestPDF.UnitTests/RowTests.cs
  34. 3 3
      QuestPDF/Drawing/DocumentContainer.cs
  35. 4 2
      QuestPDF/Drawing/DocumentGenerator.cs
  36. 1 1
      QuestPDF/Drawing/PdfCanvas.cs
  37. 1 1
      QuestPDF/Drawing/XpsCanvas.cs
  38. 120 0
      QuestPDF/Elements/Column.cs
  39. 75 61
      QuestPDF/Elements/Decoration.cs
  40. 6 6
      QuestPDF/Elements/Grid.cs
  41. 30 43
      QuestPDF/Elements/Inlined.cs
  42. 46 0
      QuestPDF/Elements/Line.cs
  43. 2 2
      QuestPDF/Elements/Page.cs
  44. 98 119
      QuestPDF/Elements/Row.cs
  45. 78 0
      QuestPDF/Elements/ScaleToFit.cs
  46. 0 143
      QuestPDF/Elements/Stack.cs
  47. 25 0
      QuestPDF/Elements/StopPaging.cs
  48. 20 14
      QuestPDF/Fluent/BorderExtensions.cs
  49. 44 0
      QuestPDF/Fluent/ColumnExtensions.cs
  50. 16 12
      QuestPDF/Fluent/ConstrainedExtensions.cs
  51. 38 6
      QuestPDF/Fluent/DecorationExtensions.cs
  52. 11 2
      QuestPDF/Fluent/ElementExtensions.cs
  53. 7 7
      QuestPDF/Fluent/GridExtensions.cs
  54. 12 5
      QuestPDF/Fluent/InlinedExtensions.cs
  55. 36 0
      QuestPDF/Fluent/LineExtensions.cs
  56. 20 14
      QuestPDF/Fluent/PaddingExtensions.cs
  57. 28 20
      QuestPDF/Fluent/PageExtensions.cs
  58. 31 10
      QuestPDF/Fluent/RowExtensions.cs
  59. 2 2
      QuestPDF/Fluent/ScaleExtensions.cs
  60. 0 33
      QuestPDF/Fluent/StackExtensions.cs
  61. 5 5
      QuestPDF/Fluent/TableExtensions.cs
  62. 5 5
      QuestPDF/Fluent/TextExtensions.cs
  63. 4 4
      QuestPDF/Fluent/TranslateExtensions.cs
  64. 3 3
      QuestPDF/Helpers/PageSizes.cs
  65. 56 0
      QuestPDF/Helpers/WriteOnlyStream.cs
  66. 2 2
      QuestPDF/Infrastructure/Size.cs
  67. 44 0
      QuestPDF/Infrastructure/Unit.cs
  68. 1 1
      QuestPDF/QuestPDF.csproj
  69. 7 7
      QuestPDF/Resources/Description.md
  70. 8 4
      QuestPDF/Resources/ReleaseNotes.txt
  71. 31 32
      readme.md

+ 3 - 3
QuestPDF.Examples/ChartExamples.cs

@@ -52,14 +52,14 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Background(Colors.White)
                         .Background(Colors.White)
                         .Padding(25)
                         .Padding(25)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack
+                            column
                                 .Item()
                                 .Item()
                                 .PaddingBottom(10)
                                 .PaddingBottom(10)
                                 .Text("Chart example", TextStyle.Default.Size(20).SemiBold().Color(Colors.Blue.Medium));
                                 .Text("Chart example", TextStyle.Default.Size(20).SemiBold().Color(Colors.Blue.Medium));
                             
                             
-                            stack
+                            column
                                 .Item()
                                 .Item()
                                 .Border(1)
                                 .Border(1)
                                 .ExtendHorizontal()
                                 .ExtendHorizontal()

+ 37 - 0
QuestPDF.Examples/ColumnExamples.cs

@@ -0,0 +1,37 @@
+using NUnit.Framework;
+using QuestPDF.Examples.Engine;
+using QuestPDF.Fluent;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Examples
+{
+    public class ColumnExamples
+    {
+        [Test]
+        public void Column()
+        {
+            RenderingTest
+                .Create()
+                .PageSize(PageSizes.A4)
+                .ShowResults()
+                .ProducePdf()
+                .Render(container =>
+                {
+                    container.Column(column =>
+                    {
+                        column.Item().Element(Block);
+
+                        static void Block(IContainer container)
+                        {
+                            container
+                                .Width(72)
+                                .Height(3.5f)
+                                .Height(1.5f)
+                                .Background(Placeholders.BackgroundColor());
+                        }
+                    });
+                });
+        }
+    }
+}

+ 5 - 5
QuestPDF.Examples/ComplexLayoutBenchmark.cs

@@ -36,8 +36,8 @@ namespace QuestPDF.Examples
                     .BorderColor(Colors.Black)
                     .BorderColor(Colors.Black)
                     .Row(row =>
                     .Row(row =>
                     {
                     {
-                        row.RelativeColumn().Element(x => GenerateStructure(x, level));
-                        row.RelativeColumn().Element(x => GenerateStructure(x, level));
+                        row.RelativeItem().Element(x => GenerateStructure(x, level));
+                        row.RelativeItem().Element(x => GenerateStructure(x, level));
                     });
                     });
             }
             }
             else
             else
@@ -45,10 +45,10 @@ namespace QuestPDF.Examples
                 container
                 container
                     .Border(level / 4f)
                     .Border(level / 4f)
                     .BorderColor(Colors.Black)
                     .BorderColor(Colors.Black)
-                    .Stack(stack =>
+                    .Column(column =>
                     {
                     {
-                        stack.Item().Element(x => GenerateStructure(x, level));
-                        stack.Item().Element(x => GenerateStructure(x, level));
+                        column.Item().Element(x => GenerateStructure(x, level));
+                        column.Item().Element(x => GenerateStructure(x, level));
                     });
                     });
             }
             }
         }
         }

+ 2 - 2
QuestPDF.Examples/ContinousPage.cs

@@ -22,10 +22,10 @@ namespace QuestPDF.Examples
                 
                 
                 page.Header().Text("Header");
                 page.Header().Text("Header");
                 
                 
-                page.Content().PaddingVertical(10).Border(1).Padding(10).Stack(stack =>
+                page.Content().PaddingVertical(10).Border(1).Padding(10).Column(column =>
                 {
                 {
                     foreach (var index in Enumerable.Range(1, 100))
                     foreach (var index in Enumerable.Range(1, 100))
-                        stack.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color()));
+                        column.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color()));
                 });
                 });
                 
                 
                 page.Footer().Text("Footer");
                 page.Footer().Text("Footer");

+ 2 - 2
QuestPDF.Examples/DebuggingTesting.cs

@@ -9,7 +9,7 @@ namespace QuestPDF.Examples
     public class DebuggingTesting
     public class DebuggingTesting
     {
     {
         [Test]
         [Test]
-        public void Stack()
+        public void Column()
         {
         {
             Assert.Throws<DocumentLayoutException>(() =>
             Assert.Throws<DocumentLayoutException>(() =>
             {
             {
@@ -23,7 +23,7 @@ namespace QuestPDF.Examples
                             .Width(100)
                             .Width(100)
                             .Background(Colors.Grey.Lighten3)
                             .Background(Colors.Grey.Lighten3)
                             .DebugPointer("Example debug pointer")
                             .DebugPointer("Example debug pointer")
-                            .Stack(x =>
+                            .Column(x =>
                             {
                             {
                                 x.Item().Text("Test");
                                 x.Item().Text("Test");
                                 x.Item().Width(150);
                                 x.Item().Width(150);

+ 4 - 4
QuestPDF.Examples/DefaultTextStyleExample.cs

@@ -13,7 +13,7 @@ namespace QuestPDF.Examples
         {
         {
             RenderingTest
             RenderingTest
                 .Create()
                 .Create()
-                .ProduceImages()
+                .ProducePdf()
                 .ShowResults()
                 .ShowResults()
                 .RenderDocument(container =>
                 .RenderDocument(container =>
                 {
                 {
@@ -26,11 +26,11 @@ namespace QuestPDF.Examples
                         page.Size(PageSizes.A4);
                         page.Size(PageSizes.A4);
                         page.Background(Colors.White);
                         page.Background(Colors.White);
         
         
-                        page.Content().Stack(stack =>
+                        page.Content().Column(column =>
                         {
                         {
-                            stack.Item().Text(Placeholders.Sentence());
+                            column.Item().Text(Placeholders.Sentence());
                         
                         
-                            stack.Item().Text(text =>
+                            column.Item().Text(text =>
                             {
                             {
                                 // text in this block is additionally semibold
                                 // text in this block is additionally semibold
                                 text.DefaultTextStyle(TextStyle.Default.SemiBold());
                                 text.DefaultTextStyle(TextStyle.Default.SemiBold());

+ 4 - 4
QuestPDF.Examples/DefaultTextStyleExamples.cs

@@ -24,12 +24,12 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Padding(10)
                         .Padding(10)
                         .DefaultTextStyle(TextStyle.Default.Bold().Underline())
                         .DefaultTextStyle(TextStyle.Default.Bold().Underline())
-                        .Stack(stack =>
+                        .Column(column =>
                         { 
                         { 
-                            stack.Item().Text("Default style applies to all children", TextStyle.Default);
-                            stack.Item().Text("You can override certain styles", TextStyle.Default.Underline(false).Color(Colors.Green.Darken2));
+                            column.Item().Text("Default style applies to all children", TextStyle.Default);
+                            column.Item().Text("You can override certain styles", TextStyle.Default.Underline(false).Color(Colors.Green.Darken2));
                             
                             
-                            stack.Item().PaddingTop(10).Border(1).Grid(grid =>
+                            column.Item().PaddingTop(10).Border(1).Grid(grid =>
                             {
                             {
                                 grid.Columns(4);
                                 grid.Columns(4);
 
 

+ 7 - 7
QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs

@@ -23,21 +23,21 @@ namespace QuestPDF.Examples
                     container.Page(page =>
                     container.Page(page =>
                     {
                     {
                         page.Size(PageSizes.A6);
                         page.Size(PageSizes.A6);
-                        page.Margin(30);
+                        page.Margin(5);
                         page.Background(Colors.White);
                         page.Background(Colors.White);
                         
                         
-                        page.Header().Stack(stack =>
+                        page.Header().Column(column =>
                         {
                         {
-                            stack.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(60);
-                            stack.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(40);
+                            column.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(60);
+                            column.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(40);
                         });
                         });
                         
                         
-                        page.Content().PaddingVertical(10).Stack(stack =>
+                        page.Content().PaddingVertical(10).Column(column =>
                         {
                         {
-                            stack.Spacing(10);
+                            column.Spacing(10);
 
 
                             foreach (var _ in Enumerable.Range(0, 13))
                             foreach (var _ in Enumerable.Range(0, 13))
-                                stack.Item().Background(Colors.Grey.Lighten2).Height(40);
+                                column.Item().Background(Colors.Grey.Lighten2).Height(40);
                         });
                         });
                         
                         
                         page.Footer().AlignCenter().Text(text =>
                         page.Footer().AlignCenter().Text(text =>

+ 46 - 46
QuestPDF.Examples/ElementExamples.cs

@@ -40,7 +40,7 @@ namespace QuestPDF.Examples
                         .Decoration(decoration =>
                         .Decoration(decoration =>
                         {
                         {
                             decoration
                             decoration
-                                .Header()
+                                .Before()
                                 .Background(Colors.Grey.Medium)
                                 .Background(Colors.Grey.Medium)
                                 .Padding(10)
                                 .Padding(10)
                                 .Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
                                 .Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
@@ -66,27 +66,27 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Background("#FFF")
                         .Background("#FFF")
                         .Padding(20)
                         .Padding(20)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack.Item()
+                            column.Item()
                                 .PaddingBottom(10)
                                 .PaddingBottom(10)
                                 .AlignCenter()
                                 .AlignCenter()
                                 .Text("This Row element is 700pt wide");
                                 .Text("This Row element is 700pt wide");
 
 
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.ConstantColumn(100)
+                                row.ConstantItem(100)
                                     .Background(Colors.Grey.Lighten1)
                                     .Background(Colors.Grey.Lighten1)
                                     .Padding(10)
                                     .Padding(10)
                                     .ExtendVertical()
                                     .ExtendVertical()
                                     .Text("This column is 100 pt wide");
                                     .Text("This column is 100 pt wide");
 
 
-                                row.RelativeColumn()
+                                row.RelativeItem()
                                     .Background(Colors.Grey.Lighten2)
                                     .Background(Colors.Grey.Lighten2)
                                     .Padding(10)
                                     .Padding(10)
                                     .Text("This column takes 1/3 of the available space (200pt)");
                                     .Text("This column takes 1/3 of the available space (200pt)");
 
 
-                                row.RelativeColumn(2)
+                                row.RelativeItem(2)
                                     .Background(Colors.Grey.Lighten3)
                                     .Background(Colors.Grey.Lighten3)
                                     .Padding(10)
                                     .Padding(10)
                                     .Text("This column takes 2/3 of the available space (400pt)");
                                     .Text("This column takes 2/3 of the available space (400pt)");
@@ -109,15 +109,15 @@ namespace QuestPDF.Examples
                         .Row(row =>
                         .Row(row =>
                         {
                         {
                             row.Spacing(20);
                             row.Spacing(20);
-                            row.RelativeColumn(2).Border(1).Background(Colors.Grey.Lighten1);
-                            row.RelativeColumn(3).Border(1).Background(Colors.Grey.Lighten2);
-                            row.RelativeColumn(4).Border(1).Background(Colors.Grey.Lighten3);
+                            row.RelativeItem(2).Border(1).Background(Colors.Grey.Lighten1);
+                            row.RelativeItem(3).Border(1).Background(Colors.Grey.Lighten2);
+                            row.RelativeItem(4).Border(1).Background(Colors.Grey.Lighten3);
                         });
                         });
                 });
                 });
         }
         }
     
     
         [Test]
         [Test]
-        public void Stack()
+        public void column()
         {
         {
             RenderingTest
             RenderingTest
                 .Create()
                 .Create()
@@ -127,13 +127,13 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Background("#FFF")
                         .Background("#FFF")
                         .Padding(15)
                         .Padding(15)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack.Spacing(15);
+                            column.Spacing(15);
                     
                     
-                            stack.Item().Background(Colors.Grey.Medium).Height(50);
-                            stack.Item().Background(Colors.Grey.Lighten1).Height(100);
-                            stack.Item().Background(Colors.Grey.Lighten2).Height(150);
+                            column.Item().Background(Colors.Grey.Medium).Height(50);
+                            column.Item().Background(Colors.Grey.Lighten1).Height(100);
+                            column.Item().Background(Colors.Grey.Lighten2).Height(150);
                         });
                         });
                 });
                 });
         }
         }
@@ -267,12 +267,12 @@ namespace QuestPDF.Examples
                             layers
                             layers
                                 .PrimaryLayer()
                                 .PrimaryLayer()
                                 .Padding(25)
                                 .Padding(25)
-                                .Stack(stack =>
+                                .Column(column =>
                                 {
                                 {
-                                    stack.Spacing(5);
+                                    column.Spacing(5);
                             
                             
                                     foreach (var _ in Enumerable.Range(0, 7))
                                     foreach (var _ in Enumerable.Range(0, 7))
-                                        stack.Item().Text(Placeholders.Sentence());
+                                        column.Item().Text(Placeholders.Sentence());
                                 });
                                 });
                         
                         
                             // layer above the main content    
                             // layer above the main content    
@@ -304,16 +304,16 @@ namespace QuestPDF.Examples
         //                 {
         //                 {
         //                     page.Header().PageNumber("Page {pdf:currentPage}");
         //                     page.Header().PageNumber("Page {pdf:currentPage}");
         //             
         //             
-        //                     page.Content().Height(300).Stack(content =>
+        //                     page.Content().Height(300).column(content =>
         //                     {
         //                     {
         //                         content.Item().Height(200).Background(Colors.Grey.Lighten2);
         //                         content.Item().Height(200).Background(Colors.Grey.Lighten2);
         //                 
         //                 
-        //                         content.Item().EnsureSpace(100).Stack(stack =>
+        //                         content.Item().EnsureSpace(100).column(column =>
         //                         {
         //                         {
-        //                             stack.Spacing(10);
+        //                             column.Spacing(10);
         //                     
         //                     
         //                             foreach (var _ in Enumerable.Range(0, 4))
         //                             foreach (var _ in Enumerable.Range(0, 4))
-        //                                 stack.Item().Height(50).Background(Colors.Green.Lighten1);
+        //                                 column.Item().Height(50).Background(Colors.Green.Lighten1);
         //                         }); 
         //                         }); 
         //                     });
         //                     });
         //                 });
         //                 });
@@ -378,7 +378,7 @@ namespace QuestPDF.Examples
                         .Row(row =>
                         .Row(row =>
                         {
                         {
                             foreach (var color in colors)
                             foreach (var color in colors)
-                                row.RelativeColumn().Background(color);
+                                row.RelativeItem().Background(color);
                         });
                         });
                 });
                 });
         }
         }
@@ -437,10 +437,10 @@ namespace QuestPDF.Examples
                         {
                         {
                             layers.Layer().Text("Something else");
                             layers.Layer().Text("Something else");
                     
                     
-                            layers.PrimaryLayer().Stack(stack =>
+                            layers.PrimaryLayer().Column(column =>
                             {
                             {
-                                stack.Item().PaddingTop(20).Text("Text 1");
-                                stack.Item().PaddingTop(40).Text("Text 2");
+                                column.Item().PaddingTop(20).Text("Text 1");
+                                column.Item().PaddingTop(40).Text("Text 2");
                             });
                             });
                     
                     
                             layers.Layer().Canvas((canvas, size) =>
                             layers.Layer().Canvas((canvas, size) =>
@@ -501,13 +501,13 @@ namespace QuestPDF.Examples
                                 .SemiBold();
                                 .SemiBold();
     
     
                             decoration
                             decoration
-                                .Header()
+                                .Before()
                                 .PaddingBottom(10)
                                 .PaddingBottom(10)
                                 .Text("Example: scale component", headerFontStyle);
                                 .Text("Example: scale component", headerFontStyle);
     
     
                             decoration
                             decoration
                                 .Content()
                                 .Content()
-                                .Stack(stack =>
+                                .Column(column =>
                                 {
                                 {
                                     var scales = new[] { 0.8f, 0.9f, 1.1f, 1.2f };
                                     var scales = new[] { 0.8f, 0.9f, 1.1f, 1.2f };
 
 
@@ -519,7 +519,7 @@ namespace QuestPDF.Examples
 
 
                                         var fontStyle = TextStyle.Default.Size(16);
                                         var fontStyle = TextStyle.Default.Size(16);
                 
                 
-                                        stack
+                                        column
                                             .Item()
                                             .Item()
                                             .Border(1)
                                             .Border(1)
                                             .Background(fontColor)
                                             .Background(fontColor)
@@ -708,14 +708,14 @@ namespace QuestPDF.Examples
                         .Border(2)
                         .Border(2)
                         .Row(row =>
                         .Row(row =>
                         {
                         {
-                            row.ConstantColumn(25)
+                            row.ConstantItem(25)
                                 .Border(1)
                                 .Border(1)
                                 .RotateLeft()
                                 .RotateLeft()
                                 .AlignCenter()
                                 .AlignCenter()
                                 .AlignMiddle()
                                 .AlignMiddle()
                                 .Text("Sample text");
                                 .Text("Sample text");
                             
                             
-                            row.RelativeColumn().Border(1).Padding(5).Text(Placeholders.Paragraph());
+                            row.RelativeItem().Border(1).Padding(5).Text(Placeholders.Paragraph());
                         });
                         });
                 });
                 });
         }
         }
@@ -731,11 +731,11 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Padding(25)
                         .Padding(25)
                         .PaddingLeft(75)
                         .PaddingLeft(75)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
+                            column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4);
                             
                             
-                            stack
+                            column
                                 .Item()
                                 .Item()
                                 
                                 
                                 // creates an infinite space for its child
                                 // creates an infinite space for its child
@@ -751,7 +751,7 @@ namespace QuestPDF.Examples
                                 
                                 
                                 .Background(Colors.Blue.Darken1);
                                 .Background(Colors.Blue.Darken1);
                             
                             
-                            stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
+                            column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);
                         });
                         });
                 });
                 });
         }
         }
@@ -766,13 +766,13 @@ namespace QuestPDF.Examples
                 {
                 {
                     container
                     container
                         .Padding(25)
                         .Padding(25)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.RelativeColumn().LabelCell("Label 1");
+                                row.RelativeItem().LabelCell("Label 1");
                                 
                                 
-                                row.RelativeColumn(3).Grid(grid =>
+                                row.RelativeItem(3).Grid(grid =>
                                 {
                                 {
                                     grid.Columns(3);
                                     grid.Columns(3);
                                     
                                     
@@ -784,11 +784,11 @@ namespace QuestPDF.Examples
                                 });
                                 });
                             });
                             });
                             
                             
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.RelativeColumn().ValueCell().Text("Value 1");
+                                row.RelativeItem().ValueCell().Text("Value 1");
                                 
                                 
-                                row.RelativeColumn(3).Grid(grid =>
+                                row.RelativeItem(3).Grid(grid =>
                                 {
                                 {
                                     grid.Columns(3);
                                     grid.Columns(3);
                                     
                                     
@@ -800,10 +800,10 @@ namespace QuestPDF.Examples
                                 });
                                 });
                             });
                             });
                             
                             
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.RelativeColumn().LabelCell("Label 6");
-                                row.RelativeColumn().ValueCell().Text("Value 6");
+                                row.RelativeItem().LabelCell("Label 6");
+                                row.RelativeItem().ValueCell().Text("Value 6");
                             });
                             });
                         });
                         });
                 });
                 });

+ 3 - 3
QuestPDF.Examples/EnsureSpaceExample.cs

@@ -25,15 +25,15 @@ namespace QuestPDF.Examples
                         
                         
                         page.Header().Text("With ensure space", TextStyle.Default.SemiBold());
                         page.Header().Text("With ensure space", TextStyle.Default.SemiBold());
                         
                         
-                        page.Content().Stack(stack =>
+                        page.Content().Column(column =>
                         {
                         {
-                            stack
+                            column
                                 .Item()
                                 .Item()
                                 .ExtendHorizontal()
                                 .ExtendHorizontal()
                                 .Height(75)
                                 .Height(75)
                                 .Background(Colors.Grey.Lighten2);
                                 .Background(Colors.Grey.Lighten2);
                             
                             
-                            stack
+                            column
                                 .Item()
                                 .Item()
                                 .EnsureSpace(100)
                                 .EnsureSpace(100)
                                 .Text(Placeholders.LoremIpsum());
                                 .Text(Placeholders.LoremIpsum());

+ 4 - 4
QuestPDF.Examples/FrameExample.cs

@@ -36,14 +36,14 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Background("#FFF")
                         .Background("#FFF")
                         .Padding(25)
                         .Padding(25)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
                             for(var i = 1; i <= 4; i++)
                             for(var i = 1; i <= 4; i++)
                             {
                             {
-                                stack.Item().Row(row =>
+                                column.Item().Row(row =>
                                 {
                                 {
-                                    row.RelativeColumn(2).LabelCell(Placeholders.Label());
-                                    row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph());
+                                    row.RelativeItem(2).LabelCell(Placeholders.Label());
+                                    row.RelativeItem(3).ValueCell().Text(Placeholders.Paragraph());
                                 });
                                 });
                             }
                             }
                         });
                         });

+ 5 - 5
QuestPDF.Examples/ImageExamples.cs

@@ -19,17 +19,17 @@ namespace QuestPDF.Examples
                 .ShowResults()
                 .ShowResults()
                 .Render(page =>
                 .Render(page =>
                 {
                 {
-                    page.Padding(25).Stack(stack =>
+                    page.Padding(25).Column(column =>
                     {
                     {
-                        stack.Spacing(25);
+                        column.Spacing(25);
                         
                         
-                        stack.Item().Image("logo.png");
+                        column.Item().Image("logo.png");
 
 
                         var binaryData = File.ReadAllBytes("logo.png");
                         var binaryData = File.ReadAllBytes("logo.png");
-                        stack.Item().Image(binaryData);
+                        column.Item().Image(binaryData);
                         
                         
                         using var stream = new FileStream("logo.png", FileMode.Open);
                         using var stream = new FileStream("logo.png", FileMode.Open);
-                        stack.Item().Image(stream);
+                        column.Item().Image(stream);
                     });
                     });
                 });
                 });
         }
         }

+ 1 - 1
QuestPDF.Examples/InlinedExamples.cs

@@ -25,7 +25,7 @@ namespace QuestPDF.Examples
                         .Padding(25)
                         .Padding(25)
                         .Decoration(decoration =>
                         .Decoration(decoration =>
                         {
                         {
-                            decoration.Header().Text(text =>
+                            decoration.Before().Text(text =>
                             {
                             {
                                 text.DefaultTextStyle(TextStyle.Default.Size(20));
                                 text.DefaultTextStyle(TextStyle.Default.Size(20));
                                 
                                 

+ 57 - 0
QuestPDF.Examples/LineExamples.cs

@@ -0,0 +1,57 @@
+using System.IO;
+using NUnit.Framework;
+using QuestPDF.Examples.Engine;
+using QuestPDF.Fluent;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Examples
+{
+    public class LineExamples
+    {
+        [Test]
+        public void LineHorizontal()
+        {
+            RenderingTest
+                .Create()
+                .PageSize(PageSizes.A5)
+                .ProduceImages()
+                .ShowResults()
+                .Render(container => 
+                {
+                    container
+                        .Padding(15)
+                        .MinimalBox()
+                        .DefaultTextStyle(TextStyle.Default.Size(16))
+                        .Column(column =>
+                        {
+                            column.Item().Text("Above text");
+                            column.Item().PaddingVertical(5).LineHorizontal(1).LineColor(Colors.Grey.Medium);
+                            column.Item().Text("Below text");
+                        });
+                });
+        }
+        
+        [Test]
+        public void LineVertical()
+        {
+            RenderingTest
+                .Create()
+                .PageSize(PageSizes.A5)
+                .ProduceImages()
+                .ShowResults()
+                .Render(container => 
+                {
+                    container
+                        .Padding(15)
+                        .DefaultTextStyle(TextStyle.Default.Size(16))
+                        .Row(row =>
+                        {
+                            row.AutoItem().Text("Left text");
+                            row.AutoItem().PaddingHorizontal(10).LineVertical(1).LineColor(Colors.Grey.Medium);
+                            row.AutoItem().Text("Right text");
+                        });
+                });
+        }
+    }
+}

+ 1 - 1
QuestPDF.Examples/LoremPicsumExample.cs

@@ -43,7 +43,7 @@ namespace QuestPDF.Examples
                     container
                     container
                         .Background("#FFF")
                         .Background("#FFF")
                         .Padding(25)
                         .Padding(25)
-                        .Stack(column =>
+                        .Column(column =>
                         {
                         {
                             column.Spacing(10);
                             column.Spacing(10);
 
 

+ 6 - 6
QuestPDF.Examples/Padding.cs

@@ -63,7 +63,7 @@ namespace QuestPDF.Examples
                 .Render(container =>
                 .Render(container =>
                 {
                 {
                     container
                     container
-                        .Stack(column =>
+                        .Column(column =>
                         {
                         {
                             column
                             column
                                 .Item()
                                 .Item()
@@ -113,14 +113,14 @@ namespace QuestPDF.Examples
                 .Render(container =>
                 .Render(container =>
                 {
                 {
                     container
                     container
-                        .Stack(column =>
+                        .Column(column =>
                         {
                         {
                             column
                             column
                                 .Item()
                                 .Item()
                                 .Height(150)
                                 .Height(150)
                                 .Row(row =>
                                 .Row(row =>
                                 {
                                 {
-                                    row.RelativeColumn()
+                                    row.RelativeItem()
                                         .Extend()
                                         .Extend()
                                         .Background("FFF")
                                         .Background("FFF")
 
 
@@ -128,7 +128,7 @@ namespace QuestPDF.Examples
                                         .Width(50)
                                         .Width(50)
                                         .Background("444");
                                         .Background("444");
                             
                             
-                                    row.RelativeColumn()
+                                    row.RelativeItem()
                                         .Extend()
                                         .Extend()
                                         .Background("BBB")
                                         .Background("BBB")
 
 
@@ -142,7 +142,7 @@ namespace QuestPDF.Examples
                                 .Height(150)
                                 .Height(150)
                                 .Row(row =>
                                 .Row(row =>
                                 {
                                 {
-                                    row.RelativeColumn()
+                                    row.RelativeItem()
                                         .Extend()
                                         .Extend()
                                         .Background("BBB")
                                         .Background("BBB")
 
 
@@ -150,7 +150,7 @@ namespace QuestPDF.Examples
                                         .Width(50)
                                         .Width(50)
                                         .Background("444");
                                         .Background("444");
                             
                             
-                                    row.RelativeColumn()
+                                    row.RelativeItem()
                                         .Extend()
                                         .Extend()
                                         .Background("BBB")
                                         .Background("BBB")
 
 

+ 20 - 21
QuestPDF.Examples/RowExamples.cs

@@ -9,7 +9,7 @@ namespace QuestPDF.Examples
     public class RowExamples
     public class RowExamples
     {
     {
         [Test]
         [Test]
-        public void ColumnTypes()
+        public void ItemTypes()
         {
         {
             RenderingTest
             RenderingTest
                 .Create()
                 .Create()
@@ -22,25 +22,24 @@ namespace QuestPDF.Examples
                         .Padding(25)
                         .Padding(25)
                         .MinimalBox()
                         .MinimalBox()
                         .Border(1)
                         .Border(1)
-                        .Stack(stack =>
+                        .Column(column =>
                         {
                         {
-                            stack.Item().LabelCell("Total width: 600px");
+                            column.Item().LabelCell("Total width: 600px");
                             
                             
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.ConstantColumn(150).ValueCell("150px");
-                                row.ConstantColumn(100).ValueCell("100px");
-                                row.RelativeColumn(4).ValueCell("200px");
-                                row.RelativeColumn(3).ValueCell("150px");
+                                row.ConstantItem(150).ValueCell("150px");
+                                row.ConstantItem(100).ValueCell("100px");
+                                row.RelativeItem(4).ValueCell("200px");
+                                row.RelativeItem(3).ValueCell("150px");
                             });
                             });
                             
                             
-                            stack.Item().Row(row =>
+                            column.Item().Row(row =>
                             {
                             {
-                                row.ConstantColumn(100).ValueCell("100px");
-                                row.ConstantColumn(50).ValueCell("50px");
-                                row.RelativeColumn(3).ValueCell("300px");
-                                row.RelativeColumn(1).ValueCell("100px");
-                                row.ConstantColumn(50).ValueCell("50px");
+                                row.ConstantItem(100).ValueCell("100px");
+                                row.ConstantItem(50).ValueCell("50px");
+                                row.RelativeItem(2).ValueCell("100px");
+                                row.RelativeItem(1).ValueCell("50px");
                             });
                             });
                         });
                         });
                 });
                 });
@@ -63,17 +62,17 @@ namespace QuestPDF.Examples
                         .Padding(25)
                         .Padding(25)
                         .Row(row =>
                         .Row(row =>
                         {
                         {
-                            row.RelativeColumn().Stack(stack =>
+                            row.RelativeItem().Column(column =>
                             {
                             {
-                                stack.Item().ShowOnce().Element(CreateBox).Text("X");
-                                stack.Item().Element(CreateBox).Text("1");
-                                stack.Item().Element(CreateBox).Text("2");
+                                column.Item().ShowOnce().Element(CreateBox).Text("X");
+                                column.Item().Element(CreateBox).Text("1");
+                                column.Item().Element(CreateBox).Text("2");
                             });
                             });
                                 
                                 
-                            row.RelativeColumn().Stack(stack =>
+                            row.RelativeItem().Column(column =>
                             {
                             {
-                                stack.Item().Element(CreateBox).Text("1");
-                                stack.Item().Element(CreateBox).Text("2");
+                                column.Item().Element(CreateBox).Text("1");
+                                column.Item().Element(CreateBox).Text("2");
                             });
                             });
                         });
                         });
                 });
                 });

+ 42 - 0
QuestPDF.Examples/ScaleToFitExamples.cs

@@ -0,0 +1,42 @@
+using System.Linq;
+using NUnit.Framework;
+using QuestPDF.Examples.Engine;
+using QuestPDF.Fluent;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Examples
+{
+    public class ScaleToFitExamples
+    {
+        [Test]
+        public void ScaleToFit()
+        {
+            RenderingTest
+                .Create()
+                .PageSize(PageSizes.A4)
+                .ProduceImages()
+                .ShowResults()
+                .Render(container =>
+                {
+                    container.Padding(25).Column(column =>
+                    {
+                        var text = Placeholders.Paragraph();
+
+                        foreach (var i in Enumerable.Range(2, 5))
+                        {
+                            column
+                                .Item()
+                                .MinimalBox()
+                                .Border(1)
+                                .Padding(5)
+                                .Width(i * 40)
+                                .Height(i * 20)
+                                .ScaleToFit()
+                                .Text(text);
+                        }
+                    });
+                });
+        }
+    }
+}

+ 2 - 2
QuestPDF.Examples/ShowOnceExample.cs

@@ -27,14 +27,14 @@ namespace QuestPDF.Examples
                         
                         
                         page.Content().PaddingVertical(5).Row(row =>
                         page.Content().PaddingVertical(5).Row(row =>
                         {
                         {
-                            row.RelativeColumn()
+                            row.RelativeItem()
                                 .Background(Colors.Grey.Lighten2)
                                 .Background(Colors.Grey.Lighten2)
                                 .Border(1)
                                 .Border(1)
                                 .Padding(5)
                                 .Padding(5)
                                 .ShowOnce()
                                 .ShowOnce()
                                 .Text(Placeholders.Label());
                                 .Text(Placeholders.Label());
                             
                             
-                            row.RelativeColumn(2)
+                            row.RelativeItem(2)
                                 .Border(1)
                                 .Border(1)
                                 .Padding(5)
                                 .Padding(5)
                                 .Text(Placeholders.Paragraph());
                                 .Text(Placeholders.Paragraph());

+ 3 - 3
QuestPDF.Examples/SkipOnceExample.cs

@@ -23,10 +23,10 @@ namespace QuestPDF.Examples
                         page.Size(PageSizes.A7.Landscape());
                         page.Size(PageSizes.A7.Landscape());
                         page.Background(Colors.White);
                         page.Background(Colors.White);
         
         
-                        page.Header().Stack(stack =>
+                        page.Header().Column(column =>
                         {
                         {
-                            stack.Item().ShowOnce().Text("This header is visible on the first page.");
-                            stack.Item().SkipOnce().Text("This header is visible on the second page and all following.");
+                            column.Item().ShowOnce().Text("This header is visible on the first page.");
+                            column.Item().SkipOnce().Text("This header is visible on the second page and all following.");
                         });
                         });
                         
                         
                         page.Content()
                         page.Content()

+ 48 - 0
QuestPDF.Examples/StopPaging.cs

@@ -0,0 +1,48 @@
+using NUnit.Framework;
+using QuestPDF.Examples.Engine;
+using QuestPDF.Fluent;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Examples
+{
+    public class StopPaging
+    {
+        [Test]
+        public void Example()
+        {
+            RenderingTest
+                .Create()
+                .PageSize(300, 250)
+                .ProduceImages()
+                .ShowResults()
+                .Render(container => 
+                {
+                    container
+                        .Padding(25)
+                        .DefaultTextStyle(TextStyle.Default.Size(14))
+                        .Decoration(decoration =>
+                        {
+                            decoration
+                                .Before()
+                                .Text(text =>
+                                {
+                                    text.DefaultTextStyle(TextStyle.Default.SemiBold().Color(Colors.Blue.Medium));
+                                    
+                                    text.Span("Page ");
+                                    text.CurrentPageNumber();
+                                });
+                            
+                            decoration
+                                .Content()
+                                .Column(column =>
+                                {
+                                    column.Spacing(25);
+                                    column.Item().StopPaging().Text(Placeholders.LoremIpsum());
+                                    column.Item().ExtendHorizontal().Height(75).Background(Colors.Grey.Lighten2);
+                                });
+                        });
+                });
+        }
+    }
+}

+ 28 - 28
QuestPDF.Examples/TextBenchmark.cs

@@ -117,19 +117,19 @@ namespace QuestPDF.Examples
                     {
                     {
                         decoration
                         decoration
                             .Content()
                             .Content()
-                            .Stack(stack =>
+                            .Column(column =>
                             {
                             {
-                                stack.Item().Element(Title);
-                                stack.Item().PageBreak();
-                                stack.Item().Element(TableOfContents);
-                                stack.Item().PageBreak();
+                                column.Item().Element(Title);
+                                column.Item().PageBreak();
+                                column.Item().Element(TableOfContents);
+                                column.Item().PageBreak();
 
 
-                                Chapters(stack);
+                                Chapters(column);
 
 
-                                stack.Item().Element(Acknowledgements);
+                                column.Item().Element(Acknowledgements);
                             });
                             });
 
 
-                        decoration.Footer().Element(Footer);
+                        decoration.After().Element(Footer);
                     });
                     });
             }
             }
             
             
@@ -139,61 +139,61 @@ namespace QuestPDF.Examples
                     .Extend()
                     .Extend()
                     .PaddingBottom(200)
                     .PaddingBottom(200)
                     .AlignBottom()
                     .AlignBottom()
-                    .Stack(stack =>
+                    .Column(column =>
                     {
                     {
-                        stack.Item().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2));
-                        stack.Item().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2));
+                        column.Item().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2));
+                        column.Item().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2));
                     });
                     });
             }
             }
 
 
             void TableOfContents(IContainer container)
             void TableOfContents(IContainer container)
             {
             {
-                container.Stack(stack =>
+                container.Column(column =>
                 {
                 {
-                    SectionTitle(stack, "Spis treści");
+                    SectionTitle(column, "Spis treści");
                     
                     
                     foreach (var chapter in chapters)
                     foreach (var chapter in chapters)
                     {
                     {
-                        stack.Item().InternalLink(chapter.Title).Row(row =>
+                        column.Item().InternalLink(chapter.Title).Row(row =>
                         {
                         {
-                            row.RelativeColumn().Text(chapter.Title, normalStyle);
-                            row.ConstantColumn(100).AlignRight().Text(text => text.PageNumberOfLocation(chapter.Title, normalStyle));
+                            row.RelativeItem().Text(chapter.Title, normalStyle);
+                            row.ConstantItem(100).AlignRight().Text(text => text.PageNumberOfLocation(chapter.Title, normalStyle));
                         });
                         });
                     }
                     }
                 });
                 });
             }
             }
 
 
-            void Chapters(StackDescriptor stack)
+            void Chapters(ColumnDescriptor column)
             {
             {
                 foreach (var chapter in chapters)
                 foreach (var chapter in chapters)
                 {
                 {
-                    stack.Item().Element(container => Chapter(container, chapter.Title, chapter.Content));
+                    column.Item().Element(container => Chapter(container, chapter.Title, chapter.Content));
                 }
                 }
             }
             }
             
             
             void Chapter(IContainer container, string title, string content)
             void Chapter(IContainer container, string title, string content)
             {
             {
-                container.Stack(stack =>
+                container.Column(column =>
                 {
                 {
-                    SectionTitle(stack, title);
+                    SectionTitle(column, title);
   
   
-                    stack.Item().Text(text =>
+                    column.Item().Text(text =>
                     {
                     {
                         text.ParagraphSpacing(5);
                         text.ParagraphSpacing(5);
                         text.Span(content, normalStyle);
                         text.Span(content, normalStyle);
                     });
                     });
                     
                     
-                    stack.Item().PageBreak();
+                    column.Item().PageBreak();
                 });
                 });
             }
             }
 
 
             void Acknowledgements(IContainer container)
             void Acknowledgements(IContainer container)
             {
             {
-                container.Stack(stack =>
+                container.Column(column =>
                 {
                 {
-                    SectionTitle(stack, "Podziękowania");
+                    SectionTitle(column, "Podziękowania");
                     
                     
-                    stack.Item().Text(text =>
+                    column.Item().Text(text =>
                     {
                     {
                         text.DefaultTextStyle(normalStyle);
                         text.DefaultTextStyle(normalStyle);
                         
                         
@@ -204,10 +204,10 @@ namespace QuestPDF.Examples
                 });
                 });
             }
             }
 
 
-            void SectionTitle(StackDescriptor stack, string text)
+            void SectionTitle(ColumnDescriptor column, string text)
             {
             {
-                stack.Item().Location(text).Text(text, subtitleStyle);
-                stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
+                column.Item().Location(text).Text(text, subtitleStyle);
+                column.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
             }
             }
             
             
             void Footer(IContainer container)
             void Footer(IContainer container)

+ 1 - 1
QuestPDF.Examples/TextExamples.cs

@@ -126,7 +126,7 @@ namespace QuestPDF.Examples
         }
         }
         
         
         [Test]
         [Test]
-        public void TextStack()
+        public void Textcolumn()
         {
         {
             RenderingTest
             RenderingTest
                 .Create()
                 .Create()

+ 21 - 21
QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs

@@ -26,58 +26,58 @@ namespace QuestPDF.ReportSample.Layouts
 
 
         private void ComposeHeader(IContainer container)
         private void ComposeHeader(IContainer container)
         {
         {
-            container.Background(Colors.Grey.Lighten3).Border(1).Stack(stack =>
+            container.Background(Colors.Grey.Lighten3).Border(1).Column(column =>
             {
             {
-                stack.Item().ShowOnce().Padding(5).AlignMiddle().Row(row =>
+                column.Item().ShowOnce().Padding(5).AlignMiddle().Row(row =>
                 {
                 {
-                    row.RelativeColumn(2).AlignMiddle().Text("PRIMARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
-                    row.RelativeColumn(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30);
+                    row.RelativeItem(2).AlignMiddle().Text("PRIMARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
+                    row.RelativeItem(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30);
                 });
                 });
-                stack.Item().SkipOnce().Padding(5).Row(row =>
+                column.Item().SkipOnce().Padding(5).Row(row =>
                 {
                 {
-                    row.RelativeColumn(2).Text("SECONDARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
-                    row.RelativeColumn(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15);
+                    row.RelativeItem(2).Text("SECONDARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold());
+                    row.RelativeItem(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15);
                 });
                 });
             });
             });
         }
         }
 
 
         private void ComposeContent(IContainer container)
         private void ComposeContent(IContainer container)
         {
         {
-            container.Stack(stack =>
+            container.Column(column =>
             {
             {
-                stack.Item().PaddingVertical(80).Text("First");
-                stack.Item().PageBreak();
-                stack.Item().PaddingVertical(80).Text("Second");
-                stack.Item().PageBreak();
-                stack.Item().PaddingVertical(80).Text("Third");
-                stack.Item().PageBreak();
+                column.Item().PaddingVertical(80).Text("First");
+                column.Item().PageBreak();
+                column.Item().PaddingVertical(80).Text("Second");
+                column.Item().PageBreak();
+                column.Item().PaddingVertical(80).Text("Third");
+                column.Item().PageBreak();
             });
             });
         }
         }
 
 
         private void ComposeFooter(IContainer container)
         private void ComposeFooter(IContainer container)
         {
         {
-            container.Background(Colors.Grey.Lighten3).Stack(stack =>
+            container.Background(Colors.Grey.Lighten3).Column(column =>
             {
             {
-                stack.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>
+                column.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>
                 {
                 {
-                    row.RelativeColumn().Text(x =>
+                    row.RelativeItem().Text(x =>
                     {
                     {
                         x.CurrentPageNumber();
                         x.CurrentPageNumber();
                         x.Span(" / ");
                         x.Span(" / ");
                         x.TotalPages();
                         x.TotalPages();
                     });
                     });
-                    row.RelativeColumn().AlignRight().Text("Footer for header");
+                    row.RelativeItem().AlignRight().Text("Footer for header");
                 });
                 });
 
 
-                stack.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>
+                column.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>
                 {
                 {
-                    row.RelativeColumn().Text(x =>
+                    row.RelativeItem().Text(x =>
                     {
                     {
                         x.CurrentPageNumber();
                         x.CurrentPageNumber();
                         x.Span(" / ");
                         x.Span(" / ");
                         x.TotalPages();
                         x.TotalPages();
                     });
                     });
-                    row.RelativeColumn().AlignRight().Text("Footer for every page except header");
+                    row.RelativeItem().AlignRight().Text("Footer for every page except header");
                 });
                 });
             });
             });
         }
         }

+ 9 - 9
QuestPDF.ReportSample/Layouts/PhotoTemplate.cs

@@ -17,11 +17,11 @@ namespace QuestPDF.ReportSample.Layouts
         {
         {
             container
             container
                 .ShowEntire()
                 .ShowEntire()
-                .Stack(stack =>
+                .Column(column =>
                 {
                 {
-                    stack.Spacing(5);
-                    stack.Item().Element(PhotoWithMaps);
-                    stack.Item().Element(PhotoDetails);
+                    column.Spacing(5);
+                    column.Item().Element(PhotoWithMaps);
+                    column.Item().Element(PhotoDetails);
                 });
                 });
         }
         }
         
         
@@ -30,14 +30,14 @@ namespace QuestPDF.ReportSample.Layouts
             container
             container
                 .Row(row =>
                 .Row(row =>
                 {
                 {
-                    row.RelativeColumn(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
+                    row.RelativeItem(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
 
 
-                    row.RelativeColumn().PaddingLeft(5).Stack(stack =>
+                    row.RelativeItem().PaddingLeft(5).Column(column =>
                     {
                     {
-                        stack.Spacing(7f);
+                        column.Spacing(7f);
                         
                         
-                        stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
-                        stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
+                        column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
+                        column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
                     });
                     });
                 });
                 });
         }
         }

+ 11 - 11
QuestPDF.ReportSample/Layouts/SectionTemplate.cs

@@ -21,25 +21,25 @@ namespace QuestPDF.ReportSample.Layouts
                 .Decoration(decoration =>
                 .Decoration(decoration =>
                 {
                 {
                     decoration
                     decoration
-                        .Header()
+                        .Before()
                         .PaddingBottom(5)
                         .PaddingBottom(5)
                         .Text(Model.Title, Typography.Headline);
                         .Text(Model.Title, Typography.Headline);
 
 
-                    decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack =>
+                    decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Column(column =>
                     {
                     {
                         foreach (var part in Model.Parts)
                         foreach (var part in Model.Parts)
                         {
                         {
-                            stack.Item().EnsureSpace(25).Row(row =>
+                            column.Item().EnsureSpace(25).Row(row =>
                             {
                             {
-                                row.ConstantColumn(150).LabelCell().Text(part.Label);
-                                var frame = row.RelativeColumn().ValueCell();
+                                row.ConstantItem(150).LabelCell().Text(part.Label);
+                                var frame = row.RelativeItem().ValueCell();
                             
                             
                                 if (part is ReportSectionText text)
                                 if (part is ReportSectionText text)
                                     frame.ShowEntire().Text(text.Text);
                                     frame.ShowEntire().Text(text.Text);
-                        
+                                
                                 if (part is ReportSectionMap map)
                                 if (part is ReportSectionMap map)
                                     frame.Element(x => MapElement(x, map));
                                     frame.Element(x => MapElement(x, map));
-                        
+                                
                                 if (part is ReportSectionPhotos photos)
                                 if (part is ReportSectionPhotos photos)
                                     frame.Element(x => PhotosElement(x, photos));
                                     frame.Element(x => PhotosElement(x, photos));
                             });
                             });
@@ -56,12 +56,12 @@ namespace QuestPDF.ReportSample.Layouts
                 return;
                 return;
             }
             }
 
 
-            container.ShowEntire().Stack(stack =>
+            container.ShowEntire().Column(column =>
             {
             {
-                stack.Spacing(5);
+                column.Spacing(5);
                 
                 
-                stack.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
-                stack.Item().Text(model.Location.Format());
+                column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
+                column.Item().Text(model.Location.Format());
             });
             });
         }
         }
         
         

+ 16 - 16
QuestPDF.ReportSample/Layouts/StandardReport.cs

@@ -48,19 +48,19 @@ namespace QuestPDF.ReportSample.Layouts
 
 
         private void ComposeHeader(IContainer container)
         private void ComposeHeader(IContainer container)
         {
         {
-            container.Stack(stack =>
+            container.Column(column =>
             {
             {
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
                     row.Spacing(50);
                     row.Spacing(50);
                     
                     
-                    row.RelativeColumn().PaddingTop(-10).Text(Model.Title, Typography.Title);
-                    row.ConstantColumn(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
+                    row.RelativeItem().PaddingTop(-10).Text(Model.Title, Typography.Title);
+                    row.ConstantItem(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
                 });
                 });
 
 
-                stack.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
+                column.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();
                 
                 
-                stack.Item().ShowOnce().Grid(grid =>
+                column.Item().ShowOnce().Grid(grid =>
                 {
                 {
                     grid.Columns(2);
                     grid.Columns(2);
                     grid.Spacing(5);
                     grid.Spacing(5);
@@ -79,22 +79,22 @@ namespace QuestPDF.ReportSample.Layouts
 
 
         void ComposeContent(IContainer container)
         void ComposeContent(IContainer container)
         {
         {
-            container.PaddingVertical(20).Stack(stack =>
+            container.PaddingVertical(20).Column(column =>
             {
             {
-                stack.Spacing(20);
-
-                stack.Item().Component(new TableOfContentsTemplate(Model.Sections));
+                column.Spacing(20);
+                
+                column.Item().Component(new TableOfContentsTemplate(Model.Sections));
                 
                 
-                stack.Item().PageBreak();
+                column.Item().PageBreak();
                 
                 
                 foreach (var section in Model.Sections)
                 foreach (var section in Model.Sections)
-                    stack.Item().Location(section.Title).Component(new SectionTemplate(section));
-
-                stack.Item().PageBreak();
-                stack.Item().Location("Photos");
+                    column.Item().Location(section.Title).Component(new SectionTemplate(section));
+                
+                column.Item().PageBreak();
+                column.Item().Location("Photos");
                 
                 
                 foreach (var photo in Model.Photos)
                 foreach (var photo in Model.Photos)
-                    stack.Item().Component(new PhotoTemplate(photo));
+                    column.Item().Component(new PhotoTemplate(photo));
             });
             });
         }
         }
     }
     }

+ 8 - 8
QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs

@@ -19,18 +19,18 @@ namespace QuestPDF.ReportSample.Layouts
                 .Decoration(decoration =>
                 .Decoration(decoration =>
                 {
                 {
                     decoration
                     decoration
-                        .Header()
+                        .Before()
                         .PaddingBottom(5)
                         .PaddingBottom(5)
                         .Text("Table of contents", Typography.Headline);
                         .Text("Table of contents", Typography.Headline);
 
 
-                    decoration.Content().Stack(stack =>
+                    decoration.Content().Column(column =>
                     {
                     {
-                        stack.Spacing(5);
+                        column.Spacing(5);
                         
                         
                         for (var i = 0; i < Sections.Count; i++)
                         for (var i = 0; i < Sections.Count; i++)
-                            stack.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
+                            column.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
 
 
-                        stack.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
+                        column.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
                     });
                     });
                 });
                 });
         }
         }
@@ -41,9 +41,9 @@ namespace QuestPDF.ReportSample.Layouts
                 .InternalLink(locationName)
                 .InternalLink(locationName)
                 .Row(row =>
                 .Row(row =>
                 {
                 {
-                    row.ConstantColumn(25).Text($"{number}.");
-                    row.RelativeColumn().Text(locationName);
-                    row.ConstantColumn(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName));
+                    row.ConstantItem(25).Text($"{number}.");
+                    row.RelativeItem().Text(locationName);
+                    row.ConstantItem(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName));
                 });
                 });
         }
         }
     }
     }

+ 1 - 1
QuestPDF.ReportSample/Tests.cs

@@ -24,7 +24,7 @@ namespace QuestPDF.ReportSample
         [Test] 
         [Test] 
         public void GenerateAndShowPdf()
         public void GenerateAndShowPdf()
         {
         {
-            ImagePlaceholder.Solid = true;
+            //ImagePlaceholder.Solid = true;
         
         
             var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
             var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
             Report.GeneratePdf(path);
             Report.GeneratePdf(path);

+ 54 - 165
QuestPDF.UnitTests/StackTests.cs → QuestPDF.UnitTests/ColumnTests.cs

@@ -1,4 +1,5 @@
-using NUnit.Framework;
+using System.Linq;
+using NUnit.Framework;
 using QuestPDF.Drawing;
 using QuestPDF.Drawing;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Fluent;
 using QuestPDF.Fluent;
@@ -8,19 +9,40 @@ using QuestPDF.UnitTests.TestEngine;
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {
     [TestFixture]
     [TestFixture]
-    public class StackTests
+    public class ColumnTests
     {
     {
+        private Column CreateColumnWithTwoItems(TestPlan testPlan)
+        {
+            return new Column
+            {
+                Items =
+                {
+                    new ColumnItem
+                    {
+                        Child = testPlan.CreateChild("first")
+                    },
+                    new ColumnItem
+                    {
+                        Child = testPlan.CreateChild("second")
+                    }
+                }
+            };
+        }
+        
+        private Column CreateColumnWithTwoItemsWhereFirstIsFullyRendered(TestPlan testPlan)
+        {
+            var column = CreateColumnWithTwoItems(testPlan);
+            column.Items.First().IsRendered = true;
+            return column;
+        }
+        
         #region Measure
         #region Measure
 
 
         [Test]
         [Test]
         public void Measure_ReturnsWrap_WhenFirstChildWraps()
         public void Measure_ReturnsWrap_WhenFirstChildWraps()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
                 .CheckMeasureResult(SpacePlan.Wrap());
                 .CheckMeasureResult(SpacePlan.Wrap());
@@ -30,11 +52,7 @@ namespace QuestPDF.UnitTests
         public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()
         public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(300, 200))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(300, 200))
                 .CheckMeasureResult(SpacePlan.PartialRender(300, 200));
                 .CheckMeasureResult(SpacePlan.PartialRender(300, 200));
@@ -44,11 +62,7 @@ namespace QuestPDF.UnitTests
         public void Measure_ReturnsPartialRender_WhenSecondChildWraps()
         public void Measure_ReturnsPartialRender_WhenSecondChildWraps()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
@@ -59,11 +73,7 @@ namespace QuestPDF.UnitTests
         public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()
         public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(300, 150))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(300, 150))
@@ -74,33 +84,13 @@ namespace QuestPDF.UnitTests
         public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()
         public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(100, 50))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(100, 50))
                 .CheckMeasureResult(SpacePlan.FullRender(200, 150));
                 .CheckMeasureResult(SpacePlan.FullRender(200, 150));
         }
         }
-        
-        [Test]
-        public void Measure_UsesEmpty_WhenFirstChildIsRendered()
-        {
-            TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second"),
-                    
-                    IsFirstRendered = true
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300))
-                .CheckMeasureResult(SpacePlan.FullRender(200, 300));
-        }
-        
+
         #endregion
         #endregion
         
         
         #region Draw
         #region Draw
@@ -109,11 +99,7 @@ namespace QuestPDF.UnitTests
         public void Draw_WhenFirstChildWraps()
         public void Draw_WhenFirstChildWraps()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap())
                 .CheckDrawResult();
                 .CheckDrawResult();
@@ -123,14 +109,12 @@ namespace QuestPDF.UnitTests
         public void Draw_WhenFirstChildPartiallyRenders()
         public void Draw_WhenFirstChildPartiallyRenders()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(200, 100))
+                .ExpectCanvasTranslate(0, 0)
                 .ExpectChildDraw("first", new Size(400, 100))
                 .ExpectChildDraw("first", new Size(400, 100))
+                .ExpectCanvasTranslate(0, 0)
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
         
         
@@ -138,15 +122,13 @@ namespace QuestPDF.UnitTests
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
-                .ExpectChildDraw("first", new Size(400, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap())
+                .ExpectCanvasTranslate(0, 0)
+                .ExpectChildDraw("first", new Size(400, 100))
+                .ExpectCanvasTranslate(0, 0)
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
         
         
@@ -154,15 +136,13 @@ namespace QuestPDF.UnitTests
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
-                .ExpectChildDraw("first", new Size(400, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(250, 150))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(250, 150))
+                .ExpectCanvasTranslate(0, 0)
+                .ExpectChildDraw("first", new Size(400, 100))
+                .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 100)
                 .ExpectCanvasTranslate(0, 100)
                 .ExpectChildDraw("second", new Size(400, 150))
                 .ExpectChildDraw("second", new Size(400, 150))
                 .ExpectCanvasTranslate(0, -100)
                 .ExpectCanvasTranslate(0, -100)
@@ -173,15 +153,13 @@ namespace QuestPDF.UnitTests
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()
         public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second")
-                })
+                .For(CreateColumnWithTwoItems)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
                 .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100))
-                .ExpectChildDraw("first", new Size(400, 100))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(250, 150))
                 .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(250, 150))
+                .ExpectCanvasTranslate(0, 0)
+                .ExpectChildDraw("first", new Size(400, 100))
+                .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 100)
                 .ExpectCanvasTranslate(0, 100)
                 .ExpectChildDraw("second", new Size(400, 150))
                 .ExpectChildDraw("second", new Size(400, 150))
                 .ExpectCanvasTranslate(0, -100)
                 .ExpectCanvasTranslate(0, -100)
@@ -192,19 +170,13 @@ namespace QuestPDF.UnitTests
         public void Draw_UsesEmpty_WhenFirstChildIsRendered()
         public void Draw_UsesEmpty_WhenFirstChildIsRendered()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second"),
-                    
-                    IsFirstRendered = true
-                })
+                .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.PartialRender(200, 300))
                 .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.PartialRender(200, 300))
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectChildDraw("second", new Size(400, 300))
                 .ExpectChildDraw("second", new Size(400, 300))
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 0)
-                .CheckState<BinaryStack>(x => x.IsFirstRendered)
+                .CheckState<Column>(x => x.Items.First().IsRendered)
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
         
         
@@ -212,97 +184,14 @@ namespace QuestPDF.UnitTests
         public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
         public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryStack
-                {
-                    First = x.CreateChild("first"),
-                    Second = x.CreateChild("second"),
-                    
-                    IsFirstRendered = true
-                })
+                .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300))
                 .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300))
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectChildDraw("second", new Size(400, 300))
                 .ExpectChildDraw("second", new Size(400, 300))
                 .ExpectCanvasTranslate(0, 0)
                 .ExpectCanvasTranslate(0, 0)
                 .CheckDrawResult()
                 .CheckDrawResult()
-                .CheckState<BinaryStack>(x => !x.IsFirstRendered);
-        }
-        
-        #endregion
-        
-        #region Structure
-        
-        [Test]
-        public void Structure_Simple()
-        { 
-            // arrange
-            var childA = TestPlan.CreateUniqueElement();
-            var childB = TestPlan.CreateUniqueElement();
-            var childC = TestPlan.CreateUniqueElement();
-            var childD = TestPlan.CreateUniqueElement();
-            var childE = TestPlan.CreateUniqueElement();
-
-            const int spacing = 20;
-            
-            // act
-            var structure = new Container();
-            
-            structure.Stack(stack =>
-            {
-                stack.Spacing(spacing);
-                
-                stack.Item().Element(childA);
-                stack.Item().Element(childB);
-                stack.Item().Element(childC);
-                stack.Item().Element(childD);
-                stack.Item().Element(childE);
-            });
-            
-            // assert
-            var expected = new Padding
-            {
-                Bottom = -spacing,
-
-                Child = new BinaryStack
-                {
-                    First = new BinaryStack
-                    {
-                        First = new Padding
-                        {
-                            Bottom = spacing,
-                            Child = childA
-                        },
-                        Second = new Padding
-                        {
-                            Bottom = spacing,
-                            Child = childB
-                        }
-                    },
-                    Second = new BinaryStack
-                    {
-                        First = new Padding
-                        {
-                            Bottom = spacing,
-                            Child = childC
-                        },
-                        Second = new BinaryStack
-                        {
-                            First = new Padding
-                            {
-                                Bottom = spacing,
-                                Child = childD
-                            },
-                            Second = new Padding
-                            {
-                                Bottom = spacing,
-                                Child = childE
-                            }
-                        }
-                    }
-                }
-            };
-
-            TestPlan.CompareOperations(structure, expected);
+                .CheckState<Column>(x => !x.Items.First().IsRendered);
         }
         }
         
         
         #endregion
         #endregion

+ 76 - 73
QuestPDF.UnitTests/DecorationTests.cs

@@ -9,125 +9,128 @@ namespace QuestPDF.UnitTests
     [TestFixture]
     [TestFixture]
     public class DecorationTests
     public class DecorationTests
     {
     {
+        private Decoration CreateDecoration(TestPlan testPlan)
+        {
+            return new Decoration
+            {
+                Before = testPlan.CreateChild("before"),
+                Content = testPlan.CreateChild("content"),
+                After = testPlan.CreateChild("after"),
+            };
+        }
+        
         #region Measure
         #region Measure
 
 
         [Test]
         [Test]
-        public void Measure_ReturnsWrap_WhenDecorationReturnsWrap()
+        public void Measure_ReturnsWrap_WhenBeforeReturnsWrap()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.Wrap())
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.Wrap())
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
                 .CheckMeasureResult(SpacePlan.Wrap());
                 .CheckMeasureResult(SpacePlan.Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_ReturnsWrap_WhenDecorationReturnsPartialRender()
+        public void Measure_ReturnsWrap_WhenContentReturnsWrap()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.PartialRender(300, 200))
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.Wrap())
                 .CheckMeasureResult(SpacePlan.Wrap());
                 .CheckMeasureResult(SpacePlan.Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_ReturnsWrap_WhenContentReturnsWrap()
+        public void Measure_ReturnsWrap_WhenAfterReturnsWrap()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
-                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.Wrap())
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.Wrap())
+                .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
                 .CheckMeasureResult(SpacePlan.Wrap());
                 .CheckMeasureResult(SpacePlan.Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_ReturnsPartialRender_WhenContentReturnsPartialRender()
+        public void Measure_ReturnsWrap_WhenBeforeReturnsPartialRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
-                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(200, 150))
-                .CheckMeasureResult(SpacePlan.PartialRender(400, 250));
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.PartialRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
+                .CheckMeasureResult(SpacePlan.Wrap());
         }
         }
         
         
         [Test]
         [Test]
-        public void Measure_ReturnsFullRender_WhenContentReturnsFullRender()
+        public void Measure_ReturnsWrap_WhenAfterReturnsPartialRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .MeasureElement(new Size(400, 300))
                 .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
-                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(200, 150))
-                .CheckMeasureResult(SpacePlan.FullRender(400, 250));
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.PartialRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100))
+                .CheckMeasureResult(SpacePlan.Wrap());
         }
         }
         
         
-        #endregion
-        
-        #region Draw
+        [Test]
+        public void Measure_ReturnsWrap_WhenContentReturnsPartialRender()
+        {
+            TestPlan
+                .For(CreateDecoration)
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(150, 100))
+                .CheckMeasureResult(SpacePlan.PartialRender(150, 200));
+        }
         
         
         [Test]
         [Test]
-        public void Draw_Prepend()
+        public void Measure_ReturnsWrap_WhenContentReturnsFullRender()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Prepend,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
-                .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
-                .ExpectChildDraw("decoration", new Size(400, 100))
-                .ExpectCanvasTranslate(0, 100)
-                .ExpectChildDraw("content", new Size(400, 200))
-                .ExpectCanvasTranslate(0, -100)
-                .CheckDrawResult();
+                .For(CreateDecoration)
+                .MeasureElement(new Size(400, 300))
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50))
+                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(150, 100))
+                .CheckMeasureResult(SpacePlan.FullRender(150, 200));
         }
         }
+
+        #endregion
+        
+        #region Draw
         
         
         [Test]
         [Test]
         public void Draw_Append()
         public void Draw_Append()
         {
         {
             TestPlan
             TestPlan
-                .For(x => new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    DecorationElement = x.CreateChild("decoration"),
-                    ContentElement = x.CreateChild("content")
-                })
+                .For(CreateDecoration)
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100))
-                .ExpectChildDraw("content", new Size(400, 200))
-                .ExpectCanvasTranslate(0, 200)
-                .ExpectChildDraw("decoration", new Size(400, 100))
-                .ExpectCanvasTranslate(0, -200)
+                .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(200, 40))
+                .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(200, 60))
+                .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(300, 100))
+                
+                .ExpectCanvasTranslate(0, 0)
+                .ExpectChildDraw("before", new Size(300, 40))
+                .ExpectCanvasTranslate(0, 0)
+                
+                .ExpectCanvasTranslate(0, 40)
+                .ExpectChildDraw("content", new Size(300, 100))
+                .ExpectCanvasTranslate(0, -40)
+                
+                .ExpectCanvasTranslate(0, 140)
+                .ExpectChildDraw("after", new Size(300, 60))
+                .ExpectCanvasTranslate(0, -140)
+
                 .CheckDrawResult();
                 .CheckDrawResult();
         }
         }
 
 

+ 54 - 54
QuestPDF.UnitTests/GridTests.cs

@@ -39,26 +39,26 @@ namespace QuestPDF.UnitTests
             // assert
             // assert
             var expected = new Container();
             var expected = new Container();
             
             
-            expected.Stack(stack =>
+            expected.Column(column =>
             {
             {
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(6).Element(childA);
-                    row.RelativeColumn(4).Element(childB);
-                    row.RelativeColumn(2);
+                    row.RelativeItem(6).Element(childA);
+                    row.RelativeItem(4).Element(childB);
+                    row.RelativeItem(2);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(4).Element(childC);
-                    row.RelativeColumn(2).Element(childD);
-                    row.RelativeColumn(6);
+                    row.RelativeItem(4).Element(childC);
+                    row.RelativeItem(2).Element(childD);
+                    row.RelativeItem(6);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(8).Element(childE);
-                    row.RelativeColumn(4);
+                    row.RelativeItem(8).Element(childE);
+                    row.RelativeItem(4);
                 });
                 });
             });
             });
             
             
@@ -93,29 +93,29 @@ namespace QuestPDF.UnitTests
             // assert
             // assert
             var expected = new Container();
             var expected = new Container();
             
             
-            expected.Stack(stack =>
+            expected.Column(column =>
             {
             {
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(1);
-                    row.RelativeColumn(6).Element(childA);
-                    row.RelativeColumn(4).Element(childB);
-                    row.RelativeColumn(1);
+                    row.RelativeItem(1);
+                    row.RelativeItem(6).Element(childA);
+                    row.RelativeItem(4).Element(childB);
+                    row.RelativeItem(1);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(3);
-                    row.RelativeColumn(4).Element(childC);
-                    row.RelativeColumn(2).Element(childD);
-                    row.RelativeColumn(3);
+                    row.RelativeItem(3);
+                    row.RelativeItem(4).Element(childC);
+                    row.RelativeItem(2).Element(childD);
+                    row.RelativeItem(3);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(2);
-                    row.RelativeColumn(8).Element(childE);
-                    row.RelativeColumn(2);
+                    row.RelativeItem(2);
+                    row.RelativeItem(8).Element(childE);
+                    row.RelativeItem(2);
                 });
                 });
             });
             });
 
 
@@ -150,26 +150,26 @@ namespace QuestPDF.UnitTests
             // assert
             // assert
             var expected = new Container();
             var expected = new Container();
             
             
-            expected.Stack(stack =>
+            expected.Column(column =>
             {
             {
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(2);
-                    row.RelativeColumn(6).Element(childA);
-                    row.RelativeColumn(4).Element(childB);
+                    row.RelativeItem(2);
+                    row.RelativeItem(6).Element(childA);
+                    row.RelativeItem(4).Element(childB);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(6);
-                    row.RelativeColumn(4).Element(childC);
-                    row.RelativeColumn(2).Element(childD);
+                    row.RelativeItem(6);
+                    row.RelativeItem(4).Element(childC);
+                    row.RelativeItem(2).Element(childD);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
-                    row.RelativeColumn(4);
-                    row.RelativeColumn(8).Element(childE);
+                    row.RelativeItem(4);
+                    row.RelativeItem(8).Element(childE);
                 });
                 });
             });
             });
             
             
@@ -210,36 +210,36 @@ namespace QuestPDF.UnitTests
             // assert
             // assert
             var expected = new Container();
             var expected = new Container();
             
             
-            expected.Stack(stack =>
+            expected.Column(column =>
             {
             {
-                stack.Spacing(20);
+                column.Spacing(20);
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
                     row.Spacing(30);
                     row.Spacing(30);
                     
                     
-                    row.RelativeColumn(3);
-                    row.RelativeColumn(5).Element(childA);
-                    row.RelativeColumn(5).Element(childB);
-                    row.RelativeColumn(3);
+                    row.RelativeItem(3);
+                    row.RelativeItem(5).Element(childA);
+                    row.RelativeItem(5).Element(childB);
+                    row.RelativeItem(3);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
                     row.Spacing(30);
                     row.Spacing(30);
                     
                     
-                    row.RelativeColumn(3);
-                    row.RelativeColumn(10).Element(childC);
-                    row.RelativeColumn(3);
+                    row.RelativeItem(3);
+                    row.RelativeItem(10).Element(childC);
+                    row.RelativeItem(3);
                 });
                 });
                 
                 
-                stack.Item().Row(row =>
+                column.Item().Row(row =>
                 {
                 {
                     row.Spacing(30);
                     row.Spacing(30);
                     
                     
-                    row.RelativeColumn(2);
-                    row.RelativeColumn(12).Element(childD);
-                    row.RelativeColumn(2);
+                    row.RelativeItem(2);
+                    row.RelativeItem(12).Element(childD);
+                    row.RelativeItem(2);
                 });
                 });
             });
             });
             
             

+ 0 - 268
QuestPDF.UnitTests/RowTests.cs

@@ -1,268 +0,0 @@
-using NUnit.Framework;
-using QuestPDF.Drawing;
-using QuestPDF.Elements;
-using QuestPDF.Fluent;
-using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.TestEngine;
-
-namespace QuestPDF.UnitTests
-{
-    [TestFixture]
-    public class RowTests
-    {
-        #region Measure
-        
-        [Test]
-        public void Measure_ReturnsWrap_WhenLeftChildReturnsWrap()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.Wrap())
-                .CheckMeasureResult(SpacePlan.Wrap());
-        }
-        
-        [Test]
-        public void Measure_ReturnsWrap_WhenRightChildReturnsWrap()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
-                .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.Wrap())
-                .CheckMeasureResult(SpacePlan.Wrap());
-        }
-        
-        [Test]
-        public void Measure_ReturnsPartialRender_WhenLeftChildReturnsPartialRender()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.PartialRender(250, 150))
-                .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(100, 100))
-                .CheckMeasureResult(SpacePlan.PartialRender(350, 150));
-        }
-        
-        [Test]
-        public void Measure_ReturnsPartialRender_WhenRightChildReturnsPartialRender()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
-                .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.PartialRender(100, 100))
-                .CheckMeasureResult(SpacePlan.PartialRender(350, 150));
-        }
-        
-        [Test]
-        public void Measure_ReturnsFullRender_WhenBothChildrenReturnFullRender()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .MeasureElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(200, 150))
-                .ExpectChildMeasure("right", new Size(200, 300), SpacePlan.FullRender(100, 100))
-                .CheckMeasureResult(SpacePlan.FullRender(300, 150));
-        }
-        
-        #endregion
-
-        #region Draw
-
-        [Test]
-        public void Draw()
-        {
-            TestPlan
-                .For(x => new BinaryRow
-                {
-                    Left = x.CreateChild("left"),
-                    Right = x.CreateChild("right")
-                })
-                .DrawElement(new Size(400, 300))
-                .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
-                .ExpectChildDraw("left", new Size(250, 300))
-                .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(150, 200))
-                .ExpectCanvasTranslate(250, 0)
-                .ExpectChildDraw("right", new Size(150, 300))
-                .ExpectCanvasTranslate(-250, 0)
-                .CheckDrawResult();
-        }
-
-        #endregion
-        
-        #region Structure
-        
-        [Test]
-        public void Structure_RelativeColumnsHandling()
-        { 
-            // arrange
-            var childA = TestPlan.CreateUniqueElement();
-            var childB = TestPlan.CreateUniqueElement();
-            var childC = TestPlan.CreateUniqueElement();
-            var childD = TestPlan.CreateUniqueElement();
-            var childE = TestPlan.CreateUniqueElement();
-
-            const int spacing = 25;
-            var availableSpace = new Size(1100, 400);
-            
-            // act
-            var value = new Container();
-
-            value.Row(row =>
-            {
-                row.Spacing(spacing);
-                
-                row.ConstantColumn(150).Element(childA);
-                row.ConstantColumn(250).Element(childB);
-                row.RelativeColumn(1).Element(childC);
-                row.RelativeColumn(2).Element(childD);
-                row.RelativeColumn(3).Element(childE);
-            });
-            
-            // assert
-            var expected = new Container();
-
-            expected.Row(row =>
-            {
-                row.Spacing(spacing);
-                
-                row.ConstantColumn(150).Element(childA);
-                row.ConstantColumn(250).Element(childB);
-                row.ConstantColumn(100).Element(childC);
-                row.ConstantColumn(200).Element(childD);
-                row.ConstantColumn(300).Element(childE);
-            });
-            
-            TestPlan.CompareOperations(value, expected, availableSpace);
-        }
-        
-        [Test]
-        public void Structure_Tree()
-        { 
-            // arrange
-            var childA = TestPlan.CreateUniqueElement();
-            var childB = TestPlan.CreateUniqueElement();
-            var childC = TestPlan.CreateUniqueElement();
-            var childD = TestPlan.CreateUniqueElement();
-            var childE = TestPlan.CreateUniqueElement();
-
-            const int spacing = 25;
-            var availableSpace = new Size(1200, 400);
-            
-            // act
-            var value = new Container();
-
-            value.Row(row =>
-            {
-                row.Spacing(spacing);
-                
-                row.ConstantColumn(150).Element(childA);
-                row.ConstantColumn(200).Element(childB);
-                row.ConstantColumn(250).Element(childC);
-                row.RelativeColumn(2).Element(childD);
-                row.RelativeColumn(3).Element(childE);
-            });
-            
-            // assert
-            var expected = new BinaryRow
-            {
-                Left = new BinaryRow
-                {
-                    Left = new BinaryRow
-                    {
-                        Left = new Constrained
-                        {
-                            MinWidth = 150,
-                            MaxWidth = 150,
-                            Child = childA
-                        },
-                        Right = new Constrained
-                        {
-                            MinWidth = 25,
-                            MaxWidth = 25
-                        }
-                    },
-                    Right = new BinaryRow
-                    {
-                        Left = new Constrained
-                        {
-                            MinWidth = 200,
-                            MaxWidth = 200,
-                            Child = childB
-                        },
-                        Right = new Constrained
-                        {
-                            MinWidth = 25,
-                            MaxWidth = 25
-                        }
-                    }
-                },
-                Right = new BinaryRow
-                {
-                    Left = new BinaryRow
-                    {
-                        Left = new Constrained
-                        {
-                            MinWidth = 250,
-                            MaxWidth = 250,
-                            Child = childC
-                        },
-                        Right = new Constrained
-                        {
-                            MinWidth = 25,
-                            MaxWidth = 25
-                        }
-                    },
-                    Right = new BinaryRow
-                    {
-                        Left = new Constrained
-                        {
-                            MinWidth = 200,
-                            MaxWidth = 200,
-                            Child = childD
-                        },
-                        Right = new BinaryRow
-                        {
-                            Left = new Constrained
-                            {
-                                MinWidth = 25,
-                                MaxWidth = 25
-                            },
-                            Right = new Constrained
-                            {
-                                MinWidth = 300,
-                                MaxWidth = 300,
-                                Child = childE
-                            }
-                        }
-                    }
-                }
-            };
-            
-            TestPlan.CompareOperations(value, expected, availableSpace);
-        }
-        
-        #endregion
-    }
-}

+ 3 - 3
QuestPDF/Drawing/DocumentContainer.cs

@@ -16,13 +16,13 @@ namespace QuestPDF.Drawing
             var container = new Container();
             var container = new Container();
             
             
             container
             container
-                .Stack(stack =>
+                .Column(column =>
                 {
                 {
                     Pages
                     Pages
                         .SelectMany(x => new List<Action>()
                         .SelectMany(x => new List<Action>()
                         {
                         {
-                            () => stack.Item().PageBreak(),
-                            () => stack.Item().Component(x)
+                            () => column.Item().PageBreak(),
+                            () => column.Item().Component(x)
                         })
                         })
                         .Skip(1)
                         .Skip(1)
                         .ToList()
                         .ToList()

+ 4 - 2
QuestPDF/Drawing/DocumentGenerator.cs

@@ -18,14 +18,16 @@ namespace QuestPDF.Drawing
         internal static void GeneratePdf(Stream stream, IDocument document)
         internal static void GeneratePdf(Stream stream, IDocument document)
         {
         {
             var metadata = document.GetMetadata();
             var metadata = document.GetMetadata();
-            var canvas = new PdfCanvas(stream, metadata);
+            var writeOnlyStream = new WriteOnlyStream(stream);
+            var canvas = new PdfCanvas(writeOnlyStream, metadata);
             RenderDocument(canvas, document);
             RenderDocument(canvas, document);
         }
         }
         
         
         internal static void GenerateXps(Stream stream, IDocument document)
         internal static void GenerateXps(Stream stream, IDocument document)
         {
         {
             var metadata = document.GetMetadata();
             var metadata = document.GetMetadata();
-            var canvas = new XpsCanvas(stream, metadata);
+            var writeOnlyStream = new WriteOnlyStream(stream);
+            var canvas = new XpsCanvas(writeOnlyStream, metadata);
             RenderDocument(canvas, document);
             RenderDocument(canvas, document);
         }
         }
         
         

+ 1 - 1
QuestPDF/Drawing/PdfCanvas.cs

@@ -1,5 +1,5 @@
 using System.IO;
 using System.IO;
-using QuestPDF.Infrastructure;
+using QuestPDF.Helpers;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace QuestPDF.Drawing
 namespace QuestPDF.Drawing

+ 1 - 1
QuestPDF/Drawing/XpsCanvas.cs

@@ -1,5 +1,5 @@
 using System.IO;
 using System.IO;
-using QuestPDF.Infrastructure;
+using QuestPDF.Helpers;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace QuestPDF.Drawing
 namespace QuestPDF.Drawing

+ 120 - 0
QuestPDF/Elements/Column.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using QuestPDF.Drawing;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class ColumnItem : Container
+    {
+        public bool IsRendered { get; set; }
+    }
+    
+    internal class ColumnItemRenderingCommand
+    {
+        public ColumnItem ColumnItem { get; set; }
+        public SpacePlan Measurement { get; set; }
+        public Size Size { get; set; }
+        public Position Offset { get; set; }
+    }
+    
+    internal class Column : Element, ICacheable, IStateResettable
+    {
+        internal List<ColumnItem> Items { get; } = new();
+        internal float Spacing { get; set; }
+
+        public void ResetState()
+        {
+            Items.ForEach(x => x.IsRendered = false);
+        }
+        
+        internal override IEnumerable<Element?> GetChildren()
+        {
+            return Items;
+        }
+        
+        internal override void CreateProxy(Func<Element?, Element?> create)
+        {
+            Items.ForEach(x => x.Child = create(x.Child));
+        }
+
+        internal override SpacePlan Measure(Size availableSpace)
+        {
+            var renderingCommands = PlanLayout(availableSpace);
+
+            if (!renderingCommands.Any())
+                return SpacePlan.Wrap();
+
+            var width = renderingCommands.Max(x => x.Size.Width);
+            var height = renderingCommands.Last().Offset.Y + renderingCommands.Last().Size.Height;
+            var size = new Size(width, height);
+            
+            if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon)
+                return SpacePlan.Wrap();
+            
+            var totalRenderedItems = Items.Count(x => x.IsRendered) + renderingCommands.Count(x => x.Measurement.Type == SpacePlanType.FullRender);
+            var willBeFullyRendered = totalRenderedItems == Items.Count;
+
+            return willBeFullyRendered
+                ? SpacePlan.FullRender(size)
+                : SpacePlan.PartialRender(size);
+        }
+
+        internal override void Draw(Size availableSpace)
+        {
+            var renderingCommands = PlanLayout(availableSpace);
+
+            foreach (var command in renderingCommands)
+            {
+                if (command.Measurement.Type == SpacePlanType.FullRender)
+                    command.ColumnItem.IsRendered = true;
+
+                var targetSize = new Size(availableSpace.Width, command.Size.Height);
+                
+                Canvas.Translate(command.Offset);
+                command.ColumnItem.Draw(targetSize);
+                Canvas.Translate(command.Offset.Reverse());
+            }
+            
+            if (Items.All(x => x.IsRendered))
+                ResetState();
+        }
+
+        private ICollection<ColumnItemRenderingCommand> PlanLayout(Size availableSpace)
+        {
+            var topOffset = 0f;
+            var commands = new List<ColumnItemRenderingCommand>();
+
+            foreach (var item in Items)
+            {
+                if (item.IsRendered)
+                    continue;
+
+                var itemSpace = new Size(availableSpace.Width, availableSpace.Height - topOffset);
+                var measurement = item.Measure(itemSpace);
+                
+                if (measurement.Type == SpacePlanType.Wrap)
+                    break;
+
+                commands.Add(new ColumnItemRenderingCommand
+                {
+                    ColumnItem = item,
+                    Size = measurement,
+                    Measurement = measurement,
+                    Offset = new Position(0, topOffset)
+                });
+                
+                if (measurement.Type == SpacePlanType.PartialRender)
+                    break;
+                
+                topOffset += measurement.Height + Spacing;
+            }
+
+            var targetWidth = commands.Select(x => x.Size.Width).DefaultIfEmpty(0).Max();
+            commands.ForEach(x => x.Size = new Size(targetWidth, x.Size.Height));
+            
+            return commands;
+        }
+    }
+}

+ 75 - 61
QuestPDF/Elements/Decoration.cs

@@ -1,98 +1,112 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Linq;
 using QuestPDF.Drawing;
 using QuestPDF.Drawing;
 using QuestPDF.Fluent;
 using QuestPDF.Fluent;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
 
 
 namespace QuestPDF.Elements
 namespace QuestPDF.Elements
 {
 {
-    internal enum DecorationType
+    internal class DecorationItemRenderingCommand
     {
     {
-        Prepend,
-        Append
+        public Element Element { get; set; }
+        public SpacePlan Measurement { get; set; }
+        public Position Offset { get; set; }
     }
     }
     
     
-    internal class BinaryDecoration : Element, ICacheable
+    internal class Decoration : Element, ICacheable
     {
     {
-        public Element DecorationElement { get; set; } = Empty.Instance;
-        public Element ContentElement { get; set; } = Empty.Instance;
-        public DecorationType Type { get; set; }
+        internal Element Before { get; set; } = new Empty();
+        internal Element Content { get; set; } = new Empty();
+        internal Element After { get; set; } = new Empty();
 
 
         internal override IEnumerable<Element?> GetChildren()
         internal override IEnumerable<Element?> GetChildren()
         {
         {
-            yield return DecorationElement;
-            yield return ContentElement;
+            yield return Before;
+            yield return Content;
+            yield return After;
         }
         }
-
-        internal override void CreateProxy(Func<Element, Element> create)
+        
+        internal override void CreateProxy(Func<Element?, Element?> create)
         {
         {
-            DecorationElement = create(DecorationElement);
-            ContentElement = create(ContentElement);
+            Before = create(Before);
+            Content = create(Content);
+            After = create(After);
         }
         }
 
 
         internal override SpacePlan Measure(Size availableSpace)
         internal override SpacePlan Measure(Size availableSpace)
         {
         {
-            var decorationMeasure = DecorationElement.Measure(availableSpace);
-            
-            if (decorationMeasure.Type == SpacePlanType.Wrap || decorationMeasure.Type == SpacePlanType.PartialRender)
-                return SpacePlan.Wrap();
+            var renderingCommands = PlanLayout(availableSpace).ToList();
 
 
-            var decorationSize = decorationMeasure;
-            var contentMeasure = ContentElement.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height));
-            
-            if (contentMeasure.Type == SpacePlanType.Wrap)
+            if (renderingCommands.Any(x => x.Measurement.Type == SpacePlanType.Wrap))
                 return SpacePlan.Wrap();
                 return SpacePlan.Wrap();
 
 
-            var contentSize = contentMeasure;
-            var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height);
-            
-            if (contentSize.Type == SpacePlanType.PartialRender)
-                return SpacePlan.PartialRender(resultSize);
+            var width = renderingCommands.Max(x => x.Measurement.Width);
+            var height = renderingCommands.Sum(x => x.Measurement.Height);
+            var size = new Size(width, height);
             
             
-            if (contentSize.Type == SpacePlanType.FullRender)
-                return SpacePlan.FullRender(resultSize);
+            if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon)
+                return SpacePlan.Wrap();
             
             
-            throw new NotSupportedException();
+            var willBeFullyRendered = renderingCommands.All(x => x.Measurement.Type == SpacePlanType.FullRender);
+
+            return willBeFullyRendered
+                ? SpacePlan.FullRender(size)
+                : SpacePlan.PartialRender(size);
         }
         }
 
 
         internal override void Draw(Size availableSpace)
         internal override void Draw(Size availableSpace)
         {
         {
-            var decorationSize = DecorationElement.Measure(availableSpace);
-            var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height);
-
-            var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height;
-            Action drawDecoration = () => DecorationElement?.Draw(new Size(availableSpace.Width, decorationSize.Height));
-            Action drawContent = () => ContentElement?.Draw(new Size (availableSpace.Width, contentSize.Height));
-
-            var first = Type == DecorationType.Prepend ? drawDecoration : drawContent;
-            var second = Type == DecorationType.Prepend ? drawContent : drawDecoration;
-
-            first();
-            Canvas.Translate(new Position(0, translateHeight));
-            second();
-            Canvas.Translate(new Position(0, -translateHeight));
+            var renderingCommands = PlanLayout(availableSpace).ToList();
+            var width = renderingCommands.Max(x => x.Measurement.Width);
+            
+            foreach (var command in renderingCommands)
+            {
+                var elementSize = new Size(width, command.Measurement.Height);
+                
+                Canvas.Translate(command.Offset);
+                command.Element.Draw(elementSize);
+                Canvas.Translate(command.Offset.Reverse());
+            }
         }
         }
-    }
-    
-    internal class Decoration : IComponent
-    {
-        public Element Header { get; set; } = Empty.Instance;
-        public Element Content { get; set; } = Empty.Instance;
-        public Element Footer { get; set; } = Empty.Instance;
 
 
-        public void Compose(IContainer container)
+        private IEnumerable<DecorationItemRenderingCommand> PlanLayout(Size availableSpace)
         {
         {
-            container.Element(new BinaryDecoration
+            SpacePlan GetDecorationMeasurement(Element element)
+            {
+                var measurement = element.Measure(availableSpace);
+                
+                return measurement.Type == SpacePlanType.FullRender 
+                    ? measurement 
+                    : SpacePlan.Wrap();
+            }
+            
+            var beforeMeasurement = GetDecorationMeasurement(Before);
+            var afterMeasurement = GetDecorationMeasurement(After);
+            
+            var contentSpace = new Size(availableSpace.Width, availableSpace.Height - beforeMeasurement.Height - afterMeasurement.Height);
+            var contentMeasurement = Content.Measure(contentSpace);
+
+            yield return new DecorationItemRenderingCommand
+            {
+                Element = Before,
+                Measurement = beforeMeasurement,
+                Offset = Position.Zero
+            };
+            
+            yield return new DecorationItemRenderingCommand
+            {
+                Element = Content,
+                Measurement = contentMeasurement,
+                Offset = new Position(0, beforeMeasurement.Height)
+            };
+
+            yield return new DecorationItemRenderingCommand
             {
             {
-                Type = DecorationType.Prepend,
-                DecorationElement = Header,
-                ContentElement = new BinaryDecoration
-                {
-                    Type = DecorationType.Append,
-                    ContentElement = Content,
-                    DecorationElement = Footer
-                }
-            });
+                Element = After,
+                Measurement = afterMeasurement,
+                Offset = new Position(0, beforeMeasurement.Height + contentMeasurement.Height)
+            };
         }
         }
     }
     }
 }
 }

+ 6 - 6
QuestPDF/Elements/Grid.cs

@@ -27,12 +27,12 @@ namespace QuestPDF.Elements
         {
         {
             ChildrenQueue = new Queue<GridElement>(Children);
             ChildrenQueue = new Queue<GridElement>(Children);
             
             
-            container.Stack(stack =>
+            container.Column(column =>
             {
             {
-                stack.Spacing(VerticalSpacing);
+                column.Spacing(VerticalSpacing);
                 
                 
                 while (ChildrenQueue.Any())
                 while (ChildrenQueue.Any())
-                    stack.Item().Row(BuildRow);
+                    column.Item().Row(BuildRow);
             });
             });
         }
         }
         
         
@@ -65,12 +65,12 @@ namespace QuestPDF.Elements
                 emptySpace /= 2;
                 emptySpace /= 2;
             
             
             if (hasEmptySpace && Alignment != HorizontalAlignment.Left)
             if (hasEmptySpace && Alignment != HorizontalAlignment.Left)
-                row.RelativeColumn(emptySpace);
+                row.RelativeItem(emptySpace);
                 
                 
-            elements.ForEach(x => row.RelativeColumn(x.Columns).Element(x.Child));
+            elements.ForEach(x => row.RelativeItem(x.Columns).Element(x.Child));
 
 
             if (hasEmptySpace && Alignment != HorizontalAlignment.Right)
             if (hasEmptySpace && Alignment != HorizontalAlignment.Right)
-                row.RelativeColumn(emptySpace);
+                row.RelativeItem(emptySpace);
         }
         }
     }
     }
 }
 }

+ 30 - 43
QuestPDF/Elements/Inlined.cs

@@ -8,15 +8,7 @@ namespace QuestPDF.Elements
 {
 {
     internal class InlinedElement : Container
     internal class InlinedElement : Container
     {
     {
-        public SpacePlan? MeasureCache { get; set; }
 
 
-        internal override SpacePlan Measure(Size availableSpace)
-        {
-            // TODO: once element caching proxy is introduces, this can be removed
-            
-            MeasureCache ??= Child.Measure(Size.Max);
-            return MeasureCache.Value;
-        }
     }
     }
 
 
     internal enum InlinedAlignment
     internal enum InlinedAlignment
@@ -112,8 +104,11 @@ namespace QuestPDF.Elements
                 
                 
                 foreach (var element in elements)
                 foreach (var element in elements)
                 {
                 {
-                    var size = element.Measure(Size.Max);
+                    var size = (Size)element.Measure(Size.Max);
                     var baselineOffset = BaselineOffset(size, lineSize.Height);
                     var baselineOffset = BaselineOffset(size, lineSize.Height);
+
+                    if (size.Height == 0)
+                        size = new Size(size.Width, lineSize.Height);
                     
                     
                     Canvas.Translate(new Position(0, baselineOffset));
                     Canvas.Translate(new Position(0, baselineOffset));
                     element.Draw(size);
                     element.Draw(size);
@@ -132,48 +127,39 @@ namespace QuestPDF.Elements
                     if (elements.Count == 1)
                     if (elements.Count == 1)
                         return 0;
                         return 0;
 
 
-                    if (ElementsAlignment == InlinedAlignment.Justify)
-                        return difference / (elements.Count - 1);
-                    
-                    if (ElementsAlignment == InlinedAlignment.SpaceAround)
-                        return difference / (elements.Count + 1);
-                    
-                    return HorizontalSpacing;
+                    return ElementsAlignment switch
+                    {
+                        InlinedAlignment.Justify => difference / (elements.Count - 1),
+                        InlinedAlignment.SpaceAround => difference / (elements.Count + 1),
+                        _ => HorizontalSpacing
+                    };
                 }
                 }
 
 
                 float AlignOffset()
                 float AlignOffset()
                 {
                 {
-                    if (ElementsAlignment == InlinedAlignment.Left)
-                        return 0;
-                    
-                    if (ElementsAlignment == InlinedAlignment.Justify)
-                        return 0;
-                    
-                    if (ElementsAlignment == InlinedAlignment.SpaceAround)
-                        return elementOffset;
-
                     var difference = availableSpace.Width - lineSize.Width - (elements.Count - 1) * HorizontalSpacing;
                     var difference = availableSpace.Width - lineSize.Width - (elements.Count - 1) * HorizontalSpacing;
-                    
-                    if (ElementsAlignment == InlinedAlignment.Center)
-                        return difference / 2;
-
-                    if (ElementsAlignment == InlinedAlignment.Right)
-                        return difference;
 
 
-                    return 0;
+                    return ElementsAlignment switch
+                    {
+                        InlinedAlignment.Left => 0,
+                        InlinedAlignment.Justify => 0,
+                        InlinedAlignment.SpaceAround => elementOffset,
+                        InlinedAlignment.Center => difference / 2,
+                        InlinedAlignment.Right => difference,
+                        _ => 0
+                    };
                 }
                 }
                 
                 
                 float BaselineOffset(Size elementSize, float lineHeight)
                 float BaselineOffset(Size elementSize, float lineHeight)
                 {
                 {
-                    if (BaselineAlignment == VerticalAlignment.Top)
-                        return 0;
-
                     var difference = lineHeight - elementSize.Height;
                     var difference = lineHeight - elementSize.Height;
-                    
-                    if (BaselineAlignment == VerticalAlignment.Middle)
-                        return difference / 2;
 
 
-                    return difference;
+                    return BaselineAlignment switch
+                    {
+                        VerticalAlignment.Top => 0,
+                        VerticalAlignment.Middle => difference / 2,
+                        _ => difference
+                    };
                 }
                 }
             }
             }
         }
         }
@@ -250,11 +236,12 @@ namespace QuestPDF.Elements
             float GetInitialAlignmentOffset()
             float GetInitialAlignmentOffset()
             {
             {
                 // this method makes sure that the spacing between elements is no lesser than configured
                 // this method makes sure that the spacing between elements is no lesser than configured
-                
-                if (ElementsAlignment == InlinedAlignment.SpaceAround)
-                    return HorizontalSpacing * 2;
 
 
-                return 0;
+                return ElementsAlignment switch
+                {
+                    InlinedAlignment.SpaceAround => HorizontalSpacing * 2,
+                    _ => 0
+                };
             }
             }
         }
         }
     }
     }

+ 46 - 0
QuestPDF/Elements/Line.cs

@@ -0,0 +1,46 @@
+using QuestPDF.Drawing;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    public interface ILine
+    {
+        
+    }
+    
+    internal enum LineType
+    {
+        Vertical,
+        Horizontal
+    }
+    
+    internal class Line : Element, ILine, ICacheable
+    {
+        public LineType Type { get; set; } = LineType.Vertical;
+        public string Color { get; set; } = Colors.Black;
+        public float Size { get; set; } = 1;
+        
+        internal override SpacePlan Measure(Size availableSpace)
+        {
+            return Type switch
+            {
+                LineType.Vertical when availableSpace.Width >= Size => SpacePlan.FullRender(Size, 0),
+                LineType.Horizontal when availableSpace.Height >= Size => SpacePlan.FullRender(0, Size),
+                _ => SpacePlan.Wrap()
+            };
+        }
+
+        internal override void Draw(Size availableSpace)
+        {
+            if (Type == LineType.Vertical)
+            {
+                Canvas.DrawRectangle(new Position(-Size/2, 0), new Size(Size, availableSpace.Height), Color);
+            }
+            else if (Type == LineType.Horizontal)
+            {
+                Canvas.DrawRectangle(new Position(0, -Size/2), new Size(availableSpace.Width, Size), Color);
+            }
+        }
+    }
+}

+ 2 - 2
QuestPDF/Elements/Page.cs

@@ -45,7 +45,7 @@ namespace QuestPDF.Elements
                 .Decoration(decoration =>
                 .Decoration(decoration =>
                 {
                 {
                     decoration
                     decoration
-                        .Header()
+                        .Before()
                         .DebugPointer("Page header")
                         .DebugPointer("Page header")
                         .Element(Header);
                         .Element(Header);
                     
                     
@@ -57,7 +57,7 @@ namespace QuestPDF.Elements
                         .Element(Content);
                         .Element(Content);
                     
                     
                     decoration
                     decoration
-                        .Footer()
+                        .After()
                         .DebugPointer("Page footer")
                         .DebugPointer("Page footer")
                         .Element(Footer);
                         .Element(Footer);
                 });
                 });

+ 98 - 119
QuestPDF/Elements/Row.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using QuestPDF.Drawing;
 using QuestPDF.Drawing;
@@ -6,174 +7,152 @@ using QuestPDF.Infrastructure;
 
 
 namespace QuestPDF.Elements
 namespace QuestPDF.Elements
 {
 {
-    internal class RowElement : Constrained
+    internal enum RowItemType
     {
     {
-        public float ConstantSize { get; }
-        public float RelativeSize { get; }
-
-        public RowElement(float constantSize, float relativeSize)
-        {
-            ConstantSize = constantSize;
-            RelativeSize = relativeSize;
-        }
+        Auto,
+        Constant,
+        Relative
+    }
+    
+    internal class RowItem : Container
+    {
+        public bool IsRendered { get; set; }
+        public float Width { get; set; }
         
         
-        public void SetWidth(float width)
-        {
-            MinWidth = width;
-            MaxWidth = width;
-        }
+        public RowItemType Type { get; set; }
+        public float Size { get; set; }
+    }
+
+    internal class RowItemRenderingCommand
+    {
+        public RowItem RowItem { get; set; }
+        public SpacePlan Measurement { get; set; }
+        public Size Size { get; set; }
+        public Position Offset { get; set; }
     }
     }
     
     
-    internal class BinaryRow : Element, ICacheable, IStateResettable
+    internal class Row : Element, ICacheable, IStateResettable
     {
     {
-        internal Element Left { get; set; }
-        internal Element Right { get; set; }
+        internal List<RowItem> Items { get; } = new();
+        internal float Spacing { get; set; }
 
 
-        private bool IsLeftRendered { get; set; } 
-        private bool IsRightRendered { get; set; } 
-        
         public void ResetState()
         public void ResetState()
         {
         {
-            IsLeftRendered = false;
-            IsRightRendered = false;
+            Items.ForEach(x => x.IsRendered = false);
         }
         }
         
         
         internal override IEnumerable<Element?> GetChildren()
         internal override IEnumerable<Element?> GetChildren()
         {
         {
-            yield return Left;
-            yield return Right;
+            return Items;
         }
         }
         
         
         internal override void CreateProxy(Func<Element?, Element?> create)
         internal override void CreateProxy(Func<Element?, Element?> create)
         {
         {
-            Left = create(Left);
-            Right = create(Right);
+            Items.ForEach(x => x.Child = create(x.Child));
         }
         }
 
 
         internal override SpacePlan Measure(Size availableSpace)
         internal override SpacePlan Measure(Size availableSpace)
         {
         {
-            var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height));
-            
-            if (leftMeasurement.Type == SpacePlanType.Wrap)
-                return SpacePlan.Wrap();
-
-            var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height));
+            UpdateItemsWidth(availableSpace.Width);
+            var renderingCommands = PlanLayout(availableSpace);
 
 
-            if (rightMeasurement.Type == SpacePlanType.Wrap)
+            if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.Wrap))
                 return SpacePlan.Wrap();
                 return SpacePlan.Wrap();
 
 
-            var totalWidth = leftMeasurement.Width + rightMeasurement.Width;
-            var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height);
+            var width = renderingCommands.Last().Offset.X + renderingCommands.Last().Size.Width;
+            var height = renderingCommands.Max(x => x.Size.Height);
+            var size = new Size(width, height);
 
 
-            var targetSize = new Size(totalWidth, totalHeight);
-
-            if ((!IsLeftRendered && leftMeasurement.Type == SpacePlanType.PartialRender) || 
-                (!IsRightRendered && rightMeasurement.Type == SpacePlanType.PartialRender))
-                return SpacePlan.PartialRender(targetSize);
+            if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon)
+                return SpacePlan.Wrap();
+            
+            if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.PartialRender))
+                return SpacePlan.PartialRender(size);
 
 
-            return SpacePlan.FullRender(targetSize);
+            return SpacePlan.FullRender(size);
         }
         }
 
 
         internal override void Draw(Size availableSpace)
         internal override void Draw(Size availableSpace)
         {
         {
-            var leftSpace = new Size(availableSpace.Width, availableSpace.Height);
-            var leftMeasurement = Left.Measure(leftSpace);
-
-            if (leftMeasurement.Type == SpacePlanType.FullRender)
-                IsLeftRendered = true;
-            
-            Left.Draw(new Size(leftMeasurement.Width, availableSpace.Height));
+            UpdateItemsWidth(availableSpace.Width);
+            var renderingCommands = PlanLayout(availableSpace);
 
 
-            var rightSpace = new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height);
-            var rightMeasurement = Right.Measure(rightSpace);
-            
-            if (rightMeasurement.Type == SpacePlanType.FullRender)
-                IsRightRendered = true;
+            foreach (var command in renderingCommands)
+            {
+                if (command.Measurement.Type == SpacePlanType.FullRender)
+                    command.RowItem.IsRendered = true;
+                
+                if (command.Measurement.Type == SpacePlanType.Wrap)
+                    continue;
+
+                Canvas.Translate(command.Offset);
+                command.RowItem.Draw(command.Size);
+                Canvas.Translate(command.Offset.Reverse());
+            }
             
             
-            Canvas.Translate(new Position(leftMeasurement.Width, 0));
-            Right.Draw(rightSpace);
-            Canvas.Translate(new Position(-leftMeasurement.Width, 0));
+            if (Items.All(x => x.IsRendered))
+                ResetState();
         }
         }
-    }
-    
-    internal class Row : Element
-    {
-        public float Spacing { get; set; } = 0;
-        
-        public ICollection<RowElement> Items { get; internal set; } = new List<RowElement>();
-        private Element? RootElement { get; set; }
 
 
-        internal override IEnumerable<Element?> GetChildren()
+        private void UpdateItemsWidth(float availableWidth)
         {
         {
-            if (RootElement == null)
-                ComposeTree();
-
-            yield return RootElement;
-        }
+            HandleItemsWithAutoWidth();
+            
+            var constantWidth = Items.Where(x => x.Type == RowItemType.Constant).Sum(x => x.Size);
+            var relativeWidth = Items.Where(x => x.Type == RowItemType.Relative).Sum(x => x.Size);
+            var spacingWidth = (Items.Count - 1) * Spacing;
 
 
-        internal override SpacePlan Measure(Size availableSpace)
-        {
-            UpdateElementsWidth(availableSpace.Width);
-            return RootElement.Measure(availableSpace);
-        }
+            foreach (var item in Items.Where(x => x.Type == RowItemType.Constant))
+                item.Width = item.Size;
+            
+            if (relativeWidth <= 0)
+                return;
 
 
-        internal override void Draw(Size availableSpace)
-        {
-            UpdateElementsWidth(availableSpace.Width);
-            RootElement.Draw(availableSpace);
-        }
-        
-        #region structure
-        
-        private void ComposeTree()
-        {
-            Items = AddSpacing(Items, Spacing);
+            var widthPerRelativeUnit = (availableWidth - constantWidth - spacingWidth) / relativeWidth;
             
             
-            var elements = Items.Cast<Element>().ToArray();
-            RootElement = BuildTree(elements);
+            foreach (var item in Items.Where(x => x.Type == RowItemType.Relative))
+                item.Width = item.Size * widthPerRelativeUnit;
         }
         }
 
 
-        private void UpdateElementsWidth(float availableWidth)
+        private void HandleItemsWithAutoWidth()
         {
         {
-            var constantWidth = Items.Sum(x => x.ConstantSize);
-            var relativeWidth = Items.Sum(x => x.RelativeSize);
-
-            var widthPerRelativeUnit = (relativeWidth > 0) ? (availableWidth - constantWidth) / relativeWidth : 0;
-            
-            foreach (var row in Items)
+            foreach (var rowItem in Items.Where(x => x.Type == RowItemType.Auto))
             {
             {
-                row.SetWidth(row.ConstantSize + row.RelativeSize * widthPerRelativeUnit);
+                rowItem.Size = rowItem.Measure(Size.Max).Width;
+                rowItem.Type = RowItemType.Constant;
             }
             }
         }
         }
-        
-        private static ICollection<RowElement> AddSpacing(ICollection<RowElement> elements, float spacing)
-        {
-            if (spacing < Size.Epsilon)
-                return elements;
-            
-            return elements
-                .SelectMany(x => new[] { new RowElement(spacing, 0), x })
-                .Skip(1)
-                .ToList();
-        }
 
 
-        private static Element BuildTree(Span<Element> elements)
+        private ICollection<RowItemRenderingCommand> PlanLayout(Size availableSpace)
         {
         {
-            if (elements.IsEmpty)
-                return Empty.Instance;
+            var leftOffset = 0f;
+            var renderingCommands = new List<RowItemRenderingCommand>();
 
 
-            if (elements.Length == 1)
-                return elements[0];
+            foreach (var item in Items)
+            {
+                var itemSpace = new Size(item.Width, availableSpace.Height);
+                
+                var command = new RowItemRenderingCommand
+                {
+                    RowItem = item,
+                    Size = itemSpace,
+                    Measurement = item.Measure(itemSpace),
+                    Offset = new Position(leftOffset, 0)
+                };
+                
+                renderingCommands.Add(command);
+                leftOffset += item.Width + Spacing;
+            }
 
 
-            var half = elements.Length / 2;
+            var rowHeight = renderingCommands.Where(x => !x.RowItem.IsRendered).Max(x => x.Measurement.Height);
             
             
-            return new BinaryRow
+            foreach (var command in renderingCommands)
             {
             {
-                Left = BuildTree(elements.Slice(0, half)),
-                Right = BuildTree(elements.Slice(half))
-            };
+                command.Size = new Size(command.Size.Width, rowHeight);
+                command.Measurement = command.RowItem.Measure(command.Size);
+            }
+            
+            return renderingCommands;
         }
         }
-        
-        #endregion
     }
     }
 }
 }

+ 78 - 0
QuestPDF/Elements/ScaleToFit.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Linq;
+using QuestPDF.Drawing;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class ScaleToFit : ContainerElement
+    {
+        internal override SpacePlan Measure(Size availableSpace)
+        {
+            if (Child == null)
+                return SpacePlan.FullRender(Size.Zero);
+
+            var perfectScale = FindPerfectScale(Child, availableSpace);
+
+            if (perfectScale == null)
+                return SpacePlan.Wrap();
+
+            var targetSpace = ScaleSize(availableSpace, perfectScale.Value);
+            return SpacePlan.FullRender(targetSpace);
+        }
+        
+        internal override void Draw(Size availableSpace)
+        {
+            var perfectScale = FindPerfectScale(Child, availableSpace);
+            
+            if (!perfectScale.HasValue)
+                return;
+
+            var targetScale = perfectScale.Value;
+            var targetSpace = ScaleSize(availableSpace, 1 / targetScale);
+            
+            Canvas.Scale(targetScale, targetScale);
+            Child?.Draw(targetSpace);
+            Canvas.Scale(1 / targetScale, 1 / targetScale);
+        }
+
+        private static Size ScaleSize(Size size, float factor)
+        {
+            return new Size(size.Width * factor, size.Height * factor);
+        }
+        
+        private static float? FindPerfectScale(Element child, Size availableSpace)
+        {
+            if (ChildFits(1))
+                return 1;
+            
+            var maxScale = 1f;
+            var minScale = Size.Epsilon;
+
+            var lastWorkingScale = (float?)null;
+            
+            foreach (var _ in Enumerable.Range(0, 8))
+            {
+                var halfScale = (maxScale + minScale) / 2;
+
+                if (ChildFits(halfScale))
+                {
+                    minScale = halfScale;
+                    lastWorkingScale = halfScale;
+                }
+                else
+                {
+                    maxScale = halfScale;
+                }
+            }
+            
+            return lastWorkingScale;
+            
+            bool ChildFits(float scale)
+            {
+                var scaledSpace = ScaleSize(availableSpace, 1 / scale);
+                return child.Measure(scaledSpace).Type == SpacePlanType.FullRender;
+            }
+        }
+    }
+}

+ 0 - 143
QuestPDF/Elements/Stack.cs

@@ -1,143 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using QuestPDF.Drawing;
-using QuestPDF.Fluent;
-using QuestPDF.Infrastructure;
-using IComponent = QuestPDF.Infrastructure.IComponent;
-using IContainer = QuestPDF.Infrastructure.IContainer;
-
-namespace QuestPDF.Elements
-{
-    internal class BinaryStack : Element, IStateResettable, ICacheable
-    {
-        internal Element First { get; set; } = Empty.Instance;
-        internal Element Second { get; set; } = Empty.Instance;
-
-        internal bool IsFirstRendered { get; set; } = false;
-
-        internal override IEnumerable<Element?> GetChildren()
-        {
-            yield return First;
-            yield return Second;
-        }
-
-        public void ResetState()
-        {
-            IsFirstRendered = false;
-        }
-
-        internal override void CreateProxy(Func<Element?, Element?> create)
-        {
-            First = create(First);
-            Second = create(Second);
-        }
-        
-        internal override SpacePlan Measure(Size availableSpace)
-        {
-            var firstElement = IsFirstRendered ? Empty.Instance : First;
-            var firstSize = firstElement.Measure(availableSpace);
-
-            if (firstSize.Type == SpacePlanType.Wrap)
-                return SpacePlan.Wrap();
-            
-            if (firstSize.Type == SpacePlanType.PartialRender)
-                return firstSize;
-                
-            var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstSize.Height);
-            var secondSize = Second.Measure(spaceForSecond);
-
-            if (secondSize.Type == SpacePlanType.Wrap)
-                return SpacePlan.PartialRender(firstSize);
-
-            var totalWidth = Math.Max(firstSize.Width, secondSize.Width);
-            var totalHeight = firstSize.Height + secondSize.Height;
-            var targetSize = new Size(totalWidth, totalHeight);
-
-            if (secondSize.Type == SpacePlanType.PartialRender)
-                return SpacePlan.PartialRender(targetSize);
-                
-            return SpacePlan.FullRender(targetSize);
-        }
-
-        internal override void Draw(Size availableSpace)
-        {
-            var firstElement = IsFirstRendered ? Empty.Instance : First;
-
-            var firstMeasurement = firstElement.Measure(availableSpace);
-
-            if (firstMeasurement.Type == SpacePlanType.FullRender)
-                IsFirstRendered = true;
-
-            var firstSize = firstMeasurement;
-
-            if (firstSize.Type != SpacePlanType.Wrap)
-                firstElement.Draw(new Size(availableSpace.Width, firstSize.Height));
-
-            if (firstMeasurement.Type == SpacePlanType.Wrap || firstMeasurement.Type == SpacePlanType.PartialRender)
-                return;
-
-            var firstHeight = firstSize.Height;
-            var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstHeight);
-            var secondMeasurement = Second.Measure(spaceForSecond);
-
-            if (secondMeasurement.Type == SpacePlanType.Wrap)
-                return;
-
-            Canvas.Translate(new Position(0, firstHeight));
-            Second.Draw(new Size(availableSpace.Width, secondMeasurement.Height));
-            Canvas.Translate(new Position(0, -firstHeight));
-            
-            if (secondMeasurement.Type == SpacePlanType.FullRender)
-                IsFirstRendered = false;
-        }
-    }
-    
-    internal class Stack : IComponent
-    {
-        public ICollection<Element> Items { get; } = new List<Element>();
-        public float Spacing { get; set; } = 0;
-        
-        public void Compose(IContainer container)
-        {
-            var elements = AddSpacing(Spacing, Items);
-
-            container
-                .PaddingBottom(-Spacing)    
-                .Element(BuildTree(elements.ToArray()));
-        }
-        
-        static ICollection<Element> AddSpacing(float spacing, ICollection<Element> elements)
-        {
-            if (spacing < Size.Epsilon)
-                return elements;
-                
-            return elements
-                .Where(x => !(x is Empty))
-                .Select(x => new Padding
-                {
-                    Bottom = spacing,
-                    Child = x
-                })
-                .Cast<Element>()
-                .ToList();
-        }
-
-        static Element BuildTree(Span<Element> elements)
-        {
-            if (elements.IsEmpty)
-                return Empty.Instance;
-
-            if (elements.Length == 1)
-                return elements[0];
-
-            var half = elements.Length / 2;
-                
-            return new BinaryStack
-            {
-                First = BuildTree(elements.Slice(0, half)),
-                Second = BuildTree(elements.Slice(half))
-            };
-        }
-    }
-}

+ 25 - 0
QuestPDF/Elements/StopPaging.cs

@@ -0,0 +1,25 @@
+using System;
+using QuestPDF.Drawing;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class StopPaging : ContainerElement
+    {
+        internal override SpacePlan Measure(Size availableSpace)
+        {
+            if (Child == null)
+                return SpacePlan.FullRender(Size.Zero);
+
+            var measurement = Child.Measure(availableSpace);
+
+            return measurement.Type switch
+            {
+                SpacePlanType.Wrap => SpacePlan.FullRender(Size.Zero),
+                SpacePlanType.PartialRender => SpacePlan.FullRender(measurement),
+                SpacePlanType.FullRender => measurement,
+                _ => throw new ArgumentOutOfRangeException()
+            };
+        }
+    }
+}

+ 20 - 14
QuestPDF/Fluent/BorderExtensions.cs

@@ -14,39 +14,45 @@ namespace QuestPDF.Fluent
             return element.Element(border);
             return element.Element(border);
         }
         }
         
         
-        public static IContainer Border(this IContainer element, float value)
+        public static IContainer Border(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.BorderHorizontal(value).BorderVertical(value);
+            return element
+                .BorderHorizontal(value, unit)
+                .BorderVertical(value, unit);
         }
         }
         
         
-        public static IContainer BorderVertical(this IContainer element, float value)
+        public static IContainer BorderVertical(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.BorderLeft(value).BorderRight(value);
+            return element
+                .BorderLeft(value, unit)
+                .BorderRight(value, unit);
         }
         }
         
         
-        public static IContainer BorderHorizontal(this IContainer element, float value)
+        public static IContainer BorderHorizontal(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.BorderTop(value).BorderBottom(value);
+            return element
+                .BorderTop(value, unit)
+                .BorderBottom(value, unit);
         }
         }
         
         
-        public static IContainer BorderLeft(this IContainer element, float value)
+        public static IContainer BorderLeft(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Border(x => x.Left = value);
+            return element.Border(x => x.Left = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer BorderRight(this IContainer element, float value)
+        public static IContainer BorderRight(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Border(x => x.Right = value);
+            return element.Border(x => x.Right = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer BorderTop(this IContainer element, float value)
+        public static IContainer BorderTop(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Border(x => x.Top = value);
+            return element.Border(x => x.Top = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer BorderBottom(this IContainer element, float value)
+        public static IContainer BorderBottom(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Border(x => x.Bottom = value);
+            return element.Border(x => x.Bottom = value.ToPoints(unit));
         }
         }
         
         
         public static IContainer BorderColor(this IContainer element, string color)
         public static IContainer BorderColor(this IContainer element, string color)

+ 44 - 0
QuestPDF/Fluent/ColumnExtensions.cs

@@ -0,0 +1,44 @@
+using System;
+using QuestPDF.Elements;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Fluent
+{
+    public class ColumnDescriptor
+    {
+        internal Column Column { get; } = new();
+
+        public void Spacing(float value, Unit unit = Unit.Point)
+        {
+            Column.Spacing = value.ToPoints(unit);
+        }
+        
+        public IContainer Item()
+        {
+            var container = new Container();
+            
+            Column.Items.Add(new ColumnItem
+            {
+                Child = container
+            });
+            
+            return container;
+        }
+    }
+    
+    public static class ColumnExtensions
+    {
+        [Obsolete("This element has been renamed since version 2022.2. Please use the 'Column' method.")]
+        public static void Stack(this IContainer element, Action<ColumnDescriptor> handler)
+        {
+            element.Column(handler);
+        }
+        
+        public static void Column(this IContainer element, Action<ColumnDescriptor> handler)
+        {
+            var descriptor = new ColumnDescriptor();
+            handler(descriptor);
+            element.Element(descriptor.Column);
+        }
+    }
+}

+ 16 - 12
QuestPDF/Fluent/ConstrainedExtensions.cs

@@ -14,34 +14,38 @@ namespace QuestPDF.Fluent
             return element.Element(constrained);
             return element.Element(constrained);
         }
         }
         
         
-        public static IContainer Width(this IContainer element, float value)
+        public static IContainer Width(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.MinWidth(value).MaxWidth(value);
+            return element
+                .MinWidth(value, unit)
+                .MaxWidth(value, unit);
         }
         }
         
         
-        public static IContainer MinWidth(this IContainer element, float value)
+        public static IContainer MinWidth(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Constrained(x => x.MinWidth = value);
+            return element.Constrained(x => x.MinWidth = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer MaxWidth(this IContainer element, float value)
+        public static IContainer MaxWidth(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Constrained(x => x.MaxWidth = value);
+            return element.Constrained(x => x.MaxWidth = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer Height(this IContainer element, float value)
+        public static IContainer Height(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.MinHeight(value).MaxHeight(value);
+            return element
+                .MinHeight(value, unit)
+                .MaxHeight(value, unit);
         }
         }
         
         
-        public static IContainer MinHeight(this IContainer element, float value)
+        public static IContainer MinHeight(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Constrained(x => x.MinHeight = value);
+            return element.Constrained(x => x.MinHeight = value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer MaxHeight(this IContainer element, float value)
+        public static IContainer MaxHeight(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Constrained(x => x.MaxHeight = value);
+            return element.Constrained(x => x.MaxHeight = value.ToPoints(unit));
         }
         }
     }
     }
 }
 }

+ 38 - 6
QuestPDF/Fluent/DecorationExtensions.cs

@@ -8,16 +8,16 @@ namespace QuestPDF.Fluent
     {
     {
         internal Decoration Decoration { get; } = new Decoration();
         internal Decoration Decoration { get; } = new Decoration();
         
         
-        public IContainer Header()
+        public IContainer Before()
         {
         {
             var container = new Container();
             var container = new Container();
-            Decoration.Header = container;
+            Decoration.Before = container;
             return container;
             return container;
         }
         }
         
         
-        public void Header(Action<IContainer> handler)
+        public void Before(Action<IContainer> handler)
         {
         {
-            handler?.Invoke(Header());
+            handler?.Invoke(Before());
         }
         }
         
         
         public IContainer Content()
         public IContainer Content()
@@ -32,17 +32,49 @@ namespace QuestPDF.Fluent
             handler?.Invoke(Content());
             handler?.Invoke(Content());
         }
         }
         
         
+        public IContainer After()
+        {
+            var container = new Container();
+            Decoration.After = container;
+            return container;
+        }
+        
+        public void After(Action<IContainer> handler)
+        {
+            handler?.Invoke(After());
+        }
+
+        #region Obsolete
+
+        [Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")]
+        public IContainer Header()
+        {
+            var container = new Container();
+            Decoration.Before = container;
+            return container;
+        }
+        
+        [Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")]
+        public void Header(Action<IContainer> handler)
+        {
+            handler?.Invoke(Header());
+        }
+        
+        [Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")]
         public IContainer Footer()
         public IContainer Footer()
         {
         {
             var container = new Container();
             var container = new Container();
-            Decoration.Footer = container;
+            Decoration.After = container;
             return container;
             return container;
         }
         }
         
         
+        [Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")]
         public void Footer(Action<IContainer> handler)
         public void Footer(Action<IContainer> handler)
         {
         {
             handler?.Invoke(Footer());
             handler?.Invoke(Footer());
         }
         }
+
+        #endregion
     }
     }
     
     
     public static class DecorationExtensions
     public static class DecorationExtensions
@@ -52,7 +84,7 @@ namespace QuestPDF.Fluent
             var descriptor = new DecorationDescriptor();
             var descriptor = new DecorationDescriptor();
             handler(descriptor);
             handler(descriptor);
             
             
-            element.Component(descriptor.Decoration);
+            element.Element(descriptor.Decoration);
         }
         }
     }
     }
 }
 }

+ 11 - 2
QuestPDF/Fluent/ElementExtensions.cs

@@ -136,8 +136,7 @@ namespace QuestPDF.Fluent
             });
             });
         }
         }
         
         
-        // TODO: deprecated Box method in QuestPDF 2022.1
-        [Obsolete("This element has been renamed. Please use the MinimalBox method.")]
+        [Obsolete("This element has been renamed since version 2022.1. Please use the MinimalBox method.")]
         public static IContainer Box(this IContainer element)
         public static IContainer Box(this IContainer element)
         {
         {
             return element.Element(new MinimalBox());
             return element.Element(new MinimalBox());
@@ -160,5 +159,15 @@ namespace QuestPDF.Fluent
                 TextStyle = textStyle
                 TextStyle = textStyle
             });
             });
         }
         }
+
+        public static IContainer StopPaging(this IContainer element)
+        {
+            return element.Element(new StopPaging());
+        }
+        
+        public static IContainer ScaleToFit(this IContainer element)
+        {
+            return element.Element(new ScaleToFit());
+        }
     }
     }
 }
 }

+ 7 - 7
QuestPDF/Fluent/GridExtensions.cs

@@ -8,20 +8,20 @@ namespace QuestPDF.Fluent
     {
     {
         internal Grid Grid { get; } = new Grid();
         internal Grid Grid { get; } = new Grid();
         
         
-        public void Spacing(float value)
+        public void Spacing(float value, Unit unit = Unit.Point)
         {
         {
-            VerticalSpacing(value);
-            HorizontalSpacing(value);
+            VerticalSpacing(value, unit);
+            HorizontalSpacing(value, unit);
         }
         }
         
         
-        public void VerticalSpacing(float value)
+        public void VerticalSpacing(float value, Unit unit = Unit.Point)
         {
         {
-            Grid.VerticalSpacing = value;
+            Grid.VerticalSpacing = value.ToPoints(unit);
         }
         }
          
          
-        public void HorizontalSpacing(float value)
+        public void HorizontalSpacing(float value, Unit unit = Unit.Point)
         {
         {
-            Grid.HorizontalSpacing = value;
+            Grid.HorizontalSpacing = value.ToPoints(unit);
         }
         }
         
         
         public void Columns(int value = Grid.DefaultColumnsCount)
         public void Columns(int value = Grid.DefaultColumnsCount)

+ 12 - 5
QuestPDF/Fluent/InlinedExtensions.cs

@@ -10,14 +10,21 @@ namespace QuestPDF.Fluent
     {
     {
         internal Inlined Inlined { get; } = new Inlined();
         internal Inlined Inlined { get; } = new Inlined();
         
         
-        public void Spacing(float value)
+        public void Spacing(float value, Unit unit = Unit.Point)
         {
         {
-            VerticalSpacing(value);
-            HorizontalSpacing(value);
+            VerticalSpacing(value, unit);
+            HorizontalSpacing(value, unit);
         }
         }
         
         
-        public void VerticalSpacing(float value) => Inlined.VerticalSpacing = value;
-        public void HorizontalSpacing(float value) => Inlined.HorizontalSpacing = value;
+        public void VerticalSpacing(float value, Unit unit = Unit.Point)
+        {
+            Inlined.VerticalSpacing = value.ToPoints(unit);
+        }
+
+        public void HorizontalSpacing(float value, Unit unit = Unit.Point)
+        {
+            Inlined.HorizontalSpacing = value.ToPoints(unit);
+        }
 
 
         public void BaselineTop() => Inlined.BaselineAlignment = VerticalAlignment.Top;
         public void BaselineTop() => Inlined.BaselineAlignment = VerticalAlignment.Top;
         public void BaselineMiddle() => Inlined.BaselineAlignment = VerticalAlignment.Middle;
         public void BaselineMiddle() => Inlined.BaselineAlignment = VerticalAlignment.Middle;

+ 36 - 0
QuestPDF/Fluent/LineExtensions.cs

@@ -0,0 +1,36 @@
+using System;
+using QuestPDF.Elements;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Fluent
+{
+    public static class LineExtensions
+    {
+        private static ILine Line(this IContainer element, LineType type, float size)
+        {
+            var line = new Line
+            {
+                Size = size,
+                Type = type
+            };
+
+            element.Element(line);
+            return line;
+        }
+        
+        public static ILine LineVertical(this IContainer element, float size, Unit unit = Unit.Point)
+        {
+            return element.Line(LineType.Vertical, size.ToPoints(unit));
+        }
+        
+        public static ILine LineHorizontal(this IContainer element, float size, Unit unit = Unit.Point)
+        {
+            return element.Line(LineType.Horizontal, size.ToPoints(unit));
+        }
+        
+        public static void LineColor(this ILine descriptor, string value)
+        {
+            (descriptor as Line).Color = value;
+        }
+    }
+}

+ 20 - 14
QuestPDF/Fluent/PaddingExtensions.cs

@@ -14,39 +14,45 @@ namespace QuestPDF.Fluent
             return element.Element(padding);
             return element.Element(padding);
         }
         }
         
         
-        public static IContainer Padding(this IContainer element, float value)
+        public static IContainer Padding(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.PaddingVertical(value).PaddingHorizontal(value);
+            return element
+                .PaddingVertical(value, unit)
+                .PaddingHorizontal(value, unit);
         }
         }
         
         
-        public static IContainer PaddingHorizontal(this IContainer element, float value)
+        public static IContainer PaddingHorizontal(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.PaddingLeft(value).PaddingRight(value);
+            return element
+                .PaddingLeft(value, unit)
+                .PaddingRight(value, unit);
         }
         }
         
         
-        public static IContainer PaddingVertical(this IContainer element, float value)
+        public static IContainer PaddingVertical(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.PaddingTop(value).PaddingBottom(value);
+            return element
+                .PaddingTop(value, unit)
+                .PaddingBottom(value, unit);
         }
         }
         
         
-        public static IContainer PaddingTop(this IContainer element, float value)
+        public static IContainer PaddingTop(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Padding(x => x.Top = value);
+            return element.Padding(x => x.Top += value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer PaddingBottom(this IContainer element, float value)
+        public static IContainer PaddingBottom(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Padding(x => x.Bottom = value);
+            return element.Padding(x => x.Bottom += value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer PaddingLeft(this IContainer element, float value)
+        public static IContainer PaddingLeft(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Padding(x => x.Left = value);
+            return element.Padding(x => x.Left += value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer PaddingRight(this IContainer element, float value)
+        public static IContainer PaddingRight(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Padding(x => x.Right = value);
+            return element.Padding(x => x.Right += value.ToPoints(unit));
         }
         }
     }
     }
 }
 }

+ 28 - 20
QuestPDF/Fluent/PageExtensions.cs

@@ -10,16 +10,24 @@ namespace QuestPDF.Fluent
     {
     {
         internal Page Page { get; } = new Page();
         internal Page Page { get; } = new Page();
 
 
+        public void Size(float width, float height, Unit unit = Unit.Inch)
+        {
+            var pageSize = new PageSize(width, height, unit);
+            
+            MinSize(pageSize);
+            MaxSize(pageSize);
+        }
+        
         public void Size(PageSize pageSize)
         public void Size(PageSize pageSize)
         {
         {
             MinSize(pageSize);
             MinSize(pageSize);
             MaxSize(pageSize);
             MaxSize(pageSize);
         }
         }
         
         
-        public void ContinuousSize(float width)
+        public void ContinuousSize(float width, Unit unit = Unit.Point)
         {
         {
-            MinSize(new PageSize(width, 0));
-            MaxSize(new PageSize(width, Infrastructure.Size.Max.Height));
+            MinSize(new PageSize(width.ToPoints(unit), 0));
+            MaxSize(new PageSize(width.ToPoints(unit), Infrastructure.Size.Max.Height));
         }
         }
 
 
         public void MinSize(PageSize pageSize)
         public void MinSize(PageSize pageSize)
@@ -32,42 +40,42 @@ namespace QuestPDF.Fluent
             Page.MaxSize = pageSize;
             Page.MaxSize = pageSize;
         }
         }
 
 
-        public void MarginLeft(float value)
+        public void MarginLeft(float value, Unit unit = Unit.Point)
         {
         {
-            Page.MarginLeft = value;
+            Page.MarginLeft = value.ToPoints(unit);
         }
         }
         
         
-        public void MarginRight(float value)
+        public void MarginRight(float value, Unit unit = Unit.Point)
         {
         {
-            Page.MarginRight = value;
+            Page.MarginRight = value.ToPoints(unit);
         }
         }
         
         
-        public void MarginTop(float value)
+        public void MarginTop(float value, Unit unit = Unit.Point)
         {
         {
-            Page.MarginTop = value;
+            Page.MarginTop = value.ToPoints(unit);
         }
         }
         
         
-        public void MarginBottom(float value)
+        public void MarginBottom(float value, Unit unit = Unit.Point)
         {
         {
-            Page.MarginBottom = value;
+            Page.MarginBottom = value.ToPoints(unit);
         }
         }
         
         
-        public void MarginVertical(float value)
+        public void MarginVertical(float value, Unit unit = Unit.Point)
         {
         {
-            MarginTop(value);
-            MarginBottom(value);
+            MarginTop(value, unit);
+            MarginBottom(value, unit);
         }
         }
         
         
-        public void MarginHorizontal(float value)
+        public void MarginHorizontal(float value, Unit unit = Unit.Point)
         {
         {
-            MarginLeft(value);
-            MarginRight(value);
+            MarginLeft(value, unit);
+            MarginRight(value, unit);
         }
         }
         
         
-        public void Margin(float value)
+        public void Margin(float value, Unit unit = Unit.Point)
         {
         {
-            MarginVertical(value);
-            MarginHorizontal(value);
+            MarginVertical(value, unit);
+            MarginHorizontal(value, unit);
         }
         }
         
         
         public void DefaultTextStyle(TextStyle textStyle)
         public void DefaultTextStyle(TextStyle textStyle)

+ 31 - 10
QuestPDF/Fluent/RowExtensions.cs

@@ -6,29 +6,50 @@ namespace QuestPDF.Fluent
 {
 {
     public class RowDescriptor
     public class RowDescriptor
     {
     {
-        internal Row Row { get; } = new Row();
+        internal Row Row { get; } = new();
 
 
         public void Spacing(float value)
         public void Spacing(float value)
         {
         {
             Row.Spacing = value;
             Row.Spacing = value;
         }
         }
+
+        private IContainer Item(RowItemType type, float size = 0)
+        {
+            var element = new RowItem
+            {
+                Type = type,
+                Size = size
+            };
+            
+            Row.Items.Add(element);
+            return element;
+        }
         
         
-        public IContainer ConstantColumn(float width)
+        [Obsolete("This element has been renamed since version 2022.2. Please use the RelativeItem method.")]
+        public IContainer RelativeColumn(float size = 1)
         {
         {
-            return Column(constantWidth: width);
+            return Item(RowItemType.Relative, size);
         }
         }
         
         
-        public IContainer RelativeColumn(float width = 1)
+        [Obsolete("This element has been renamed since version 2022.2. Please use the ConstantItem method.")]
+        public IContainer ConstantColumn(float size)
         {
         {
-            return Column(relativeWidth: width);
+            return Item(RowItemType.Constant, size);
+        }
+
+        public IContainer RelativeItem(float size = 1)
+        {
+            return Item(RowItemType.Relative, size);
         }
         }
         
         
-        private IContainer Column(float constantWidth = 0, float relativeWidth = 0)
+        public IContainer ConstantItem(float size, Unit unit = Unit.Point)
         {
         {
-            var element = new RowElement(constantWidth, relativeWidth);
-            
-            Row.Items.Add(element);
-            return element;
+            return Item(RowItemType.Constant, size.ToPoints(unit));
+        }
+
+        public IContainer AutoItem()
+        {
+            return Item(RowItemType.Auto);
         }
         }
     }
     }
     
     

+ 2 - 2
QuestPDF/Fluent/ScaleExtensions.cs

@@ -21,7 +21,7 @@ namespace QuestPDF.Fluent
         
         
         public static IContainer ScaleHorizontal(this IContainer element, float value)
         public static IContainer ScaleHorizontal(this IContainer element, float value)
         {
         {
-            return element.Scale(x => x.ScaleX = value);
+            return element.Scale(x => x.ScaleX *= value);
         }
         }
         
         
         public static IContainer FlipHorizontal(this IContainer element)
         public static IContainer FlipHorizontal(this IContainer element)
@@ -31,7 +31,7 @@ namespace QuestPDF.Fluent
         
         
         public static IContainer ScaleVertical(this IContainer element, float value)
         public static IContainer ScaleVertical(this IContainer element, float value)
         {
         {
-            return element.Scale(x => x.ScaleY = value);
+            return element.Scale(x => x.ScaleY *= value);
         }
         }
         
         
         public static IContainer FlipVertical(this IContainer element)
         public static IContainer FlipVertical(this IContainer element)

+ 0 - 33
QuestPDF/Fluent/StackExtensions.cs

@@ -1,33 +0,0 @@
-using System;
-using QuestPDF.Elements;
-using QuestPDF.Infrastructure;
-
-namespace QuestPDF.Fluent
-{
-    public class StackDescriptor
-    {
-        internal Stack Stack { get; } = new Stack();
-
-        public void Spacing(float value)
-        {
-            Stack.Spacing = value;
-        }
-        
-        public IContainer Item()
-        {
-            var container = new Container();
-            Stack.Items.Add(container);
-            return container;
-        }
-    }
-    
-    public static class StackExtensions
-    {
-        public static void Stack(this IContainer element, Action<StackDescriptor> handler)
-        {
-            var descriptor = new StackDescriptor();
-            handler(descriptor);
-            element.Component(descriptor.Stack);
-        }
-    }
-}

+ 5 - 5
QuestPDF/Fluent/TableExtensions.cs

@@ -14,9 +14,9 @@ namespace QuestPDF.Fluent
     {
     {
         internal List<TableColumnDefinition> Columns { get; } = new();
         internal List<TableColumnDefinition> Columns { get; } = new();
         
         
-        public void ConstantColumn(float width)
+        public void ConstantColumn(float width, Unit unit = Unit.Point)
         {
         {
-            ComplexColumn(constantWidth: width);
+            ComplexColumn(constantWidth: width.ToPoints(unit));
         }
         }
         
         
         public void RelativeColumn(float width = 1)
         public void RelativeColumn(float width = 1)
@@ -24,7 +24,7 @@ namespace QuestPDF.Fluent
             ComplexColumn(relativeWidth: width);
             ComplexColumn(relativeWidth: width);
         }
         }
         
         
-        public void ComplexColumn(float constantWidth = 0, float relativeWidth = 0)
+        private void ComplexColumn(float constantWidth = 0, float relativeWidth = 0)
         {
         {
             var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth);
             var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth);
             Columns.Add(columnDefinition);
             Columns.Add(columnDefinition);
@@ -101,9 +101,9 @@ namespace QuestPDF.Fluent
             container
             container
                 .Decoration(decoration =>
                 .Decoration(decoration =>
                 {
                 {
-                    decoration.Header().Element(HeaderTable);
+                    decoration.Before().Element(HeaderTable);
                     decoration.Content().Element(ContentTable);
                     decoration.Content().Element(ContentTable);
-                    decoration.Footer().Element(FooterTable);
+                    decoration.After().Element(FooterTable);
                 });
                 });
 
 
             return container;
             return container;

+ 5 - 5
QuestPDF/Fluent/TextExtensions.cs

@@ -37,9 +37,9 @@ namespace QuestPDF.Fluent
             Alignment = HorizontalAlignment.Right;
             Alignment = HorizontalAlignment.Right;
         }
         }
 
 
-        public void ParagraphSpacing(float value)
+        public void ParagraphSpacing(float value, Unit unit = Unit.Point)
         {
         {
-            Spacing = value;
+            Spacing = value.ToPoints(unit);
         }
         }
 
 
         private void AddItemToLastTextBlock(ITextBlockItem item)
         private void AddItemToLastTextBlock(ITextBlockItem item)
@@ -174,12 +174,12 @@ namespace QuestPDF.Fluent
         {
         {
             TextBlocks.ToList().ForEach(x => x.Alignment = Alignment);
             TextBlocks.ToList().ForEach(x => x.Alignment = Alignment);
 
 
-            container.DefaultTextStyle(DefaultStyle).Stack(stack =>
+            container.DefaultTextStyle(DefaultStyle).Column(column =>
             {
             {
-                stack.Spacing(Spacing);
+                column.Spacing(Spacing);
 
 
                 foreach (var textBlock in TextBlocks)
                 foreach (var textBlock in TextBlocks)
-                    stack.Item().Element(textBlock);
+                    column.Item().Element(textBlock);
             });
             });
         }
         }
     }
     }

+ 4 - 4
QuestPDF/Fluent/TranslateExtensions.cs

@@ -14,14 +14,14 @@ namespace QuestPDF.Fluent
             return element.Element(translate);
             return element.Element(translate);
         }
         }
 
 
-        public static IContainer TranslateX(this IContainer element, float value)
+        public static IContainer TranslateX(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Translate(x => x.TranslateX = value);
+            return element.Translate(x => x.TranslateX += value.ToPoints(unit));
         }
         }
         
         
-        public static IContainer TranslateY(this IContainer element, float value)
+        public static IContainer TranslateY(this IContainer element, float value, Unit unit = Unit.Point)
         {
         {
-            return element.Translate(x => x.TranslateY = value);
+            return element.Translate(x => x.TranslateY += value.ToPoints(unit));
         }
         }
     }
     }
 }
 }

+ 3 - 3
QuestPDF/Helpers/PageSizes.cs

@@ -8,10 +8,10 @@ namespace QuestPDF.Helpers
         public readonly float Width;
         public readonly float Width;
         public readonly float Height;
         public readonly float Height;
         
         
-        public PageSize(float width, float height)
+        public PageSize(float width, float height, Unit unit = Unit.Point)
         {
         {
-            Width = width;
-            Height = height;
+            Width = width.ToPoints(unit);
+            Height = height.ToPoints(unit);
         }
         }
 
 
         public static implicit operator Size(PageSize pageSize) => new Size(pageSize.Width, pageSize.Height);
         public static implicit operator Size(PageSize pageSize) => new Size(pageSize.Width, pageSize.Height);

+ 56 - 0
QuestPDF/Helpers/WriteOnlyStream.cs

@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+
+namespace QuestPDF.Helpers
+{
+    /// <summary>
+    /// SkiaSharp calls the Position property when generating target document file.
+    /// If the output stream does not support the Position property, the NullReferenceException is thrown.
+    /// This wrapper fixes this issue by providing cached Position value (always the end of the stream / current length).
+    /// Example stream affected: HttpContext.Response.Body
+    /// </summary>
+    internal class WriteOnlyStream : Stream
+    {
+        private readonly Stream InnerStream;
+        private long StreamLength { get; set; }
+
+        public WriteOnlyStream(Stream stream)
+        {            
+            if (!stream.CanWrite)
+                throw new NotSupportedException("Stream cannot be written");
+
+            InnerStream = stream;
+        }
+
+        public override bool CanRead => false;
+
+        public override bool CanSeek => false;
+
+        public override bool CanWrite => true;
+
+        public override long Length => StreamLength;
+
+        public override long Position
+        { 
+            get => StreamLength; 
+            set => throw new NotImplementedException(); 
+        }
+
+        public override void Flush() => InnerStream.Flush();
+
+        public override int Read(byte[] buffer, int offset, int count) 
+            => throw new NotImplementedException();
+
+        public override long Seek(long offset, SeekOrigin origin) 
+            => throw new NotImplementedException();
+
+        public override void SetLength(long value) 
+            => throw new NotImplementedException();
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            InnerStream.Write(buffer, offset, count);
+            StreamLength += count;
+        }
+    }
+}

+ 2 - 2
QuestPDF/Infrastructure/Size.cs

@@ -3,13 +3,13 @@
     public readonly struct Size
     public readonly struct Size
     {
     {
         public const float Epsilon = 0.001f;
         public const float Epsilon = 0.001f;
-        public const float Infinity = float.PositiveInfinity;
+        public const float Infinity = 14_400;
 
 
         public readonly float Width;
         public readonly float Width;
         public readonly float Height;
         public readonly float Height;
         
         
         public static Size Zero { get; } = new Size(0, 0);
         public static Size Zero { get; } = new Size(0, 0);
-        public static Size Max { get; } = new Size(14_400, 14_400);
+        public static Size Max { get; } = new Size(Infinity, Infinity);
 
 
         public Size(float width, float height)
         public Size(float width, float height)
         {
         {

+ 44 - 0
QuestPDF/Infrastructure/Unit.cs

@@ -0,0 +1,44 @@
+using System;
+using static QuestPDF.Infrastructure.Unit;
+
+namespace QuestPDF.Infrastructure
+{
+    public enum Unit
+    {
+        Point,
+        
+        Meter,
+        Centimetre,
+        Millimetre,
+        
+        Feet,
+        Inch,
+        Mill
+    }
+
+    internal static class UnitExtensions
+    {
+        private const float InchToCentimetre = 2.54f;
+        private const float InchToPoints = 72;
+        
+        public static float ToPoints(this float value, Unit unit)
+        {
+            return value * GetConversionFactor();
+            
+            float GetConversionFactor()
+            {
+                return unit switch
+                {
+                    Point => 1,
+                    Meter => 100 / InchToCentimetre * InchToPoints,
+                    Centimetre => 1 / InchToCentimetre * InchToPoints,
+                    Millimetre => 10 / InchToCentimetre * InchToPoints,
+                    Feet => 12 * InchToPoints,
+                    Inch => InchToPoints,
+                    Mill => InchToPoints / 1000f,
+                    _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null)
+                };
+            }
+        }
+    }
+}

+ 1 - 1
QuestPDF/QuestPDF.csproj

@@ -4,7 +4,7 @@
         <Authors>MarcinZiabek</Authors>
         <Authors>MarcinZiabek</Authors>
         <Company>CodeFlint</Company>
         <Company>CodeFlint</Company>
         <PackageId>QuestPDF</PackageId>
         <PackageId>QuestPDF</PackageId>
-        <Version>2022.1.0</Version>
+        <Version>2022.2.0</Version>
         <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
         <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
         <PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
         <PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
         <LangVersion>9</LangVersion>
         <LangVersion>9</LangVersion>

+ 7 - 7
QuestPDF/Resources/Description.md

@@ -71,15 +71,15 @@ void ComposeHeader(IContainer container)
     container.Row(row =>
     container.Row(row =>
     {
     {
         {
         {
-            stack.Item().Text($"Invoice #{Model.InvoiceNumber}", titleStyle);
+            column.Item().Text($"Invoice #{Model.InvoiceNumber}", titleStyle);
 
 
-            stack.Item().Text(text =>
+            column.Item().Text(text =>
             {
             {
                 text.Span("Issue date: ", TextStyle.Default.SemiBold());
                 text.Span("Issue date: ", TextStyle.Default.SemiBold());
                 text.Span($"{Model.IssueDate:d}");
                 text.Span($"{Model.IssueDate:d}");
             });
             });
 
 
-            stack.Item().Text(text =>
+            column.Item().Text(text =>
             {
             {
                 text.Span("Due date: ", TextStyle.Default.SemiBold());
                 text.Span("Due date: ", TextStyle.Default.SemiBold());
                 text.Span($"{Model.DueDate:d}");
                 text.Span($"{Model.DueDate:d}");
@@ -97,7 +97,7 @@ Implementation of **the content area** that contains seller and customer details
 ```csharp
 ```csharp
 void ComposeContent(IContainer container)
 void ComposeContent(IContainer container)
 {
 {
-    container.PaddingVertical(40).Stack(column => 
+    container.PaddingVertical(40).column(column => 
     {
     {
         column.Spacing(20);
         column.Spacing(20);
         
         
@@ -147,7 +147,7 @@ void ComposeTable(IContainer container)
         // content
         // content
         decoration
         decoration
             .Content()
             .Content()
-            .Stack(column =>
+            .column(column =>
             {
             {
                 foreach (var item in Model.Items)
                 foreach (var item in Model.Items)
                 {
                 {
@@ -174,7 +174,7 @@ void ComposeTable(IContainer container)
 ```csharp
 ```csharp
 void ComposeComments(IContainer container)
 void ComposeComments(IContainer container)
 {
 {
-    container.ShowEntire().Background(Colors.Grey.Lighten3).Padding(10).Stack(message => 
+    container.ShowEntire().Background(Colors.Grey.Lighten3).Padding(10).column(message => 
     {
     {
         message.Spacing(5);
         message.Spacing(5);
         message.Item().Text("Comments", TextStyle.Default.Size(14).SemiBold());
         message.Item().Text("Comments", TextStyle.Default.Size(14).SemiBold());
@@ -200,7 +200,7 @@ public class AddressComponent : IComponent
     
     
     public void Compose(IContainer container)
     public void Compose(IContainer container)
     {
     {
-        container.ShowEntire().Stack(column =>
+        container.ShowEntire().column(column =>
         {
         {
             column.Spacing(5);
             column.Spacing(5);
 
 

+ 8 - 4
QuestPDF/Resources/ReleaseNotes.txt

@@ -1,4 +1,8 @@
-- Introduced new element: `Table` - a great way to construct complex document structures, e.g. reports. This element covers all cases offered by combination of the `Stack` and the `Row` elements. Additionally, it provides support for more complex layouts and corner cases. Updating to the `Table` element can greatly simplify your code 😁
-- Added new element `DefaultTextStyle` - it allows set new text style to all its children,
-- Improved the default paging behavior for the `Row` element. In some minor corner cases it might cause infinite layout exceptions and confuse developers.
-- Fixed default page sizes for: Letter and Legal.
+- Added a `ScaleToFit` element - scales its child down so it fits in the provided space,
+- Added a `StopPaging` element - when its child requires more than one page to fully render, only the first page is shown,
+- Added a 'LineVertical' and a 'LineHorizontal' elements - those will simplify your code a lot, there is no need to use the `Border` element anymore!
+- Renaming: the `Stack` element was renamed to the `Column` element,
+- Renaming: children of the `Row` element are now called `items` instead of `columns`, e.g. `RelativeItem` instead of `RelativeColumn`,
+- Added support of the `AutoItem` to the `Row` element - those items take as little width as possible,
+- Improved default Fluent configuration behavior for elements: Scale, Padding, Translate,
+- Improved integration support with the HttpContext.Response.Body. This improvement was introduced by schulz3000, thank you!

+ 31 - 32
readme.md

@@ -149,41 +149,40 @@ void ComposeTable(IContainer container)
 {
 {
     var headerStyle = TextStyle.Default.SemiBold();
     var headerStyle = TextStyle.Default.SemiBold();
     
     
-    container.Decoration(decoration =>
+    container.Table(table =>
     {
     {
-        // header
-        decoration.Header().BorderBottom(1).Padding(5).Row(row => 
+        table.ColumnsDefinition(columns =>
         {
         {
-            row.ConstantColumn(25).Text("#", headerStyle);
-            row.RelativeColumn(3).Text("Product", headerStyle);
-            row.RelativeColumn().AlignRight().Text("Unit price", headerStyle);
-            row.RelativeColumn().AlignRight().Text("Quantity", headerStyle);
-            row.RelativeColumn().AlignRight().Text("Total", headerStyle);
+            columns.ConstantColumn(25);
+            columns.RelativeColumn(3);
+            columns.RelativeColumn();
+            columns.RelativeColumn();
+            columns.RelativeColumn();
         });
         });
-
-        // content
-        decoration
-            .Content()
-            .Stack(column =>
-            {
-                foreach (var item in Model.Items)
-                {
-                    column
-                    .Item()
-                    .ShowEntire()
-                    .BorderBottom(1)
-                    .BorderColor(Colors.Grey.Lighten2)
-                    .Padding(5)
-                    .Row(row => 
-                    {
-                        row.ConstantColumn(25).Text(Model.Items.IndexOf(item) + 1);
-                        row.RelativeColumn(3).Text(item.Name);
-                        row.RelativeColumn().AlignRight().Text($"{item.Price}$");
-                        row.RelativeColumn().AlignRight().Text(item.Quantity);
-                        row.RelativeColumn().AlignRight().Text($"{item.Price * item.Quantity}$");
-                    });
-                }
-            });
+        
+        table.Header(header =>
+        {
+            header.Cell().Text("#", headerStyle);
+            header.Cell().Text("Product", headerStyle);
+            header.Cell().AlignRight().Text("Unit price", headerStyle);
+            header.Cell().AlignRight().Text("Quantity", headerStyle);
+            header.Cell().AlignRight().Text("Total", headerStyle);
+            
+            header.Cell().ColumnSpan(5)
+                  .PaddingVertical(5).BorderBottom(1).BorderColor(Colors.Black);
+        });
+        
+        foreach (var item in Model.Items)
+        {
+            table.Cell().Text(Model.Items.IndexOf(item) + 1);
+            table.Cell().Text(item.Name);
+            table.Cell().AlignRight().Text($"{item.Price}$");
+            table.Cell().AlignRight().Text(item.Quantity);
+            table.Cell().AlignRight().Text($"{item.Price * item.Quantity}$");
+            
+            table.Cell().ColumnSpan(5)
+                 .PaddingVertical(5).LineHorizontal(1).LineColor(Colors.Grey.Lighten2);
+        }
     });
     });
 }
 }
 ```
 ```