mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:18:11 +00:00

The absolute rect of a paintable is somewhat expensive to compute. This is because all coordinates are relative to the nearest containing block, so we have to traverse the containing block chain and apply each offset to get the final rect. Paintables will never move between containing blocks, nor will their absolute rect change. If anything changes, we'll simpl make a new paintable and replace the old one. Take advantage of this by caching the containing block and absolute rect after first access.
89 lines
2.8 KiB
C++
89 lines
2.8 KiB
C++
/*
|
|
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/NonnullOwnPtr.h>
|
|
#include <LibWeb/Layout/Box.h>
|
|
#include <LibWeb/Layout/LineBox.h>
|
|
#include <LibWeb/Layout/TextNode.h>
|
|
|
|
namespace Web::Painting {
|
|
|
|
enum class PaintPhase {
|
|
Background,
|
|
Border,
|
|
Foreground,
|
|
FocusOutline,
|
|
Overlay,
|
|
};
|
|
|
|
struct HitTestResult {
|
|
RefPtr<Painting::Paintable> paintable;
|
|
int index_in_node { 0 };
|
|
|
|
enum InternalPosition {
|
|
None,
|
|
Before,
|
|
Inside,
|
|
After,
|
|
};
|
|
InternalPosition internal_position { None };
|
|
};
|
|
|
|
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<Paintable> {
|
|
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 HitTestResult hit_test(Gfx::IntPoint const&, HitTestType) const;
|
|
|
|
virtual bool wants_mouse_events() const { return false; }
|
|
virtual void handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
|
|
virtual void handle_mouseup(Badge<EventHandler>, const Gfx::IntPoint&, unsigned button, unsigned modifiers);
|
|
virtual void handle_mousemove(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers);
|
|
virtual bool handle_mousewheel(Badge<EventHandler>, 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<Layout::Node&>(m_layout_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<Layout::Node&>(m_layout_node).set_needs_display(); }
|
|
|
|
Layout::BlockContainer const* containing_block() const
|
|
{
|
|
if (!m_containing_block.has_value())
|
|
m_containing_block = const_cast<Layout::Node&>(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<Layout::BlockContainer*> mutable m_containing_block;
|
|
};
|
|
|
|
}
|