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