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.slow_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::LengthPercentageAuto> {
116 let position_styles = self.style.get_position();
117 taffy::Size {
118 width: convert::min_size(&position_styles.min_width),
119 height: convert::min_size(&position_styles.min_height),
120 }
121 }
122
123 #[inline]
124 fn max_size(&self) -> taffy::Size<taffy::LengthPercentageAuto> {
125 let position_styles = self.style.get_position();
126 taffy::Size {
127 width: convert::max_size(&position_styles.max_width),
128 height: convert::max_size(&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 }
290 }
291
292 #[inline]
293 fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
294 match &self.style.get_position().grid_template_columns {
295 stylo::GenericGridTemplateComponent::None => None,
296 stylo::GenericGridTemplateComponent::TrackList(list) => {
297 Some(list.values.iter().map(|track| match track {
298 stylo::TrackListValue::TrackSize(size) => {
299 taffy::GenericGridTemplateComponent::Single(convert::track_size(size))
300 },
301 stylo::TrackListValue::TrackRepeat(repeat) => {
302 taffy::GenericGridTemplateComponent::Repeat(RepetitionWrapper(repeat))
303 },
304 }))
305 },
306
307 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
309 }
310 }
311
312 #[inline]
313 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
314 self.style
315 .get_position()
316 .grid_auto_rows
317 .0
318 .iter()
319 .map(convert::track_size)
320 }
321
322 #[inline]
323 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
324 self.style
325 .get_position()
326 .grid_auto_columns
327 .0
328 .iter()
329 .map(convert::track_size)
330 }
331
332 fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
333 match &self.style.get_position().grid_template_areas {
334 GridTemplateAreas::Areas(areas) => {
335 Some(areas.0.areas.iter().map(|area| taffy::GridTemplateArea {
336 name: area.name.clone(),
337 row_start: area.rows.start as u16,
338 row_end: area.rows.end as u16,
339 column_start: area.columns.start as u16,
340 column_end: area.columns.end as u16,
341 }))
342 },
343 GridTemplateAreas::None => None,
344 }
345 }
346
347 fn grid_template_area_row_count(&self) -> u16 {
348 match &self.style.get_position().grid_template_areas {
349 GridTemplateAreas::Areas(areas) => as_clamped_i16(areas.0.strings.len() as i32) as u16,
350 GridTemplateAreas::None => 0,
351 }
352 }
353
354 fn grid_template_area_column_count(&self) -> u16 {
355 match &self.style.get_position().grid_template_areas {
356 GridTemplateAreas::Areas(areas) => as_clamped_i16(areas.0.width as i32) as u16,
357 GridTemplateAreas::None => 0,
358 }
359 }
360
361 fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
362 match &self.style.get_position().grid_template_columns {
363 stylo::GenericGridTemplateComponent::None => None,
364 stylo::GenericGridTemplateComponent::TrackList(list) => {
365 Some(StyloLineNameIter::new(&list.line_names))
366 },
367 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
369 }
370 }
371
372 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
373 match &self.style.get_position().grid_template_rows {
374 stylo::GenericGridTemplateComponent::None => None,
375 stylo::GenericGridTemplateComponent::TrackList(list) => {
376 Some(StyloLineNameIter::new(&list.line_names))
377 },
378 stylo::GenericGridTemplateComponent::Subgrid(_) => None,
380 }
381 }
382
383 #[inline]
384 fn grid_auto_flow(&self) -> taffy::GridAutoFlow {
385 convert::grid_auto_flow(self.style.get_position().grid_auto_flow)
386 }
387
388 #[inline]
389 fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
390 let position_styles = self.style.get_position();
391 taffy::Size {
392 width: convert::gap(&position_styles.column_gap),
393 height: convert::gap(&position_styles.row_gap),
394 }
395 }
396
397 #[inline]
398 fn align_content(&self) -> Option<taffy::AlignContent> {
399 convert::content_alignment(self.style.get_position().align_content)
400 }
401
402 #[inline]
403 fn justify_content(&self) -> Option<taffy::JustifyContent> {
404 convert::content_alignment(self.style.get_position().justify_content)
405 }
406
407 #[inline]
408 fn align_items(&self) -> Option<taffy::AlignItems> {
409 convert::item_alignment(self.style.get_position().align_items.0)
410 }
411
412 #[inline]
413 fn justify_items(&self) -> Option<taffy::AlignItems> {
414 convert::item_alignment(self.style.get_position().justify_items.computed.0.0)
415 }
416}
417
418impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle<T> {
419 #[inline]
420 fn grid_row(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
421 let position_styles = self.style.get_position();
422 taffy::Line {
423 start: convert::grid_line(&position_styles.grid_row_start),
424 end: convert::grid_line(&position_styles.grid_row_end),
425 }
426 }
427
428 #[inline]
429 fn grid_column(&self) -> taffy::Line<taffy::GridPlacement<Atom>> {
430 let position_styles = self.style.get_position();
431 taffy::Line {
432 start: convert::grid_line(&position_styles.grid_column_start),
433 end: convert::grid_line(&position_styles.grid_column_end),
434 }
435 }
436
437 #[inline]
438 fn align_self(&self) -> Option<taffy::AlignSelf> {
439 convert::item_alignment(self.style.get_position().align_self.0)
440 }
441
442 #[inline]
443 fn justify_self(&self) -> Option<taffy::AlignSelf> {
444 convert::item_alignment(self.style.get_position().justify_self.0)
445 }
446}