From b924b6292433c1948af4e8e5aa4a325e2f1d1ae2 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Fri, 3 Nov 2023 18:13:38 +0200 Subject: [PATCH] Provide allocate-less overloads of methods in SKTextBlobBuilder --- binding/SkiaSharp/SKTextBlob.cs | 172 +++++++++++++++--- .../SkiaSharp.HarfBuzz/CanvasExtensions.cs | 4 +- 2 files changed, 149 insertions(+), 27 deletions(-) diff --git a/binding/SkiaSharp/SKTextBlob.cs b/binding/SkiaSharp/SKTextBlob.cs index 704b3e95b8..7558feb0a1 100644 --- a/binding/SkiaSharp/SKTextBlob.cs +++ b/binding/SkiaSharp/SKTextBlob.cs @@ -61,9 +61,9 @@ internal static SKTextBlob Create (void* text, int length, SKTextEncoding encodi return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + builder.AllocatePositionedRun (font, count, bounds: null, out var positionSpan, out var glyphSpan); + font.GetGlyphs (text, length, encoding, glyphSpan); + font.GetGlyphPositions (glyphSpan, positionSpan, origin); return builder.Build (); } @@ -99,9 +99,9 @@ internal static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocateHorizontalRun (font, count, y); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + builder.AllocateHorizontalRun (font, count, y, bounds: null, out var positionSpan, out var glyphSpan); + font.GetGlyphs (text, length, encoding, glyphSpan); + positions.CopyTo (positionSpan); return builder.Build (); } @@ -137,9 +137,9 @@ internal static SKTextBlob CreatePositioned (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + builder.AllocatePositionedRun (font, count, bounds: null, out var positionSpan, out var glyphSpan); + font.GetGlyphs (text, length, encoding, glyphSpan); + positions.CopyTo (positionSpan); return builder.Build (); } @@ -175,9 +175,9 @@ internal static SKTextBlob CreateRotationScale (void* text, int length, SKTextEn return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocateRotationScaleRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + builder.AllocateRotationScaleRun (font, count, bounds: null, out var glyphSpan, out var rotationScaleSpan); + font.GetGlyphs (text, length, encoding, glyphSpan); + positions.CopyTo (rotationScaleSpan); return builder.Build (); } @@ -296,9 +296,9 @@ public void AddRun (ReadOnlySpan glyphs, SKFont font, SKPoint origin = d if (font == null) throw new ArgumentNullException (nameof (font)); - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + AllocatePositionedRun (font, glyphs.Length, bounds: null, out var positionSpan, out var glyphSpan); + glyphs.CopyTo (glyphSpan); + font.GetGlyphPositions (glyphSpan, positionSpan, origin); } // AddHorizontalRun @@ -308,9 +308,9 @@ public void AddHorizontalRun (ReadOnlySpan glyphs, SKFont font, ReadOnly if (font == null) throw new ArgumentNullException (nameof (font)); - var buffer = AllocateHorizontalRun (font, glyphs.Length, y); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + AllocateHorizontalRun (font, glyphs.Length, y, bounds: null, out var positionSpan, out var glyphSpan); + glyphs.CopyTo (glyphSpan); + positions.CopyTo (positionSpan); } // AddPositionedRun @@ -320,9 +320,9 @@ public void AddPositionedRun (ReadOnlySpan glyphs, SKFont font, ReadOnly if (font == null) throw new ArgumentNullException (nameof (font)); - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + AllocatePositionedRun (font, glyphs.Length, bounds: null, out var positionSpan, out var glyphSpan); + glyphs.CopyTo (glyphSpan); + positions.CopyTo (positionSpan); } // AddRotationScaleRun @@ -332,9 +332,9 @@ public void AddRotationScaleRun (ReadOnlySpan glyphs, SKFont font, ReadO if (font == null) throw new ArgumentNullException (nameof (font)); - var buffer = AllocateRotationScaleRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + AllocateRotationScaleRun (font, glyphs.Length, bounds: null, out var glyphSpan, out var rotationScaleSpan); + glyphs.CopyTo (glyphSpan); + positions.CopyTo (rotationScaleSpan); } // AddPathPositionedRun @@ -406,6 +406,20 @@ public SKRunBuffer AllocateRun (SKFont font, int count, float x, float y, SKRect return new SKRunBuffer (runbuffer, count); } + public void AllocateRun (SKFont font, int count, float x, float y, SKRect? bounds, out Span glyphSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run (Handle, font.Handle, count, x, y, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run (Handle, font.Handle, count, x, y, null, &runbuffer); + + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + } + public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds = null) { if (font == null) @@ -420,6 +434,22 @@ public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y return new SKTextRunBuffer (runbuffer, count, textByteCount); } + public void AllocateTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds, out Span textSpan, out Span glyphSpan, out Span clusterSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.Handle, count, x, y, textByteCount, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.Handle, count, x, y, textByteCount, null, &runbuffer); + + textSpan = new Span (runbuffer.utf8text, runbuffer.utf8text == null ? 0 : textByteCount); + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + clusterSpan = new Span (runbuffer.clusters, runbuffer.clusters == null ? 0 : count); + } + // AllocateHorizontalRun public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, float y, SKRect? bounds = null) @@ -436,6 +466,21 @@ public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, floa return new SKHorizontalRunBuffer (runbuffer, count); } + public void AllocateHorizontalRun (SKFont font, int count, float y, SKRect? bounds, out Span positionSpan, out Span glyphSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_pos_h (Handle, font.Handle, count, y, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_pos_h (Handle, font.Handle, count, y, null, &runbuffer); + + positionSpan = new Span (runbuffer.pos, runbuffer.pos == null ? 0 : count); + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + } + public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds = null) { if (font == null) @@ -450,6 +495,23 @@ public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int cou return new SKHorizontalTextRunBuffer (runbuffer, count, textByteCount); } + public void AllocateHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds, out Span textSpan, out Span positionSpan, out Span glyphSpan, out Span clusterSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.Handle, count, y, textByteCount, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.Handle, count, y, textByteCount, null, &runbuffer); + + textSpan = new Span (runbuffer.utf8text, runbuffer.utf8text == null ? 0 : textByteCount); + positionSpan = new Span (runbuffer.pos, runbuffer.pos == null ? 0 : count); + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + clusterSpan = new Span (runbuffer.clusters, runbuffer.clusters == null ? 0 : count); + } + // AllocatePositionedRun public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRect? bounds = null) @@ -466,6 +528,21 @@ public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRe return new SKPositionedRunBuffer (runbuffer, count); } + public void AllocatePositionedRun (SKFont font, int count, SKRect? bounds, out Span positionSpan, out Span glyphSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_pos (Handle, font.Handle, count, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_pos (Handle, font.Handle, count, null, &runbuffer); + + positionSpan = new Span (runbuffer.pos, runbuffer.pos == null ? 0 : count); + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + } + public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) @@ -480,6 +557,23 @@ public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int cou return new SKPositionedTextRunBuffer (runbuffer, count, textByteCount); } + public void AllocatePositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds, out Span textSpan, out Span positionSpan, out Span glyphSpan, out Span clusterSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.Handle, count, textByteCount, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.Handle, count, textByteCount, null, &runbuffer); + + textSpan = new Span (runbuffer.utf8text, runbuffer.utf8text == null ? 0 : textByteCount); + positionSpan = new Span (runbuffer.pos, runbuffer.pos == null ? 0 : count); + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + clusterSpan = new Span (runbuffer.clusters, runbuffer.clusters == null ? 0 : count); + } + // AllocateRotationScaleRun public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count, SKRect? bounds = null) @@ -496,6 +590,21 @@ public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count return new SKRotationScaleRunBuffer (runbuffer, count); } + public void AllocateRotationScaleRun (SKFont font, int count, SKRect? bounds, out Span glyphSpan, out Span rotationScaleSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_rsxform (Handle, font.Handle, count, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_rsxform (Handle, font.Handle, count, null, &runbuffer); + + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + rotationScaleSpan = new Span (runbuffer.pos, count); + } + public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) @@ -509,5 +618,20 @@ public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int c return new SKRotationScaleRunBuffer (runbuffer, count); } + + public void AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds, out Span glyphSpan, out Span rotationScaleSpan) + { + if (font == null) + throw new ArgumentNullException (nameof (font)); + + SKRunBufferInternal runbuffer; + if (bounds is SKRect b) + SkiaApi.sk_textblob_builder_alloc_run_text_rsxform (Handle, font.Handle, count, textByteCount, &b, &runbuffer); + else + SkiaApi.sk_textblob_builder_alloc_run_text_rsxform (Handle, font.Handle, count, textByteCount, null, &runbuffer); + + glyphSpan = new Span (runbuffer.glyphs, runbuffer.glyphs == null ? 0 : count); + rotationScaleSpan = new Span (runbuffer.pos, count); + } } } diff --git a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs index d03462caf8..410469f6e7 100644 --- a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs +++ b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs @@ -74,11 +74,9 @@ public static void DrawShapedText(this SKCanvas canvas, SKShaper shaper, string // create the text blob using var builder = new SKTextBlobBuilder(); - var run = builder.AllocatePositionedRun(font, result.Codepoints.Length); + builder.AllocatePositionedRun(font, result.Codepoints.Length, bounds: null, out var p, out var g); // copy the glyphs - var g = run.GetGlyphSpan(); - var p = run.GetPositionSpan(); for (var i = 0; i < result.Codepoints.Length; i++) { g[i] = (ushort)result.Codepoints[i];