mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Add FlexLine and its method for flex resolving
Add the 'FlexLine' struct to represent a line in flex container, and the 'flex_resolve()' method for flex lengths resolving.
This commit is contained in:
parent
bf5805f2a6
commit
87a041d416
1 changed files with 96 additions and 0 deletions
|
@ -24,6 +24,7 @@ use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
|
||||||
use model::{specified, specified_or_none};
|
use model::{specified, specified_or_none};
|
||||||
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::flex_direction;
|
use style::computed_values::flex_direction;
|
||||||
use style::computed_values::{box_sizing, border_collapse};
|
use style::computed_values::{box_sizing, border_collapse};
|
||||||
|
@ -262,6 +263,98 @@ impl FlexItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A line in a flex container.
|
||||||
|
// TODO(stshine): More fields are required to handle collapsed items and baseline alignment.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FlexLine {
|
||||||
|
/// Range of items belong to this line in 'self.items'.
|
||||||
|
pub range: Range<usize>,
|
||||||
|
/// Remainig free space of this line, items will grow or shrink based on it being positive or negative.
|
||||||
|
pub free_space: Au,
|
||||||
|
/// the number of auto margins of items.
|
||||||
|
pub auto_margin_count: i32,
|
||||||
|
/// Line size in the block direction.
|
||||||
|
pub cross_size: Au,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlexLine {
|
||||||
|
pub fn new(range: Range<usize>, free_space: Au, auto_margin_count: i32) -> FlexLine {
|
||||||
|
FlexLine {
|
||||||
|
range: range,
|
||||||
|
auto_margin_count: auto_margin_count,
|
||||||
|
free_space: free_space,
|
||||||
|
cross_size: Au(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method implements the flexible lengths resolving algorithm.
|
||||||
|
/// The 'collapse' parameter is used to indicate whether items with 'visibility: hidden'
|
||||||
|
/// is included in length resolving. The result main size is stored in 'item.main_size'.
|
||||||
|
/// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
|
||||||
|
pub fn flex_resolve(&mut self, items: &mut [FlexItem], collapse: bool) {
|
||||||
|
let mut total_grow = 0.0;
|
||||||
|
let mut total_shrink = 0.0;
|
||||||
|
let mut total_scaled = 0.0;
|
||||||
|
let mut active_count = 0;
|
||||||
|
// Iterate through items, collect total factors and freeze those that have already met
|
||||||
|
// their constraints or won't grow/shrink in corresponding scenario.
|
||||||
|
// https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths
|
||||||
|
for item in items.iter_mut().filter(|i| !(i.is_strut && collapse)) {
|
||||||
|
item.main_size = max(item.min_size, min(item.base_size, item.max_size));
|
||||||
|
if item.main_size != item.base_size
|
||||||
|
|| (self.free_space > Au(0) && item.flex_grow == 0.0)
|
||||||
|
|| (self.free_space < Au(0) && item.flex_shrink == 0.0) {
|
||||||
|
item.is_frozen = true;
|
||||||
|
} else {
|
||||||
|
item.is_frozen = false;
|
||||||
|
total_grow += item.flex_grow;
|
||||||
|
total_shrink += item.flex_shrink;
|
||||||
|
// The scaled factor is used to calculate flex shrink
|
||||||
|
total_scaled += item.flex_shrink * item.base_size.0 as f32;
|
||||||
|
active_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let initial_free_space = self.free_space;
|
||||||
|
let mut total_variation = Au(1);
|
||||||
|
// If there is no remaining free space or all items are frozen, stop loop.
|
||||||
|
while total_variation != Au(0) && self.free_space != Au(0) && active_count > 0 {
|
||||||
|
self.free_space =
|
||||||
|
// https://drafts.csswg.org/css-flexbox/#remaining-free-space
|
||||||
|
if self.free_space > Au(0) {
|
||||||
|
min(initial_free_space.scale_by(total_grow), self.free_space)
|
||||||
|
} else {
|
||||||
|
max(initial_free_space.scale_by(total_shrink), self.free_space)
|
||||||
|
};
|
||||||
|
|
||||||
|
total_variation = Au(0);
|
||||||
|
for item in items.iter_mut().filter(|i| !i.is_frozen).filter(|i| !(i.is_strut && collapse)) {
|
||||||
|
// Use this and the 'abs()' below to make the code work in both grow and shrink scenarios.
|
||||||
|
let (factor, end_size) = if self.free_space > Au(0) {
|
||||||
|
(item.flex_grow / total_grow, item.max_size)
|
||||||
|
} else {
|
||||||
|
(item.flex_shrink * item.base_size.0 as f32 / total_scaled, item.min_size)
|
||||||
|
};
|
||||||
|
let variation = self.free_space.scale_by(factor);
|
||||||
|
if variation.0.abs() > (end_size - item.main_size).0.abs() {
|
||||||
|
// Use constraint as the target main size, and freeze item.
|
||||||
|
total_variation += end_size - item.main_size;
|
||||||
|
item.main_size = end_size;
|
||||||
|
item.is_frozen = true;
|
||||||
|
active_count -= 1;
|
||||||
|
total_shrink -= item.flex_shrink;
|
||||||
|
total_grow -= item.flex_grow;
|
||||||
|
total_scaled -= item.flex_shrink * item.base_size.0 as f32;
|
||||||
|
} else {
|
||||||
|
total_variation += variation;
|
||||||
|
item.main_size += variation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.free_space -= total_variation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A block with the CSS `display` property equal to `flex`.
|
/// A block with the CSS `display` property equal to `flex`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FlexFlow {
|
pub struct FlexFlow {
|
||||||
|
@ -274,6 +367,8 @@ pub struct FlexFlow {
|
||||||
available_main_size: AxisSize,
|
available_main_size: AxisSize,
|
||||||
/// The available cross axis size
|
/// The available cross axis size
|
||||||
available_cross_size: AxisSize,
|
available_cross_size: AxisSize,
|
||||||
|
/// List of flex lines in the container.
|
||||||
|
lines: Vec<FlexLine>,
|
||||||
/// List of flex-items that belong to this flex-container
|
/// List of flex-items that belong to this flex-container
|
||||||
items: Vec<FlexItem>,
|
items: Vec<FlexItem>,
|
||||||
/// True if the flex-direction is *-reversed
|
/// True if the flex-direction is *-reversed
|
||||||
|
@ -318,6 +413,7 @@ impl FlexFlow {
|
||||||
main_mode: main_mode,
|
main_mode: main_mode,
|
||||||
available_main_size: AxisSize::Infinite,
|
available_main_size: AxisSize::Infinite,
|
||||||
available_cross_size: AxisSize::Infinite,
|
available_cross_size: AxisSize::Infinite,
|
||||||
|
lines: Vec::new(),
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
main_reverse: main_reverse,
|
main_reverse: main_reverse,
|
||||||
is_wrappable: is_wrappable,
|
is_wrappable: is_wrappable,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue