PaintableBox.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 before_paint(PaintContext&, PaintPhase) const override;
  18. virtual void after_paint(PaintContext&, PaintPhase) const override;
  19. virtual void paint(PaintContext&, PaintPhase) const override;
  20. [[nodiscard]] bool is_visible() const;
  21. virtual Optional<CSSPixelRect> get_masking_area() const { return {}; }
  22. virtual Optional<Gfx::Bitmap::MaskKind> get_mask_type() const { return {}; }
  23. virtual RefPtr<Gfx::Bitmap> calculate_mask(PaintContext&, CSSPixelRect const&) const { return {}; }
  24. Layout::Box& layout_box() { return static_cast<Layout::Box&>(Paintable::layout_node()); }
  25. Layout::Box const& layout_box() const { return static_cast<Layout::Box const&>(Paintable::layout_node()); }
  26. auto const& box_model() const { return layout_box().box_model(); }
  27. struct OverflowData {
  28. CSSPixelRect scrollable_overflow_rect;
  29. bool has_scrollable_overflow { false };
  30. CSSPixelPoint scroll_offset {};
  31. };
  32. CSSPixelRect absolute_rect() const;
  33. // Offset from the top left of the containing block's content edge.
  34. [[nodiscard]] CSSPixelPoint offset() const;
  35. CSSPixelPoint scroll_offset() const;
  36. void set_scroll_offset(CSSPixelPoint);
  37. void scroll_by(int delta_x, int delta_y);
  38. void set_offset(CSSPixelPoint);
  39. void set_offset(float x, float y) { set_offset({ x, y }); }
  40. CSSPixelSize const& content_size() const { return m_content_size; }
  41. void set_content_size(CSSPixelSize);
  42. void set_content_size(CSSPixels width, CSSPixels height) { set_content_size({ width, height }); }
  43. void set_content_width(CSSPixels width) { set_content_size(width, content_height()); }
  44. void set_content_height(CSSPixels height) { set_content_size(content_width(), height); }
  45. CSSPixels content_width() const { return m_content_size.width(); }
  46. CSSPixels content_height() const { return m_content_size.height(); }
  47. CSSPixelRect absolute_padding_box_rect() const
  48. {
  49. auto absolute_rect = this->absolute_rect();
  50. CSSPixelRect rect;
  51. rect.set_x(absolute_rect.x() - box_model().padding.left);
  52. rect.set_width(content_width() + box_model().padding.left + box_model().padding.right);
  53. rect.set_y(absolute_rect.y() - box_model().padding.top);
  54. rect.set_height(content_height() + box_model().padding.top + box_model().padding.bottom);
  55. return rect;
  56. }
  57. CSSPixelRect absolute_border_box_rect() const
  58. {
  59. auto padded_rect = this->absolute_padding_box_rect();
  60. CSSPixelRect rect;
  61. auto use_collapsing_borders_model = override_borders_data().has_value();
  62. // Implement the collapsing border model https://www.w3.org/TR/CSS22/tables.html#collapsing-borders.
  63. auto border_top = use_collapsing_borders_model ? round(box_model().border.top / 2) : box_model().border.top;
  64. auto border_bottom = use_collapsing_borders_model ? round(box_model().border.bottom / 2) : box_model().border.bottom;
  65. auto border_left = use_collapsing_borders_model ? round(box_model().border.left / 2) : box_model().border.left;
  66. auto border_right = use_collapsing_borders_model ? round(box_model().border.right / 2) : box_model().border.right;
  67. rect.set_x(padded_rect.x() - border_left);
  68. rect.set_width(padded_rect.width() + border_left + border_right);
  69. rect.set_y(padded_rect.y() - border_top);
  70. rect.set_height(padded_rect.height() + border_top + border_bottom);
  71. return rect;
  72. }
  73. CSSPixelRect absolute_paint_rect() const;
  74. CSSPixels border_box_width() const
  75. {
  76. auto border_box = box_model().border_box();
  77. return content_width() + border_box.left + border_box.right;
  78. }
  79. CSSPixels border_box_height() const
  80. {
  81. auto border_box = box_model().border_box();
  82. return content_height() + border_box.top + border_box.bottom;
  83. }
  84. CSSPixels absolute_x() const { return absolute_rect().x(); }
  85. CSSPixels absolute_y() const { return absolute_rect().y(); }
  86. CSSPixelPoint absolute_position() const { return absolute_rect().location(); }
  87. [[nodiscard]] bool has_scrollable_overflow() const { return m_overflow_data->has_scrollable_overflow; }
  88. [[nodiscard]] Optional<CSSPixelRect> scrollable_overflow_rect() const
  89. {
  90. if (!m_overflow_data.has_value())
  91. return {};
  92. return m_overflow_data->scrollable_overflow_rect;
  93. }
  94. Optional<CSSPixelRect> calculate_overflow_clipped_rect() const;
  95. void set_overflow_data(OverflowData data) { m_overflow_data = move(data); }
  96. StackingContext* stacking_context() { return m_stacking_context; }
  97. StackingContext const* stacking_context() const { return m_stacking_context; }
  98. void set_stacking_context(NonnullOwnPtr<StackingContext>);
  99. StackingContext* enclosing_stacking_context();
  100. DOM::Node const* dom_node() const { return layout_box().dom_node(); }
  101. DOM::Node* dom_node() { return layout_box().dom_node(); }
  102. DOM::Document const& document() const { return layout_box().document(); }
  103. DOM::Document& document() { return layout_box().document(); }
  104. virtual void before_children_paint(PaintContext&, PaintPhase) const override;
  105. virtual void after_children_paint(PaintContext&, PaintPhase) const override;
  106. virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const override;
  107. virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const override;
  108. virtual Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const override;
  109. virtual bool handle_mousewheel(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) override;
  110. void invalidate_stacking_context();
  111. enum class ConflictingElementKind {
  112. Cell,
  113. Row,
  114. RowGroup,
  115. Column,
  116. ColumnGroup,
  117. Table,
  118. };
  119. struct BorderDataWithElementKind {
  120. CSS::BorderData border_data;
  121. ConflictingElementKind element_kind;
  122. };
  123. struct BordersDataWithElementKind {
  124. BorderDataWithElementKind top;
  125. BorderDataWithElementKind right;
  126. BorderDataWithElementKind bottom;
  127. BorderDataWithElementKind left;
  128. };
  129. void set_override_borders_data(BordersDataWithElementKind const& override_borders_data) { m_override_borders_data = override_borders_data; }
  130. Optional<BordersDataWithElementKind> const& override_borders_data() const { return m_override_borders_data; }
  131. static BordersData remove_element_kind_from_borders_data(PaintableBox::BordersDataWithElementKind borders_data);
  132. struct TableCellCoordinates {
  133. size_t row_index;
  134. size_t column_index;
  135. size_t row_span;
  136. size_t column_span;
  137. };
  138. void set_table_cell_coordinates(TableCellCoordinates const& table_cell_coordinates) { m_table_cell_coordinates = table_cell_coordinates; }
  139. auto const& table_cell_coordinates() const { return m_table_cell_coordinates; }
  140. enum class ShrinkRadiiForBorders {
  141. Yes,
  142. No
  143. };
  144. BorderRadiiData normalized_border_radii_data(ShrinkRadiiForBorders shrink = ShrinkRadiiForBorders::No) const;
  145. BorderRadiiData const& border_radii_data() const { return m_border_radii_data; }
  146. void set_border_radii_data(BorderRadiiData const& border_radii_data) { m_border_radii_data = border_radii_data; }
  147. protected:
  148. explicit PaintableBox(Layout::Box const&);
  149. Optional<CSSPixelRect> get_clip_rect() const;
  150. virtual void paint_border(PaintContext&) const;
  151. virtual void paint_backdrop_filter(PaintContext&) const;
  152. virtual void paint_background(PaintContext&) const;
  153. virtual void paint_box_shadow(PaintContext&) const;
  154. virtual CSSPixelRect compute_absolute_rect() const;
  155. virtual CSSPixelRect compute_absolute_paint_rect() const;
  156. Vector<ShadowData> resolve_box_shadow_data() const;
  157. private:
  158. [[nodiscard]] virtual bool is_paintable_box() const final { return true; }
  159. Optional<OverflowData> m_overflow_data;
  160. CSSPixelPoint m_offset;
  161. CSSPixelSize m_content_size;
  162. OwnPtr<StackingContext> m_stacking_context;
  163. Optional<CSSPixelRect> mutable m_absolute_rect;
  164. Optional<CSSPixelRect> mutable m_absolute_paint_rect;
  165. Optional<CSSPixelRect> mutable m_clip_rect;
  166. mutable bool m_clipping_overflow { false };
  167. mutable Optional<u32> m_corner_clipper_id;
  168. Optional<BordersDataWithElementKind> m_override_borders_data;
  169. Optional<TableCellCoordinates> m_table_cell_coordinates;
  170. BorderRadiiData m_border_radii_data;
  171. };
  172. class PaintableWithLines : public PaintableBox {
  173. JS_CELL(PaintableWithLines, PaintableBox);
  174. public:
  175. static JS::NonnullGCPtr<PaintableWithLines> create(Layout::BlockContainer const&);
  176. virtual ~PaintableWithLines() override;
  177. Layout::BlockContainer const& layout_box() const;
  178. Layout::BlockContainer& layout_box();
  179. Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
  180. void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
  181. template<typename Callback>
  182. void for_each_fragment(Callback callback) const
  183. {
  184. for (auto& line_box : line_boxes()) {
  185. for (auto& fragment : line_box.fragments()) {
  186. if (callback(fragment) == IterationDecision::Break)
  187. return;
  188. }
  189. }
  190. }
  191. virtual void paint(PaintContext&, PaintPhase) const override;
  192. virtual bool wants_mouse_events() const override { return false; }
  193. virtual Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const override;
  194. protected:
  195. PaintableWithLines(Layout::BlockContainer const&);
  196. private:
  197. [[nodiscard]] virtual bool is_paintable_with_lines() const final { return true; }
  198. Vector<Layout::LineBox> m_line_boxes;
  199. };
  200. }