Impl GridItemStyle and BlockContainerStyle for Style (#832)
1//! A typed representation of [CSS style properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust. Used as input to layout computation.
2mod alignment;
3mod available_space;
4mod compact_length;
5mod dimension;
6
7#[cfg(feature = "block_layout")]
8mod block;
9#[cfg(feature = "flexbox")]
10mod flex;
11#[cfg(feature = "grid")]
12mod grid;
13
14pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf};
15pub use self::available_space::AvailableSpace;
16pub use self::compact_length::CompactLength;
17pub use self::dimension::{Dimension, LengthPercentage, LengthPercentageAuto};
18
19#[cfg(feature = "block_layout")]
20pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign};
21#[cfg(feature = "flexbox")]
22pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle};
23#[cfg(feature = "grid")]
24pub(crate) use self::grid::{GenericGridPlacement, OriginZeroGridPlacement};
25#[cfg(feature = "grid")]
26pub use self::grid::{
27 GridAutoFlow, GridContainerStyle, GridItemStyle, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction,
28 MinTrackSizingFunction, NonRepeatedTrackSizingFunction, TrackSizingFunction,
29};
30
31use crate::geometry::{Point, Rect, Size};
32use crate::style_helpers::TaffyAuto as _;
33
34#[cfg(feature = "grid")]
35use crate::geometry::Line;
36#[cfg(feature = "serde")]
37use crate::style_helpers;
38#[cfg(feature = "grid")]
39use crate::util::sys::GridTrackVec;
40
41/// The core set of styles that are shared between all CSS layout nodes
42///
43/// Note that all methods come with a default implementation which simply returns the default value for that style property
44/// but this is a just a convenience to save on boilerplate for styles that your implementation doesn't support. You will need
45/// to override the default implementation for each style property that your style type actually supports.
46pub trait CoreStyle {
47 /// Which box generation mode should be used
48 #[inline(always)]
49 fn box_generation_mode(&self) -> BoxGenerationMode {
50 BoxGenerationMode::DEFAULT
51 }
52 /// Is block layout?
53 #[inline(always)]
54 fn is_block(&self) -> bool {
55 false
56 }
57 /// Is it a compressible replaced element?
58 /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
59 #[inline(always)]
60 fn is_compressible_replaced(&self) -> bool {
61 false
62 }
63 /// Which box do size styles apply to
64 #[inline(always)]
65 fn box_sizing(&self) -> BoxSizing {
66 BoxSizing::BorderBox
67 }
68
69 // Overflow properties
70 /// How children overflowing their container should affect layout
71 #[inline(always)]
72 fn overflow(&self) -> Point<Overflow> {
73 Style::DEFAULT.overflow
74 }
75 /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
76 #[inline(always)]
77 fn scrollbar_width(&self) -> f32 {
78 0.0
79 }
80
81 // Position properties
82 /// What should the `position` value of this struct use as a base offset?
83 #[inline(always)]
84 fn position(&self) -> Position {
85 Style::DEFAULT.position
86 }
87 /// How should the position of this element be tweaked relative to the layout defined?
88 #[inline(always)]
89 fn inset(&self) -> Rect<LengthPercentageAuto> {
90 Style::DEFAULT.inset
91 }
92
93 // Size properies
94 /// Sets the initial size of the item
95 #[inline(always)]
96 fn size(&self) -> Size<Dimension> {
97 Style::DEFAULT.size
98 }
99 /// Controls the minimum size of the item
100 #[inline(always)]
101 fn min_size(&self) -> Size<Dimension> {
102 Style::DEFAULT.min_size
103 }
104 /// Controls the maximum size of the item
105 #[inline(always)]
106 fn max_size(&self) -> Size<Dimension> {
107 Style::DEFAULT.max_size
108 }
109 /// Sets the preferred aspect ratio for the item
110 /// The ratio is calculated as width divided by height.
111 #[inline(always)]
112 fn aspect_ratio(&self) -> Option<f32> {
113 Style::DEFAULT.aspect_ratio
114 }
115
116 // Spacing Properties
117 /// How large should the margin be on each side?
118 #[inline(always)]
119 fn margin(&self) -> Rect<LengthPercentageAuto> {
120 Style::DEFAULT.margin
121 }
122 /// How large should the padding be on each side?
123 #[inline(always)]
124 fn padding(&self) -> Rect<LengthPercentage> {
125 Style::DEFAULT.padding
126 }
127 /// How large should the border be on each side?
128 #[inline(always)]
129 fn border(&self) -> Rect<LengthPercentage> {
130 Style::DEFAULT.border
131 }
132}
133
134/// Sets the layout used for the children of this node
135///
136/// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
137#[derive(Copy, Clone, PartialEq, Eq, Debug)]
138#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
139pub enum Display {
140 /// The children will follow the block layout algorithm
141 #[cfg(feature = "block_layout")]
142 Block,
143 /// The children will follow the flexbox layout algorithm
144 #[cfg(feature = "flexbox")]
145 Flex,
146 /// The children will follow the CSS Grid layout algorithm
147 #[cfg(feature = "grid")]
148 Grid,
149 /// The node is hidden, and it's children will also be hidden
150 None,
151}
152
153impl Display {
154 /// The default Display mode
155 #[cfg(feature = "flexbox")]
156 pub const DEFAULT: Display = Display::Flex;
157
158 /// The default Display mode
159 #[cfg(all(feature = "grid", not(feature = "flexbox")))]
160 pub const DEFAULT: Display = Display::Grid;
161
162 /// The default Display mode
163 #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))]
164 pub const DEFAULT: Display = Display::Block;
165
166 /// The default Display mode
167 #[cfg(all(not(feature = "flexbox"), not(feature = "grid"), not(feature = "block_layout")))]
168 pub const DEFAULT: Display = Display::None;
169}
170
171impl Default for Display {
172 fn default() -> Self {
173 Self::DEFAULT
174 }
175}
176
177impl core::fmt::Display for Display {
178 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179 match self {
180 Display::None => write!(f, "NONE"),
181 #[cfg(feature = "block_layout")]
182 Display::Block => write!(f, "BLOCK"),
183 #[cfg(feature = "flexbox")]
184 Display::Flex => write!(f, "FLEX"),
185 #[cfg(feature = "grid")]
186 Display::Grid => write!(f, "GRID"),
187 }
188 }
189}
190
191/// An abstracted version of the CSS `display` property where any value other than "none" is represented by "normal"
192/// See: <https://www.w3.org/TR/css-display-3/#box-generation>
193#[derive(Copy, Clone, PartialEq, Eq, Debug)]
194#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
195pub enum BoxGenerationMode {
196 /// The node generates a box in the regular way
197 Normal,
198 /// The node and it's descendants generate no boxes (they are hidden)
199 None,
200}
201
202impl BoxGenerationMode {
203 /// The default of BoxGenerationMode
204 pub const DEFAULT: BoxGenerationMode = BoxGenerationMode::Normal;
205}
206
207impl Default for BoxGenerationMode {
208 fn default() -> Self {
209 Self::DEFAULT
210 }
211}
212
213/// The positioning strategy for this item.
214///
215/// This controls both how the origin is determined for the [`Style::position`] field,
216/// and whether or not the item will be controlled by flexbox's layout algorithm.
217///
218/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
219/// which can be unintuitive.
220///
221/// [`Position::Relative`] is the default value, in contrast to the default behavior in CSS.
222#[derive(Copy, Clone, PartialEq, Eq, Debug)]
223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
224pub enum Position {
225 /// The offset is computed relative to the final position given by the layout algorithm.
226 /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
227 Relative,
228 /// The offset is computed relative to this item's closest positioned ancestor, if any.
229 /// Otherwise, it is placed relative to the origin.
230 /// No space is created for the item in the page layout, and its size will not be altered.
231 ///
232 /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
233 Absolute,
234}
235
236impl Default for Position {
237 fn default() -> Self {
238 Self::Relative
239 }
240}
241
242/// Specifies whether size styles for this node are assigned to the node's "content box" or "border box"
243///
244/// - The "content box" is the node's inner size excluding padding, border and margin
245/// - The "border box" is the node's outer size including padding and border (but still excluding margin)
246///
247/// This property modifies the application of the following styles:
248///
249/// - `size`
250/// - `min_size`
251/// - `max_size`
252/// - `flex_basis`
253///
254/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
255#[derive(Copy, Clone, PartialEq, Eq, Debug)]
256#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
257pub enum BoxSizing {
258 /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border)
259 BorderBox,
260 /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin)
261 ContentBox,
262}
263
264impl Default for BoxSizing {
265 fn default() -> Self {
266 Self::BorderBox
267 }
268}
269
270/// How children overflowing their container should affect layout
271///
272/// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should
273/// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout,
274/// the main ones being:
275///
276/// - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based
277/// - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property)
278///
279/// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for
280/// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`.
281///
282/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
283#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
285pub enum Overflow {
286 /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
287 /// Content that overflows this node *should* contribute to the scroll region of its parent.
288 #[default]
289 Visible,
290 /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
291 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
292 Clip,
293 /// The automatic minimum size of this node as a flexbox/grid item should be `0`.
294 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
295 Hidden,
296 /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved
297 /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property.
298 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
299 Scroll,
300}
301
302impl Overflow {
303 /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`)
304 /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`).
305 #[inline(always)]
306 pub(crate) fn is_scroll_container(self) -> bool {
307 match self {
308 Self::Visible | Self::Clip => false,
309 Self::Hidden | Self::Scroll => true,
310 }
311 }
312
313 /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item
314 /// to be `0`. Else returns None.
315 #[inline(always)]
316 pub(crate) fn maybe_into_automatic_min_size(self) -> Option<f32> {
317 match self.is_scroll_container() {
318 true => Some(0.0),
319 false => None,
320 }
321 }
322}
323
324/// A typed representation of the CSS style information for a single node.
325///
326/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
327/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
328///
329/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
330/// information about the behavior on the web should transfer directly.
331///
332/// Detailed information about the exact behavior of each of these fields
333/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
334/// The distinction between margin, padding and border is explained well in
335/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
336///
337/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
338#[derive(Clone, PartialEq, Debug)]
339#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
340#[cfg_attr(feature = "serde", serde(default))]
341pub struct Style {
342 /// What layout strategy should be used?
343 pub display: Display,
344 /// Whether a child is display:table or not. This affects children of block layouts.
345 /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented
346 pub item_is_table: bool,
347 /// Is it a replaced element like an image or form field?
348 /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
349 pub item_is_replaced: bool,
350 /// Should size styles apply to the content box or the border box of the node
351 pub box_sizing: BoxSizing,
352
353 // Overflow properties
354 /// How children overflowing their container should affect layout
355 pub overflow: Point<Overflow>,
356 /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
357 pub scrollbar_width: f32,
358
359 // Position properties
360 /// What should the `position` value of this struct use as a base offset?
361 pub position: Position,
362 /// How should the position of this element be tweaked relative to the layout defined?
363 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
364 pub inset: Rect<LengthPercentageAuto>,
365
366 // Size properties
367 /// Sets the initial size of the item
368 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
369 pub size: Size<Dimension>,
370 /// Controls the minimum size of the item
371 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
372 pub min_size: Size<Dimension>,
373 /// Controls the maximum size of the item
374 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
375 pub max_size: Size<Dimension>,
376 /// Sets the preferred aspect ratio for the item
377 ///
378 /// The ratio is calculated as width divided by height.
379 pub aspect_ratio: Option<f32>,
380
381 // Spacing Properties
382 /// How large should the margin be on each side?
383 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
384 pub margin: Rect<LengthPercentageAuto>,
385 /// How large should the padding be on each side?
386 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
387 pub padding: Rect<LengthPercentage>,
388 /// How large should the border be on each side?
389 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
390 pub border: Rect<LengthPercentage>,
391
392 // Alignment properties
393 /// How this node's children aligned in the cross/block axis?
394 #[cfg(any(feature = "flexbox", feature = "grid"))]
395 pub align_items: Option<AlignItems>,
396 /// How this node should be aligned in the cross/block axis
397 /// Falls back to the parents [`AlignItems`] if not set
398 #[cfg(any(feature = "flexbox", feature = "grid"))]
399 pub align_self: Option<AlignSelf>,
400 /// How this node's children should be aligned in the inline axis
401 #[cfg(feature = "grid")]
402 pub justify_items: Option<AlignItems>,
403 /// How this node should be aligned in the inline axis
404 /// Falls back to the parents [`JustifyItems`] if not set
405 #[cfg(feature = "grid")]
406 pub justify_self: Option<AlignSelf>,
407 /// How should content contained within this item be aligned in the cross/block axis
408 #[cfg(any(feature = "flexbox", feature = "grid"))]
409 pub align_content: Option<AlignContent>,
410 /// How should content contained within this item be aligned in the main/inline axis
411 #[cfg(any(feature = "flexbox", feature = "grid"))]
412 pub justify_content: Option<JustifyContent>,
413 /// How large should the gaps between items in a grid or flex container be?
414 #[cfg(any(feature = "flexbox", feature = "grid"))]
415 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
416 pub gap: Size<LengthPercentage>,
417
418 // Block container properties
419 /// How items elements should aligned in the inline axis
420 #[cfg(feature = "block_layout")]
421 pub text_align: TextAlign,
422
423 // Flexbox container properties
424 /// Which direction does the main axis flow in?
425 #[cfg(feature = "flexbox")]
426 pub flex_direction: FlexDirection,
427 /// Should elements wrap, or stay in a single line?
428 #[cfg(feature = "flexbox")]
429 pub flex_wrap: FlexWrap,
430
431 // Flexbox item properties
432 /// Sets the initial main axis size of the item
433 #[cfg(feature = "flexbox")]
434 pub flex_basis: Dimension,
435 /// The relative rate at which this item grows when it is expanding to fill space
436 ///
437 /// 0.0 is the default value, and this value must be positive.
438 #[cfg(feature = "flexbox")]
439 pub flex_grow: f32,
440 /// The relative rate at which this item shrinks when it is contracting to fit into space
441 ///
442 /// 1.0 is the default value, and this value must be positive.
443 #[cfg(feature = "flexbox")]
444 pub flex_shrink: f32,
445
446 // Grid container properies
447 /// Defines the track sizing functions (heights) of the grid rows
448 #[cfg(feature = "grid")]
449 pub grid_template_rows: GridTrackVec<TrackSizingFunction>,
450 /// Defines the track sizing functions (widths) of the grid columns
451 #[cfg(feature = "grid")]
452 pub grid_template_columns: GridTrackVec<TrackSizingFunction>,
453 /// Defines the size of implicitly created rows
454 #[cfg(feature = "grid")]
455 pub grid_auto_rows: GridTrackVec<NonRepeatedTrackSizingFunction>,
456 /// Defined the size of implicitly created columns
457 #[cfg(feature = "grid")]
458 pub grid_auto_columns: GridTrackVec<NonRepeatedTrackSizingFunction>,
459 /// Controls how items get placed into the grid for auto-placed items
460 #[cfg(feature = "grid")]
461 pub grid_auto_flow: GridAutoFlow,
462
463 // Grid child properties
464 /// Defines which row in the grid the item should start and end at
465 #[cfg(feature = "grid")]
466 pub grid_row: Line<GridPlacement>,
467 /// Defines which column in the grid the item should start and end at
468 #[cfg(feature = "grid")]
469 pub grid_column: Line<GridPlacement>,
470}
471
472impl Style {
473 /// The [`Default`] layout, in a form that can be used in const functions
474 pub const DEFAULT: Style = Style {
475 display: Display::DEFAULT,
476 item_is_table: false,
477 item_is_replaced: false,
478 box_sizing: BoxSizing::BorderBox,
479 overflow: Point { x: Overflow::Visible, y: Overflow::Visible },
480 scrollbar_width: 0.0,
481 position: Position::Relative,
482 inset: Rect::auto(),
483 margin: Rect::zero(),
484 padding: Rect::zero(),
485 border: Rect::zero(),
486 size: Size::auto(),
487 min_size: Size::auto(),
488 max_size: Size::auto(),
489 aspect_ratio: None,
490 #[cfg(any(feature = "flexbox", feature = "grid"))]
491 gap: Size::zero(),
492 // Alignment
493 #[cfg(any(feature = "flexbox", feature = "grid"))]
494 align_items: None,
495 #[cfg(any(feature = "flexbox", feature = "grid"))]
496 align_self: None,
497 #[cfg(feature = "grid")]
498 justify_items: None,
499 #[cfg(feature = "grid")]
500 justify_self: None,
501 #[cfg(any(feature = "flexbox", feature = "grid"))]
502 align_content: None,
503 #[cfg(any(feature = "flexbox", feature = "grid"))]
504 justify_content: None,
505 // Block
506 #[cfg(feature = "block_layout")]
507 text_align: TextAlign::Auto,
508 // Flexbox
509 #[cfg(feature = "flexbox")]
510 flex_direction: FlexDirection::Row,
511 #[cfg(feature = "flexbox")]
512 flex_wrap: FlexWrap::NoWrap,
513 #[cfg(feature = "flexbox")]
514 flex_grow: 0.0,
515 #[cfg(feature = "flexbox")]
516 flex_shrink: 1.0,
517 #[cfg(feature = "flexbox")]
518 flex_basis: Dimension::AUTO,
519 // Grid
520 #[cfg(feature = "grid")]
521 grid_template_rows: GridTrackVec::new(),
522 #[cfg(feature = "grid")]
523 grid_template_columns: GridTrackVec::new(),
524 #[cfg(feature = "grid")]
525 grid_auto_rows: GridTrackVec::new(),
526 #[cfg(feature = "grid")]
527 grid_auto_columns: GridTrackVec::new(),
528 #[cfg(feature = "grid")]
529 grid_auto_flow: GridAutoFlow::Row,
530 #[cfg(feature = "grid")]
531 grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
532 #[cfg(feature = "grid")]
533 grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
534 };
535}
536
537impl Default for Style {
538 fn default() -> Self {
539 Style::DEFAULT
540 }
541}
542
543impl CoreStyle for Style {
544 #[inline(always)]
545 fn box_generation_mode(&self) -> BoxGenerationMode {
546 match self.display {
547 Display::None => BoxGenerationMode::None,
548 _ => BoxGenerationMode::Normal,
549 }
550 }
551 #[inline(always)]
552 #[cfg(feature = "block_layout")]
553 fn is_block(&self) -> bool {
554 matches!(self.display, Display::Block)
555 }
556 #[inline(always)]
557 fn is_compressible_replaced(&self) -> bool {
558 self.item_is_replaced
559 }
560 #[inline(always)]
561 fn box_sizing(&self) -> BoxSizing {
562 self.box_sizing
563 }
564 #[inline(always)]
565 fn overflow(&self) -> Point<Overflow> {
566 self.overflow
567 }
568 #[inline(always)]
569 fn scrollbar_width(&self) -> f32 {
570 self.scrollbar_width
571 }
572 #[inline(always)]
573 fn position(&self) -> Position {
574 self.position
575 }
576 #[inline(always)]
577 fn inset(&self) -> Rect<LengthPercentageAuto> {
578 self.inset
579 }
580 #[inline(always)]
581 fn size(&self) -> Size<Dimension> {
582 self.size
583 }
584 #[inline(always)]
585 fn min_size(&self) -> Size<Dimension> {
586 self.min_size
587 }
588 #[inline(always)]
589 fn max_size(&self) -> Size<Dimension> {
590 self.max_size
591 }
592 #[inline(always)]
593 fn aspect_ratio(&self) -> Option<f32> {
594 self.aspect_ratio
595 }
596 #[inline(always)]
597 fn margin(&self) -> Rect<LengthPercentageAuto> {
598 self.margin
599 }
600 #[inline(always)]
601 fn padding(&self) -> Rect<LengthPercentage> {
602 self.padding
603 }
604 #[inline(always)]
605 fn border(&self) -> Rect<LengthPercentage> {
606 self.border
607 }
608}
609
610impl<T: CoreStyle> CoreStyle for &'_ T {
611 #[inline(always)]
612 fn box_generation_mode(&self) -> BoxGenerationMode {
613 (*self).box_generation_mode()
614 }
615 #[inline(always)]
616 fn is_block(&self) -> bool {
617 (*self).is_block()
618 }
619 #[inline(always)]
620 fn is_compressible_replaced(&self) -> bool {
621 (*self).is_compressible_replaced()
622 }
623 #[inline(always)]
624 fn box_sizing(&self) -> BoxSizing {
625 (*self).box_sizing()
626 }
627 #[inline(always)]
628 fn overflow(&self) -> Point<Overflow> {
629 (*self).overflow()
630 }
631 #[inline(always)]
632 fn scrollbar_width(&self) -> f32 {
633 (*self).scrollbar_width()
634 }
635 #[inline(always)]
636 fn position(&self) -> Position {
637 (*self).position()
638 }
639 #[inline(always)]
640 fn inset(&self) -> Rect<LengthPercentageAuto> {
641 (*self).inset()
642 }
643 #[inline(always)]
644 fn size(&self) -> Size<Dimension> {
645 (*self).size()
646 }
647 #[inline(always)]
648 fn min_size(&self) -> Size<Dimension> {
649 (*self).min_size()
650 }
651 #[inline(always)]
652 fn max_size(&self) -> Size<Dimension> {
653 (*self).max_size()
654 }
655 #[inline(always)]
656 fn aspect_ratio(&self) -> Option<f32> {
657 (*self).aspect_ratio()
658 }
659 #[inline(always)]
660 fn margin(&self) -> Rect<LengthPercentageAuto> {
661 (*self).margin()
662 }
663 #[inline(always)]
664 fn padding(&self) -> Rect<LengthPercentage> {
665 (*self).padding()
666 }
667 #[inline(always)]
668 fn border(&self) -> Rect<LengthPercentage> {
669 (*self).border()
670 }
671}
672
673#[cfg(feature = "block_layout")]
674impl BlockContainerStyle for Style {
675 #[inline(always)]
676 fn text_align(&self) -> TextAlign {
677 self.text_align
678 }
679}
680
681#[cfg(feature = "block_layout")]
682impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T {
683 #[inline(always)]
684 fn text_align(&self) -> TextAlign {
685 (*self).text_align()
686 }
687}
688
689#[cfg(feature = "block_layout")]
690impl BlockItemStyle for Style {
691 #[inline(always)]
692 fn is_table(&self) -> bool {
693 self.item_is_table
694 }
695}
696
697#[cfg(feature = "block_layout")]
698impl<T: BlockItemStyle> BlockItemStyle for &'_ T {
699 #[inline(always)]
700 fn is_table(&self) -> bool {
701 (*self).is_table()
702 }
703}
704
705#[cfg(feature = "flexbox")]
706impl FlexboxContainerStyle for Style {
707 #[inline(always)]
708 fn flex_direction(&self) -> FlexDirection {
709 self.flex_direction
710 }
711 #[inline(always)]
712 fn flex_wrap(&self) -> FlexWrap {
713 self.flex_wrap
714 }
715 #[inline(always)]
716 fn gap(&self) -> Size<LengthPercentage> {
717 self.gap
718 }
719 #[inline(always)]
720 fn align_content(&self) -> Option<AlignContent> {
721 self.align_content
722 }
723 #[inline(always)]
724 fn align_items(&self) -> Option<AlignItems> {
725 self.align_items
726 }
727 #[inline(always)]
728 fn justify_content(&self) -> Option<JustifyContent> {
729 self.justify_content
730 }
731}
732
733#[cfg(feature = "flexbox")]
734impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
735 #[inline(always)]
736 fn flex_direction(&self) -> FlexDirection {
737 (*self).flex_direction()
738 }
739 #[inline(always)]
740 fn flex_wrap(&self) -> FlexWrap {
741 (*self).flex_wrap()
742 }
743 #[inline(always)]
744 fn gap(&self) -> Size<LengthPercentage> {
745 (*self).gap()
746 }
747 #[inline(always)]
748 fn align_content(&self) -> Option<AlignContent> {
749 (*self).align_content()
750 }
751 #[inline(always)]
752 fn align_items(&self) -> Option<AlignItems> {
753 (*self).align_items()
754 }
755 #[inline(always)]
756 fn justify_content(&self) -> Option<JustifyContent> {
757 (*self).justify_content()
758 }
759}
760
761#[cfg(feature = "flexbox")]
762impl FlexboxItemStyle for Style {
763 #[inline(always)]
764 fn flex_basis(&self) -> Dimension {
765 self.flex_basis
766 }
767 #[inline(always)]
768 fn flex_grow(&self) -> f32 {
769 self.flex_grow
770 }
771 #[inline(always)]
772 fn flex_shrink(&self) -> f32 {
773 self.flex_shrink
774 }
775 #[inline(always)]
776 fn align_self(&self) -> Option<AlignSelf> {
777 self.align_self
778 }
779}
780
781#[cfg(feature = "flexbox")]
782impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
783 #[inline(always)]
784 fn flex_basis(&self) -> Dimension {
785 (*self).flex_basis()
786 }
787 #[inline(always)]
788 fn flex_grow(&self) -> f32 {
789 (*self).flex_grow()
790 }
791 #[inline(always)]
792 fn flex_shrink(&self) -> f32 {
793 (*self).flex_shrink()
794 }
795 #[inline(always)]
796 fn align_self(&self) -> Option<AlignSelf> {
797 (*self).align_self()
798 }
799}
800
801#[cfg(feature = "grid")]
802impl GridContainerStyle for Style {
803 type TemplateTrackList<'a>
804 = &'a [TrackSizingFunction]
805 where
806 Self: 'a;
807 type AutoTrackList<'a>
808 = &'a [NonRepeatedTrackSizingFunction]
809 where
810 Self: 'a;
811
812 #[inline(always)]
813 fn grid_template_rows(&self) -> &[TrackSizingFunction] {
814 &self.grid_template_rows
815 }
816 #[inline(always)]
817 fn grid_template_columns(&self) -> &[TrackSizingFunction] {
818 &self.grid_template_columns
819 }
820 #[inline(always)]
821 fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
822 &self.grid_auto_rows
823 }
824 #[inline(always)]
825 fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
826 &self.grid_auto_columns
827 }
828 #[inline(always)]
829 fn grid_auto_flow(&self) -> GridAutoFlow {
830 self.grid_auto_flow
831 }
832 #[inline(always)]
833 fn gap(&self) -> Size<LengthPercentage> {
834 self.gap
835 }
836 #[inline(always)]
837 fn align_content(&self) -> Option<AlignContent> {
838 self.align_content
839 }
840 #[inline(always)]
841 fn justify_content(&self) -> Option<JustifyContent> {
842 self.justify_content
843 }
844 #[inline(always)]
845 fn align_items(&self) -> Option<AlignItems> {
846 self.align_items
847 }
848 #[inline(always)]
849 fn justify_items(&self) -> Option<AlignItems> {
850 self.justify_items
851 }
852}
853
854#[cfg(feature = "grid")]
855impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
856 type TemplateTrackList<'a>
857 = T::TemplateTrackList<'a>
858 where
859 Self: 'a;
860 type AutoTrackList<'a>
861 = T::AutoTrackList<'a>
862 where
863 Self: 'a;
864
865 #[inline(always)]
866 fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> {
867 (*self).grid_template_rows()
868 }
869 #[inline(always)]
870 fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> {
871 (*self).grid_template_columns()
872 }
873 #[inline(always)]
874 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
875 (*self).grid_auto_rows()
876 }
877 #[inline(always)]
878 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
879 (*self).grid_auto_columns()
880 }
881 #[inline(always)]
882 fn grid_auto_flow(&self) -> GridAutoFlow {
883 (*self).grid_auto_flow()
884 }
885 #[inline(always)]
886 fn gap(&self) -> Size<LengthPercentage> {
887 (*self).gap()
888 }
889 #[inline(always)]
890 fn align_content(&self) -> Option<AlignContent> {
891 (*self).align_content()
892 }
893 #[inline(always)]
894 fn justify_content(&self) -> Option<JustifyContent> {
895 (*self).justify_content()
896 }
897 #[inline(always)]
898 fn align_items(&self) -> Option<AlignItems> {
899 (*self).align_items()
900 }
901 #[inline(always)]
902 fn justify_items(&self) -> Option<AlignItems> {
903 (*self).justify_items()
904 }
905}
906
907#[cfg(feature = "grid")]
908impl GridItemStyle for Style {
909 #[inline(always)]
910 fn grid_row(&self) -> Line<GridPlacement> {
911 self.grid_row
912 }
913 #[inline(always)]
914 fn grid_column(&self) -> Line<GridPlacement> {
915 self.grid_column
916 }
917 #[inline(always)]
918 fn align_self(&self) -> Option<AlignSelf> {
919 self.align_self
920 }
921 #[inline(always)]
922 fn justify_self(&self) -> Option<AlignSelf> {
923 self.justify_self
924 }
925}
926
927#[cfg(feature = "grid")]
928impl<T: GridItemStyle> GridItemStyle for &'_ T {
929 #[inline(always)]
930 fn grid_row(&self) -> Line<GridPlacement> {
931 (*self).grid_row()
932 }
933 #[inline(always)]
934 fn grid_column(&self) -> Line<GridPlacement> {
935 (*self).grid_column()
936 }
937 #[inline(always)]
938 fn align_self(&self) -> Option<AlignSelf> {
939 (*self).align_self()
940 }
941 #[inline(always)]
942 fn justify_self(&self) -> Option<AlignSelf> {
943 (*self).justify_self()
944 }
945}
946
947#[cfg(test)]
948mod tests {
949 use super::Style;
950 use crate::{geometry::*, style_helpers::TaffyAuto as _};
951
952 #[test]
953 fn defaults_match() {
954 #[cfg(feature = "grid")]
955 use super::GridPlacement;
956
957 let old_defaults = Style {
958 display: Default::default(),
959 item_is_table: false,
960 item_is_replaced: false,
961 box_sizing: Default::default(),
962 overflow: Default::default(),
963 scrollbar_width: 0.0,
964 position: Default::default(),
965 #[cfg(feature = "flexbox")]
966 flex_direction: Default::default(),
967 #[cfg(feature = "flexbox")]
968 flex_wrap: Default::default(),
969 #[cfg(any(feature = "flexbox", feature = "grid"))]
970 align_items: Default::default(),
971 #[cfg(any(feature = "flexbox", feature = "grid"))]
972 align_self: Default::default(),
973 #[cfg(feature = "grid")]
974 justify_items: Default::default(),
975 #[cfg(feature = "grid")]
976 justify_self: Default::default(),
977 #[cfg(any(feature = "flexbox", feature = "grid"))]
978 align_content: Default::default(),
979 #[cfg(any(feature = "flexbox", feature = "grid"))]
980 justify_content: Default::default(),
981 inset: Rect::auto(),
982 margin: Rect::zero(),
983 padding: Rect::zero(),
984 border: Rect::zero(),
985 gap: Size::zero(),
986 #[cfg(feature = "block_layout")]
987 text_align: Default::default(),
988 #[cfg(feature = "flexbox")]
989 flex_grow: 0.0,
990 #[cfg(feature = "flexbox")]
991 flex_shrink: 1.0,
992 #[cfg(feature = "flexbox")]
993 flex_basis: super::Dimension::AUTO,
994 size: Size::auto(),
995 min_size: Size::auto(),
996 max_size: Size::auto(),
997 aspect_ratio: Default::default(),
998 #[cfg(feature = "grid")]
999 grid_template_rows: Default::default(),
1000 #[cfg(feature = "grid")]
1001 grid_template_columns: Default::default(),
1002 #[cfg(feature = "grid")]
1003 grid_auto_rows: Default::default(),
1004 #[cfg(feature = "grid")]
1005 grid_auto_columns: Default::default(),
1006 #[cfg(feature = "grid")]
1007 grid_auto_flow: Default::default(),
1008 #[cfg(feature = "grid")]
1009 grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1010 #[cfg(feature = "grid")]
1011 grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1012 };
1013
1014 assert_eq!(Style::DEFAULT, Style::default());
1015 assert_eq!(Style::DEFAULT, old_defaults);
1016 }
1017
1018 // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes
1019 // and to serve as accurate up-to-date documentation on the sizes.
1020 #[test]
1021 fn style_sizes() {
1022 use super::*;
1023
1024 fn assert_type_size<T>(expected_size: usize) {
1025 let name = ::core::any::type_name::<T>();
1026 let name = name.replace("taffy::geometry::", "");
1027 let name = name.replace("taffy::style::dimension::", "");
1028 let name = name.replace("taffy::style::alignment::", "");
1029 let name = name.replace("taffy::style::flex::", "");
1030 let name = name.replace("taffy::style::grid::", "");
1031
1032 assert_eq!(
1033 ::core::mem::size_of::<T>(),
1034 expected_size,
1035 "Expected {} for be {} byte(s) but it was {} byte(s)",
1036 name,
1037 expected_size,
1038 ::core::mem::size_of::<T>(),
1039 );
1040 }
1041
1042 // Display and Position
1043 assert_type_size::<Display>(1);
1044 assert_type_size::<BoxSizing>(1);
1045 assert_type_size::<Position>(1);
1046 assert_type_size::<Overflow>(1);
1047
1048 // Dimensions and aggregations of Dimensions
1049 assert_type_size::<f32>(4);
1050 assert_type_size::<LengthPercentage>(8);
1051 assert_type_size::<LengthPercentageAuto>(8);
1052 assert_type_size::<Dimension>(8);
1053 assert_type_size::<Size<LengthPercentage>>(16);
1054 assert_type_size::<Size<LengthPercentageAuto>>(16);
1055 assert_type_size::<Size<Dimension>>(16);
1056 assert_type_size::<Rect<LengthPercentage>>(32);
1057 assert_type_size::<Rect<LengthPercentageAuto>>(32);
1058 assert_type_size::<Rect<Dimension>>(32);
1059
1060 // Alignment
1061 assert_type_size::<AlignContent>(1);
1062 assert_type_size::<AlignItems>(1);
1063 assert_type_size::<Option<AlignItems>>(1);
1064
1065 // Flexbox Container
1066 assert_type_size::<FlexDirection>(1);
1067 assert_type_size::<FlexWrap>(1);
1068
1069 // CSS Grid Container
1070 assert_type_size::<GridAutoFlow>(1);
1071 assert_type_size::<MinTrackSizingFunction>(8);
1072 assert_type_size::<MaxTrackSizingFunction>(8);
1073 assert_type_size::<NonRepeatedTrackSizingFunction>(16);
1074 assert_type_size::<TrackSizingFunction>(32);
1075 assert_type_size::<Vec<NonRepeatedTrackSizingFunction>>(24);
1076 assert_type_size::<Vec<TrackSizingFunction>>(24);
1077
1078 // CSS Grid Item
1079 assert_type_size::<GridPlacement>(4);
1080 assert_type_size::<Line<GridPlacement>>(8);
1081
1082 // Overall
1083 assert_type_size::<Style>(352);
1084 }
1085}