PaintableBox.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <LibWeb/Painting/BorderPainting.h>
  8. #include <LibWeb/Painting/BorderRadiusCornerClipper.h>
  9. #include <LibWeb/Painting/Paintable.h>
  10. #include <LibWeb/Painting/ShadowPainting.h>
  11. namespace Web::Painting {
  12. class PaintableBox : public Paintable {
  13. JS_CELL(PaintableBox, Paintable);
  14. public:
  15. static JS::NonnullGCPtr<PaintableBox> create(Layout::Box const&);
  16. virtual ~PaintableBox();
  17. virtual void paint(PaintContext&, PaintPhase) const override;
  18. bool is_visible() const { return layout_box().is_visible(); }
  19. Layout::Box& layout_box() { return static_cast<Layout::Box&>(Paintable::layout_node()); }
  20. Layout::Box const& layout_box() const { return static_cast<Layout::Box const&>(Paintable::layout_node()); }
  21. auto const& box_model() const { return layout_box().box_model(); }
  22. struct OverflowData {
  23. CSSPixelRect scrollable_overflow_rect;
  24. bool has_scrollable_overflow { false };
  25. CSSPixelPoint scroll_offset {};
  26. };
  27. CSSPixelRect absolute_rect() const;
  28. CSSPixelPoint effective_offset() const;
  29. void set_offset(CSSPixelPoint);
  30. void set_offset(float x, float y) { set_offset({ x, y }); }
  31. CSSPixelSize const& content_size() const { return m_content_size; }
  32. void set_content_size(CSSPixelSize);
  33. void set_content_size(CSSPixels width, CSSPixels height) { set_content_size({ width, height }); }
  34. void set_content_width(CSSPixels width) { set_content_size(width, content_height()); }
  35. void set_content_height(CSSPixels height) { set_content_size(content_width(), height); }
  36. CSSPixels content_width() const { return m_content_size.width(); }
  37. CSSPixels content_height() const { return m_content_size.height(); }
  38. CSSPixelRect absolute_padding_box_rect() const
  39. {
  40. auto absolute_rect = this->absolute_rect();
  41. CSSPixelRect rect;
  42. rect.set_x(absolute_rect.x() - box_model().padding.left);
  43. rect.set_width(content_width() + box_model().padding.left + box_model().padding.right);
  44. rect.set_y(absolute_rect.y() - box_model().padding.top);
  45. rect.set_height(content_height() + box_model().padding.top + box_model().padding.bottom);
  46. return rect;
  47. }
  48. CSSPixelRect absolute_border_box_rect() const
  49. {
  50. auto padded_rect = this->absolute_padding_box_rect();
  51. CSSPixelRect rect;
  52. auto use_collapsing_borders_model = override_borders_data().has_value();
  53. // Implement the collapsing border model https://www.w3.org/TR/CSS22/tables.html#collapsing-borders.
  54. auto border_top = use_collapsing_borders_model ? round(box_model().border.top / 2) : box_model().border.top;
  55. auto border_bottom = use_collapsing_borders_model ? round(box_model().border.bottom / 2) : box_model().border.bottom;
  56. auto border_left = use_collapsing_borders_model ? round(box_model().border.left / 2) : box_model().border.left;
  57. auto border_right = use_collapsing_borders_model ? round(box_model().border.right / 2) : box_model().border.right;
  58. rect.set_x(padded_rect.x() - border_left);
  59. rect.set_width(padded_rect.width() + border_left + border_right);
  60. rect.set_y(padded_rect.y() - border_top);
  61. rect.set_height(padded_rect.height() + border_top + border_bottom);
  62. return rect;
  63. }
  64. CSSPixelRect absolute_paint_rect() const;
  65. CSSPixels border_box_width() const
  66. {
  67. auto border_box = box_model().border_box();
  68. return content_width() + border_box.left + border_box.right;
  69. }
  70. CSSPixels border_box_height() const
  71. {
  72. auto border_box = box_model().border_box();
  73. return content_height() + border_box.top + border_box.bottom;
  74. }
  75. CSSPixels absolute_x() const { return absolute_rect().x(); }
  76. CSSPixels absolute_y() const { return absolute_rect().y(); }
  77. CSSPixelPoint absolute_position() const { return absolute_rect().location(); }
  78. [[nodiscard]] bool has_scrollable_overflow() const { return m_overflow_data->has_scrollable_overflow; }
  79. [[nodiscard]] Optional<CSSPixelRect> scrollable_overflow_rect() const
  80. {
  81. if (!m_overflow_data.has_value())
  82. return {};
  83. return m_overflow_data->scrollable_overflow_rect;
  84. }
  85. Optional<CSSPixelRect> calculate_overflow_clipped_rect() const;
  86. void set_overflow_data(OverflowData data) { m_overflow_data = move(data); }
  87. void set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate>);
  88. StackingContext* stacking_context() { return m_stacking_context; }
  89. StackingContext const* stacking_context() const { return m_stacking_context; }
  90. void set_stacking_context(NonnullOwnPtr<StackingContext>);
  91. StackingContext* enclosing_stacking_context();
  92. DOM::Node const* dom_node() const { return layout_box().dom_node(); }
  93. DOM::Node* dom_node() { return layout_box().dom_node(); }
  94. DOM::Document const& document() const { return layout_box().document(); }
  95. DOM::Document& document() { return layout_box().document(); }
  96. virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const override;
  97. virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const override;
  98. virtual Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const override;
  99. void invalidate_stacking_context();
  100. bool is_out_of_view(PaintContext&) const;
  101. enum class ConflictingElementKind {
  102. Cell,
  103. Row,
  104. RowGroup,
  105. Column,
  106. ColumnGroup,
  107. Table,
  108. };
  109. struct BorderDataWithElementKind {
  110. CSS::BorderData border_data;
  111. ConflictingElementKind element_kind;
  112. };
  113. struct BordersDataWithElementKind {
  114. BorderDataWithElementKind top;
  115. BorderDataWithElementKind right;
  116. BorderDataWithElementKind bottom;
  117. BorderDataWithElementKind left;
  118. };
  119. void set_override_borders_data(BordersDataWithElementKind const& override_borders_data) { m_override_borders_data = override_borders_data; }
  120. Optional<BordersDataWithElementKind> const& override_borders_data() const { return m_override_borders_data; }
  121. static BordersData remove_element_kind_from_borders_data(PaintableBox::BordersDataWithElementKind borders_data);
  122. struct TableCellCoordinates {
  123. size_t row_index;
  124. size_t column_index;
  125. size_t row_span;
  126. size_t column_span;
  127. };
  128. void set_table_cell_coordinates(TableCellCoordinates const& table_cell_coordinates) { m_table_cell_coordinates = table_cell_coordinates; }
  129. auto const& table_cell_coordinates() const { return m_table_cell_coordinates; }
  130. enum class ShrinkRadiiForBorders {
  131. Yes,
  132. No
  133. };
  134. BorderRadiiData normalized_border_radii_data(ShrinkRadiiForBorders shrink = ShrinkRadiiForBorders::No) const;
  135. protected:
  136. explicit PaintableBox(Layout::Box const&);
  137. virtual void paint_border(PaintContext&) const;
  138. virtual void paint_backdrop_filter(PaintContext&) const;
  139. virtual void paint_background(PaintContext&) const;
  140. virtual void paint_box_shadow(PaintContext&) const;
  141. virtual CSSPixelRect compute_absolute_rect() const;
  142. virtual CSSPixelRect compute_absolute_paint_rect() const;
  143. Vector<ShadowData> resolve_box_shadow_data() const;
  144. private:
  145. Optional<OverflowData> m_overflow_data;
  146. CSSPixelPoint m_offset;
  147. CSSPixelSize m_content_size;
  148. // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
  149. Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
  150. OwnPtr<StackingContext> m_stacking_context;
  151. Optional<CSSPixelRect> mutable m_absolute_rect;
  152. Optional<CSSPixelRect> mutable m_absolute_paint_rect;
  153. Optional<CSSPixelRect> mutable m_clip_rect;
  154. mutable bool m_clipping_overflow { false };
  155. Optional<BorderRadiusCornerClipper> mutable m_overflow_corner_radius_clipper;
  156. Optional<BordersDataWithElementKind> m_override_borders_data;
  157. Optional<TableCellCoordinates> m_table_cell_coordinates;
  158. };
  159. class PaintableWithLines final : public PaintableBox {
  160. JS_CELL(PaintableWithLines, PaintableBox);
  161. public:
  162. static JS::NonnullGCPtr<PaintableWithLines> create(Layout::BlockContainer const&);
  163. virtual ~PaintableWithLines() override;
  164. Layout::BlockContainer const& layout_box() const;
  165. Layout::BlockContainer& layout_box();
  166. Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
  167. void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
  168. template<typename Callback>
  169. void for_each_fragment(Callback callback) const
  170. {
  171. for (auto& line_box : line_boxes()) {
  172. for (auto& fragment : line_box.fragments()) {
  173. if (callback(fragment) == IterationDecision::Break)
  174. return;
  175. }
  176. }
  177. }
  178. virtual void paint(PaintContext&, PaintPhase) const override;
  179. virtual bool wants_mouse_events() const override { return false; }
  180. virtual bool handle_mousewheel(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) override;
  181. virtual Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const override;
  182. protected:
  183. PaintableWithLines(Layout::BlockContainer const&);
  184. private:
  185. Vector<Layout::LineBox> m_line_boxes;
  186. };
  187. }