Open menoua opened 1 year ago
@hecrj @mtkennerly I have dug deeper into this since posting the issue and identified the root cause. I think it is upstream in glyphon
. FWIW, here's what I have found so far.
This happens because glyphon
(I'm assuming that's where the text rendering happens) renders all right-to-left text as right-aligned, regardless of the horizontal_alignment
value provided. That is the text is rendered from the rightmost end of the bounds
(bounds.x + bounds.width
) towards the left. Since TextInput
has bounds.width = infinity
, when you try to input RTL text into a TextInput, it tries to render the text at x = infinity
which obviously will never show up on screen. What is different now compared to when I opened the issue is that performing this action simply leads to a crash in glyphon
of "attempt to add with overflow" when trying to do math with infinity here.
Setting the bounds.width
value here to f32::max(text_width, text_bounds.width)
makes TextInput
work with LTR scripts without problem (so far as I can tell), and RTL scripts display correctly too, although making the cursor work properly in this case requires some additional tweaking. I'm not making a PR on this yet because I haven't found the time to work on the cursor stuff and text selection, but I'll keep looking into it.
https://github.com/iced-rs/iced/assets/39179450/ba417ae5-e173-4c25-bebf-87cee277718d
NOTE: the clipping at the end happens because renderer.measure_width
returns a width of zero for RTL text having again to do with bounds.x = infinity
. Setting bounds = Size {width: 1e6, height: 1e6}
instead of bounds = Size::INFINITY
in the measure_width
function makes it return a non-zero value, but this is an ugly solution.
This is also causing an even more serious issue with the regular Text
widget, because the bounds.x
value of text is updated here assuming the renderer will respect the horizontal_alignment
paramter. But because that doesn't happen for RTL text, the text is rendered completely out of bounds if any alignment other than Horizontal::Left
is provided. As you can see below, RTL left-aligned acts like LTR right-aligned, and the other RTLs are out of the specified widget width, because their bounds.x
is being moved to the right.
A downstream solution for this would be to update the bounds
parameter differently for different cases of alignment when the text is RTL, for example:
bounds.width = text_width;
let x = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x,
alignment::Horizontal::Center => bounds.center_x() - text_width / 2.0,
alignment::Horizontal::Right => bounds.x + bounds.width - text_width,
};
Since I didn't find a function within iced
or glyphon
that returns the direction of a language, I couldn't test it out (without adding an explicit direction parameter to text widgets). The Horizontal::Left
case works for both LTR and RTL however:
I'm not making a PR on this because I think it needs a fix upstream.
Is there an existing issue for this?
Is this issue related to iced?
What happened?
Thanks to #1830, regular
Text
widgets can handle complex scripts, including left-to-right (LTR), right-to-left (RTL), and mixed LTR/RTL. But this is only partially true for theTextInput
widget, such that complex scripts will be displayed properly only if the content of the text input starts with an LTR (alphabet) character. In other words, the content of text input is only displayed when the content should be aligned LTR.The screen capture below demonstrates the issue using the Todos example of the library, but this issue is reproducible with any
TextInput
instance. The video covers LTR, RTL, LTR->RTL, and RTL->LTR.https://github.com/iced-rs/iced/assets/39179450/899d857a-61bb-43d7-ab0c-63dc7941c82c
What is the expected behavior?
Ultimately, if the user input starts with an RTL (alphabet) character, the entire content should be displayed RTL and be right-aligned. However, since
TextInput
does not yet have horizontal text alignment support, a first step would be to just make the text show up, even if left-aligned.I don't have enough knowledge of text rendering or the internals of this library to pinpoint where the issue stems from and how to fix it. But I did try a couple of basic modifications to this function call:
Alignment::Left
toAlignment::Right
bounds.x
to a value expected byAlignment::Right
I also tried rendering with different values of
offset
withrenderer.with_translation(...)
. None of my attempts so far has made the missing text appear.I would be happy to look into fixing the issue if someone can point me to the potential location of the issue in the codebase.
Version
master
Operative System
macOS
Do you have any log output?
No response