From 2bc7c11e8d9c6aae561a9e34c6bcf9bc29fd9917 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 21 Feb 2023 07:50:41 -0500 Subject: [PATCH] LibGfx: Consult Unicode data to decode emoji sequences For example, consider the Pirate Flag emoji, which is the code point sequence U+1F3F4 U+200D U+2620 U+FE0F. Our current emoji resolution does not consider U+200D (Zero Width Joiner) as part of an emoji sequence. Therefore fonts like Katica, which have a glyph for U+1F3F4, will draw that glyph without checking if we have an emoji bitmap. This removes some hard-coded code points and consults the UCD's code point properties for emoji sequence components and variation selectors. This recognizes the ZWJ code point as part of an emoji sequence. --- Userland/Libraries/LibGfx/CMakeLists.txt | 2 +- Userland/Libraries/LibGfx/Painter.cpp | 30 ++++++++++-------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 3f5073ec8e..9e5ac10092 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -59,4 +59,4 @@ set(SOURCES ) serenity_lib(LibGfx gfx) -target_link_libraries(LibGfx PRIVATE LibCompress LibCore LibCrypto LibTextCodec LibIPC) +target_link_libraries(LibGfx PRIVATE LibCompress LibCore LibCrypto LibTextCodec LibIPC LibUnicode) diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index b7ee81fda1..ee85d60752 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #if defined(AK_COMPILER_GCC) @@ -1395,36 +1396,31 @@ void Painter::draw_glyph_or_emoji(FloatPoint point, u32 code_point, Font const& void Painter::draw_glyph_or_emoji(FloatPoint point, Utf8CodePointIterator& it, Font const& font, Color color) { - // FIXME: These should live somewhere else. - constexpr u32 text_variation_selector = 0xFE0E; - constexpr u32 emoji_variation_selector = 0xFE0F; - constexpr u32 regional_indicator_symbol_a = 0x1F1E6; - constexpr u32 regional_indicator_symbol_z = 0x1F1FF; + static auto const emoji_component_property = Unicode::property_from_string("Emoji_Component"sv); + static auto const variation_selector = Unicode::property_from_string("Variation_Selector"sv); - auto initial_it = it; u32 code_point = *it; auto next_code_point = it.peek(1); - ScopeGuard consume_variation_selector = [&] { + ScopeGuard consume_variation_selector = [&, initial_it = it] { // If we advanced the iterator to consume an emoji sequence, don't look for another variation selector. if (initial_it != it) return; + // Otherwise, discard one code point if it's a variation selector. - auto next_code_point = it.peek(1); - if (next_code_point == text_variation_selector || next_code_point == emoji_variation_selector) + if (next_code_point.has_value() && Unicode::code_point_has_property(*next_code_point, *variation_selector)) ++it; }; - auto code_point_is_regional_indicator = code_point >= regional_indicator_symbol_a && code_point <= regional_indicator_symbol_z; auto font_contains_glyph = font.contains_glyph(code_point); + auto check_for_emoji = false; - auto check_for_emoji = false - // Flag emojis consist of two regional indicators. - || code_point_is_regional_indicator - // U+00A9 (copyright) or U+00AE (registered) are text glyphs by default, - // keycap emojis ({#,*,0-9} U+FE0F U+20E3) start with a regular ASCII character. - // Both cases are handled by peeking for the variation selector. - || next_code_point == emoji_variation_selector; + if (emoji_component_property.has_value()) { + auto code_point_is_emoji_component = Unicode::code_point_has_property(code_point, *emoji_component_property); + auto next_code_point_is_emoji_component = next_code_point.has_value() && Unicode::code_point_has_property(*next_code_point, *emoji_component_property); + + check_for_emoji = code_point_is_emoji_component || next_code_point_is_emoji_component; + } // If the font contains the glyph, and we know it's not the start of an emoji, draw a text glyph. if (font_contains_glyph && !check_for_emoji) {