Fixed: corner cases of paging support

This commit is contained in:
MarcinZiabek
2021-12-30 18:40:54 +01:00
parent 7f72e50eb8
commit 2fcf543817
9 changed files with 84 additions and 55 deletions
+3 -3
View File
@@ -12,9 +12,9 @@ namespace QuestPDF.Examples
{
return container
.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());
+5 -3
View File
@@ -117,15 +117,17 @@ namespace QuestPDF.Examples
.EnableCaching()
.EnableDebugging(false)
.ShowResults()
.Render(container => GeneratePerformanceStructure(container, 250));
.Render(container => GeneratePerformanceStructure(container, 2500));
}
public static void GeneratePerformanceStructure(IContainer container, int repeats)
{
container
.Padding(25)
.Background(Colors.Blue.Lighten2)
.Box()
.Border(2)
.Border(1)
.Background(Colors.Red.Lighten2)
.Table(table =>
{
table.ColumnsDefinition(columns =>
@@ -139,7 +141,7 @@ namespace QuestPDF.Examples
foreach (var i in Enumerable.Range(0, repeats))
{
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().ValueCell(i.ToString());
+69 -34
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using QuestPDF.Drawing;
using QuestPDF.Infrastructure;
@@ -75,30 +76,64 @@ namespace QuestPDF.Elements.Table
{
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)
{
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;
Canvas.Translate(command.Offset);
command.Cell.Draw(command.Size);
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)
@@ -113,11 +148,9 @@ namespace QuestPDF.Elements.Table
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];
cellOffsets[0] = 0;
@@ -135,22 +168,25 @@ namespace QuestPDF.Elements.Table
foreach (var child in childrenToTry)
{
if (child.Row > maxRenderingRow)
break;
if (child.Row > currentRow)
{
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;
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);
if (cellSize.Type == SpacePlanType.PartialRender)
@@ -161,6 +197,7 @@ namespace QuestPDF.Elements.Table
if (cellSize.Type == SpacePlanType.Wrap)
{
maxRenderingRow = Math.Min(maxRenderingRow, child.Row - 1);
continue;
}
var cellBottomOffset = cellSize.Height + topOffset;
@@ -169,6 +206,8 @@ namespace QuestPDF.Elements.Table
rowBottomOffsets[targetRowId] = Math.Max(rowBottomOffsets[targetRowId], cellBottomOffset);
}
Console.WriteLine($"{CurrentRow} / {maxRenderingRow}");
var rowHeights = new DynamicDictionary<int, float>();
Enumerable
@@ -177,9 +216,6 @@ namespace QuestPDF.Elements.Table
.ForEach(x => rowHeights[x] = rowBottomOffsets[x] - rowBottomOffsets[x-1]);
// 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
.Range(CurrentRow, maxRenderingRow - CurrentRow + 1)
.SelectMany(x => OrderedChildren[x]);
@@ -190,23 +226,22 @@ namespace QuestPDF.Elements.Table
var topOffset = cell.Row == 1 ? 0 : rowBottomOffsets[cell.Row - 1];
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();
cellRenderingCommands.Add(new TableCellRenderingCommand()
var measurement = GetCellSize(cell, height);
if (measurement.Type == SpacePlanType.Wrap)
continue;
yield return new TableCellRenderingCommand()
{
Cell = cell,
Measurement = measurement,
Size = new Size(width, height),
Offset = new Position(leftOffset, topOffset)
});
};
}
return new TableRenderingPlan
{
Size = new Size(totalWidth, totalHeight),
CellRenderingCommands = cellRenderingCommands,
MaxRowRendered = maxRenderingRow
};
float GetCellWidth(TableCell cell)
{
return cellOffsets[cell.Column + cell.ColumnSpan - 1] - cellOffsets[cell.Column - 1];
@@ -1,3 +1,4 @@
using QuestPDF.Drawing;
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements.Table
@@ -5,6 +6,7 @@ namespace QuestPDF.Elements.Table
internal class TableCellRenderingCommand
{
public TableCell Cell { get; set; }
public SpacePlan Measurement { get; set; }
public Size Size { get; set; }
public Position Offset { get; set; }
}
@@ -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
View File
@@ -32,7 +32,7 @@ namespace QuestPDF.Elements.Text
var lines = DivideTextItemsIntoLines(availableSpace.Width, availableSpace.Height).ToList();
if (!lines.Any())
return SpacePlan.PartialRender(Size.Zero);
return SpacePlan.Wrap();
var width = lines.Max(x => x.Width);
var height = lines.Sum(x => x.LineHeight);
+1 -1
View File
@@ -7,7 +7,7 @@ namespace QuestPDF.Helpers
{
public static class Placeholders
{
public static readonly Random Random = new Random();
public static readonly Random Random = new Random(3); // 3
#region Word Cache
+2
View File
@@ -17,5 +17,7 @@
{
return new Position(-X, -Y);
}
public override string ToString() => $"(Left: {X:N3}, Top: {Y:N3})";
}
}
+1 -1
View File
@@ -17,6 +17,6 @@
Height = height;
}
public override string ToString() => $"(Width: {Width}, Height: {Height})";
public override string ToString() => $"(Width: {Width:N3}, Height: {Height:N3})";
}
}