layout/taffy/stylo_taffy/
wrapper.rs1use std::ops::Deref;
6
7use style::properties::ComputedValues;
8use style::values::CustomIdent;
9use style::values::computed::{GridTemplateAreas, LengthPercentage};
10use style::values::generics::grid::{TrackListValue, TrackRepeat, TrackSize};
11use style::values::specified::position::NamedArea;
12use style::{Atom, OwnedSlice};
13use taffy::prelude::TaffyAuto;
14
15use super::{convert, stylo};
16
17pub struct TaffyStyloStyle<T: Deref<Target = ComputedValues>> {
20 pub style: T,
21 pub is_compressible_replaced: bool,
22}
23
24impl<T: Deref<Target = ComputedValues>> TaffyStyloStyle<T> {
25 pub fn new(style: T, is_compressible_replaced: bool) -> Self {
26 Self {
27 style,
28 is_compressible_replaced,
29 }
30 }
31}
32
33impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> {
34 type CustomIdent = Atom;
35
36 #[inline]
37 fn box_generation_mode(&self) -> taffy::BoxGenerationMode {
38 convert::box_generation_mode(self.style.get_box().display)
39 }
40
41 #[inline]
42 fn is_block(&self) -> bool {
43 convert::is_block(self.style.get_box().display)
44 }
45
46 #[inline]
47 fn is_compressible_replaced(&self) -> bool {
48 self.is_compressible_replaced
49 }
50
51 #[inline]
52 fn box_sizing(&self) -> taffy::BoxSizing {
53 convert::box_sizing(self.style.get_position().box_sizing)
54 }
55
56 #[inline]
57 fn overflow(&self) -> taffy::Point<taffy::Overflow> {
58 let box_styles = self.style.get_box();
59 taffy::Point {
60 x: convert::overflow(box_styles.overflow_x),
61 y: convert::overflow(box_styles.overflow_y),
62 }
63 }
64
65 #[inline]
66 fn scrollbar_width(&self) -> f32 {
67 0.0
68 }
69
70 #[inline]
71 fn position(&self) -> taffy::Position {
72 convert::position(self.style.get_box().position)
73 }
74
75 #[inline]
76 fn inset(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
77 if matches!(
80 self.style.get_box().position,
81 stylo::Position::Static | stylo::Position::Sticky
82 ) {
83 return taffy::Rect {
84 left: taffy::LengthPercentageAuto::AUTO,
85 right: taffy::LengthPercentageAuto::AUTO,
86 top: taffy::LengthPercentageAuto::AUTO,
87 bottom: taffy::LengthPercentageAuto::AUTO,
88 };
89 }
90 let position_styles = self.style.get_position();
91 taffy::Rect {
92 left: convert::inset(&position_styles.left),
93 right: convert::inset(&position_styles.right),
94 top: convert::inset(&position_styles.top),
95 bottom: convert::inset(&position_styles.bottom),
96 }
97 }
98
99 #[inline]
100 fn size(&self) -> taffy::Size<taffy::Dimension> {
101 let position_styles = self.style.get_position();
102 taffy::Size {
103 width: convert::dimension(&position_styles.width),
104 height: convert::dimension(&position_styles.height),
105 }
106 }
107
108 #[inline]
109 fn min_size(&self) -> taffy::Size<taffy::Dimension> {
110 let position_styles = self.style.get_position();
111 taffy::Size {
112 width: convert::dimension(&position_styles.min_width),
113 height: convert::dimension(&position_styles.min_height),
114 }
115 }
116
117 #[inline]
118 fn max_size(&self) -> taffy::Size<taffy::Dimension> {
119 let position_styles = self.style.get_position();
120 taffy::Size {
121 width: convert::max_size_dimension(&position_styles.max_width),
122 height: convert::max_size_dimension(&position_styles.max_height),
123 }
124 }
125
126 #[inline]
127 fn aspect_ratio(&self) -> Option<f32> {
128 convert::aspect_ratio(self.style.get_position().aspect_ratio)
129 }
130
131 #[inline]
132 fn margin(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
133 let margin_styles = self.style.get_margin();
134 taffy::Rect {
135 left: convert::margin(&margin_styles.margin_left),
136 right: convert::margin(&margin_styles.margin_right),
137 top: convert::margin(&margin_styles.margin_top),
138 bottom: convert::margin(&margin_styles.margin_bottom),
139 }
140 }
141
142 #[inline]
143 fn padding(&self) -> taffy::Rect<taffy::LengthPercentage> {
144 let padding_styles = self.style.get_padding();
145 taffy::Rect {
146 left: convert::length_percentage(&padding_styles.padding_left.0),
147 right: convert::length_percentage(&padding_styles.padding_right.0),
148 top: convert::length_percentage(&padding_styles.padding_top.0),
149 bottom: convert::length_percentage(&padding_styles.padding_bottom.0),
150 }
151 }
152
153 #[inline]
154 fn border(&self) -> taffy::Rect<taffy::LengthPercentage> {
155 let border_styles = self.style.get_border();
156 taffy::Rect {
157 left: taffy::LengthPercentage::length(border_styles.border_left_width.to_f32_px()),
158 right: taffy::LengthPercentage::length(border_styles.border_right_width.to_f32_px()),
159 top: taffy::LengthPercentage::length(border_styles.border_top_width.to_f32_px()),
160 bottom: taffy::LengthPercentage::length(border_styles.border_bottom_width.to_f32_px()),
161 }
162 }
163}
164
165type SliceMapIter<'a, Input, Output> =
166 core::iter::Map<core::slice::Iter<'a, Input>, for<'c> fn(&'c Input) -> Output>;
167type SliceMapRefIter<'a, Input, Output> =
168 core::iter::Map<core::slice::Iter<'a, Input>, for<'c> fn(&'c Input) -> &'c Output>;
169
170type LineNameSetIter<'a> = SliceMapRefIter<'a, CustomIdent, Atom>;
172type LineNameIter<'a> = core::iter::Map<
173 core::slice::Iter<'a, OwnedSlice<CustomIdent>>,
174 fn(&OwnedSlice<CustomIdent>) -> LineNameSetIter<'_>,
175>;
176
177#[derive(Clone)]
178pub struct StyloLineNameIter<'a>(LineNameIter<'a>);
179impl<'a> StyloLineNameIter<'a> {
180 fn new(names: &'a OwnedSlice<OwnedSlice<CustomIdent>>) -> Self {
181 Self(names.iter().map(|names| names.iter().map(|ident| &ident.0)))
182 }
183}
184impl<'a> Iterator for StyloLineNameIter<'a> {
185 type Item = core::iter::Map<core::slice::Iter<'a, CustomIdent>, fn(&CustomIdent) -> &Atom>;
186 fn next(&mut self) -> Option<Self::Item> {
187 self.0.next()
188 }
189 fn size_hint(&self) -> (usize, Option<usize>) {
190 self.0.size_hint()
191 }
192}
193impl ExactSizeIterator for StyloLineNameIter<'_> {}
194impl<'a> taffy::TemplateLineNames<'a, Atom> for StyloLineNameIter<'a> {
195 type LineNameSet<'b>
196 = SliceMapRefIter<'b, CustomIdent, Atom>
197 where
198 Self: 'b;
199}
200
201pub struct RepetitionWrapper<'a>(&'a TrackRepeat<LengthPercentage, i32>);
202
203impl taffy::GenericRepetition for RepetitionWrapper<'_> {
204 type CustomIdent = Atom;
205
206 type RepetitionTrackList<'a>
207 = SliceMapIter<'a, stylo::TrackSize<LengthPercentage>, taffy::TrackSizingFunction>
208 where
209 Self: 'a;
210
211 type TemplateLineNames<'a>
212 = StyloLineNameIter<'a>
213 where
214 Self: 'a;
215
216 fn count(&self) -> taffy::RepetitionCount {
217 convert::track_repeat(self.0.count)
218 }
219
220 fn tracks(&self) -> Self::RepetitionTrackList<'_> {
221 self.0.track_sizes.iter().map(convert::track_size)
222 }
223
224 fn lines_names(&self) -> Self::TemplateLineNames<'_> {
225 StyloLineNameIter::new(&self.0.line_names)
226 }
227}
228
229impl<T: Deref<Target = ComputedValues>> taffy::GridContainerStyle for TaffyStyloStyle<T> {
230 type Repetition<'a>
231 = RepetitionWrapper<'a>
232 where
233 Self: 'a;
234
235 type TemplateTrackList<'a>
236 = core::iter::Map<
237 core::slice::Iter<'a, TrackListValue<LengthPercentage, i32>>,
238 fn(
239 &'a TrackListValue<LengthPercentage, i32>,
240 ) -> taffy::GenericGridTemplateComponent<Atom, RepetitionWrapper<'a>>,
241 >
242 where
243 Self: 'a;
244
245 type AutoTrackList<'a>
246 = SliceMapIter<'a, TrackSize<LengthPercentage>, taffy::TrackSizingFunction>
247 where
248 Self: 'a;
249
250 type TemplateLineNames<'a>
251 = StyloLineNameIter<'a>
252 where
253 Self: 'a;
254 type GridTemplateAreas<'a>
255 = SliceMapIter<'a, NamedArea, taffy::GridTemplateArea<Atom>>
256 where
257 Self: 'a;
258
259 #[inline]
260 fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
261 match &self.style.get_position().grid_template_rows {
262 stylo::GenericGridTemplateComponent::None => None,
263 stylo::GenericGridTemplateComponent::TrackList(list) => {
264 Some(list.values.iter().map(|track| match track {
265 stylo::TrackListValue::TrackSize(size) => {
266 taffy::GenericGridTemplateComponent::Single(convert::track_size(size))
267 },
268 stylo::TrackListValue::TrackRepeat(repeat) => {
269 taffy::GenericGridTemplateComponent::Repeat(RepetitionWrapper(repeat))
270 },
271 }))
272 },
273
274 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
276 stylo::GenericGridTemplateComponent::Masonry => None,
277 }
278 }
279
280 #[inline]
281 fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
282 match &self.style.get_position().grid_template_columns {
283 stylo::GenericGridTemplateComponent::None => None,
284 stylo::GenericGridTemplateComponent::TrackList(list) => {
285 Some(list.values.iter().map(|track| match track {
286 stylo::TrackListValue::TrackSize(size) => {
287 taffy::GenericGridTemplateComponent::Single(convert::track_size(size))
288 },
289 stylo::TrackListValue::TrackRepeat(repeat) => {
290 taffy::GenericGridTemplateComponent::Repeat(RepetitionWrapper(repeat))
291 },
292 }))
293 },
294
295 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
297 stylo::GenericGridTemplateComponent::Masonry => None,
298 }
299 }
300
301 #[inline]
302 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
303 self.style
304 .get_position()
305 .grid_auto_rows
306 .0
307 .iter()
308 .map(convert::track_size)
309 }
310
311 #[inline]
312 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
313 self.style
314 .get_position()
315 .grid_auto_columns
316 .0
317 .iter()
318 .map(convert::track_size)
319 }
320
321 fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
322 match &self.style.get_position().grid_template_areas {
323 GridTemplateAreas::Areas(areas) => {
324 Some(areas.0.areas.iter().map(|area| taffy::GridTemplateArea {
325 name: area.name.clone(),
326 row_start: area.rows.start as u16,
327 row_end: area.rows.end as u16,
328 column_start: area.columns.start as u16,
329 column_end: area.columns.end as u16,
330 }))
331 },
332 GridTemplateAreas::None => None,
333 }
334 }
335
336 fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
337 match &self.style.get_position().grid_template_columns {
338 stylo::GenericGridTemplateComponent::None => None,
339 stylo::GenericGridTemplateComponent::TrackList(list) => {
340 Some(StyloLineNameIter::new(&list.line_names))
341 },
342 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
344 stylo::GenericGridTemplateComponent::Masonry => None,
345 }
346 }
347
348 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
349 match &self.style.get_position().grid_template_rows {
350 stylo::GenericGridTemplateComponent::None => None,
351 stylo::GenericGridTemplateComponent::TrackList(list) => {
352 Some(StyloLineNameIter::new(&list.line_names))
353 },
354 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
356 stylo::GenericGridTemplateComponent::Masonry => None,
357 }
358 }
359
360 #[inline]
361 fn grid_auto_flow(&self) -> taffy::GridAutoFlow {
362 convert::grid_auto_flow(self.style.get_position().grid_auto_flow)
363 }
364
365 #[inline]
366 fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
367 let position_styles = self.style.get_position();
368 taffy::Size {
369 width: convert::gap(&position_styles.column_gap),
370 height: convert::gap(&position_styles.row_gap),
371 }
372 }
373
374 #[inline]
375 fn align_content(&self) -> Option<taffy::AlignContent> {
376 convert::content_alignment(self.style.get_position().align_content.0)
377 }
378
379 #[inline]
380 fn justify_content(&self) -> Option<taffy::JustifyContent> {
381 convert::content_alignment(self.style.get_position().justify_content.0)
382 }
383
384 #[inline]
385 fn align_items(&self) -> Option<taffy::AlignItems> {
386 convert::item_alignment(self.style.get_position().align_items.0)
387 }
388
389 #[inline]
390 fn justify_items(&self) -> Option<taffy::AlignItems> {
391 convert::item_alignment(self.style.get_position().justify_items.computed.0)
392 }
393}
394
395impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle<T> {
396 #[inline]
397 fn grid_row(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
398 let position_styles = self.style.get_position();
399 taffy::Line {
400 start: convert::grid_line(&position_styles.grid_row_start),
401 end: convert::grid_line(&position_styles.grid_row_end),
402 }
403 }
404
405 #[inline]
406 fn grid_column(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
407 let position_styles = self.style.get_position();
408 taffy::Line {
409 start: convert::grid_line(&position_styles.grid_column_start),
410 end: convert::grid_line(&position_styles.grid_column_end),
411 }
412 }
413
414 #[inline]
415 fn align_self(&self) -> Option<taffy::AlignSelf> {
416 convert::item_alignment(self.style.get_position().align_self.0.0)
417 }
418
419 #[inline]
420 fn justify_self(&self) -> Option<taffy::AlignSelf> {
421 convert::item_alignment(self.style.get_position().justify_self.0.0)
422 }
423}