diff --git a/CHANGELOG.md b/CHANGELOG.md index d5670d605..d10e64e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### Added +- Support for `flex-wrap: balance` and the `flex-line-count` property from [CSS Flexbox Level 2](https://drafts.csswg.org/css-flexbox-2/#balance-values), gated behind a new on-by-default `flexbox_balance` cargo feature (which depends on `flexbox`): + - `FlexWrap` gains `Balance` and `BalanceReverse` variants, and its CSS parser accepts the multi-keyword grammar `nowrap | [ wrap | wrap-reverse ] || balance`. When balancing, items are collected into flex lines such that the largest line is as small as possible (minimising the sum of squares of each line's free space), rather than greedily filling each line + - `Style::flex_line_count` (and a corresponding `FlexboxContainerStyle::flex_line_count` trait method) specifies the minimum number of lines to balance items into (default `1`). When it is greater than 1 on any multi-line container (`wrap`, `wrap-reverse`, `balance` or `balance-reverse`), definite cross-axis available space for measuring items is divided between the requested number of lines (after subtracting cross-axis gaps), per the [CSSWG resolution](https://github.com/w3c/csswg-drafts/issues/13414) + - `Dimension` (used for `size`) now supports the sizing keywords `min-content`, `max-content`, `fit-content`, `fit-content()` and `stretch` via new constructors (`Dimension::min_content()`, `Dimension::max_content()`, `Dimension::fit_content()`, `Dimension::fit_content_px()`, `Dimension::fit_content_percent()`, `Dimension::stretch()`), new `CompactLength::FIT_CONTENT_KEYWORD_TAG`/`CompactLength::STRETCH_TAG` representations, and CSS parsing support. These keywords are resolved: - In block layout: for the widths of in-flow children and floats - In flexbox layout: for the main-axis size when determining an item's flex base size, for the cross-axis size when determining an item's hypothetical cross size, and for `flex-basis` (where `stretch` resolves to the stretch-fit main size and the other keywords determine the sizing constraint the item is measured under when computing its flex base size) diff --git a/Cargo.toml b/Cargo.toml index 6a23e712c..7b145f688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ default = [ "std", "taffy_tree", "flexbox", + "flexbox_balance", "grid", "block_layout", "float_layout", @@ -54,6 +55,8 @@ block_layout = [] float_layout = [] ## Enables the Flexbox layout algorithm. See [`compute_flexbox_layout`](crate::compute_flexbox_layout). flexbox = [] +## Enables support for `flex-wrap: balance` and `flex-line-count` from [CSS Flexbox Level 2](https://drafts.csswg.org/css-flexbox-2/) +flexbox_balance = ["flexbox"] ## Enables the CSS Grid layout algorithm. See [`compute_grid_layout`](crate::compute_grid_layout). grid = ["alloc", "dep:smallvec"] ## Enables calc() values for all layout algorithms diff --git a/benches/src/yoga_helpers.rs b/benches/src/yoga_helpers.rs index 935374e6a..dc520c5f3 100644 --- a/benches/src/yoga_helpers.rs +++ b/benches/src/yoga_helpers.rs @@ -259,6 +259,9 @@ fn apply_taffy_style(node: &mut yg::Node, style: &tf::Style) { tf::FlexWrap::NoWrap => yg::Wrap::NoWrap, tf::FlexWrap::Wrap => yg::Wrap::Wrap, tf::FlexWrap::WrapReverse => yg::Wrap::WrapReverse, + // Yoga has no equivalent of `flex-wrap: balance` + tf::FlexWrap::Balance => yg::Wrap::Wrap, + tf::FlexWrap::BalanceReverse => yg::Wrap::WrapReverse, }); node.set_flex_basis(into_yg_units(style.flex_basis)); node.set_flex_grow(style.flex_grow); diff --git a/scripts/gentest/src/main.rs b/scripts/gentest/src/main.rs index 853c8e45d..6a5c5b58c 100644 --- a/scripts/gentest/src/main.rs +++ b/scripts/gentest/src/main.rs @@ -127,6 +127,9 @@ async fn main() { if name.starts_with("grid") { writeln!(&mut mod_file, r#"#[cfg(feature = "grid")]"#).unwrap(); } + if name.starts_with("balance") { + writeln!(&mut mod_file, r#"#[cfg(feature = "flexbox_balance")]"#).unwrap(); + } writeln!( &mut mod_file, "#[test] @@ -650,6 +653,7 @@ fn generate_node(w: &mut XmlWriter, node: &Value) { maybe_write(w, "clear", get_str_attr(&style["clear"], None)); maybe_write(w, "flex-direction", get_str_attr(&style["flexDirection"], Some("row"))); maybe_write(w, "flex-wrap", get_str_attr(&style["flexWrap"], Some("nowrap"))); + maybe_write(w, "flex-line-count", get_num_attr(&style["flexLineCount"], Some(1.0))); maybe_write(w, "overflow-x", get_str_attr(&style["overflowX"], Some("visible"))); maybe_write(w, "overflow-y", get_str_attr(&style["overflowY"], Some("visible"))); diff --git a/scripts/gentest/test_helper.js b/scripts/gentest/test_helper.js index 14807073e..6fad0d9f8 100644 --- a/scripts/gentest/test_helper.js +++ b/scripts/gentest/test_helper.js @@ -228,6 +228,7 @@ function describeElement(e) { flexDirection: parseEnum(e.style.flexDirection), flexWrap: parseEnum(e.style.flexWrap), + flexLineCount: parseNumber(e.style.flexLineCount), overflowX: parseEnum(e.style.overflowX), overflowY: parseEnum(e.style.overflowY), scrollbarWidth: getScrollBarWidth(), diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index 7cc714637..d42f4400f 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -2,15 +2,15 @@ use crate::compute::common::alignment::{compute_alignment_offset, resolve_self_alignment_safety}; use crate::geometry::{Line, Point, Rect, Size}; use crate::style::{ - AlignContent, AlignContentKeyword, AlignItems, AlignItemsKeyword, AlignSelf, AvailableSpace, FlexWrap, - JustifyContent, LengthPercentageAuto, Overflow, Position, + AlignContent, AlignContentKeyword, AlignItems, AlignItemsKeyword, AlignSelf, AvailableSpace, JustifyContent, + LengthPercentageAuto, Overflow, Position, }; use crate::style::{CoreStyle, FlexDirection, FlexboxContainerStyle, FlexboxItemStyle}; use crate::style_helpers::{TaffyMaxContent, TaffyMinContent}; use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode}; use crate::tree::{LayoutFlexboxContainer, LayoutPartialTreeExt, NodeId}; use crate::util::debug::debug_log; -use crate::util::sys::{f32_max, new_vec_with_capacity, Vec}; +use crate::util::sys::{f32_max, f32_min, new_vec_with_capacity, Vec}; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; use crate::{BoxGenerationMode, BoxSizing, Dimension, Direction, RequestedAxis}; @@ -138,6 +138,13 @@ struct AlgoConstants { is_wrap: bool, /// Is the wrap direction inverted is_wrap_reverse: bool, + /// Are items balanced across lines (`flex-wrap: balance`)? + #[cfg(feature = "flexbox_balance")] + is_balance: bool, + /// The requested minimum number of lines (`flex-line-count`). `Some` for every + /// multi-line container, `None` for `nowrap`. + #[cfg(feature = "flexbox_balance")] + line_count: Option, /// The item's min_size style min_size: Size>, @@ -182,6 +189,24 @@ struct AlgoConstants { inner_container_size: Size, } +impl AlgoConstants { + /// When a multi-line container requests a minimum number of lines (`flex-line-count`), + /// definite cross-axis available space for measuring items is divided between the requested + /// number of lines (after subtracting the cross-axis gaps between them). + /// See + #[inline] + fn divided_cross_space(&self, cross_available_space: f32) -> f32 { + #[cfg(feature = "flexbox_balance")] + if let Some(line_count) = self.line_count { + if line_count > 1 { + let line_count = line_count as f32; + return (cross_available_space - (line_count - 1.0) * self.gap.cross(self.dir)) / line_count; + } + } + cross_available_space + } +} + /// Computes the layout of a box according to the flexbox algorithm pub fn compute_flexbox_layout( tree: &mut impl LayoutFlexboxContainer, @@ -316,6 +341,13 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp // 5. Collect flex items into flex lines. debug_log!("collect_flex_lines"); + #[cfg(feature = "flexbox_balance")] + let mut flex_lines = if constants.is_balance { + collect_balanced_flex_lines(&constants, available_space, &mut flex_items) + } else { + collect_flex_lines(&constants, available_space, &mut flex_items) + }; + #[cfg(not(feature = "flexbox_balance"))] let mut flex_lines = collect_flex_lines(&constants, available_space, &mut flex_items); // If container size is undefined, determine the container's main size @@ -474,8 +506,13 @@ fn compute_constants( let dir = style.flex_direction(); let is_row = dir.is_row(); let is_column = dir.is_column(); - let is_wrap = matches!(style.flex_wrap(), FlexWrap::Wrap | FlexWrap::WrapReverse); - let is_wrap_reverse = style.flex_wrap() == FlexWrap::WrapReverse; + let flex_wrap = style.flex_wrap(); + let is_wrap = flex_wrap.is_multi_line(); + let is_wrap_reverse = flex_wrap.is_reverse(); + #[cfg(feature = "flexbox_balance")] + let is_balance = flex_wrap.is_balance(); + #[cfg(feature = "flexbox_balance")] + let line_count = if is_wrap { Some(style.flex_line_count().max(1)) } else { None }; let aspect_ratio = style.aspect_ratio(); let margin = style.margin().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis)); @@ -522,6 +559,10 @@ fn compute_constants( is_column, is_wrap, is_wrap_reverse, + #[cfg(feature = "flexbox_balance")] + is_balance, + #[cfg(feature = "flexbox_balance")] + line_count, min_size: style .min_size() .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis)) @@ -741,7 +782,9 @@ fn determine_flex_base_size( // Clamp available space by min- and max- size let cross_axis_available_space: AvailableSpace = match available_space.cross(dir) { AvailableSpace::Definite(val) => AvailableSpace::Definite( - cross_axis_parent_size.unwrap_or(val).maybe_clamp(child_min_cross, child_max_cross), + constants + .divided_cross_space(cross_axis_parent_size.unwrap_or(val)) + .maybe_clamp(child_min_cross, child_max_cross), ), AvailableSpace::MinContent => match child_min_cross { Some(min) => AvailableSpace::Definite(min), @@ -1076,6 +1119,72 @@ fn collect_flex_lines<'a>( } } +/// Collect flex items into balanced flex lines (`flex-wrap: balance`), such that the largest +/// line is as small as possible. +/// +/// See +#[cfg(feature = "flexbox_balance")] +fn collect_balanced_flex_lines<'a>( + constants: &AlgoConstants, + available_space: Size, + flex_items: &'a mut [FlexItem], +) -> Vec> { + if flex_items.is_empty() { + return new_vec_with_capacity(0); + } + + // If the container's known main size is derived from its own content (and is thus indefinite) + // then items are balanced without a size limit, matching how the container was sized under a + // min/max-content constraint. + let main_axis_available_space = if constants.known_main_size_is_definite { + match constants.max_size.main(constants.dir) { + Some(max_size) => AvailableSpace::Definite({ + let available = available_space.main(constants.dir).into_option().unwrap_or(max_size); + // If the container's main size is not definite then it is at most the max main size, + // so the max size (and not the available space) is the limit that items wrap against. + let available = if constants.has_definite_main_size { available } else { available.min(max_size) }; + available.maybe_max(constants.min_size.main(constants.dir)) + }), + None => available_space.main(constants.dir), + } + } else { + AvailableSpace::MaxContent + }; + + // If we're sizing under a min-content constraint then we take every possible wrapping + // opportunity and place each item in its own line, the same as greedy wrapping (the + // min-content main size of a multi-line container is the size of its largest item) + if main_axis_available_space == AvailableSpace::MinContent { + let mut lines = new_vec_with_capacity(flex_items.len()); + let mut items = &mut flex_items[..]; + while !items.is_empty() { + let (line_items, rest) = items.split_at_mut(1); + lines.push(FlexLine { items: line_items, cross_size: 0.0, offset_cross: 0.0 }); + items = rest; + } + return lines; + } + + let line_break_size = main_axis_available_space.into_option().unwrap_or(f32::INFINITY); + let min_line_count = constants.line_count.unwrap_or(1) as usize; + let item_counts = balance::balanced_line_item_counts( + flex_items.iter().map(|item| item.hypothetical_outer_size.main(constants.dir)), + line_break_size, + constants.gap.main(constants.dir), + min_line_count, + ); + + let mut lines = new_vec_with_capacity(item_counts.len()); + let mut items = &mut flex_items[..]; + for count in item_counts { + let (line_items, rest) = items.split_at_mut(count); + lines.push(FlexLine { items: line_items, cross_size: 0.0, offset_cross: 0.0 }); + items = rest; + } + debug_assert!(items.is_empty()); + lines +} + /// Compute whether each of an item's known dimensions should be treated as definite when performing /// layout on the item. An item's post-flexing main size is only treated as definite if the container /// has a definite main size or the item's used flex basis is definite. @@ -1099,25 +1208,59 @@ fn determine_container_main_size( let outer_main_size: f32 = constants.node_outer_size.main(constants.dir).unwrap_or_else(|| { match available_space.main(dir) { AvailableSpace::Definite(main_axis_available_space) => { + let main_axis_gap = constants.gap.main(constants.dir); + let item_main_length = |child: &FlexItem| { + let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir); + (child.flex_basis.maybe_max(child.min_size.main(constants.dir)) + + child.margin.main_axis_sum(constants.dir)) + .max(padding_border_sum) + }; let longest_line_length: f32 = lines .iter() .map(|line| { - let line_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len()); - let total_target_size = line - .items - .iter() - .map(|child| { - let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir); - (child.flex_basis.maybe_max(child.min_size.main(constants.dir)) - + child.margin.main_axis_sum(constants.dir)) - .max(padding_border_sum) - }) - .sum::(); + let line_main_axis_gap = sum_axis_gaps(main_axis_gap, line.items.len()); + let total_target_size = line.items.iter().map(item_main_length).sum::(); total_target_size + line_main_axis_gap }) .max_by(|a, b| a.total_cmp(b)) .unwrap_or(0.0); let size = longest_line_length + main_content_box_inset; + + // A balanced container can produce multiple lines that all fit within the + // available space (via `flex-line-count`), in which case fit-content sizing + // uses its max-content size: the longest line when items are balanced across + // the minimum line count without a size limit. + #[cfg(feature = "flexbox_balance")] + if constants.is_balance { + let min_line_count = constants.line_count.unwrap_or(1); + let item_count = lines.iter().map(|line| line.items.len()).sum::(); + if item_count == 0 { + return size; + } + let mut item_lengths: Vec = new_vec_with_capacity(item_count); + for line in lines.iter() { + for child in line.items.iter() { + item_lengths.push(item_main_length(child)); + } + } + let item_counts = balance::balanced_line_item_counts( + item_lengths.iter().copied(), + f32::INFINITY, + main_axis_gap, + min_line_count.max(1) as usize, + ); + let mut widest_line_length: f32 = 0.0; + let mut index = 0; + for count in item_counts { + let line_length: f32 = item_lengths[index..index + count].iter().sum::() + + sum_axis_gaps(main_axis_gap, count); + widest_line_length = widest_line_length.max(line_length); + index += count; + } + let max_content_size = widest_line_length + main_content_box_inset; + return f32_max(size, f32_min(max_content_size, main_axis_available_space)); + } + if lines.len() > 1 { f32_max(size, main_axis_available_space) } else { @@ -1199,7 +1342,9 @@ fn determine_container_main_size( let child_max_cross = item.max_size.cross(dir).maybe_add(cross_axis_margin_sum); let cross_axis_available_space: AvailableSpace = available_space .cross(dir) - .map_definite_value(|val| cross_axis_parent_size.unwrap_or(val)) + .map_definite_value(|val| { + constants.divided_cross_space(cross_axis_parent_size.unwrap_or(val)) + }) .maybe_clamp(child_min_cross, child_max_cross); let child_available_space = available_space.with_cross(dir, cross_axis_available_space); @@ -1548,6 +1693,7 @@ fn determine_hypothetical_cross_size( let child_available_cross = available_space .cross(constants.dir) + .map_definite_value(|val| constants.divided_cross_space(val)) .maybe_clamp(transferred_min_cross, transferred_max_cross) .maybe_max(padding_border_sum); @@ -1555,8 +1701,11 @@ fn determine_hypothetical_cross_size( // fit-content(...)) determines the available space constraint the item is measured under. // The `stretch` keyword is not resolved here: it stretches to the flex line, which is // handled in `determine_used_cross_size` - let cross_stretch_size = - constants.node_inner_size.cross(constants.dir).maybe_sub(child.margin.cross_axis_sum(constants.dir)); + let cross_stretch_size = constants + .node_inner_size + .cross(constants.dir) + .map(|val| constants.divided_cross_space(val)) + .maybe_sub(child.margin.cross_axis_sum(constants.dir)); let child_available_cross = match resolve_sizing_keyword( child.size_style.cross(constants.dir), cross_stretch_size, @@ -2823,3 +2972,530 @@ fn sum_axis_gaps(gap: f32, num_items: usize) -> f32 { gap * (num_items - 1) as f32 } } + +/// Balanced line breaking for `flex-wrap: balance`. +/// +/// Implements the balancing algorithm from the CSS Flexbox Level 2 draft +/// (). Items are divided into exactly +/// `line_count` contiguous sequences (lines), where `line_count` is the number of lines that +/// greedy line breaking would produce (with item sizes floored at zero), raised to the minimum +/// flex line count (`flex-line-count`, clamped to the number of items), such that: +/// +/// - every line holds at least one item; +/// - no line's size exceeds the container's inner main size, unless the line holds a single +/// (overflowing) item; +/// - a zero-sized item is assigned to the end of the preceding line rather than the beginning +/// of a line, unless no valid division can glue it there: because extending the preceding +/// line through the item would make it exceed the container's inner main size (which covers +/// a preceding single overflowing item), or because gluing leaves the remaining lines +/// without a valid division of the remaining items; +/// - calling the difference between a line's size and the container's inner main size the +/// line's *error*, the sum of the squared errors of all lines is minimized; +/// - ties are broken by assigning the most items to the first line, then the most items to the +/// second line, and so on. +/// +/// Because every division has the same line count, total item size, and total gap size, +/// minimizing the sum of squared errors is equivalent to minimizing the sum of squared *line +/// sizes*, which is what is actually computed: it needs no target size, so an indefinite +/// (infinite) container size needs no special handling — no line overflows, and the +/// minimization equalizes the line sizes. All arithmetic uses `f64`: finite `f32` sizes +/// convert exactly, and the squares and sums involved are far from `f64`'s limits, so +/// equally-balanced divisions compare equal and are resolved by the tie-break rather than by +/// rounding noise. +/// +/// The minimization is a dynamic program over (line count, first item of suffix) accelerated +/// with the divide-and-conquer optimization, running in `O(line_count * item_count * +/// log(item_count))` time; the naive `O(line_count * item_count²)` dynamic program is kept as +/// a test oracle. +#[cfg(feature = "flexbox_balance")] +mod balance { + use crate::util::sys::{new_vec_with_capacity, Vec}; + + /// Score assigned to divisions that violate the line size constraint + const INFEASIBLE: f64 = f64::INFINITY; + + /// Convert an item size in pixels to an `f64`, flooring negative sizes at zero. (An + /// infinite size is clamped to the largest finite `f32` so that sums stay meaningful.) + fn to_size(value: f32) -> f64 { + (value as f64).clamp(0.0, f32::MAX as f64) + } + + /// Line sizing shared by the scoring and readback phases + struct LineSizes { + /// Per item, the prefix sum of the item sizes through it (each item also contributes + /// one trailing gap, so the size of the line holding items `start..=end` is + /// `sums[end].0 - sums[start - 1].0 - gap_between_items`), paired with whether the + /// item's (floored) size is zero + sums: Vec<(f64, bool)>, + /// The size of the gap between adjacent items on a line + gap_between_items: f64, + /// The container's inner main size, which lines may not exceed (unless they hold a + /// single item) + limit: f64, + } + + impl LineSizes { + /// The total number of items + fn item_count(&self) -> usize { + self.sums.len() + } + + /// Whether the item at `index` has a (floored) size of zero + fn is_zero_item(&self, index: usize) -> bool { + self.sums[index].1 + } + + /// The size of the line holding items `start..=end` + fn line_size(&self, start: usize, end: usize) -> f64 { + let start_sum = if start == 0 { 0.0 } else { self.sums[start - 1].0 }; + self.sums[end].0 - start_sum - self.gap_between_items + } + + /// The squared size of the line holding items `start..=end`, or [`INFEASIBLE`] for a + /// line of more than one item exceeding the limit + fn line_cost(&self, start: usize, end: usize) -> f64 { + let size = self.line_size(start, end); + if end > start && size > self.limit { + return INFEASIBLE; + } + size * size + } + + /// For every suffix of the items, the number of lines that greedy line breaking + /// produces for it: each line collects consecutive items until the next item no longer + /// fits, and if even the first item of a line doesn't fit, that line takes just the one + /// (overflowing) item. (The entry for the empty suffix is zero.) + /// + /// This is also the *fewest* lines each suffix can validly be divided into, and a + /// suffix can validly be divided into any number of lines from that count up to its + /// item count: dividing at greedy line ends never violates the zero-sized-item rule + /// (a line that can hold no more of the following items can never glue them), and + /// from any in-range line count the same holds with line ends capped to leave one + /// item per remaining line. + fn suffix_greedy_line_counts(&self) -> Vec { + let item_count = self.item_count(); + let mut counts: Vec = new_vec_with_capacity(item_count + 1); + counts.extend(core::iter::repeat(0).take(item_count + 1)); + // The (exclusive) end of the greedy first line of the suffix, which only moves + // down as the suffix grows leftwards since lines starting earlier are larger + let mut line_end = item_count; + for start in (0..item_count).rev() { + while line_end > start + 1 && self.line_size(start, line_end - 1) > self.limit { + line_end -= 1; + } + counts[start] = 1 + counts[line_end]; + } + counts + } + + /// For every `start`, the largest `end` such that the line holding items `start..=end` + /// does not exceed the limit (or `start` itself if even that one item overflows) + fn fit_ends(&self) -> Vec { + let item_count = self.item_count(); + let mut fit_ends: Vec = new_vec_with_capacity(item_count); + // Lines starting later are smaller, so the fit end only moves up + let mut fit_end = 0; + for start in 0..item_count { + if fit_end < start { + fit_end = start; + } + while fit_end + 1 < item_count && self.line_size(start, fit_end + 1) <= self.limit { + fit_end += 1; + } + fit_ends.push(fit_end as u32); + } + fit_ends + } + } + + /// One row of the balancing dynamic program: divisions of item suffixes into exactly + /// `lines` lines + struct Row<'a> { + /// The line sizing for the items being divided + sizes: &'a LineSizes, + /// See [`LineSizes::fit_ends`] + fit_ends: &'a [u32], + /// The previous row: `prev[start]` is the minimum score of any valid division of items + /// `start..` into exactly `lines - 1` lines ([`INFEASIBLE`] if there is none) + prev: &'a [f64], + /// The line ends that precede a non-zero item, in ascending order and capped to + /// `max_end`. Line ends preceding a *zero* item are constrained by the + /// zero-sized-item rule and handled separately: for a first line starting at `start`, + /// the only end preceding a zero item that can be part of a valid division is + /// `min(fit_ends[start], max_end)` — the line extended as far as the limit and the + /// remaining lines' one-item-each budget allow. Ending earlier is forbidden by the + /// rule (the zero item could be glued: the extended line fits and, per + /// [`LineSizes::suffix_greedy_line_counts`], what remains after even the longest glued + /// line divides validly into the remaining lines whenever what remains after the + /// shorter line does, which it must for the division to be feasible at all), and + /// ending later exceeds the limit on a line of more than one item. + nonzero_ends: &'a [u32], + /// The largest possible end of the first line: the remaining `lines - 1` lines need + /// one item each + max_end: usize, + } + + /// Compute `cur[start]` and `opts[start]` for `start` in `start_lo..=start_hi`, where + /// `cur[start]` is the minimum over valid ends `end` of + /// `row.sizes.line_cost(start, end) + row.prev[end + 1]` and `opts[start]` is the largest + /// `end` achieving that minimum. Ends preceding a non-zero item are minimized over + /// `row.nonzero_ends[col_lo..col_hi]`; the (at most one) end preceding a zero item allowed + /// by the zero-sized-item rule is merged in afterwards. + /// + /// Uses the divide-and-conquer dynamic programming optimization: over the ends preceding + /// non-zero items, the cost function satisfies the concave quadrangle inequality (it is + /// the square of a quantity that increases in `end` and decreases in `start`, plus a term + /// depending on `end` alone, with infeasibility monotone in line length), so the largest + /// minimizing end is non-decreasing in `start`. Solving the middle `start` therefore + /// splits the end range in two, and each recursion level scans each candidate end a + /// bounded number of times. (The ends constrained by the zero-sized-item rule are *not* + /// monotone this way, which is why they are excluded from the scan and merged in + /// separately.) + fn fill_row( + row: &Row, + cur: &mut [f64], + opts: &mut [u32], + start_lo: usize, + start_hi: usize, + col_lo: usize, + col_hi: usize, + ) { + if start_lo > start_hi { + return; + } + let start = start_lo + (start_hi - start_lo) / 2; + + // Minimize over the in-range ends preceding a non-zero item, starting from `start` + // (the line must hold at least one item) + let first_col = col_lo + row.nonzero_ends[col_lo..col_hi].partition_point(|&end| (end as usize) < start); + let mut min_cost = INFEASIBLE; + let mut min_col = None; + for col in first_col..col_hi { + let end = row.nonzero_ends[col] as usize; + let line_cost = row.sizes.line_cost(start, end); + if line_cost == INFEASIBLE { + // Every longer line also exceeds the limit + break; + } + let cost = line_cost + row.prev[end + 1]; + // `<=` keeps the *largest* minimizing end, assigning the most items to the + // earliest lines as the tie-break requires + if cost <= min_cost { + min_cost = cost; + min_col = Some(col); + } + } + + // Merge the single end preceding a zero item that the zero-sized-item rule allows + let mut min_end = min_col.map(|col| row.nonzero_ends[col] as usize); + let zero_end = (row.fit_ends[start] as usize).min(row.max_end); + if row.sizes.is_zero_item(zero_end + 1) { + let cost = row.sizes.line_cost(start, zero_end) + row.prev[zero_end + 1]; + if cost < min_cost || (cost == min_cost && min_end.map_or(true, |end| end < zero_end)) { + min_cost = cost; + min_end = Some(zero_end); + } + } + + // Infeasible states are excluded from the range by the caller, and every feasible + // state has a valid transition (see [`LineSizes::suffix_greedy_line_counts`]) + debug_assert!(min_cost.is_finite()); + cur[start] = min_cost; + opts[start] = min_end.unwrap_or(start) as u32; + + // The zero-rule end is excluded from the narrowing: only the non-zero ends' minima + // are monotone + if start > start_lo { + let col_hi = min_col.map_or(col_hi, |col| col + 1); + fill_row(row, cur, opts, start_lo, start - 1, col_lo, col_hi); + } + if start < start_hi { + let col_lo = min_col.unwrap_or(first_col); + fill_row(row, cur, opts, start + 1, start_hi, col_lo, col_hi); + } + } + + /// Determine the number of items on each line that balances items across lines, such that + /// the largest line is as small as possible, with a minimum of `min_line_count` lines + /// (or one line per item if there are fewer items). + /// + /// `item_sizes` must be non-empty. The returned line item counts are all non-zero and sum to + /// the number of items. + /// + /// Runs in `O(line_count * item_count * log(item_count))` time using + /// `O(line_count * item_count)` transient memory. + pub(super) fn balanced_line_item_counts( + item_sizes: impl ExactSizeIterator, + line_limit: f32, + gap_between_items: f32, + min_line_count: usize, + ) -> Vec { + let item_count = item_sizes.len(); + debug_assert!(item_count > 0); + let gap_between_items = to_size(gap_between_items); + let limit = line_limit as f64; + + let mut sums: Vec<(f64, bool)> = new_vec_with_capacity(item_count); + let mut sum = 0.0; + for size in item_sizes { + let size = to_size(size); + sum += size + gap_between_items; + sums.push((sum, size == 0.0)); + } + let sizes = LineSizes { sums, gap_between_items, limit }; + + // `suffix_greedy[start]` is the number of lines greedy line breaking produces for items + // `start..`, which is also the *fewest* lines the suffix can validly be divided into + let suffix_greedy = sizes.suffix_greedy_line_counts(); + let line_count = (suffix_greedy[0] as usize).max(min_line_count.clamp(1, item_count)); + + let mut item_counts: Vec = new_vec_with_capacity(line_count); + if line_count == item_count { + // One item per line is the only division (this covers `flex-line-count` of at least + // the item count as well as every item overflowing a line of its own) + item_counts.extend(core::iter::repeat(1).take(item_count)); + return item_counts; + } + + let fit_ends = sizes.fit_ends(); + let mut nonzero_ends: Vec = new_vec_with_capacity(item_count - 1); + for end in 0..item_count - 1 { + if !sizes.is_zero_item(end + 1) { + nonzero_ends.push(end as u32); + } + } + + // `prev[start]` is the minimum total score of any valid division of items `start..` + // into exactly `lines - 1` lines ([`INFEASIBLE`] if there is none), and `cur` is the + // row being computed for `lines` lines: a division into `lines` lines is a first line + // `start..=end` plus a division of `end + 1..` into `lines - 1` lines. + // `opts[(lines - 2) * item_count + start]` records the largest `end` achieving + // `cur[start]`, from which the chosen division is read back. + let mut prev: Vec = new_vec_with_capacity(item_count); + for start in 0..item_count { + prev.push(sizes.line_cost(start, item_count - 1)); + } + let mut cur: Vec = new_vec_with_capacity(item_count); + cur.extend(core::iter::repeat(INFEASIBLE).take(item_count)); + let mut opts: Vec = new_vec_with_capacity((line_count - 1) * item_count); + opts.extend(core::iter::repeat(0).take((line_count - 1) * item_count)); + for lines in 2..=line_count { + // The remaining `lines - 1` lines need one item each, bounding this line's end + let max_end = item_count - lines; + // Starts whose suffix doesn't fit in `lines` lines even with greedy breaking are + // infeasible; they form a prefix (a longer suffix never needs fewer lines), and + // excluding them keeps every state `fill_row` solves feasible + let mut first_start = 0; + while first_start < max_end && suffix_greedy[first_start] as usize > lines { + cur[first_start] = INFEASIBLE; + first_start += 1; + } + let col_hi = nonzero_ends.partition_point(|&end| (end as usize) <= max_end); + let row = Row { sizes: &sizes, fit_ends: &fit_ends, prev: &prev, nonzero_ends: &nonzero_ends, max_end }; + let opts_row = &mut opts[(lines - 2) * item_count..(lines - 1) * item_count]; + fill_row(&row, &mut cur, opts_row, first_start, max_end, 0, col_hi); + core::mem::swap(&mut prev, &mut cur); + } + + // Read the division back out front to back + debug_assert!(prev[0].is_finite()); + let mut start = 0; + for lines in (2..=line_count).rev() { + let end = opts[(lines - 2) * item_count + start] as usize; + item_counts.push(end - start + 1); + start = end + 1; + } + item_counts.push(item_count - start); + item_counts + } + + #[cfg(test)] + mod tests { + use super::*; + + /// The number of lines that greedy line breaking produces: each line collects + /// consecutive items until the next item no longer fits, and if even the first item of + /// a line doesn't fit, that line takes just the one (overflowing) item + fn greedy_line_count(sizes: &LineSizes) -> usize { + let item_count = sizes.item_count(); + let mut line_count = 1; + let mut index = 0; + while index < item_count { + let mut next = index; + while next < item_count && sizes.line_size(index, next) <= sizes.limit { + next += 1; + } + if next == index { + next = index + 1; + } + index = next; + if index < item_count { + line_count += 1; + } + } + line_count + } + + /// The zero-sized-item rule, brute force: a line `start..=end` (of a division of + /// `start..` into `lines` lines) may only end before a zero-sized item if no division + /// that extends the line through the item exists — every extension either exceeds the + /// limit or leaves the remaining items without a valid division into the remaining + /// lines. (`min_errors` rows below `lines` must already be computed.) + fn zero_boundary_valid(sizes: &LineSizes, min_errors: &[f64], lines: usize, start: usize, end: usize) -> bool { + let item_count = sizes.item_count(); + if !sizes.is_zero_item(end + 1) { + return true; + } + for glued_end in end + 1..=item_count - lines { + if sizes.line_size(start, glued_end) > sizes.limit { + break; + } + if min_errors[(lines - 2) * item_count + glued_end + 1].is_finite() { + return false; + } + } + true + } + + /// The naive `O(line_count * item_count²)` dynamic program from the spec, used as a + /// test oracle for the divide-and-conquer optimized implementation + fn naive_line_item_counts( + item_sizes: &[f32], + line_limit: f32, + gap_between_items: f32, + min_line_count: usize, + ) -> Vec { + let item_count = item_sizes.len(); + let gap_between_items = to_size(gap_between_items); + let limit = line_limit as f64; + + let mut sums: Vec<(f64, bool)> = new_vec_with_capacity(item_count); + let mut sum = 0.0; + for size in item_sizes { + let size = to_size(*size); + sum += size + gap_between_items; + sums.push((sum, size == 0.0)); + } + let sizes = LineSizes { sums, gap_between_items, limit }; + + let line_count = greedy_line_count(&sizes).max(min_line_count.clamp(1, item_count)); + + // `min_errors[(lines - 1) * item_count + start]` is the minimum total score of any + // valid division of items `start..` into exactly `lines` lines + let mut min_errors: Vec = new_vec_with_capacity(line_count * item_count); + for start in 0..item_count { + min_errors.push(sizes.line_cost(start, item_count - 1)); + } + for lines in 2..=line_count { + let row = (lines - 1) * item_count; + for start in 0..item_count { + let mut min_error = INFEASIBLE; + let mut end = start; + while end + lines <= item_count { + let line_cost = sizes.line_cost(start, end); + if line_cost == INFEASIBLE { + break; + } + if zero_boundary_valid(&sizes, &min_errors, lines, start, end) { + let error = line_cost + min_errors[row - item_count + end + 1]; + if error < min_error { + min_error = error; + } + } + end += 1; + } + min_errors.push(min_error); + } + } + + // For each line, the *largest* end whose error plus the minimum remaining error + // adds up to the (feasible) minimum is chosen + assert!(min_errors[(line_count - 1) * item_count].is_finite()); + let mut item_counts: Vec = new_vec_with_capacity(line_count); + let mut start = 0; + for lines_after in (0..line_count).rev() { + let target = min_errors[lines_after * item_count + start]; + let mut end = item_count - 1 - lines_after; + loop { + if sizes.line_cost(start, end) != INFEASIBLE + && (lines_after == 0 || zero_boundary_valid(&sizes, &min_errors, lines_after + 1, start, end)) + { + let remaining_error = + if lines_after == 0 { 0.0 } else { min_errors[(lines_after - 1) * item_count + end + 1] }; + if sizes.line_cost(start, end) + remaining_error == target { + break; + } + } + assert!(end > start); + end -= 1; + } + item_counts.push(end - start + 1); + start = end + 1; + } + assert_eq!(start, item_count); + item_counts + } + + #[test] + fn zero_sized_item_rule() { + // The zero item joins the first line even though the gap it brings makes the score + // worse: [70, 0] / [20] has line sizes 80 / 20 (score 6800), while [70] / [0, 20] + // would have line sizes 70 / 30 (score 5800) + let counts = balanced_line_item_counts([70.0, 0.0, 20.0].iter().copied(), 100.0, 10.0, 1); + assert_eq!(counts, [2, 1]); + // The zero item is not glued to a single overflowing item's line + let counts = balanced_line_item_counts([150.0, 0.0, 30.0].iter().copied(), 100.0, 0.0, 1); + assert_eq!(counts, [1, 2]); + // Zero items are glued as far as the requested line count allows + let counts = balanced_line_item_counts([70.0, 0.0, 0.0].iter().copied(), 100.0, 0.0, 2); + assert_eq!(counts, [2, 1]); + } + + #[test] + fn matches_naive_dp() { + // A simple xorshift PRNG so the test is deterministic and dependency-free + let mut state: u64 = 0x243F6A8885A308D3; + let mut rand = move |bound: u32| -> u32 { + state ^= state << 13; + state ^= state >> 7; + state ^= state << 17; + ((state >> 32) as u32) % bound + }; + + for case in 0..5000 { + // Mostly small item counts (quantized sizes maximize ties, exercising the + // tie-break rules), with some larger ones exercising the recursion + let item_count = if case % 20 == 0 { (rand(60) + 1) as usize } else { (rand(15) + 1) as usize }; + let mut item_sizes: Vec = new_vec_with_capacity(item_count); + for _ in 0..item_count { + let size = match rand(8) { + // Frequent zero items exercise the zero-sized-item rule + 0 | 1 => 0.0, + 2 => -10.0, + _ => rand(8) as f32 * 25.0, + }; + item_sizes.push(size); + } + let line_limit = match rand(5) { + 0 => f32::INFINITY, + _ => rand(10) as f32 * 30.0, + }; + let gap_between_items = rand(4) as f32 * 5.0; + let min_line_count = rand(item_count as u32 + 2) as usize; + + let expected = naive_line_item_counts(&item_sizes, line_limit, gap_between_items, min_line_count); + let actual = balanced_line_item_counts( + item_sizes.iter().copied(), + line_limit, + gap_between_items, + min_line_count, + ); + assert_eq!( + actual, expected, + "case {case}: item_sizes={item_sizes:?} line_limit={line_limit} \ + gap_between_items={gap_between_items} min_line_count={min_line_count}" + ); + } + } + } +} diff --git a/src/style/flex.rs b/src/style/flex.rs index e4c7654ad..8a530b4b0 100644 --- a/src/style/flex.rs +++ b/src/style/flex.rs @@ -14,6 +14,15 @@ pub trait FlexboxContainerStyle: CoreStyle { fn flex_wrap(&self) -> FlexWrap { Style::::DEFAULT.flex_wrap } + /// The minimum number of flex lines requested for a multi-line container. When items are + /// balanced ([`FlexWrap::Balance`] or [`FlexWrap::BalanceReverse`]) they are balanced into + /// at least this many lines. For any multi-line container, definite cross-axis available + /// space for measuring items is divided between this many lines. + #[cfg(feature = "flexbox_balance")] + #[inline(always)] + fn flex_line_count(&self) -> u16 { + Style::::DEFAULT.flex_line_count + } /// How large should the gaps between items in a grid or flex container be? #[inline(always)] @@ -83,15 +92,96 @@ pub enum FlexWrap { Wrap, /// Items will wrap in the opposite direction to this item's [`FlexDirection`] WrapReverse, + /// Items will wrap according to this item's [`FlexDirection`], and be balanced across + /// lines such that the largest line is as small as possible + /// + /// [Specification](https://drafts.csswg.org/css-flexbox-2/#balance-values) + #[cfg(feature = "flexbox_balance")] + Balance, + /// Items will wrap in the opposite direction to this item's [`FlexDirection`], and be + /// balanced across lines such that the largest line is as small as possible + /// + /// [Specification](https://drafts.csswg.org/css-flexbox-2/#balance-values) + #[cfg(feature = "flexbox_balance")] + BalanceReverse, } -#[cfg(feature = "parse")] +impl FlexWrap { + /// Is this a wrapping mode (any value other than [`FlexWrap::NoWrap`])? + #[inline] + pub(crate) fn is_multi_line(self) -> bool { + self != Self::NoWrap + } + + /// Do lines stack in the opposite direction to the cross axis? + #[inline] + pub(crate) fn is_reverse(self) -> bool { + match self { + Self::WrapReverse => true, + #[cfg(feature = "flexbox_balance")] + Self::BalanceReverse => true, + _ => false, + } + } + + /// Are items balanced across lines? + #[cfg(feature = "flexbox_balance")] + #[inline] + pub(crate) fn is_balance(self) -> bool { + matches!(self, Self::Balance | Self::BalanceReverse) + } +} + +#[cfg(all(feature = "parse", not(feature = "flexbox_balance")))] crate::util::parse::impl_parse_for_keyword_enum!(FlexWrap, "nowrap" => NoWrap, "wrap" => Wrap, "wrap-reverse" => WrapReverse, ); +#[cfg(all(feature = "parse", feature = "flexbox_balance"))] +impl crate::util::parse::FromCss for FlexWrap { + fn from_css<'i>(input: &mut crate::util::parse::Parser<'i, '_>) -> crate::util::parse::CssParseResult<'i, Self> { + let mut wrap: Option = None; + let mut balance = false; + let mut is_first = true; + loop { + let ident = if is_first { + input.expect_ident()?.clone() + } else { + match input.try_parse(|input| input.expect_ident().cloned()) { + Ok(ident) => ident, + Err(_) => break, + } + }; + let is_valid = cssparser::match_ignore_ascii_case! { &ident, + "nowrap" => { + if is_first { + return Ok(Self::NoWrap); + } + false + }, + "wrap" => wrap.replace(Self::Wrap).is_none(), + "wrap-reverse" => wrap.replace(Self::WrapReverse).is_none(), + "balance" => !core::mem::replace(&mut balance, true), + _ => false, + }; + if !is_valid { + return Err(input.new_unexpected_token_error(crate::util::parse::Token::Ident(ident))); + } + is_first = false; + } + Ok(match (wrap, balance) { + (Some(Self::WrapReverse), true) => Self::BalanceReverse, + (_, true) => Self::Balance, + // At least one keyword is always parsed, so `wrap` must be `Some` if `balance` is false + (wrap, false) => wrap.unwrap_or(Self::NoWrap), + }) + } +} +#[cfg(all(feature = "parse", feature = "flexbox_balance"))] +crate::util::parse::from_str_from_css!(FlexWrap); + /// The direction of the flexbox layout main axis. /// /// There are always two perpendicular layout axes: main (or primary) and cross (or secondary). diff --git a/src/style/mod.rs b/src/style/mod.rs index 962b47bdf..49efff965 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -542,6 +542,14 @@ pub struct Style { /// Should elements wrap, or stay in a single line? #[cfg(feature = "flexbox")] pub flex_wrap: FlexWrap, + /// The minimum number of flex lines requested for a multi-line container. When items are + /// balanced ([`FlexWrap::Balance`] or [`FlexWrap::BalanceReverse`]) they are balanced into + /// at least this many lines. For any multi-line container, definite cross-axis available + /// space for measuring items is divided between this many lines. + /// + /// 1 is the default value, and this value must be at least 1. + #[cfg(feature = "flexbox_balance")] + pub flex_line_count: u16, // Flexbox item properties /// Sets the initial main axis size of the item @@ -642,6 +650,8 @@ impl Style { flex_direction: FlexDirection::Row, #[cfg(feature = "flexbox")] flex_wrap: FlexWrap::NoWrap, + #[cfg(feature = "flexbox_balance")] + flex_line_count: 1, #[cfg(feature = "flexbox")] flex_grow: 0.0, #[cfg(feature = "flexbox")] @@ -896,6 +906,11 @@ impl FlexboxContainerStyle for Style { fn flex_wrap(&self) -> FlexWrap { self.flex_wrap } + #[cfg(feature = "flexbox_balance")] + #[inline(always)] + fn flex_line_count(&self) -> u16 { + self.flex_line_count + } #[inline(always)] fn gap(&self) -> Size { self.gap @@ -924,6 +939,11 @@ impl FlexboxContainerStyle for &'_ T { fn flex_wrap(&self) -> FlexWrap { (*self).flex_wrap() } + #[cfg(feature = "flexbox_balance")] + #[inline(always)] + fn flex_line_count(&self) -> u16 { + (*self).flex_line_count() + } #[inline(always)] fn gap(&self) -> Size { (*self).gap() @@ -1250,6 +1270,8 @@ mod tests { flex_direction: Default::default(), #[cfg(feature = "flexbox")] flex_wrap: Default::default(), + #[cfg(feature = "flexbox_balance")] + flex_line_count: 1, #[cfg(any(feature = "flexbox", feature = "grid"))] align_items: Default::default(), #[cfg(any(feature = "flexbox", feature = "grid"))] diff --git a/test_fixtures/flex/balance_column.html b/test_fixtures/flex/balance_column.html new file mode 100644 index 000000000..4953cda69 --- /dev/null +++ b/test_fixtures/flex/balance_column.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_column_intrinsic_line_count.html b/test_fixtures/flex/balance_column_intrinsic_line_count.html new file mode 100644 index 000000000..be4b00d49 --- /dev/null +++ b/test_fixtures/flex/balance_column_intrinsic_line_count.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_column_line_count_content_measure.html b/test_fixtures/flex/balance_column_line_count_content_measure.html new file mode 100644 index 000000000..2fa25be8d --- /dev/null +++ b/test_fixtures/flex/balance_column_line_count_content_measure.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
XXXXXXXXXX​XXXXXXXXXX
+
XXXXXXXXXX​XXXXXXXXXX
+
XXXXXXXXXX​XXXXXXXXXX
+
+ + + diff --git a/test_fixtures/flex/balance_column_line_count_cross_space.html b/test_fixtures/flex/balance_column_line_count_cross_space.html new file mode 100644 index 000000000..3d18e7b1c --- /dev/null +++ b/test_fixtures/flex/balance_column_line_count_cross_space.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
HHHHHHHHHH​HHHHHHHHHH​HHHHHHHHHH
+
+
+ + + diff --git a/test_fixtures/flex/balance_nowrap_line_count_no_effect.html b/test_fixtures/flex/balance_nowrap_line_count_no_effect.html new file mode 100644 index 000000000..d220dfcb2 --- /dev/null +++ b/test_fixtures/flex/balance_nowrap_line_count_no_effect.html @@ -0,0 +1,22 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row.html b/test_fixtures/flex/balance_row.html new file mode 100644 index 000000000..0b886eb8b --- /dev/null +++ b/test_fixtures/flex/balance_row.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_all_oversized_items.html b/test_fixtures/flex/balance_row_all_oversized_items.html new file mode 100644 index 000000000..a9b32fa5d --- /dev/null +++ b/test_fixtures/flex/balance_row_all_oversized_items.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_all_perfect_fit.html b/test_fixtures/flex/balance_row_all_perfect_fit.html new file mode 100644 index 000000000..f504612fc --- /dev/null +++ b/test_fixtures/flex/balance_row_all_perfect_fit.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_complex.html b/test_fixtures/flex/balance_row_complex.html new file mode 100644 index 000000000..18dee6a1f --- /dev/null +++ b/test_fixtures/flex/balance_row_complex.html @@ -0,0 +1,42 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_flex_grow.html b/test_fixtures/flex/balance_row_flex_grow.html new file mode 100644 index 000000000..8c5ea5d44 --- /dev/null +++ b/test_fixtures/flex/balance_row_flex_grow.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_gap.html b/test_fixtures/flex/balance_row_gap.html new file mode 100644 index 000000000..7f237cae5 --- /dev/null +++ b/test_fixtures/flex/balance_row_gap.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_intrinsic_line_count.html b/test_fixtures/flex/balance_row_intrinsic_line_count.html new file mode 100644 index 000000000..76331777d --- /dev/null +++ b/test_fixtures/flex/balance_row_intrinsic_line_count.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_large_sizes.html b/test_fixtures/flex/balance_row_large_sizes.html new file mode 100644 index 000000000..7f9afdfa4 --- /dev/null +++ b/test_fixtures/flex/balance_row_large_sizes.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_line_count.html b/test_fixtures/flex/balance_row_line_count.html new file mode 100644 index 000000000..709bac546 --- /dev/null +++ b/test_fixtures/flex/balance_row_line_count.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_line_count_exceeds_items.html b/test_fixtures/flex/balance_row_line_count_exceeds_items.html new file mode 100644 index 000000000..9731dba5f --- /dev/null +++ b/test_fixtures/flex/balance_row_line_count_exceeds_items.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_line_count_fit_content.html b/test_fixtures/flex/balance_row_line_count_fit_content.html new file mode 100644 index 000000000..d5e35de33 --- /dev/null +++ b/test_fixtures/flex/balance_row_line_count_fit_content.html @@ -0,0 +1,21 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_line_count_identical_items.html b/test_fixtures/flex/balance_row_line_count_identical_items.html new file mode 100644 index 000000000..d6d14fc0f --- /dev/null +++ b/test_fixtures/flex/balance_row_line_count_identical_items.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_max_content_uneven_line_count.html b/test_fixtures/flex/balance_row_max_content_uneven_line_count.html new file mode 100644 index 000000000..1e82b7d29 --- /dev/null +++ b/test_fixtures/flex/balance_row_max_content_uneven_line_count.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_min_content_line_count.html b/test_fixtures/flex/balance_row_min_content_line_count.html new file mode 100644 index 000000000..7f39901de --- /dev/null +++ b/test_fixtures/flex/balance_row_min_content_line_count.html @@ -0,0 +1,21 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_negative_margin.html b/test_fixtures/flex/balance_row_negative_margin.html new file mode 100644 index 000000000..7ba742633 --- /dev/null +++ b/test_fixtures/flex/balance_row_negative_margin.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_negative_margin_flexed.html b/test_fixtures/flex/balance_row_negative_margin_flexed.html new file mode 100644 index 000000000..a36155c3f --- /dev/null +++ b/test_fixtures/flex/balance_row_negative_margin_flexed.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_oversized_item.html b/test_fixtures/flex/balance_row_oversized_item.html new file mode 100644 index 000000000..d334c5dc5 --- /dev/null +++ b/test_fixtures/flex/balance_row_oversized_item.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_percent.html b/test_fixtures/flex/balance_row_percent.html new file mode 100644 index 000000000..85f946952 --- /dev/null +++ b/test_fixtures/flex/balance_row_percent.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_percent_aspect_ratio_line_count.html b/test_fixtures/flex/balance_row_percent_aspect_ratio_line_count.html new file mode 100644 index 000000000..f367f90d8 --- /dev/null +++ b/test_fixtures/flex/balance_row_percent_aspect_ratio_line_count.html @@ -0,0 +1,19 @@ + + + + + + + Test description + + + + +
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_single_oversized_item.html b/test_fixtures/flex/balance_row_single_oversized_item.html new file mode 100644 index 000000000..642b22e1b --- /dev/null +++ b/test_fixtures/flex/balance_row_single_oversized_item.html @@ -0,0 +1,17 @@ + + + + + + + Test description + + + + +
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_start_bias.html b/test_fixtures/flex/balance_row_start_bias.html new file mode 100644 index 000000000..d7d119e91 --- /dev/null +++ b/test_fixtures/flex/balance_row_start_bias.html @@ -0,0 +1,32 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_start_bias_line_count.html b/test_fixtures/flex/balance_row_start_bias_line_count.html new file mode 100644 index 000000000..6032ce1da --- /dev/null +++ b/test_fixtures/flex/balance_row_start_bias_line_count.html @@ -0,0 +1,23 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_ties.html b/test_fixtures/flex/balance_row_ties.html new file mode 100644 index 000000000..63a844d18 --- /dev/null +++ b/test_fixtures/flex/balance_row_ties.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_zero_after_oversized.html b/test_fixtures/flex/balance_row_zero_after_oversized.html new file mode 100644 index 000000000..5dcc492b7 --- /dev/null +++ b/test_fixtures/flex/balance_row_zero_after_oversized.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_zero_perfect_fit.html b/test_fixtures/flex/balance_row_zero_perfect_fit.html new file mode 100644 index 000000000..9ee0c39a8 --- /dev/null +++ b/test_fixtures/flex/balance_row_zero_perfect_fit.html @@ -0,0 +1,18 @@ + + + + + + + Test description + + + + +
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_row_zero_sized_items.html b/test_fixtures/flex/balance_row_zero_sized_items.html new file mode 100644 index 000000000..09fe73a04 --- /dev/null +++ b/test_fixtures/flex/balance_row_zero_sized_items.html @@ -0,0 +1,21 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_wrap_reverse_row.html b/test_fixtures/flex/balance_wrap_reverse_row.html new file mode 100644 index 000000000..9a2568b84 --- /dev/null +++ b/test_fixtures/flex/balance_wrap_reverse_row.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_wrap_row.html b/test_fixtures/flex/balance_wrap_row.html new file mode 100644 index 000000000..4cc39df2f --- /dev/null +++ b/test_fixtures/flex/balance_wrap_row.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/test_fixtures/flex/balance_wrap_row_line_count_no_effect.html b/test_fixtures/flex/balance_wrap_row_line_count_no_effect.html new file mode 100644 index 000000000..772ad383c --- /dev/null +++ b/test_fixtures/flex/balance_wrap_row_line_count_no_effect.html @@ -0,0 +1,20 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+ + + diff --git a/tests/hand_written.rs b/tests/hand_written.rs index bf2dbee6c..05ade0c38 100644 --- a/tests/hand_written.rs +++ b/tests/hand_written.rs @@ -4,6 +4,8 @@ mod hand_written { mod block_replaced; mod border_and_padding; mod caching; + #[cfg(feature = "flexbox_balance")] + mod flex_line_count; mod floats; mod measure; mod min_max_overrides; diff --git a/tests/hand_written/flex_line_count.rs b/tests/hand_written/flex_line_count.rs new file mode 100644 index 000000000..cf84a370e --- /dev/null +++ b/tests/hand_written/flex_line_count.rs @@ -0,0 +1,72 @@ +#[cfg(test)] +mod flex_line_count { + use taffy::prelude::*; + use taffy_test_helpers::{new_test_tree, test_measure_function, TestNodeContext, WritingMode}; + + const TEXT: &str = "HHHHHHHHHH\u{200B}HHHHHHHHHH\u{200B}HHHHHHHHHH"; + + fn container_style(flex_wrap: FlexWrap) -> Style { + Style { + display: Display::Flex, + flex_direction: FlexDirection::Column, + flex_wrap, + flex_line_count: 2, + size: Size { width: Dimension::from_length(210.0), height: Dimension::from_length(100.0) }, + gap: Size { width: LengthPercentage::from_length(10.0), height: LengthPercentage::ZERO }, + align_items: Some(AlignItems::START), + align_content: Some(AlignContent::START), + ..Default::default() + } + } + + fn measure_text_child(flex_wrap: FlexWrap) -> Size { + let mut taffy = new_test_tree(); + let text = TestNodeContext::ahem_text(TEXT.to_string(), WritingMode::Horizontal); + let child = taffy.new_leaf_with_context(Style::default(), text).unwrap(); + let container = taffy.new_with_children(container_style(flex_wrap), &[child]).unwrap(); + taffy.compute_layout_with_measure(container, Size::MAX_CONTENT, test_measure_function).unwrap(); + taffy.layout(child).unwrap().size + } + + // A multi-line container with `flex-line-count: 2` measures content against the cross-axis + // available space divided between the requested number of lines (after subtracting the + // cross-axis gaps): (210 - 10) / 2 = 100. + #[test] + fn wrap_line_count_divides_cross_available_space() { + assert_eq!(measure_text_child(FlexWrap::Wrap), Size { width: 100.0, height: 30.0 }); + } + + #[test] + fn wrap_reverse_line_count_divides_cross_available_space() { + assert_eq!(measure_text_child(FlexWrap::WrapReverse), Size { width: 100.0, height: 30.0 }); + } + + // `flex-line-count` has no effect on `nowrap` containers. + #[test] + fn nowrap_line_count_has_no_effect() { + assert_eq!(measure_text_child(FlexWrap::NoWrap), Size { width: 210.0, height: 20.0 }); + } + + fn measure_fit_content_child(flex_wrap: FlexWrap) -> Size { + let mut taffy = new_test_tree(); + let text = TestNodeContext::ahem_text(TEXT.to_string(), WritingMode::Horizontal); + let child_style = + Style { size: Size { width: Dimension::fit_content(), height: auto() }, ..Default::default() }; + let child = taffy.new_leaf_with_context(child_style, text).unwrap(); + let container = taffy.new_with_children(container_style(flex_wrap), &[child]).unwrap(); + taffy.compute_layout_with_measure(container, Size::MAX_CONTENT, test_measure_function).unwrap(); + taffy.layout(child).unwrap().size + } + + // A bare `fit-content` cross size is also measured against the divided cross-axis + // available space, not the full container cross size. + #[test] + fn wrap_line_count_divides_fit_content_cross_size() { + assert_eq!(measure_fit_content_child(FlexWrap::Wrap), Size { width: 100.0, height: 30.0 }); + } + + #[test] + fn nowrap_line_count_does_not_divide_fit_content_cross_size() { + assert_eq!(measure_fit_content_child(FlexWrap::NoWrap), Size { width: 210.0, height: 20.0 }); + } +} diff --git a/tests/xml.rs b/tests/xml.rs index 842483e4e..f03fd8a0d 100644 --- a/tests/xml.rs +++ b/tests/xml.rs @@ -312,6 +312,8 @@ fn build_style(xnode: roxmltree::Node) -> taffy::Style { text_align: parse_or_default(xnode.attribute("text-align")), flex_direction: parse_or_default(xnode.attribute("flex-direction")), flex_wrap: parse_or_default(xnode.attribute("flex-wrap")), + #[cfg(feature = "flexbox_balance")] + flex_line_count: parse_or(xnode.attribute("flex-line-count"), 1), flex_grow: parse_or(xnode.attribute("flex-grow"), 0.0), flex_shrink: parse_or(xnode.attribute("flex-shrink"), 1.0), flex_basis: parse_or(xnode.attribute("flex-basis"), Dimension::auto()), diff --git a/tests/xml/flex/balance_column__border_box_ltr.xml b/tests/xml/flex/balance_column__border_box_ltr.xml new file mode 100644 index 000000000..ee73dab31 --- /dev/null +++ b/tests/xml/flex/balance_column__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_column__border_box_rtl.xml b/tests/xml/flex/balance_column__border_box_rtl.xml new file mode 100644 index 000000000..ad80ac8ca --- /dev/null +++ b/tests/xml/flex/balance_column__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_column__content_box_ltr.xml b/tests/xml/flex/balance_column__content_box_ltr.xml new file mode 100644 index 000000000..669c429fe --- /dev/null +++ b/tests/xml/flex/balance_column__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_column__content_box_rtl.xml b/tests/xml/flex/balance_column__content_box_rtl.xml new file mode 100644 index 000000000..5113b953e --- /dev/null +++ b/tests/xml/flex/balance_column__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_column_intrinsic_line_count__border_box_ltr.xml b/tests/xml/flex/balance_column_intrinsic_line_count__border_box_ltr.xml new file mode 100644 index 000000000..11dd971d3 --- /dev/null +++ b/tests/xml/flex/balance_column_intrinsic_line_count__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_column_intrinsic_line_count__border_box_rtl.xml b/tests/xml/flex/balance_column_intrinsic_line_count__border_box_rtl.xml new file mode 100644 index 000000000..1dfbc7732 --- /dev/null +++ b/tests/xml/flex/balance_column_intrinsic_line_count__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_column_intrinsic_line_count__content_box_ltr.xml b/tests/xml/flex/balance_column_intrinsic_line_count__content_box_ltr.xml new file mode 100644 index 000000000..8636db1dd --- /dev/null +++ b/tests/xml/flex/balance_column_intrinsic_line_count__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_column_intrinsic_line_count__content_box_rtl.xml b/tests/xml/flex/balance_column_intrinsic_line_count__content_box_rtl.xml new file mode 100644 index 000000000..e288b528e --- /dev/null +++ b/tests/xml/flex/balance_column_intrinsic_line_count__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_column_line_count_content_measure__border_box_ltr.xml b/tests/xml/flex/balance_column_line_count_content_measure__border_box_ltr.xml new file mode 100644 index 000000000..1ca6e349b --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_content_measure__border_box_ltr.xml @@ -0,0 +1,23 @@ + + + +
+ + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + +
+ + + + + + + + +
diff --git a/tests/xml/flex/balance_column_line_count_content_measure__border_box_rtl.xml b/tests/xml/flex/balance_column_line_count_content_measure__border_box_rtl.xml new file mode 100644 index 000000000..c16670061 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_content_measure__border_box_rtl.xml @@ -0,0 +1,23 @@ + + + +
+ + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + +
+ + + + + + + + +
diff --git a/tests/xml/flex/balance_column_line_count_content_measure__content_box_ltr.xml b/tests/xml/flex/balance_column_line_count_content_measure__content_box_ltr.xml new file mode 100644 index 000000000..09422ffa0 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_content_measure__content_box_ltr.xml @@ -0,0 +1,23 @@ + + + +
+ + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + +
+ + + + + + + + +
diff --git a/tests/xml/flex/balance_column_line_count_content_measure__content_box_rtl.xml b/tests/xml/flex/balance_column_line_count_content_measure__content_box_rtl.xml new file mode 100644 index 000000000..180b034f5 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_content_measure__content_box_rtl.xml @@ -0,0 +1,23 @@ + + + +
+ + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + + + XXXXXXXXXX​XXXXXXXXXX + +
+ + + + + + + + +
diff --git a/tests/xml/flex/balance_column_line_count_cross_space__border_box_ltr.xml b/tests/xml/flex/balance_column_line_count_cross_space__border_box_ltr.xml new file mode 100644 index 000000000..980ecf12d --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_cross_space__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+ + HHHHHHHHHH​HHHHHHHHHH​HHHHHHHHHH + +
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_column_line_count_cross_space__border_box_rtl.xml b/tests/xml/flex/balance_column_line_count_cross_space__border_box_rtl.xml new file mode 100644 index 000000000..e002db196 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_cross_space__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+ + HHHHHHHHHH​HHHHHHHHHH​HHHHHHHHHH + +
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_column_line_count_cross_space__content_box_ltr.xml b/tests/xml/flex/balance_column_line_count_cross_space__content_box_ltr.xml new file mode 100644 index 000000000..c4c8c7791 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_cross_space__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+ + HHHHHHHHHH​HHHHHHHHHH​HHHHHHHHHH + +
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_column_line_count_cross_space__content_box_rtl.xml b/tests/xml/flex/balance_column_line_count_cross_space__content_box_rtl.xml new file mode 100644 index 000000000..f8858d642 --- /dev/null +++ b/tests/xml/flex/balance_column_line_count_cross_space__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+ + HHHHHHHHHH​HHHHHHHHHH​HHHHHHHHHH + +
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_ltr.xml b/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_ltr.xml new file mode 100644 index 000000000..60820c050 --- /dev/null +++ b/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_ltr.xml @@ -0,0 +1,23 @@ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + diff --git a/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_rtl.xml b/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_rtl.xml new file mode 100644 index 000000000..7b3dcd937 --- /dev/null +++ b/tests/xml/flex/balance_nowrap_line_count_no_effect__border_box_rtl.xml @@ -0,0 +1,23 @@ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + diff --git a/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_ltr.xml b/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_ltr.xml new file mode 100644 index 000000000..a3fc6815a --- /dev/null +++ b/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_ltr.xml @@ -0,0 +1,23 @@ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + diff --git a/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_rtl.xml b/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_rtl.xml new file mode 100644 index 000000000..d2fb77a7b --- /dev/null +++ b/tests/xml/flex/balance_nowrap_line_count_no_effect__content_box_rtl.xml @@ -0,0 +1,23 @@ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row__border_box_ltr.xml b/tests/xml/flex/balance_row__border_box_ltr.xml new file mode 100644 index 000000000..d7c29011a --- /dev/null +++ b/tests/xml/flex/balance_row__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row__border_box_rtl.xml b/tests/xml/flex/balance_row__border_box_rtl.xml new file mode 100644 index 000000000..282ed189e --- /dev/null +++ b/tests/xml/flex/balance_row__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row__content_box_ltr.xml b/tests/xml/flex/balance_row__content_box_ltr.xml new file mode 100644 index 000000000..5e8e85ab6 --- /dev/null +++ b/tests/xml/flex/balance_row__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row__content_box_rtl.xml b/tests/xml/flex/balance_row__content_box_rtl.xml new file mode 100644 index 000000000..a3655469c --- /dev/null +++ b/tests/xml/flex/balance_row__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_all_oversized_items__border_box_ltr.xml b/tests/xml/flex/balance_row_all_oversized_items__border_box_ltr.xml new file mode 100644 index 000000000..1ee864811 --- /dev/null +++ b/tests/xml/flex/balance_row_all_oversized_items__border_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_all_oversized_items__border_box_rtl.xml b/tests/xml/flex/balance_row_all_oversized_items__border_box_rtl.xml new file mode 100644 index 000000000..f9bbd7558 --- /dev/null +++ b/tests/xml/flex/balance_row_all_oversized_items__border_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_all_oversized_items__content_box_ltr.xml b/tests/xml/flex/balance_row_all_oversized_items__content_box_ltr.xml new file mode 100644 index 000000000..67a542daa --- /dev/null +++ b/tests/xml/flex/balance_row_all_oversized_items__content_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_all_oversized_items__content_box_rtl.xml b/tests/xml/flex/balance_row_all_oversized_items__content_box_rtl.xml new file mode 100644 index 000000000..a6e11af4f --- /dev/null +++ b/tests/xml/flex/balance_row_all_oversized_items__content_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_all_perfect_fit__border_box_ltr.xml b/tests/xml/flex/balance_row_all_perfect_fit__border_box_ltr.xml new file mode 100644 index 000000000..d324e8e48 --- /dev/null +++ b/tests/xml/flex/balance_row_all_perfect_fit__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_all_perfect_fit__border_box_rtl.xml b/tests/xml/flex/balance_row_all_perfect_fit__border_box_rtl.xml new file mode 100644 index 000000000..c91b7e157 --- /dev/null +++ b/tests/xml/flex/balance_row_all_perfect_fit__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_all_perfect_fit__content_box_ltr.xml b/tests/xml/flex/balance_row_all_perfect_fit__content_box_ltr.xml new file mode 100644 index 000000000..51baddde6 --- /dev/null +++ b/tests/xml/flex/balance_row_all_perfect_fit__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_all_perfect_fit__content_box_rtl.xml b/tests/xml/flex/balance_row_all_perfect_fit__content_box_rtl.xml new file mode 100644 index 000000000..54f2abbbe --- /dev/null +++ b/tests/xml/flex/balance_row_all_perfect_fit__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_complex__border_box_ltr.xml b/tests/xml/flex/balance_row_complex__border_box_ltr.xml new file mode 100644 index 000000000..98650bafe --- /dev/null +++ b/tests/xml/flex/balance_row_complex__border_box_ltr.xml @@ -0,0 +1,63 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_complex__border_box_rtl.xml b/tests/xml/flex/balance_row_complex__border_box_rtl.xml new file mode 100644 index 000000000..4142bfd7d --- /dev/null +++ b/tests/xml/flex/balance_row_complex__border_box_rtl.xml @@ -0,0 +1,63 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_complex__content_box_ltr.xml b/tests/xml/flex/balance_row_complex__content_box_ltr.xml new file mode 100644 index 000000000..a2e73dec4 --- /dev/null +++ b/tests/xml/flex/balance_row_complex__content_box_ltr.xml @@ -0,0 +1,63 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_complex__content_box_rtl.xml b/tests/xml/flex/balance_row_complex__content_box_rtl.xml new file mode 100644 index 000000000..64e88ca40 --- /dev/null +++ b/tests/xml/flex/balance_row_complex__content_box_rtl.xml @@ -0,0 +1,63 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_flex_grow__border_box_ltr.xml b/tests/xml/flex/balance_row_flex_grow__border_box_ltr.xml new file mode 100644 index 000000000..d5be0a454 --- /dev/null +++ b/tests/xml/flex/balance_row_flex_grow__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_flex_grow__border_box_rtl.xml b/tests/xml/flex/balance_row_flex_grow__border_box_rtl.xml new file mode 100644 index 000000000..55f45db0e --- /dev/null +++ b/tests/xml/flex/balance_row_flex_grow__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_flex_grow__content_box_ltr.xml b/tests/xml/flex/balance_row_flex_grow__content_box_ltr.xml new file mode 100644 index 000000000..25987a2d3 --- /dev/null +++ b/tests/xml/flex/balance_row_flex_grow__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_flex_grow__content_box_rtl.xml b/tests/xml/flex/balance_row_flex_grow__content_box_rtl.xml new file mode 100644 index 000000000..ade89f74f --- /dev/null +++ b/tests/xml/flex/balance_row_flex_grow__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_gap__border_box_ltr.xml b/tests/xml/flex/balance_row_gap__border_box_ltr.xml new file mode 100644 index 000000000..dee8b1eee --- /dev/null +++ b/tests/xml/flex/balance_row_gap__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_gap__border_box_rtl.xml b/tests/xml/flex/balance_row_gap__border_box_rtl.xml new file mode 100644 index 000000000..2655dec85 --- /dev/null +++ b/tests/xml/flex/balance_row_gap__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_gap__content_box_ltr.xml b/tests/xml/flex/balance_row_gap__content_box_ltr.xml new file mode 100644 index 000000000..fb36c4de0 --- /dev/null +++ b/tests/xml/flex/balance_row_gap__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_gap__content_box_rtl.xml b/tests/xml/flex/balance_row_gap__content_box_rtl.xml new file mode 100644 index 000000000..9ff87e9cc --- /dev/null +++ b/tests/xml/flex/balance_row_gap__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_intrinsic_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_intrinsic_line_count__border_box_ltr.xml new file mode 100644 index 000000000..d33c71457 --- /dev/null +++ b/tests/xml/flex/balance_row_intrinsic_line_count__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_intrinsic_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_intrinsic_line_count__border_box_rtl.xml new file mode 100644 index 000000000..082eea1ac --- /dev/null +++ b/tests/xml/flex/balance_row_intrinsic_line_count__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_intrinsic_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_intrinsic_line_count__content_box_ltr.xml new file mode 100644 index 000000000..5c61ed16c --- /dev/null +++ b/tests/xml/flex/balance_row_intrinsic_line_count__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_intrinsic_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_intrinsic_line_count__content_box_rtl.xml new file mode 100644 index 000000000..c898a2441 --- /dev/null +++ b/tests/xml/flex/balance_row_intrinsic_line_count__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_large_sizes__border_box_ltr.xml b/tests/xml/flex/balance_row_large_sizes__border_box_ltr.xml new file mode 100644 index 000000000..66d9097fd --- /dev/null +++ b/tests/xml/flex/balance_row_large_sizes__border_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_large_sizes__border_box_rtl.xml b/tests/xml/flex/balance_row_large_sizes__border_box_rtl.xml new file mode 100644 index 000000000..10a183083 --- /dev/null +++ b/tests/xml/flex/balance_row_large_sizes__border_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_large_sizes__content_box_ltr.xml b/tests/xml/flex/balance_row_large_sizes__content_box_ltr.xml new file mode 100644 index 000000000..41964fa05 --- /dev/null +++ b/tests/xml/flex/balance_row_large_sizes__content_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_large_sizes__content_box_rtl.xml b/tests/xml/flex/balance_row_large_sizes__content_box_rtl.xml new file mode 100644 index 000000000..c61a8a60f --- /dev/null +++ b/tests/xml/flex/balance_row_large_sizes__content_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_line_count__border_box_ltr.xml new file mode 100644 index 000000000..d28594454 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_line_count__border_box_rtl.xml new file mode 100644 index 000000000..0df18762e --- /dev/null +++ b/tests/xml/flex/balance_row_line_count__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_line_count__content_box_ltr.xml new file mode 100644 index 000000000..1cba89ea3 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_line_count__content_box_rtl.xml new file mode 100644 index 000000000..3fd8ee74e --- /dev/null +++ b/tests/xml/flex/balance_row_line_count__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_ltr.xml b/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_ltr.xml new file mode 100644 index 000000000..696f8e2c3 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_rtl.xml b/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_rtl.xml new file mode 100644 index 000000000..4c76c4aa8 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_exceeds_items__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_ltr.xml b/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_ltr.xml new file mode 100644 index 000000000..a2181a561 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_rtl.xml b/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_rtl.xml new file mode 100644 index 000000000..2b5a5486f --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_exceeds_items__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_fit_content__border_box_ltr.xml b/tests/xml/flex/balance_row_line_count_fit_content__border_box_ltr.xml new file mode 100644 index 000000000..badaa0726 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_fit_content__border_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_fit_content__border_box_rtl.xml b/tests/xml/flex/balance_row_line_count_fit_content__border_box_rtl.xml new file mode 100644 index 000000000..ebb22fdb2 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_fit_content__border_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_fit_content__content_box_ltr.xml b/tests/xml/flex/balance_row_line_count_fit_content__content_box_ltr.xml new file mode 100644 index 000000000..f0c194da4 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_fit_content__content_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_fit_content__content_box_rtl.xml b/tests/xml/flex/balance_row_line_count_fit_content__content_box_rtl.xml new file mode 100644 index 000000000..92093b087 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_fit_content__content_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_identical_items__border_box_ltr.xml b/tests/xml/flex/balance_row_line_count_identical_items__border_box_ltr.xml new file mode 100644 index 000000000..441a6c45e --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_identical_items__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_identical_items__border_box_rtl.xml b/tests/xml/flex/balance_row_line_count_identical_items__border_box_rtl.xml new file mode 100644 index 000000000..2e6b38662 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_identical_items__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_identical_items__content_box_ltr.xml b/tests/xml/flex/balance_row_line_count_identical_items__content_box_ltr.xml new file mode 100644 index 000000000..587fe5cf2 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_identical_items__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_line_count_identical_items__content_box_rtl.xml b/tests/xml/flex/balance_row_line_count_identical_items__content_box_rtl.xml new file mode 100644 index 000000000..5222c4b01 --- /dev/null +++ b/tests/xml/flex/balance_row_line_count_identical_items__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_ltr.xml new file mode 100644 index 000000000..9fe051d16 --- /dev/null +++ b/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_rtl.xml new file mode 100644 index 000000000..462bdf36a --- /dev/null +++ b/tests/xml/flex/balance_row_max_content_uneven_line_count__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_ltr.xml new file mode 100644 index 000000000..b83d38e52 --- /dev/null +++ b/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_rtl.xml new file mode 100644 index 000000000..15ce95581 --- /dev/null +++ b/tests/xml/flex/balance_row_max_content_uneven_line_count__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_min_content_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_min_content_line_count__border_box_ltr.xml new file mode 100644 index 000000000..cc2772bbb --- /dev/null +++ b/tests/xml/flex/balance_row_min_content_line_count__border_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_min_content_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_min_content_line_count__border_box_rtl.xml new file mode 100644 index 000000000..f1d2618ca --- /dev/null +++ b/tests/xml/flex/balance_row_min_content_line_count__border_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_min_content_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_min_content_line_count__content_box_ltr.xml new file mode 100644 index 000000000..cf263a9f3 --- /dev/null +++ b/tests/xml/flex/balance_row_min_content_line_count__content_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_min_content_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_min_content_line_count__content_box_rtl.xml new file mode 100644 index 000000000..46d44b72c --- /dev/null +++ b/tests/xml/flex/balance_row_min_content_line_count__content_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin__border_box_ltr.xml b/tests/xml/flex/balance_row_negative_margin__border_box_ltr.xml new file mode 100644 index 000000000..27f77e4fd --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin__border_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin__border_box_rtl.xml b/tests/xml/flex/balance_row_negative_margin__border_box_rtl.xml new file mode 100644 index 000000000..de001e1cd --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin__border_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin__content_box_ltr.xml b/tests/xml/flex/balance_row_negative_margin__content_box_ltr.xml new file mode 100644 index 000000000..1e9b331b4 --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin__content_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin__content_box_rtl.xml b/tests/xml/flex/balance_row_negative_margin__content_box_rtl.xml new file mode 100644 index 000000000..b08b4a559 --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin__content_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin_flexed__border_box_ltr.xml b/tests/xml/flex/balance_row_negative_margin_flexed__border_box_ltr.xml new file mode 100644 index 000000000..d9aa4be4d --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin_flexed__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin_flexed__border_box_rtl.xml b/tests/xml/flex/balance_row_negative_margin_flexed__border_box_rtl.xml new file mode 100644 index 000000000..8267263c2 --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin_flexed__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin_flexed__content_box_ltr.xml b/tests/xml/flex/balance_row_negative_margin_flexed__content_box_ltr.xml new file mode 100644 index 000000000..552ed08e7 --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin_flexed__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_negative_margin_flexed__content_box_rtl.xml b/tests/xml/flex/balance_row_negative_margin_flexed__content_box_rtl.xml new file mode 100644 index 000000000..fbf4af696 --- /dev/null +++ b/tests/xml/flex/balance_row_negative_margin_flexed__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_oversized_item__border_box_ltr.xml b/tests/xml/flex/balance_row_oversized_item__border_box_ltr.xml new file mode 100644 index 000000000..a32456da1 --- /dev/null +++ b/tests/xml/flex/balance_row_oversized_item__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_oversized_item__border_box_rtl.xml b/tests/xml/flex/balance_row_oversized_item__border_box_rtl.xml new file mode 100644 index 000000000..ca5449f52 --- /dev/null +++ b/tests/xml/flex/balance_row_oversized_item__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_oversized_item__content_box_ltr.xml b/tests/xml/flex/balance_row_oversized_item__content_box_ltr.xml new file mode 100644 index 000000000..2cd214fb2 --- /dev/null +++ b/tests/xml/flex/balance_row_oversized_item__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_oversized_item__content_box_rtl.xml b/tests/xml/flex/balance_row_oversized_item__content_box_rtl.xml new file mode 100644 index 000000000..2452c17d2 --- /dev/null +++ b/tests/xml/flex/balance_row_oversized_item__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent__border_box_ltr.xml b/tests/xml/flex/balance_row_percent__border_box_ltr.xml new file mode 100644 index 000000000..38196dccb --- /dev/null +++ b/tests/xml/flex/balance_row_percent__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent__border_box_rtl.xml b/tests/xml/flex/balance_row_percent__border_box_rtl.xml new file mode 100644 index 000000000..bb293677e --- /dev/null +++ b/tests/xml/flex/balance_row_percent__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent__content_box_ltr.xml b/tests/xml/flex/balance_row_percent__content_box_ltr.xml new file mode 100644 index 000000000..314ce4a02 --- /dev/null +++ b/tests/xml/flex/balance_row_percent__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent__content_box_rtl.xml b/tests/xml/flex/balance_row_percent__content_box_rtl.xml new file mode 100644 index 000000000..6b6be0ef7 --- /dev/null +++ b/tests/xml/flex/balance_row_percent__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_ltr.xml new file mode 100644 index 000000000..e9ac830d2 --- /dev/null +++ b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_rtl.xml new file mode 100644 index 000000000..d18da42fd --- /dev/null +++ b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__border_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_ltr.xml new file mode 100644 index 000000000..5c9794035 --- /dev/null +++ b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_ltr.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_rtl.xml new file mode 100644 index 000000000..8a5046bfc --- /dev/null +++ b/tests/xml/flex/balance_row_percent_aspect_ratio_line_count__content_box_rtl.xml @@ -0,0 +1,17 @@ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/tests/xml/flex/balance_row_single_oversized_item__border_box_ltr.xml b/tests/xml/flex/balance_row_single_oversized_item__border_box_ltr.xml new file mode 100644 index 000000000..8fb3e11e2 --- /dev/null +++ b/tests/xml/flex/balance_row_single_oversized_item__border_box_ltr.xml @@ -0,0 +1,13 @@ + + + +
+
+
+ + + + + + + diff --git a/tests/xml/flex/balance_row_single_oversized_item__border_box_rtl.xml b/tests/xml/flex/balance_row_single_oversized_item__border_box_rtl.xml new file mode 100644 index 000000000..649f26a24 --- /dev/null +++ b/tests/xml/flex/balance_row_single_oversized_item__border_box_rtl.xml @@ -0,0 +1,13 @@ + + + +
+
+
+ + + + + + + diff --git a/tests/xml/flex/balance_row_single_oversized_item__content_box_ltr.xml b/tests/xml/flex/balance_row_single_oversized_item__content_box_ltr.xml new file mode 100644 index 000000000..73d981bcd --- /dev/null +++ b/tests/xml/flex/balance_row_single_oversized_item__content_box_ltr.xml @@ -0,0 +1,13 @@ + + + +
+
+
+ + + + + + + diff --git a/tests/xml/flex/balance_row_single_oversized_item__content_box_rtl.xml b/tests/xml/flex/balance_row_single_oversized_item__content_box_rtl.xml new file mode 100644 index 000000000..d9b311b67 --- /dev/null +++ b/tests/xml/flex/balance_row_single_oversized_item__content_box_rtl.xml @@ -0,0 +1,13 @@ + + + +
+
+
+ + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias__border_box_ltr.xml b/tests/xml/flex/balance_row_start_bias__border_box_ltr.xml new file mode 100644 index 000000000..eacec3830 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias__border_box_ltr.xml @@ -0,0 +1,43 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias__border_box_rtl.xml b/tests/xml/flex/balance_row_start_bias__border_box_rtl.xml new file mode 100644 index 000000000..1dcb72107 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias__border_box_rtl.xml @@ -0,0 +1,43 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias__content_box_ltr.xml b/tests/xml/flex/balance_row_start_bias__content_box_ltr.xml new file mode 100644 index 000000000..400255ba8 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias__content_box_ltr.xml @@ -0,0 +1,43 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias__content_box_rtl.xml b/tests/xml/flex/balance_row_start_bias__content_box_rtl.xml new file mode 100644 index 000000000..b0858feee --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias__content_box_rtl.xml @@ -0,0 +1,43 @@ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias_line_count__border_box_ltr.xml b/tests/xml/flex/balance_row_start_bias_line_count__border_box_ltr.xml new file mode 100644 index 000000000..9ebc7a4a8 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias_line_count__border_box_ltr.xml @@ -0,0 +1,25 @@ + + + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias_line_count__border_box_rtl.xml b/tests/xml/flex/balance_row_start_bias_line_count__border_box_rtl.xml new file mode 100644 index 000000000..72193ed83 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias_line_count__border_box_rtl.xml @@ -0,0 +1,25 @@ + + + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias_line_count__content_box_ltr.xml b/tests/xml/flex/balance_row_start_bias_line_count__content_box_ltr.xml new file mode 100644 index 000000000..2ff9b6e90 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias_line_count__content_box_ltr.xml @@ -0,0 +1,25 @@ + + + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_start_bias_line_count__content_box_rtl.xml b/tests/xml/flex/balance_row_start_bias_line_count__content_box_rtl.xml new file mode 100644 index 000000000..18172d652 --- /dev/null +++ b/tests/xml/flex/balance_row_start_bias_line_count__content_box_rtl.xml @@ -0,0 +1,25 @@ + + + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_ties__border_box_ltr.xml b/tests/xml/flex/balance_row_ties__border_box_ltr.xml new file mode 100644 index 000000000..7dddafb8c --- /dev/null +++ b/tests/xml/flex/balance_row_ties__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_ties__border_box_rtl.xml b/tests/xml/flex/balance_row_ties__border_box_rtl.xml new file mode 100644 index 000000000..b4577f4ca --- /dev/null +++ b/tests/xml/flex/balance_row_ties__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_ties__content_box_ltr.xml b/tests/xml/flex/balance_row_ties__content_box_ltr.xml new file mode 100644 index 000000000..1d247cb16 --- /dev/null +++ b/tests/xml/flex/balance_row_ties__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_ties__content_box_rtl.xml b/tests/xml/flex/balance_row_ties__content_box_rtl.xml new file mode 100644 index 000000000..0e9c14a52 --- /dev/null +++ b/tests/xml/flex/balance_row_ties__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_after_oversized__border_box_ltr.xml b/tests/xml/flex/balance_row_zero_after_oversized__border_box_ltr.xml new file mode 100644 index 000000000..c4caab64f --- /dev/null +++ b/tests/xml/flex/balance_row_zero_after_oversized__border_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_after_oversized__border_box_rtl.xml b/tests/xml/flex/balance_row_zero_after_oversized__border_box_rtl.xml new file mode 100644 index 000000000..656996faf --- /dev/null +++ b/tests/xml/flex/balance_row_zero_after_oversized__border_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_after_oversized__content_box_ltr.xml b/tests/xml/flex/balance_row_zero_after_oversized__content_box_ltr.xml new file mode 100644 index 000000000..5397ea48c --- /dev/null +++ b/tests/xml/flex/balance_row_zero_after_oversized__content_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_after_oversized__content_box_rtl.xml b/tests/xml/flex/balance_row_zero_after_oversized__content_box_rtl.xml new file mode 100644 index 000000000..8b4d2bf53 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_after_oversized__content_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_perfect_fit__border_box_ltr.xml b/tests/xml/flex/balance_row_zero_perfect_fit__border_box_ltr.xml new file mode 100644 index 000000000..3debdc530 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_perfect_fit__border_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_perfect_fit__border_box_rtl.xml b/tests/xml/flex/balance_row_zero_perfect_fit__border_box_rtl.xml new file mode 100644 index 000000000..e6e1257d4 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_perfect_fit__border_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_perfect_fit__content_box_ltr.xml b/tests/xml/flex/balance_row_zero_perfect_fit__content_box_ltr.xml new file mode 100644 index 000000000..2e76de8bb --- /dev/null +++ b/tests/xml/flex/balance_row_zero_perfect_fit__content_box_ltr.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_perfect_fit__content_box_rtl.xml b/tests/xml/flex/balance_row_zero_perfect_fit__content_box_rtl.xml new file mode 100644 index 000000000..230b3db45 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_perfect_fit__content_box_rtl.xml @@ -0,0 +1,15 @@ + + + +
+
+
+
+ + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_sized_items__border_box_ltr.xml b/tests/xml/flex/balance_row_zero_sized_items__border_box_ltr.xml new file mode 100644 index 000000000..d5b4c0ffb --- /dev/null +++ b/tests/xml/flex/balance_row_zero_sized_items__border_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_sized_items__border_box_rtl.xml b/tests/xml/flex/balance_row_zero_sized_items__border_box_rtl.xml new file mode 100644 index 000000000..5fa09b8c8 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_sized_items__border_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_sized_items__content_box_ltr.xml b/tests/xml/flex/balance_row_zero_sized_items__content_box_ltr.xml new file mode 100644 index 000000000..e6ab3d81b --- /dev/null +++ b/tests/xml/flex/balance_row_zero_sized_items__content_box_ltr.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_row_zero_sized_items__content_box_rtl.xml b/tests/xml/flex/balance_row_zero_sized_items__content_box_rtl.xml new file mode 100644 index 000000000..5398f1c29 --- /dev/null +++ b/tests/xml/flex/balance_row_zero_sized_items__content_box_rtl.xml @@ -0,0 +1,21 @@ + + + +
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_reverse_row__border_box_ltr.xml b/tests/xml/flex/balance_wrap_reverse_row__border_box_ltr.xml new file mode 100644 index 000000000..2e6f17b99 --- /dev/null +++ b/tests/xml/flex/balance_wrap_reverse_row__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_reverse_row__border_box_rtl.xml b/tests/xml/flex/balance_wrap_reverse_row__border_box_rtl.xml new file mode 100644 index 000000000..b4ffb255b --- /dev/null +++ b/tests/xml/flex/balance_wrap_reverse_row__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_reverse_row__content_box_ltr.xml b/tests/xml/flex/balance_wrap_reverse_row__content_box_ltr.xml new file mode 100644 index 000000000..ffbea25ab --- /dev/null +++ b/tests/xml/flex/balance_wrap_reverse_row__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_reverse_row__content_box_rtl.xml b/tests/xml/flex/balance_wrap_reverse_row__content_box_rtl.xml new file mode 100644 index 000000000..8733add2c --- /dev/null +++ b/tests/xml/flex/balance_wrap_reverse_row__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row__border_box_ltr.xml b/tests/xml/flex/balance_wrap_row__border_box_ltr.xml new file mode 100644 index 000000000..67d5ae62c --- /dev/null +++ b/tests/xml/flex/balance_wrap_row__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row__border_box_rtl.xml b/tests/xml/flex/balance_wrap_row__border_box_rtl.xml new file mode 100644 index 000000000..e76bde006 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row__content_box_ltr.xml b/tests/xml/flex/balance_wrap_row__content_box_ltr.xml new file mode 100644 index 000000000..cdffb7091 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row__content_box_rtl.xml b/tests/xml/flex/balance_wrap_row__content_box_rtl.xml new file mode 100644 index 000000000..ffccce9f3 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_ltr.xml b/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_ltr.xml new file mode 100644 index 000000000..f28474241 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_rtl.xml b/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_rtl.xml new file mode 100644 index 000000000..352fd1f10 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row_line_count_no_effect__border_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_ltr.xml b/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_ltr.xml new file mode 100644 index 000000000..558829948 --- /dev/null +++ b/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_ltr.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_rtl.xml b/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_rtl.xml new file mode 100644 index 000000000..e3779559e --- /dev/null +++ b/tests/xml/flex/balance_wrap_row_line_count_no_effect__content_box_rtl.xml @@ -0,0 +1,19 @@ + + + +
+
+
+
+
+
+ + + + + + + + + + diff --git a/tests/xml/mod.rs b/tests/xml/mod.rs index a5cb5c4e4..fefa587d5 100644 --- a/tests/xml/mod.rs +++ b/tests/xml/mod.rs @@ -9435,6 +9435,822 @@ mod flex { crate::run_xml_test("flex", "aspect_ratio_flex_row_stretch_fill_width__content_box_rtl"); } + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column__border_box_ltr() { + crate::run_xml_test("flex", "balance_column__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column__content_box_ltr() { + crate::run_xml_test("flex", "balance_column__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column__border_box_rtl() { + crate::run_xml_test("flex", "balance_column__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column__content_box_rtl() { + crate::run_xml_test("flex", "balance_column__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_intrinsic_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_column_intrinsic_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_intrinsic_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_column_intrinsic_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_intrinsic_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_column_intrinsic_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_intrinsic_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_column_intrinsic_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_content_measure__border_box_ltr() { + crate::run_xml_test("flex", "balance_column_line_count_content_measure__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_content_measure__content_box_ltr() { + crate::run_xml_test("flex", "balance_column_line_count_content_measure__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_content_measure__border_box_rtl() { + crate::run_xml_test("flex", "balance_column_line_count_content_measure__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_content_measure__content_box_rtl() { + crate::run_xml_test("flex", "balance_column_line_count_content_measure__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_cross_space__border_box_ltr() { + crate::run_xml_test("flex", "balance_column_line_count_cross_space__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_cross_space__content_box_ltr() { + crate::run_xml_test("flex", "balance_column_line_count_cross_space__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_cross_space__border_box_rtl() { + crate::run_xml_test("flex", "balance_column_line_count_cross_space__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_column_line_count_cross_space__content_box_rtl() { + crate::run_xml_test("flex", "balance_column_line_count_cross_space__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_nowrap_line_count_no_effect__border_box_ltr() { + crate::run_xml_test("flex", "balance_nowrap_line_count_no_effect__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_nowrap_line_count_no_effect__content_box_ltr() { + crate::run_xml_test("flex", "balance_nowrap_line_count_no_effect__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_nowrap_line_count_no_effect__border_box_rtl() { + crate::run_xml_test("flex", "balance_nowrap_line_count_no_effect__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_nowrap_line_count_no_effect__content_box_rtl() { + crate::run_xml_test("flex", "balance_nowrap_line_count_no_effect__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row__border_box_ltr() { + crate::run_xml_test("flex", "balance_row__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row__content_box_ltr() { + crate::run_xml_test("flex", "balance_row__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row__border_box_rtl() { + crate::run_xml_test("flex", "balance_row__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row__content_box_rtl() { + crate::run_xml_test("flex", "balance_row__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_oversized_items__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_all_oversized_items__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_oversized_items__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_all_oversized_items__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_oversized_items__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_all_oversized_items__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_oversized_items__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_all_oversized_items__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_perfect_fit__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_all_perfect_fit__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_perfect_fit__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_all_perfect_fit__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_perfect_fit__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_all_perfect_fit__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_all_perfect_fit__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_all_perfect_fit__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_complex__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_complex__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_complex__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_complex__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_complex__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_complex__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_complex__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_complex__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_flex_grow__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_flex_grow__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_flex_grow__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_flex_grow__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_flex_grow__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_flex_grow__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_flex_grow__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_flex_grow__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_gap__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_gap__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_gap__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_gap__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_gap__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_gap__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_gap__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_gap__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_intrinsic_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_intrinsic_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_intrinsic_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_intrinsic_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_intrinsic_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_intrinsic_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_intrinsic_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_intrinsic_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_large_sizes__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_large_sizes__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_large_sizes__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_large_sizes__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_large_sizes__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_large_sizes__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_large_sizes__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_large_sizes__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_exceeds_items__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_exceeds_items__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_exceeds_items__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_exceeds_items__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_exceeds_items__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_exceeds_items__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_exceeds_items__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_exceeds_items__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_fit_content__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_fit_content__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_fit_content__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_fit_content__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_fit_content__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_fit_content__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_fit_content__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_fit_content__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_identical_items__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_identical_items__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_identical_items__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_line_count_identical_items__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_identical_items__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_identical_items__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_line_count_identical_items__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_line_count_identical_items__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_max_content_uneven_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_max_content_uneven_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_max_content_uneven_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_max_content_uneven_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_max_content_uneven_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_max_content_uneven_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_max_content_uneven_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_max_content_uneven_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_min_content_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_min_content_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_min_content_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_min_content_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_min_content_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_min_content_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_min_content_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_min_content_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_negative_margin__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_negative_margin__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_negative_margin__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_negative_margin__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin_flexed__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_negative_margin_flexed__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin_flexed__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_negative_margin_flexed__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin_flexed__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_negative_margin_flexed__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_negative_margin_flexed__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_negative_margin_flexed__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_oversized_item__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_oversized_item__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_oversized_item__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_oversized_item__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_oversized_item__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_oversized_item__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_oversized_item__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_oversized_item__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_percent__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_percent__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_percent__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_percent__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent_aspect_ratio_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_percent_aspect_ratio_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent_aspect_ratio_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_percent_aspect_ratio_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent_aspect_ratio_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_percent_aspect_ratio_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_percent_aspect_ratio_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_percent_aspect_ratio_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_single_oversized_item__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_single_oversized_item__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_single_oversized_item__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_single_oversized_item__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_single_oversized_item__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_single_oversized_item__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_single_oversized_item__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_single_oversized_item__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_start_bias__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_start_bias__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_start_bias__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_start_bias__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias_line_count__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_start_bias_line_count__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias_line_count__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_start_bias_line_count__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias_line_count__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_start_bias_line_count__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_start_bias_line_count__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_start_bias_line_count__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_ties__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_ties__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_ties__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_ties__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_ties__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_ties__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_ties__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_ties__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_after_oversized__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_after_oversized__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_after_oversized__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_after_oversized__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_after_oversized__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_after_oversized__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_after_oversized__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_after_oversized__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_perfect_fit__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_perfect_fit__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_perfect_fit__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_perfect_fit__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_perfect_fit__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_perfect_fit__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_perfect_fit__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_perfect_fit__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_sized_items__border_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_sized_items__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_sized_items__content_box_ltr() { + crate::run_xml_test("flex", "balance_row_zero_sized_items__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_sized_items__border_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_sized_items__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_row_zero_sized_items__content_box_rtl() { + crate::run_xml_test("flex", "balance_row_zero_sized_items__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_reverse_row__border_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_reverse_row__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_reverse_row__content_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_reverse_row__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_reverse_row__border_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_reverse_row__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_reverse_row__content_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_reverse_row__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row__border_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_row__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row__content_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_row__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row__border_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_row__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row__content_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_row__content_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row_line_count_no_effect__border_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_row_line_count_no_effect__border_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row_line_count_no_effect__content_box_ltr() { + crate::run_xml_test("flex", "balance_wrap_row_line_count_no_effect__content_box_ltr"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row_line_count_no_effect__border_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_row_line_count_no_effect__border_box_rtl"); + } + + #[cfg(feature = "flexbox_balance")] + #[test] + fn balance_wrap_row_line_count_no_effect__content_box_rtl() { + crate::run_xml_test("flex", "balance_wrap_row_line_count_no_effect__content_box_rtl"); + } + #[test] fn bevy_issue_10343_block__border_box_ltr() { crate::run_xml_test("flex", "bevy_issue_10343_block__border_box_ltr");