Table of Contents

Class TextShaper

Namespace
Egami.Fonts.Shaping
Assembly
Egami.Fonts.dll

OpenType text shaping in managed code: a run of text in one font becomes positioned glyphs with GSUB substitutions, GPOS positioning and the script rules HarfBuzz applies.

public static class TextShaper
Inheritance
TextShaper
Inherited Members

Examples

// One run, one font, as HarfBuzz's hb_shape: ligatures, kerning and marks from the font's GSUB and GPOS.
var font = new Font(face, 24);
var glyphs = new GlyphBuffer();
string text = "office";
TextShaper.ShapeRun(text, 0, text.Length, font, new RunProperties { Script = Script.Latin }, glyphs);

for (int i = 0; i < glyphs.Count; i++)
{
    ushort id = glyphs.GlyphIds[i];
    int cluster = glyphs.Clusters[i];                 // index in text the glyph came from
    GlyphPosition position = glyphs.Positions[i];     // in the font's units (pixels here)
    bool breakable = (glyphs.Flags[i] & GlyphFlags.UnsafeToBreak) == 0;
}

float width = glyphs.Advance;

Remarks

Stateless and thread-safe; each call needs its own GlyphBuffer.

Methods

Shape(string, Font, ShapingOptions?)

Shapes text: splits it into lines at hard breaks, resolves each line's bidi levels, splits it into runs of one level, script, span and font (falling back per grapheme cluster as Fallback says), shapes each run as ShapeRun(ReadOnlySpan<char>, int, int, Font, RunProperties, GlyphBuffer) does and orders the runs for display. Control characters other than the breaks (a tab, for one) give no glyph. Nothing wraps.

public static ShapedText Shape(string text, Font font, ShapingOptions? options = null)

Parameters

text string

The text.

font Font

The font and size.

options ShapingOptions

The direction, language, script, features, fallback, cluster level and spans; null for Default.

Returns

ShapedText

The shaped lines; an empty text gives one empty line.

Examples

// Whole text: lines at hard breaks, bidi levels, script runs, fallback fonts, runs in display order.
var font = new Font(face, 24);
var options = new ShapingOptions { Fallback = new FontFallback(fonts.Families) };
ShapedText shaped = TextShaper.Shape("Shalom: \u05E9\u05DC\u05D5\u05DD!", font, options);

float x = 0;
foreach (ShapedRun run in shaped.Lines[0].Runs)
{
    GlyphRun glyphs = run.ToGlyphRun(new System.Numerics.Vector2(x, 0), shaped.Text); // what a canvas draws
    x += run.Advance;
}

Exceptions

ArgumentNullException

text is null, or font has no typeface.

ArgumentOutOfRangeException

A span is not inside the text, or two spans overlap.

ShapeRun(ReadOnlySpan<char>, int, int, Font, RunProperties, GlyphBuffer)

Shapes one run, as HarfBuzz's hb_shape: no bidi, script or font splitting; the run is one script in one direction. Clusters are UTF-16 indexes into text; the characters around the run are context for joining scripts.

public static void ShapeRun(ReadOnlySpan<char> text, int start, int length, Font font, RunProperties properties, GlyphBuffer buffer)

Parameters

text ReadOnlySpan<char>

The text the run is part of.

start int

The index of the run's first UTF-16 unit.

length int

The number of UTF-16 units in the run.

font Font

The font and size; positions are in its units.

properties RunProperties

The run's script, language, direction, features and cluster level.

buffer GlyphBuffer

Receives the glyphs in visual order.

Exceptions

ArgumentNullException

buffer is null, or font has no typeface.

ArgumentOutOfRangeException

The run is not inside text.