Remove platform glyph abstraction, just use non-zero u16 as glyph index
like everyone else. As a bonus, this reduces the memory consumption of
the glyph buffers per glyph from a size of a pointer to the size of the
u16.
The AboutSlint text has a forced linebreak in it, which becomes a box
glyph on MCUs when the font on the host system doesn't use an empty
glyph but a box glyph for \n.
This patch explicitly excludes glyph clusters from text fragments that
feed into lines that originate from one of the three valid separators:
ascii newline, unicode paragraph and unicode line separators.
Separate the text shaping functionality from font metrics by having a
FontMetrics trait next to the TextShaper. AbstractFont is the combining
super trait. This allows eliminating the font height member from
TextParagraphLayout and improving the overall naming of fields and
types.
Finally, this prepares the API for composability of TextShaper for font
fallback handling.
Use the term glyph cluster instead of grapheme where we're dealing with
the glyphs for line breaking. Those may coincide with grapheme
boundaries, but aren't required to.
Replace the abstract glyph trait with a glyph struct. That way the text
layout code can operate properly on a struct with fields, instead of on
functions on a trait (some of which returning a mutable reference). The
input is a glyph with offset, advance, etc. - everything needed for the
layout and the output is a position along with the platform specific
glyph data.
Remove the font reference field anymore as it's not needed anymore and
remove the manual clone implementations. Those were needed because
otherwise the TextShaper trait would have to also support clone - as
[derive(Clone)] imposes that. Now we can impose that just on Glyph and
that's easy and makes sense.
Replace the lazy text shaping with an up-front shaping of all text. It
needs to be done eventually anyway, so by doing it in one go we can
avoid interior mutability and simplify the code overall.
Make ShapeBoundaries produce single offsets, there's no need for
ranges as the boundaries are contiguous.
In GraphemeCursor collect all boundaries in one go as text runs, to
simplify state handling. This will be needed anyway for recording bidi
runs in the future.
The unicode linebreak iterator always produces a mandatory break at end
of text. This is not only confusing, but also inconsistent with the
simple line break iterator and with trailing spaces it could cause the
line break algorithm to emit empty lines at the end of text.
* janitor: Fix clippy error in textlayout.rs
This one is almost certainly a bug.
* janitor: clippy fixes in inline_expressions.rs
Clippy claims the original code was slower and less clean, so let's
change this.
* MCU: fix text being cut in the printer demo sometimes being cut off
When a text element is rendered at exactly the width it reports,
then last letter would be cut off.
* Adjust elision test
Store the result of all text shaping calls in one glyph buffer when laying out a
a paragraph of text.
This paves the way of avoiding unnecessary shape_text calls when processing lines.
* Impose no bounds on the associated Glyph type
* Report the byte offset only in shape_text - it doesn't belong into an aritrary glyph
* Move querying the advance into the TextShaper, where the MCU implementation can deal with missing glyphs
without storing fallback values in the Glyph type
This is based on the unicode line breaking algorithm (uses crate for
that), which also supports forced line breaks. The shaping is generic,
so on the MCU side we can do without at first.