LibGfx+AK: Make text elision work with multi-byte characters

This was causing WindowServer and Taskbar to crash sometimes when the
stars aligned and we tried cutting off a string ending with "..." right
on top of an emoji. :^)
This commit is contained in:
Andreas Kling 2020-12-28 23:51:24 +01:00
parent 9af33e2e4b
commit 13594b7146
Notes: sideshowbarker 2024-07-19 00:28:56 +09:00
4 changed files with 17 additions and 4 deletions

View file

@ -105,6 +105,13 @@ public:
bool is_empty() const { return m_length == 0; } bool is_empty() const { return m_length == 0; }
size_t length() const { return m_length; } size_t length() const { return m_length; }
size_t iterator_offset(const Utf32CodepointIterator& it) const
{
ASSERT(it.m_ptr >= m_code_points);
ASSERT(it.m_ptr < m_code_points + m_length);
return ((ptrdiff_t)it.m_ptr - (ptrdiff_t)m_code_points) / sizeof(u32);
}
Utf32View substring_view(size_t offset, size_t length) const Utf32View substring_view(size_t offset, size_t length) const
{ {
if (length == 0) if (length == 0)

View file

@ -65,7 +65,7 @@ Utf8CodepointIterator Utf8View::end() const
return { end_ptr(), 0 }; return { end_ptr(), 0 };
} }
int Utf8View::byte_offset_of(const Utf8CodepointIterator& it) const size_t Utf8View::byte_offset_of(const Utf8CodepointIterator& it) const
{ {
ASSERT(it.m_ptr >= begin_ptr()); ASSERT(it.m_ptr >= begin_ptr());
ASSERT(it.m_ptr <= end_ptr()); ASSERT(it.m_ptr <= end_ptr());

View file

@ -76,10 +76,15 @@ public:
const unsigned char* bytes() const { return begin_ptr(); } const unsigned char* bytes() const { return begin_ptr(); }
int byte_length() const { return m_string.length(); } int byte_length() const { return m_string.length(); }
int byte_offset_of(const Utf8CodepointIterator&) const; size_t byte_offset_of(const Utf8CodepointIterator&) const;
Utf8View substring_view(int byte_offset, int byte_length) const; Utf8View substring_view(int byte_offset, int byte_length) const;
bool is_empty() const { return m_string.is_empty(); } bool is_empty() const { return m_string.is_empty(); }
size_t iterator_offset(const Utf8CodepointIterator& it) const
{
return byte_offset_of(it);
}
bool validate(size_t& valid_bytes) const; bool validate(size_t& valid_bytes) const;
bool validate() const bool validate() const
{ {

View file

@ -918,7 +918,8 @@ void draw_text_line(const IntRect& a_rect, const TextType& text, const Font& fon
int new_width = font.width("..."); int new_width = font.width("...");
if (new_width < text_width) { if (new_width < text_width) {
size_t offset = 0; size_t offset = 0;
for (auto code_point : text) { for (auto it = text.begin(); it != text.end(); ++it) {
auto code_point = *it;
int glyph_width = font.glyph_or_emoji_width(code_point); int glyph_width = font.glyph_or_emoji_width(code_point);
// NOTE: Glyph spacing should not be added after the last glyph on the line, // NOTE: Glyph spacing should not be added after the last glyph on the line,
// but since we are here because the last glyph does not actually fit on the line, // but since we are here because the last glyph does not actually fit on the line,
@ -927,7 +928,7 @@ void draw_text_line(const IntRect& a_rect, const TextType& text, const Font& fon
if (width_with_this_glyph_included > rect.width()) if (width_with_this_glyph_included > rect.width())
break; break;
new_width += glyph_width + glyph_spacing; new_width += glyph_width + glyph_spacing;
offset++; offset = text.iterator_offset(it);
} }
apply_elision(final_text, elided_text, offset); apply_elision(final_text, elided_text, offset);
} }