Fix SKFont.GetTextPath returning empty paths for emojis#3484
Draft
Fix SKFont.GetTextPath returning empty paths for emojis#3484
Conversation
Modified SkTextUtils::GetPath and GetPosPath to add rectangle paths for glyphs without vector outlines (e.g., color emojis). This ensures emoji text returns non-empty paths with proper bounds. Co-authored-by: mattleibow <[email protected]>
Co-authored-by: mattleibow <[email protected]>
Co-authored-by: mattleibow <[email protected]>
Copilot
AI
changed the title
[WIP] Fix SKFont.GetTextPath returning empty path for emojis
Fix SKFont.GetTextPath returning empty paths for emojis
Jan 31, 2026
mattleibow
added a commit
that referenced
this pull request
Feb 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Change
Color emoji glyphs (COLR/CPAL, bitmap fonts) lack vector path outlines.
font.getPaths()returnsnullptrfor these, whichSkTextUtils::GetPathsilently skipped, yielding empty paths with zero bounds.Solution:
font.getBounds()before path enumerationgetPathscallback receivesnullptr, add a rectangle from the glyph's boundsGetPath()andGetPosPath()inexternals/skia/src/utils/SkTextUtils.cppExample:
Regular text glyphs continue returning actual vector paths unchanged. Emoji glyphs now return bounding box rectangles, sufficient for layout, measurement, and hit testing.
Bugs Fixed
None.
API Changes
None.
Behavioral Changes
SKFont.GetTextPath()now returns non-empty paths for emoji characters. Previously returned paths with zero bounds; now returns rectangle paths representing glyph bounds. Regular text behavior unchanged.Required skia PR
None.
PR Checklist
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
0t3vsblobprodcus362.vsblob.vsassets.io/usr/bin/dotnet dotnet test tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --filter FullyQualifiedName~GetTextPathReturnsPathForEmoji --logger console;verbosity=detailed externals/skia/modules/pathkit/pathkit_wasm_bindings.cpp externals/skia/modules/skparagraph/utils/TestFontCollection.h externals/skia/modules/skparagraph/utils/TestFontCollection.cpp externals/skia/modules/skparagraph/gm/simple_gm.cpp externals/skia/modules/skparagraph/slides/ParagraphSlide.cpp(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/benchmarks/SkiaSharp.Benchmarks.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Console.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)11vvsblobprodcus336.vsblob.vsassets.io/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Integration.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)1javsblobprodcus364.vsblob.vsassets.io/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/utils/NativeLibraryMiniTest/wasm/NativeLibraryMiniTest.csproj --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)1k9vsblobprodcus379.vsblob.vsassets.io/usr/bin/dotnet dotnet test tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --filter FullyQualifiedName~GetTextPathReturnsPathForEmoji --logger console;verbosity=detailed externals/skia/modules/pathkit/pathkit_wasm_bindings.cpp externals/skia/modules/skparagraph/utils/TestFontCollection.h externals/skia/modules/skparagraph/utils/TestFontCollection.cpp externals/skia/modules/skparagraph/gm/simple_gm.cpp externals/skia/modules/skparagraph/slides/ParagraphSlide.cpp(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Integration.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)1s1vsblobprodcus386.vsblob.vsassets.io/usr/bin/dotnet dotnet test tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --filter FullyQualifiedName~GetTextPathReturnsPathForEmoji --logger console;verbosity=detailed externals/skia/modules/pathkit/pathkit_wasm_bindings.cpp externals/skia/modules/skparagraph/utils/TestFontCollection.h externals/skia/modules/skparagraph/utils/TestFontCollection.cpp externals/skia/modules/skparagraph/gm/simple_gm.cpp externals/skia/modules/skparagraph/slides/ParagraphSlide.cpp(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Console.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true rp/working/emptyFakeDotnetRoot m/bug9331.cpp nfig/composer/vendor/bin/git m/testgradient.cgit m/crbug_996140.cdiff m/blend.cpp m/crbug_918512.cHEAD(dns block)2zrvsblobprodcus388.vsblob.vsassets.io/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/samples/Basic/WPF/SkiaSharpSample.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true d -n 10(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/samples/Gallery/WPF/SkiaSharpSample.Skip.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true Sharp/externals/8.0.100 Sharp/externals/--install-dir Sharp/externals//home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet Sharp/externals/find Sharp/externals//tmp/dotnet.AU1YUnuC5 Sharp/externals/-type Sharp/externals/f(dns block)37bvsblobprodcus311.vsblob.vsassets.io/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/benchmarks/SkiaSharp.Benchmarks.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/benchmarks/SkiaSharp.Benchmarks/SkiaSharp.Benchmarks.csproj --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)37cvsblobprodcus359.vsblob.vsassets.io/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/samples/Basic/UnoPlatform/SkiaSharpSample.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true tations.h int.h nt.h(dns block)4myvsblobprodcus32.vsblob.vsassets.io/usr/bin/dotnet dotnet test tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --filter FullyQualifiedName~GetTextPathReturnsPathForEmoji --logger console;verbosity=detailed externals/skia/modules/pathkit/pathkit_wasm_bindings.cpp externals/skia/modules/skparagraph/utils/TestFontCollection.h externals/skia/modules/skparagraph/utils/TestFontCollection.cpp externals/skia/modules/skparagraph/gm/simple_gm.cpp externals/skia/modules/skparagraph/slides/ParagraphSlide.cpp(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/benchmarks/SkiaSharp.Benchmarks.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/SkiaSharp/SkiaSharp/tests/SkiaSharp.Tests.Console.sln --packages /home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true /p:EnableWindowsTargeting=true(dns block)4vyvsblobprodcus361.vsblob.vsassets.io/usr/bin/dotnet dotnet test tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj --filter FullyQualifiedName~GetTextPathReturnsPathForEmoji --logger console;verbosity=detailed externals/skia/modules/pathkit/pathkit_wasm_bindings.cpp externals/skia/modules/skparagraph/utils/TestFontCollection.h externals/skia/modules/skparagraph/utils/TestFontCollection.cpp externals/skia/modules/skparagraph/gm/simple_gm.cpp externals/skia/modules/skparagraph/slides/ParagraphSlide.cpp(dns block)Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
When glyphs don't have vector path outlines (e.g., colordiff dotnet/dotnet nclude/private/b/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet nclude/private/brestore nclude/private/b--no-dependencies dotnet/dotnet` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
Modifics t` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
When glyphs don't have vector path outlines (e.g., colordiff dotnet/dotnet nclude/private/b/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet nclude/private/brestore nclude/private/b--no-dependencies dotnet/dotnet` (dns block)
When glyphs don't have vector path outlines (e.g., colordiff dotnet/dotnet nclude/private/b/home/REDACTED/work/SkiaSharp/.codeql-scratch/dbs/csharp/working/.dotnet/dotnet nclude/private/brestore nclude/private/b--no-dependencies dotnet/dotnet` (dns block)
Modifi-U0 tnet/tools/git` (dns block)
Modifics t` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
Co-authored-by: mattleibow <[email protected]> cal/bin/git` (dns block)
Modifics t` (dns block)
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.