Paintable.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (c) 2022-2023, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/NonnullOwnPtr.h>
  8. #include <LibWeb/Layout/Box.h>
  9. #include <LibWeb/Layout/LineBox.h>
  10. #include <LibWeb/Layout/TextNode.h>
  11. namespace Web::Painting {
  12. enum class TraversalDecision {
  13. Continue,
  14. SkipChildrenAndContinue,
  15. Break,
  16. };
  17. enum class PaintPhase {
  18. Background,
  19. Border,
  20. Foreground,
  21. FocusOutline,
  22. Overlay,
  23. };
  24. struct HitTestResult {
  25. JS::Handle<Painting::Paintable> paintable;
  26. int index_in_node { 0 };
  27. enum InternalPosition {
  28. None,
  29. Before,
  30. Inside,
  31. After,
  32. };
  33. InternalPosition internal_position { None };
  34. DOM::Node* dom_node();
  35. DOM::Node const* dom_node() const;
  36. };
  37. enum class HitTestType {
  38. Exact, // Exact matches only
  39. TextCursor, // Clicking past the right/bottom edge of text will still hit the text
  40. };
  41. class Paintable : public JS::Cell {
  42. JS_CELL(Paintable, Cell);
  43. public:
  44. virtual ~Paintable() = default;
  45. Paintable const* first_child() const;
  46. Paintable const* last_child() const;
  47. Paintable const* next_sibling() const;
  48. Paintable const* previous_sibling() const;
  49. template<typename U, typename Callback>
  50. TraversalDecision for_each_in_inclusive_subtree_of_type(Callback callback) const
  51. {
  52. if (is<U>(*this)) {
  53. if (auto decision = callback(static_cast<U const&>(*this)); decision != TraversalDecision::Continue)
  54. return decision;
  55. }
  56. for (auto* child = first_child(); child; child = child->next_sibling()) {
  57. if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
  58. return TraversalDecision::Break;
  59. }
  60. return TraversalDecision::Continue;
  61. }
  62. template<typename U, typename Callback>
  63. TraversalDecision for_each_in_subtree_of_type(Callback callback) const
  64. {
  65. for (auto* child = first_child(); child; child = child->next_sibling()) {
  66. if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
  67. return TraversalDecision::Break;
  68. }
  69. return TraversalDecision::Continue;
  70. }
  71. virtual void paint(PaintContext&, PaintPhase) const { }
  72. virtual void before_children_paint(PaintContext&, PaintPhase) const { }
  73. virtual void after_children_paint(PaintContext&, PaintPhase) const { }
  74. virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const { }
  75. virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const { }
  76. virtual Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const;
  77. virtual bool wants_mouse_events() const { return false; }
  78. enum class DispatchEventOfSameName {
  79. Yes,
  80. No,
  81. };
  82. // When these methods return true, the DOM event with the same name will be
  83. // dispatch at the mouse_event_target if it returns a valid DOM::Node, or
  84. // the layout node's associated DOM node if it doesn't.
  85. virtual DispatchEventOfSameName handle_mousedown(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
  86. virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers);
  87. virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers);
  88. virtual DOM::Node* mouse_event_target() const { return nullptr; }
  89. virtual bool handle_mousewheel(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y);
  90. Layout::Node const& layout_node() const { return m_layout_node; }
  91. Layout::Node& layout_node() { return const_cast<Layout::Node&>(*m_layout_node); }
  92. DOM::Node* dom_node() { return layout_node().dom_node(); }
  93. DOM::Node const* dom_node() const { return layout_node().dom_node(); }
  94. auto const& computed_values() const { return m_layout_node->computed_values(); }
  95. bool visible_for_hit_testing() const { return computed_values().pointer_events() != CSS::PointerEvents::None; }
  96. HTML::BrowsingContext const& browsing_context() const { return m_layout_node->browsing_context(); }
  97. HTML::BrowsingContext& browsing_context() { return layout_node().browsing_context(); }
  98. void set_needs_display() const { const_cast<Layout::Node&>(*m_layout_node).set_needs_display(); }
  99. Layout::Box const* containing_block() const
  100. {
  101. if (!m_containing_block.has_value())
  102. m_containing_block = m_layout_node->containing_block();
  103. return *m_containing_block;
  104. }
  105. template<typename T>
  106. bool fast_is() const = delete;
  107. protected:
  108. explicit Paintable(Layout::Node const& layout_node)
  109. : m_layout_node(layout_node)
  110. {
  111. }
  112. virtual void visit_edges(Cell::Visitor&) override;
  113. private:
  114. JS::NonnullGCPtr<Layout::Node const> m_layout_node;
  115. Optional<JS::GCPtr<Layout::Box const>> mutable m_containing_block;
  116. };
  117. inline DOM::Node* HitTestResult::dom_node()
  118. {
  119. return paintable->dom_node();
  120. }
  121. inline DOM::Node const* HitTestResult::dom_node() const
  122. {
  123. return paintable->dom_node();
  124. }
  125. template<>
  126. inline bool Paintable::fast_is<PaintableBox>() const { return m_layout_node->is_box(); }
  127. }