1use geom::{FlexAxis, MainStartCrossStart};
6use malloc_size_of_derive::MallocSizeOf;
7use script::layout_dom::ServoThreadSafeLayoutNode;
8use servo_arc::Arc as ServoArc;
9use style::context::SharedStyleContext;
10use style::logical_geometry::WritingMode;
11use style::properties::ComputedValues;
12use style::properties::longhands::align_items::computed_value::T as AlignItems;
13use style::properties::longhands::flex_direction::computed_value::T as FlexDirection;
14use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
15use style::values::computed::{AlignContent, JustifyContent};
16use style::values::specified::align::AlignFlags;
17
18use crate::PropagatedBoxTreeData;
19use crate::cell::ArcRefCell;
20use crate::construct_modern::{ModernContainerBuilder, ModernItemKind};
21use crate::context::LayoutContext;
22use crate::dom::LayoutBox;
23use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
24use crate::formatting_contexts::IndependentFormattingContext;
25use crate::fragment_tree::BaseFragmentInfo;
26use crate::layout_box_base::LayoutBoxBase;
27use crate::positioned::AbsolutelyPositionedBox;
28
29mod geom;
30mod layout;
31
32#[derive(Clone, Debug, MallocSizeOf)]
35pub(crate) struct FlexContainerConfig {
36 container_is_single_line: bool,
37 writing_mode: WritingMode,
38 flex_axis: FlexAxis,
39 flex_direction: FlexDirection,
40 flex_direction_is_reversed: bool,
41 flex_wrap: FlexWrap,
42 flex_wrap_is_reversed: bool,
43 main_start_cross_start_sides_are: MainStartCrossStart,
44 align_content: AlignContent,
45 align_items: AlignItems,
46 justify_content: JustifyContent,
47}
48
49impl FlexContainerConfig {
50 fn new(container_style: &ComputedValues) -> FlexContainerConfig {
51 let flex_direction = container_style.clone_flex_direction();
52 let flex_axis = FlexAxis::from(flex_direction);
53 let flex_wrap = container_style.get_position().flex_wrap;
54 let container_is_single_line = match flex_wrap {
55 FlexWrap::Nowrap => true,
56 FlexWrap::Wrap | FlexWrap::WrapReverse => false,
57 };
58 let flex_direction_is_reversed = match flex_direction {
59 FlexDirection::Row | FlexDirection::Column => false,
60 FlexDirection::RowReverse | FlexDirection::ColumnReverse => true,
61 };
62 let flex_wrap_reverse = match flex_wrap {
63 FlexWrap::Nowrap | FlexWrap::Wrap => false,
64 FlexWrap::WrapReverse => true,
65 };
66
67 let align_content = container_style.clone_align_content();
68 let align_items = AlignItems(match container_style.clone_align_items().0 {
69 AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH,
70 align => align,
71 });
72 let justify_content = container_style.clone_justify_content();
73 let main_start_cross_start_sides_are =
74 MainStartCrossStart::from(flex_direction, flex_wrap_reverse);
75
76 FlexContainerConfig {
77 container_is_single_line,
78 writing_mode: container_style.writing_mode,
79 flex_axis,
80 flex_direction,
81 flex_direction_is_reversed,
82 flex_wrap,
83 flex_wrap_is_reversed: flex_wrap_reverse,
84 main_start_cross_start_sides_are,
85 align_content,
86 align_items,
87 justify_content,
88 }
89 }
90}
91
92#[derive(Debug, MallocSizeOf)]
93pub(crate) struct FlexContainer {
94 children: Vec<ArcRefCell<FlexLevelBox>>,
95
96 style: ServoArc<ComputedValues>,
97
98 config: FlexContainerConfig,
100}
101
102impl FlexContainer {
103 pub fn construct(
104 context: &LayoutContext,
105 info: &NodeAndStyleInfo<'_>,
106 contents: NonReplacedContents,
107 propagated_data: PropagatedBoxTreeData,
108 ) -> Self {
109 let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
110 contents.traverse(context, info, &mut builder);
111 let items = builder.finish();
112
113 let children = items
114 .into_iter()
115 .map(|item| {
116 let box_ = match item.kind {
117 ModernItemKind::InFlow(independent_formatting_context) => ArcRefCell::new(
118 FlexLevelBox::FlexItem(FlexItemBox::new(independent_formatting_context)),
119 ),
120 ModernItemKind::OutOfFlow(independent_formatting_context) => {
121 let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
122 independent_formatting_context,
123 ));
124 ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(abs_pos_box))
125 },
126 ModernItemKind::ReusedBox(layout_box) => match layout_box {
127 LayoutBox::FlexLevel(flex_level_box) => flex_level_box,
128 _ => unreachable!(
129 "Undamaged flex level element should be associated with flex level box"
130 ),
131 },
132 };
133
134 if let Some(box_slot) = item.box_slot {
135 box_slot.set(LayoutBox::FlexLevel(box_.clone()));
136 }
137
138 box_
139 })
140 .collect();
141
142 Self {
143 children,
144 style: info.style.clone(),
145 config: FlexContainerConfig::new(&info.style),
146 }
147 }
148
149 pub(crate) fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
150 self.config = FlexContainerConfig::new(new_style);
151 self.style = new_style.clone();
152 }
153}
154
155#[allow(clippy::large_enum_variant)]
156#[derive(Debug, MallocSizeOf)]
157pub(crate) enum FlexLevelBox {
158 FlexItem(FlexItemBox),
159 OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
160}
161
162impl FlexLevelBox {
163 pub(crate) fn repair_style(
164 &mut self,
165 context: &SharedStyleContext,
166 node: &ServoThreadSafeLayoutNode,
167 new_style: &ServoArc<ComputedValues>,
168 ) {
169 match self {
170 FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
171 .independent_formatting_context
172 .repair_style(context, node, new_style),
173 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
174 .borrow_mut()
175 .context
176 .repair_style(context, node, new_style),
177 }
178 }
179
180 pub(crate) fn clear_fragment_layout_cache(&self) {
181 match self {
182 FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
183 .independent_formatting_context
184 .base
185 .clear_fragment_layout_cache(),
186 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
187 .borrow()
188 .context
189 .base
190 .clear_fragment_layout_cache(),
191 }
192 }
193
194 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
195 match self {
196 FlexLevelBox::FlexItem(flex_item_box) => {
197 callback(&flex_item_box.independent_formatting_context.base)
198 },
199 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
200 callback(&positioned_box.borrow().context.base)
201 },
202 }
203 }
204
205 pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T {
206 match self {
207 FlexLevelBox::FlexItem(flex_item_box) => {
208 callback(&mut flex_item_box.independent_formatting_context.base)
209 },
210 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
211 callback(&mut positioned_box.borrow_mut().context.base)
212 },
213 }
214 }
215}
216
217#[derive(MallocSizeOf)]
218pub(crate) struct FlexItemBox {
219 independent_formatting_context: IndependentFormattingContext,
220}
221
222impl std::fmt::Debug for FlexItemBox {
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 f.write_str("FlexItemBox")
225 }
226}
227
228impl FlexItemBox {
229 fn new(independent_formatting_context: IndependentFormattingContext) -> Self {
230 Self {
231 independent_formatting_context,
232 }
233 }
234
235 fn style(&self) -> &ServoArc<ComputedValues> {
236 self.independent_formatting_context.style()
237 }
238
239 fn base_fragment_info(&self) -> BaseFragmentInfo {
240 self.independent_formatting_context.base_fragment_info()
241 }
242}