WICG / canvas-formatted-text

Other
80 stars 17 forks source link

Selection scenarios (render-only styling changes) #50

Open travisleithead opened 2 years ago

travisleithead commented 2 years ago

In brainstorming sessions around how an author would implement selection of text rendered out through a canvas using this feature, we determined that some additional functionality for rendering a selection is advantagous. This was also pointed out in #27 as a performance drawback:

More expensive text style animations: consider a piece of text with animating color. If the color is supplied through the data model, when the value of the color changes the developer would need to reconstruct the text with new color and re-lay it out. This is more expensive than rerendering previously built and laid out text.

The web platform has taken an interesting turn with CSS Custom Highlighting, in which the notion of arbitrary ranges can be used as markers upon which the web platform may draw a highlight (supporting a very restricted set of CSS properties for styling that don't require shaping or formatting) in which it is not necessary to adjust the DOM by adding spans, etc., to attach the styling. This direction is also important for the FormattedText objects, because (like DOM), there are important use cases for supporting highlighting of ranges or other effects that should not require a full re-format of the input data in order to draw.

But why not just leave selection/highlighting as an exercise to the author?

It seems trivially easy to implement selection in a web app by drawing a semi-transparent rectangle over the text and calling it good. However, native selection often handles a variety of edge cases that aren't usually considered and are much more tricky/involved to do with author-provided JavaScript. Specifically,

  1. Font color inversion: to improve color-contrast, many selections will not only paint a background behind the given text, but will also invert the font-color of the selected text. In order to effect a font-color change, in the FormattedText API as currently specified, the entire text would need to be reformatted with an object representing the new highlighted text surface with alternate font color. This is a heavyweight operation for a simple highlight effect. Complicating matters, breaking the source text up into a separate run for styling may also impact ligatures that were on the boundary of adjacent character input which could result in text formatting size changes causing text to "jump" slightly, or for different glyphs to be selected (non-ligatures).
  2. Overlapping glyhs and ligatures: selection of strongly italicized glphs or ligatures will often apply a clipping rect in order to mark the selection of a partial ligature or the rectangular bounds of a glyph that extends past its regular advance. The selection thus only paints a part of the glyph and not the entire glyph. If text color is changed (see the previous point), then oddness between the selection rect and the font color clipping may result.

In order to make the above complexities easier, to support a variety of highlight effects (a la Custom Highlights) without needing to reformat already formatted text, and to improve the performance of selection scenarios over the text, we think it would be a good idea to provide a primitive to apply "override" selection styles onto a "range" of already formatted text.