Text rendering optimization: style key, font metrics caching

This commit is contained in:
Marcin Ziąbek
2021-08-26 23:36:43 +02:00
parent fd5d51e764
commit 23e8aa3491
5 changed files with 79 additions and 6 deletions
+6 -1
View File
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
@@ -22,12 +23,16 @@ namespace QuestPDF.Examples
var chapters = GetChapters().ToList();
var results = PerformTest(16).ToList();
var results = PerformTest(1).ToList();
var a = CanvasCache.Paints;
Console.WriteLine($"Min: {results.Min():F}");
Console.WriteLine($"Max: {results.Max():F}");
Console.WriteLine($"Avg: {results.Average():F}");
IEnumerable<(string title, string content)> GetChapters()
{
var book = File.ReadAllLines("quo-vadis.txt");
+58
View File
@@ -31,4 +31,62 @@ Max: 19876,00
Avg: 18622,44
```
## Text Style Key Caching
Attempts:
```
Attempt 0: 17140,00
Attempt 1: 16146,00
Attempt 2: 16345,00
Attempt 3: 16428,00
Attempt 4: 17203,00
Attempt 5: 16890,00
Attempt 6: 17450,00
Attempt 7: 16455,00
Attempt 8: 16553,00
Attempt 9: 17281,00
Attempt 10: 16688,00
Attempt 11: 16459,00
Attempt 12: 17245,00
Attempt 13: 17346,00
Attempt 14: 16514,00
Attempt 15: 16427,00
```
Results:
```
Min: 16146,00
Max: 17450,00
Avg: 16785,62
```
## Font Metrics Caching
```
Attempt 0: 13906,00
Attempt 1: 13510,00
Attempt 2: 13570,00
Attempt 3: 13442,00
Attempt 4: 13580,00
Attempt 5: 13421,00
Attempt 6: 13470,00
Attempt 7: 13456,00
Attempt 8: 13672,00
Attempt 9: 14489,00
Attempt 10: 13543,00
Attempt 11: 13685,00
Attempt 12: 13469,00
Attempt 13: 13586,00
Attempt 14: 13423,00
Attempt 15: 13487,00
```
Results:
```
Min: 13421,00
Max: 14489,00
Avg: 13606,81
```
+7 -1
View File
@@ -7,7 +7,8 @@ namespace QuestPDF.Drawing
{
internal static class CanvasCache
{
private static ConcurrentDictionary<string, SKPaint> Paints = new ConcurrentDictionary<string, SKPaint>();
internal static ConcurrentDictionary<string, SKPaint> Paints = new ConcurrentDictionary<string, SKPaint>();
private static ConcurrentDictionary<string, SKFontMetrics> FontMetrics = new ConcurrentDictionary<string, SKFontMetrics>();
private static ConcurrentDictionary<string, SKPaint> ColorPaint = new ConcurrentDictionary<string, SKPaint>();
internal static SKPaint ColorToPaint(this string color)
@@ -41,6 +42,11 @@ namespace QuestPDF.Drawing
}
}
internal static SKFontMetrics ToFontMetrics(this TextStyle style)
{
return FontMetrics.GetOrAdd(style.ToString(), key => style.ToPaint().FontMetrics);
}
internal static TextMeasurement BreakText(this TextStyle style, string text, float availableWidth)
{
var index = (int)style.ToPaint().BreakText(text, availableWidth, out var width);
+4 -3
View File
@@ -60,6 +60,7 @@ namespace QuestPDF.Elements.Text
public TextMeasurementResult? Measure(TextMeasurementRequest request)
{
var paint = Style.ToPaint();
var fontMetrics = Style.ToFontMetrics();
// start breaking text from requested position
var text = Text.Substring(request.StartIndex);
@@ -88,8 +89,8 @@ namespace QuestPDF.Elements.Text
{
Width = width,
Ascent = paint.FontMetrics.Ascent,
Descent = paint.FontMetrics.Descent,
Ascent = fontMetrics.Ascent,
Descent = fontMetrics.Descent,
LineHeight = Style.LineHeight,
@@ -101,7 +102,7 @@ namespace QuestPDF.Elements.Text
public void Draw(TextDrawingRequest request)
{
var fontMetrics = Style.ToPaint().FontMetrics;
var fontMetrics = Style.ToFontMetrics();
var text = Text.Substring(request.StartIndex, request.EndIndex - request.StartIndex);
+4 -1
View File
@@ -17,9 +17,12 @@ namespace QuestPDF.Infrastructure
public static TextStyle Default => new TextStyle();
private string? KeyCache { get; set; }
public override string ToString()
{
return $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{FontWeight}|{IsItalic}|{IsStroked}|{IsUnderlined}";
KeyCache ??= $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{FontWeight}|{IsItalic}|{IsStroked}|{IsUnderlined}";
return KeyCache;
}
internal TextStyle Clone() => (TextStyle)MemberwiseClone();