Преглед на файлове

LibGfx: Consider multi-code point glyphs when computing text width

Currently, we compute the width of text one code point at a time. This
ignores grapheme clusters (emoji in particular). One effect of this is
when highlighting a multi-code point emoji. We will errantly increase
the highlight rect to the sum of all code point widths, rather than
just the width of the resolved emoji bitmap.
Timothy Flynn преди 2 години
родител
ревизия
b823f3d29f
променени са 3 файла, в които са добавени 13 реда и са изтрити 8 реда
  1. 6 2
      Userland/Libraries/LibGfx/Font/BitmapFont.cpp
  2. 6 4
      Userland/Libraries/LibGfx/Painter.cpp
  3. 1 2
      Userland/Libraries/LibGfx/TextLayout.cpp

+ 6 - 2
Userland/Libraries/LibGfx/Font/BitmapFont.cpp

@@ -357,7 +357,9 @@ ALWAYS_INLINE int BitmapFont::unicode_view_width(T const& view) const
     int width = 0;
     int longest_width = 0;
 
-    for (u32 code_point : view) {
+    for (auto it = view.begin(); it != view.end(); ++it) {
+        auto code_point = *it;
+
         if (code_point == '\n' || code_point == '\r') {
             first = true;
             longest_width = max(width, longest_width);
@@ -367,8 +369,10 @@ ALWAYS_INLINE int BitmapFont::unicode_view_width(T const& view) const
         if (!first)
             width += glyph_spacing();
         first = false;
-        width += glyph_or_emoji_width(code_point);
+
+        width += glyph_or_emoji_width(it);
     }
+
     longest_width = max(width, longest_width);
     return longest_width;
 }

+ 6 - 4
Userland/Libraries/LibGfx/Painter.cpp

@@ -1518,7 +1518,9 @@ void draw_text_line(FloatRect const& a_rect, Utf8View const& text, Font const& f
         if (kerning != 0.0f)
             point.translate_by(direction == TextDirection::LTR ? kerning : -kerning, 0);
 
-        FloatSize glyph_size(font.glyph_or_emoji_width(code_point) + font.glyph_spacing(), font.pixel_size());
+        auto it_copy = it; // The callback function will advance the iterator, so create a copy for this lookup.
+        FloatSize glyph_size(font.glyph_or_emoji_width(it_copy) + font.glyph_spacing(), font.pixel_size());
+
         if (direction == TextDirection::RTL)
             point.translate_by(-glyph_size.width(), 0); // If we are drawing right to left, we have to move backwards before drawing the glyph
         draw_glyph({ point, glyph_size }, it);
@@ -2480,11 +2482,11 @@ void Gfx::Painter::draw_ui_text(Gfx::IntRect const& rect, StringView text, Gfx::
             if (utf8_view.byte_offset_of(it) >= underline_offset.value()) {
                 int y = text_rect.bottom() + 1;
                 int x1 = text_rect.left() + width;
-                int x2 = x1 + font.glyph_or_emoji_width(*it);
+                int x2 = x1 + font.glyph_or_emoji_width(it);
                 draw_line({ x1, y }, { x2, y }, color);
                 break;
             }
-            width += font.glyph_or_emoji_width(*it) + font.glyph_spacing();
+            width += font.glyph_or_emoji_width(it) + font.glyph_spacing();
         }
     }
 }
@@ -2514,7 +2516,7 @@ void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, F
         // FIXME: this is probably not the real space taken for complex emojis
         x += font.glyphs_horizontal_kerning(last_code_point, code_point);
         draw_glyph_or_emoji(FloatPoint { x, y }, code_point_iterator, font, color);
-        x += font.glyph_or_emoji_width(code_point) + font.glyph_spacing();
+        x += font.glyph_or_emoji_width(code_point_iterator) + font.glyph_spacing();
         last_code_point = code_point;
     }
 }

+ 1 - 2
Userland/Libraries/LibGfx/TextLayout.cpp

@@ -171,8 +171,7 @@ DeprecatedString TextLayout::elide_text_from_right(Utf8View text) const
         if (ellipsis_width < text_width) {
             size_t offset = 0;
             for (auto it = text.begin(); !it.done(); ++it) {
-                auto code_point = *it;
-                auto glyph_width = m_font.glyph_or_emoji_width(code_point);
+                auto glyph_width = m_font.glyph_or_emoji_width(it);
                 // 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,
                 //       we don't have to worry about spacing.