WICG / canvas-formatted-text

Other
80 stars 17 forks source link

efficient raw data for Metrics output #29

Open mikerreed opened 2 years ago

mikerreed commented 2 years ago

The Metrics output describes how an entire paragraph is broken down into

Motivation

For clients that want to draw the Fragments themselves, and/or want to perform hit-testing and editing/selection themselves, more explicit data is needed. Below is a proposal for the necessary data to perform this drawing and/or editing.

interface Typeface {
    // Number or opaque object: Whatever is needed for the client to know exactly
    // what font-resource (e.g. file, byte-array, etc.) is being used.
    // Without this, the glyph IDs would be meaningless.
    //
    // This interface is really an “instance” of the font-resource. It includes
    // any font-wide modifies that the client (or the shaper) may have requested:
    //    e.g. variations, synthetic-bold, …
    //
    // Factories to create Typeface can be described elsewhere. The point here
    // is that such a unique identifier exists for each font-asset-instance,
    // and that they can be passed around (in/out of the browser), and compared
    // to each other.
};

interface FormattedTextFragment {
    // Information to know which font-resource (typeface) to use,
    // and at what transformation (size, etc.) to use it.
    //
    readonly attribute Typeface typeface;
    readonly attribute double size;
    readonly attribute double scaleX?;   // 1.0 if not specified
    readonly attribute double skewX?:    // 0.0 if not specified (could be a bool)

    // Information to know what positioned glyphs are in the run,
    // and what the corresponding text offsets are for those glyphs.
    // These “offsets” are not needed to correctly draw the glyphs, but are needed
    // during selections and editing, to know the mapping back to the original text.
    //
    readonly attribute sequence<unsigned short> glyphIDs;   // N glyphs
    readonly attribute sequence<float> positions;           // N+1 x,y pairs
    readonly attribute sequence<TextIndex> offsets;         // N+1 offsets
};

Descriptions

Each fragment includes a specific Typeface and scaling information. The Typeface is needed, so the client can refer to the exact font asset that was used by the Shaping process, since the positioned glyphs are only meaningful with that asset. The specifics of what a Typeface is are left intentionally vague (for now). The choice likely will need to be coordinated with how "requested" typefaces are specified in the Data Model. The key feature however, is that somehow a Typeface object is sufficient for the client to identify the font assets per fragment.

The glyph IDs and positions (x,y pairs) are straight-forward. This is sufficient to know precisely where to draw each glyph, and sufficient (given other utilities such as glyph-bounds, not provided by this API) to perform hit-testing.

Offsets are not required for drawing, but are needed for any selections or editing, as they provide a back-mapping for each glyph to the (first) unichar that generated that glyph. With this information, and proper grapheme knowledge (e.g. from ICU) a client can properly identify corresponding graphemes and glyphemes (logical clusters for purposes of selections).

Efficiency

The choice to use homogenous arrays (for glyphIDs, positions, offsets) is a deliberate one. Especially for clients calling from WASM modules, have fast access to the underlying data is very important, so the hope is that JavaScript would use TypedArrays to return this data.

Background details for this proposal.