Fix bounds check in `CellOccupancyMatrix::last_of_type` (#890)
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, Default)]
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 #[default]
260 Relative,
261 /// The offset is computed relative to this item's closest positioned ancestor, if any.
262 /// Otherwise, it is placed relative to the origin.
263 /// No space is created for the item in the page layout, and its size will not be altered.
264 ///
265 /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
266 Absolute,
267}
268
269/// Specifies whether size styles for this node are assigned to the node's "content box" or "border box"
270///
271/// - The "content box" is the node's inner size excluding padding, border and margin
272/// - The "border box" is the node's outer size including padding and border (but still excluding margin)
273///
274/// This property modifies the application of the following styles:
275///
276/// - `size`
277/// - `min_size`
278/// - `max_size`
279/// - `flex_basis`
280///
281/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
282#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284pub enum BoxSizing {
285 /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border)
286 #[default]
287 BorderBox,
288 /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin)
289 ContentBox,
290}
291
292/// How children overflowing their container should affect layout
293///
294/// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should
295/// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout,
296/// the main ones being:
297///
298/// - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based
299/// - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property)
300///
301/// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for
302/// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`.
303///
304/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
305#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
306#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
307pub enum Overflow {
308 /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
309 /// Content that overflows this node *should* contribute to the scroll region of its parent.
310 #[default]
311 Visible,
312 /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
313 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
314 Clip,
315 /// The automatic minimum size of this node as a flexbox/grid item should be `0`.
316 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
317 Hidden,
318 /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved
319 /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property.
320 /// Content that overflows this node should *not* contribute to the scroll region of its parent.
321 Scroll,
322}
323
324impl Overflow {
325 /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`)
326 /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`).
327 #[inline(always)]
328 pub(crate) fn is_scroll_container(self) -> bool {
329 match self {
330 Self::Visible | Self::Clip => false,
331 Self::Hidden | Self::Scroll => true,
332 }
333 }
334
335 /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item
336 /// to be `0`. Else returns None.
337 #[inline(always)]
338 pub(crate) fn maybe_into_automatic_min_size(self) -> Option<f32> {
339 match self.is_scroll_container() {
340 true => Some(0.0),
341 false => None,
342 }
343 }
344}
345
346/// A typed representation of the CSS style information for a single node.
347///
348/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
349/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
350///
351/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
352/// information about the behavior on the web should transfer directly.
353///
354/// Detailed information about the exact behavior of each of these fields
355/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
356/// The distinction between margin, padding and border is explained well in
357/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
358///
359/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
360#[derive(Clone, PartialEq, Debug)]
361#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
362#[cfg_attr(feature = "serde", serde(default))]
363pub struct Style<S: CheapCloneStr = DefaultCheapStr> {
364 /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled
365 /// It should always be set to `core::marker::PhantomData`.
366 pub dummy: core::marker::PhantomData<S>,
367 /// What layout strategy should be used?
368 pub display: Display,
369 /// Whether a child is display:table or not. This affects children of block layouts.
370 /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented
371 pub item_is_table: bool,
372 /// Is it a replaced element like an image or form field?
373 /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
374 pub item_is_replaced: bool,
375 /// Should size styles apply to the content box or the border box of the node
376 pub box_sizing: BoxSizing,
377
378 // Overflow properties
379 /// How children overflowing their container should affect layout
380 pub overflow: Point<Overflow>,
381 /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
382 pub scrollbar_width: f32,
383
384 // Position properties
385 /// What should the `position` value of this struct use as a base offset?
386 pub position: Position,
387 /// How should the position of this element be tweaked relative to the layout defined?
388 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
389 pub inset: Rect<LengthPercentageAuto>,
390
391 // Size properties
392 /// Sets the initial size of the item
393 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
394 pub size: Size<Dimension>,
395 /// Controls the minimum size of the item
396 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
397 pub min_size: Size<Dimension>,
398 /// Controls the maximum size of the item
399 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
400 pub max_size: Size<Dimension>,
401 /// Sets the preferred aspect ratio for the item
402 ///
403 /// The ratio is calculated as width divided by height.
404 pub aspect_ratio: Option<f32>,
405
406 // Spacing Properties
407 /// How large should the margin be on each side?
408 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
409 pub margin: Rect<LengthPercentageAuto>,
410 /// How large should the padding be on each side?
411 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
412 pub padding: Rect<LengthPercentage>,
413 /// How large should the border be on each side?
414 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
415 pub border: Rect<LengthPercentage>,
416
417 // Alignment properties
418 /// How this node's children aligned in the cross/block axis?
419 #[cfg(any(feature = "flexbox", feature = "grid"))]
420 pub align_items: Option<AlignItems>,
421 /// How this node should be aligned in the cross/block axis
422 /// Falls back to the parents [`AlignItems`] if not set
423 #[cfg(any(feature = "flexbox", feature = "grid"))]
424 pub align_self: Option<AlignSelf>,
425 /// How this node's children should be aligned in the inline axis
426 #[cfg(feature = "grid")]
427 pub justify_items: Option<AlignItems>,
428 /// How this node should be aligned in the inline axis
429 /// Falls back to the parents [`JustifyItems`] if not set
430 #[cfg(feature = "grid")]
431 pub justify_self: Option<AlignSelf>,
432 /// How should content contained within this item be aligned in the cross/block axis
433 #[cfg(any(feature = "flexbox", feature = "grid"))]
434 pub align_content: Option<AlignContent>,
435 /// How should content contained within this item be aligned in the main/inline axis
436 #[cfg(any(feature = "flexbox", feature = "grid"))]
437 pub justify_content: Option<JustifyContent>,
438 /// How large should the gaps between items in a grid or flex container be?
439 #[cfg(any(feature = "flexbox", feature = "grid"))]
440 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
441 pub gap: Size<LengthPercentage>,
442
443 // Block container properties
444 /// How items elements should aligned in the inline axis
445 #[cfg(feature = "block_layout")]
446 pub text_align: TextAlign,
447
448 // Flexbox container properties
449 /// Which direction does the main axis flow in?
450 #[cfg(feature = "flexbox")]
451 pub flex_direction: FlexDirection,
452 /// Should elements wrap, or stay in a single line?
453 #[cfg(feature = "flexbox")]
454 pub flex_wrap: FlexWrap,
455
456 // Flexbox item properties
457 /// Sets the initial main axis size of the item
458 #[cfg(feature = "flexbox")]
459 pub flex_basis: Dimension,
460 /// The relative rate at which this item grows when it is expanding to fill space
461 ///
462 /// 0.0 is the default value, and this value must be positive.
463 #[cfg(feature = "flexbox")]
464 pub flex_grow: f32,
465 /// The relative rate at which this item shrinks when it is contracting to fit into space
466 ///
467 /// 1.0 is the default value, and this value must be positive.
468 #[cfg(feature = "flexbox")]
469 pub flex_shrink: f32,
470
471 // Grid container properies
472 /// Defines the track sizing functions (heights) of the grid rows
473 #[cfg(feature = "grid")]
474 pub grid_template_rows: GridTrackVec<GridTemplateComponent<S>>,
475 /// Defines the track sizing functions (widths) of the grid columns
476 #[cfg(feature = "grid")]
477 pub grid_template_columns: GridTrackVec<GridTemplateComponent<S>>,
478 /// Defines the size of implicitly created rows
479 #[cfg(feature = "grid")]
480 pub grid_auto_rows: GridTrackVec<TrackSizingFunction>,
481 /// Defined the size of implicitly created columns
482 #[cfg(feature = "grid")]
483 pub grid_auto_columns: GridTrackVec<TrackSizingFunction>,
484 /// Controls how items get placed into the grid for auto-placed items
485 #[cfg(feature = "grid")]
486 pub grid_auto_flow: GridAutoFlow,
487
488 // Grid container named properties
489 /// Defines the rectangular grid areas
490 #[cfg(feature = "grid")]
491 pub grid_template_areas: GridTrackVec<GridTemplateArea<S>>,
492 /// The named lines between the columns
493 #[cfg(feature = "grid")]
494 pub grid_template_column_names: GridTrackVec<GridTrackVec<S>>,
495 /// The named lines between the rows
496 #[cfg(feature = "grid")]
497 pub grid_template_row_names: GridTrackVec<GridTrackVec<S>>,
498
499 // Grid child properties
500 /// Defines which row in the grid the item should start and end at
501 #[cfg(feature = "grid")]
502 pub grid_row: Line<GridPlacement<S>>,
503 /// Defines which column in the grid the item should start and end at
504 #[cfg(feature = "grid")]
505 pub grid_column: Line<GridPlacement<S>>,
506}
507
508impl<S: CheapCloneStr> Style<S> {
509 /// The [`Default`] layout, in a form that can be used in const functions
510 pub const DEFAULT: Style<S> = Style {
511 dummy: core::marker::PhantomData,
512 display: Display::DEFAULT,
513 item_is_table: false,
514 item_is_replaced: false,
515 box_sizing: BoxSizing::BorderBox,
516 overflow: Point { x: Overflow::Visible, y: Overflow::Visible },
517 scrollbar_width: 0.0,
518 position: Position::Relative,
519 inset: Rect::auto(),
520 margin: Rect::zero(),
521 padding: Rect::zero(),
522 border: Rect::zero(),
523 size: Size::auto(),
524 min_size: Size::auto(),
525 max_size: Size::auto(),
526 aspect_ratio: None,
527 #[cfg(any(feature = "flexbox", feature = "grid"))]
528 gap: Size::zero(),
529 // Alignment
530 #[cfg(any(feature = "flexbox", feature = "grid"))]
531 align_items: None,
532 #[cfg(any(feature = "flexbox", feature = "grid"))]
533 align_self: None,
534 #[cfg(feature = "grid")]
535 justify_items: None,
536 #[cfg(feature = "grid")]
537 justify_self: None,
538 #[cfg(any(feature = "flexbox", feature = "grid"))]
539 align_content: None,
540 #[cfg(any(feature = "flexbox", feature = "grid"))]
541 justify_content: None,
542 // Block
543 #[cfg(feature = "block_layout")]
544 text_align: TextAlign::Auto,
545 // Flexbox
546 #[cfg(feature = "flexbox")]
547 flex_direction: FlexDirection::Row,
548 #[cfg(feature = "flexbox")]
549 flex_wrap: FlexWrap::NoWrap,
550 #[cfg(feature = "flexbox")]
551 flex_grow: 0.0,
552 #[cfg(feature = "flexbox")]
553 flex_shrink: 1.0,
554 #[cfg(feature = "flexbox")]
555 flex_basis: Dimension::AUTO,
556 // Grid
557 #[cfg(feature = "grid")]
558 grid_template_rows: GridTrackVec::new(),
559 #[cfg(feature = "grid")]
560 grid_template_columns: GridTrackVec::new(),
561 #[cfg(feature = "grid")]
562 grid_template_areas: GridTrackVec::new(),
563 #[cfg(feature = "grid")]
564 grid_template_column_names: GridTrackVec::new(),
565 #[cfg(feature = "grid")]
566 grid_template_row_names: GridTrackVec::new(),
567 #[cfg(feature = "grid")]
568 grid_auto_rows: GridTrackVec::new(),
569 #[cfg(feature = "grid")]
570 grid_auto_columns: GridTrackVec::new(),
571 #[cfg(feature = "grid")]
572 grid_auto_flow: GridAutoFlow::Row,
573 #[cfg(feature = "grid")]
574 grid_row: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
575 #[cfg(feature = "grid")]
576 grid_column: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
577 };
578}
579
580impl<S: CheapCloneStr> Default for Style<S> {
581 fn default() -> Self {
582 Style::DEFAULT
583 }
584}
585
586impl<S: CheapCloneStr> CoreStyle for Style<S> {
587 type CustomIdent = S;
588
589 #[inline(always)]
590 fn box_generation_mode(&self) -> BoxGenerationMode {
591 match self.display {
592 Display::None => BoxGenerationMode::None,
593 _ => BoxGenerationMode::Normal,
594 }
595 }
596 #[inline(always)]
597 #[cfg(feature = "block_layout")]
598 fn is_block(&self) -> bool {
599 matches!(self.display, Display::Block)
600 }
601 #[inline(always)]
602 fn is_compressible_replaced(&self) -> bool {
603 self.item_is_replaced
604 }
605 #[inline(always)]
606 fn box_sizing(&self) -> BoxSizing {
607 self.box_sizing
608 }
609 #[inline(always)]
610 fn overflow(&self) -> Point<Overflow> {
611 self.overflow
612 }
613 #[inline(always)]
614 fn scrollbar_width(&self) -> f32 {
615 self.scrollbar_width
616 }
617 #[inline(always)]
618 fn position(&self) -> Position {
619 self.position
620 }
621 #[inline(always)]
622 fn inset(&self) -> Rect<LengthPercentageAuto> {
623 self.inset
624 }
625 #[inline(always)]
626 fn size(&self) -> Size<Dimension> {
627 self.size
628 }
629 #[inline(always)]
630 fn min_size(&self) -> Size<Dimension> {
631 self.min_size
632 }
633 #[inline(always)]
634 fn max_size(&self) -> Size<Dimension> {
635 self.max_size
636 }
637 #[inline(always)]
638 fn aspect_ratio(&self) -> Option<f32> {
639 self.aspect_ratio
640 }
641 #[inline(always)]
642 fn margin(&self) -> Rect<LengthPercentageAuto> {
643 self.margin
644 }
645 #[inline(always)]
646 fn padding(&self) -> Rect<LengthPercentage> {
647 self.padding
648 }
649 #[inline(always)]
650 fn border(&self) -> Rect<LengthPercentage> {
651 self.border
652 }
653}
654
655impl<T: CoreStyle> CoreStyle for &'_ T {
656 type CustomIdent = T::CustomIdent;
657
658 #[inline(always)]
659 fn box_generation_mode(&self) -> BoxGenerationMode {
660 (*self).box_generation_mode()
661 }
662 #[inline(always)]
663 fn is_block(&self) -> bool {
664 (*self).is_block()
665 }
666 #[inline(always)]
667 fn is_compressible_replaced(&self) -> bool {
668 (*self).is_compressible_replaced()
669 }
670 #[inline(always)]
671 fn box_sizing(&self) -> BoxSizing {
672 (*self).box_sizing()
673 }
674 #[inline(always)]
675 fn overflow(&self) -> Point<Overflow> {
676 (*self).overflow()
677 }
678 #[inline(always)]
679 fn scrollbar_width(&self) -> f32 {
680 (*self).scrollbar_width()
681 }
682 #[inline(always)]
683 fn position(&self) -> Position {
684 (*self).position()
685 }
686 #[inline(always)]
687 fn inset(&self) -> Rect<LengthPercentageAuto> {
688 (*self).inset()
689 }
690 #[inline(always)]
691 fn size(&self) -> Size<Dimension> {
692 (*self).size()
693 }
694 #[inline(always)]
695 fn min_size(&self) -> Size<Dimension> {
696 (*self).min_size()
697 }
698 #[inline(always)]
699 fn max_size(&self) -> Size<Dimension> {
700 (*self).max_size()
701 }
702 #[inline(always)]
703 fn aspect_ratio(&self) -> Option<f32> {
704 (*self).aspect_ratio()
705 }
706 #[inline(always)]
707 fn margin(&self) -> Rect<LengthPercentageAuto> {
708 (*self).margin()
709 }
710 #[inline(always)]
711 fn padding(&self) -> Rect<LengthPercentage> {
712 (*self).padding()
713 }
714 #[inline(always)]
715 fn border(&self) -> Rect<LengthPercentage> {
716 (*self).border()
717 }
718}
719
720#[cfg(feature = "block_layout")]
721impl<S: CheapCloneStr> BlockContainerStyle for Style<S> {
722 #[inline(always)]
723 fn text_align(&self) -> TextAlign {
724 self.text_align
725 }
726}
727
728#[cfg(feature = "block_layout")]
729impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T {
730 #[inline(always)]
731 fn text_align(&self) -> TextAlign {
732 (*self).text_align()
733 }
734}
735
736#[cfg(feature = "block_layout")]
737impl<S: CheapCloneStr> BlockItemStyle for Style<S> {
738 #[inline(always)]
739 fn is_table(&self) -> bool {
740 self.item_is_table
741 }
742}
743
744#[cfg(feature = "block_layout")]
745impl<T: BlockItemStyle> BlockItemStyle for &'_ T {
746 #[inline(always)]
747 fn is_table(&self) -> bool {
748 (*self).is_table()
749 }
750}
751
752#[cfg(feature = "flexbox")]
753impl<S: CheapCloneStr> FlexboxContainerStyle for Style<S> {
754 #[inline(always)]
755 fn flex_direction(&self) -> FlexDirection {
756 self.flex_direction
757 }
758 #[inline(always)]
759 fn flex_wrap(&self) -> FlexWrap {
760 self.flex_wrap
761 }
762 #[inline(always)]
763 fn gap(&self) -> Size<LengthPercentage> {
764 self.gap
765 }
766 #[inline(always)]
767 fn align_content(&self) -> Option<AlignContent> {
768 self.align_content
769 }
770 #[inline(always)]
771 fn align_items(&self) -> Option<AlignItems> {
772 self.align_items
773 }
774 #[inline(always)]
775 fn justify_content(&self) -> Option<JustifyContent> {
776 self.justify_content
777 }
778}
779
780#[cfg(feature = "flexbox")]
781impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
782 #[inline(always)]
783 fn flex_direction(&self) -> FlexDirection {
784 (*self).flex_direction()
785 }
786 #[inline(always)]
787 fn flex_wrap(&self) -> FlexWrap {
788 (*self).flex_wrap()
789 }
790 #[inline(always)]
791 fn gap(&self) -> Size<LengthPercentage> {
792 (*self).gap()
793 }
794 #[inline(always)]
795 fn align_content(&self) -> Option<AlignContent> {
796 (*self).align_content()
797 }
798 #[inline(always)]
799 fn align_items(&self) -> Option<AlignItems> {
800 (*self).align_items()
801 }
802 #[inline(always)]
803 fn justify_content(&self) -> Option<JustifyContent> {
804 (*self).justify_content()
805 }
806}
807
808#[cfg(feature = "flexbox")]
809impl<S: CheapCloneStr> FlexboxItemStyle for Style<S> {
810 #[inline(always)]
811 fn flex_basis(&self) -> Dimension {
812 self.flex_basis
813 }
814 #[inline(always)]
815 fn flex_grow(&self) -> f32 {
816 self.flex_grow
817 }
818 #[inline(always)]
819 fn flex_shrink(&self) -> f32 {
820 self.flex_shrink
821 }
822 #[inline(always)]
823 fn align_self(&self) -> Option<AlignSelf> {
824 self.align_self
825 }
826}
827
828#[cfg(feature = "flexbox")]
829impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
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 = "grid")]
849impl<S: CheapCloneStr> GridContainerStyle for Style<S> {
850 type Repetition<'a>
851 = &'a GridTemplateRepetition<S>
852 where
853 Self: 'a;
854
855 type TemplateTrackList<'a>
856 = core::iter::Map<
857 core::slice::Iter<'a, GridTemplateComponent<S>>,
858 fn(&'a GridTemplateComponent<S>) -> GenericGridTemplateComponent<S, &'a GridTemplateRepetition<S>>,
859 >
860 where
861 Self: 'a;
862
863 type AutoTrackList<'a>
864 = core::iter::Copied<core::slice::Iter<'a, TrackSizingFunction>>
865 where
866 Self: 'a;
867
868 #[cfg(feature = "grid")]
869 type TemplateLineNames<'a>
870 = core::iter::Map<core::slice::Iter<'a, GridTrackVec<S>>, fn(&GridTrackVec<S>) -> core::slice::Iter<'_, S>>
871 where
872 Self: 'a;
873 #[cfg(feature = "grid")]
874 type GridTemplateAreas<'a>
875 = core::iter::Cloned<core::slice::Iter<'a, GridTemplateArea<S>>>
876 where
877 Self: 'a;
878
879 #[inline(always)]
880 fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
881 Some(self.grid_template_rows.iter().map(|c| c.as_component_ref()))
882 }
883 #[inline(always)]
884 fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
885 Some(self.grid_template_columns.iter().map(|c| c.as_component_ref()))
886 }
887 #[inline(always)]
888 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
889 self.grid_auto_rows.iter().copied()
890 }
891 #[inline(always)]
892 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
893 self.grid_auto_columns.iter().copied()
894 }
895 #[inline(always)]
896 fn grid_auto_flow(&self) -> GridAutoFlow {
897 self.grid_auto_flow
898 }
899 #[inline(always)]
900 fn gap(&self) -> Size<LengthPercentage> {
901 self.gap
902 }
903 #[inline(always)]
904 fn align_content(&self) -> Option<AlignContent> {
905 self.align_content
906 }
907 #[inline(always)]
908 fn justify_content(&self) -> Option<JustifyContent> {
909 self.justify_content
910 }
911 #[inline(always)]
912 fn align_items(&self) -> Option<AlignItems> {
913 self.align_items
914 }
915 #[inline(always)]
916 fn justify_items(&self) -> Option<AlignItems> {
917 self.justify_items
918 }
919
920 #[inline(always)]
921 #[cfg(feature = "grid")]
922 fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
923 Some(self.grid_template_areas.iter().cloned())
924 }
925
926 #[inline(always)]
927 #[cfg(feature = "grid")]
928 fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
929 Some(self.grid_template_column_names.iter().map(|names| names.iter()))
930 }
931
932 #[inline(always)]
933 #[cfg(feature = "grid")]
934 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
935 Some(self.grid_template_row_names.iter().map(|names| names.iter()))
936 }
937}
938
939#[cfg(feature = "grid")]
940impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
941 type Repetition<'a>
942 = T::Repetition<'a>
943 where
944 Self: 'a;
945
946 type TemplateTrackList<'a>
947 = T::TemplateTrackList<'a>
948 where
949 Self: 'a;
950
951 type AutoTrackList<'a>
952 = T::AutoTrackList<'a>
953 where
954 Self: 'a;
955
956 /// The type returned by grid_template_row_names and grid_template_column_names
957 #[cfg(feature = "grid")]
958 type TemplateLineNames<'a>
959 = T::TemplateLineNames<'a>
960 where
961 Self: 'a;
962 #[cfg(feature = "grid")]
963 type GridTemplateAreas<'a>
964 = T::GridTemplateAreas<'a>
965 where
966 Self: 'a;
967
968 #[inline(always)]
969 fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
970 (*self).grid_template_rows()
971 }
972 #[inline(always)]
973 fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
974 (*self).grid_template_columns()
975 }
976 #[inline(always)]
977 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
978 (*self).grid_auto_rows()
979 }
980 #[inline(always)]
981 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
982 (*self).grid_auto_columns()
983 }
984 #[cfg(feature = "grid")]
985 #[inline(always)]
986 fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
987 (*self).grid_template_areas()
988 }
989 #[cfg(feature = "grid")]
990 #[inline(always)]
991 fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
992 (*self).grid_template_column_names()
993 }
994 #[cfg(feature = "grid")]
995 #[inline(always)]
996 fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
997 (*self).grid_template_row_names()
998 }
999 #[inline(always)]
1000 fn grid_auto_flow(&self) -> GridAutoFlow {
1001 (*self).grid_auto_flow()
1002 }
1003 #[inline(always)]
1004 fn gap(&self) -> Size<LengthPercentage> {
1005 (*self).gap()
1006 }
1007 #[inline(always)]
1008 fn align_content(&self) -> Option<AlignContent> {
1009 (*self).align_content()
1010 }
1011 #[inline(always)]
1012 fn justify_content(&self) -> Option<JustifyContent> {
1013 (*self).justify_content()
1014 }
1015 #[inline(always)]
1016 fn align_items(&self) -> Option<AlignItems> {
1017 (*self).align_items()
1018 }
1019 #[inline(always)]
1020 fn justify_items(&self) -> Option<AlignItems> {
1021 (*self).justify_items()
1022 }
1023}
1024
1025#[cfg(feature = "grid")]
1026impl<S: CheapCloneStr> GridItemStyle for Style<S> {
1027 #[inline(always)]
1028 fn grid_row(&self) -> Line<GridPlacement<S>> {
1029 // TODO: Investigate eliminating clone
1030 self.grid_row.clone()
1031 }
1032 #[inline(always)]
1033 fn grid_column(&self) -> Line<GridPlacement<S>> {
1034 // TODO: Investigate eliminating clone
1035 self.grid_column.clone()
1036 }
1037 #[inline(always)]
1038 fn align_self(&self) -> Option<AlignSelf> {
1039 self.align_self
1040 }
1041 #[inline(always)]
1042 fn justify_self(&self) -> Option<AlignSelf> {
1043 self.justify_self
1044 }
1045}
1046
1047#[cfg(feature = "grid")]
1048impl<T: GridItemStyle> GridItemStyle for &'_ T {
1049 #[inline(always)]
1050 fn grid_row(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1051 (*self).grid_row()
1052 }
1053 #[inline(always)]
1054 fn grid_column(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1055 (*self).grid_column()
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(test)]
1068mod tests {
1069 use std::sync::Arc;
1070
1071 use super::Style;
1072 use crate::sys::DefaultCheapStr;
1073 use crate::{geometry::*, style_helpers::TaffyAuto as _};
1074
1075 #[test]
1076 fn defaults_match() {
1077 #[cfg(feature = "grid")]
1078 use super::GridPlacement;
1079
1080 let old_defaults: Style<DefaultCheapStr> = Style {
1081 dummy: core::marker::PhantomData,
1082 display: Default::default(),
1083 item_is_table: false,
1084 item_is_replaced: false,
1085 box_sizing: Default::default(),
1086 overflow: Default::default(),
1087 scrollbar_width: 0.0,
1088 position: Default::default(),
1089 #[cfg(feature = "flexbox")]
1090 flex_direction: Default::default(),
1091 #[cfg(feature = "flexbox")]
1092 flex_wrap: Default::default(),
1093 #[cfg(any(feature = "flexbox", feature = "grid"))]
1094 align_items: Default::default(),
1095 #[cfg(any(feature = "flexbox", feature = "grid"))]
1096 align_self: Default::default(),
1097 #[cfg(feature = "grid")]
1098 justify_items: Default::default(),
1099 #[cfg(feature = "grid")]
1100 justify_self: Default::default(),
1101 #[cfg(any(feature = "flexbox", feature = "grid"))]
1102 align_content: Default::default(),
1103 #[cfg(any(feature = "flexbox", feature = "grid"))]
1104 justify_content: Default::default(),
1105 inset: Rect::auto(),
1106 margin: Rect::zero(),
1107 padding: Rect::zero(),
1108 border: Rect::zero(),
1109 gap: Size::zero(),
1110 #[cfg(feature = "block_layout")]
1111 text_align: Default::default(),
1112 #[cfg(feature = "flexbox")]
1113 flex_grow: 0.0,
1114 #[cfg(feature = "flexbox")]
1115 flex_shrink: 1.0,
1116 #[cfg(feature = "flexbox")]
1117 flex_basis: super::Dimension::AUTO,
1118 size: Size::auto(),
1119 min_size: Size::auto(),
1120 max_size: Size::auto(),
1121 aspect_ratio: Default::default(),
1122 #[cfg(feature = "grid")]
1123 grid_template_rows: Default::default(),
1124 #[cfg(feature = "grid")]
1125 grid_template_columns: Default::default(),
1126 #[cfg(feature = "grid")]
1127 grid_template_row_names: Default::default(),
1128 #[cfg(feature = "grid")]
1129 grid_template_column_names: Default::default(),
1130 #[cfg(feature = "grid")]
1131 grid_template_areas: Default::default(),
1132 #[cfg(feature = "grid")]
1133 grid_auto_rows: Default::default(),
1134 #[cfg(feature = "grid")]
1135 grid_auto_columns: Default::default(),
1136 #[cfg(feature = "grid")]
1137 grid_auto_flow: Default::default(),
1138 #[cfg(feature = "grid")]
1139 grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1140 #[cfg(feature = "grid")]
1141 grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1142 };
1143
1144 assert_eq!(Style::DEFAULT, Style::<DefaultCheapStr>::default());
1145 assert_eq!(Style::DEFAULT, old_defaults);
1146 }
1147
1148 // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes
1149 // and to serve as accurate up-to-date documentation on the sizes.
1150 #[test]
1151 fn style_sizes() {
1152 use super::*;
1153 type S = crate::sys::DefaultCheapStr;
1154
1155 fn assert_type_size<T>(expected_size: usize) {
1156 let name = ::core::any::type_name::<T>();
1157 let name = name.replace("taffy::geometry::", "");
1158 let name = name.replace("taffy::style::dimension::", "");
1159 let name = name.replace("taffy::style::alignment::", "");
1160 let name = name.replace("taffy::style::flex::", "");
1161 let name = name.replace("taffy::style::grid::", "");
1162
1163 assert_eq!(
1164 ::core::mem::size_of::<T>(),
1165 expected_size,
1166 "Expected {} for be {} byte(s) but it was {} byte(s)",
1167 name,
1168 expected_size,
1169 ::core::mem::size_of::<T>(),
1170 );
1171 }
1172
1173 // Display and Position
1174 assert_type_size::<Display>(1);
1175 assert_type_size::<BoxSizing>(1);
1176 assert_type_size::<Position>(1);
1177 assert_type_size::<Overflow>(1);
1178
1179 // Dimensions and aggregations of Dimensions
1180 assert_type_size::<f32>(4);
1181 assert_type_size::<LengthPercentage>(8);
1182 assert_type_size::<LengthPercentageAuto>(8);
1183 assert_type_size::<Dimension>(8);
1184 assert_type_size::<Size<LengthPercentage>>(16);
1185 assert_type_size::<Size<LengthPercentageAuto>>(16);
1186 assert_type_size::<Size<Dimension>>(16);
1187 assert_type_size::<Rect<LengthPercentage>>(32);
1188 assert_type_size::<Rect<LengthPercentageAuto>>(32);
1189 assert_type_size::<Rect<Dimension>>(32);
1190
1191 // Alignment
1192 assert_type_size::<AlignContent>(1);
1193 assert_type_size::<AlignItems>(1);
1194 assert_type_size::<Option<AlignItems>>(1);
1195
1196 // Flexbox Container
1197 assert_type_size::<FlexDirection>(1);
1198 assert_type_size::<FlexWrap>(1);
1199
1200 // CSS Grid Container
1201 assert_type_size::<GridAutoFlow>(1);
1202 assert_type_size::<MinTrackSizingFunction>(8);
1203 assert_type_size::<MaxTrackSizingFunction>(8);
1204 assert_type_size::<TrackSizingFunction>(16);
1205 assert_type_size::<Vec<TrackSizingFunction>>(24);
1206 assert_type_size::<Vec<GridTemplateComponent<S>>>(24);
1207
1208 // String-type dependent (String)
1209 assert_type_size::<GridTemplateComponent<String>>(56);
1210 assert_type_size::<GridPlacement<String>>(32);
1211 assert_type_size::<Line<GridPlacement<String>>>(64);
1212 assert_type_size::<Style<String>>(536);
1213
1214 // String-type dependent (Arc<str>)
1215 assert_type_size::<GridTemplateComponent<Arc<str>>>(56);
1216 assert_type_size::<GridPlacement<Arc<str>>>(24);
1217 assert_type_size::<Line<GridPlacement<Arc<str>>>>(48);
1218 assert_type_size::<Style<Arc<str>>>(504);
1219 }
1220}