Serenity Operating System
at master 189 lines 7.7 kB view raw
1/* 2 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/HashMap.h> 10#include <LibGfx/Point.h> 11#include <LibWeb/Layout/Box.h> 12#include <LibWeb/Layout/LineBox.h> 13#include <LibWeb/Painting/PaintableBox.h> 14 15namespace Web::Layout { 16 17enum class SizeConstraint { 18 None, 19 MinContent, 20 MaxContent, 21}; 22 23class AvailableSize; 24class AvailableSpace; 25 26struct LayoutState { 27 LayoutState() 28 : m_root(*this) 29 { 30 } 31 32 explicit LayoutState(LayoutState const* parent) 33 : m_parent(parent) 34 , m_root(find_root()) 35 { 36 used_values_per_layout_node.resize(m_root.used_values_per_layout_node.size()); 37 } 38 39 LayoutState const& find_root() const 40 { 41 LayoutState const* root = this; 42 for (auto* state = m_parent; state; state = state->m_parent) 43 root = state; 44 return *root; 45 } 46 47 struct UsedValues { 48 NodeWithStyleAndBoxModelMetrics const& node() const { return *m_node; } 49 void set_node(NodeWithStyleAndBoxModelMetrics&, UsedValues const* containing_block_used_values); 50 51 CSSPixels content_width() const { return m_content_width; } 52 CSSPixels content_height() const { return m_content_height; } 53 void set_content_width(CSSPixels); 54 void set_content_height(CSSPixels); 55 56 // NOTE: These are used by FlexFormattingContext to assign a temporary main size to items 57 // early on, so that descendants have something to resolve percentages against. 58 void set_temporary_content_width(CSSPixels); 59 void set_temporary_content_height(CSSPixels); 60 61 bool has_definite_width() const { return m_has_definite_width && width_constraint == SizeConstraint::None; } 62 bool has_definite_height() const { return m_has_definite_height && height_constraint == SizeConstraint::None; } 63 64 // Returns the available space for content inside this layout box. 65 // If the space in an axis is indefinite, and the outer space is an intrinsic sizing constraint, 66 // the constraint is used in that axis instead. 67 AvailableSpace available_inner_space_or_constraints_from(AvailableSpace const& outer_space) const; 68 69 void set_content_offset(CSSPixelPoint); 70 void set_content_x(CSSPixels); 71 void set_content_y(CSSPixels); 72 73 CSSPixelPoint offset; 74 75 SizeConstraint width_constraint { SizeConstraint::None }; 76 SizeConstraint height_constraint { SizeConstraint::None }; 77 78 CSSPixels margin_left { 0 }; 79 CSSPixels margin_right { 0 }; 80 CSSPixels margin_top { 0 }; 81 CSSPixels margin_bottom { 0 }; 82 83 CSSPixels border_left { 0 }; 84 CSSPixels border_right { 0 }; 85 CSSPixels border_top { 0 }; 86 CSSPixels border_bottom { 0 }; 87 88 CSSPixels padding_left { 0 }; 89 CSSPixels padding_right { 0 }; 90 CSSPixels padding_top { 0 }; 91 CSSPixels padding_bottom { 0 }; 92 93 CSSPixels inset_left { 0 }; 94 CSSPixels inset_right { 0 }; 95 CSSPixels inset_top { 0 }; 96 CSSPixels inset_bottom { 0 }; 97 98 Vector<LineBox> line_boxes; 99 100 CSSPixels margin_box_left() const { return margin_left + border_left + padding_left; } 101 CSSPixels margin_box_right() const { return margin_right + border_right + padding_right; } 102 CSSPixels margin_box_top() const { return margin_top + border_top + padding_top; } 103 CSSPixels margin_box_bottom() const { return margin_bottom + border_bottom + padding_bottom; } 104 105 CSSPixels margin_box_width() const { return margin_box_left() + content_width() + margin_box_right(); } 106 CSSPixels margin_box_height() const { return margin_box_top() + content_height() + margin_box_bottom(); } 107 108 CSSPixels border_box_left() const { return border_left + padding_left; } 109 CSSPixels border_box_right() const { return border_right + padding_right; } 110 CSSPixels border_box_top() const { return border_top + padding_top; } 111 CSSPixels border_box_bottom() const { return border_bottom + padding_bottom; } 112 113 CSSPixels border_box_width() const { return border_box_left() + content_width() + border_box_right(); } 114 CSSPixels border_box_height() const { return border_box_top() + content_height() + border_box_bottom(); } 115 116 Optional<Painting::PaintableBox::OverflowData> overflow_data; 117 118 Painting::PaintableBox::OverflowData& ensure_overflow_data() 119 { 120 if (!overflow_data.has_value()) 121 overflow_data = Painting::PaintableBox::OverflowData {}; 122 return *overflow_data; 123 } 124 125 Optional<LineBoxFragmentCoordinate> containing_line_box_fragment; 126 127 void add_floating_descendant(Box const& box) { m_floating_descendants.set(&box); } 128 auto const& floating_descendants() const { return m_floating_descendants; } 129 130 private: 131 AvailableSize available_width_inside() const; 132 AvailableSize available_height_inside() const; 133 134 Layout::NodeWithStyleAndBoxModelMetrics* m_node { nullptr }; 135 136 CSSPixels m_content_width { 0 }; 137 CSSPixels m_content_height { 0 }; 138 139 bool m_has_definite_width { false }; 140 bool m_has_definite_height { false }; 141 142 HashTable<Box const*> m_floating_descendants; 143 }; 144 145 CSSPixels resolved_definite_width(Box const&) const; 146 CSSPixels resolved_definite_height(Box const&) const; 147 148 void commit(); 149 150 // NOTE: get_mutable() will CoW the UsedValues if it's inherited from an ancestor state; 151 UsedValues& get_mutable(NodeWithStyleAndBoxModelMetrics const&); 152 153 // NOTE: get() will not CoW the UsedValues. 154 UsedValues const& get(NodeWithStyleAndBoxModelMetrics const&) const; 155 156 Vector<OwnPtr<UsedValues>> used_values_per_layout_node; 157 158 // We cache intrinsic sizes once determined, as they will not change over the course of a full layout. 159 // This avoids computing them several times while performing flex layout. 160 struct IntrinsicSizes { 161 Optional<CSSPixels> min_content_width; 162 Optional<CSSPixels> max_content_width; 163 164 // NOTE: Since intrinsic heights depend on the amount of available width, we have to cache 165 // three separate kinds of results, depending on the available width at the time of calculation. 166 HashMap<CSSPixels, Optional<CSSPixels>> min_content_height_with_definite_available_width; 167 HashMap<CSSPixels, Optional<CSSPixels>> max_content_height_with_definite_available_width; 168 Optional<CSSPixels> min_content_height_with_min_content_available_width; 169 Optional<CSSPixels> max_content_height_with_min_content_available_width; 170 Optional<CSSPixels> min_content_height_with_max_content_available_width; 171 Optional<CSSPixels> max_content_height_with_max_content_available_width; 172 }; 173 174 HashMap<NodeWithStyleAndBoxModelMetrics const*, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes; 175 176 LayoutState const* m_parent { nullptr }; 177 LayoutState const& m_root; 178}; 179 180CSSPixelRect absolute_content_rect(Box const&, LayoutState const&); 181CSSPixelRect margin_box_rect(Box const&, LayoutState const&); 182CSSPixelRect margin_box_rect_in_ancestor_coordinate_space(Box const& box, Box const& ancestor_box, LayoutState const&); 183CSSPixelRect border_box_rect(Box const&, LayoutState const&); 184CSSPixelRect border_box_rect_in_ancestor_coordinate_space(Box const& box, Box const& ancestor_box, LayoutState const&); 185CSSPixelRect content_box_rect(Box const&, LayoutState const&); 186CSSPixelRect content_box_rect_in_ancestor_coordinate_space(Box const& box, Box const& ancestor_box, LayoutState const&); 187CSSPixels box_baseline(LayoutState const& state, Box const& box); 188 189}