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