layout/taffy/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4mod layout;
5mod stylo_taffy;
6use std::fmt;
7
8use app_units::Au;
9use malloc_size_of_derive::MallocSizeOf;
10use script::layout_dom::ServoThreadSafeLayoutNode;
11use servo_arc::Arc;
12use style::context::SharedStyleContext;
13use style::properties::ComputedValues;
14use stylo_taffy::TaffyStyloStyle;
15
16use crate::PropagatedBoxTreeData;
17use crate::cell::ArcRefCell;
18use crate::construct_modern::{ModernContainerBuilder, ModernItemKind};
19use crate::context::LayoutContext;
20use crate::dom::LayoutBox;
21use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
22use crate::formatting_contexts::IndependentFormattingContext;
23use crate::fragment_tree::Fragment;
24use crate::layout_box_base::LayoutBoxBase;
25use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
26
27#[derive(Debug, MallocSizeOf)]
28pub(crate) struct TaffyContainer {
29    children: Vec<ArcRefCell<TaffyItemBox>>,
30    style: Arc<ComputedValues>,
31}
32
33impl TaffyContainer {
34    pub fn construct(
35        context: &LayoutContext,
36        info: &NodeAndStyleInfo,
37        contents: NonReplacedContents,
38        propagated_data: PropagatedBoxTreeData,
39    ) -> Self {
40        let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
41        contents.traverse(context, info, &mut builder);
42        let items = builder.finish();
43
44        let children = items
45            .into_iter()
46            .map(|item| {
47                let box_ = match item.kind {
48                    ModernItemKind::InFlow(independent_formatting_context) => {
49                        ArcRefCell::new(TaffyItemBox::new(TaffyItemBoxInner::InFlowBox(
50                            independent_formatting_context,
51                        )))
52                    },
53                    ModernItemKind::OutOfFlow(independent_formatting_context) => {
54                        let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
55                            independent_formatting_context,
56                        ));
57                        ArcRefCell::new(TaffyItemBox::new(
58                            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box),
59                        ))
60                    },
61                    ModernItemKind::ReusedBox(layout_box) => match layout_box {
62                        LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box,
63                        _ => unreachable!("Undamaged taffy level element should be associated with taffy level box"),
64                    },
65                };
66
67                if let Some(box_slot) = item.box_slot {
68                    box_slot.set(LayoutBox::TaffyItemBox(box_.clone()));
69                }
70
71                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) child_fragments: Vec<Fragment>,
90    pub(crate) positioning_context: PositioningContext,
91    pub(crate) style: Arc<ComputedValues>,
92    pub(crate) taffy_level_box: TaffyItemBoxInner,
93}
94
95#[allow(clippy::large_enum_variant)]
96#[derive(Debug, MallocSizeOf)]
97pub(crate) enum TaffyItemBoxInner {
98    InFlowBox(IndependentFormattingContext),
99    OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
100}
101
102impl fmt::Debug for TaffyItemBox {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        f.debug_struct("TaffyItemBox")
105            .field("taffy_layout", &self.taffy_layout)
106            .field("child_fragments", &self.child_fragments.len())
107            .field("style", &self.style)
108            .field("taffy_level_box", &self.taffy_level_box)
109            .finish()
110    }
111}
112
113impl TaffyItemBox {
114    fn new(inner: TaffyItemBoxInner) -> Self {
115        let style: Arc<ComputedValues> = match &inner {
116            TaffyItemBoxInner::InFlowBox(item) => item.style().clone(),
117            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(absbox) => {
118                (*absbox).borrow().context.style().clone()
119            },
120        };
121
122        Self {
123            taffy_layout: Default::default(),
124            child_fragments: Vec::new(),
125            positioning_context: PositioningContext::default(),
126            style,
127            taffy_level_box: inner,
128        }
129    }
130
131    pub(crate) fn clear_fragment_layout_cache(&mut self) {
132        self.taffy_layout = Default::default();
133        self.positioning_context = PositioningContext::default();
134        match self.taffy_level_box {
135            TaffyItemBoxInner::InFlowBox(ref independent_formatting_context) => {
136                independent_formatting_context
137                    .base
138                    .clear_fragment_layout_cache()
139            },
140            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => {
141                positioned_box
142                    .borrow()
143                    .context
144                    .base
145                    .clear_fragment_layout_cache()
146            },
147        }
148    }
149
150    pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
151        match self.taffy_level_box {
152            TaffyItemBoxInner::InFlowBox(ref independent_formatting_context) => {
153                callback(&independent_formatting_context.base)
154            },
155            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => {
156                callback(&positioned_box.borrow().context.base)
157            },
158        }
159    }
160
161    pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T {
162        match &mut self.taffy_level_box {
163            TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
164                callback(&mut independent_formatting_context.base)
165            },
166            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
167                callback(&mut positioned_box.borrow_mut().context.base)
168            },
169        }
170    }
171
172    pub(crate) fn repair_style(
173        &mut self,
174        context: &SharedStyleContext,
175        node: &ServoThreadSafeLayoutNode,
176        new_style: &Arc<ComputedValues>,
177    ) {
178        self.style = new_style.clone();
179        match &mut self.taffy_level_box {
180            TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
181                independent_formatting_context.repair_style(context, node, new_style)
182            },
183            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
184                .borrow_mut()
185                .context
186                .repair_style(context, node, new_style),
187        }
188    }
189
190    fn is_in_flow_replaced(&self) -> bool {
191        match &self.taffy_level_box {
192            TaffyItemBoxInner::InFlowBox(fc) => fc.is_replaced(),
193            TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(_) => false,
194        }
195    }
196}
197
198/// Details from Taffy grid layout that will be stored
199#[derive(Clone, Debug, MallocSizeOf)]
200pub(crate) struct SpecificTaffyGridInfo {
201    pub rows: SpecificTaffyGridTrackInfo,
202    pub columns: SpecificTaffyGridTrackInfo,
203}
204
205impl SpecificTaffyGridInfo {
206    fn from_detailed_grid_layout(grid_info: taffy::DetailedGridInfo) -> Self {
207        Self {
208            rows: SpecificTaffyGridTrackInfo {
209                sizes: grid_info
210                    .rows
211                    .sizes
212                    .iter()
213                    .map(|size| Au::from_f32_px(*size))
214                    .collect(),
215            },
216            columns: SpecificTaffyGridTrackInfo {
217                sizes: grid_info
218                    .columns
219                    .sizes
220                    .iter()
221                    .map(|size| Au::from_f32_px(*size))
222                    .collect(),
223            },
224        }
225    }
226}
227
228#[derive(Clone, Debug, MallocSizeOf)]
229pub(crate) struct SpecificTaffyGridTrackInfo {
230    pub sizes: Box<[Au]>,
231}