From 1c88536298666cff39aaba7457c9ff94e0862de1 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 28 Mar 2022 21:05:51 +0200 Subject: [PATCH] LibWeb: Use the new Gfx::Painter::draw_text_run() API for drawing text This avoids a bunch of unnecessary work in Painter which not only took time, but sometimes also led to alignment issues. draw_text_run() will draw the text where we tell it, and that's it. --- Userland/Libraries/LibWeb/Layout/LineBoxFragment.h | 5 +++++ Userland/Libraries/LibWeb/Layout/LineBuilder.cpp | 5 ++++- Userland/Libraries/LibWeb/Painting/PaintableBox.cpp | 12 +++++------- .../Libraries/LibWeb/Painting/ShadowPainting.cpp | 3 ++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h index 0a5fe51610..5338b36bee 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h +++ b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h @@ -43,6 +43,10 @@ public: const Gfx::FloatPoint& offset() const { return m_offset; } void set_offset(const Gfx::FloatPoint& offset) { m_offset = offset; } + // The baseline of a fragment is the number of pixels from the top to the text baseline. + void set_baseline(float y) { m_baseline = y; } + float baseline() const { return m_baseline; } + const Gfx::FloatSize& size() const { return m_size; } void set_width(float width) { m_size.set_width(width); } void set_height(float height) { m_size.set_height(height); } @@ -75,6 +79,7 @@ private: Gfx::FloatSize m_size; float m_border_box_top { 0 }; float m_border_box_bottom { 0 }; + float m_baseline { 0 }; Type m_type { Type::Normal }; }; diff --git a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp index fe1b0cacca..d52c03cac5 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp @@ -159,7 +159,7 @@ void LineBuilder::update_last_line() auto line_box_baseline = [&] { float line_box_baseline = 0; - for (auto const& fragment : line_box.fragments()) { + for (auto& fragment : line_box.fragments()) { auto baseline = fragment_baseline(fragment); if (fragment.height() < m_context.containing_block().line_height()) baseline += (m_context.containing_block().line_height() - fragment.height()) / 2; @@ -168,6 +168,9 @@ void LineBuilder::update_last_line() if (auto length_percentage = fragment.layout_node().computed_values().vertical_align().template get_pointer(); length_percentage && length_percentage->is_length()) baseline += length_percentage->length().to_px(fragment.layout_node()); + // Store the baseline on the fragment. This is used when painting. + fragment.set_baseline(baseline); + line_box_baseline = max(line_box_baseline, baseline); } return line_box_baseline; diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index c28958f8c7..765cae866b 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -369,8 +369,6 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t if (phase == Painting::PaintPhase::Foreground) { auto fragment_absolute_rect = fragment.absolute_rect(); - painter.set_font(text_node.font()); - if (text_node.document().inspected_node() == &text_node.dom_node()) context.painter().draw_rect(enclosing_int_rect(fragment_absolute_rect), Color::Magenta); @@ -382,17 +380,17 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t if (text_transform == CSS::TextTransform::Lowercase) text = text_node.text_for_rendering().to_lowercase(); - // FIXME: This is a hack to prevent text clipping when painting a bitmap font into a too-small box. - auto draw_rect = enclosing_int_rect(fragment_absolute_rect); - draw_rect.set_height(max(draw_rect.height(), text_node.font().pixel_size())); - painter.draw_text(draw_rect, text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::CenterLeft, text_node.computed_values().color()); + Gfx::FloatPoint baseline_start { fragment_absolute_rect.x(), fragment_absolute_rect.y() + fragment.baseline() }; + Utf8View view { text.substring_view(fragment.start(), fragment.length()) }; + + painter.draw_text_run(baseline_start, view, fragment.layout_node().font(), text_node.computed_values().color()); auto selection_rect = fragment.selection_rect(text_node.font()); if (!selection_rect.is_empty()) { painter.fill_rect(enclosing_int_rect(selection_rect), context.palette().selection()); Gfx::PainterStateSaver saver(painter); painter.add_clip_rect(enclosing_int_rect(selection_rect)); - painter.draw_text(enclosing_int_rect(fragment_absolute_rect), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::CenterLeft, context.palette().selection_text()); + painter.draw_text_run(baseline_start, view, fragment.layout_node().font(), context.palette().selection_text()); } paint_text_decoration(painter, text_node, fragment); diff --git a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp index 51b1b0903a..8439f9adbd 100644 --- a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp @@ -159,7 +159,8 @@ void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fra Gfx::Painter shadow_painter { *shadow_bitmap }; shadow_painter.set_font(context.painter().font()); // FIXME: "Spread" the shadow somehow. - shadow_painter.draw_text(text_rect, fragment.text(), Gfx::TextAlignment::CenterLeft, layer.color); + Gfx::FloatPoint baseline_start(text_rect.x(), text_rect.y() + fragment.baseline()); + shadow_painter.draw_text_run(baseline_start, Utf8View(fragment.text()), context.painter().font(), layer.color); // Blur Gfx::FastBoxBlurFilter filter(*shadow_bitmap);