LayoutState.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/HashMap.h>
  8. #include <LibGfx/Point.h>
  9. #include <LibWeb/Layout/Box.h>
  10. #include <LibWeb/Layout/LineBox.h>
  11. #include <LibWeb/Painting/PaintableBox.h>
  12. #include <LibWeb/Painting/SVGGraphicsPaintable.h>
  13. namespace Web::Layout {
  14. enum class SizeConstraint {
  15. None,
  16. MinContent,
  17. MaxContent,
  18. };
  19. class AvailableSize;
  20. class AvailableSpace;
  21. struct LayoutState {
  22. LayoutState()
  23. : m_root(*this)
  24. {
  25. }
  26. explicit LayoutState(LayoutState const* parent);
  27. ~LayoutState();
  28. LayoutState const& find_root() const
  29. {
  30. LayoutState const* root = this;
  31. for (auto* state = m_parent; state; state = state->m_parent)
  32. root = state;
  33. return *root;
  34. }
  35. struct UsedValues {
  36. NodeWithStyle const& node() const { return *m_node; }
  37. void set_node(NodeWithStyle&, UsedValues const* containing_block_used_values);
  38. UsedValues const* containing_block_used_values() const { return m_containing_block_used_values; }
  39. CSSPixels content_width() const { return m_content_width; }
  40. CSSPixels content_height() const { return m_content_height; }
  41. void set_content_width(CSSPixels);
  42. void set_content_height(CSSPixels);
  43. void set_indefinite_content_width();
  44. void set_indefinite_content_height();
  45. void set_has_definite_width(bool has_definite_width) { m_has_definite_width = has_definite_width; }
  46. void set_has_definite_height(bool has_definite_height) { m_has_definite_height = has_definite_height; }
  47. // NOTE: These are used by FlexFormattingContext to assign a temporary main size to items
  48. // early on, so that descendants have something to resolve percentages against.
  49. void set_temporary_content_width(CSSPixels);
  50. void set_temporary_content_height(CSSPixels);
  51. bool has_definite_width() const { return m_has_definite_width && width_constraint == SizeConstraint::None; }
  52. bool has_definite_height() const { return m_has_definite_height && height_constraint == SizeConstraint::None; }
  53. // Returns the available space for content inside this layout box.
  54. // If the space in an axis is indefinite, and the outer space is an intrinsic sizing constraint,
  55. // the constraint is used in that axis instead.
  56. AvailableSpace available_inner_space_or_constraints_from(AvailableSpace const& outer_space) const;
  57. void set_content_offset(CSSPixelPoint);
  58. void set_content_x(CSSPixels);
  59. void set_content_y(CSSPixels);
  60. CSSPixelPoint offset;
  61. SizeConstraint width_constraint { SizeConstraint::None };
  62. SizeConstraint height_constraint { SizeConstraint::None };
  63. CSSPixels margin_left { 0 };
  64. CSSPixels margin_right { 0 };
  65. CSSPixels margin_top { 0 };
  66. CSSPixels margin_bottom { 0 };
  67. CSSPixels border_left { 0 };
  68. CSSPixels border_right { 0 };
  69. CSSPixels border_top { 0 };
  70. CSSPixels border_bottom { 0 };
  71. CSSPixels padding_left { 0 };
  72. CSSPixels padding_right { 0 };
  73. CSSPixels padding_top { 0 };
  74. CSSPixels padding_bottom { 0 };
  75. CSSPixels inset_left { 0 };
  76. CSSPixels inset_right { 0 };
  77. CSSPixels inset_top { 0 };
  78. CSSPixels inset_bottom { 0 };
  79. // Used for calculating the static position of an abspos block-level box.
  80. CSSPixels vertical_offset_of_parent_block_container { 0 };
  81. Vector<LineBox> line_boxes;
  82. CSSPixels margin_box_left() const { return margin_left + border_left_collapsed() + padding_left; }
  83. CSSPixels margin_box_right() const { return margin_right + border_right_collapsed() + padding_right; }
  84. CSSPixels margin_box_top() const { return margin_top + border_top_collapsed() + padding_top; }
  85. CSSPixels margin_box_bottom() const { return margin_bottom + border_bottom_collapsed() + padding_bottom; }
  86. CSSPixels margin_box_width() const { return margin_box_left() + content_width() + margin_box_right(); }
  87. CSSPixels margin_box_height() const { return margin_box_top() + content_height() + margin_box_bottom(); }
  88. CSSPixels border_box_left() const { return border_left_collapsed() + padding_left; }
  89. CSSPixels border_box_right() const { return border_right_collapsed() + padding_right; }
  90. CSSPixels border_box_top() const { return border_top_collapsed() + padding_top; }
  91. CSSPixels border_box_bottom() const { return border_bottom_collapsed() + padding_bottom; }
  92. CSSPixels border_box_width() const { return border_box_left() + content_width() + border_box_right(); }
  93. CSSPixels border_box_height() const { return border_box_top() + content_height() + border_box_bottom(); }
  94. Optional<LineBoxFragmentCoordinate> containing_line_box_fragment;
  95. void add_floating_descendant(Box const& box) { m_floating_descendants.set(&box); }
  96. auto const& floating_descendants() const { return m_floating_descendants; }
  97. void set_override_borders_data(Painting::PaintableBox::BordersDataWithElementKind const& override_borders_data) { m_override_borders_data = override_borders_data; }
  98. auto const& override_borders_data() const { return m_override_borders_data; }
  99. void set_table_cell_coordinates(Painting::PaintableBox::TableCellCoordinates const& table_cell_coordinates) { m_table_cell_coordinates = table_cell_coordinates; }
  100. auto const& table_cell_coordinates() const { return m_table_cell_coordinates; }
  101. void set_computed_svg_path(Gfx::Path const& svg_path) { m_computed_svg_path = svg_path; }
  102. auto& computed_svg_path() { return m_computed_svg_path; }
  103. void set_computed_svg_transforms(Painting::SVGGraphicsPaintable::ComputedTransforms const& computed_transforms) { m_computed_svg_transforms = computed_transforms; }
  104. auto const& computed_svg_transforms() const { return m_computed_svg_transforms; }
  105. private:
  106. AvailableSize available_width_inside() const;
  107. AvailableSize available_height_inside() const;
  108. bool use_collapsing_borders_model() const { return m_override_borders_data.has_value(); }
  109. // Implement the collapsing border model https://www.w3.org/TR/CSS22/tables.html#collapsing-borders.
  110. CSSPixels border_left_collapsed() const { return use_collapsing_borders_model() ? round(border_left / 2) : border_left; }
  111. CSSPixels border_right_collapsed() const { return use_collapsing_borders_model() ? round(border_right / 2) : border_right; }
  112. CSSPixels border_top_collapsed() const { return use_collapsing_borders_model() ? round(border_top / 2) : border_top; }
  113. CSSPixels border_bottom_collapsed() const { return use_collapsing_borders_model() ? round(border_bottom / 2) : border_bottom; }
  114. JS::GCPtr<Layout::NodeWithStyle> m_node { nullptr };
  115. UsedValues const* m_containing_block_used_values { nullptr };
  116. CSSPixels m_content_width { 0 };
  117. CSSPixels m_content_height { 0 };
  118. bool m_has_definite_width { false };
  119. bool m_has_definite_height { false };
  120. HashTable<JS::GCPtr<Box const>> m_floating_descendants;
  121. Optional<Painting::PaintableBox::BordersDataWithElementKind> m_override_borders_data;
  122. Optional<Painting::PaintableBox::TableCellCoordinates> m_table_cell_coordinates;
  123. Optional<Gfx::Path> m_computed_svg_path;
  124. Optional<Painting::SVGGraphicsPaintable::ComputedTransforms> m_computed_svg_transforms;
  125. };
  126. // Commits the used values produced by layout and builds a paintable tree.
  127. void commit(Box& root);
  128. // NOTE: get_mutable() will CoW the UsedValues if it's inherited from an ancestor state;
  129. UsedValues& get_mutable(NodeWithStyle const&);
  130. // NOTE: get() will not CoW the UsedValues.
  131. UsedValues const& get(NodeWithStyle const&) const;
  132. HashMap<Layout::Node const*, NonnullOwnPtr<UsedValues>> used_values_per_layout_node;
  133. // We cache intrinsic sizes once determined, as they will not change over the course of a full layout.
  134. // This avoids computing them several times while performing flex layout.
  135. struct IntrinsicSizes {
  136. Optional<CSSPixels> min_content_width;
  137. Optional<CSSPixels> max_content_width;
  138. HashMap<CSSPixels, Optional<CSSPixels>> min_content_height;
  139. HashMap<CSSPixels, Optional<CSSPixels>> max_content_height;
  140. };
  141. HashMap<JS::GCPtr<NodeWithStyle const>, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes;
  142. LayoutState const* m_parent { nullptr };
  143. LayoutState const& m_root;
  144. private:
  145. void resolve_relative_positions();
  146. };
  147. }