/* * Copyright (c) 2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace Web::Painting { enum class PaintPhase { Background, Border, Foreground, FocusOutline, Overlay, }; struct HitTestResult { NonnullRefPtr paintable; int index_in_node { 0 }; enum InternalPosition { None, Before, Inside, After, }; InternalPosition internal_position { None }; DOM::Node* dom_node(); DOM::Node const* dom_node() const; }; enum class HitTestType { Exact, // Exact matches only TextCursor, // Clicking past the right/bottom edge of text will still hit the text }; class Paintable : public RefCounted { AK_MAKE_NONMOVABLE(Paintable); AK_MAKE_NONCOPYABLE(Paintable); public: virtual ~Paintable() = default; virtual void paint(PaintContext&, PaintPhase) const { } virtual void before_children_paint(PaintContext&, PaintPhase) const { } virtual void after_children_paint(PaintContext&, PaintPhase) const { } virtual Optional hit_test(Gfx::FloatPoint const&, HitTestType) const; virtual bool wants_mouse_events() const { return false; } 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. virtual DispatchEventOfSameName handle_mousedown(Badge, const Gfx::IntPoint&, unsigned button, unsigned modifiers); virtual DispatchEventOfSameName handle_mouseup(Badge, const Gfx::IntPoint&, unsigned button, unsigned modifiers); virtual DispatchEventOfSameName handle_mousemove(Badge, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers); virtual DOM::Node* mouse_event_target() const { return nullptr; } virtual bool handle_mousewheel(Badge, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y); Layout::Node const& layout_node() const { return m_layout_node; } Layout::Node& layout_node() { return const_cast(m_layout_node); } DOM::Node* dom_node() { return layout_node().dom_node(); } DOM::Node const* dom_node() const { return layout_node().dom_node(); } auto const& computed_values() const { return m_layout_node.computed_values(); } HTML::BrowsingContext const& browsing_context() const { return m_layout_node.browsing_context(); } HTML::BrowsingContext& browsing_context() { return layout_node().browsing_context(); } void set_needs_display() const { const_cast(m_layout_node).set_needs_display(); } Layout::BlockContainer const* containing_block() const { if (!m_containing_block.has_value()) m_containing_block = const_cast(m_layout_node).containing_block(); return *m_containing_block; } protected: explicit Paintable(Layout::Node const& layout_node) : m_layout_node(layout_node) { } private: Layout::Node const& m_layout_node; Optional mutable m_containing_block; }; inline DOM::Node* HitTestResult::dom_node() { return paintable->dom_node(); } inline DOM::Node const* HitTestResult::dom_node() const { return paintable->dom_node(); } }