From a1726b1ba5aa6d19949f682936b3ee95b368a370 Mon Sep 17 00:00:00 2001 From: MacDue Date: Sun, 1 Jan 2023 19:42:00 +0100 Subject: [PATCH] LibGfx: Avoid rounding/truncating glyph positions till blitting This keeps some overloads that accept ints to avoid adding calls to .to_type() all over the place. --- Userland/Applets/Audio/main.cpp | 2 +- .../Applications/PixelPaint/ImageEditor.cpp | 4 +- .../PixelPaint/Tools/TextTool.cpp | 2 +- .../SystemMonitor/NetworkStatisticsWidget.cpp | 2 +- .../Applications/Welcome/WelcomeWidget.cpp | 6 +- Userland/Demos/LibGfxDemo/main.cpp | 26 +-- Userland/Libraries/LibCards/CardPainter.cpp | 2 +- Userland/Libraries/LibGUI/AbstractView.cpp | 6 +- Userland/Libraries/LibGUI/Label.cpp | 2 +- Userland/Libraries/LibGfx/Painter.cpp | 171 ++++++++++++------ Userland/Libraries/LibGfx/Painter.h | 19 +- Userland/Libraries/LibGfx/TextLayout.cpp | 22 +-- Userland/Libraries/LibGfx/TextLayout.h | 10 +- Userland/Services/WindowServer/Overlays.cpp | 4 +- 14 files changed, 172 insertions(+), 106 deletions(-) diff --git a/Userland/Applets/Audio/main.cpp b/Userland/Applets/Audio/main.cpp index c45bb1a4dc..a217edde68 100644 --- a/Userland/Applets/Audio/main.cpp +++ b/Userland/Applets/Audio/main.cpp @@ -170,7 +170,7 @@ private: if (m_show_percent) { auto volume_text = m_audio_muted ? "mute" : DeprecatedString::formatted("{}%", m_audio_volume); - painter.draw_text({ 16, 3, 24, 16 }, volume_text, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::TopLeft, palette().window_text()); + painter.draw_text(Gfx::IntRect { 16, 3, 24, 16 }, volume_text, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::TopLeft, palette().window_text()); } } diff --git a/Userland/Applications/PixelPaint/ImageEditor.cpp b/Userland/Applications/PixelPaint/ImageEditor.cpp index 2599f752f4..d8a91da810 100644 --- a/Userland/Applications/PixelPaint/ImageEditor.cpp +++ b/Userland/Applications/PixelPaint/ImageEditor.cpp @@ -217,7 +217,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event) int const editor_x = content_to_frame_position({ x, 0 }).x(); painter.draw_line({ editor_x, 0 }, { editor_x, m_ruler_thickness }, ruler_fg_color); - painter.draw_text({ { editor_x + 2, 0 }, { m_ruler_thickness, m_ruler_thickness - 2 } }, DeprecatedString::formatted("{}", x), painter.font(), Gfx::TextAlignment::CenterLeft, ruler_text_color); + painter.draw_text(Gfx::IntRect { { editor_x + 2, 0 }, { m_ruler_thickness, m_ruler_thickness - 2 } }, DeprecatedString::formatted("{}", x), painter.font(), Gfx::TextAlignment::CenterLeft, ruler_text_color); } // Vertical ruler @@ -234,7 +234,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event) int const editor_y = content_to_frame_position({ 0, y }).y(); painter.draw_line({ 0, editor_y }, { m_ruler_thickness, editor_y }, ruler_fg_color); - painter.draw_text({ { 0, editor_y - m_ruler_thickness }, { m_ruler_thickness, m_ruler_thickness } }, DeprecatedString::formatted("{}", y), painter.font(), Gfx::TextAlignment::BottomRight, ruler_text_color); + painter.draw_text(Gfx::IntRect { { 0, editor_y - m_ruler_thickness }, { m_ruler_thickness, m_ruler_thickness } }, DeprecatedString::formatted("{}", y), painter.font(), Gfx::TextAlignment::BottomRight, ruler_text_color); } // Mouse position indicator diff --git a/Userland/Applications/PixelPaint/Tools/TextTool.cpp b/Userland/Applications/PixelPaint/Tools/TextTool.cpp index d30fdd439c..a8dfd8df6d 100644 --- a/Userland/Applications/PixelPaint/Tools/TextTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/TextTool.cpp @@ -142,7 +142,7 @@ void TextTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event) auto text_bitmap = text_bitmap_result.release_value(); auto text_painter = GUI::Painter(text_bitmap); text_painter.set_font(*m_selected_font); - text_painter.draw_text({ 0, 0, text_width, text_height }, typed_text, Gfx::TextAlignment::TopLeft, m_text_color); + text_painter.draw_text(Gfx::IntRect { 0, 0, text_width, text_height }, typed_text, Gfx::TextAlignment::TopLeft, m_text_color); m_text_editor->update(); diff --git a/Userland/Applications/SystemMonitor/NetworkStatisticsWidget.cpp b/Userland/Applications/SystemMonitor/NetworkStatisticsWidget.cpp index 3b422b6ef0..057fbf1978 100644 --- a/Userland/Applications/SystemMonitor/NetworkStatisticsWidget.cpp +++ b/Userland/Applications/SystemMonitor/NetworkStatisticsWidget.cpp @@ -32,7 +32,7 @@ NetworkStatisticsWidget::NetworkStatisticsWidget() m_network_link_down_bitmap = Gfx::Bitmap::try_create(m_network_connected_bitmap->format(), m_network_connected_bitmap->size()).release_value_but_fixme_should_propagate_errors(); { Gfx::Painter painter(*m_network_link_down_bitmap); - painter.blit_filtered({}, *m_network_connected_bitmap, m_network_connected_bitmap->rect(), [](Color color) { + painter.blit_filtered(Gfx::IntPoint {}, *m_network_connected_bitmap, m_network_connected_bitmap->rect(), [](Color color) { return color.to_grayscale(); }); } diff --git a/Userland/Applications/Welcome/WelcomeWidget.cpp b/Userland/Applications/Welcome/WelcomeWidget.cpp index 0078ab8c9b..85cd69aba8 100644 --- a/Userland/Applications/Welcome/WelcomeWidget.cpp +++ b/Userland/Applications/Welcome/WelcomeWidget.cpp @@ -109,7 +109,7 @@ void WelcomeWidget::paint_event(GUI::PaintEvent& event) painter.add_clip_rect(event.rect()); static auto font = Gfx::BitmapFont::load_from_file("/res/fonts/MarietaRegular24.font"sv); - painter.draw_text({ 12, 4, 1, 30 }, "Welcome to "sv, *font, Gfx::TextAlignment::CenterLeft, palette().base_text()); - painter.draw_text({ 12 + static_cast(ceilf(font->width("Welcome to "sv))), 4, 1, 30 }, "Serenity"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base_text()); - painter.draw_text({ 12 + static_cast(ceilf(font->width("Welcome to "sv))) + static_cast(ceilf(font->bold_variant().width("Serenity"sv))), 4, 1, 30 }, "OS"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base() == palette().window() ? palette().base_text() : palette().base()); + painter.draw_text(Gfx::IntRect { 12, 4, 1, 30 }, "Welcome to "sv, *font, Gfx::TextAlignment::CenterLeft, palette().base_text()); + painter.draw_text(Gfx::IntRect { 12 + static_cast(ceilf(font->width("Welcome to "sv))), 4, 1, 30 }, "Serenity"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base_text()); + painter.draw_text(Gfx::IntRect { 12 + static_cast(ceilf(font->width("Welcome to "sv))) + static_cast(ceilf(font->bold_variant().width("Serenity"sv))), 4, 1, 30 }, "OS"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base() == palette().window() ? palette().base_text() : palette().base()); } diff --git a/Userland/Demos/LibGfxDemo/main.cpp b/Userland/Demos/LibGfxDemo/main.cpp index a72885c441..b6b0cfa3fa 100644 --- a/Userland/Demos/LibGfxDemo/main.cpp +++ b/Userland/Demos/LibGfxDemo/main.cpp @@ -135,26 +135,26 @@ void Canvas::draw() painter.draw_rect({ 20, 260, 480, 320 }, Color::DarkGray); painter.draw_rect({ 520, 260, 240, 80 }, Color::DarkGray); - painter.draw_text({ 520, 260, 240, 80 }, "CenterLeft"sv, Gfx::TextAlignment::CenterLeft, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "Center"sv, Gfx::TextAlignment::Center, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "CenterRight"sv, Gfx::TextAlignment::CenterRight, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "TopLeft"sv, Gfx::TextAlignment::TopLeft, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "TopRight"sv, Gfx::TextAlignment::TopRight, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "BottomLeft"sv, Gfx::TextAlignment::BottomLeft, Color::White); - painter.draw_text({ 520, 260, 240, 80 }, "BottomRight"sv, Gfx::TextAlignment::BottomRight, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "CenterLeft"sv, Gfx::TextAlignment::CenterLeft, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "Center"sv, Gfx::TextAlignment::Center, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "CenterRight"sv, Gfx::TextAlignment::CenterRight, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "TopLeft"sv, Gfx::TextAlignment::TopLeft, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "TopRight"sv, Gfx::TextAlignment::TopRight, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "BottomLeft"sv, Gfx::TextAlignment::BottomLeft, Color::White); + painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "BottomRight"sv, Gfx::TextAlignment::BottomRight, Color::White); painter.draw_rect({ 520, 360, 240, 30 }, Color::DarkGray); - painter.draw_text({ 520, 360, 240, 30 }, "Emojis! 🙂😂🐞🦄"sv, Gfx::TextAlignment::Center, Color::White); + painter.draw_text(Gfx::IntRect { 520, 360, 240, 30 }, "Emojis! 🙂😂🐞🦄"sv, Gfx::TextAlignment::Center, Color::White); painter.draw_rect({ 520, 410, 240, 80 }, Color::DarkGray); - painter.draw_text({ 520, 415, 240, 20 }, "Normal text"sv, Gfx::FontDatabase::default_font(), Gfx::TextAlignment::CenterLeft, Color::Red); - painter.draw_text({ 520, 430, 240, 20 }, "Bold text"sv, Gfx::FontDatabase::default_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Green); - painter.draw_text({ 520, 450, 240, 20 }, "Normal text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::CenterLeft, Color::Blue); - painter.draw_text({ 520, 465, 240, 20 }, "Bold text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Yellow); + painter.draw_text(Gfx::IntRect { 520, 415, 240, 20 }, "Normal text"sv, Gfx::FontDatabase::default_font(), Gfx::TextAlignment::CenterLeft, Color::Red); + painter.draw_text(Gfx::IntRect { 520, 430, 240, 20 }, "Bold text"sv, Gfx::FontDatabase::default_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Green); + painter.draw_text(Gfx::IntRect { 520, 450, 240, 20 }, "Normal text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::CenterLeft, Color::Blue); + painter.draw_text(Gfx::IntRect { 520, 465, 240, 20 }, "Bold text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Yellow); auto font = Gfx::BitmapFont::load_from_file("/res/fonts/PebbletonBold14.font"sv); painter.draw_rect({ 520, 510, 240, 30 }, Color::DarkGray); - painter.draw_text({ 520, 510, 240, 30 }, "Hello friends! :^)"sv, *font, Gfx::TextAlignment::Center, Color::White); + painter.draw_text(Gfx::IntRect { 520, 510, 240, 30 }, "Hello friends! :^)"sv, *font, Gfx::TextAlignment::Center, Color::White); painter.fill_rect({ 520, 560, 10, 20 }, Color::White); painter.fill_rect({ 530, 560, 10, 20 }, Color::WarmGray); diff --git a/Userland/Libraries/LibCards/CardPainter.cpp b/Userland/Libraries/LibCards/CardPainter.cpp index 8ac0aa5a2b..c2c869617a 100644 --- a/Userland/Libraries/LibCards/CardPainter.cpp +++ b/Userland/Libraries/LibCards/CardPainter.cpp @@ -207,7 +207,7 @@ void CardPainter::paint_inverted_card(Gfx::Bitmap& bitmap, Gfx::Bitmap const& so { Gfx::Painter painter { bitmap }; painter.clear_rect(bitmap.rect(), Gfx::Color::Transparent); - painter.blit_filtered({ 0, 0 }, source_to_invert, source_to_invert.rect(), [&](Color color) { + painter.blit_filtered(Gfx::IntPoint {}, source_to_invert, source_to_invert.rect(), [&](Color color) { return color.inverted(); }); } diff --git a/Userland/Libraries/LibGUI/AbstractView.cpp b/Userland/Libraries/LibGUI/AbstractView.cpp index b267a8f861..ddb6752625 100644 --- a/Userland/Libraries/LibGUI/AbstractView.cpp +++ b/Userland/Libraries/LibGUI/AbstractView.cpp @@ -727,10 +727,10 @@ 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, Utf8CodePointIterator&) { + painter.draw_text([&](Gfx::FloatRect const& rect, Utf8CodePointIterator&) { if (background_searching_length > 0) { background_searching_length--; - painter.fill_rect(rect.inflated(0, 2), palette().highlight_searching()); + painter.fill_rect(rect.to_type().inflated(0, 2), palette().highlight_searching()); } }, text_rect, item_text, font, alignment, elision); @@ -739,7 +739,7 @@ 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, Utf8CodePointIterator& it) { + painter.draw_text([&](auto const& rect, Utf8CodePointIterator& it) { if (text_searching_length > 0) { text_searching_length--; painter.draw_glyph_or_emoji(rect.location(), it, font, highlight_text_color); diff --git a/Userland/Libraries/LibGUI/Label.cpp b/Userland/Libraries/LibGUI/Label.cpp index 33f5d1ccdd..06388284ec 100644 --- a/Userland/Libraries/LibGUI/Label.cpp +++ b/Userland/Libraries/LibGUI/Label.cpp @@ -117,7 +117,7 @@ void Label::size_to_fit() int Label::text_calculated_preferred_height() const { - return Gfx::TextLayout(&font(), Utf8View { m_text }, text_rect()).bounding_rect(Gfx::TextWrapping::Wrap, Gfx::Painter::LINE_SPACING).height(); + return int(AK::ceil(Gfx::TextLayout(&font(), Utf8View { m_text }, text_rect().to_type()).bounding_rect(Gfx::TextWrapping::Wrap, Gfx::Painter::LINE_SPACING).height())); } Optional Label::calculated_preferred_size() const diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index 080edbf347..27c5e6480b 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -1375,20 +1375,20 @@ void Painter::draw_scaled_bitmap(IntRect const& a_dst_rect, Gfx::Bitmap const& s } } -FLATTEN void Painter::draw_glyph(IntPoint point, u32 code_point, Color color) +FLATTEN void Painter::draw_glyph(FloatPoint point, u32 code_point, Color color) { draw_glyph(point, code_point, font(), color); } -FLATTEN void Painter::draw_glyph(IntPoint point, u32 code_point, Font const& font, Color color) +FLATTEN void Painter::draw_glyph(FloatPoint point, u32 code_point, Font const& font, Color color) { auto glyph = font.glyph(code_point); auto top_left = point + IntPoint(glyph.left_bearing(), 0); if (glyph.is_glyph_bitmap()) { - draw_bitmap(top_left, glyph.glyph_bitmap(), color); + draw_bitmap(top_left.to_type(), glyph.glyph_bitmap(), color); } else { - blit_filtered(top_left, *glyph.bitmap(), glyph.bitmap()->rect(), [color](Color pixel) -> Color { + blit_filtered(top_left.to_type(), *glyph.bitmap(), glyph.bitmap()->rect(), [color](Color pixel) -> Color { return pixel.multiply(color); }); } @@ -1405,7 +1405,7 @@ void Painter::draw_emoji(IntPoint point, Gfx::Bitmap const& emoji, Font const& f draw_scaled_bitmap(dst_rect, emoji, emoji.rect()); } -void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& font, Color color) +void Painter::draw_glyph_or_emoji(FloatPoint point, u32 code_point, Font const& font, Color color) { StringBuilder builder; builder.append_code_point(code_point); @@ -1413,7 +1413,7 @@ void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& fo return draw_glyph_or_emoji(point, it, font, color); } -void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Font const& font, Color color) +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; @@ -1454,7 +1454,7 @@ void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Fon // If we didn't find a text glyph, or have an emoji variation selector or regional indicator, try to draw an emoji glyph. if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) { - draw_emoji(point, *emoji, font); + draw_emoji(point.to_type(), *emoji, font); return; } @@ -1469,8 +1469,28 @@ void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Fon draw_glyph(point, 0xFFFD, font, color); } +void Painter::draw_glyph(IntPoint point, u32 code_point, Color color) +{ + draw_glyph(point.to_type(), code_point, font(), color); +} + +void Painter::draw_glyph(IntPoint point, u32 code_point, Font const& font, Color color) +{ + draw_glyph(point.to_type(), code_point, font, color); +} + +void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& font, Color color) +{ + draw_glyph_or_emoji(point.to_type(), code_point, font, color); +} + +void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Font const& font, Color color) +{ + draw_glyph_or_emoji(point.to_type(), it, font, color); +} + template -void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextDirection direction, DrawGlyphFunction draw_glyph) +void draw_text_line(FloatRect const& a_rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextDirection direction, DrawGlyphFunction draw_glyph) { auto rect = a_rect; @@ -1498,12 +1518,12 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon } if (is_vertically_centered_text_alignment(alignment)) { - int distance_from_baseline_to_bottom = (font.pixel_size() - 1) - font.baseline(); + auto distance_from_baseline_to_bottom = (font.pixel_size() - 1) - font.baseline(); rect.translate_by(0, distance_from_baseline_to_bottom / 2); } auto point = rect.location(); - int space_width = font.glyph_width(' ') + font.glyph_spacing(); + auto space_width = font.glyph_width(' ') + font.glyph_spacing(); if (direction == TextDirection::RTL) { point.translate_by(rect.width(), 0); // Start drawing from the end @@ -1519,11 +1539,11 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon continue; } - int kerning = round_to(font.glyphs_horizontal_kerning(last_code_point, code_point)); - if (kerning != 0.f) + auto kerning = font.glyphs_horizontal_kerning(last_code_point, code_point); + if (kerning != 0.0f) point.translate_by(direction == TextDirection::LTR ? kerning : -kerning, 0); - IntSize glyph_size(font.glyph_or_emoji_width(code_point) + font.glyph_spacing(), font.pixel_size()); + FloatSize glyph_size(font.glyph_or_emoji_width(code_point) + 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); @@ -1698,14 +1718,14 @@ bool Painter::text_contains_bidirectional_text(Utf8View const& text, TextDirecti } template -void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping, DrawGlyphFunction draw_glyph) +void Painter::do_draw_text(FloatRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping, DrawGlyphFunction draw_glyph) { if (draw_text_get_length(text) == 0) return; TextLayout layout(&font, text, rect); - int line_height = font.pixel_size() + LINE_SPACING; + auto line_height = font.pixel_size() + LINE_SPACING; auto lines = layout.lines(elision, wrapping, LINE_SPACING); auto bounding_rect = layout.bounding_rect(wrapping, LINE_SPACING); @@ -1722,10 +1742,10 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.y() }); break; case TextAlignment::CenterLeft: - bounding_rect.set_location({ rect.x(), rect.center().y() - (bounding_rect.height() / 2) }); + bounding_rect.set_location({ rect.x(), rect.center().y() - int(bounding_rect.height() / 2) }); break; case TextAlignment::CenterRight: - bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.center().y() - (bounding_rect.height() / 2) }); + bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.center().y() - int(bounding_rect.height() / 2) }); break; case TextAlignment::Center: bounding_rect.center_within(rect); @@ -1749,7 +1769,7 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const for (size_t i = 0; i < lines.size(); ++i) { auto line = Utf8View { lines[i] }; - IntRect line_rect { bounding_rect.x(), bounding_rect.y() + static_cast(i) * line_height, bounding_rect.width(), line_height }; + FloatRect line_rect { bounding_rect.x(), bounding_rect.y() + i * line_height, bounding_rect.width(), line_height }; line_rect.intersect(rect); TextDirection line_direction = get_text_direction(line); @@ -1779,67 +1799,102 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const } } -void Painter::draw_text(IntRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) +void Painter::draw_text(FloatRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) { draw_text(rect, text, font(), alignment, color, elision, wrapping); } +void Painter::draw_text(FloatRect const& rect, Utf32View const& text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) +{ + draw_text(rect, text, font(), alignment, color, elision, wrapping); +} + +void Painter::draw_text(FloatRect 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, [&](FloatRect const& r, Utf8CodePointIterator& it) { + draw_glyph_or_emoji(r.location(), it, font, color); + }); +} + +void Painter::draw_text(FloatRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) +{ + // FIXME: UTF-32 should eventually be completely removed, but for the time + // being some places might depend on it, so we do some internal conversion. + StringBuilder builder; + builder.append(raw_text); + auto text = Utf8View { builder.string_view() }; + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) { + draw_glyph_or_emoji(r.location(), it, font, color); + }); +} + +void Painter::draw_text(Function draw_one_glyph, FloatRect 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, [&](FloatRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); + }); +} + +void Painter::draw_text(Function draw_one_glyph, FloatRect 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, [&](FloatRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); + }); +} + +void Painter::draw_text(Function draw_one_glyph, FloatRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping) +{ + VERIFY(scale() == 1); // FIXME: Add scaling support. + + // FIXME: UTF-32 should eventually be completely removed, but for the time + // being some places might depend on it, so we do some internal conversion. + StringBuilder builder; + builder.append(raw_text); + auto text = Utf8View { builder.string_view() }; + do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) { + draw_one_glyph(r, it); + }); +} + +void Painter::draw_text(IntRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) +{ + draw_text(rect.to_type(), text, font(), alignment, color, elision, wrapping); +} + void Painter::draw_text(IntRect const& rect, Utf32View const& text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) { - draw_text(rect, text, font(), alignment, color, elision, wrapping); + draw_text(rect.to_type(), text, font(), alignment, color, elision, wrapping); } 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, Utf8CodePointIterator& it) { - draw_glyph_or_emoji(r.location(), it, font, color); - }); + draw_text(rect.to_type(), raw_text, font, alignment, color, elision, wrapping); } void Painter::draw_text(IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping) { - // FIXME: UTF-32 should eventually be completely removed, but for the time - // being some places might depend on it, so we do some internal conversion. - StringBuilder builder; - builder.append(raw_text); - auto text = Utf8View { builder.string_view() }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { - draw_glyph_or_emoji(r.location(), it, font, color); - }); + return draw_text(rect.to_type(), raw_text, font, alignment, color, elision, wrapping); } -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, Utf8CodePointIterator& it) { - draw_one_glyph(r, it); - }); + return draw_text(move(draw_one_glyph), rect.to_type(), text, font, alignment, elision, wrapping); } -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, Utf8CodePointIterator& it) { - draw_one_glyph(r, it); - }); + return draw_text(move(draw_one_glyph), rect.to_type(), raw_text, font, alignment, elision, 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) +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. - - // FIXME: UTF-32 should eventually be completely removed, but for the time - // being some places might depend on it, so we do some internal conversion. - StringBuilder builder; - builder.append(raw_text); - auto text = Utf8View { builder.string_view() }; - do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) { - draw_one_glyph(r, it); - }); + return draw_text(move(draw_one_glyph), rect.to_type(), raw_text, font, alignment, elision, wrapping); } void Painter::set_pixel(IntPoint p, Color color, bool blend) @@ -2481,7 +2536,7 @@ void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, F { auto pixel_metrics = font.pixel_metrics(); float x = baseline_start.x(); - int y = baseline_start.y() - pixel_metrics.ascent; + float y = baseline_start.y() - pixel_metrics.ascent; float space_width = font.glyph_or_emoji_width(' '); u32 last_code_point = 0; @@ -2496,7 +2551,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({ static_cast(x), y }, code_point_iterator, font, color); + draw_glyph_or_emoji(FloatPoint { x, y }, code_point_iterator, font, color); x += font.glyph_or_emoji_width(code_point) + font.glyph_spacing(); last_code_point = code_point; } diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index 1d6e093927..86d4e54fbe 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -81,19 +81,30 @@ public: void blit_offset(IntPoint, Gfx::Bitmap const&, IntRect const& src_rect, IntPoint); void blit_disabled(IntPoint, Gfx::Bitmap const&, IntRect const&, Palette const&); void blit_tiled(IntRect const&, Gfx::Bitmap const&, IntRect const& src_rect); + void draw_text(FloatRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(FloatRect const&, StringView, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(FloatRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(FloatRect const&, Utf32View const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, FloatRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, FloatRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); + void draw_text(Function, FloatRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); void draw_text(IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap); 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, u32, Color); void draw_glyph(IntPoint, u32, Font const&, Color); void draw_emoji(IntPoint, Gfx::Bitmap const&, Font const&); void draw_glyph_or_emoji(IntPoint, u32, Font const&, Color); void draw_glyph_or_emoji(IntPoint, Utf8CodePointIterator&, Font const&, Color); + void draw_glyph(FloatPoint, u32, Color); + void draw_glyph(FloatPoint, u32, Font const&, Color); + void draw_glyph_or_emoji(FloatPoint, u32, Font const&, Color); + void draw_glyph_or_emoji(FloatPoint, Utf8CodePointIterator&, Font const&, Color); void draw_circle_arc_intersecting(IntRect const&, IntPoint, int radius, Color, int thickness); // Streamlined text drawing routine that does no wrapping/elision/alignment. @@ -214,7 +225,7 @@ private: Vector split_text_into_directional_runs(Utf8View const&, TextDirection initial_direction); bool text_contains_bidirectional_text(Utf8View const&, TextDirection); template - void do_draw_text(IntRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction); + void do_draw_text(FloatRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction); }; class PainterStateSaver { diff --git a/Userland/Libraries/LibGfx/TextLayout.cpp b/Userland/Libraries/LibGfx/TextLayout.cpp index afb9d2e07a..4f63e06ce7 100644 --- a/Userland/Libraries/LibGfx/TextLayout.cpp +++ b/Userland/Libraries/LibGfx/TextLayout.cpp @@ -20,15 +20,15 @@ struct Block { Utf8View characters; }; -IntRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const +FloatRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const { auto lines = wrap_lines(TextElision::None, wrapping, line_spacing, FitWithinRect::No); if (!lines.size()) { return {}; } - IntRect bounding_rect = { - 0, 0, 0, static_cast((lines.size() * (m_font->pixel_size() + line_spacing)) - line_spacing) + FloatRect bounding_rect = { + 0, 0, 0, (lines.size() * (m_font->pixel_size() + line_spacing)) - line_spacing }; for (auto& line : lines) { @@ -119,7 +119,7 @@ Vector TextLayout::wrap_lines(TextElision elision, TextWra Vector lines; StringBuilder builder; - size_t line_width = 0; + float line_width = 0; size_t current_block = 0; bool did_not_finish = false; for (Block& block : blocks) { @@ -139,14 +139,14 @@ Vector TextLayout::wrap_lines(TextElision elision, TextWra } case BlockType::Whitespace: case BlockType::Word: { - size_t block_width = font().width(block.characters); + float block_width = font().width(block.characters); // FIXME: This should look at the specific advance amount of the // last character, but we don't support that yet. if (current_block != blocks.size() - 1) { block_width += font().glyph_spacing(); } - if (wrapping == TextWrapping::Wrap && line_width + block_width > static_cast(m_rect.width())) { + if (wrapping == TextWrapping::Wrap && line_width + block_width > m_rect.width()) { lines.append(builder.to_deprecated_string()); builder.clear(); line_width = 0; @@ -185,10 +185,10 @@ blocks_processed: DeprecatedString TextLayout::elide_text_from_right(Utf8View text, bool force_elision) const { - size_t text_width = m_font->width(text); + float text_width = m_font->width(text); if (force_elision || text_width > static_cast(m_rect.width())) { - size_t ellipsis_width = m_font->width("..."sv); - size_t current_width = ellipsis_width; + float ellipsis_width = m_font->width("..."sv); + float current_width = ellipsis_width; size_t glyph_spacing = m_font->glyph_spacing(); // FIXME: This code will break when the font has glyphs with advance @@ -198,11 +198,11 @@ DeprecatedString TextLayout::elide_text_from_right(Utf8View text, bool force_eli size_t offset = 0; for (auto it = text.begin(); !it.done(); ++it) { auto code_point = *it; - int glyph_width = m_font->glyph_or_emoji_width(code_point); + auto glyph_width = m_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, // we don't have to worry about spacing. - int width_with_this_glyph_included = current_width + glyph_width + glyph_spacing; + auto width_with_this_glyph_included = current_width + glyph_width + glyph_spacing; if (width_with_this_glyph_included > m_rect.width()) break; current_width += glyph_width + glyph_spacing; diff --git a/Userland/Libraries/LibGfx/TextLayout.h b/Userland/Libraries/LibGfx/TextLayout.h index 909896f8d7..c67375d43f 100644 --- a/Userland/Libraries/LibGfx/TextLayout.h +++ b/Userland/Libraries/LibGfx/TextLayout.h @@ -44,7 +44,7 @@ enum class FitWithinRect { // b) Taking the Lines from TextLayout and painting each glyph. class TextLayout { public: - TextLayout(Gfx::Font const* font, Utf8View const& text, IntRect const& rect) + TextLayout(Gfx::Font const* font, Utf8View const& text, FloatRect const& rect) : m_font(font) , m_text(text) , m_rect(rect) @@ -57,15 +57,15 @@ public: Utf8View const& text() const { return m_text; } void set_text(Utf8View const& text) { m_text = text; } - IntRect const& rect() const { return m_rect; } - void set_rect(IntRect const& rect) { m_rect = rect; } + FloatRect const& rect() const { return m_rect; } + void set_rect(FloatRect const& rect) { m_rect = rect; } Vector lines(TextElision elision, TextWrapping wrapping, int line_spacing) const { return wrap_lines(elision, wrapping, line_spacing, FitWithinRect::Yes); } - IntRect bounding_rect(TextWrapping wrapping, int line_spacing) const; + FloatRect bounding_rect(TextWrapping wrapping, int line_spacing) const; private: Vector wrap_lines(TextElision, TextWrapping, int line_spacing, FitWithinRect) const; @@ -73,7 +73,7 @@ private: Font const* m_font; Utf8View m_text; - IntRect m_rect; + FloatRect m_rect; }; } diff --git a/Userland/Services/WindowServer/Overlays.cpp b/Userland/Services/WindowServer/Overlays.cpp index 0fa782341a..5724837038 100644 --- a/Userland/Services/WindowServer/Overlays.cpp +++ b/Userland/Services/WindowServer/Overlays.cpp @@ -213,7 +213,7 @@ Gfx::Font const& ScreenNumberOverlay::font() void ScreenNumberOverlay::render_overlay_bitmap(Gfx::Painter& painter) { - painter.draw_text({ {}, rect().size() }, DeprecatedString::formatted("{}", m_screen.index() + 1), font(), Gfx::TextAlignment::Center, Color::White); + painter.draw_text(Gfx::IntRect { {}, rect().size() }, DeprecatedString::formatted("{}", m_screen.index() + 1), font(), Gfx::TextAlignment::Center, Color::White); } Gfx::IntRect ScreenNumberOverlay::calculate_content_rect_for_screen(Screen& screen) @@ -264,7 +264,7 @@ void WindowGeometryOverlay::update_rect() void WindowGeometryOverlay::render_overlay_bitmap(Gfx::Painter& painter) { - painter.draw_text({ {}, rect().size() }, m_label, WindowManager::the().font(), Gfx::TextAlignment::Center, Color::White); + painter.draw_text(Gfx::IntRect { {}, rect().size() }, m_label, WindowManager::the().font(), Gfx::TextAlignment::Center, Color::White); } void WindowGeometryOverlay::window_rect_changed()