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