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