Browse Source

Fixed: corner cases of paging support

MarcinZiabek 4 years ago
parent
commit
96732b5856

+ 3 - 3
QuestPDF.Examples/FrameExample.cs

@@ -12,9 +12,9 @@ namespace QuestPDF.Examples
         {
         {
             return container
             return container
                 .Border(1)
                 .Border(1)
-                .Background(dark ? Colors.Grey.Lighten2 : Colors.White)
-                .Padding(5)
-                .EnsureSpace(10);
+                .BorderColor(Colors.Grey.Medium)
+                .Background(dark ? Colors.Grey.Lighten3 : Colors.White)
+                .Padding(5);
         }
         }
         
         
         public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text, TextStyle.Default.SemiBold());
         public static void LabelCell(this IContainer container, string text) => container.Cell(true).Text(text, TextStyle.Default.SemiBold());

+ 5 - 3
QuestPDF.Examples/TableExamples.cs

@@ -117,15 +117,17 @@ namespace QuestPDF.Examples
                 .EnableCaching()
                 .EnableCaching()
                 .EnableDebugging(false)
                 .EnableDebugging(false)
                 .ShowResults()
                 .ShowResults()
-                .Render(container => GeneratePerformanceStructure(container, 250));
+                .Render(container => GeneratePerformanceStructure(container, 2500));
         }
         }
         
         
         public static void GeneratePerformanceStructure(IContainer container, int repeats)
         public static void GeneratePerformanceStructure(IContainer container, int repeats)
         {
         {
             container
             container
                 .Padding(25)
                 .Padding(25)
+                .Background(Colors.Blue.Lighten2)
                 .Box()
                 .Box()
-                .Border(2) 
+                .Border(1)
+                .Background(Colors.Red.Lighten2)
                 .Table(table =>
                 .Table(table =>
                 {
                 {
                     table.ColumnsDefinition(columns =>
                     table.ColumnsDefinition(columns =>
@@ -139,7 +141,7 @@ namespace QuestPDF.Examples
                     foreach (var i in Enumerable.Range(0, repeats))
                     foreach (var i in Enumerable.Range(0, repeats))
                     {
                     {
                         table.Cell().RowSpan(3).LabelCell("Project");
                         table.Cell().RowSpan(3).LabelCell("Project");
-                        table.Cell().RowSpan(3).ValueCell(Placeholders.Sentence());
+                        table.Cell().RowSpan(3).ShowEntire().ValueCell(Placeholders.Sentence());
                 
                 
                         table.Cell().LabelCell("Report number");
                         table.Cell().LabelCell("Report number");
                         table.Cell().ValueCell(i.ToString());
                         table.Cell().ValueCell(i.ToString());

+ 69 - 34
QuestPDF/Elements/Table/Table.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using QuestPDF.Drawing;
 using QuestPDF.Drawing;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
@@ -75,30 +76,64 @@ namespace QuestPDF.Elements.Table
         {
         {
             UpdateColumnsWidth(availableSpace.Width);
             UpdateColumnsWidth(availableSpace.Width);
             
             
-            var layout = PlanLayout(availableSpace);
+            var renderingCommands = PlanLayout(availableSpace).ToList();
 
 
-            return layout.MaxRowRendered < RowsCount
-                ? SpacePlan.PartialRender(layout.Size) 
-                : SpacePlan.FullRender(layout.Size);
+            if (!renderingCommands.Any())
+                return SpacePlan.Wrap();
+            
+            var lastFullyRenderedRow = renderingCommands
+                .GroupBy(x => x.Cell.Row)
+                .Where(x => x.All(y => y.Measurement.Type == SpacePlanType.FullRender))
+                .Select(x => x.Key)
+                .DefaultIfEmpty(0)
+                .Max();
+
+            var width = Columns.Sum(x => x.Width);
+            var height = renderingCommands.Max(x => x.Offset.Y + x.Size.Height);
+
+            if (width > availableSpace.Width + Size.Epsilon)
+                return SpacePlan.Wrap();
+            
+            var tableSize = new Size(width, height);
+
+            var result = lastFullyRenderedRow == RowsCount 
+                ? SpacePlan.FullRender(tableSize) 
+                : SpacePlan.PartialRender(tableSize);
+            
+            var x = renderingCommands.Select(x => $"{x.Cell.Row} {x.Cell.Column} {x.Offset} {x.Size} {x.Measurement}");
+            var res = string.Join("\n", x);
+            
+            Console.WriteLine($"Measure: {availableSpace} / {result}");
+            return result;
         }
         }
 
 
         internal override void Draw(Size availableSpace)
         internal override void Draw(Size availableSpace)
         {
         {
             UpdateColumnsWidth(availableSpace.Width);
             UpdateColumnsWidth(availableSpace.Width);
-            var layout = PlanLayout(availableSpace);
-            CurrentRow = layout.MaxRowRendered;
-            
-            foreach (var command in layout.CellRenderingCommands)
-            {
-                var measurementResult = command.Cell.Measure(command.Size);
+            var renderingCommands = PlanLayout(new Size(availableSpace.Width, availableSpace.Height + 1)).ToList();
 
 
-                if (measurementResult.Type == SpacePlanType.FullRender)
+            foreach (var command in renderingCommands)
+            {
+                if (command.Measurement.Type == SpacePlanType.FullRender)
                     command.Cell.IsRendered = true;
                     command.Cell.IsRendered = true;
                 
                 
                 Canvas.Translate(command.Offset);
                 Canvas.Translate(command.Offset);
                 command.Cell.Draw(command.Size);
                 command.Cell.Draw(command.Size);
                 Canvas.Translate(command.Offset.Reverse());
                 Canvas.Translate(command.Offset.Reverse());
             }
             }
+
+            CurrentRow = renderingCommands
+                .GroupBy(x => x.Cell.Row)
+                .Where(x => x.All(y => y.Measurement.Type == SpacePlanType.FullRender))
+                .Select(x => x.Key)
+                .DefaultIfEmpty(0)
+                .Max() + 1;
+
+            var x = renderingCommands.Select(x => $"{x.Cell.Row} {x.Cell.Column} {x.Offset} {x.Size} {x.Measurement}");
+            var res = string.Join("\n", x);
+            
+            var height = renderingCommands.Max(x => x.Offset.Y + x.Size.Height);
+            Console.WriteLine($"Draw: {availableSpace} / height {height}");
         }
         }
         
         
         private void UpdateColumnsWidth(float availableWidth)
         private void UpdateColumnsWidth(float availableWidth)
@@ -113,11 +148,9 @@ namespace QuestPDF.Elements.Table
                 column.Width = column.ConstantSize + column.RelativeSize * widthPerRelativeUnit;
                 column.Width = column.ConstantSize + column.RelativeSize * widthPerRelativeUnit;
             }
             }
         }
         }
-
-        private TableRenderingPlan PlanLayout(Size availableSpace)
+        
+        private IEnumerable<TableCellRenderingCommand> PlanLayout(Size availableSpace)
         {
         {
-            var cellRenderingCommands = new List<TableCellRenderingCommand>();
-            
             var cellOffsets = new float[Columns.Count + 1];
             var cellOffsets = new float[Columns.Count + 1];
             cellOffsets[0] = 0;
             cellOffsets[0] = 0;
             
             
@@ -135,22 +168,25 @@ namespace QuestPDF.Elements.Table
             
             
             foreach (var child in childrenToTry)
             foreach (var child in childrenToTry)
             {
             {
-                if (child.Row > maxRenderingRow)
-                    break;
-                
                 if (child.Row > currentRow)
                 if (child.Row > currentRow)
                 {
                 {
                     rowBottomOffsets[currentRow] = Math.Max(rowBottomOffsets[currentRow], rowBottomOffsets[currentRow - 1]);
                     rowBottomOffsets[currentRow] = Math.Max(rowBottomOffsets[currentRow], rowBottomOffsets[currentRow - 1]);
                         
                         
-                    if (rowBottomOffsets[currentRow - 1] > availableSpace.Height + Single.Epsilon)
+                    if (rowBottomOffsets[currentRow - 1] > availableSpace.Height + Size.Epsilon)
                         break;
                         break;
                     
                     
                     currentRow = child.Row;
                     currentRow = child.Row;
                 }
                 }
 
 
-                var topOffset = rowBottomOffsets[child.Row - 1];
-                var availableHeight = availableSpace.Height - topOffset;
+                if (child.Row > maxRenderingRow)
+                    break;
                 
                 
+                if (child.IsRendered)
+                    continue;
+                
+                var topOffset = rowBottomOffsets[child.Row - 1];
+                var availableHeight = availableSpace.Height - topOffset + Size.Epsilon;
+
                 var cellSize = GetCellSize(child, availableHeight);
                 var cellSize = GetCellSize(child, availableHeight);
 
 
                 if (cellSize.Type == SpacePlanType.PartialRender)
                 if (cellSize.Type == SpacePlanType.PartialRender)
@@ -161,6 +197,7 @@ namespace QuestPDF.Elements.Table
                 if (cellSize.Type == SpacePlanType.Wrap)
                 if (cellSize.Type == SpacePlanType.Wrap)
                 {
                 {
                     maxRenderingRow = Math.Min(maxRenderingRow, child.Row - 1);
                     maxRenderingRow = Math.Min(maxRenderingRow, child.Row - 1);
+                    continue;
                 }
                 }
                 
                 
                 var cellBottomOffset = cellSize.Height + topOffset;
                 var cellBottomOffset = cellSize.Height + topOffset;
@@ -169,6 +206,8 @@ namespace QuestPDF.Elements.Table
                 rowBottomOffsets[targetRowId] = Math.Max(rowBottomOffsets[targetRowId], cellBottomOffset);
                 rowBottomOffsets[targetRowId] = Math.Max(rowBottomOffsets[targetRowId], cellBottomOffset);
             }
             }
 
 
+            Console.WriteLine($"{CurrentRow} / {maxRenderingRow}");
+            
             var rowHeights = new DynamicDictionary<int, float>();
             var rowHeights = new DynamicDictionary<int, float>();
             
             
             Enumerable
             Enumerable
@@ -177,9 +216,6 @@ namespace QuestPDF.Elements.Table
                 .ForEach(x => rowHeights[x] = rowBottomOffsets[x] - rowBottomOffsets[x-1]);
                 .ForEach(x => rowHeights[x] = rowBottomOffsets[x] - rowBottomOffsets[x-1]);
             
             
             // find rows count to render in this pass
             // find rows count to render in this pass
-            var totalHeight = rowHeights.Items.Where(x => x.Key <= maxRenderingRow).Sum(x => x.Value);
-            var totalWidth = Columns.Sum(x => x.Width);
-
             var childrenToDraw = Enumerable
             var childrenToDraw = Enumerable
                 .Range(CurrentRow, maxRenderingRow - CurrentRow + 1)
                 .Range(CurrentRow, maxRenderingRow - CurrentRow + 1)
                 .SelectMany(x => OrderedChildren[x]);
                 .SelectMany(x => OrderedChildren[x]);
@@ -190,23 +226,22 @@ namespace QuestPDF.Elements.Table
                 var topOffset = cell.Row == 1 ? 0 : rowBottomOffsets[cell.Row - 1];
                 var topOffset = cell.Row == 1 ? 0 : rowBottomOffsets[cell.Row - 1];
 
 
                 var width = GetCellWidth(cell);
                 var width = GetCellWidth(cell);
-                var height = Enumerable.Range(cell.Row, cell.RowSpan).Select(x => rowHeights[x]).Sum();
+                var height = Enumerable.Range(cell.Row, cell.RowSpan).Where(x => x <= maxRenderingRow).Select(x => rowHeights[x]).Sum();
+
+                var measurement = GetCellSize(cell, height);
 
 
-                cellRenderingCommands.Add(new TableCellRenderingCommand()
+                if (measurement.Type == SpacePlanType.Wrap)
+                    continue;
+                
+                yield return new TableCellRenderingCommand()
                 {
                 {
                     Cell = cell,
                     Cell = cell,
+                    Measurement = measurement,
                     Size = new Size(width, height),
                     Size = new Size(width, height),
                     Offset = new Position(leftOffset, topOffset)
                     Offset = new Position(leftOffset, topOffset)
-                });
+                };
             }
             }
 
 
-            return new TableRenderingPlan
-            {
-                Size = new Size(totalWidth, totalHeight),
-                CellRenderingCommands = cellRenderingCommands,
-                MaxRowRendered = maxRenderingRow
-            };
-            
             float GetCellWidth(TableCell cell)
             float GetCellWidth(TableCell cell)
             {
             {
                 return cellOffsets[cell.Column + cell.ColumnSpan - 1] - cellOffsets[cell.Column - 1];
                 return cellOffsets[cell.Column + cell.ColumnSpan - 1] - cellOffsets[cell.Column - 1];

+ 2 - 0
QuestPDF/Elements/Table/TableCellRenderingCommand.cs

@@ -1,3 +1,4 @@
+using QuestPDF.Drawing;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
 
 
 namespace QuestPDF.Elements.Table
 namespace QuestPDF.Elements.Table
@@ -5,6 +6,7 @@ namespace QuestPDF.Elements.Table
     internal class TableCellRenderingCommand
     internal class TableCellRenderingCommand
     {
     {
         public TableCell Cell { get; set; }
         public TableCell Cell { get; set; }
+        public SpacePlan Measurement { get; set; }
         public Size Size { get; set; }
         public Size Size { get; set; }
         public Position Offset { get; set; }
         public Position Offset { get; set; }
     }
     }

+ 0 - 12
QuestPDF/Elements/Table/TableRenderingPlan.cs

@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-using QuestPDF.Infrastructure;
-
-namespace QuestPDF.Elements.Table
-{
-    internal class TableRenderingPlan
-    {
-        public Size Size { get; set; }
-        public List<TableCellRenderingCommand> CellRenderingCommands { get; set; }
-        public int MaxRowRendered { get; set; }
-    }
-}

+ 1 - 1
QuestPDF/Elements/Text/TextBlock.cs

@@ -32,7 +32,7 @@ namespace QuestPDF.Elements.Text
             var lines = DivideTextItemsIntoLines(availableSpace.Width, availableSpace.Height).ToList();
             var lines = DivideTextItemsIntoLines(availableSpace.Width, availableSpace.Height).ToList();
 
 
             if (!lines.Any())
             if (!lines.Any())
-                return SpacePlan.PartialRender(Size.Zero);
+                return SpacePlan.Wrap();
             
             
             var width = lines.Max(x => x.Width);
             var width = lines.Max(x => x.Width);
             var height = lines.Sum(x => x.LineHeight);
             var height = lines.Sum(x => x.LineHeight);

+ 1 - 1
QuestPDF/Helpers/Placeholders.cs

@@ -7,7 +7,7 @@ namespace QuestPDF.Helpers
 {
 {
     public static class Placeholders
     public static class Placeholders
     {
     {
-        public static readonly Random Random = new Random();
+        public static readonly Random Random = new Random(3); // 3
         
         
         #region Word Cache
         #region Word Cache
 
 

+ 2 - 0
QuestPDF/Infrastructure/Position.cs

@@ -17,5 +17,7 @@
         {
         {
             return new Position(-X, -Y);
             return new Position(-X, -Y);
         }
         }
+        
+        public override string ToString() => $"(Left: {X:N3}, Top: {Y:N3})";
     }
     }
 }
 }

+ 1 - 1
QuestPDF/Infrastructure/Size.cs

@@ -17,6 +17,6 @@
             Height = height;
             Height = height;
         }
         }
         
         
-        public override string ToString() => $"(Width: {Width}, Height: {Height})";
+        public override string ToString() => $"(Width: {Width:N3}, Height: {Height:N3})";
     }
     }
 }
 }