From bd747170db624526a5db9a1f9c26daca86844760 Mon Sep 17 00:00:00 2001 From: RomChung Date: Mon, 9 Dec 2024 15:42:36 +0800 Subject: [PATCH 1/4] refactor: special position layout --- float-pigment-layout/src/algo/flex_box.rs | 8 +- float-pigment-layout/src/algo/flow.rs | 11 +- .../src/special_positioned.rs | 816 +++++++----------- 3 files changed, 335 insertions(+), 500 deletions(-) diff --git a/float-pigment-layout/src/algo/flex_box.rs b/float-pigment-layout/src/algo/flex_box.rs index c4a4e94..f52267d 100644 --- a/float-pigment-layout/src/algo/flex_box.rs +++ b/float-pigment-layout/src/algo/flex_box.rs @@ -1344,9 +1344,11 @@ impl FlexBox for LayoutUnit { &ret, border, padding_border, - dir, - main_dir_rev, - AxisReverse::NotReversed, + AxisInfo { + dir, + main_dir_rev, + cross_dir_rev: AxisReverse::NotReversed, + }, true, ); self.result = Rect::new(Point::zero(), ret.size.0); diff --git a/float-pigment-layout/src/algo/flow.rs b/float-pigment-layout/src/algo/flow.rs index 395fd6a..238e86e 100644 --- a/float-pigment-layout/src/algo/flow.rs +++ b/float-pigment-layout/src/algo/flow.rs @@ -297,9 +297,10 @@ impl Flow for LayoutUnit { &ret, border, padding_border, - axis_info.dir, - axis_info.main_dir_rev, - AxisReverse::NotReversed, + AxisInfo { + cross_dir_rev: AxisReverse::NotReversed, + ..axis_info + }, false, ); self.result = Rect::new(Point::zero(), ret.size.0); @@ -671,9 +672,7 @@ impl Flow for LayoutUnit { }, border, padding_border, - axis_info.dir, - axis_info.main_dir_rev, - axis_info.cross_dir_rev, + axis_info, false, ) } diff --git a/float-pigment-layout/src/special_positioned.rs b/float-pigment-layout/src/special_positioned.rs index eccf4cb..ce13c32 100644 --- a/float-pigment-layout/src/special_positioned.rs +++ b/float-pigment-layout/src/special_positioned.rs @@ -24,9 +24,7 @@ pub(crate) fn compute_special_position_children( node_result: &ComputeResult, border: Edge, padding_border: Edge, - dir: AxisDirection, - main_dir_rev: AxisReverse, - cross_dir_rev: AxisReverse, + axis_info: AxisInfo, accept_flex_props: bool, ) { let style: &::Style = node.style(); @@ -49,32 +47,35 @@ pub(crate) fn compute_special_position_children( return; } match child_style.position() { - Position::Absolute | Position::Sticky => { - compute_position_absolute( - env, - child_node, - ( - node_result, - style, - node_inner_size, - node_inner_option_size, - border, - padding_border, - ), - dir, - main_dir_rev, - cross_dir_rev, - accept_flex_props, - ); - } - Position::Fixed => compute_position_fixed( + Position::Absolute | Position::Sticky => compute_special_position( env, child_node, - (node_result, style, node_inner_size, border, padding_border), - dir, - main_dir_rev, - cross_dir_rev, + ParentInfo { + compute_result: node_result, + style, + inner_size: &node_inner_size, + inner_option_size: &node_inner_option_size, + border: &border, + padding_border: &padding_border, + }, + axis_info, accept_flex_props, + false, + ), + Position::Fixed => compute_special_position( + env, + child_node, + ParentInfo { + compute_result: node_result, + style, + inner_size: &node_inner_size, + inner_option_size: &node_inner_option_size, + border: &border, + padding_border: &padding_border, + }, + axis_info, + accept_flex_props, + true, ), Position::Static => {} Position::Relative => { @@ -86,43 +87,50 @@ pub(crate) fn compute_special_position_children( .for_each_child(|child_node, _| f(child_node)); } -#[allow(clippy::type_complexity)] -pub(crate) fn compute_position_fixed( +pub(crate) struct ParentInfo<'a, T: LayoutTreeNode> { + pub(crate) compute_result: &'a ComputeResult, + pub(crate) style: &'a T::Style, + pub(crate) inner_size: &'a Normalized>, + pub(crate) inner_option_size: &'a Normalized>, + pub(crate) border: &'a Edge, + pub(crate) padding_border: &'a Edge, +} + +pub(crate) fn compute_special_position( env: &mut T::Env, node: &T, - parent: ( - &ComputeResult, - &T::Style, - Normalized>, - Edge, - Edge, - ), - dir: AxisDirection, - main_dir_rev: AxisReverse, - cross_dir_rev: AxisReverse, + parent: ParentInfo, + axis_info: AxisInfo, accept_flex_props: bool, + is_position_fixed: bool, ) { - let (parent_node_result, parent_style, parent_inner_size, parent_border, parent_padding_border) = - parent; let mut layout_unit = node.layout_node().unit(); let style = node.style(); - let container_width = env.screen_width(); - let container_height = env.screen_height(); - let container_option_size = OptionSize::new( - OptionNum::some(container_width), - OptionNum::some(container_height), - ); - let container_size = Size::new(container_width, container_height); - let left = style.left().resolve_num(container_width, node); - let right = style.right().resolve_num(container_width, node); - let top = style.top().resolve_num(container_height, node); - let bottom = style.bottom().resolve_num(container_height, node); + + let container_size = if is_position_fixed { + Size::new(env.screen_width(), env.screen_height()) + } else { + **parent.inner_size + }; + let container_option_size = if is_position_fixed { + Normalized(OptionSize::new( + OptionNum::some(container_size.width), + OptionNum::some(container_size.height), + )) + } else { + *parent.inner_option_size + }; + + let left = style.left().resolve_num(container_size.width, node); + let right = style.right().resolve_num(container_size.width, node); + let top = style.top().resolve_num(container_size.height, node); + let bottom = style.bottom().resolve_num(container_size.height, node); let (margin, border, padding_border) = - layout_unit.margin_border_padding(node, container_option_size); + layout_unit.margin_border_padding(node, *container_option_size); let css_size = - layout_unit.css_border_box_size(node, container_option_size, border, padding_border); + layout_unit.css_border_box_size(node, *container_option_size, border, padding_border); let width = css_size.width.or(if left.is_some() && right.is_some() { - OptionNum::some(container_width) + OptionNum::some(container_size.width) - left - right - margin.left.or_zero() @@ -131,7 +139,7 @@ pub(crate) fn compute_position_fixed( OptionNum::none() }); let height = css_size.height.or(if top.is_some() && bottom.is_some() { - OptionNum::some(container_height) + OptionNum::some(container_size.height) - top - bottom - margin.top.or_zero() @@ -140,26 +148,25 @@ pub(crate) fn compute_position_fixed( OptionNum::none() }); let min_max_limit = - layout_unit.normalized_min_max_limit(node, container_option_size, border, padding_border); + layout_unit.normalized_min_max_limit(node, *container_option_size, border, padding_border); let size = min_max_limit.normalized_size(OptionSize::new(width, height)); - let max_content_width = size.width.unwrap_or( - container_width - - left.or_zero() - - right.or_zero() - - margin.left.or_zero() - - margin.right.or_zero(), - ); - let max_content_height = size.height.unwrap_or( - container_height - - top.or_zero() - - bottom.or_zero() - - margin.top.or_zero() - - margin.bottom.or_zero(), - ); let max_content = min_max_limit.normalized_size(OptionSize::new( - OptionNum::some(max_content_width), - OptionNum::some(max_content_height), + OptionNum::some(size.width.unwrap_or( + container_size.width + - left.or_zero() + - right.or_zero() + - margin.left.or_zero() + - margin.right.or_zero(), + )), + OptionNum::some(size.height.unwrap_or( + container_size.height + - top.or_zero() + - bottom.or_zero() + - margin.top.or_zero() + - margin.bottom.or_zero(), + )), )); + let result = if size.width.is_none() || size.height.is_none() { let auto_size = layout_unit .compute_internal( @@ -167,7 +174,7 @@ pub(crate) fn compute_position_fixed( node, ComputeRequest { size, - parent_inner_size: Normalized(container_option_size), + parent_inner_size: container_option_size, max_content, kind: ComputeRequestKind::AllSize, parent_is_block: false, @@ -182,7 +189,7 @@ pub(crate) fn compute_position_fixed( OptionNum::some(auto_size.width), OptionNum::some(auto_size.height), )), - parent_inner_size: Normalized(container_option_size), + parent_inner_size: container_option_size, max_content, kind: ComputeRequestKind::Position, parent_is_block: false, @@ -194,7 +201,7 @@ pub(crate) fn compute_position_fixed( node, ComputeRequest { size, - parent_inner_size: Normalized(container_option_size), + parent_inner_size: container_option_size, max_content, kind: ComputeRequestKind::Position, parent_is_block: false, @@ -202,432 +209,259 @@ pub(crate) fn compute_position_fixed( ) }; let free_space = container_size - result.size.0; - let parent_free_space = *parent_inner_size - result.size.0; - macro_rules! axis { - ( - $main_start: ident, - $main_end: ident, - $cross_start: ident, - $cross_end: ident, - $main_size: ident, - $cross_size: ident, - $main_axis: ident, - $cross_axis: ident, - ) => {{ - let offset_main = if $main_start.val().is_some() - && $main_end.val().is_some() - && margin.$main_start.val().is_none() - && margin.$main_end.val().is_none() - { - let main_start = $main_start.val().unwrap_or(T::Length::zero()); - let main_end = $main_end.val().unwrap_or(T::Length::zero()); - let free_space_main_size = container_size.$main_size; - main_start + (free_space_main_size - main_end - main_start).div_i32(2) - - result.size.0.$main_size.div_i32(2) - } else { - let offset_main = if let Some(x) = $main_start.val() { - x - } else if let Some(x) = $main_end.val() { - free_space.$main_size - x - } else if accept_flex_props { - match parent_style.justify_content() { - JustifyContent::SpaceBetween - | JustifyContent::FlexStart - | JustifyContent::Start - | JustifyContent::Stretch - | JustifyContent::Baseline => parent_padding_border.$main_start, - JustifyContent::FlexEnd | JustifyContent::End => { - parent_border.$main_start + parent_free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - JustifyContent::Left => match main_dir_rev { - AxisReverse::NotReversed => parent_padding_border.$main_start, - AxisReverse::Reversed => { - parent_border.$main_start + parent_free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - }, - JustifyContent::Right => match main_dir_rev { - AxisReverse::NotReversed => { - parent_border.$main_start + parent_free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - AxisReverse::Reversed => parent_padding_border.$main_start, - }, - JustifyContent::SpaceEvenly - | JustifyContent::SpaceAround - | JustifyContent::Center => { - parent_border.$main_start + parent_free_space.$main_size.div_i32(2) - } - } - } else { - T::Length::zero() - }; - let offset_main = if let Some(x) = margin.$main_start.val() { - offset_main + x - } else if let Some(x) = margin.$main_end.val() { - offset_main - x - } else { - offset_main - }; - offset_main - }; - - let offset_cross = if $cross_start.val().is_some() - && $cross_end.val().is_some() - && margin.$cross_start.val().is_none() - && margin.$cross_end.val().is_none() - { - let cross_start = $cross_start.val().unwrap_or(T::Length::zero()); - let cross_end = $cross_end.val().unwrap_or(T::Length::zero()); - let free_space_cross_size = container_size.$cross_size; - cross_start + (free_space_cross_size - cross_end - cross_start).div_i32(2) - - (result.size.0.$cross_size.div_i32(2)) - } else { - let offset_cross = if let Some(x) = $cross_start.val() { - x - } else if let Some(x) = $cross_end.val() { - free_space.$cross_size - x - } else if accept_flex_props { - match algo::flex_box::align_self::(style, parent_style) { - AlignSelf::FlexStart - | AlignSelf::Start - | AlignSelf::SelfStart - | AlignSelf::Normal => parent_padding_border.$cross_start, - AlignSelf::FlexEnd | AlignSelf::End | AlignSelf::SelfEnd => { - parent_border.$cross_start + parent_free_space.$cross_size - - (parent_padding_border.$cross_end - parent_border.$cross_end) - } - AlignSelf::Center => { - parent_border.$cross_start + parent_free_space.$cross_size.div_i32(2) - } - AlignSelf::Baseline => { - parent_node_result.first_baseline_ascent.$cross_axis - - result.first_baseline_ascent.$cross_axis - } - AlignSelf::Auto | AlignSelf::Stretch => parent_padding_border.$cross_start, - } - } else { - T::Length::zero() - }; - let offset_cross = if let Some(x) = margin.$cross_start.val() { - offset_cross + x - } else if let Some(x) = margin.$cross_end.val() { - offset_cross - x - } else { - offset_cross - }; - offset_cross - }; + let parent_free_space = **parent.inner_size - result.size.0; + let (main_start, main_end, cross_start, cross_end) = + match (axis_info.dir, axis_info.main_dir_rev) { + (AxisDirection::Horizontal, AxisReverse::NotReversed) => (left, right, top, bottom), + (AxisDirection::Horizontal, AxisReverse::Reversed) => (right, left, top, bottom), + (AxisDirection::Vertical, AxisReverse::NotReversed) => (top, bottom, left, right), + (AxisDirection::Vertical, AxisReverse::Reversed) => (top, bottom, right, left), + }; - layout_unit.gen_origin( - dir, - main_dir_rev, - cross_dir_rev, - container_size, - offset_main, - offset_cross, - ); - }}; - } + let offset_main = if main_start.val().is_some() + && main_end.val().is_some() + && margin + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + .val() + .is_none() + && margin + .main_axis_end(axis_info.dir, axis_info.main_dir_rev) + .val() + .is_none() + { + let main_start = main_start.val().unwrap_or(T::Length::zero()); + let main_end = main_end.val().unwrap_or(T::Length::zero()); + let free_space_main_size = container_size.main_size(axis_info.dir); - match (dir, main_dir_rev) { - (AxisDirection::Horizontal, AxisReverse::NotReversed) => { - axis!(left, right, top, bottom, width, height, x, y,); - } - (AxisDirection::Horizontal, AxisReverse::Reversed) => { - axis!(right, left, top, bottom, width, height, x, y,); - } - (AxisDirection::Vertical, AxisReverse::NotReversed) => { - axis!(top, bottom, left, right, height, width, y, x,); + if is_position_fixed { + main_start + (free_space_main_size - main_end - main_start).div_i32(2) + - result.size.0.main_size(axis_info.dir).div_i32(2) + } else { + main_start + (free_space_main_size - main_end - main_start).div_i32(2) + - parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + - result.size.0.main_size(axis_info.dir).div_i32(2) } - (AxisDirection::Vertical, AxisReverse::Reversed) => { - axis!(top, bottom, right, left, height, width, y, x,); - } - }; -} - -#[allow(clippy::too_many_arguments, clippy::type_complexity)] -pub(crate) fn compute_position_absolute( - env: &mut T::Env, - node: &T, - parent: ( - &ComputeResult, - &T::Style, - Normalized>, - Normalized>, - Edge, - Edge, - ), - dir: AxisDirection, - main_dir_rev: AxisReverse, - cross_dir_rev: AxisReverse, - accept_flex_props: bool, -) { - let ( - parent_node_result, - parent_style, - parent_inner_size, - parent_inner_option_size, - parent_border, - parent_padding_border, - ) = parent; - let mut layout_unit = node.layout_node().unit(); - let style = node.style(); - let container_width = parent_inner_size.width; - let container_height = parent_inner_size.height; - let left = style.left().resolve_num(parent_inner_size.width, node); - let right = style.right().resolve_num(parent_inner_size.width, node); - let top = style.top().resolve_num(parent_inner_size.height, node); - let bottom = style.bottom().resolve_num(parent_inner_size.height, node); - - let (margin, border, padding_border) = - layout_unit.margin_border_padding(node, *parent_inner_option_size); - let css_size = - layout_unit.css_border_box_size(node, *parent_inner_option_size, border, padding_border); - let width = css_size.width.or(if left.is_some() && right.is_some() { - OptionNum::some(container_width) - - left - - right - - margin.left.or_zero() - - margin.right.or_zero() - } else { - OptionNum::none() - }); - let height = css_size.height.or(if top.is_some() && bottom.is_some() { - OptionNum::some(container_height) - - top - - bottom - - margin.top.or_zero() - - margin.bottom.or_zero() } else { - OptionNum::none() - }); - let min_max_limit = layout_unit.normalized_min_max_limit( - node, - *parent_inner_option_size, - border, - padding_border, - ); - let size = min_max_limit.normalized_size(OptionSize::new(width, height)); - let max_content_width = size.width.unwrap_or( - container_width - - left.or_zero() - - right.or_zero() - - margin.left.or_zero() - - margin.right.or_zero(), - ); - let max_content_height = size.height.unwrap_or( - container_height - - top.or_zero() - - bottom.or_zero() - - margin.top.or_zero() - - margin.bottom.or_zero(), - ); - let max_content = min_max_limit.normalized_size(OptionSize::new( - OptionNum::some(max_content_width), - OptionNum::some(max_content_height), - )); - - let result = if size.width.is_none() || size.height.is_none() { - let auto_size = layout_unit - .compute_internal( - env, - node, - ComputeRequest { - size, - parent_inner_size: parent_inner_option_size, - max_content, - kind: ComputeRequestKind::AllSize, - parent_is_block: false, + let offset_main = if let Some(x) = main_start.val() { + if is_position_fixed { + x + } else { + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + x + } + } else if let Some(x) = main_end.val() { + if is_position_fixed { + free_space.main_size(axis_info.dir) - x + } else { + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.main_size(axis_info.dir) + - x + } + } else if accept_flex_props { + match parent.style.justify_content() { + JustifyContent::SpaceBetween + | JustifyContent::FlexStart + | JustifyContent::Start + | JustifyContent::Stretch + | JustifyContent::Baseline => parent + .padding_border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev), + JustifyContent::FlexEnd | JustifyContent::End => { + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.main_size(axis_info.dir) + - (parent + .padding_border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev) + - parent + .border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev)) + } + JustifyContent::Left => match axis_info.main_dir_rev { + AxisReverse::NotReversed => parent + .padding_border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev), + AxisReverse::Reversed => { + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.main_size(axis_info.dir) + - (parent + .padding_border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev) + - parent + .border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev)) + } }, - ) - .size; - layout_unit.compute_internal( - env, - node, - ComputeRequest { - size: Normalized(OptionSize::new( - OptionNum::some(auto_size.width), - OptionNum::some(auto_size.height), - )), - parent_inner_size: parent_inner_option_size, - max_content, - kind: ComputeRequestKind::Position, - parent_is_block: false, - }, - ) - } else { - layout_unit.compute_internal( - env, - node, - ComputeRequest { - size, - parent_inner_size: parent_inner_option_size, - max_content, - kind: ComputeRequestKind::Position, - parent_is_block: false, - }, - ) + JustifyContent::Right => match axis_info.main_dir_rev { + AxisReverse::NotReversed => { + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.main_size(axis_info.dir) + - (parent + .padding_border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev) + - parent + .border + .main_axis_end(axis_info.dir, axis_info.main_dir_rev)) + } + AxisReverse::Reversed => parent + .padding_border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev), + }, + JustifyContent::SpaceEvenly + | JustifyContent::SpaceAround + | JustifyContent::Center => { + let parent_padding = *parent.padding_border - *parent.border; + let free_content_main_size = parent_free_space.main_size(axis_info.dir) + - parent_padding.main_axis_start(axis_info.dir, axis_info.main_dir_rev) + - parent_padding.main_axis_end(axis_info.dir, axis_info.main_dir_rev); + parent + .border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_padding.main_axis_start(axis_info.dir, axis_info.main_dir_rev) + + free_content_main_size.div_i32(2) + } + } + } else { + parent + .padding_border + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + }; + let offset_main = if let Some(x) = margin + .main_axis_start(axis_info.dir, axis_info.main_dir_rev) + .val() + { + offset_main + x + } else if let Some(x) = margin + .main_axis_end(axis_info.dir, axis_info.main_dir_rev) + .val() + { + offset_main - x + } else { + offset_main + }; + offset_main }; - let free_space = *parent_inner_size - result.size.0; - macro_rules! axis { - ( - $main_start: ident, - $main_end: ident, - $cross_start: ident, - $cross_end: ident, - $main_size: ident, - $cross_size: ident, - $main_axis: ident, - $cross_axis: ident, - ) => {{ - let offset_main = if $main_start.val().is_some() - && $main_end.val().is_some() - && margin.$main_start.val().is_none() - && margin.$main_end.val().is_none() - { - let main_start = $main_start.val().unwrap_or(T::Length::zero()); - let main_end = $main_end.val().unwrap_or(T::Length::zero()); - let free_space_main_size = parent_inner_size.$main_size; - main_start + (free_space_main_size - main_end - main_start).div_i32(2) - - parent_border.$main_start - - result.size.0.$main_size.div_i32(2) + let offset_cross = if cross_end.val().is_some() + && cross_end.val().is_some() + && margin + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + .val() + .is_none() + && margin + .cross_axis_end(axis_info.dir, axis_info.main_dir_rev) + .val() + .is_none() + { + let cross_start = cross_start.val().unwrap_or(T::Length::zero()); + let cross_end = cross_end.val().unwrap_or(T::Length::zero()); + let free_space_cross_size = container_size.cross_size(axis_info.dir); + cross_start + (free_space_cross_size - cross_end - cross_start).div_i32(2) + - parent + .border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + - (result.size.0.cross_size(axis_info.dir).div_i32(2)) + } else { + let offset_cross = if let Some(x) = cross_start.val() { + if is_position_fixed { + x } else { - let offset_main = if let Some(x) = $main_start.val() { - parent_border.$main_start + x - } else if let Some(x) = $main_end.val() { - parent_border.$main_start + free_space.$main_size - x - } else if accept_flex_props { - match parent_style.justify_content() { - JustifyContent::SpaceBetween - | JustifyContent::FlexStart - | JustifyContent::Start - | JustifyContent::Stretch - | JustifyContent::Baseline => parent_padding_border.$main_start, - JustifyContent::FlexEnd | JustifyContent::End => { - parent_border.$main_start + free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - JustifyContent::Left => match main_dir_rev { - AxisReverse::NotReversed => parent_padding_border.$main_start, - AxisReverse::Reversed => { - parent_border.$main_start + free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - }, - JustifyContent::Right => match main_dir_rev { - AxisReverse::NotReversed => { - parent_border.$main_start + free_space.$main_size - - (parent_padding_border.$main_end - parent_border.$main_end) - } - AxisReverse::Reversed => parent_padding_border.$main_start, - }, - JustifyContent::SpaceEvenly - | JustifyContent::SpaceAround - | JustifyContent::Center => { - let parent_padding = parent_padding_border - parent_border; - let free_content_main_size = free_space.$main_size - - parent_padding.$main_start - - parent_padding.$main_end; - parent_border.$main_start - + parent_padding.$main_start - + free_content_main_size.div_i32(2) - } - } - } else { - parent_padding_border.$main_start - }; - let offset_main = if let Some(x) = margin.$main_start.val() { - offset_main + x - } else if let Some(x) = margin.$main_end.val() { - offset_main - x - } else { - offset_main - }; - offset_main - }; - - let offset_cross = if $cross_start.val().is_some() - && $cross_end.val().is_some() - && margin.$cross_start.val().is_none() - && margin.$cross_end.val().is_none() - { - let cross_start = $cross_start.val().unwrap_or(T::Length::zero()); - let cross_end = $cross_end.val().unwrap_or(T::Length::zero()); - let free_space_cross_size = parent_inner_size.$cross_size; - cross_start + (free_space_cross_size - cross_end - cross_start).div_i32(2) - - parent_border.$cross_start - - (result.size.0.$cross_size.div_i32(2)) + x + parent + .border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + } + } else if let Some(x) = cross_end.val() { + if is_position_fixed { + free_space.cross_size(axis_info.dir) - x } else { - let offset_cross = if let Some(x) = $cross_start.val() { - x + parent_border.$cross_start - } else if let Some(x) = $cross_end.val() { - parent_border.$cross_start + free_space.$cross_size - x - } else if accept_flex_props { - match algo::flex_box::align_self::(style, parent_style) { - AlignSelf::FlexStart - | AlignSelf::Start - | AlignSelf::SelfStart - | AlignSelf::Normal => parent_padding_border.$cross_start, - AlignSelf::FlexEnd | AlignSelf::End | AlignSelf::SelfEnd => { - parent_border.$cross_start + free_space.$cross_size - - (parent_padding_border.$cross_end - parent_border.$cross_end) - } - AlignSelf::Center => { - let parent_padding = parent_padding_border - parent_border; - let free_content_cross_size = free_space.$cross_size - - parent_padding.$cross_start - - parent_padding.$cross_end; - parent_border.$cross_start - + parent_padding.$cross_start - + free_content_cross_size.div_i32(2) - } - AlignSelf::Baseline => { - parent_node_result.first_baseline_ascent.$cross_axis - - result.first_baseline_ascent.$cross_axis - } - AlignSelf::Auto | AlignSelf::Stretch => parent_padding_border.$cross_start, - } - } else { - parent_padding_border.$cross_start - }; - let offset_cross = if let Some(x) = margin.$cross_start.val() { - offset_cross + x - } else if let Some(x) = margin.$cross_end.val() { - offset_cross - x - } else { - offset_cross - }; - offset_cross - }; - - layout_unit.gen_origin( - dir, - main_dir_rev, - cross_dir_rev, - *parent_inner_size, - offset_main, - offset_cross, - ); - }}; - } - - match (dir, main_dir_rev) { - (AxisDirection::Horizontal, AxisReverse::NotReversed) => { - axis!(left, right, top, bottom, width, height, x, y,); - } - (AxisDirection::Horizontal, AxisReverse::Reversed) => { - axis!(right, left, top, bottom, width, height, x, y,); - } - (AxisDirection::Vertical, AxisReverse::NotReversed) => { - axis!(top, bottom, left, right, height, width, y, x,); - } - (AxisDirection::Vertical, AxisReverse::Reversed) => { - axis!(top, bottom, right, left, height, width, y, x,); - } + parent + .border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.cross_size(axis_info.dir) + - x + } + } else if accept_flex_props { + match algo::flex_box::align_self::(style, parent.style) { + AlignSelf::FlexStart + | AlignSelf::Start + | AlignSelf::SelfStart + | AlignSelf::Normal => parent + .padding_border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev), + AlignSelf::FlexEnd | AlignSelf::End | AlignSelf::SelfEnd => { + parent + .border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_free_space.cross_size(axis_info.dir) + - (parent + .padding_border + .cross_axis_end(axis_info.dir, axis_info.main_dir_rev) + - parent + .border + .cross_axis_end(axis_info.dir, axis_info.main_dir_rev)) + } + AlignSelf::Center => { + let parent_padding = *parent.padding_border - *parent.border; + let free_content_cross_size = parent_free_space.cross_size(axis_info.dir) + - parent_padding.cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + - parent_padding.cross_axis_end(axis_info.dir, axis_info.main_dir_rev); + parent + .border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + + parent_padding.cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + + free_content_cross_size.div_i32(2) + } + AlignSelf::Baseline => { + parent + .compute_result + .first_baseline_ascent + .cross_axis(axis_info.dir) + - result.first_baseline_ascent.cross_axis(axis_info.dir) + } + AlignSelf::Auto | AlignSelf::Stretch => parent + .padding_border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev), + } + } else { + parent + .padding_border + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + }; + let offset_cross = if let Some(x) = margin + .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) + .val() + { + offset_cross + x + } else if let Some(x) = margin + .cross_axis_end(axis_info.dir, axis_info.main_dir_rev) + .val() + { + offset_cross - x + } else { + offset_cross + }; + offset_cross }; + + layout_unit.gen_origin( + axis_info.dir, + axis_info.main_dir_rev, + axis_info.cross_dir_rev, + **parent.inner_size, + offset_main, + offset_cross, + ); } pub(crate) fn compute_position_relative( From 89a6f85372d67885035a7fd8b7f8dfa61194f24f Mon Sep 17 00:00:00 2001 From: RomChung Date: Mon, 9 Dec 2024 15:47:01 +0800 Subject: [PATCH 2/4] refactor: better impl for axis info --- float-pigment-layout/src/algo/flex_box.rs | 10 ++-------- float-pigment-layout/src/algo/flow.rs | 14 ++++++++------ float-pigment-layout/src/special_positioned.rs | 9 +-------- float-pigment-layout/src/unit.rs | 10 ++++------ 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/float-pigment-layout/src/algo/flex_box.rs b/float-pigment-layout/src/algo/flex_box.rs index f52267d..5ebc4f7 100644 --- a/float-pigment-layout/src/algo/flex_box.rs +++ b/float-pigment-layout/src/algo/flex_box.rs @@ -1302,14 +1302,8 @@ impl FlexBox for LayoutUnit { .or_zero() } }; - let baseline_diff = child.gen_origin( - dir, - main_dir_rev, - cross_dir_rev, - *container_size, - offset_main, - offset_cross, - ); + let baseline_diff = + child.gen_origin(axis_info, *container_size, offset_main, offset_cross); if self_first_baseline_ascent.is_none() { self_first_baseline_ascent = Some(flex_child.first_baseline_ascent + baseline_diff); diff --git a/float-pigment-layout/src/algo/flow.rs b/float-pigment-layout/src/algo/flow.rs index 238e86e..8a43363 100644 --- a/float-pigment-layout/src/algo/flow.rs +++ b/float-pigment-layout/src/algo/flow.rs @@ -492,9 +492,10 @@ impl Flow for LayoutUnit { .or_zero() }; let baseline_diff = child.gen_origin( - axis_info.dir, - axis_info.main_dir_rev, - AxisReverse::NotReversed, + AxisInfo { + cross_dir_rev: AxisReverse::NotReversed, + ..axis_info + }, node_inner_size.or_zero(), main_offset, cross_offset, @@ -617,9 +618,10 @@ impl Flow for LayoutUnit { child.result = Rect::new(Point::zero(), child_res.size); child.cache.touch(child_node); child.gen_origin( - axis_info.dir, - axis_info.main_dir_rev, - AxisReverse::NotReversed, + AxisInfo { + cross_dir_rev: AxisReverse::NotReversed, + ..axis_info + }, node_inner_size.or_zero(), main_offset + child_origin.main_axis(axis_info.dir), cross_offset + child_origin.cross_axis(axis_info.dir), diff --git a/float-pigment-layout/src/special_positioned.rs b/float-pigment-layout/src/special_positioned.rs index ce13c32..d43b616 100644 --- a/float-pigment-layout/src/special_positioned.rs +++ b/float-pigment-layout/src/special_positioned.rs @@ -454,14 +454,7 @@ pub(crate) fn compute_special_position( offset_cross }; - layout_unit.gen_origin( - axis_info.dir, - axis_info.main_dir_rev, - axis_info.cross_dir_rev, - **parent.inner_size, - offset_main, - offset_cross, - ); + layout_unit.gen_origin(axis_info, **parent.inner_size, offset_main, offset_cross); } pub(crate) fn compute_position_relative( diff --git a/float-pigment-layout/src/unit.rs b/float-pigment-layout/src/unit.rs index 7665101..be694eb 100644 --- a/float-pigment-layout/src/unit.rs +++ b/float-pigment-layout/src/unit.rs @@ -646,16 +646,14 @@ impl LayoutUnit { #[inline] pub(crate) fn gen_origin( &mut self, - dir: AxisDirection, - main_dir_rev: AxisReverse, - cross_dir_rev: AxisReverse, + axis_info: AxisInfo, parent_size: Size, offset_main: T::Length, offset_cross: T::Length, ) -> Vector { - let (width, height, width_rev, height_rev) = match dir { - AxisDirection::Horizontal => (offset_main, offset_cross, main_dir_rev, cross_dir_rev), - AxisDirection::Vertical => (offset_cross, offset_main, cross_dir_rev, main_dir_rev), + let (width, height, width_rev, height_rev) = match axis_info.dir { + AxisDirection::Horizontal => (offset_main, offset_cross, axis_info.main_dir_rev, axis_info.cross_dir_rev), + AxisDirection::Vertical => (offset_cross, offset_main, axis_info.cross_dir_rev, axis_info.main_dir_rev), }; let width = match width_rev { AxisReverse::NotReversed => width, From c3fb90a00df7433ceac251474f7c56b345934bc2 Mon Sep 17 00:00:00 2001 From: RomChung Date: Mon, 9 Dec 2024 16:29:58 +0800 Subject: [PATCH 3/4] refactor: better impl for axis info --- float-pigment-layout/src/algo/flex_box.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/float-pigment-layout/src/algo/flex_box.rs b/float-pigment-layout/src/algo/flex_box.rs index 5ebc4f7..be302e5 100644 --- a/float-pigment-layout/src/algo/flex_box.rs +++ b/float-pigment-layout/src/algo/flex_box.rs @@ -1302,8 +1302,16 @@ impl FlexBox for LayoutUnit { .or_zero() } }; - let baseline_diff = - child.gen_origin(axis_info, *container_size, offset_main, offset_cross); + let baseline_diff = child.gen_origin( + AxisInfo { + main_dir_rev, + cross_dir_rev, + dir, + }, + *container_size, + offset_main, + offset_cross, + ); if self_first_baseline_ascent.is_none() { self_first_baseline_ascent = Some(flex_child.first_baseline_ascent + baseline_diff); From c9ee263b69279c63398b7a0054944bec6d0cc138 Mon Sep 17 00:00:00 2001 From: RomChung Date: Mon, 9 Dec 2024 16:30:55 +0800 Subject: [PATCH 4/4] refactor: special position layout --- .../src/special_positioned.rs | 86 +++++++++---------- float-pigment-layout/src/unit.rs | 14 ++- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/float-pigment-layout/src/special_positioned.rs b/float-pigment-layout/src/special_positioned.rs index d43b616..b27e93a 100644 --- a/float-pigment-layout/src/special_positioned.rs +++ b/float-pigment-layout/src/special_positioned.rs @@ -46,42 +46,21 @@ pub(crate) fn compute_special_position_children( child.clear_display_none_result(child_node); return; } - match child_style.position() { - Position::Absolute | Position::Sticky => compute_special_position( - env, - child_node, - ParentInfo { - compute_result: node_result, - style, - inner_size: &node_inner_size, - inner_option_size: &node_inner_option_size, - border: &border, - padding_border: &padding_border, - }, - axis_info, - accept_flex_props, - false, - ), - Position::Fixed => compute_special_position( - env, - child_node, - ParentInfo { - compute_result: node_result, - style, - inner_size: &node_inner_size, - inner_option_size: &node_inner_option_size, - border: &border, - padding_border: &padding_border, - }, - axis_info, - accept_flex_props, - true, - ), - Position::Static => {} - Position::Relative => { - compute_position_relative(child_node, node_inner_size); - } - } + compute_special_position( + env, + child_node, + ParentInfo { + compute_result: node_result, + style, + inner_size: &node_inner_size, + inner_option_size: &node_inner_option_size, + border: &border, + padding_border: &padding_border, + }, + axis_info, + accept_flex_props, + child_style.position(), + ); }; node.tree_visitor() .for_each_child(|child_node, _| f(child_node)); @@ -96,23 +75,27 @@ pub(crate) struct ParentInfo<'a, T: LayoutTreeNode> { pub(crate) padding_border: &'a Edge, } +#[inline] pub(crate) fn compute_special_position( env: &mut T::Env, node: &T, parent: ParentInfo, axis_info: AxisInfo, accept_flex_props: bool, - is_position_fixed: bool, + position: Position, ) { + if position == Position::Static { + return; + } let mut layout_unit = node.layout_node().unit(); let style = node.style(); - let container_size = if is_position_fixed { + let container_size = if position == Position::Fixed { Size::new(env.screen_width(), env.screen_height()) } else { **parent.inner_size }; - let container_option_size = if is_position_fixed { + let container_option_size = if position == Position::Fixed { Normalized(OptionSize::new( OptionNum::some(container_size.width), OptionNum::some(container_size.height), @@ -125,6 +108,21 @@ pub(crate) fn compute_special_position( let right = style.right().resolve_num(container_size.width, node); let top = style.top().resolve_num(container_size.height, node); let bottom = style.bottom().resolve_num(container_size.height, node); + + if position == Position::Relative { + if let Some(left) = left.val() { + layout_unit.result.origin.x += left; + } else if let Some(right) = right.val() { + layout_unit.result.origin.x -= right; + } + if let Some(top) = top.val() { + layout_unit.result.origin.y += top; + } else if let Some(bottom) = bottom.val() { + layout_unit.result.origin.y -= bottom; + } + return; + } + let (margin, border, padding_border) = layout_unit.margin_border_padding(node, *container_option_size); let css_size = @@ -233,7 +231,7 @@ pub(crate) fn compute_special_position( let main_end = main_end.val().unwrap_or(T::Length::zero()); let free_space_main_size = container_size.main_size(axis_info.dir); - if is_position_fixed { + if position == Position::Fixed { main_start + (free_space_main_size - main_end - main_start).div_i32(2) - result.size.0.main_size(axis_info.dir).div_i32(2) } else { @@ -245,7 +243,7 @@ pub(crate) fn compute_special_position( } } else { let offset_main = if let Some(x) = main_start.val() { - if is_position_fixed { + if position == Position::Fixed { x } else { parent @@ -254,7 +252,7 @@ pub(crate) fn compute_special_position( + x } } else if let Some(x) = main_end.val() { - if is_position_fixed { + if position == Position::Fixed { free_space.main_size(axis_info.dir) - x } else { parent @@ -374,7 +372,7 @@ pub(crate) fn compute_special_position( - (result.size.0.cross_size(axis_info.dir).div_i32(2)) } else { let offset_cross = if let Some(x) = cross_start.val() { - if is_position_fixed { + if position == Position::Fixed { x } else { x + parent @@ -382,7 +380,7 @@ pub(crate) fn compute_special_position( .cross_axis_start(axis_info.dir, axis_info.main_dir_rev) } } else if let Some(x) = cross_end.val() { - if is_position_fixed { + if position == Position::Fixed { free_space.cross_size(axis_info.dir) - x } else { parent diff --git a/float-pigment-layout/src/unit.rs b/float-pigment-layout/src/unit.rs index be694eb..c3ac0b4 100644 --- a/float-pigment-layout/src/unit.rs +++ b/float-pigment-layout/src/unit.rs @@ -652,8 +652,18 @@ impl LayoutUnit { offset_cross: T::Length, ) -> Vector { let (width, height, width_rev, height_rev) = match axis_info.dir { - AxisDirection::Horizontal => (offset_main, offset_cross, axis_info.main_dir_rev, axis_info.cross_dir_rev), - AxisDirection::Vertical => (offset_cross, offset_main, axis_info.cross_dir_rev, axis_info.main_dir_rev), + AxisDirection::Horizontal => ( + offset_main, + offset_cross, + axis_info.main_dir_rev, + axis_info.cross_dir_rev, + ), + AxisDirection::Vertical => ( + offset_cross, + offset_main, + axis_info.cross_dir_rev, + axis_info.main_dir_rev, + ), }; let width = match width_rev { AxisReverse::NotReversed => width,