1mod layout;
5mod stylo_taffy;
6use std::fmt;
7
8use app_units::Au;
9use malloc_size_of_derive::MallocSizeOf;
10use script::layout_dom::ServoLayoutNode;
11use servo_arc::Arc;
12use style::Atom;
13use style::context::SharedStyleContext;
14use style::properties::ComputedValues;
15pub(crate) use stylo_taffy::TaffyStyloStyle;
16use taffy::GridItemStyle;
17
18use crate::cell::ArcRefCell;
19use crate::construct_modern::{ModernContainerBuilder, ModernItemKind};
20use crate::context::LayoutContext;
21use crate::dom::{LayoutBox, WeakLayoutBox};
22use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
23use crate::formatting_contexts::IndependentFormattingContext;
24use crate::fragment_tree::Fragment;
25use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
26use crate::layout_box_base::LayoutBoxBase;
27use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
28use crate::{DefiniteContainingBlock, PropagatedBoxTreeData};
29
30#[derive(Debug, MallocSizeOf)]
31pub(crate) struct TaffyContainer {
32 children: Vec<ArcRefCell<TaffyItemBox>>,
33 style: Arc<ComputedValues>,
34}
35
36impl TaffyContainer {
37 pub fn construct(
38 context: &LayoutContext,
39 info: &NodeAndStyleInfo,
40 contents: NonReplacedContents,
41 propagated_data: PropagatedBoxTreeData,
42 ) -> Self {
43 let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
44 contents.traverse(context, info, &mut builder);
45 let items = builder.finish();
46
47 let children = items
48 .into_iter()
49 .map(|item| {
50 let taffy_item_box = match item.kind {
51 ModernItemKind::InFlow(independent_formatting_context) => {
52 ArcRefCell::new(TaffyItemBox::new(TaffyItemBoxInner::InFlowBox(
53 independent_formatting_context,
54 )))
55 },
56 ModernItemKind::OutOfFlow(independent_formatting_context) => {
57 let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
58 independent_formatting_context,
59 ));
60 ArcRefCell::new(TaffyItemBox::new(
61 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box),
62 ))
63 },
64 ModernItemKind::ReusedBox(layout_box) => match layout_box {
65 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box,
66 _ => unreachable!("Undamaged taffy level element should be associated with taffy level box"),
67 },
68 };
69
70 item.box_slot.set(LayoutBox::TaffyItemBox(taffy_item_box.clone()));
71 taffy_item_box
72 })
73 .collect();
74
75 Self {
76 children,
77 style: info.style.clone(),
78 }
79 }
80
81 pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
82 self.style = new_style.clone();
83 }
84}
85
86#[derive(MallocSizeOf)]
87pub(crate) struct TaffyItemBox {
88 pub(crate) taffy_layout: taffy::Layout,
89 pub(crate) taffy_baselines: taffy::Baselines,
90 pub(crate) child_fragments: Vec<Fragment>,
91 pub(crate) positioning_context: PositioningContext,
92 pub(crate) style: Arc<ComputedValues>,
93 pub(crate) taffy_level_box: TaffyItemBoxInner,
94}
95
96#[expect(clippy::large_enum_variant)]
97#[derive(Debug, MallocSizeOf)]
98pub(crate) enum TaffyItemBoxInner {
99 InFlowBox(IndependentFormattingContext),
100 OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
101}
102
103impl fmt::Debug for TaffyItemBox {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("TaffyItemBox")
106 .field("taffy_layout", &self.taffy_layout)
107 .field("taffy_baselines", &self.taffy_baselines)
108 .field("child_fragments", &self.child_fragments.len())
109 .field("style", &self.style)
110 .field("taffy_level_box", &self.taffy_level_box)
111 .finish()
112 }
113}
114
115impl TaffyItemBox {
116 fn new(inner: TaffyItemBoxInner) -> Self {
117 let style: Arc<ComputedValues> = match &inner {
118 TaffyItemBoxInner::InFlowBox(item) => item.style().clone(),
119 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(absbox) => {
120 (*absbox).borrow().context.style().clone()
121 },
122 };
123
124 Self {
125 taffy_layout: Default::default(),
126 taffy_baselines: taffy::Baselines::NONE,
127 child_fragments: Vec::new(),
128 positioning_context: PositioningContext::default(),
129 style,
130 taffy_level_box: inner,
131 }
132 }
133
134 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
135 match self.taffy_level_box {
136 TaffyItemBoxInner::InFlowBox(ref independent_formatting_context) => {
137 callback(&independent_formatting_context.base)
138 },
139 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => {
140 callback(&positioned_box.borrow().context.base)
141 },
142 }
143 }
144
145 pub(crate) fn with_base_mut<T>(&mut self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
146 match &mut self.taffy_level_box {
147 TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
148 callback(&mut independent_formatting_context.base)
149 },
150 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
151 callback(&mut positioned_box.borrow_mut().context.base)
152 },
153 }
154 }
155
156 pub(crate) fn repair_style(
157 &mut self,
158 context: &SharedStyleContext,
159 node: &ServoLayoutNode,
160 new_style: &Arc<ComputedValues>,
161 ) {
162 self.style = new_style.clone();
163 match &mut self.taffy_level_box {
164 TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
165 independent_formatting_context.repair_style(context, node, new_style)
166 },
167 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
168 .borrow_mut()
169 .context
170 .repair_style(context, node, new_style),
171 }
172 }
173
174 fn is_in_flow_replaced(&self) -> bool {
175 match &self.taffy_level_box {
176 TaffyItemBoxInner::InFlowBox(fc) => fc.is_replaced(),
177 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(_) => false,
178 }
179 }
180
181 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
182 match &self.taffy_level_box {
183 TaffyItemBoxInner::InFlowBox(formatting_context) => {
184 formatting_context.attached_to_tree(layout_box)
185 },
186 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
187 .borrow_mut()
188 .context
189 .attached_to_tree(layout_box),
190 }
191 }
192}
193
194#[derive(Clone, Debug, MallocSizeOf)]
196pub(crate) struct SpecificTaffyGridInfo {
197 pub info: taffy::DetailedGridInfo<Atom>,
198}
199
200impl SpecificTaffyGridInfo {
201 fn from_detailed_grid_layout(grid_info: taffy::DetailedGridInfo<Atom>) -> Self {
202 Self { info: grid_info }
203 }
204
205 pub(crate) fn resolve_grid_area(
206 &self,
207 item_style: &ComputedValues,
208 containing_block: &DefiniteContainingBlock,
209 containing_block_border: PhysicalSides<Au>,
210 ) -> PhysicalRect<Au> {
211 let item_style = TaffyStyloStyle::new(item_style, false);
212 let writing_mode = containing_block.style.writing_mode;
213 let physical_containing_block_size = containing_block.size.to_physical_size(writing_mode);
214
215 let direction = if writing_mode.is_bidi_ltr() {
217 taffy::Direction::Ltr
218 } else {
219 taffy::Direction::Rtl
220 };
221
222 let border_left = containing_block_border.left.to_f32_px();
224 let border_top = containing_block_border.top.to_f32_px();
225
226 let padding_box = taffy::Rect {
227 left: border_left,
228 right: border_left + physical_containing_block_size.width.to_f32_px(),
229 top: border_top,
230 bottom: border_top + physical_containing_block_size.height.to_f32_px(),
231 };
232
233 let area = self.info.resolve_absolute_grid_area(
235 item_style.grid_row(),
236 item_style.grid_column(),
237 direction,
238 padding_box,
239 );
240
241 PhysicalRect::new(
243 PhysicalPoint::new(
244 Au::from_f32_px(area.left) - containing_block_border.left,
245 Au::from_f32_px(area.top) - containing_block_border.top,
246 ),
247 PhysicalSize::new(
248 Au::from_f32_px(area.right - area.left),
249 Au::from_f32_px(area.bottom - area.top),
250 ),
251 )
252 }
253}