From a391ea3da3f555d63e4d6aaffa3ec4d8e664ede1 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 20 Feb 2023 14:40:12 -0500 Subject: [PATCH] LibGfx: Support computing a font's glyph width with code point iterators This allows consideration of multi-code point glyphs. --- Userland/Libraries/LibGfx/Font/BitmapFont.cpp | 41 ++++++++++++------- Userland/Libraries/LibGfx/Font/BitmapFont.h | 11 ++--- Userland/Libraries/LibGfx/Font/Font.h | 2 + Userland/Libraries/LibGfx/Font/ScaledFont.cpp | 12 ++++++ Userland/Libraries/LibGfx/Font/ScaledFont.h | 2 + 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Userland/Libraries/LibGfx/Font/BitmapFont.cpp b/Userland/Libraries/LibGfx/Font/BitmapFont.cpp index fbaa81a8e5..14e22ed0e3 100644 --- a/Userland/Libraries/LibGfx/Font/BitmapFont.cpp +++ b/Userland/Libraries/LibGfx/Font/BitmapFont.cpp @@ -314,23 +314,34 @@ float BitmapFont::glyph_width(u32 code_point) const return m_fixed_width || !index.has_value() ? m_glyph_width : m_glyph_widths[index.value()]; } -int BitmapFont::glyph_or_emoji_width_for_variable_width_font(u32 code_point) const +template +static float glyph_or_emoji_width_impl(BitmapFont const& font, CodePointIterator& it) { - // FIXME: This is a hack in lieu of proper code point identification. - // 0xFFFF is arbitrary but also the end of the Basic Multilingual Plane. - if (code_point < 0xFFFF) { - auto index = glyph_index(code_point); - if (!index.has_value()) - return glyph_width(0xFFFD); - if (m_glyph_widths[index.value()] > 0) - return glyph_width(code_point); - return glyph_width(0xFFFD); - } + if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) + return font.pixel_size() * emoji->width() / emoji->height(); - auto const* emoji = Emoji::emoji_for_code_point(code_point); - if (emoji == nullptr) - return glyph_width(0xFFFD); - return glyph_height() * emoji->width() / emoji->height(); + if (font.is_fixed_width()) + return font.glyph_fixed_width(); + + return font.glyph_width(*it); +} + +float BitmapFont::glyph_or_emoji_width(u32 code_point) const +{ + Utf32View code_point_view { &code_point, 1 }; + auto it = code_point_view.begin(); + + return glyph_or_emoji_width_impl(*this, it); +} + +float BitmapFont::glyph_or_emoji_width(Utf8CodePointIterator& it) const +{ + return glyph_or_emoji_width_impl(*this, it); +} + +float BitmapFont::glyph_or_emoji_width(Utf32CodePointIterator& it) const +{ + return glyph_or_emoji_width_impl(*this, it); } float BitmapFont::width(StringView view) const { return unicode_view_width(Utf8View(view)); } diff --git a/Userland/Libraries/LibGfx/Font/BitmapFont.h b/Userland/Libraries/LibGfx/Font/BitmapFont.h index 62c22871d8..b786ef6b13 100644 --- a/Userland/Libraries/LibGfx/Font/BitmapFont.h +++ b/Userland/Libraries/LibGfx/Font/BitmapFont.h @@ -61,12 +61,10 @@ public: bool contains_glyph(u32 code_point) const override; bool contains_raw_glyph(u32 code_point) const { return m_glyph_widths[code_point] > 0; } - virtual float glyph_or_emoji_width(u32 code_point) const override - { - if (m_fixed_width) - return m_glyph_width; - return glyph_or_emoji_width_for_variable_width_font(code_point); - } + virtual float glyph_or_emoji_width(u32) const override; + virtual float glyph_or_emoji_width(Utf8CodePointIterator&) const override; + virtual float glyph_or_emoji_width(Utf32CodePointIterator&) const override; + float glyphs_horizontal_kerning(u32, u32) const override { return 0.f; } u8 glyph_height() const override { return m_glyph_height; } int x_height() const override { return m_x_height; } @@ -138,7 +136,6 @@ private: int unicode_view_width(T const& view) const; void update_x_height() { m_x_height = m_baseline - m_mean_line; }; - int glyph_or_emoji_width_for_variable_width_font(u32 code_point) const; DeprecatedString m_name; DeprecatedString m_family; diff --git a/Userland/Libraries/LibGfx/Font/Font.h b/Userland/Libraries/LibGfx/Font/Font.h index 40ca2ac92a..ce3575010d 100644 --- a/Userland/Libraries/LibGfx/Font/Font.h +++ b/Userland/Libraries/LibGfx/Font/Font.h @@ -168,6 +168,8 @@ public: virtual float glyph_left_bearing(u32 code_point) const = 0; virtual float glyph_width(u32 code_point) const = 0; virtual float glyph_or_emoji_width(u32 code_point) const = 0; + virtual float glyph_or_emoji_width(Utf8CodePointIterator&) const = 0; + virtual float glyph_or_emoji_width(Utf32CodePointIterator&) const = 0; virtual float glyphs_horizontal_kerning(u32 left_code_point, u32 right_code_point) const = 0; virtual u8 glyph_height() const = 0; virtual int x_height() const = 0; diff --git a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp index 9cb6fdf37c..ad94ce7d1c 100644 --- a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp +++ b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp @@ -105,6 +105,18 @@ float ScaledFont::glyph_or_emoji_width(u32 code_point) const return metrics.advance_width; } +float ScaledFont::glyph_or_emoji_width(Utf8CodePointIterator& it) const +{ + // FIXME: Support multi-code point emoji with scaled fonts. + return glyph_or_emoji_width(*it); +} + +float ScaledFont::glyph_or_emoji_width(Utf32CodePointIterator& it) const +{ + // FIXME: Support multi-code point emoji with scaled fonts. + return glyph_or_emoji_width(*it); +} + float ScaledFont::glyphs_horizontal_kerning(u32 left_code_point, u32 right_code_point) const { if (left_code_point == 0 || right_code_point == 0) diff --git a/Userland/Libraries/LibGfx/Font/ScaledFont.h b/Userland/Libraries/LibGfx/Font/ScaledFont.h index b0f4f9f17b..f88a36937f 100644 --- a/Userland/Libraries/LibGfx/Font/ScaledFont.h +++ b/Userland/Libraries/LibGfx/Font/ScaledFont.h @@ -47,6 +47,8 @@ public: virtual bool contains_glyph(u32 code_point) const override { return m_font->glyph_id_for_code_point(code_point) > 0; } virtual float glyph_width(u32 code_point) const override; virtual float glyph_or_emoji_width(u32 code_point) const override; + virtual float glyph_or_emoji_width(Utf8CodePointIterator&) const override; + virtual float glyph_or_emoji_width(Utf32CodePointIterator&) const override; virtual float glyphs_horizontal_kerning(u32 left_code_point, u32 right_code_point) const override; virtual float preferred_line_height() const override { return metrics().height() + metrics().line_gap; } virtual u8 glyph_height() const override { return pixel_size(); }