From 13594b7146cc4791625280123a6071805a0be7c3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 28 Dec 2020 23:51:24 +0100 Subject: [PATCH] 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. :^) --- AK/Utf32View.h | 7 +++++++ AK/Utf8View.cpp | 2 +- AK/Utf8View.h | 7 ++++++- Libraries/LibGfx/Painter.cpp | 5 +++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/AK/Utf32View.h b/AK/Utf32View.h index 49b8efb13cc..95c8d29e123 100644 --- a/AK/Utf32View.h +++ b/AK/Utf32View.h @@ -105,6 +105,13 @@ public: bool is_empty() const { return m_length == 0; } 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 { if (length == 0) diff --git a/AK/Utf8View.cpp b/AK/Utf8View.cpp index 63ae61658d8..f43ee1b0cd4 100644 --- a/AK/Utf8View.cpp +++ b/AK/Utf8View.cpp @@ -65,7 +65,7 @@ Utf8CodepointIterator Utf8View::end() const 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 <= end_ptr()); diff --git a/AK/Utf8View.h b/AK/Utf8View.h index 5270addd4a9..bfb5d489b32 100644 --- a/AK/Utf8View.h +++ b/AK/Utf8View.h @@ -76,10 +76,15 @@ public: const unsigned char* bytes() const { return begin_ptr(); } 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; 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() const { diff --git a/Libraries/LibGfx/Painter.cpp b/Libraries/LibGfx/Painter.cpp index ca96ef068ba..70aa7ec77f1 100644 --- a/Libraries/LibGfx/Painter.cpp +++ b/Libraries/LibGfx/Painter.cpp @@ -918,7 +918,8 @@ void draw_text_line(const IntRect& a_rect, const TextType& text, const Font& fon int new_width = font.width("..."); if (new_width < text_width) { 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); // 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, @@ -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()) break; new_width += glyph_width + glyph_spacing; - offset++; + offset = text.iterator_offset(it); } apply_elision(final_text, elided_text, offset); }