---
title: "Check if a font supports a character"
url: https://recursiveai.org/onefont/cookbook/font-supports-character/
description: "Find out in C# whether a font has a glyph for a character, list the characters it lacks, and fall back to other fonts cluster by cluster."
version: "1.3.0"
---

# Check if a font supports a character

Find out in C# whether a font has a glyph for a character, list the characters it lacks, and fall back to other fonts cluster by cluster.

A font supports a character when its Unicode character map gives it a glyph. `HasGlyph` answers that for one code point. For text with several scripts, a `FontFallbackChain` picks a face for each cluster and shapes it with that face’s own tables.

```csharp
using System.Text;
using OneFont;

FontFace noto = FontFace.Load(File.ReadAllBytes("NotoSans-Regular.ttf"));
FontFace dejavu = FontFace.Load(File.ReadAllBytes("DejaVuSans.ttf"));
FontFace cjk = FontFace.Load(File.ReadAllBytes("NotoSansCJK-Regular.ttc"), faceIndex: 0);

string text = "Café ✓ 東京 😀 क";

// One character: HasGlyph takes a code point, so surrogate pairs (emoji) need Rune, not char.
Console.WriteLine($"Noto Sans has 'é': {noto.HasGlyph('é')}, has '✓': {noto.HasGlyph(0x2713)}");

// Every character a font lacks.
var missing = text.EnumerateRunes().Where(r => !Rune.IsWhiteSpace(r) && !noto.HasGlyph(r.Value));
Console.WriteLine($"Noto Sans lacks: {string.Join(" ", missing.Select(r => $"U+{r.Value:X4}"))}");

// Pick a face for each character, then shape through the chain.
var chain = new FontFallbackChain([noto, dejavu, cjk]);
Console.WriteLine($"'✓' comes from face {chain.SelectFace(0x2713)}, '東' from face {chain.SelectFace('東')}");
foreach (ShapedCluster c in chain.ShapeRun(text).Where(c => !char.IsWhiteSpace(text[c.Start])))
{
    string note = c.HasMissingGlyph ? ", missing: no face has it" : "";
    Console.WriteLine($"  {text.Substring(c.Start, c.Length)}  {chain.Faces[c.FaceIndex].FamilyName}{note}");
}
```

```text
Noto Sans has 'é': True, has '✓': False
Noto Sans lacks: U+2713 U+6771 U+4EAC U+1F600 U+0915
'✓' comes from face 1, '東' from face 2
  C  Noto Sans
  a  Noto Sans
  f  Noto Sans
  é  Noto Sans
  ✓  DejaVu Sans
  東  Noto Sans CJK JP
  京  Noto Sans CJK JP
  😀  DejaVu Sans
  क  Noto Sans, missing: no face has it
```

- `HasGlyph` and `GetGlyphIndex` take a code point (an `int`), not a `char`. Characters outside the Basic Multilingual Plane, such as most emoji, are two `char`s in a .NET string, so walk the text with `EnumerateRunes`.
- Glyph 0 is the font’s missing-glyph box. `HasGlyph` is true when the character map gives any other glyph.
- `SelectFace` returns the index of the first face in the chain with a glyph for a code point, or 0 when no face has one.
- `ShapeRun` on the chain chooses a face for each grapheme cluster by its first character. Invisible characters (controls, zero width spaces and joiners, soft hyphens, bidi controls) take the face of the cluster before them. Each stretch of one face is shaped with that face’s GSUB, GPOS and GDEF tables.
- A character no face has stays with the first face, and its cluster has `HasMissingGlyph` set. Here none of the three fonts has Devanagari.
- DejaVu Sans has an outline glyph for 😀, so the chain uses it. onefont doesn’t draw color glyphs: a color emoji font’s `COLR` or bitmap tables are available only as raw bytes.
- A chain holds at most 32 faces.

A glyph in the character map is not the whole story for complex scripts: a font can have every letter of a script and still lack the conjuncts or contextual forms a word needs. For those, see [Shape complex scripts](https://recursiveai.org/onefont/cookbook/complex-scripts/).
