diff --git a/Userland/Libraries/LibGUI/AbstractView.cpp b/Userland/Libraries/LibGUI/AbstractView.cpp index ca6692c8f4..5c069ce8bf 100644 --- a/Userland/Libraries/LibGUI/AbstractView.cpp +++ b/Userland/Libraries/LibGUI/AbstractView.cpp @@ -569,9 +569,9 @@ void AbstractView::keydown_event(KeyEvent& event) if (is_searchable()) { if (event.key() == KeyCode::Key_Backspace) { if (!m_highlighted_search.is_null()) { - //if (event.modifiers() == Mod_Ctrl) { - // TODO: delete last word - //} + // if (event.modifiers() == Mod_Ctrl) { + // TODO: delete last word + // } Utf8View view(m_highlighted_search); size_t n_code_points = view.length(); if (n_code_points > 1) { @@ -704,7 +704,7 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index // Highlight the text background first auto background_searching_length = searching_length; - painter.draw_text([&](Gfx::IntRect const& rect, u32) { + painter.draw_text([&](Gfx::IntRect const& rect, Utf8CodePointIterator&) { if (background_searching_length > 0) { background_searching_length--; painter.fill_rect(rect.inflated(0, 2), palette().highlight_searching()); @@ -716,12 +716,12 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index auto text_searching_length = searching_length; auto highlight_text_color = palette().highlight_searching_text(); searching_length = searching_text.length(); - painter.draw_text([&](Gfx::IntRect const& rect, u32 code_point) { + painter.draw_text([&](Gfx::IntRect const& rect, Utf8CodePointIterator& it) { if (text_searching_length > 0) { text_searching_length--; - painter.draw_glyph_or_emoji(rect.location(), code_point, font, highlight_text_color); + painter.draw_glyph_or_emoji(rect.location(), it, font, highlight_text_color); } else { - painter.draw_glyph_or_emoji(rect.location(), code_point, font, text_color); + painter.draw_glyph_or_emoji(rect.location(), it, font, text_color); } }, text_rect, item_text, font, alignment, elision); diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index b7b13af879..38f14d39c1 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -4,6 +4,7 @@ * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2021, Sam Atkins * Copyright (c) 2022, Tobias Christiansen + * Copyright (c) 2022, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ @@ -1240,20 +1241,31 @@ void Painter::draw_emoji(IntPoint const& point, Gfx::Bitmap const& emoji, Font c void Painter::draw_glyph_or_emoji(IntPoint const& point, u32 code_point, Font const& font, Color color) { + StringBuilder builder; + builder.append_code_point(code_point); + auto it = Utf8View { builder.string_view() }.begin(); + return draw_glyph_or_emoji(point, it, font, color); +} + +void Painter::draw_glyph_or_emoji(IntPoint const& point, Utf8CodePointIterator& it, Font const& font, Color color) +{ + // FIXME: Handle variation selectors. Additionally, some emojis start with a 'regular' character, + // so the 'font contains' check isn't sufficient for all of them - we'll have to peek. + + u32 code_point = *it; + if (font.contains_glyph(code_point)) { draw_glyph(point, code_point, font, color); return; } - // Perhaps it's an emoji? - auto* emoji = Emoji::emoji_for_code_point(code_point); - if (emoji == nullptr) { - dbgln_if(EMOJI_DEBUG, "Failed to find an emoji for code_point {}", code_point); - draw_glyph(point, 0xFFFD, font, color); + if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) { + draw_emoji(point, *emoji, font); return; } - draw_emoji(point, *emoji, font); + dbgln_if(EMOJI_DEBUG, "Failed to find a glyph or emoji for code_point {}", code_point); + draw_glyph(point, 0xFFFD, font, color); } template @@ -1295,7 +1307,8 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon space_width = -space_width; // Draw spaces backwards } - for (u32 code_point : text) { + for (auto it = text.begin(); it != text.end(); ++it) { + auto code_point = *it; if (code_point == ' ') { point.translate_by(space_width, 0); continue; @@ -1303,9 +1316,12 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon IntSize glyph_size(font.glyph_or_emoji_width(code_point) + font.glyph_spacing(), font.glyph_height()); 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 }, code_point); + draw_glyph({ point, glyph_size }, it); if (direction == TextDirection::LTR) point.translate_by(glyph_size.width(), 0); + // The callback function might have exhausted the iterator. + if (it == text.end()) + break; } } @@ -1558,8 +1574,8 @@ void Painter::draw_text(IntRect const& rect, Utf32View const& text, TextAlignmen void Painter::draw_text(IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) { Utf8View text { raw_text }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, u32 code_point) { - draw_glyph_or_emoji(r.location(), code_point, font, color); + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { + draw_glyph_or_emoji(r.location(), it, font, color); }); } @@ -1570,31 +1586,31 @@ void Painter::draw_text(IntRect const& rect, Utf32View const& raw_text, Font con StringBuilder builder; builder.append(raw_text); auto text = Utf8View { builder.string_view() }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, u32 code_point) { - draw_glyph_or_emoji(r.location(), code_point, font, color); + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { + draw_glyph_or_emoji(r.location(), it, font, color); }); } -void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) +void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) { VERIFY(scale() == 1); // FIXME: Add scaling support. - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, u32 code_point) { - draw_one_glyph(r, code_point); + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); }); } -void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) +void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) { VERIFY(scale() == 1); // FIXME: Add scaling support. Utf8View text { raw_text }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, u32 code_point) { - draw_one_glyph(r, code_point); + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); }); } -void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) +void Painter::draw_text(Function draw_one_glyph, IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) { VERIFY(scale() == 1); // FIXME: Add scaling support. @@ -1603,8 +1619,8 @@ void Painter::draw_text(Function draw_one_glyph, IntR StringBuilder builder; builder.append(raw_text); auto text = Utf8View { builder.string_view() }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, u32 code_point) { - draw_one_glyph(r, code_point); + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); }); } diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index e95be51324..2e23b63e9f 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -75,14 +76,15 @@ public: void draw_text(IntRect const&, StringView, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); void draw_text(IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); void draw_text(IntRect const&, Utf32View const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); - void draw_text(Function, IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); - void draw_text(Function, IntRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); - void draw_text(Function, IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, IntRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); void draw_ui_text(Gfx::IntRect const&, StringView, Gfx::Font const&, TextAlignment, Gfx::Color); void draw_glyph(IntPoint const&, u32, Color); void draw_glyph(IntPoint const&, u32, Font const&, Color); void draw_emoji(IntPoint const&, Gfx::Bitmap const&, Font const&); - void draw_glyph_or_emoji(IntPoint const&, u32 code_point, Font const&, Color); + void draw_glyph_or_emoji(IntPoint const&, u32, Font const&, Color); + void draw_glyph_or_emoji(IntPoint const&, Utf8CodePointIterator&, Font const&, Color); void draw_circle_arc_intersecting(IntRect const&, IntPoint const&, int radius, Color, int thickness); enum class CornerOrientation {