diff --git a/benches/src/yoga_helpers.rs b/benches/src/yoga_helpers.rs index f91280dee..83b82d5fa 100644 --- a/benches/src/yoga_helpers.rs +++ b/benches/src/yoga_helpers.rs @@ -202,6 +202,7 @@ fn apply_taffy_style(node: &mut yg::Node, style: &tf::Style) { // position node.set_position_type(match style.position { + tf::Position::Static => yg::PositionType::Static, tf::Position::Relative => yg::PositionType::Relative, tf::Position::Absolute => yg::PositionType::Absolute, }); diff --git a/src/compute/block.rs b/src/compute/block.rs index 64792de93..fe159dd57 100644 --- a/src/compute/block.rs +++ b/src/compute/block.rs @@ -174,13 +174,13 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: start: vertical_margins_are_collapsible.start && !style.overflow().x.is_scroll_container() && !style.overflow().y.is_scroll_container() - && style.position() == Position::Relative + && style.position().is_in_flow() && padding.top == 0.0 && border.top == 0.0, end: vertical_margins_are_collapsible.end && !style.overflow().x.is_scroll_container() && !style.overflow().y.is_scroll_container() - && style.position() == Position::Relative + && style.position().is_in_flow() && padding.bottom == 0.0 && border.bottom == 0.0 && size.height.is_none(), @@ -188,7 +188,7 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: let has_styles_preventing_being_collapsed_through = !style.is_block() || style.overflow().x.is_scroll_container() || style.overflow().y.is_scroll_container() - || style.position() == Position::Absolute + || style.position().is_out_of_flow() || padding.top > 0.0 || padding.bottom > 0.0 || border.top > 0.0 @@ -267,7 +267,7 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: // 7. Determine whether this node can be collapsed through let all_in_flow_children_can_be_collapsed_through = - items.iter().all(|item| item.position == Position::Absolute || item.can_be_collapsed_through); + items.iter().all(|item| item.position.is_out_of_flow() || item.can_be_collapsed_through); let can_be_collapsed_through = !has_styles_preventing_being_collapsed_through && all_in_flow_children_can_be_collapsed_through; @@ -361,7 +361,7 @@ fn determine_content_based_container_width( let available_space = Size { width: available_width, height: AvailableSpace::MinContent }; let mut max_child_width = 0.0; - for item in items.iter().filter(|item| item.position != Position::Absolute) { + for item in items.iter().filter(|item| item.position.is_in_flow()) { let known_dimensions = item.size.maybe_clamp(item.min_size, item.max_size); let width = known_dimensions.width.unwrap_or_else(|| { @@ -413,7 +413,7 @@ fn perform_final_layout_on_in_flow_children( let mut active_collapsible_margin_set = CollapsibleMarginSet::ZERO; let mut is_collapsing_with_first_margin_set = true; for item in items.iter_mut() { - if item.position == Position::Absolute { + if item.position.is_out_of_flow() { item.static_position = Point { x: resolved_content_box_inset.left, y: y_offset_for_absolute } } else { let item_margin = item @@ -490,11 +490,17 @@ fn perform_final_layout_on_in_flow_children( x: resolved_content_box_inset.left, y: committed_y_offset + active_collapsible_margin_set.resolve(), }; + let mut location = Point { - x: resolved_content_box_inset.left + inset_offset.x + resolved_margin.left, - y: committed_y_offset + inset_offset.y + y_margin_offset, + x: resolved_content_box_inset.left + resolved_margin.left, + y: committed_y_offset + y_margin_offset, }; + if item.position == Position::Relative { + location.x += inset_offset.x; + location.y += inset_offset.y; + } + // Apply alignment let item_outer_width = item_layout.size.width + resolved_margin.horizontal_axis_sum(); if item_outer_width < container_inner_width { @@ -589,12 +595,11 @@ fn perform_absolute_layout_on_absolute_children( #[cfg_attr(not(feature = "content_size"), allow(unused_mut))] let mut absolute_content_size = Size::ZERO; - for item in items.iter().filter(|item| item.position == Position::Absolute) { + for item in items.iter().filter(|item| item.position.is_out_of_flow()) { let child_style = tree.get_block_child_style(item.node_id); // Skip items that are display:none or are not position:absolute - if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute - { + if child_style.box_generation_mode() == BoxGenerationMode::None { continue; } diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index 2cf25ae4b..7ad8e48eb 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -3,7 +3,6 @@ use crate::compute::common::alignment::compute_alignment_offset; use crate::geometry::{Line, Point, Rect, Size}; use crate::style::{ AlignContent, AlignItems, AlignSelf, AvailableSpace, FlexWrap, JustifyContent, LengthPercentageAuto, Overflow, - Position, }; use crate::style::{CoreStyle, FlexDirection, FlexboxContainerStyle, FlexboxItemStyle}; use crate::style_helpers::{TaffyMaxContent, TaffyMinContent}; @@ -13,7 +12,7 @@ use crate::util::debug::debug_log; use crate::util::sys::{f32_max, new_vec_with_capacity, Vec}; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; -use crate::{BoxGenerationMode, BoxSizing}; +use crate::{BoxGenerationMode, BoxSizing, Position}; use super::common::alignment::apply_alignment_fallback; #[cfg(feature = "content_size")] @@ -36,6 +35,9 @@ struct FlexItem { /// The cross-alignment of this item align_self: AlignSelf, + /// The position style of the item + position: Position, + /// The overflow style of the item overflow: Point, /// The width of the scrollbars (if it has any) @@ -502,7 +504,7 @@ fn generate_anonymous_flex_items( tree.child_ids(node) .enumerate() .map(|(index, child)| (index, child, tree.get_flexbox_child_style(child))) - .filter(|(_, _, style)| style.position() != Position::Absolute) + .filter(|(_, _, style)| style.position().is_in_flow()) .filter(|(_, _, style)| style.box_generation_mode() != BoxGenerationMode::None) .map(|(index, child, child_style)| { let aspect_ratio = child_style.aspect_ratio(); @@ -518,6 +520,7 @@ fn generate_anonymous_flex_items( FlexItem { node: child, order: index as u32, + position: child_style.position(), size: child_style .size() .maybe_resolve(constants.node_inner_size, |val, basis| tree.calc(val, basis)) @@ -1903,16 +1906,17 @@ fn calculate_flex_item( .. } = layout_output; - let offset_main = *total_offset_main - + item.offset_main - + item.margin.main_start(direction) - + (item.inset.main_start(direction).or(item.inset.main_end(direction).map(|pos| -pos)).unwrap_or(0.0)); + let mut offset_main = *total_offset_main + item.offset_main + item.margin.main_start(direction); + + let mut offset_cross = + total_offset_cross + item.offset_cross + line_offset_cross + item.margin.cross_start(direction); - let offset_cross = total_offset_cross - + item.offset_cross - + line_offset_cross - + item.margin.cross_start(direction) - + (item.inset.cross_start(direction).or(item.inset.cross_end(direction).map(|pos| -pos)).unwrap_or(0.0)); + if item.position == Position::Relative { + offset_main += + item.inset.main_start(direction).or(item.inset.main_end(direction).map(|pos| -pos)).unwrap_or(0.0); + offset_cross += + item.inset.cross_start(direction).or(item.inset.cross_end(direction).map(|pos| -pos)).unwrap_or(0.0); + } if direction.is_row() { let baseline_offset_cross = total_offset_cross + item.offset_cross + item.margin.cross_start(direction); @@ -2075,8 +2079,7 @@ fn perform_absolute_layout_on_absolute_children( let child_style = tree.get_flexbox_child_style(child); // Skip items that are display:none or are not position:absolute - if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute - { + if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position().is_in_flow() { continue; } diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs index 9ec256adb..a1b2f9b22 100644 --- a/src/compute/grid/alignment.rs +++ b/src/compute/grid/alignment.rs @@ -146,7 +146,7 @@ pub(super) fn align_and_position_item( let width = inherent_size.width.or_else(|| { // Apply width derived from both the left and right properties of an absolutely // positioned element being set - if position == Position::Absolute { + if position.is_out_of_flow() { if let (Some(left), Some(right)) = (inset_horizontal.start, inset_horizontal.end) { return Some(f32_max(grid_area_minus_item_margins_size.width - left - right, 0.0)); } @@ -159,7 +159,7 @@ pub(super) fn align_and_position_item( if margin.left.is_some() && margin.right.is_some() && alignment_styles.horizontal == AlignSelf::Stretch - && position != Position::Absolute + && position.is_in_flow() { return Some(grid_area_minus_item_margins_size.width); } @@ -171,7 +171,7 @@ pub(super) fn align_and_position_item( let Size { width, height } = Size { width, height: inherent_size.height }.maybe_apply_aspect_ratio(aspect_ratio); let height = height.or_else(|| { - if position == Position::Absolute { + if position.is_out_of_flow() { if let (Some(top), Some(bottom)) = (inset_vertical.start, inset_vertical.end) { return Some(f32_max(grid_area_minus_item_margins_size.height - top - bottom, 0.0)); } @@ -184,7 +184,7 @@ pub(super) fn align_and_position_item( if margin.top.is_some() && margin.bottom.is_some() && alignment_styles.vertical == AlignSelf::Stretch - && position != Position::Absolute + && position.is_in_flow() { return Some(grid_area_minus_item_margins_size.height); } @@ -309,7 +309,7 @@ pub(super) fn align_item_within_area( AlignSelf::Stretch => resolved_margin.start, }; - let offset_within_area = if position == Position::Absolute { + let offset_within_area = if position.is_out_of_flow() { if let Some(start) = inset.start { start + non_auto_margin.start } else if let Some(end) = inset.end { diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs index a9a3ab089..a5f7a2865 100644 --- a/src/compute/grid/mod.rs +++ b/src/compute/grid/mod.rs @@ -2,7 +2,7 @@ //! use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis}; use crate::geometry::{Line, Point, Rect, Size}; -use crate::style::{AlignItems, AlignSelf, AvailableSpace, Overflow, Position}; +use crate::style::{AlignItems, AlignSelf, AvailableSpace, Overflow}; use crate::tree::{Layout, LayoutInput, LayoutOutput, LayoutPartialTreeExt, NodeId, RunMode, SizingMode}; use crate::util::debug::debug_log; use crate::util::sys::{f32_max, GridTrackVec, Vec}; @@ -202,7 +202,7 @@ pub fn compute_grid_layout( .enumerate() .map(|(index, child_node)| (index, child_node, tree.get_grid_child_style(child_node))) .filter(|(_, _, style)| { - style.box_generation_mode() != BoxGenerationMode::None && style.position() != Position::Absolute + style.box_generation_mode() != BoxGenerationMode::None && style.position().is_in_flow() }) }; place_grid_items( @@ -548,7 +548,7 @@ pub fn compute_grid_layout( } // Position absolutely positioned child - if child_style.position() == Position::Absolute { + if child_style.position().is_out_of_flow() { // Convert grid-col-{start/end} into Option's of indexes into the columns vector // The Option is None if the style property is Auto and an unresolvable Span let maybe_col_indexes = name_resolver diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs index 4f1d979cd..33b93d40c 100644 --- a/src/compute/leaf.rs +++ b/src/compute/leaf.rs @@ -1,7 +1,7 @@ //! Computes size using styles and measure functions use crate::geometry::{Point, Size}; -use crate::style::{AvailableSpace, Overflow, Position}; +use crate::style::{AvailableSpace, Overflow}; use crate::tree::{CollapsibleMarginSet, RunMode}; use crate::tree::{LayoutInput, LayoutOutput, SizingMode}; use crate::util::debug::debug_log; @@ -76,7 +76,7 @@ where let has_styles_preventing_being_collapsed_through = !style.is_block() || style.overflow().x.is_scroll_container() || style.overflow().y.is_scroll_container() - || style.position() == Position::Absolute + || style.position().is_out_of_flow() || padding.top > 0.0 || padding.bottom > 0.0 || border.top > 0.0 diff --git a/src/style/mod.rs b/src/style/mod.rs index e44d06b74..c9c0581d8 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -254,6 +254,8 @@ impl Default for BoxGenerationMode { #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Position { + /// Offets are not applied + Static, /// The offset is computed relative to the final position given by the layout algorithm. /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end. Relative, @@ -271,6 +273,26 @@ impl Default for Position { } } +impl Position { + /// Whether the element has a non-static position + #[inline(always)] + pub fn is_positioned(self) -> bool { + !matches!(self, Self::Static) + } + + /// Whether the element is positioned out-of-flow (absolute or fixed position) + #[inline(always)] + pub fn is_out_of_flow(self) -> bool { + matches!(self, Self::Absolute) + } + + /// Whether the element is positioned in-flow (NOT absolute or fixed position) + #[inline(always)] + pub fn is_in_flow(self) -> bool { + !self.is_out_of_flow() + } +} + /// Specifies whether size styles for this node are assigned to the node's "content box" or "border box" /// /// - The "content box" is the node's inner size excluding padding, border and margin