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::{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_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
350 match &self.style.get_position().grid_template_columns {
351 stylo::GenericGridTemplateComponent::None => None,
352 stylo::GenericGridTemplateComponent::TrackList(list) => {
353 Some(StyloLineNameIter::new(&list.line_names))
354 },
355 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
357 stylo::GenericGridTemplateComponent::Masonry => None,
358 }
359 }
360
361 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
362 match &self.style.get_position().grid_template_rows {
363 stylo::GenericGridTemplateComponent::None => None,
364 stylo::GenericGridTemplateComponent::TrackList(list) => {
365 Some(StyloLineNameIter::new(&list.line_names))
366 },
367 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
369 stylo::GenericGridTemplateComponent::Masonry => None,
370 }
371 }
372
373 #[inline]
374 fn grid_auto_flow(&self) -> taffy::GridAutoFlow {
375 convert::grid_auto_flow(self.style.get_position().grid_auto_flow)
376 }
377
378 #[inline]
379 fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
380 let position_styles = self.style.get_position();
381 taffy::Size {
382 width: convert::gap(&position_styles.column_gap),
383 height: convert::gap(&position_styles.row_gap),
384 }
385 }
386
387 #[inline]
388 fn align_content(&self) -> Option<taffy::AlignContent> {
389 convert::content_alignment(self.style.get_position().align_content)
390 }
391
392 #[inline]
393 fn justify_content(&self) -> Option<taffy::JustifyContent> {
394 convert::content_alignment(self.style.get_position().justify_content)
395 }
396
397 #[inline]
398 fn align_items(&self) -> Option<taffy::AlignItems> {
399 convert::item_alignment(self.style.get_position().align_items.0)
400 }
401
402 #[inline]
403 fn justify_items(&self) -> Option<taffy::AlignItems> {
404 convert::item_alignment(self.style.get_position().justify_items.computed.0.0)
405 }
406}
407
408impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle<T> {
409 #[inline]
410 fn grid_row(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
411 let position_styles = self.style.get_position();
412 taffy::Line {
413 start: convert::grid_line(&position_styles.grid_row_start),
414 end: convert::grid_line(&position_styles.grid_row_end),
415 }
416 }
417
418 #[inline]
419 fn grid_column(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
420 let position_styles = self.style.get_position();
421 taffy::Line {
422 start: convert::grid_line(&position_styles.grid_column_start),
423 end: convert::grid_line(&position_styles.grid_column_end),
424 }
425 }
426
427 #[inline]
428 fn align_self(&self) -> Option<taffy::AlignSelf> {
429 convert::item_alignment(self.style.get_position().align_self.0)
430 }
431
432 #[inline]
433 fn justify_self(&self) -> Option<taffy::AlignSelf> {
434 convert::item_alignment(self.style.get_position().justify_self.0)
435 }
436}