When clicking in a TextEditor to position the caret, the caret would be
placed at the penultimate position when clicking at the end of a line
with trailing non-newline whitespaces.
Co-authored-by: Aga Janowicz <aga@roli.com>
Newlines get removed in the sanitised string, so we need to take extra
steps to keep track of their positions.
Co-authored-by: Aga Janowicz <aga@roli.com>
This is intended to address an assertion that sometimes fired during
shaping text on Android, for example when using the font "Noto Sans
Symbols" and shaping ASCII text including a line break in a multiline
text editor.
The cause of the issue seems to be that the shaper would search for
substitute fonts using the original string content, but would then
replace some characters in the string during shaping. Shaping could then
fail if the font did not contain glyphs for the replaced characters.
We now create a UTF32 string with replaced characters at the beginning
of the shaping process, and use that new string for all queries other
than unicode analysis.
This commit removes the possibility to construct BidiParagraph and
BidiLine objects with non-zero offsets. We don't use these features,
and the assumption that these offsets are always zero simplifies our
visual ordering algorithm.
Prior to this commit we overallocated the s32 buffer. The buffer was
unnecessarily padded by zeros, and the line stating this, wasn't
actually dropping the null terminator.
Applies the previously missed line spacing value of the TextEditor.
The changes in JustifiedText fix calculating the vertical position of
the first line for the case where ShapedTextOptions has the following
settings:
isBaselineAtZero() == false,
getHeight().has_value() == false
getLeading() > 1.0f
This case however is only triggered by the TextEditor, as with all
functions in GlyphArrangement at least one setting is different.
This change also fixes bad access that could happen with \r\n
line terminators. An incorrectly sized buffer meant that \n was
clobbered by the null terminator.
With this change you can use makeIntersectingRangedValues() not just for
RangedValues objects, but any object that has a begin() and end()
function returning a RangedValuesIterator.
Previously using the FontForRange type was motivated by hiding the
RangedValues type in case we wanted to expose the ShapedText API. This
introduced unnecessary conversions between FontForRange and
RangedValues<Font>.
Since the original function template has been exposed, we can now use it
directly. Also ShapedText::Detail has been removed, because it wouldn't
work across module boundaries.