tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1061HTML 997Markdown 12TOML 83120 Definiciones

⎇ 90ca73fcec69bf4a1b2fdcb21125cf19df393d8a src/style.rs Rust · 706 líneas · 27.1 KB Historia Quién tocó qué crudo

Added unreachable macro to alleged unreachable code rather than using hidden default value (#169) 90ca73fce · Troels Jessen ·

1//! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout
2
3use crate::geometry::{Rect, Size};
4
5/// How [`Nodes`](crate::node::Node) are aligned relative to the cross axis
6///
7/// The default behavior is [`AlignItems::Stretch`].
8///
9/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-items-property)
10#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum AlignItems {
13    /// Items are packed toward the start of the cross axis
14    FlexStart,
15    /// Items are packed toward the end of the cross axis
16    FlexEnd,
17    /// Items are packed along the center of the cross axis
18    Center,
19    /// Items are aligned such as their baselines align
20    Baseline,
21    /// Stretch to fill the container
22    Stretch,
23}
24
25impl Default for AlignItems {
26    fn default() -> Self {
27        Self::Stretch
28    }
29}
30
31/// Overrides the inherited [`AlignItems`] behavior for this node.
32///
33/// The behavior of any child nodes will be controlled by this node's [`AlignItems`] value.
34///
35/// The default behavior is [`AlignSelf::Auto`].
36///
37/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-items-property)
38#[derive(Copy, Clone, PartialEq, Eq, Debug)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub enum AlignSelf {
41    /// Inherits the [`AlignItems`] behavior of the parent
42    Auto,
43    /// Items are packed toward the start of the cross axis
44    FlexStart,
45    /// Items are packed toward the end of the cross axis
46    FlexEnd,
47    /// Items are packed along the center of the cross axis
48    Center,
49    /// Items are aligned such as their baselines align
50    Baseline,
51    /// Distribute items evenly, but stretch them to fill the container
52    Stretch,
53}
54
55impl Default for AlignSelf {
56    fn default() -> Self {
57        Self::Auto
58    }
59}
60
61/// Sets the distribution of space between and around content items along the cross-axis
62///
63/// The default value is [`AlignContent::Stretch`].
64///
65/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-content-property)
66#[derive(Copy, Clone, PartialEq, Eq, Debug)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68pub enum AlignContent {
69    /// Items are packed toward the start of the cross axis
70    FlexStart,
71    /// Items are packed toward the end of the cross axis
72    FlexEnd,
73    /// Items are packed along the center of the cross axis
74    Center,
75    /// Distribute items evenly, but stretch them to fill the container
76    Stretch,
77    /// Distribute items evenly, such that the first and last item are aligned with the edges
78    SpaceBetween,
79    /// Distribute items evenly,
80    /// such that the space between items is the same as the space between the first and last item and the edges
81    SpaceAround,
82}
83
84impl Default for AlignContent {
85    fn default() -> Self {
86        Self::Stretch
87    }
88}
89
90/// Sets the layout used for the children of this node
91///
92/// [`Display::Flex`] is the default value.
93#[derive(Copy, Clone, PartialEq, Eq, Debug)]
94#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
95pub enum Display {
96    /// The children will follow the flexbox layout algorithm
97    Flex,
98    /// The children will not be laid out, and will follow absolute positioning
99    None,
100}
101
102impl Default for Display {
103    fn default() -> Self {
104        Self::Flex
105    }
106}
107
108/// The direction of the flexbox layout main axis.
109///
110/// There are always two perpendicular layout axes: main (or primary) and cross (or secondary).
111/// Adding items will cause them to be positioned adjacent to each other along the main axis.
112/// By varying this value throughout your tree, you can create complex axis-aligned layouts.
113///
114/// Items are always aligned relative to the cross axis, and justified relative to the main axis.
115///
116/// The default behavior is [`FlexDirection::Row`].
117///
118/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-direction-property)
119#[derive(Copy, Clone, PartialEq, Eq, Debug)]
120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121pub enum FlexDirection {
122    /// Defines +x as the main axis
123    ///
124    /// Items will be added from left to right in a row.
125    Row,
126    /// Defines +y as the main axis
127    ///
128    /// Items will be added from top to bottom in a column.
129    Column,
130    /// Defines -x as the main axis
131    ///
132    /// Items will be added from right to left in a row.
133    RowReverse,
134    /// Defines -y as the main axis
135    ///
136    /// Items will be added from bottom to top in a column.
137    ColumnReverse,
138}
139
140impl Default for FlexDirection {
141    fn default() -> Self {
142        Self::Row
143    }
144}
145
146impl FlexDirection {
147    #[inline]
148    /// Is the direction [`FlexDirection::Row`] or [`FlexDirection::RowReverse`]?
149    pub(crate) fn is_row(self) -> bool {
150        matches!(self, Self::Row | Self::RowReverse)
151    }
152
153    #[inline]
154    /// Is the direction [`FlexDirection::Column`] or [`FlexDirection::ColumnReverse`]?
155    pub(crate) fn is_column(self) -> bool {
156        matches!(self, Self::Column | Self::ColumnReverse)
157    }
158
159    #[inline]
160    /// Is the direction [`FlexDirection::RowReverse`] or [`FlexDirection::ColumnReverse`]?
161    pub(crate) fn is_reverse(self) -> bool {
162        matches!(self, Self::RowReverse | Self::ColumnReverse)
163    }
164}
165
166/// Sets the distribution of space between and around content items along the main-axis
167///
168/// The default value is [`JustifyContent::FlexStart`].
169///
170/// [Specification](https://www.w3.org/TR/css-flexbox-1/#justify-content-property)
171#[derive(Copy, Clone, PartialEq, Eq, Debug)]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173pub enum JustifyContent {
174    /// Items are packed toward the start of the main axis
175    FlexStart,
176    /// Items are packed toward the end of the main axis
177    FlexEnd,
178    /// Items are packed along the center of the main axis
179    Center,
180    /// Distribute items evenly, such that the first and last item are aligned with the edges
181    SpaceBetween,
182    /// Distribute items evenly,
183    /// such that the space between items is twice same as the space between the first and last item and the edges
184    SpaceAround,
185    /// Distribute items evenly,
186    /// such that the space between items is the same as the space between the first and last item and the edges
187    SpaceEvenly,
188}
189
190impl Default for JustifyContent {
191    fn default() -> Self {
192        Self::FlexStart
193    }
194}
195
196/// The positioning strategy for this item.
197///
198/// This controls both how the origin is determined for the [`Style::position`] field,
199/// and whether or not the item will be controlled by flexbox's layout algorithm.
200///
201/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
202/// which can be unintuitive.
203///
204/// [`PositionType::Relative`] is the default value, in contrast to the default behavior in CSS.
205#[derive(Copy, Clone, PartialEq, Eq, Debug)]
206#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
207pub enum PositionType {
208    /// The offset is computed relative to the final position given by the layout algorithm.
209    /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
210    Relative,
211    /// The offset is computed relative to this item's closest positioned ancestor, if any.
212    /// Otherwise, it is placed relative to the origin.
213    /// No space is created for the item in the page layout, and its size will not be altered.
214    ///
215    /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
216    Absolute,
217}
218
219impl Default for PositionType {
220    fn default() -> Self {
221        Self::Relative
222    }
223}
224
225/// Controls whether flex items are forced onto one line or can wrap onto multiple lines.
226///
227/// Defaults to [`FlexWrap::NoWrap`]
228///
229/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property)
230#[derive(Copy, Clone, PartialEq, Eq, Debug)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub enum FlexWrap {
233    /// Items will not wrap and stay on a single line
234    NoWrap,
235    /// Items will wrap according to this item's [`FlexDirection`]
236    Wrap,
237    /// Items will wrap in the opposite direction to this item's [`FlexDirection`]
238    WrapReverse,
239}
240
241impl Default for FlexWrap {
242    fn default() -> Self {
243        Self::NoWrap
244    }
245}
246
247/// A unit of linear measurement
248///
249/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`].
250/// The default value is [`Dimension::Undefined`].
251#[derive(Copy, Clone, PartialEq, Debug)]
252#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
253pub enum Dimension {
254    /// The dimension is not given
255    Undefined,
256    /// The dimension should be automatically computed
257    Auto,
258    /// The dimension is stored in [points](https://en.wikipedia.org/wiki/Point_(typography))
259    ///
260    /// Each point is about 0.353 mm in size.
261    Points(f32),
262    /// The dimension is stored in percentage relative to the parent item.
263    Percent(f32),
264}
265
266impl Default for Dimension {
267    fn default() -> Self {
268        Self::Undefined
269    }
270}
271
272impl Dimension {
273    /// Converts the given [`Dimension`] into a concrete value of points
274    pub(crate) fn resolve(self, parent_dim: Option<f32>) -> Option<f32> {
275        match self {
276            Dimension::Points(points) => Some(points),
277            // parent_dim * percent
278            Dimension::Percent(percent) => parent_dim.map(|dim| dim * percent),
279            _ => None,
280        }
281    }
282
283    /// Is this value defined?
284    pub(crate) fn is_defined(self) -> bool {
285        matches!(self, Dimension::Points(_) | Dimension::Percent(_))
286    }
287}
288
289impl Default for Rect<Dimension> {
290    fn default() -> Self {
291        Self { start: Default::default(), end: Default::default(), top: Default::default(), bottom: Default::default() }
292    }
293}
294
295impl Rect<Dimension> {
296    /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `start` and `top`
297    pub fn top_from_points(start: f32, top: f32) -> Rect<Dimension> {
298        Rect { start: Dimension::Points(start), top: Dimension::Points(top), ..Default::default() }
299    }
300
301    /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `end` and `bottom`
302    pub fn bot_from_points(end: f32, bottom: f32) -> Rect<Dimension> {
303        Rect { end: Dimension::Points(end), bottom: Dimension::Points(bottom), ..Default::default() }
304    }
305
306    /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `start` and `top`
307    pub fn top_from_percent(start: f32, top: f32) -> Rect<Dimension> {
308        Rect { start: Dimension::Percent(start), top: Dimension::Percent(top), ..Default::default() }
309    }
310
311    /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `end` and `bottom`
312    pub fn bot_from_percent(end: f32, bottom: f32) -> Rect<Dimension> {
313        Rect { end: Dimension::Percent(end), bottom: Dimension::Percent(bottom), ..Default::default() }
314    }
315}
316
317impl Default for Size<Dimension> {
318    fn default() -> Self {
319        Self { width: Dimension::Auto, height: Dimension::Auto }
320    }
321}
322
323/// The flexbox layout information for a single [`Node`](crate::node::Node).
324///
325/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
326/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
327///
328/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
329/// information about the behavior on the web should transfer directly.
330///
331/// Detailed information about the exact behavior of each of these fields
332/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
333/// The distinction between margin, padding and border is explained well in
334/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
335///
336/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
337#[derive(Copy, Clone, PartialEq, Debug)]
338#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
339#[cfg_attr(feature = "serde", serde(default))]
340pub struct FlexboxLayout {
341    /// What layout strategy should be used?
342    pub display: Display,
343    /// What should the `position` value of this struct use as a base offset?
344    pub position_type: PositionType,
345    /// Which direction does the main axis flow in?
346    pub flex_direction: FlexDirection,
347    /// Should elements wrap, or stay in a single line?
348    pub flex_wrap: FlexWrap,
349    /// How should items be aligned relative to the cross axis?
350    pub align_items: AlignItems,
351    /// Should this item violate the cross axis alignment specified by its parent's [`AlignItems`]?
352    pub align_self: AlignSelf,
353    /// How should content contained within this item be aligned relative to the cross axis?
354    pub align_content: AlignContent,
355    /// How should items be aligned relative to the main axis?
356    pub justify_content: JustifyContent,
357    /// How should the position of this element be tweaked relative to the layout defined?
358    pub position: Rect<Dimension>,
359    /// How large should the margin be on each side?
360    pub margin: Rect<Dimension>,
361    /// How large should the padding be on each side?
362    pub padding: Rect<Dimension>,
363    /// How large should the border be on each side?
364    pub border: Rect<Dimension>,
365    /// The relative rate at which this item grows when it is expanding to fill space
366    ///
367    /// 0.0 is the default value, and this value must be positive.
368    pub flex_grow: f32,
369    /// The relative rate at which this item shrinks when it is contracting to fit into space
370    ///
371    /// 1.0 is the default value, and this value must be positive.
372    pub flex_shrink: f32,
373    /// Sets the initial main axis size of the item
374    pub flex_basis: Dimension,
375    /// Sets the initial size of the item
376    // TODO: why does this exist as distinct from flex_basis? How do they interact?
377    pub size: Size<Dimension>,
378    /// Controls the minimum size of the item
379    pub min_size: Size<Dimension>,
380    /// Controls the maximum size of the item
381    pub max_size: Size<Dimension>,
382    /// Sets the preferred aspect ratio for the item
383    ///
384    /// The ratio is calculated as width divided by height.
385    pub aspect_ratio: Option<f32>,
386}
387
388impl Default for FlexboxLayout {
389    fn default() -> Self {
390        Self {
391            display: Default::default(),
392            position_type: Default::default(),
393            flex_direction: Default::default(),
394            flex_wrap: Default::default(),
395            align_items: Default::default(),
396            align_self: Default::default(),
397            align_content: Default::default(),
398            justify_content: Default::default(),
399            position: Default::default(),
400            margin: Default::default(),
401            padding: Default::default(),
402            border: Default::default(),
403            flex_grow: 0.0,
404            flex_shrink: 1.0,
405            flex_basis: Dimension::Auto,
406            size: Default::default(),
407            min_size: Default::default(),
408            max_size: Default::default(),
409            aspect_ratio: Default::default(),
410        }
411    }
412}
413
414impl FlexboxLayout {
415    /// If the `direction` is row-oriented, the min width. Otherwise the min height
416    pub(crate) fn min_main_size(&self, direction: FlexDirection) -> Dimension {
417        if direction.is_row() {
418            self.min_size.width
419        } else {
420            self.min_size.height
421        }
422    }
423
424    /// If the `direction` is row-oriented, the max width. Otherwise the max height
425    pub(crate) fn max_main_size(&self, direction: FlexDirection) -> Dimension {
426        if direction.is_row() {
427            self.max_size.width
428        } else {
429            self.max_size.height
430        }
431    }
432
433    /// If the `direction` is row-oriented, the margin start. Otherwise the margin top
434    pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> Dimension {
435        if direction.is_row() {
436            self.margin.start
437        } else {
438            self.margin.top
439        }
440    }
441
442    /// If the `direction` is row-oriented, the margin end. Otherwise the margin bottom
443    pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> Dimension {
444        if direction.is_row() {
445            self.margin.end
446        } else {
447            self.margin.bottom
448        }
449    }
450
451    /// If the `direction` is row-oriented, the height. Otherwise the width
452    pub(crate) fn cross_size(&self, direction: FlexDirection) -> Dimension {
453        if direction.is_row() {
454            self.size.height
455        } else {
456            self.size.width
457        }
458    }
459
460    /// If the `direction` is row-oriented, the min height. Otherwise the min width
461    pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> Dimension {
462        if direction.is_row() {
463            self.min_size.height
464        } else {
465            self.min_size.width
466        }
467    }
468
469    /// If the `direction` is row-oriented, the max height. Otherwise the max width
470    pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> Dimension {
471        if direction.is_row() {
472            self.max_size.height
473        } else {
474            self.max_size.width
475        }
476    }
477
478    /// If the `direction` is row-oriented, the margin top. Otherwise the margin start
479    pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> Dimension {
480        if direction.is_row() {
481            self.margin.top
482        } else {
483            self.margin.start
484        }
485    }
486
487    /// If the `direction` is row-oriented, the margin bottom. Otherwise the margin end
488    pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> Dimension {
489        if direction.is_row() {
490            self.margin.bottom
491        } else {
492            self.margin.end
493        }
494    }
495
496    /// Computes the final alignment of this item based on the parent's [`AlignItems`] and this item's [`AlignSelf`]
497    pub(crate) fn align_self(&self, parent: &FlexboxLayout) -> AlignSelf {
498        // FUTURE WARNING: This function should never return AlignSelf::Auto
499        // See #169 https://github.com/DioxusLabs/taffy/pull/169#issuecomment-1157698840
500
501        if self.align_self == AlignSelf::Auto {
502            match parent.align_items {
503                AlignItems::FlexStart => AlignSelf::FlexStart,
504                AlignItems::FlexEnd => AlignSelf::FlexEnd,
505                AlignItems::Center => AlignSelf::Center,
506                AlignItems::Baseline => AlignSelf::Baseline,
507                AlignItems::Stretch => AlignSelf::Stretch,
508            }
509        } else {
510            self.align_self
511        }
512    }
513}
514
515#[cfg(test)]
516mod tests {
517    mod test_resolve_dimensions {
518        use crate::style::Dimension;
519        use rstest::rstest;
520
521        #[rstest]
522        #[case(Dimension::Undefined, None, None)]
523        #[case(Dimension::Undefined, Some(5.0), None)]
524        #[case(Dimension::Undefined, Some(-5.0), None)]
525        #[case(Dimension::Undefined, Some(0.), None)]
526        fn resolve_undefined(#[case] input: Dimension, #[case] parent: Option<f32>, #[case] expected: Option<f32>) {
527            assert_eq!(input.resolve(parent), expected);
528        }
529
530        #[rstest]
531        #[case(Dimension::Auto, None, None)]
532        #[case(Dimension::Auto, Some(5.0), None)]
533        #[case(Dimension::Auto, Some(-5.0), None)]
534        #[case(Dimension::Auto, Some(0.), None)]
535        fn resolve_auto(#[case] input: Dimension, #[case] parent: Option<f32>, #[case] expected: Option<f32>) {
536            assert_eq!(input.resolve(parent), expected);
537        }
538
539        #[rstest]
540        #[case(Dimension::Points(0.), None, Some(0.))]
541        #[case(Dimension::Points(1.), Some(5.0), Some(1.))]
542        #[case(Dimension::Points(-1.), Some(-5.0), Some(-1.))]
543        #[case(Dimension::Points(1.0), Some(0.), Some(1.0))]
544        fn resolve_points(#[case] input: Dimension, #[case] parent: Option<f32>, #[case] expected: Option<f32>) {
545            assert_eq!(input.resolve(parent), expected);
546        }
547
548        #[rstest]
549        #[case(Dimension::Percent(1.0), None, None)]
550        #[case(Dimension::Percent(1.0), Some(5.0), Some(5.0))]
551        #[case(Dimension::Percent(1.0), Some(-5.0), Some(-5.0))]
552        #[case(Dimension::Percent(10.0), Some(5.0), Some(50.0))]
553        fn resolve_percent(#[case] input: Dimension, #[case] parent: Option<f32>, #[case] expected: Option<f32>) {
554            assert_eq!(input.resolve(parent), expected);
555        }
556    }
557
558    mod test_flex_direction {
559        use crate::style::*;
560
561        #[test]
562        fn flex_direction_is_row() {
563            assert_eq!(FlexDirection::Row.is_row(), true);
564            assert_eq!(FlexDirection::RowReverse.is_row(), true);
565            assert_eq!(FlexDirection::Column.is_row(), false);
566            assert_eq!(FlexDirection::ColumnReverse.is_row(), false);
567        }
568
569        #[test]
570        fn flex_direction_is_column() {
571            assert_eq!(FlexDirection::Row.is_column(), false);
572            assert_eq!(FlexDirection::RowReverse.is_column(), false);
573            assert_eq!(FlexDirection::Column.is_column(), true);
574            assert_eq!(FlexDirection::ColumnReverse.is_column(), true);
575        }
576
577        #[test]
578        fn flex_direction_is_reverse() {
579            assert_eq!(FlexDirection::Row.is_reverse(), false);
580            assert_eq!(FlexDirection::RowReverse.is_reverse(), true);
581            assert_eq!(FlexDirection::Column.is_reverse(), false);
582            assert_eq!(FlexDirection::ColumnReverse.is_reverse(), true);
583        }
584    }
585
586    mod test_flexbox_layout {
587        use crate::style::*;
588
589        fn layout_from_align_items(align: AlignItems) -> FlexboxLayout {
590            FlexboxLayout { align_items: align, ..Default::default() }
591        }
592
593        fn layout_from_align_self(align: AlignSelf) -> FlexboxLayout {
594            FlexboxLayout { align_self: align, ..Default::default() }
595        }
596
597        #[test]
598        fn flexbox_layout_min_main_size() {
599            let layout = FlexboxLayout { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
600            assert_eq!(layout.min_main_size(FlexDirection::Row), Dimension::Points(1.0));
601            assert_eq!(layout.min_main_size(FlexDirection::Column), Dimension::Points(2.0));
602        }
603
604        #[test]
605        fn flexbox_layout_max_main_size() {
606            let layout = FlexboxLayout { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
607            assert_eq!(layout.max_main_size(FlexDirection::Row), Dimension::Points(1.0));
608            assert_eq!(layout.max_main_size(FlexDirection::Column), Dimension::Points(2.0));
609        }
610
611        #[test]
612        fn flexbox_layout_main_margin_start() {
613            let layout = FlexboxLayout { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
614            assert_eq!(layout.main_margin_start(FlexDirection::Row), Dimension::Points(2.0));
615            assert_eq!(layout.main_margin_start(FlexDirection::Column), Dimension::Points(1.0));
616        }
617
618        #[test]
619        fn flexbox_layout_main_margin_end() {
620            let layout = FlexboxLayout { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
621            assert_eq!(layout.main_margin_end(FlexDirection::Row), Dimension::Points(2.0));
622            assert_eq!(layout.main_margin_end(FlexDirection::Column), Dimension::Points(1.0));
623        }
624
625        #[test]
626        fn flexbox_layout_cross_size() {
627            let layout = FlexboxLayout { size: Size::from_points(1.0, 2.0), ..Default::default() };
628            assert_eq!(layout.cross_size(FlexDirection::Row), Dimension::Points(2.0));
629            assert_eq!(layout.cross_size(FlexDirection::Column), Dimension::Points(1.0));
630        }
631
632        #[test]
633        fn flexbox_layout_min_cross_size() {
634            let layout = FlexboxLayout { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
635            assert_eq!(layout.min_cross_size(FlexDirection::Row), Dimension::Points(2.0));
636            assert_eq!(layout.min_cross_size(FlexDirection::Column), Dimension::Points(1.0));
637        }
638
639        #[test]
640        fn flexbox_layout_max_cross_size() {
641            let layout = FlexboxLayout { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
642            assert_eq!(layout.max_cross_size(FlexDirection::Row), Dimension::Points(2.0));
643            assert_eq!(layout.max_cross_size(FlexDirection::Column), Dimension::Points(1.0));
644        }
645
646        #[test]
647        fn flexbox_layout_cross_margin_start() {
648            let layout = FlexboxLayout { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
649            assert_eq!(layout.cross_margin_start(FlexDirection::Row), Dimension::Points(1.0));
650            assert_eq!(layout.cross_margin_start(FlexDirection::Column), Dimension::Points(2.0));
651        }
652
653        #[test]
654        fn flexbox_layout_cross_margin_end() {
655            let layout = FlexboxLayout { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
656            assert_eq!(layout.cross_margin_end(FlexDirection::Row), Dimension::Points(1.0));
657            assert_eq!(layout.cross_margin_end(FlexDirection::Column), Dimension::Points(2.0));
658        }
659
660        #[test]
661        fn flexbox_layout_align_self_auto() {
662            let parent = layout_from_align_items(AlignItems::FlexStart);
663            let layout = layout_from_align_self(AlignSelf::Auto);
664            assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
665
666            let parent = layout_from_align_items(AlignItems::FlexEnd);
667            let layout = layout_from_align_self(AlignSelf::Auto);
668            assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
669
670            let parent = layout_from_align_items(AlignItems::Center);
671            let layout = layout_from_align_self(AlignSelf::Auto);
672            assert_eq!(layout.align_self(&parent), AlignSelf::Center);
673
674            let parent = layout_from_align_items(AlignItems::Baseline);
675            let layout = layout_from_align_self(AlignSelf::Auto);
676            assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
677
678            let parent = layout_from_align_items(AlignItems::Stretch);
679            let layout = layout_from_align_self(AlignSelf::Auto);
680            assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
681        }
682
683        #[test]
684        fn align_self() {
685            let parent = layout_from_align_items(AlignItems::FlexEnd);
686            let layout = layout_from_align_self(AlignSelf::FlexStart);
687            assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
688
689            let parent = layout_from_align_items(AlignItems::FlexStart);
690            let layout = layout_from_align_self(AlignSelf::FlexEnd);
691            assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
692
693            let parent = layout_from_align_items(AlignItems::FlexStart);
694            let layout = layout_from_align_self(AlignSelf::Center);
695            assert_eq!(layout.align_self(&parent), AlignSelf::Center);
696
697            let parent = layout_from_align_items(AlignItems::FlexStart);
698            let layout = layout_from_align_self(AlignSelf::Baseline);
699            assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
700
701            let parent = layout_from_align_items(AlignItems::FlexStart);
702            let layout = layout_from_align_self(AlignSelf::Stretch);
703            assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
704        }
705    }
706}