LibWeb/Painting: Add ClippableAndScrollable mixin

Moves code that was duplicated across PaintableBox and InlinePaintable
into separate class.
This commit is contained in:
Aliaksandr Kalenik 2024-04-27 14:26:42 +02:00 committed by Andreas Kling
parent 56e0cd0b1a
commit cd07249482
8 changed files with 103 additions and 92 deletions

View file

@ -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

View file

@ -12,6 +12,7 @@
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/InlinePaintable.h>
#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Painting/ClippableAndScrollable.h>
namespace Web::Painting {
Optional<int> ClippableAndScrollable::scroll_frame_id() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->id;
return {};
}
Optional<CSSPixelPoint> ClippableAndScrollable::enclosing_scroll_frame_offset() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->offset;
return {};
}
Optional<CSSPixelRect> 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<CSSPixels>());
return rect;
}
return {};
}
Span<BorderRadiiClip const> ClippableAndScrollable::border_radii_clips() const
{
if (m_enclosing_clip_frame)
return m_enclosing_clip_frame->border_radii_clips();
return {};
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Painting/ClipFrame.h>
namespace Web::Painting {
struct ScrollFrame : public RefCounted<ScrollFrame> {
i32 id { -1 };
CSSPixelPoint offset;
};
class ClippableAndScrollable {
public:
virtual ~ClippableAndScrollable() = default;
void set_enclosing_scroll_frame(RefPtr<ScrollFrame> scroll_frame) { m_enclosing_scroll_frame = scroll_frame; }
void set_enclosing_clip_frame(RefPtr<ClipFrame> clip_frame) { m_enclosing_clip_frame = clip_frame; }
[[nodiscard]] Optional<int> scroll_frame_id() const;
[[nodiscard]] Optional<CSSPixelPoint> enclosing_scroll_frame_offset() const;
[[nodiscard]] Optional<CSSPixelRect> clip_rect() const;
[[nodiscard]] Span<BorderRadiiClip const> border_radii_clips() const;
virtual Gfx::AffineTransform compute_combined_css_transform_for_clippable_and_scrollable() const = 0;
private:
RefPtr<ScrollFrame const> m_enclosing_scroll_frame;
RefPtr<ClipFrame const> m_enclosing_clip_frame;
};
}

View file

@ -30,35 +30,6 @@ Layout::InlineNode const& InlinePaintable::layout_node() const
return static_cast<Layout::InlineNode const&>(Paintable::layout_node());
}
Optional<int> InlinePaintable::scroll_frame_id() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->id;
return {};
}
Optional<CSSPixelPoint> InlinePaintable::enclosing_scroll_frame_offset() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->offset;
return {};
}
Optional<CSSPixelRect> 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<CSSPixels>());
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<TraversalDecision(HitTestResult)> 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;

View file

@ -7,12 +7,14 @@
#pragma once
#include <LibWeb/Layout/InlineNode.h>
#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Painting/ClippableAndScrollable.h>
#include <LibWeb/Painting/Paintable.h>
#include <LibWeb/Painting/PaintableFragment.h>
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<ScrollFrame> scroll_frame) { m_enclosing_scroll_frame = scroll_frame; }
void set_enclosing_clip_frame(RefPtr<ClipFrame> clip_frame) { m_enclosing_clip_frame = clip_frame; }
Optional<int> scroll_frame_id() const;
Optional<CSSPixelPoint> enclosing_scroll_frame_offset() const;
Optional<CSSPixelRect> 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<typename Callback>
void for_each_fragment(Callback) const;
Optional<CSSPixelRect> m_clip_rect;
RefPtr<ScrollFrame const> m_enclosing_scroll_frame;
RefPtr<ClipFrame const> m_enclosing_clip_frame;
Vector<ShadowData> m_box_shadow_data;
Optional<BordersData> m_outline_data;
CSSPixels m_outline_offset { 0 };

View file

@ -209,43 +209,6 @@ Optional<CSSPixelRect> PaintableBox::get_clip_rect() const
return {};
}
Optional<int> PaintableBox::scroll_frame_id() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->id;
return {};
}
Optional<CSSPixelPoint> PaintableBox::enclosing_scroll_frame_offset() const
{
if (m_enclosing_scroll_frame)
return m_enclosing_scroll_frame->offset;
return {};
}
Optional<CSSPixelRect> 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<CSSPixels>());
return rect;
}
return {};
}
Span<BorderRadiiClip const> 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())

View file

@ -9,18 +9,15 @@
#include <LibWeb/Painting/BorderPainting.h>
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
#include <LibWeb/Painting/ClipFrame.h>
#include <LibWeb/Painting/ClippableAndScrollable.h>
#include <LibWeb/Painting/Paintable.h>
#include <LibWeb/Painting/PaintableFragment.h>
#include <LibWeb/Painting/ShadowPainting.h>
namespace Web::Painting {
struct ScrollFrame : public RefCounted<ScrollFrame> {
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<CSSPixelRect> get_clip_rect() const;
void set_enclosing_scroll_frame(RefPtr<ScrollFrame> scroll_frame) { m_enclosing_scroll_frame = scroll_frame; }
void set_enclosing_clip_frame(RefPtr<ClipFrame> clip_frame) { m_enclosing_clip_frame = clip_frame; }
Optional<int> scroll_frame_id() const;
Optional<CSSPixelPoint> enclosing_scroll_frame_offset() const;
Optional<CSSPixelRect> clip_rect() const;
Span<BorderRadiiClip const> 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&);