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