From 1555ba95b3b5acb6932d608ee78156afd327440a Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 22:59:43 +0200
Subject: [PATCH 01/24] removed allocations in the DrawText function
---
Scribe/FontSystem.cs | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/Scribe/FontSystem.cs b/Scribe/FontSystem.cs
index 3630278..5517031 100644
--- a/Scribe/FontSystem.cs
+++ b/Scribe/FontSystem.cs
@@ -457,12 +457,17 @@ public void DrawText(string text, Vector2 position, FontColor color, TextLayoutS
DrawLayout(layout, position, color);
}
+
+ List _vertices = new List();
+ List _indices = new List();
public void DrawLayout(TextLayout layout, Vector2 position, FontColor color)
{
if (layout.Lines.Count == 0) return;
- var vertices = new List();
- var indices = new List();
+ _vertices.Clear();
+ var vertices = _vertices;
+ _indices.Clear();
+ var indices = _indices;
int vertexCount = 0;
foreach (var line in layout.Lines)
@@ -487,7 +492,12 @@ public void DrawLayout(TextLayout layout, Vector2 position, FontColor color)
vertices.Add(new IFontRenderer.Vertex(new Vector3(glyphX + glyphW, glyphY + glyphH, 0), color, new Vector2(glyph.U1, glyph.V1)));
// Create quad indices
- indices.AddRange(new[] { vertexCount, vertexCount + 1, vertexCount + 2, vertexCount + 1, vertexCount + 3, vertexCount + 2 });
+ indices.Add(vertexCount);
+ indices.Add(vertexCount + 1);
+ indices.Add(vertexCount + 2);
+ indices.Add(vertexCount + 1);
+ indices.Add(vertexCount + 3);
+ indices.Add(vertexCount + 2);
vertexCount += 4;
}
}
From 934a61e45050c68e2f8f02578d00c417b291c9fd Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:11:19 +0200
Subject: [PATCH 02/24] pooling for text layouts
---
Scribe/FontSystem.cs | 24 +++++++++++++++++++++---
Scribe/TextLayout.cs | 2 --
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/Scribe/FontSystem.cs b/Scribe/FontSystem.cs
index 5517031..28672c4 100644
--- a/Scribe/FontSystem.cs
+++ b/Scribe/FontSystem.cs
@@ -389,14 +389,14 @@ public TextLayout CreateLayout(string text, TextLayoutSettings settings)
{
if (string.IsNullOrEmpty(text))
{
- var empty = new TextLayout();
+ var empty = GetTextLayoutFromPool();
empty.UpdateLayout(text, settings, this);
return empty;
}
if (!CacheLayouts)
{
- var direct = new TextLayout();
+ var direct = GetTextLayoutFromPool();
direct.UpdateLayout(text, settings, this);
return direct;
}
@@ -406,7 +406,7 @@ public TextLayout CreateLayout(string text, TextLayoutSettings settings)
if (layoutCache.TryGetValue(key, out var cached))
return cached;
- var layout = new TextLayout();
+ var layout = GetTextLayoutFromPool();
layout.UpdateLayout(text, settings, this);
layoutCache.Add(key, layout);
@@ -457,6 +457,17 @@ public void DrawText(string text, Vector2 position, FontColor color, TextLayoutS
DrawLayout(layout, position, color);
}
+ private Stack _textLayouts = new Stack();
+
+ private TextLayout GetTextLayoutFromPool()
+ {
+ if (_textLayouts.TryPop(out TextLayout layout))
+ {
+ return layout;
+ }
+
+ return new TextLayout();
+ }
List _vertices = new List();
List _indices = new List();
@@ -504,8 +515,15 @@ public void DrawLayout(TextLayout layout, Vector2 position, FontColor color)
if (vertices.Count > 0)
{
+ #if NET5_0_OR_GREATER
+ renderer.DrawQuads(atlasTexture, CollectionsMarshal.AsSpan(vertices), CollectionsMarshal.AsSpan(indices));
+ #else
renderer.DrawQuads(atlasTexture, vertices.ToArray(), indices.ToArray());
+#endif
+
}
+
+ _textLayouts.Push(layout);
}
#endregion
diff --git a/Scribe/TextLayout.cs b/Scribe/TextLayout.cs
index a0bcc0e..dda471b 100644
--- a/Scribe/TextLayout.cs
+++ b/Scribe/TextLayout.cs
@@ -40,8 +40,6 @@ private void LayoutText(FontSystem fontSystem)
int i = 0;
bool hasTrailingNewline = false;
- Lines.Clear();
-
var line = new Line(new Vector2(0, currentY), 0);
// Hoist Settings & constants
From 232517d0a0cf147907c9280febe5708dbf891942 Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:17:05 +0200
Subject: [PATCH 03/24] use predefined arrays in image drawing
---
Scribe/MarkdownLayoutEngine.cs | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/Scribe/MarkdownLayoutEngine.cs b/Scribe/MarkdownLayoutEngine.cs
index dfe5d6b..aa97077 100644
--- a/Scribe/MarkdownLayoutEngine.cs
+++ b/Scribe/MarkdownLayoutEngine.cs
@@ -234,20 +234,21 @@ public static void Render(MarkdownDisplayList dl, FontSystem fontSystem, IFontRe
}
else if (op is DrawImage img)
{
- var vertsImg = new IFontRenderer.Vertex[4];
- var idxImg = new int[] { 0, 2, 1, 1, 2, 3 };
var r = img.Rect;
float offsetX = r.X + position.X;
float offsetY = r.Y + position.Y;
- vertsImg[0] = new IFontRenderer.Vertex(new Vector3(offsetX, offsetY, 0), FontColor.White, new Vector2(0, 0));
- vertsImg[1] = new IFontRenderer.Vertex(new Vector3(offsetX + r.Width, offsetY, 0), FontColor.White, new Vector2(1, 0));
- vertsImg[2] = new IFontRenderer.Vertex(new Vector3(offsetX, offsetY + r.Height, 0), FontColor.White, new Vector2(0, 1));
- vertsImg[3] = new IFontRenderer.Vertex(new Vector3(offsetX + r.Width, offsetY + r.Height, 0), FontColor.White, new Vector2(1, 1));
- renderer.DrawQuads(img.Texture, vertsImg, idxImg);
+ _vertsImg[0] = new IFontRenderer.Vertex(new Vector3(offsetX, offsetY, 0), FontColor.White, new Vector2(0, 0));
+ _vertsImg[1] = new IFontRenderer.Vertex(new Vector3(offsetX + r.Width, offsetY, 0), FontColor.White, new Vector2(1, 0));
+ _vertsImg[2] = new IFontRenderer.Vertex(new Vector3(offsetX, offsetY + r.Height, 0), FontColor.White, new Vector2(0, 1));
+ _vertsImg[3] = new IFontRenderer.Vertex(new Vector3(offsetX + r.Width, offsetY + r.Height, 0), FontColor.White, new Vector2(1, 1));
+ renderer.DrawQuads(img.Texture, _vertsImg, _idxImg);
}
}
}
+ static IFontRenderer.Vertex[] _vertsImg = new IFontRenderer.Vertex[4];
+ static int[] _idxImg = new int[] { 0, 2, 1, 1, 2, 3 };
+
public static bool TryGetLinkAt(MarkdownDisplayList dl, Vector2 point, Vector2 renderOffset, out string href)
{
foreach (var link in dl.Links)
From 6ea5c768b3df300779f6d2e7a630c2839f0db168 Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:27:13 +0200
Subject: [PATCH 04/24] use collection marshalling to reduce .ToArray() calls
---
Scribe/MarkdownLayoutEngine.cs | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/Scribe/MarkdownLayoutEngine.cs b/Scribe/MarkdownLayoutEngine.cs
index aa97077..3ec8121 100644
--- a/Scribe/MarkdownLayoutEngine.cs
+++ b/Scribe/MarkdownLayoutEngine.cs
@@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
+using System.Runtime.InteropServices;
namespace Prowl.Scribe
{
@@ -693,8 +694,10 @@ private static void DrawLinkOverprint(DrawText t, Vector2 position, FontSystem f
var layout = t.Layout;
if (layout.Lines == null || layout.Lines.Count == 0) return;
- var verts = new List(256);
- var idx = new List(512);
+ _verts.Clear();
+ var verts = _verts;
+ _indices.Clear();
+ var idx = _indices;
int vbase = 0;
string text = layout.Text ?? string.Empty;
@@ -751,16 +754,26 @@ private static void DrawLinkOverprint(DrawText t, Vector2 position, FontSystem f
}
if (verts.Count > 0)
+ {
+#if NET5_0_OR_GREATER
+ renderer.DrawQuads(fontSystem.Texture, CollectionsMarshal.AsSpan(verts), CollectionsMarshal.AsSpan(idx));
+ #else
renderer.DrawQuads(fontSystem.Texture, verts.ToArray(), idx.ToArray());
+#endif
+ }
}
+ static List _verts = new List(128);
+ static List _indices = new List(256);
private static void DrawDecorations(DrawText t, Vector2 position, FontSystem fontSystem, IFontRenderer renderer, MarkdownLayoutSettings settings)
{
var layout = t.Layout;
if (layout.Lines == null || layout.Lines.Count == 0) return;
- var verts = new List(128);
- var idx = new List(256);
+ _verts.Clear();
+ var verts = _verts;
+ _indices.Clear();
+ var idx = _indices;
int vbase = 0;
// We will map each line's glyphs to absolute character indices in layout.Text.
@@ -856,7 +869,13 @@ private static void DrawDecorations(DrawText t, Vector2 position, FontSystem fon
}
if (verts.Count > 0)
+ {
+#if NET5_0_OR_GREATER
+ renderer.DrawQuads(fontSystem.Texture, CollectionsMarshal.AsSpan(verts), CollectionsMarshal.AsSpan(idx));
+#else
renderer.DrawQuads(fontSystem.Texture, verts.ToArray(), idx.ToArray());
+#endif
+ }
}
private static void AddLinkHitBoxes(MarkdownDisplayList dl, DrawText t, List links)
From f7d6efc4754e705e11435d5189257f1e760a94cc Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:41:49 +0200
Subject: [PATCH 05/24] use a static string builder over a new one each frame
---
Scribe/MarkdownParser.cs | 29 ++++++++++++++++++++++++-----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/Scribe/MarkdownParser.cs b/Scribe/MarkdownParser.cs
index ff8f28f..8e9fb42 100644
--- a/Scribe/MarkdownParser.cs
+++ b/Scribe/MarkdownParser.cs
@@ -293,7 +293,8 @@ private static bool TryParseBlockQuote(string text, ref int pos, out BlockQuote
quote = default;
if (!AtLineStart(text, pos)) return false;
int i = pos;
- var sb = new StringBuilder();
+ var sb = _stringBuilder;
+ sb.Clear();
bool any = false;
while (i < text.Length)
{
@@ -369,7 +370,8 @@ private static bool TryParseList(string text, ref int pos, out ListBlock list)
// Gather any following indented lines as the item's continuation
int j = NextLineStart(text, le);
- var cont = new StringBuilder();
+ var cont = _stringBuilder;
+ cont.Clear();
while (j < text.Length)
{
int le2 = LineEnd(text, j);
@@ -623,6 +625,7 @@ private static List TokenizeInline(string text)
return list;
}
+ private static StringBuilder _stringBuilder = new StringBuilder();
private static List ApplyStyles(List tokens)
{
// Join Text runs first
@@ -632,7 +635,8 @@ private static List ApplyStyles(List tokens)
{
if (t.Kind != InlineKind.Text) { output.Add(t); continue; }
string s = t.Text;
- var sb = new StringBuilder();
+ var sb = _stringBuilder;
+ sb.Clear();
int i = 0;
while (i < s.Length)
{
@@ -703,11 +707,26 @@ private static int IndexOfClosing(string s, char ch, int count, int from)
return -1;
}
+ private static Stack _inlinePool;
+
+ private static Inline GetInlineFromPool()
+ {
+ if (_inlinePool.TryPop(out Inline inline))
+ {
+ return inline;
+ }
+
+ return new Inline();
+ }
+
private static List CoalesceText(List list)
{
if (list.Count == 0) return list;
+
var res = new List(list.Count);
- var sb = (StringBuilder)null;
+ var sb = _stringBuilder;
+ sb.Clear();
+
void Flush()
{
if (sb != null && sb.Length > 0) { res.Add(Inline.TextRun(sb.ToString())); sb.Clear(); }
@@ -716,7 +735,7 @@ void Flush()
{
if (it.Kind == InlineKind.Text)
{
- sb ??= new StringBuilder(); sb.Append(it.Text);
+ sb.Append(it.Text);
}
else { Flush(); res.Add(it); }
}
From 15c734a9f6a41660aad59f5c6e29348d8304db17 Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:42:09 +0200
Subject: [PATCH 06/24] use static lists for markdown engine
---
Scribe/FontSystem.cs | 1 -
Scribe/MarkdownLayoutEngine.cs | 18 ++++++++++++++----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/Scribe/FontSystem.cs b/Scribe/FontSystem.cs
index 28672c4..49f6b51 100644
--- a/Scribe/FontSystem.cs
+++ b/Scribe/FontSystem.cs
@@ -520,7 +520,6 @@ public void DrawLayout(TextLayout layout, Vector2 position, FontColor color)
#else
renderer.DrawQuads(atlasTexture, vertices.ToArray(), indices.ToArray());
#endif
-
}
_textLayouts.Push(layout);
diff --git a/Scribe/MarkdownLayoutEngine.cs b/Scribe/MarkdownLayoutEngine.cs
index 3ec8121..70a2d5a 100644
--- a/Scribe/MarkdownLayoutEngine.cs
+++ b/Scribe/MarkdownLayoutEngine.cs
@@ -11,6 +11,7 @@
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
+using System.Text;
namespace Prowl.Scribe
{
@@ -607,12 +608,21 @@ private static FontFile ResolveFontForIndex(int idx, FontSystem fs, FontFile bas
#region Inline flattening & decorations
+ static StringBuilder _stringBuilder = new StringBuilder();
+ static List _decorationSpans = new List();
+ static List _linkSpans = new List();
+ static List _styleSpans = new List();
+
private static (string text, List decos, List links, List styles) FlattenInlines(List inlines)
{
- var sb = new System.Text.StringBuilder();
- var decos = new List();
- var links = new List();
- var styles = new List();
+ _stringBuilder.Clear();
+ var sb = _stringBuilder;
+ _decorationSpans.Clear();
+ var decos = _decorationSpans;
+ _linkSpans.Clear();
+ var links = _linkSpans;
+ _styleSpans.Clear();
+ var styles = _styleSpans;
void EmitText(string s, bool bold, bool italic)
{
From addd165856c5c2a4b40495169fd0ac7c1166e655 Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sat, 13 Sep 2025 23:56:34 +0200
Subject: [PATCH 07/24] moved font selector to textlayout, not markdown layout
engine
---
Scribe/MarkdownLayoutEngine.cs | 25 ++++++++++++++++++-------
Scribe/Primitives.cs | 5 ++++-
Scribe/TextLayout.cs | 23 ++++++++++++++++++++---
3 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/Scribe/MarkdownLayoutEngine.cs b/Scribe/MarkdownLayoutEngine.cs
index 70a2d5a..2f0a034 100644
--- a/Scribe/MarkdownLayoutEngine.cs
+++ b/Scribe/MarkdownLayoutEngine.cs
@@ -7,6 +7,7 @@
using Prowl.Scribe.Internal;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@@ -313,7 +314,9 @@ private static float LayoutTextSegment(List inlines, float x, float y, M
tls.MaxWidth = width;
tls.Alignment = TextAlignment.Left;
tls.Font = baseFont;
- tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, baseFont, styles, settings);
+ tls.StyleSpans = styles;
+ tls.LayoutSettings = settings;
+ // tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, baseFont, styles, settings);
var tl = fontSystem.CreateLayout(text, tls);
var linkRanges = new List();
@@ -470,7 +473,8 @@ private static float LayoutCode(CodeBlock cb, float x, float y, MarkdownDisplayL
private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList dl, FontSystem fontSystem, MarkdownLayoutSettings settings, float? widthOverride = null)
{
int cols = t.Rows.Max(r => r.Cells.Count);
- float[] minCol = new float[cols];
+ // float[] minCol = new float[cols];
+ var minCol = ArrayPool.Shared.Rent(cols);
float wAvail = widthOverride ?? settings.Width;
// pass 1: min widths via NoWrap measure
@@ -487,7 +491,9 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
tls.MaxWidth = float.MaxValue;
tls.Alignment = AlignToText(cell.Align);
tls.Font = settings.ParagraphFont;
- tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, settings.ParagraphFont, styles, settings);
+ tls.StyleSpans = styles;
+ tls.LayoutSettings = settings;
+ // tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, settings.ParagraphFont, styles, settings);
var tl = fontSystem.CreateLayout(text, tls);
minCol[c] = MathF.Max(minCol[c], tl.Size.X);
@@ -496,7 +502,8 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
// distribute to fit content width
float totalMin = minCol.Sum();
- float[] colW = new float[cols];
+ // float[] colW = new float[cols];
+ var colW = ArrayPool.Shared.Rent(cols);
if (totalMin <= wAvail)
{
float extra = wAvail - totalMin;
@@ -510,13 +517,15 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
}
// Precompute column x positions for grid lines
- float[] colX = new float[cols + 1];
+ // float[] colX = new float[cols + 1];
+ var colX = ArrayPool.Shared.Rent(cols + 1);
colX[0] = x;
for (int c = 0; c < cols; c++) colX[c + 1] = colX[c] + colW[c];
float tableTop = y;
float rowY = y;
- var perRowHeights = new float[t.Rows.Count];
+ // var perRowHeights = new float[t.Rows.Count];
+ var perRowHeights = ArrayPool.Shared.Rent(t.Rows.Count);
// Pass 2: layout rows (we'll emit text now and draw grid after we know full height)
for (int r = 0; r < t.Rows.Count; r++)
@@ -537,7 +546,9 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
tls.MaxWidth = colW[c];
tls.Alignment = AlignToText(cell.Align);
tls.Font = settings.ParagraphFont;
- tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, settings.ParagraphFont, styles, settings);
+ tls.StyleSpans = styles;
+ tls.LayoutSettings = settings;
+ // tls.FontSelector = (charIndex) => ResolveFontForIndex(charIndex, fontSystem, settings.ParagraphFont, styles, settings);
var tl = fontSystem.CreateLayout(text, tls);
diff --git a/Scribe/Primitives.cs b/Scribe/Primitives.cs
index 1080dfd..3846673 100644
--- a/Scribe/Primitives.cs
+++ b/Scribe/Primitives.cs
@@ -79,6 +79,8 @@ public struct TextLayoutSettings
public TextWrapMode WrapMode;
public TextAlignment Alignment;
public float MaxWidth; // for wrapping, 0 = no limit
+ public List StyleSpans;
+ public MarkdownLayoutSettings LayoutSettings;
public Func FontSelector; // optional: index in the full string -> font
@@ -91,7 +93,8 @@ public struct TextLayoutSettings
TabSize = 4,
WrapMode = TextWrapMode.NoWrap,
Alignment = TextAlignment.Left,
- MaxWidth = 0
+ MaxWidth = 0,
+ StyleSpans = new List()
};
}
diff --git a/Scribe/TextLayout.cs b/Scribe/TextLayout.cs
index dda471b..20bc19e 100644
--- a/Scribe/TextLayout.cs
+++ b/Scribe/TextLayout.cs
@@ -224,9 +224,11 @@ void EmitGlyph(AtlasGlyph glyph, FontFile font, char c, float offsetX, float off
{
char c = text[j];
- FontFile font = Settings.Font;
- if (Settings.FontSelector != null)
- font = Settings.FontSelector(j);
+ // FontFile font = Settings.Font;
+ FontFile font = ResolveFontForIndex(j, fontSystem, Settings.Font, Settings.StyleSpans,
+ Settings.LayoutSettings);
+ // if (Settings.FontSelector != null)
+ // font = Settings.FontSelector(j);
var g = fontSystem.GetOrCreateGlyph(c, pixelSize, font);
//var g = fontSystem.GetOrCreateGlyph(c, pixelSize, Settings.PreferredFont);
@@ -255,6 +257,21 @@ void EmitGlyph(AtlasGlyph glyph, FontFile font, char c, float offsetX, float off
FinalizeLine(ref line, currentY, lineHeight, i, currentX);
}
+ private static FontFile ResolveFontForIndex(int idx, FontSystem fs, FontFile baseFont, List spans, MarkdownLayoutSettings settings)
+ {
+ bool bold = false, italic = false;
+ for (int i = 0; i < spans.Count; i++)
+ {
+ var s = spans[i];
+ if (idx >= s.Start && idx < s.End) { bold |= s.Bold; italic |= s.Italic; if (bold && italic) break; }
+ }
+
+ if (bold && italic) return settings.BoldItalicFont;
+ if (bold) return settings.BoldFont;
+ if (italic) return settings.ItalicFont;
+ return baseFont;
+ }
+
// Split a too-long word across lines, char by char, with minimal overhead.
// Note: we do not kern across line starts; inside a run we keep kerning.
private int LayoutLongWordFast(
From 147797d7663ed3a7079938fde88ee0233ac7331c Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sun, 14 Sep 2025 00:01:12 +0200
Subject: [PATCH 08/24] move get cols to a function, not delegate
---
Scribe/MarkdownLayoutEngine.cs | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/Scribe/MarkdownLayoutEngine.cs b/Scribe/MarkdownLayoutEngine.cs
index 2f0a034..fecb318 100644
--- a/Scribe/MarkdownLayoutEngine.cs
+++ b/Scribe/MarkdownLayoutEngine.cs
@@ -470,10 +470,20 @@ private static float LayoutCode(CodeBlock cb, float x, float y, MarkdownDisplayL
return y + h + settings.ParagraphSpacing;
}
+ private static int GetTableMaxCells(Table table)
+ {
+ int cols = 0;
+ foreach (TableRow row in table.Rows)
+ {
+ cols = Math.Max(cols, row.Cells.Count);
+ }
+
+ return cols;
+ }
+
private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList dl, FontSystem fontSystem, MarkdownLayoutSettings settings, float? widthOverride = null)
{
- int cols = t.Rows.Max(r => r.Cells.Count);
- // float[] minCol = new float[cols];
+ int cols = GetTableMaxCells(t);
var minCol = ArrayPool.Shared.Rent(cols);
float wAvail = widthOverride ?? settings.Width;
@@ -502,7 +512,6 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
// distribute to fit content width
float totalMin = minCol.Sum();
- // float[] colW = new float[cols];
var colW = ArrayPool.Shared.Rent(cols);
if (totalMin <= wAvail)
{
@@ -517,14 +526,12 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
}
// Precompute column x positions for grid lines
- // float[] colX = new float[cols + 1];
var colX = ArrayPool.Shared.Rent(cols + 1);
colX[0] = x;
for (int c = 0; c < cols; c++) colX[c + 1] = colX[c] + colW[c];
float tableTop = y;
float rowY = y;
- // var perRowHeights = new float[t.Rows.Count];
var perRowHeights = ArrayPool.Shared.Rent(t.Rows.Count);
// Pass 2: layout rows (we'll emit text now and draw grid after we know full height)
@@ -590,7 +597,11 @@ private static float LayoutTable(Table t, float x, float y, MarkdownDisplayList
Color = settings.ColorRule
});
}
-
+
+ ArrayPool.Shared.Return(minCol);
+ ArrayPool.Shared.Return(colW);
+ ArrayPool.Shared.Return(colX);
+ ArrayPool.Shared.Return(perRowHeights);
return tableBottom + settings.ParagraphSpacing;
}
From 45129ce4bc80fa392f76e80d1eb6330ce0d5f15f Mon Sep 17 00:00:00 2001
From: Trey Ramm
Date: Sun, 14 Sep 2025 00:10:49 +0200
Subject: [PATCH 09/24] remove delegate creation inside of the layout text
function
---
Scribe/TextLayout.cs | 59 ++++++++++++++++++++++++--------------------
1 file changed, 32 insertions(+), 27 deletions(-)
diff --git a/Scribe/TextLayout.cs b/Scribe/TextLayout.cs
index 20bc19e..5f3865f 100644
--- a/Scribe/TextLayout.cs
+++ b/Scribe/TextLayout.cs
@@ -10,10 +10,13 @@ public class TextLayout
public Vector2 Size { get; private set; }
public TextLayoutSettings Settings { get; private set; }
public string Text { get; private set; }
+
+ private static int _createdLayouts = 0;
public TextLayout()
{
Lines = new List();
+ _createdLayouts++;
}
internal void UpdateLayout(string text, TextLayoutSettings settings, FontSystem fontSystem)
@@ -33,6 +36,26 @@ internal void UpdateLayout(string text, TextLayoutSettings settings, FontSystem
CalculateSize();
}
+ new Dictionary