Convert layout to use Gecko's alignment style representation (#32790)

Signed-off-by: Nico Burns <nico@nicoburns.com>
Co-authored-by: Nico Burns <nico@nicoburns.com>
This commit is contained in:
Martin Robinson 2024-07-17 16:18:55 +02:00 committed by GitHub
parent a0d2b36ad8
commit 882a855b8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
80 changed files with 177 additions and 6482 deletions

View file

@ -11,16 +11,14 @@ use app_units::{Au, MAX_AU};
use euclid::default::Point2D;
use log::debug;
use serde::Serialize;
use style::computed_values::align_content::T as AlignContent;
use style::computed_values::align_self::T as AlignSelf;
use style::computed_values::flex_direction::T as FlexDirection;
use style::computed_values::flex_wrap::T as FlexWrap;
use style::computed_values::justify_content::T as JustifyContent;
use style::logical_geometry::{Direction, LogicalSize};
use style::properties::ComputedValues;
use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::flex::FlexBasis;
use style::values::computed::{MaxSize, Size};
use style::values::specified::align::AlignFlags;
use crate::block::{AbsoluteAssignBSizesTraversal, BlockFlow, MarginsMayCollapseFlag};
use crate::context::LayoutContext;
@ -612,42 +610,47 @@ impl FlexFlow {
// TODO(stshine): if this flex line contain children that have
// property visibility:collapse, exclude them and resolve again.
let item_count = items.len() as i32;
let mut cur_i = inline_start_content_edge;
let item_interval = if line.free_space >= Au(0) && line.auto_margin_count == 0 {
match self
let justify_content = {
let justify_content = self
.block_flow
.fragment
.style()
.get_position()
.justify_content
{
JustifyContent::SpaceBetween => {
.0
.primary()
.value();
match justify_content {
AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH,
_ => justify_content,
}
};
let item_count = items.len() as i32;
let mut cur_i = inline_start_content_edge;
let item_interval = if line.free_space >= Au(0) && line.auto_margin_count == 0 {
match justify_content {
AlignFlags::SPACE_BETWEEN => {
if item_count == 1 {
Au(0)
} else {
line.free_space / (item_count - 1)
}
},
JustifyContent::SpaceAround => line.free_space / item_count,
AlignFlags::SPACE_AROUND => line.free_space / item_count,
_ => Au(0),
}
} else {
Au(0)
};
match self
.block_flow
.fragment
.style()
.get_position()
.justify_content
{
match justify_content {
// Overflow equally in both ends of line.
JustifyContent::Center | JustifyContent::SpaceAround => {
AlignFlags::CENTER | AlignFlags::SPACE_AROUND => {
cur_i += (line.free_space - item_interval * (item_count - 1)) / 2;
},
JustifyContent::FlexEnd => {
AlignFlags::FLEX_END => {
cur_i += line.free_space;
},
_ => {},
@ -721,12 +724,22 @@ impl FlexFlow {
let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
let line_count = self.lines.len() as i32;
let line_align = self
.block_flow
.fragment
.style()
.get_position()
.align_content;
let line_align = {
let line_align = self
.block_flow
.fragment
.style()
.get_position()
.align_content
.0
.primary()
.value();
match line_align {
AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH,
_ => line_align,
}
};
let mut cur_b = self.block_flow.fragment.border_padding.block_start;
let mut total_cross_size = Au(0);
let mut line_interval = Au(0);
@ -762,21 +775,21 @@ impl FlexFlow {
let free_space = container_block_size - total_cross_size;
total_cross_size = container_block_size;
if line_align == AlignContent::Stretch && free_space > Au(0) {
if line_align == AlignFlags::STRETCH && free_space > Au(0) {
for line in self.lines.iter_mut() {
line.cross_size += free_space / line_count;
}
}
line_interval = match line_align {
AlignContent::SpaceBetween => {
AlignFlags::SPACE_BETWEEN => {
if line_count <= 1 {
Au(0)
} else {
free_space / (line_count - 1)
}
},
AlignContent::SpaceAround => {
AlignFlags::SPACE_AROUND => {
if line_count == 0 {
Au(0)
} else {
@ -787,16 +800,31 @@ impl FlexFlow {
};
match line_align {
AlignContent::Center | AlignContent::SpaceAround => {
AlignFlags::CENTER | AlignFlags::SPACE_AROUND => {
cur_b += (free_space - line_interval * (line_count - 1)) / 2;
},
AlignContent::FlexEnd => {
AlignFlags::FLEX_END => {
cur_b += free_space;
},
_ => {},
}
}
let align_items = {
let align_items = self
.block_flow
.fragment
.style()
.clone_align_items()
.0
.value();
match align_items {
AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH,
_ => align_items,
}
};
let mut children = self.block_flow.base.children.random_access_mut();
for line in &self.lines {
for item in self.items[line.range.clone()].iter_mut() {
@ -826,8 +854,23 @@ impl FlexFlow {
free_space = Au(0);
}
let self_align = block.fragment.style().get_position().align_self;
if self_align == AlignSelf::Stretch &&
let self_align = {
let self_align = block
.fragment
.style()
.get_position()
.align_self
.0
.0
.value();
match self_align {
AlignFlags::AUTO | AlignFlags::NORMAL => align_items,
_ => self_align,
}
};
if self_align == AlignFlags::STRETCH &&
block.fragment.style().content_block_size().is_auto()
{
free_space = Au(0);
@ -850,8 +893,8 @@ impl FlexFlow {
// TODO(stshine): support baseline alignment.
if free_space != Au(0) {
let flex_cross = match self_align {
AlignSelf::FlexEnd => free_space,
AlignSelf::Center => free_space / 2,
AlignFlags::FLEX_END => free_space,
AlignFlags::CENTER => free_space / 2,
_ => Au(0),
};
block.base.position.start.b += if !self.cross_reverse {

View file

@ -18,6 +18,7 @@ use style::properties::ComputedValues;
use style::values::computed::length::Size;
use style::values::computed::Length;
use style::values::generics::flex::GenericFlexBasis as FlexBasis;
use style::values::specified::align::AlignFlags;
use style::Zero;
use super::geom::{
@ -136,14 +137,12 @@ impl FlexContext<'_> {
}
fn align_for(&self, align_self: &AlignSelf) -> AlignItems {
match align_self {
AlignSelf::Auto => self.align_items,
AlignSelf::Stretch => AlignItems::Stretch,
AlignSelf::FlexStart => AlignItems::FlexStart,
AlignSelf::FlexEnd => AlignItems::FlexEnd,
AlignSelf::Center => AlignItems::Center,
AlignSelf::Baseline => AlignItems::Baseline,
}
let value = align_self.0 .0.value();
let mapped_value = match value {
AlignFlags::AUTO | AlignFlags::NORMAL => self.align_items.0,
_ => value,
};
AlignItems(mapped_value)
}
}
@ -225,8 +224,12 @@ impl FlexContainer {
FlexWrap::Nowrap | FlexWrap::Wrap => false,
FlexWrap::WrapReverse => true,
};
let align_content = container_style.clone_align_content();
let align_items = container_style.clone_align_items();
let align_items = AlignItems(match container_style.clone_align_items().0 {
AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH,
align => align,
});
let justify_content = container_style.clone_justify_content();
let mut flex_context = FlexContext {
@ -310,10 +313,12 @@ impl FlexContainer {
//
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
// the resolution of https://github.com/w3c/csswg-drafts/issues/10154
let resolved_align_content: AlignContent = {
let resolved_align_content: AlignFlags = {
let align_content_style = flex_context.align_content.0.primary();
// Inital values from the style system
let mut resolved_align_content = flex_context.align_content;
let mut is_safe = false; // FIXME: retrieve from style system
let mut resolved_align_content = align_content_style.value();
let mut is_safe = align_content_style.flags() == AlignFlags::SAFE;
// Fallback occurs in two cases:
@ -321,17 +326,17 @@ impl FlexContainer {
// https://www.w3.org/TR/css-align-3/#distribution-values
if line_count <= 1 || free_space <= Au::zero() {
(resolved_align_content, is_safe) = match resolved_align_content {
AlignContent::Stretch => (AlignContent::FlexStart, true),
AlignContent::SpaceBetween => (AlignContent::FlexStart, true),
AlignContent::SpaceAround => (AlignContent::Center, true),
AlignContent::SpaceEvenly => (AlignContent::Center, true),
AlignFlags::STRETCH => (AlignFlags::FLEX_START, true),
AlignFlags::SPACE_BETWEEN => (AlignFlags::FLEX_START, true),
AlignFlags::SPACE_AROUND => (AlignFlags::CENTER, true),
AlignFlags::SPACE_EVENLY => (AlignFlags::CENTER, true),
_ => (resolved_align_content, is_safe),
}
};
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
if free_space <= Au::zero() && is_safe {
resolved_align_content = AlignContent::Start;
resolved_align_content = AlignFlags::START;
}
resolved_align_content
@ -339,40 +344,46 @@ impl FlexContainer {
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
cross_start_position_cursor = match resolved_align_content {
AlignContent::Start => Au::zero(),
AlignContent::FlexStart => {
AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => {
if layout_is_flex_reversed {
free_space
} else {
Au::zero()
}
},
AlignContent::End => free_space,
AlignContent::FlexEnd => {
AlignFlags::END => free_space,
AlignFlags::FLEX_END => {
if layout_is_flex_reversed {
Au::zero()
} else {
free_space
}
},
AlignContent::Center => free_space / 2,
AlignContent::Stretch => Au::zero(),
AlignContent::SpaceBetween => Au::zero(),
AlignContent::SpaceAround => free_space / line_count as i32 / 2,
AlignContent::SpaceEvenly => free_space / (line_count + 1) as i32,
AlignFlags::CENTER => free_space / 2,
AlignFlags::STRETCH => Au::zero(),
AlignFlags::SPACE_BETWEEN => Au::zero(),
AlignFlags::SPACE_AROUND => free_space / line_count as i32 / 2,
AlignFlags::SPACE_EVENLY => free_space / (line_count + 1) as i32,
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
_ => Au::zero(),
};
// TODO: Implement gap property
line_interval = /*gap + */ match resolved_align_content {
AlignContent::Start => Au::zero(),
AlignContent::FlexStart => Au::zero(),
AlignContent::End => Au::zero(),
AlignContent::FlexEnd => Au::zero(),
AlignContent::Center => Au::zero(),
AlignContent::Stretch => Au::zero(),
AlignContent::SpaceBetween => free_space / (line_count - 1) as i32,
AlignContent::SpaceAround => free_space / line_count as i32,
AlignContent::SpaceEvenly => free_space / (line_count + 1) as i32,
AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => Au::zero(),
AlignFlags::END => Au::zero(),
AlignFlags::FLEX_END => Au::zero(),
AlignFlags::CENTER => Au::zero(),
AlignFlags::STRETCH => Au::zero(),
AlignFlags::SPACE_BETWEEN => free_space / (line_count - 1) as i32,
AlignFlags::SPACE_AROUND => free_space / line_count as i32,
AlignFlags::SPACE_EVENLY => free_space / (line_count + 1) as i32,
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
_ => Au::zero(),
};
};
@ -819,7 +830,7 @@ impl FlexLine<'_> {
.zip(item_layout_results)
.zip(&item_used_main_sizes)
.map(|((item, mut item_result), &used_main_size)| {
let has_stretch = item.align_self == AlignItems::Stretch;
let has_stretch = item.align_self.0.value() == AlignFlags::STRETCH;
let cross_size = if has_stretch &&
item.content_box_size.cross.is_auto() &&
!(item.margin.cross_start.is_auto() || item.margin.cross_end.is_auto())
@ -857,10 +868,12 @@ impl FlexLine<'_> {
//
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
// the resolution of https://github.com/w3c/csswg-drafts/issues/10154
let resolved_justify_content: JustifyContent = {
let resolved_justify_content: AlignFlags = {
let justify_content_style = flex_context.justify_content.0.primary();
// Inital values from the style system
let mut resolved_justify_content = flex_context.justify_content;
let mut is_safe = false; // FIXME: retrieve from style system
let mut resolved_justify_content = justify_content_style.value();
let mut is_safe = justify_content_style.flags() == AlignFlags::SAFE;
// Fallback occurs in two cases:
@ -868,17 +881,17 @@ impl FlexLine<'_> {
// https://www.w3.org/TR/css-align-3/#distribution-values
if item_count <= 1 || free_space <= Au::zero() {
(resolved_justify_content, is_safe) = match resolved_justify_content {
JustifyContent::Stretch => (JustifyContent::FlexStart, true),
JustifyContent::SpaceBetween => (JustifyContent::FlexStart, true),
JustifyContent::SpaceAround => (JustifyContent::Center, true),
JustifyContent::SpaceEvenly => (JustifyContent::Center, true),
AlignFlags::STRETCH => (AlignFlags::FLEX_START, true),
AlignFlags::SPACE_BETWEEN => (AlignFlags::FLEX_START, true),
AlignFlags::SPACE_AROUND => (AlignFlags::CENTER, true),
AlignFlags::SPACE_EVENLY => (AlignFlags::CENTER, true),
_ => (resolved_justify_content, is_safe),
}
};
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
if free_space <= Au::zero() && is_safe {
resolved_justify_content = JustifyContent::Start;
resolved_justify_content = AlignFlags::START;
}
resolved_justify_content
@ -886,40 +899,46 @@ impl FlexLine<'_> {
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
let main_start_position = match resolved_justify_content {
JustifyContent::Start => Au::zero(),
JustifyContent::FlexStart => {
AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => {
if layout_is_flex_reversed {
free_space
} else {
Au::zero()
}
},
JustifyContent::End => free_space,
JustifyContent::FlexEnd => {
AlignFlags::END => free_space,
AlignFlags::FLEX_END => {
if layout_is_flex_reversed {
Au::zero()
} else {
free_space
}
},
JustifyContent::Center => free_space / 2,
JustifyContent::Stretch => Au::zero(),
JustifyContent::SpaceBetween => Au::zero(),
JustifyContent::SpaceAround => (free_space / item_count as i32) / 2,
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as i32,
AlignFlags::CENTER => free_space / 2,
AlignFlags::STRETCH => Au::zero(),
AlignFlags::SPACE_BETWEEN => Au::zero(),
AlignFlags::SPACE_AROUND => (free_space / item_count as i32) / 2,
AlignFlags::SPACE_EVENLY => free_space / (item_count + 1) as i32,
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
_ => Au::zero(),
};
// TODO: Implement gap property
let item_main_interval = /*gap + */ match resolved_justify_content {
JustifyContent::Start => Au::zero(),
JustifyContent::FlexStart => Au::zero(),
JustifyContent::End => Au::zero(),
JustifyContent::FlexEnd => Au::zero(),
JustifyContent::Center => Au::zero(),
JustifyContent::Stretch => Au::zero(),
JustifyContent::SpaceBetween => free_space / (item_count - 1) as i32,
JustifyContent::SpaceAround => free_space / item_count as i32,
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as i32,
AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => Au::zero(),
AlignFlags::END => Au::zero(),
AlignFlags::FLEX_END => Au::zero(),
AlignFlags::CENTER => Au::zero(),
AlignFlags::STRETCH => Au::zero(),
AlignFlags::SPACE_BETWEEN => free_space / (item_count - 1) as i32,
AlignFlags::SPACE_AROUND => free_space / item_count as i32,
AlignFlags::SPACE_EVENLY => free_space / (item_count + 1) as i32,
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
_ => Au::zero(),
};
// https://drafts.csswg.org/css-flexbox/#algo-cross-margins
@ -1440,18 +1459,18 @@ impl FlexItem<'_> {
if self.margin.cross_start.is_auto() || self.margin.cross_end.is_auto() {
Au::zero()
} else {
match self.align_self {
AlignItems::Stretch | AlignItems::FlexStart => Au::zero(),
AlignItems::FlexEnd => {
match self.align_self.0.value() {
AlignFlags::STRETCH | AlignFlags::FLEX_START => Au::zero(),
AlignFlags::FLEX_END => {
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross;
line_cross_size - margin_box_cross
},
AlignItems::Center => {
AlignFlags::CENTER => {
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross;
(line_cross_size - margin_box_cross) / 2
},
// FIXME: handle baseline alignment
AlignItems::Baseline => Au::zero(),
// FIXME: handle other alignments (note: not all AlignFlags values are valid for self alignment)
_ => Au::zero(),
}
};
outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start