@@ -59,6 +59,12 @@ public sealed class DrawingCanvas<TPixel> : DrawingCanvas
5959 /// </summary>
6060 private readonly Stack < DrawingCanvasState > savedStates = new ( ) ;
6161
62+ // Per-canvas glyph-outline cache: hoists RichTextGlyphRenderer's per-glyph outline cache from
63+ // per-DrawText-call scope up to the whole canvas, so a glyph outline built once is reused by
64+ // every DrawText call on this canvas (across a frame's many text runs) instead of being
65+ // rebuilt for every run on a text-heavy page.
66+ private readonly Dictionary < RichTextGlyphRenderer . CacheKey , List < RichTextGlyphRenderer . GlyphRenderData > > glyphCache = [ ] ;
67+
6268 /// <summary>
6369 /// Initializes a new instance of the <see cref="DrawingCanvas{TPixel}"/> class.
6470 /// </summary>
@@ -457,7 +463,7 @@ private void DrawTextCore(
457463 EnsureTextPaint ( brush , pen ) ;
458464
459465 RichTextOptions configuredOptions = ConfigureTextOptions ( textOptions , path , out IPath ? configuredPath ) ;
460- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , configuredPath , pen , brush ) ;
466+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , configuredPath , pen , brush , this . glyphCache ) ;
461467 TextRenderer renderer = new ( glyphRenderer ) ;
462468 renderer . RenderText ( text , configuredOptions ) ;
463469
@@ -487,7 +493,7 @@ public override void DrawText(
487493 effectiveOptions . ShapeOptions ,
488494 Matrix4x4 . CreateTranslation ( location . X , location . Y , 0 ) * effectiveOptions . Transform ) ;
489495
490- using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush ) ;
496+ using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . glyphCache ) ;
491497 textBlock . RenderTo ( glyphRenderer , wrappingLength ) ;
492498
493499 this . DrawTextOperations ( glyphRenderer . DrawingOperations , placedOptions , state . ClipPaths ) ;
@@ -509,7 +515,7 @@ public override void DrawText(
509515 DrawingCanvasState state = this . ResolveState ( ) ;
510516 DrawingOptions effectiveOptions = state . Options ;
511517
512- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush ) ;
518+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . glyphCache ) ;
513519 textBlock . RenderTo ( glyphRenderer , wrappingLength ) ;
514520
515521 this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions , state . ClipPaths ) ;
@@ -537,7 +543,7 @@ public override void DrawText(
537543 effectiveOptions . ShapeOptions ,
538544 Matrix4x4 . CreateTranslation ( location . X , location . Y , 0 ) * effectiveOptions . Transform ) ;
539545
540- using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush ) ;
546+ using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . glyphCache ) ;
541547 lineLayout . RenderTo ( glyphRenderer ) ;
542548
543549 this . DrawTextOperations ( glyphRenderer . DrawingOperations , placedOptions , state . ClipPaths ) ;
@@ -558,7 +564,7 @@ public override void DrawText(
558564 DrawingCanvasState state = this . ResolveState ( ) ;
559565 DrawingOptions effectiveOptions = state . Options ;
560566
561- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush ) ;
567+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . glyphCache ) ;
562568 lineLayout . RenderTo ( glyphRenderer ) ;
563569
564570 this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions , state . ClipPaths ) ;
@@ -1144,6 +1150,9 @@ public override void Dispose()
11441150 this . DisposePendingImageResources ( ) ;
11451151 }
11461152
1153+ // Release the per-canvas glyph-outline cache.
1154+ this . glyphCache . Clear ( ) ;
1155+
11471156 this . isDisposed = true ;
11481157 }
11491158 }
0 commit comments