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