diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index b1f5bf5f875..f60cf73f2af 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -527,6 +527,7 @@ set(SOURCES Painting/CommandExecutorCPU.cpp Painting/CommandList.cpp Painting/CheckBoxPaintable.cpp + Painting/ClippableAndScrollable.cpp Painting/GradientPainting.cpp Painting/FilterPainting.cpp Painting/ImagePaintable.cpp diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index d788d57cc56..f42511894da 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::Painting { diff --git a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp new file mode 100644 index 00000000000..f24cb180cc6 --- /dev/null +++ b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Web::Painting { + +Optional ClippableAndScrollable::scroll_frame_id() const +{ + if (m_enclosing_scroll_frame) + return m_enclosing_scroll_frame->id; + return {}; +} + +Optional ClippableAndScrollable::enclosing_scroll_frame_offset() const +{ + if (m_enclosing_scroll_frame) + return m_enclosing_scroll_frame->offset; + return {}; +} + +Optional ClippableAndScrollable::clip_rect() const +{ + if (m_enclosing_clip_frame) { + auto rect = m_enclosing_clip_frame->rect(); + // NOTE: Since the painting command executor applies a CSS transform and the clip rect is calculated + // with this transform taken into account, we need to remove the transform from the clip rect. + // Otherwise, the transform will be applied twice to the clip rect. + // Similarly, for hit-testing, the transform must be removed from the clip rectangle since the position + // includes the transform. + auto combined_transform = compute_combined_css_transform_for_clippable_and_scrollable(); + rect.translate_by(-combined_transform.translation().to_type()); + return rect; + } + return {}; +} + +Span ClippableAndScrollable::border_radii_clips() const +{ + if (m_enclosing_clip_frame) + return m_enclosing_clip_frame->border_radii_clips(); + return {}; +} + +} diff --git a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h new file mode 100644 index 00000000000..beb1b56e01e --- /dev/null +++ b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::Painting { + +struct ScrollFrame : public RefCounted { + i32 id { -1 }; + CSSPixelPoint offset; +}; + +class ClippableAndScrollable { +public: + virtual ~ClippableAndScrollable() = default; + + void set_enclosing_scroll_frame(RefPtr scroll_frame) { m_enclosing_scroll_frame = scroll_frame; } + void set_enclosing_clip_frame(RefPtr clip_frame) { m_enclosing_clip_frame = clip_frame; } + + [[nodiscard]] Optional scroll_frame_id() const; + [[nodiscard]] Optional enclosing_scroll_frame_offset() const; + [[nodiscard]] Optional clip_rect() const; + [[nodiscard]] Span border_radii_clips() const; + + virtual Gfx::AffineTransform compute_combined_css_transform_for_clippable_and_scrollable() const = 0; + +private: + RefPtr m_enclosing_scroll_frame; + RefPtr m_enclosing_clip_frame; +}; + +} diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp index 709a95320d5..198b978c8c7 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp @@ -30,35 +30,6 @@ Layout::InlineNode const& InlinePaintable::layout_node() const return static_cast(Paintable::layout_node()); } -Optional InlinePaintable::scroll_frame_id() const -{ - if (m_enclosing_scroll_frame) - return m_enclosing_scroll_frame->id; - return {}; -} - -Optional InlinePaintable::enclosing_scroll_frame_offset() const -{ - if (m_enclosing_scroll_frame) - return m_enclosing_scroll_frame->offset; - return {}; -} - -Optional InlinePaintable::clip_rect() const -{ - if (m_enclosing_clip_frame) { - auto rect = m_enclosing_clip_frame->rect(); - - // NOTE: Since the painting command executor applies a CSS transform and the clip rect is calculated - // with this transform taken into account, we need to remove the transform from the clip rect. - // Otherwise, the transform will be applied twice to the clip rect. - auto combined_transform = compute_combined_css_transform(); - rect.translate_by(-combined_transform.translation().to_type()); - return rect; - } - return {}; -} - void InlinePaintable::before_paint(PaintContext& context, PaintPhase) const { if (scroll_frame_id().has_value()) { @@ -218,7 +189,7 @@ void InlinePaintable::for_each_fragment(Callback callback) const TraversalDecision InlinePaintable::hit_test(CSSPixelPoint position, HitTestType type, Function const& callback) const { - if (m_clip_rect.has_value() && !m_clip_rect.value().contains(position)) + if (clip_rect().has_value() && !clip_rect().value().contains(position)) return TraversalDecision::Continue; auto position_adjusted_by_scroll_offset = position; diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h index dfb6c3f9e5e..a9924ace75b 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h @@ -7,12 +7,14 @@ #pragma once #include -#include +#include +#include #include namespace Web::Painting { -class InlinePaintable final : public Paintable { +class InlinePaintable final : public Paintable + , public ClippableAndScrollable { JS_CELL(InlinePaintable, Paintable); JS_DECLARE_ALLOCATOR(InlinePaintable); @@ -44,12 +46,10 @@ public: void set_outline_offset(CSSPixels outline_offset) { m_outline_offset = outline_offset; } CSSPixels outline_offset() const { return m_outline_offset; } - void set_enclosing_scroll_frame(RefPtr scroll_frame) { m_enclosing_scroll_frame = scroll_frame; } - void set_enclosing_clip_frame(RefPtr clip_frame) { m_enclosing_clip_frame = clip_frame; } - - Optional scroll_frame_id() const; - Optional enclosing_scroll_frame_offset() const; - Optional clip_rect() const; + virtual Gfx::AffineTransform compute_combined_css_transform_for_clippable_and_scrollable() const override + { + return compute_combined_css_transform(); + } private: InlinePaintable(Layout::InlineNode const&); @@ -57,10 +57,6 @@ private: template void for_each_fragment(Callback) const; - Optional m_clip_rect; - RefPtr m_enclosing_scroll_frame; - RefPtr m_enclosing_clip_frame; - Vector m_box_shadow_data; Optional m_outline_data; CSSPixels m_outline_offset { 0 }; diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 6c7bd259192..331c310f290 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -209,43 +209,6 @@ Optional PaintableBox::get_clip_rect() const return {}; } -Optional PaintableBox::scroll_frame_id() const -{ - if (m_enclosing_scroll_frame) - return m_enclosing_scroll_frame->id; - return {}; -} - -Optional PaintableBox::enclosing_scroll_frame_offset() const -{ - if (m_enclosing_scroll_frame) - return m_enclosing_scroll_frame->offset; - return {}; -} - -Optional PaintableBox::clip_rect() const -{ - if (m_enclosing_clip_frame) { - auto rect = m_enclosing_clip_frame->rect(); - // NOTE: Since the painting command executor applies a CSS transform and the clip rect is calculated - // with this transform in account, we need to remove the transform from the clip rect. - // Otherwise, the transform will be applied twice to the clip rect. - // Similarly, for hit-testing, the transform must be removed from the clip rectangle since the position - // includes the transform. - auto combined_transform = compute_combined_css_transform(); - rect.translate_by(-combined_transform.translation().to_type()); - return rect; - } - return {}; -} - -Span PaintableBox::border_radii_clips() const -{ - if (m_enclosing_clip_frame) - return m_enclosing_clip_frame->border_radii_clips(); - return {}; -} - void PaintableBox::before_paint(PaintContext& context, [[maybe_unused]] PaintPhase phase) const { if (!is_visible()) diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 1e51694e9f6..4d99d181e39 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -9,18 +9,15 @@ #include #include #include +#include #include #include #include namespace Web::Painting { -struct ScrollFrame : public RefCounted { - i32 id { -1 }; - CSSPixelPoint offset; -}; - -class PaintableBox : public Paintable { +class PaintableBox : public Paintable + , public ClippableAndScrollable { JS_CELL(PaintableBox, Paintable); public: @@ -206,13 +203,10 @@ public: Optional get_clip_rect() const; - void set_enclosing_scroll_frame(RefPtr scroll_frame) { m_enclosing_scroll_frame = scroll_frame; } - void set_enclosing_clip_frame(RefPtr clip_frame) { m_enclosing_clip_frame = clip_frame; } - - Optional scroll_frame_id() const; - Optional enclosing_scroll_frame_offset() const; - Optional clip_rect() const; - Span border_radii_clips() const; + virtual Gfx::AffineTransform compute_combined_css_transform_for_clippable_and_scrollable() const override + { + return compute_combined_css_transform(); + } protected: explicit PaintableBox(Layout::Box const&);