From 6c645f3a9fe513a60ab845d0fef81532b3435514 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Wed, 3 Jan 2024 19:00:04 +0100 Subject: [PATCH] LibWeb: Paint fragments contained by inline node as part of this node Fragments contained by the inline node should be painted in the foreground phase for this node, instead of being painted as a part of the containing PaintableWithLines. This change implements that by marking all fragments contained by inline nodes so they can be skipped while painting the content of PaintableWithLines. This is an ugly way, and instead, we should make InlinePaintables own all fragments contained by them. --- Userland/Libraries/LibWeb/Layout/LayoutState.cpp | 12 ++++++++++++ .../Libraries/LibWeb/Layout/LineBoxFragment.h | 4 ++++ .../LibWeb/Painting/InlinePaintable.cpp | 16 ++++++++++++++++ .../Libraries/LibWeb/Painting/InlinePaintable.h | 2 ++ .../Libraries/LibWeb/Painting/PaintableBox.cpp | 10 +++++++--- .../Libraries/LibWeb/Painting/PaintableBox.h | 4 ++++ 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index c236fb2b6c..e6d22e12ac 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -460,6 +460,18 @@ void LayoutState::commit(Box& root) resolve_border_radii(); resolve_box_shadow_data(); + + for (auto& it : used_values_per_layout_node) { + auto& used_values = *it.value; + auto& node = const_cast(used_values.node()); + auto* paintable = node.paintable(); + if (paintable && is(*paintable)) { + auto& inline_paintable = static_cast(*paintable); + // FIXME: Marking fragments contained by inline node is a hack required to skip them while painting + // PaintableWithLines content. + inline_paintable.mark_contained_fragments(); + } + } } void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* containing_block_used_values) diff --git a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h index cdefae8740..07ace56168 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h +++ b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h @@ -79,6 +79,9 @@ public: Painting::BorderRadiiData const& border_radii_data() const { return m_border_radii_data; } void set_border_radii_data(Painting::BorderRadiiData const& border_radii_data) { m_border_radii_data = border_radii_data; } + bool contained_by_inline_node() const { return m_contained_by_inline_node; } + void set_contained_by_inline_node() { m_contained_by_inline_node = true; } + private: JS::NonnullGCPtr m_layout_node; int m_start { 0 }; @@ -90,6 +93,7 @@ private: CSSPixels m_baseline { 0 }; Vector m_glyph_run; Painting::BorderRadiiData m_border_radii_data; + bool m_contained_by_inline_node { false }; }; } diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp index ceb4883b35..3ffb27a542 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp @@ -146,6 +146,13 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const } } + if (phase == PaintPhase::Foreground) { + for_each_fragment([&](auto const& fragment, bool, bool) { + if (is(fragment.layout_node())) + paint_text_fragment(context, static_cast(fragment.layout_node()), fragment, phase); + }); + } + if (phase == PaintPhase::Overlay && layout_node().document().inspected_layout_node() == &layout_node()) { // FIXME: This paints a double-thick border between adjacent fragments, where ideally there // would be none. Once we implement non-rectangular outlines for the `outline` CSS @@ -173,6 +180,15 @@ void InlinePaintable::for_each_fragment(Callback callback) const } } +void InlinePaintable::mark_contained_fragments() +{ + verify_cast(*containing_block()->paintable_box()).for_each_fragment([&](auto& fragment) { + if (layout_node().is_inclusive_ancestor_of(fragment.layout_node())) + const_cast(fragment).set_contained_by_inline_node(); + return IterationDecision::Continue; + }); +} + CSSPixelRect InlinePaintable::bounding_rect() const { auto top = CSSPixels::max(); diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h index 204413be6b..6718bed6c5 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h @@ -24,6 +24,8 @@ public: CSSPixelRect bounding_rect() const; + void mark_contained_fragments(); + private: InlinePaintable(Layout::InlineNode const&); diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 1ee868c4aa..3218d6ef6d 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -484,7 +484,7 @@ void PaintableBox::clear_clip_overflow_rect(PaintContext& context, PaintPhase ph } } -static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment) +void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment) { auto const& browsing_context = text_node.browsing_context(); @@ -518,7 +518,7 @@ static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const context.recording_painter().draw_rect(cursor_device_rect, text_node.computed_values().color()); } -static void paint_text_decoration(PaintContext& context, Layout::Node const& text_node, Layout::LineBoxFragment const& fragment) +void paint_text_decoration(PaintContext& context, Layout::Node const& text_node, Layout::LineBoxFragment const& fragment) { auto& painter = context.recording_painter(); auto& font = fragment.layout_node().first_available_font(); @@ -600,7 +600,7 @@ static void paint_text_decoration(PaintContext& context, Layout::Node const& tex } } -static void paint_text_fragment(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment, PaintPhase phase) +void paint_text_fragment(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment, PaintPhase phase) { auto& painter = context.recording_painter(); @@ -680,6 +680,8 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const if (phase == PaintPhase::Foreground) { for (auto& line_box : m_line_boxes) { for (auto& fragment : line_box.fragments()) { + if (fragment.contained_by_inline_node()) + continue; if (is(fragment.layout_node())) { auto& text_shadow = fragment.layout_node().computed_values().text_shadow(); if (!text_shadow.is_empty()) { @@ -704,6 +706,8 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const for (auto& line_box : m_line_boxes) { for (auto& fragment : line_box.fragments()) { + if (fragment.contained_by_inline_node()) + continue; auto fragment_absolute_rect = fragment.absolute_rect(); auto fragment_absolute_device_rect = context.enclosing_device_rect(fragment_absolute_rect); if (context.should_show_line_box_borders()) { diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index c30ab28175..85a5d8f861 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -272,4 +272,8 @@ private: Vector m_line_boxes; }; +void paint_text_decoration(PaintContext& context, Layout::Node const& text_node, Layout::LineBoxFragment const& fragment); +void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment); +void paint_text_fragment(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment, PaintPhase phase); + }