2022-03-09 23:53:41 +01:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2022-2023, Andreas Kling <andreas@ladybird.org>
|
2022-03-09 23:53:41 +01:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <AK/NonnullOwnPtr.h>
|
2024-11-15 04:01:23 +13:00
|
|
|
#include <LibGC/Root.h>
|
2024-09-02 16:47:32 +01:00
|
|
|
#include <LibWeb/InvalidateDisplayList.h>
|
2022-03-09 23:53:41 +01:00
|
|
|
#include <LibWeb/Layout/LineBox.h>
|
2024-10-14 16:07:56 +02:00
|
|
|
#include <LibWeb/TraversalDecision.h>
|
|
|
|
#include <LibWeb/TreeNode.h>
|
2022-03-09 23:53:41 +01:00
|
|
|
|
|
|
|
namespace Web::Painting {
|
|
|
|
|
2022-03-11 00:03:28 +01:00
|
|
|
enum class PaintPhase {
|
|
|
|
Background,
|
|
|
|
Border,
|
2024-07-30 13:41:48 +03:00
|
|
|
TableCollapsedBorder,
|
2022-03-11 00:03:28 +01:00
|
|
|
Foreground,
|
2023-08-02 13:58:34 +01:00
|
|
|
Outline,
|
2022-03-11 00:03:28 +01:00
|
|
|
Overlay,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct HitTestResult {
|
2024-11-15 04:01:23 +13:00
|
|
|
GC::Root<Paintable> paintable;
|
2022-03-11 00:03:28 +01:00
|
|
|
int index_in_node { 0 };
|
2024-07-11 20:12:51 +01:00
|
|
|
Optional<CSSPixels> vertical_distance {};
|
|
|
|
Optional<CSSPixels> horizontal_distance {};
|
2022-03-11 00:03:28 +01:00
|
|
|
|
|
|
|
enum InternalPosition {
|
|
|
|
None,
|
|
|
|
Before,
|
|
|
|
Inside,
|
|
|
|
After,
|
|
|
|
};
|
|
|
|
InternalPosition internal_position { None };
|
2022-03-21 11:16:02 +01:00
|
|
|
|
|
|
|
DOM::Node* dom_node();
|
|
|
|
DOM::Node const* dom_node() const;
|
2022-03-11 00:03:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class HitTestType {
|
|
|
|
Exact, // Exact matches only
|
|
|
|
TextCursor, // Clicking past the right/bottom edge of text will still hit the text
|
|
|
|
};
|
|
|
|
|
2023-08-18 12:30:27 +02:00
|
|
|
class Paintable
|
|
|
|
: public JS::Cell
|
|
|
|
, public TreeNode<Paintable> {
|
2024-11-15 04:01:23 +13:00
|
|
|
GC_CELL(Paintable, JS::Cell);
|
2022-03-10 15:50:57 +01:00
|
|
|
|
2022-03-09 23:53:41 +01:00
|
|
|
public:
|
2024-01-03 02:40:31 +01:00
|
|
|
virtual ~Paintable();
|
2022-03-10 15:50:57 +01:00
|
|
|
|
2024-03-25 12:23:42 +01:00
|
|
|
[[nodiscard]] bool is_visible() const;
|
2024-03-02 11:03:02 +01:00
|
|
|
[[nodiscard]] bool is_positioned() const { return m_positioned; }
|
|
|
|
[[nodiscard]] bool is_fixed_position() const { return m_fixed_position; }
|
2024-08-24 19:20:31 +02:00
|
|
|
[[nodiscard]] bool is_sticky_position() const { return m_sticky_position; }
|
2024-03-02 11:03:02 +01:00
|
|
|
[[nodiscard]] bool is_absolutely_positioned() const { return m_absolutely_positioned; }
|
|
|
|
[[nodiscard]] bool is_floating() const { return m_floating; }
|
|
|
|
[[nodiscard]] bool is_inline() const { return m_inline; }
|
2024-10-14 16:07:56 +02:00
|
|
|
[[nodiscard]] CSS::Display display() const;
|
2023-08-19 15:20:45 +02:00
|
|
|
|
2024-11-18 16:05:22 +01:00
|
|
|
bool has_stacking_context() const;
|
2024-01-03 02:40:31 +01:00
|
|
|
StackingContext* enclosing_stacking_context();
|
|
|
|
|
2023-08-31 17:08:45 -05:00
|
|
|
virtual void before_paint(PaintContext&, PaintPhase) const { }
|
|
|
|
virtual void after_paint(PaintContext&, PaintPhase) const { }
|
|
|
|
|
2022-03-10 15:50:57 +01:00
|
|
|
virtual void paint(PaintContext&, PaintPhase) const { }
|
2022-09-13 20:45:38 +02:00
|
|
|
|
2022-11-12 00:07:43 +03:00
|
|
|
virtual void before_children_paint(PaintContext&, PaintPhase) const { }
|
|
|
|
virtual void after_children_paint(PaintContext&, PaintPhase) const { }
|
2022-03-10 15:50:57 +01:00
|
|
|
|
2023-12-11 16:47:40 +01:00
|
|
|
virtual void apply_scroll_offset(PaintContext&, PaintPhase) const { }
|
|
|
|
virtual void reset_scroll_offset(PaintContext&, PaintPhase) const { }
|
|
|
|
|
2023-01-25 04:50:14 +03:00
|
|
|
virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const { }
|
|
|
|
virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const { }
|
|
|
|
|
2024-02-13 21:34:07 +01:00
|
|
|
[[nodiscard]] virtual TraversalDecision hit_test(CSSPixelPoint, HitTestType, Function<TraversalDecision(HitTestResult)> const& callback) const;
|
2022-03-11 00:03:28 +01:00
|
|
|
|
2022-03-10 22:46:35 +01:00
|
|
|
virtual bool wants_mouse_events() const { return false; }
|
2022-03-14 23:05:55 +00:00
|
|
|
|
2023-09-17 15:32:24 +01:00
|
|
|
virtual bool forms_unconnected_subtree() const { return false; }
|
|
|
|
|
2022-03-14 23:05:55 +00:00
|
|
|
enum class DispatchEventOfSameName {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
};
|
|
|
|
// When these methods return true, the DOM event with the same name will be
|
|
|
|
// dispatch at the mouse_event_target if it returns a valid DOM::Node, or
|
|
|
|
// the layout node's associated DOM node if it doesn't.
|
2022-11-02 17:35:53 +00:00
|
|
|
virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
|
|
|
|
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
|
|
|
|
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers);
|
2022-03-14 23:05:55 +00:00
|
|
|
|
2022-11-02 17:35:53 +00:00
|
|
|
virtual bool handle_mousewheel(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y);
|
2022-03-10 22:46:35 +01:00
|
|
|
|
2022-03-10 15:50:57 +01:00
|
|
|
Layout::Node const& layout_node() const { return m_layout_node; }
|
2023-01-11 12:51:49 +01:00
|
|
|
Layout::Node& layout_node() { return const_cast<Layout::Node&>(*m_layout_node); }
|
2022-03-10 22:46:35 +01:00
|
|
|
|
2024-11-15 04:01:23 +13:00
|
|
|
[[nodiscard]] GC::Ptr<DOM::Node> dom_node();
|
|
|
|
[[nodiscard]] GC::Ptr<DOM::Node const> dom_node() const;
|
|
|
|
void set_dom_node(GC::Ptr<DOM::Node>);
|
2022-03-21 11:19:02 +01:00
|
|
|
|
2024-10-14 16:07:56 +02:00
|
|
|
CSS::ImmutableComputedValues const& computed_values() const;
|
2022-03-10 15:50:57 +01:00
|
|
|
|
2025-02-05 23:37:21 +00:00
|
|
|
bool visible_for_hit_testing() const;
|
2022-10-20 01:43:31 +03:00
|
|
|
|
2024-11-15 04:01:23 +13:00
|
|
|
GC::Ptr<HTML::Navigable> navigable() const;
|
2024-01-14 13:46:52 +01:00
|
|
|
|
2024-09-02 16:47:32 +01:00
|
|
|
virtual void set_needs_display(InvalidateDisplayList = InvalidateDisplayList::Yes);
|
2022-03-10 22:46:35 +01:00
|
|
|
|
2024-10-14 16:07:56 +02:00
|
|
|
PaintableBox* containing_block() const;
|
2022-03-12 00:35:49 +01:00
|
|
|
|
2022-04-08 15:19:02 +02:00
|
|
|
template<typename T>
|
|
|
|
bool fast_is() const = delete;
|
|
|
|
|
2023-08-18 13:47:52 +02:00
|
|
|
[[nodiscard]] virtual bool is_paintable_box() const { return false; }
|
|
|
|
[[nodiscard]] virtual bool is_paintable_with_lines() const { return false; }
|
2024-03-02 11:17:33 +01:00
|
|
|
[[nodiscard]] virtual bool is_svg_paintable() const { return false; }
|
2024-03-18 10:25:07 +01:00
|
|
|
[[nodiscard]] virtual bool is_text_paintable() const { return false; }
|
2023-08-18 13:47:52 +02:00
|
|
|
|
2024-10-14 16:07:56 +02:00
|
|
|
DOM::Document const& document() const;
|
|
|
|
DOM::Document& document();
|
2024-01-03 02:40:31 +01:00
|
|
|
|
2024-01-14 11:14:20 +01:00
|
|
|
CSSPixelPoint box_type_agnostic_position() const;
|
|
|
|
|
2024-03-18 07:42:38 +01:00
|
|
|
enum class SelectionState : u8 {
|
|
|
|
None, // No selection
|
|
|
|
Start, // Selection starts in this Node
|
|
|
|
End, // Selection ends in this Node
|
|
|
|
StartAndEnd, // Selection starts and ends in this Node
|
|
|
|
Full, // Selection starts before and ends after this Node
|
|
|
|
};
|
|
|
|
|
|
|
|
SelectionState selection_state() const { return m_selection_state; }
|
|
|
|
void set_selection_state(SelectionState state) { m_selection_state = state; }
|
|
|
|
|
2024-04-26 18:04:15 +02:00
|
|
|
Gfx::AffineTransform compute_combined_css_transform() const;
|
|
|
|
|
2024-10-14 16:07:56 +02:00
|
|
|
virtual void resolve_paint_properties() { }
|
|
|
|
|
|
|
|
virtual void finalize() override
|
|
|
|
{
|
|
|
|
if (m_list_node.is_in_list())
|
|
|
|
m_list_node.remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
friend class Layout::Node;
|
2024-07-22 18:43:01 +03:00
|
|
|
|
2022-03-10 15:50:57 +01:00
|
|
|
protected:
|
2023-08-18 13:21:38 +02:00
|
|
|
explicit Paintable(Layout::Node const&);
|
2022-03-09 23:53:41 +01:00
|
|
|
|
2023-01-11 12:51:49 +01:00
|
|
|
virtual void visit_edges(Cell::Visitor&) override;
|
|
|
|
|
2022-03-10 15:50:57 +01:00
|
|
|
private:
|
2024-10-14 16:07:56 +02:00
|
|
|
IntrusiveListNode<Paintable> m_list_node;
|
2024-11-15 04:01:23 +13:00
|
|
|
GC::Ptr<DOM::Node> m_dom_node;
|
|
|
|
GC::Ref<Layout::Node const> m_layout_node;
|
|
|
|
Optional<GC::Ptr<PaintableBox>> mutable m_containing_block;
|
2024-01-03 02:40:31 +01:00
|
|
|
|
2024-03-18 07:42:38 +01:00
|
|
|
SelectionState m_selection_state { SelectionState::None };
|
|
|
|
|
2024-03-02 11:03:02 +01:00
|
|
|
bool m_positioned : 1 { false };
|
|
|
|
bool m_fixed_position : 1 { false };
|
2024-08-24 19:20:31 +02:00
|
|
|
bool m_sticky_position : 1 { false };
|
2024-03-02 11:03:02 +01:00
|
|
|
bool m_absolutely_positioned : 1 { false };
|
|
|
|
bool m_floating : 1 { false };
|
|
|
|
bool m_inline : 1 { false };
|
2022-03-10 15:50:57 +01:00
|
|
|
};
|
2022-03-09 23:53:41 +01:00
|
|
|
|
2022-03-21 11:16:02 +01:00
|
|
|
inline DOM::Node* HitTestResult::dom_node()
|
|
|
|
{
|
2022-03-21 11:19:02 +01:00
|
|
|
return paintable->dom_node();
|
2022-03-21 11:16:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline DOM::Node const* HitTestResult::dom_node() const
|
|
|
|
{
|
2022-03-21 11:19:02 +01:00
|
|
|
return paintable->dom_node();
|
2022-03-21 11:16:02 +01:00
|
|
|
}
|
|
|
|
|
2022-04-08 15:19:02 +02:00
|
|
|
template<>
|
2023-08-18 13:47:52 +02:00
|
|
|
inline bool Paintable::fast_is<PaintableBox>() const { return is_paintable_box(); }
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool Paintable::fast_is<PaintableWithLines>() const { return is_paintable_with_lines(); }
|
2022-04-08 15:19:02 +02:00
|
|
|
|
2024-03-18 10:25:07 +01:00
|
|
|
template<>
|
|
|
|
inline bool Paintable::fast_is<TextPaintable>() const { return is_text_paintable(); }
|
|
|
|
|
2024-07-22 18:43:01 +03:00
|
|
|
Painting::BorderRadiiData normalize_border_radii_data(Layout::Node const& node, CSSPixelRect const& rect, CSS::BorderRadiusData const& top_left_radius, CSS::BorderRadiusData const& top_right_radius, CSS::BorderRadiusData const& bottom_right_radius, CSS::BorderRadiusData const& bottom_left_radius);
|
|
|
|
|
2022-03-09 23:53:41 +01:00
|
|
|
}
|