I am using drawingContext.DrawGlyphRun
in my scenario, as I need the best performance I can get as I am rendering a large amount of text at lots of different positions on screen.
However, I have come into a slight snag. The font I am using is missing some unicode characters for codes such as ✓, ∞
It looks like drawingContext.DrawText
has a very handy feature where a fallback font is used where characters are missing, such that you still at least get something rendered.
So now I am wondering how I could achieve something similar without losing all the performance gains I got from switching to DrawGlyphRun
Seems like I would need to break up the call in multiple parts
"My string with ∞ unsupported character"
[My string with ][∞][ unsupported character]
So 3 calls to drawingContext.DrawGlyphRun
, with the 2nd one using a different font :(
And then I would also need to compute the position offsets so it all aligns correctly.
Other than changing the font (something I can't really do) am I missing an obvious easy way of doing this?
I managed to get this working by using the Global User Interface
fontfamily. Which a collection of typefaces that are used as fallbacks when a character code is not found in the target font.
I decided to cache the typeface for these missing character codes.
private readonly Dictionary<int, GlyphTypeface?> _fallbackGlyphMapping = [];
private bool TryGetFallbackGlyphTypeface(int code, [NotNullWhen(true)] out GlyphTypeface? glyphTypeface)
{
if (!_fallbackGlyphMapping.TryGetValue(code, out glyphTypeface))
{
_globalFontFamily ??= new FontFamily("Global User Interface");
foreach (var map in _globalFontFamily.FamilyMaps)
{
var typeface = new Typeface(new FontFamily(map.Target), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
if (typeface.TryGetGlyphTypeface(out GlyphTypeface? tempGlyphTypeface))
{
if (tempGlyphTypeface.CharacterToGlyphMap.TryGetValue(code, out var index))
{
_fallbackGlyphMapping[code] = tempGlyphTypeface;
glyphTypeface = tempGlyphTypeface;
return true;
}
}
}
// couldn't locate
_fallbackGlyphMapping[code] = null;
return false;
}
return glyphTypeface != null;
}