FlexFormattingContext.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (c) 2021-2024, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <LibWeb/Layout/Box.h>
  8. #include <LibWeb/Layout/FormattingContext.h>
  9. namespace Web::Layout {
  10. class FlexFormattingContext final : public FormattingContext {
  11. public:
  12. FlexFormattingContext(LayoutState&, Box const& flex_container, FormattingContext* parent);
  13. ~FlexFormattingContext();
  14. virtual bool inhibits_floating() const override { return true; }
  15. virtual void run(Box const&, LayoutMode, AvailableSpace const&) override;
  16. virtual CSSPixels automatic_content_width() const override;
  17. virtual CSSPixels automatic_content_height() const override;
  18. Box const& flex_container() const { return context_box(); }
  19. virtual CSSPixelPoint calculate_static_position(Box const&) const override;
  20. private:
  21. [[nodiscard]] bool should_treat_main_size_as_auto(Box const&) const;
  22. [[nodiscard]] bool should_treat_cross_size_as_auto(Box const&) const;
  23. [[nodiscard]] bool should_treat_main_max_size_as_none(Box const&) const;
  24. [[nodiscard]] bool should_treat_cross_max_size_as_none(Box const&) const;
  25. [[nodiscard]] CSSPixels adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(Box const&, CSSPixels main_size, CSS::Size const& min_cross_size, CSS::Size const& max_cross_size) const;
  26. [[nodiscard]] CSSPixels calculate_main_size_from_cross_size_and_aspect_ratio(CSSPixels cross_size, CSSPixelFraction aspect_ratio) const;
  27. [[nodiscard]] CSSPixels calculate_cross_size_from_main_size_and_aspect_ratio(CSSPixels main_size, CSSPixelFraction aspect_ratio) const;
  28. void dump_items() const;
  29. struct DirectionAgnosticMargins {
  30. CSSPixels main_before { 0 };
  31. CSSPixels main_after { 0 };
  32. CSSPixels cross_before { 0 };
  33. CSSPixels cross_after { 0 };
  34. bool main_before_is_auto { false };
  35. bool main_after_is_auto { false };
  36. bool cross_before_is_auto { false };
  37. bool cross_after_is_auto { false };
  38. };
  39. struct FlexItem {
  40. JS::NonnullGCPtr<Box> box;
  41. LayoutState::UsedValues& used_values;
  42. Optional<CSS::FlexBasis> used_flex_basis {};
  43. bool used_flex_basis_is_definite { false };
  44. CSSPixels flex_base_size { 0 };
  45. CSSPixels hypothetical_main_size { 0 };
  46. CSSPixels hypothetical_cross_size { 0 };
  47. CSSPixels hypothetical_cross_size_with_margins() { return hypothetical_cross_size + margins.cross_before + margins.cross_after + borders.cross_after + borders.cross_before + padding.cross_after + padding.cross_before; }
  48. CSSPixels target_main_size { 0 };
  49. bool frozen { false };
  50. Optional<double> flex_factor {};
  51. double scaled_flex_shrink_factor { 0 };
  52. double desired_flex_fraction { 0 };
  53. CSSPixels outer_hypothetical_main_size() const
  54. {
  55. return hypothetical_main_size + margins.main_before + margins.main_after + borders.main_before + borders.main_after + padding.main_before + padding.main_after;
  56. }
  57. CSSPixels outer_target_main_size() const
  58. {
  59. return target_main_size + margins.main_before + margins.main_after + borders.main_before + borders.main_after + padding.main_before + padding.main_after;
  60. }
  61. CSSPixels outer_flex_base_size() const
  62. {
  63. return flex_base_size + margins.main_before + margins.main_after + borders.main_before + borders.main_after + padding.main_before + padding.main_after;
  64. }
  65. // The used main size of this flex item. Empty until determined.
  66. Optional<CSSPixels> main_size {};
  67. // The used cross size of this flex item. Empty until determined.
  68. Optional<CSSPixels> cross_size {};
  69. CSSPixels main_offset { 0 };
  70. CSSPixels cross_offset { 0 };
  71. DirectionAgnosticMargins margins {};
  72. DirectionAgnosticMargins borders {};
  73. DirectionAgnosticMargins padding {};
  74. bool is_min_violation { false };
  75. bool is_max_violation { false };
  76. CSSPixels add_main_margin_box_sizes(CSSPixels content_size) const
  77. {
  78. return content_size + margins.main_before + margins.main_after + borders.main_before + borders.main_after + padding.main_before + padding.main_after;
  79. }
  80. CSSPixels add_cross_margin_box_sizes(CSSPixels content_size) const
  81. {
  82. return content_size + margins.cross_before + margins.cross_after + borders.cross_before + borders.cross_after + padding.cross_before + padding.cross_after;
  83. }
  84. };
  85. struct FlexLine {
  86. Vector<FlexItem&> items;
  87. CSSPixels cross_size { 0 };
  88. Optional<CSSPixels> remaining_free_space;
  89. double chosen_flex_fraction { 0 };
  90. double sum_of_flex_factor_of_unfrozen_items() const;
  91. double sum_of_scaled_flex_shrink_factor_of_unfrozen_items() const;
  92. };
  93. CSSPixels main_gap() const;
  94. CSSPixels cross_gap() const;
  95. [[nodiscard]] bool has_definite_main_size(LayoutState::UsedValues const&) const;
  96. [[nodiscard]] bool has_definite_cross_size(LayoutState::UsedValues const&) const;
  97. [[nodiscard]] bool has_definite_main_size(FlexItem const& item) const { return has_definite_main_size(item.used_values); }
  98. [[nodiscard]] bool has_definite_cross_size(FlexItem const& item) const { return has_definite_cross_size(item.used_values); }
  99. [[nodiscard]] CSSPixels inner_main_size(LayoutState::UsedValues const&) const;
  100. [[nodiscard]] CSSPixels inner_cross_size(LayoutState::UsedValues const&) const;
  101. [[nodiscard]] CSSPixels inner_main_size(FlexItem const& item) const { return inner_main_size(item.used_values); }
  102. [[nodiscard]] CSSPixels inner_cross_size(FlexItem const& item) const { return inner_cross_size(item.used_values); }
  103. bool has_main_min_size(Box const&) const;
  104. bool has_cross_min_size(Box const&) const;
  105. CSSPixels specified_main_max_size(Box const&) const;
  106. CSSPixels specified_cross_max_size(Box const&) const;
  107. bool is_cross_auto(Box const&) const;
  108. CSSPixels specified_main_min_size(Box const&) const;
  109. CSSPixels specified_cross_min_size(Box const&) const;
  110. bool has_main_max_size(Box const&) const;
  111. bool has_cross_max_size(Box const&) const;
  112. CSSPixels automatic_minimum_size(FlexItem const&) const;
  113. CSSPixels content_based_minimum_size(FlexItem const&) const;
  114. Optional<CSSPixels> specified_size_suggestion(FlexItem const&) const;
  115. Optional<CSSPixels> transferred_size_suggestion(FlexItem const&) const;
  116. CSSPixels content_size_suggestion(FlexItem const&) const;
  117. CSS::Size const& computed_main_size(Box const&) const;
  118. CSS::Size const& computed_main_min_size(Box const&) const;
  119. CSS::Size const& computed_main_max_size(Box const&) const;
  120. CSS::Size const& computed_cross_size(Box const&) const;
  121. CSS::Size const& computed_cross_min_size(Box const&) const;
  122. CSS::Size const& computed_cross_max_size(Box const&) const;
  123. CSSPixels get_pixel_width(Box const&, CSS::Size const&) const;
  124. CSSPixels get_pixel_height(Box const&, CSS::Size const&) const;
  125. bool flex_item_is_stretched(FlexItem const&) const;
  126. void set_main_size(Box const&, CSSPixels size);
  127. void set_cross_size(Box const&, CSSPixels size);
  128. void set_offset(Box const&, CSSPixels main_offset, CSSPixels cross_offset);
  129. void set_main_axis_first_margin(FlexItem&, CSSPixels margin);
  130. void set_main_axis_second_margin(FlexItem&, CSSPixels margin);
  131. void set_has_definite_main_size(FlexItem&);
  132. void set_has_definite_cross_size(FlexItem&);
  133. void copy_dimensions_from_flex_items_to_boxes();
  134. void generate_anonymous_flex_items();
  135. void determine_available_space_for_items(AvailableSpace const&);
  136. void determine_flex_base_size_and_hypothetical_main_size(FlexItem&);
  137. void collect_flex_items_into_flex_lines();
  138. void resolve_flexible_lengths();
  139. void resolve_flexible_lengths_for_line(FlexLine&);
  140. void resolve_cross_axis_auto_margins();
  141. void determine_hypothetical_cross_size_of_item(FlexItem&, bool resolve_percentage_min_max_sizes);
  142. void calculate_cross_size_of_each_flex_line();
  143. void handle_align_content_stretch();
  144. CSS::AlignItems alignment_for_item(Box const&) const;
  145. void determine_used_cross_size_of_each_flex_item();
  146. void distribute_any_remaining_free_space();
  147. void align_all_flex_items_along_the_cross_axis();
  148. void determine_flex_container_used_cross_size();
  149. void align_all_flex_lines();
  150. bool is_row_layout() const { return m_flex_direction == CSS::FlexDirection::Row || m_flex_direction == CSS::FlexDirection::RowReverse; }
  151. bool is_single_line() const { return flex_container().computed_values().flex_wrap() == CSS::FlexWrap::Nowrap; }
  152. bool is_direction_reverse() const { return m_flex_direction == CSS::FlexDirection::ColumnReverse || m_flex_direction == CSS::FlexDirection::RowReverse; }
  153. void populate_specified_margins(FlexItem&, CSS::FlexDirection) const;
  154. void determine_intrinsic_size_of_flex_container();
  155. [[nodiscard]] CSSPixels calculate_intrinsic_main_size_of_flex_container();
  156. [[nodiscard]] CSSPixels calculate_intrinsic_cross_size_of_flex_container();
  157. [[nodiscard]] CSSPixels calculate_cross_min_content_contribution(FlexItem const&, bool resolve_percentage_min_max_sizes) const;
  158. [[nodiscard]] CSSPixels calculate_cross_max_content_contribution(FlexItem const&, bool resolve_percentage_min_max_sizes) const;
  159. [[nodiscard]] CSSPixels calculate_main_min_content_contribution(FlexItem const&) const;
  160. [[nodiscard]] CSSPixels calculate_main_max_content_contribution(FlexItem const&) const;
  161. [[nodiscard]] CSSPixels calculate_min_content_main_size(FlexItem const&) const;
  162. [[nodiscard]] CSSPixels calculate_max_content_main_size(FlexItem const&) const;
  163. [[nodiscard]] CSSPixels calculate_min_content_cross_size(FlexItem const&) const;
  164. [[nodiscard]] CSSPixels calculate_max_content_cross_size(FlexItem const&) const;
  165. [[nodiscard]] CSSPixels calculate_fit_content_main_size(FlexItem const&) const;
  166. [[nodiscard]] CSSPixels calculate_fit_content_cross_size(FlexItem const&) const;
  167. [[nodiscard]] CSSPixels calculate_width_to_use_when_determining_intrinsic_height_of_item(FlexItem const&) const;
  168. virtual void parent_context_did_dimension_child_root_box() override;
  169. CSS::FlexBasis used_flex_basis_for_item(FlexItem const&) const;
  170. LayoutState::UsedValues& m_flex_container_state;
  171. Vector<FlexLine> m_flex_lines;
  172. Vector<FlexItem> m_flex_items;
  173. CSS::FlexDirection m_flex_direction {};
  174. struct AxisAgnosticAvailableSpace {
  175. AvailableSize main;
  176. AvailableSize cross;
  177. AvailableSpace space;
  178. };
  179. Optional<AxisAgnosticAvailableSpace> m_available_space_for_items;
  180. };
  181. }