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