RichTextKit Documentation

repository·main·Indexed 19 days ago

https://github.com/toptensoftware/richtextkit

A rich-text layout, measurement, and rendering library built on SkiaSharp and HarfBuzzSharp. It provides advanced text handling including text shaping, RTL/LTR support (UAX #9), font fallback for emojis and international characters, and Unicode word-break algorithms (UAX #14). Key features include the RichString fluent interface, hit testing for character clusters, caret position calculation via GetCaretInfo, and support for complex layout constraints like MaxWidth and MaxHeight.

Tokens
3.9K
Snippets
10
Records
24
Agent score
65%

What's inside RichTextKit

  1. Overview of RichTextKit

    main

    RichTextKit is a library designed for rich-text layout, measurement, and rendering specifically for SkiaSharp. It provides advanced text handling capabilities that go beyond standard Skia functionality, including text shaping, font fallback, and support for complex Unicode algorithms.

    Key capabilities include:

    • Text Layout & Shaping: Uses HarfBuzzSharp for text shaping and supports common font styles (bold, italic, underline, super/sub-script, etc.).
    • Internationalization: Supports Bi-directional and LTR/RTL text (UAX #9), Unicode word-break algorithms (UAX #14), and font fallback for emojis and international character sets.
    • Layout Constraints: Supports max height, max line limits, and truncation with ellipsis.
    • Interaction & Measurement: Provides text measurement, hit testing, caret position information, and the ability to paint selection range highlights.
    • Minimal Dependencies: Only requires SkiaSharp and HarfBuzzSharp.
  2. Handle Bi-Directional (LTR and RTL) text

    main

    RichTextKit implements the Unicode Bi-directional Text Algorithm (UAX #9) to support mixed left-to-right (LTR) and right-to-left (RTL) languages.

    Each TextBlock has a "base direction" that controls the default layout order. You can control the text direction of specific spans within a text block using:

    • Embedded control characters: As specified by UAX #9.
    • Style Run direction: By setting the text direction property on StyleRun (via the IStyle interface). When set this way, text is processed as an "isolating sequence" per UAX #9.
  3. Understand the relationship between TextBlocks, Style Runs, and Font Runs

    main

    RichTextKit uses a hierarchy of abstractions to manage text from logical definition to physical rendering:

    1. TextBlock: A lower-level concept representing a single block of text (e.g., a paragraph). RichString builds one TextBlock per paragraph. Text blocks can contain forced line breaks using \n (soft returns).
    2. Style Run: Represents the logical view of a text block. A TextBlock is composed of one or more StyleRun objects, where each run is tagged with a specific style (e.g., bold, size).
    3. Font Run: Represents the physical view of a text block after layout. FontRun objects are derived by splitting StyleRuns when text wraps to a new line or when font fallback is required. Each FontRun uses the same font and style attributes for every character in that run.
    4. TextLine: After layout, a TextBlock results in a set of TextLine objects, each consisting of one or more FontRuns.
  4. Inspect detailed TextBlock layout via Lines and FontRuns

    main

    For granular control over text layout, you can go beyond basic measurements by inspecting the internal structure of a TextBlock:

    1. Lines: Access the Lines collection to inspect individual lines within the block.
    2. FontRuns: For each line, access the FontRuns collection to get detailed information about the specific font styling and layout applied to segments of that line.
  5. Working with UTF-32, Code Points, and Clusters

    main

    Internally, RichTextKit uses UTF-32 encoded text to handle characters accurately.

    • Code Point: A single UTF-32 character. The API uses CodePointIndex to refer to indices in a UTF-32 buffer.
    • Conversion: Since C# strings are UTF-16, they are automatically converted to UTF-32 when added to a text block. Note: Indices in the converted UTF-32 string may not match the original C# string indices. Use provided mapping functions to translate between them.
    • Clusters: A grouping of one or more code points used to describe a single user-perceived character (common in complex scripts). This aligns with how HarfBuzz handles text.
    • Line Endings: \r and \r\n are automatically normalized to \n. Note that \n\r is not supported and may affect index mapping.
  6. Text Shaping and Font Fallback

    main

    RichTextKit handles complex text rendering through two mechanisms:

    • Text Shaping: For languages that require more than simple left-to-right glyph placement (e.g., complex scripts), RichTextKit uses HarfBuzz to perform text shaping. This ensures glyphs are drawn correctly according to language rules.
    • Font Fallback: If a specified font lacks the required glyphs (common for emojis, Arabic, or Asian scripts), RichTextKit uses SkiaSharp's MatchCharacter function to resolve and switch to an appropriate typeface.
  7. Understand the HitTestResult structure

    main
    When you call HitTest on a RichString or TextBlock, it returns a Topten.RichTextKit.HitTestResult structure. This structure contains information describing both the line and the code point cluster that the provided coordinate is associated with (either directly under the point or the nearest one).
  8. Perform hit testing to find character clusters

    main

    Hit testing allows you to identify the character cluster (code point cluster) that a specific coordinate is either directly over or closest to. This is useful for implementing features like range selection or building custom text editors.

    You can perform hit testing using the HitTest method on either a RichString or a TextBlock object.

    Important: Coordinate Space The coordinates passed to RichString.HitTest and TextBlock.HitTest must be relative to the top-left corner of the object. If your coordinates are in global/screen space, you must subtract the top-left position of the text block before calling the method.

    // Hit test a mouse co-ordinate for example
    var htr = tb.HitTest(x, y);
  9. Create a TextBlock

    main

    The TextBlock class is a low-level class used for working with a single block of text. While the higher-level RichString class is generally recommended for most use cases, TextBlock provides direct control over text content and layout properties.

    To create a TextBlock, instantiate the class and configure layout properties such as MaxWidth and Alignment.

    using Topten.RichTextKit;
    
    // Create the text block
    var tb = new TextBlock();
    
    // Configure layout properties
    tb.MaxWidth = 900;
    tb.Alignment = TextAlignment.Center;
  10. Render text with a selection highlight

    main

    To render text with a specific portion highlighted, use the TextPaintOptions object passed to the Paint() method. You can specify the range of the highlight using SelectionStart and SelectionEnd (indices are inclusive of the start and exclusive of the end, e.g., 10 to 20 highlights code points 10 through 19) and define the highlight color via SelectionColor.

    // Highlight code points 10 through 19...
    var options = new TextPaintOptions()
    {
        SelectionStart = 10,
        SelectionEnd = 20,
        SelectionColor = new SKColor(0xFFFF0000),
    }
    
    // Paint with options
    textBlockOrRichString.Paint(canvas, new SKPoint(100,100), options);