mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +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 script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
use std::cmp::{max, min};
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::flex_direction;
|
||||
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`.
|
||||
#[derive(Debug)]
|
||||
pub struct FlexFlow {
|
||||
|
@ -274,6 +367,8 @@ pub struct FlexFlow {
|
|||
available_main_size: AxisSize,
|
||||
/// The available cross axis size
|
||||
available_cross_size: AxisSize,
|
||||
/// List of flex lines in the container.
|
||||
lines: Vec<FlexLine>,
|
||||
/// List of flex-items that belong to this flex-container
|
||||
items: Vec<FlexItem>,
|
||||
/// True if the flex-direction is *-reversed
|
||||
|
@ -318,6 +413,7 @@ impl FlexFlow {
|
|||
main_mode: main_mode,
|
||||
available_main_size: AxisSize::Infinite,
|
||||
available_cross_size: AxisSize::Infinite,
|
||||
lines: Vec::new(),
|
||||
items: Vec::new(),
|
||||
main_reverse: main_reverse,
|
||||
is_wrappable: is_wrappable,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue