diff options
Diffstat (limited to 'components/layout/taffy')
-rw-r--r-- | components/layout/taffy/layout.rs | 663 | ||||
-rw-r--r-- | components/layout/taffy/mod.rs | 184 | ||||
-rw-r--r-- | components/layout/taffy/stylo_taffy/convert.rs | 347 | ||||
-rw-r--r-- | components/layout/taffy/stylo_taffy/mod.rs | 9 | ||||
-rw-r--r-- | components/layout/taffy/stylo_taffy/wrapper.rs | 226 |
5 files changed, 1429 insertions, 0 deletions
diff --git a/components/layout/taffy/layout.rs b/components/layout/taffy/layout.rs new file mode 100644 index 00000000000..a7581136bf2 --- /dev/null +++ b/components/layout/taffy/layout.rs @@ -0,0 +1,663 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use app_units::Au; +use atomic_refcell::{AtomicRef, AtomicRefCell}; +use style::Zero; +use style::properties::ComputedValues; +use style::values::specified::align::AlignFlags; +use style::values::specified::box_::DisplayInside; +use taffy::style_helpers::{TaffyMaxContent, TaffyMinContent}; +use taffy::{AvailableSpace, MaybeMath, RequestedAxis, RunMode}; + +use super::{ + SpecificTaffyGridInfo, TaffyContainer, TaffyItemBox, TaffyItemBoxInner, TaffyStyloStyle, +}; +use crate::cell::ArcRefCell; +use crate::context::LayoutContext; +use crate::formatting_contexts::{ + Baselines, IndependentFormattingContext, IndependentFormattingContextContents, +}; +use crate::fragment_tree::{ + BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo, +}; +use crate::geom::{ + LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size, SizeConstraint, + Sizes, +}; +use crate::layout_box_base::CacheableLayoutResult; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; +use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; +use crate::style_ext::{ComputedValuesExt, LayoutStyle}; +use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize}; + +const DUMMY_NODE_ID: taffy::NodeId = taffy::NodeId::new(u64::MAX); + +fn resolve_content_size(constraint: AvailableSpace, content_sizes: ContentSizes) -> f32 { + match constraint { + AvailableSpace::Definite(limit) => { + let min = content_sizes.min_content.to_f32_px(); + let max = content_sizes.max_content.to_f32_px(); + limit.min(max).max(min) + }, + AvailableSpace::MinContent => content_sizes.min_content.to_f32_px(), + AvailableSpace::MaxContent => content_sizes.max_content.to_f32_px(), + } +} + +#[inline(always)] +fn with_independant_formatting_context<T>( + item: &mut TaffyItemBoxInner, + cb: impl FnOnce(&IndependentFormattingContext) -> T, +) -> T { + match item { + TaffyItemBoxInner::InFlowBox(context) => cb(context), + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abspos_box) => { + cb(&AtomicRefCell::borrow(abspos_box).context) + }, + } +} + +/// Layout parameters and intermediate results about a taffy container, +/// grouped to avoid passing around many parameters +struct TaffyContainerContext<'a> { + source_child_nodes: &'a [ArcRefCell<TaffyItemBox>], + layout_context: &'a LayoutContext<'a>, + positioning_context: &'a mut PositioningContext, + content_box_size_override: &'a ContainingBlock<'a>, + style: &'a ComputedValues, + specific_layout_info: Option<SpecificLayoutInfo>, + + /// Temporary location for children specific info, which will be moved into child fragments + child_specific_layout_infos: Vec<Option<SpecificLayoutInfo>>, +} + +struct ChildIter(std::ops::Range<usize>); +impl Iterator for ChildIter { + type Item = taffy::NodeId; + fn next(&mut self) -> Option<Self::Item> { + self.0.next().map(taffy::NodeId::from) + } +} + +impl taffy::TraversePartialTree for TaffyContainerContext<'_> { + type ChildIter<'a> + = ChildIter + where + Self: 'a; + + fn child_ids(&self, _node_id: taffy::NodeId) -> Self::ChildIter<'_> { + ChildIter(0..self.source_child_nodes.len()) + } + + fn child_count(&self, _node_id: taffy::NodeId) -> usize { + self.source_child_nodes.len() + } + + fn get_child_id(&self, _node_id: taffy::NodeId, index: usize) -> taffy::NodeId { + taffy::NodeId::from(index) + } +} + +impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { + type CoreContainerStyle<'a> + = TaffyStyloStyle<&'a ComputedValues> + where + Self: 'a; + + fn get_core_container_style(&self, _node_id: taffy::NodeId) -> Self::CoreContainerStyle<'_> { + TaffyStyloStyle(self.style) + } + + fn set_unrounded_layout(&mut self, node_id: taffy::NodeId, layout: &taffy::Layout) { + let id = usize::from(node_id); + (*self.source_child_nodes[id]).borrow_mut().taffy_layout = *layout; + } + + fn compute_child_layout( + &mut self, + node_id: taffy::NodeId, + inputs: taffy::LayoutInput, + ) -> taffy::LayoutOutput { + let mut child = (*self.source_child_nodes[usize::from(node_id)]).borrow_mut(); + let child = &mut *child; + + fn option_f32_to_size(input: Option<f32>) -> Size<Au> { + match input { + None => Size::Initial, + Some(length) => Size::Numeric(Au::from_f32_px(length)), + } + } + + with_independant_formatting_context( + &mut child.taffy_level_box, + |independent_context| -> taffy::LayoutOutput { + // TODO: re-evaluate sizing constraint conversions in light of recent layout changes + let containing_block = &self.content_box_size_override; + let style = independent_context.style(); + + // Adjust known_dimensions from border box to content box + let pbm = independent_context + .layout_style() + .padding_border_margin(containing_block); + let pb_sum = pbm.padding_border_sums.map(|v| v.to_f32_px()); + let margin_sum = pbm.margin.auto_is(Au::zero).sum().map(|v| v.to_f32_px()); + let content_box_inset = pb_sum + margin_sum; + let content_box_known_dimensions = taffy::Size { + width: inputs + .known_dimensions + .width + .map(|width| width - pb_sum.inline), + height: inputs + .known_dimensions + .height + .map(|height| height - pb_sum.block), + }; + + match &independent_context.contents { + IndependentFormattingContextContents::Replaced(replaced) => { + let content_box_size = replaced + .used_size_as_if_inline_element_from_content_box_sizes( + containing_block, + style, + independent_context + .preferred_aspect_ratio(&pbm.padding_border_sums), + LogicalVec2 { + block: &Sizes::new( + option_f32_to_size(content_box_known_dimensions.height), + Size::Initial, + Size::Initial, + ), + inline: &Sizes::new( + option_f32_to_size(content_box_known_dimensions.width), + Size::Initial, + Size::Initial, + ), + }, + Size::FitContent.into(), + pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum(), + ) + .to_physical_size(self.style.writing_mode); + + // Create fragments if the RunMode if PerformLayout + // If the RunMode is ComputeSize then only the returned size will be used + if inputs.run_mode == RunMode::PerformLayout { + child.child_fragments = replaced.make_fragments( + self.layout_context, + style, + content_box_size, + ); + } + + let computed_size = taffy::Size { + width: inputs.known_dimensions.width.unwrap_or_else(|| { + content_box_size.width.to_f32_px() + pb_sum.inline + }), + height: inputs.known_dimensions.height.unwrap_or_else(|| { + content_box_size.height.to_f32_px() + pb_sum.block + }), + }; + let size = inputs.known_dimensions.unwrap_or(computed_size); + taffy::LayoutOutput { + size, + ..taffy::LayoutOutput::DEFAULT + } + }, + + IndependentFormattingContextContents::NonReplaced(non_replaced) => { + // Compute inline size + let inline_size = content_box_known_dimensions.width.unwrap_or_else(|| { + let constraint_space = ConstraintSpace { + // TODO: pass min- and max- size + block_size: SizeConstraint::new( + inputs.parent_size.height.map(Au::from_f32_px), + Au::zero(), + None, + ), + writing_mode: self.style.writing_mode, + preferred_aspect_ratio: non_replaced.preferred_aspect_ratio(), + }; + + let result = independent_context + .inline_content_sizes(self.layout_context, &constraint_space); + let adjusted_available_space = inputs + .available_space + .width + .map_definite_value(|width| width - content_box_inset.inline); + + resolve_content_size(adjusted_available_space, result.sizes) + }); + + // Return early if only inline content sizes are requested + if inputs.run_mode == RunMode::ComputeSize && + inputs.axis == RequestedAxis::Horizontal + { + return taffy::LayoutOutput::from_outer_size(taffy::Size { + width: inline_size + pb_sum.inline, + // If RequestedAxis is Horizontal then height will be ignored. + height: 0.0, + }); + } + + let content_box_size_override = ContainingBlock { + size: ContainingBlockSize { + inline: Au::from_f32_px(inline_size), + block: content_box_known_dimensions + .height + .map(Au::from_f32_px) + .map_or_else(SizeConstraint::default, SizeConstraint::Definite), + }, + style, + }; + let layout = { + let mut child_positioning_context = + PositioningContext::new_for_style(style).unwrap_or_else(|| { + PositioningContext::new_for_subtree( + self.positioning_context + .collects_for_nearest_positioned_ancestor(), + ) + }); + + let layout = non_replaced.layout_without_caching( + self.layout_context, + &mut child_positioning_context, + &content_box_size_override, + containing_block, + false, /* depends_on_block_constraints */ + ); + + // Store layout data on child for later access + child.positioning_context = child_positioning_context; + + layout + }; + + child.child_fragments = layout.fragments; + self.child_specific_layout_infos[usize::from(node_id)] = + layout.specific_layout_info; + + let block_size = layout.content_block_size.to_f32_px(); + + let computed_size = taffy::Size { + width: inline_size + pb_sum.inline, + height: block_size + pb_sum.block, + }; + let size = inputs.known_dimensions.unwrap_or(computed_size); + + taffy::LayoutOutput { + size, + first_baselines: taffy::Point { + x: None, + y: layout.baselines.first.map(|au| au.to_f32_px()), + }, + ..taffy::LayoutOutput::DEFAULT + } + }, + } + }, + ) + } +} + +impl taffy::LayoutGridContainer for TaffyContainerContext<'_> { + type GridContainerStyle<'a> + = TaffyStyloStyle<&'a ComputedValues> + where + Self: 'a; + + type GridItemStyle<'a> + = TaffyStyloStyle<AtomicRef<'a, ComputedValues>> + where + Self: 'a; + + fn get_grid_container_style( + &self, + _node_id: taffy::prelude::NodeId, + ) -> Self::GridContainerStyle<'_> { + TaffyStyloStyle(self.style) + } + + fn get_grid_child_style( + &self, + child_node_id: taffy::prelude::NodeId, + ) -> Self::GridItemStyle<'_> { + let id = usize::from(child_node_id); + let child = (*self.source_child_nodes[id]).borrow(); + TaffyStyloStyle(AtomicRef::map(child, |c| &*c.style)) + } + + fn set_detailed_grid_info( + &mut self, + _node_id: taffy::NodeId, + specific_layout_info: taffy::DetailedGridInfo, + ) { + self.specific_layout_info = Some(SpecificLayoutInfo::Grid(Box::new( + SpecificTaffyGridInfo::from_detailed_grid_layout(specific_layout_info), + ))); + } +} + +impl ComputeInlineContentSizes for TaffyContainer { + fn compute_inline_content_sizes( + &self, + layout_context: &LayoutContext, + _constraint_space: &ConstraintSpace, + ) -> InlineContentSizesResult { + let style = &self.style; + + let max_content_inputs = taffy::LayoutInput { + run_mode: taffy::RunMode::ComputeSize, + sizing_mode: taffy::SizingMode::InherentSize, + axis: taffy::RequestedAxis::Horizontal, + vertical_margins_are_collapsible: taffy::Line::FALSE, + + known_dimensions: taffy::Size::NONE, + parent_size: taffy::Size::NONE, + available_space: taffy::Size::MAX_CONTENT, + }; + + let min_content_inputs = taffy::LayoutInput { + available_space: taffy::Size::MIN_CONTENT, + ..max_content_inputs + }; + + let containing_block = &ContainingBlock { + size: ContainingBlockSize { + inline: Au::zero(), + block: SizeConstraint::default(), + }, + style, + }; + + let mut grid_context = TaffyContainerContext { + layout_context, + positioning_context: + &mut PositioningContext::new_for_containing_block_for_all_descendants(), + content_box_size_override: containing_block, + style, + source_child_nodes: &self.children, + specific_layout_info: None, + child_specific_layout_infos: vec![None; self.children.len()], + }; + + let (max_content_output, min_content_output) = match style.clone_display().inside() { + DisplayInside::Grid => { + let max_content_output = taffy::compute_grid_layout( + &mut grid_context, + DUMMY_NODE_ID, + max_content_inputs, + ); + let min_content_output = taffy::compute_grid_layout( + &mut grid_context, + DUMMY_NODE_ID, + min_content_inputs, + ); + (max_content_output, min_content_output) + }, + _ => panic!("Servo is only configured to use Taffy for CSS Grid layout"), + }; + + let pb_sums = self + .layout_style() + .padding_border_margin(containing_block) + .padding_border_sums; + + InlineContentSizesResult { + sizes: ContentSizes { + max_content: Au::from_f32_px(max_content_output.size.width) - pb_sums.inline, + min_content: Au::from_f32_px(min_content_output.size.width) - pb_sums.inline, + }, + + // TODO: determine this accurately + // + // "true" is a safe default as it will prevent Servo from performing optimizations based + // on the assumption that the node's size does not depend on block constraints. + depends_on_block_constraints: true, + } + } +} + +impl TaffyContainer { + /// <https://drafts.csswg.org/css-grid/#layout-algorithm> + pub(crate) fn layout( + &self, + layout_context: &LayoutContext, + positioning_context: &mut PositioningContext, + content_box_size_override: &ContainingBlock, + containing_block: &ContainingBlock, + ) -> CacheableLayoutResult { + let mut container_ctx = TaffyContainerContext { + layout_context, + positioning_context, + content_box_size_override, + style: content_box_size_override.style, + source_child_nodes: &self.children, + specific_layout_info: None, + child_specific_layout_infos: vec![None; self.children.len()], + }; + + let container_style = &content_box_size_override.style; + let align_items = container_style.clone_align_items(); + let justify_items = container_style.clone_justify_items(); + let pbm = self.layout_style().padding_border_margin(containing_block); + + let known_dimensions = taffy::Size { + width: Some( + (content_box_size_override.size.inline + pbm.padding_border_sums.inline) + .to_f32_px(), + ), + height: content_box_size_override + .size + .block + .to_definite() + .map(Au::to_f32_px) + .maybe_add(pbm.padding_border_sums.block.to_f32_px()), + }; + + let taffy_containing_block = taffy::Size { + width: Some(containing_block.size.inline.to_f32_px()), + height: containing_block.size.block.to_definite().map(Au::to_f32_px), + }; + + let layout_input = taffy::LayoutInput { + run_mode: taffy::RunMode::PerformLayout, + sizing_mode: taffy::SizingMode::InherentSize, + axis: taffy::RequestedAxis::Vertical, + vertical_margins_are_collapsible: taffy::Line::FALSE, + + known_dimensions, + parent_size: taffy_containing_block, + available_space: taffy_containing_block.map(AvailableSpace::from), + }; + + let output = match container_ctx.style.clone_display().inside() { + DisplayInside::Grid => { + taffy::compute_grid_layout(&mut container_ctx, DUMMY_NODE_ID, layout_input) + }, + _ => panic!("Servo is only configured to use Taffy for CSS Grid layout"), + }; + + // Convert `taffy::Layout` into Servo `Fragment`s + // with container_ctx.child_specific_layout_infos will also moved to the corresponding `Fragment`s + let fragments: Vec<Fragment> = self + .children + .iter() + .map(|child| (**child).borrow_mut()) + .enumerate() + .map(|(child_id, mut child)| { + fn rect_to_physical_sides<T>(rect: taffy::Rect<T>) -> PhysicalSides<T> { + PhysicalSides::new(rect.top, rect.right, rect.bottom, rect.left) + } + + fn size_and_pos_to_logical_rect<T: Default>( + position: taffy::Point<T>, + size: taffy::Size<T>, + ) -> PhysicalRect<T> { + PhysicalRect::new( + PhysicalPoint::new(position.x, position.y), + PhysicalSize::new(size.width, size.height), + ) + } + + let layout = &child.taffy_layout; + + let padding = rect_to_physical_sides(layout.padding.map(Au::from_f32_px)); + let border = rect_to_physical_sides(layout.border.map(Au::from_f32_px)); + let margin = rect_to_physical_sides(layout.margin.map(Au::from_f32_px)); + + // Compute content box size and position. + // + // For the x/y position we have to correct for the difference between the + // content box and the border box for both the parent and the child. + let content_size = size_and_pos_to_logical_rect( + taffy::Point { + x: Au::from_f32_px( + layout.location.x + layout.padding.left + layout.border.left, + ) - pbm.padding.inline_start - + pbm.border.inline_start, + y: Au::from_f32_px( + layout.location.y + layout.padding.top + layout.border.top, + ) - pbm.padding.block_start - + pbm.border.block_start, + }, + taffy::Size { + width: layout.size.width - + layout.padding.left - + layout.padding.right - + layout.border.left - + layout.border.right, + height: layout.size.height - + layout.padding.top - + layout.padding.bottom - + layout.border.top - + layout.border.bottom, + } + .map(Au::from_f32_px), + ); + + let child_specific_layout_info: Option<SpecificLayoutInfo> = + std::mem::take(&mut container_ctx.child_specific_layout_infos[child_id]); + + let establishes_containing_block_for_absolute_descendants = + if let TaffyItemBoxInner::InFlowBox(independent_box) = &child.taffy_level_box { + child + .style + .establishes_containing_block_for_absolute_descendants( + independent_box.base_fragment_info().flags, + ) + } else { + false + }; + + let fragment = match &mut child.taffy_level_box { + TaffyItemBoxInner::InFlowBox(independent_box) => { + let mut fragment_info = independent_box.base_fragment_info(); + fragment_info + .flags + .insert(FragmentFlags::IS_FLEX_OR_GRID_ITEM); + let mut box_fragment = BoxFragment::new( + fragment_info, + independent_box.style().clone(), + std::mem::take(&mut child.child_fragments), + content_size, + padding, + border, + margin, + None, /* clearance */ + ) + .with_baselines(Baselines { + first: output.first_baselines.y.map(Au::from_f32_px), + last: None, + }) + .with_specific_layout_info(child_specific_layout_info); + + if establishes_containing_block_for_absolute_descendants { + child.positioning_context.layout_collected_children( + container_ctx.layout_context, + &mut box_fragment, + ); + } + + let fragment = Fragment::Box(ArcRefCell::new(box_fragment)); + + child + .positioning_context + .adjust_static_position_of_hoisted_fragments( + &fragment, + PositioningContextLength::zero(), + ); + let child_positioning_context = std::mem::replace( + &mut child.positioning_context, + PositioningContext::new_for_containing_block_for_all_descendants(), + ); + container_ctx + .positioning_context + .append(child_positioning_context); + fragment + }, + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box) => { + fn resolve_alignment(value: AlignFlags, auto: AlignFlags) -> AlignFlags { + match value { + AlignFlags::AUTO => auto, + AlignFlags::NORMAL => AlignFlags::STRETCH, + value => value, + } + } + + let hoisted_box = AbsolutelyPositionedBox::to_hoisted( + abs_pos_box.clone(), + PhysicalRect::from_size(PhysicalSize::new( + Au::from_f32_px(output.size.width), + Au::from_f32_px(output.size.height), + )), + LogicalVec2 { + inline: resolve_alignment( + child.style.clone_align_self().0.0, + align_items.0, + ), + block: resolve_alignment( + child.style.clone_justify_self().0.0, + justify_items.computed.0, + ), + }, + container_ctx.style.writing_mode, + ); + let hoisted_fragment = hoisted_box.fragment.clone(); + container_ctx.positioning_context.push(hoisted_box); + Fragment::AbsoluteOrFixedPositioned(hoisted_fragment) + }, + }; + + if let TaffyItemBoxInner::InFlowBox(independent_formatting_context) = + &child.taffy_level_box + { + independent_formatting_context + .base + .set_fragment(fragment.clone()); + } + fragment + }) + .collect(); + + CacheableLayoutResult { + fragments, + content_block_size: Au::from_f32_px(output.size.height) - pbm.padding_border_sums.block, + content_inline_size_for_table: None, + baselines: Baselines::default(), + + // TODO: determine this accurately + // + // "true" is a safe default as it will prevent Servo from performing optimizations based + // on the assumption that the node's size does not depend on block constraints. + depends_on_block_constraints: true, + specific_layout_info: container_ctx.specific_layout_info, + collapsible_margins_in_children: CollapsedBlockMargins::zero(), + } + } + + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } +} diff --git a/components/layout/taffy/mod.rs b/components/layout/taffy/mod.rs new file mode 100644 index 00000000000..55a678cd89a --- /dev/null +++ b/components/layout/taffy/mod.rs @@ -0,0 +1,184 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +mod layout; +mod stylo_taffy; +use std::fmt; + +use app_units::Au; +use malloc_size_of_derive::MallocSizeOf; +use servo_arc::Arc; +use style::properties::ComputedValues; +use stylo_taffy::TaffyStyloStyle; + +use crate::PropagatedBoxTreeData; +use crate::cell::ArcRefCell; +use crate::construct_modern::{ModernContainerBuilder, ModernItemKind}; +use crate::context::LayoutContext; +use crate::dom::{LayoutBox, NodeExt}; +use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents}; +use crate::formatting_contexts::IndependentFormattingContext; +use crate::fragment_tree::Fragment; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; + +#[derive(Debug, MallocSizeOf)] +pub(crate) struct TaffyContainer { + children: Vec<ArcRefCell<TaffyItemBox>>, + #[conditional_malloc_size_of] + style: Arc<ComputedValues>, +} + +impl TaffyContainer { + pub fn construct<'dom>( + context: &LayoutContext, + info: &NodeAndStyleInfo<impl NodeExt<'dom>>, + contents: NonReplacedContents, + propagated_data: PropagatedBoxTreeData, + ) -> Self { + let mut builder = + ModernContainerBuilder::new(context, info, propagated_data.union(&info.style)); + contents.traverse(context, info, &mut builder); + let items = builder.finish(); + + let children = items + .into_iter() + .map(|item| { + let box_ = match item.kind { + ModernItemKind::InFlow => ArcRefCell::new(TaffyItemBox::new( + TaffyItemBoxInner::InFlowBox(item.formatting_context), + )), + ModernItemKind::OutOfFlow => { + let abs_pos_box = + ArcRefCell::new(AbsolutelyPositionedBox::new(item.formatting_context)); + ArcRefCell::new(TaffyItemBox::new( + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box), + )) + }, + }; + + if let Some(box_slot) = item.box_slot { + box_slot.set(LayoutBox::TaffyItemBox(box_.clone())); + } + + box_ + }) + .collect(); + + Self { + children, + style: info.style.clone(), + } + } +} + +#[derive(MallocSizeOf)] +pub(crate) struct TaffyItemBox { + pub(crate) taffy_layout: taffy::Layout, + pub(crate) child_fragments: Vec<Fragment>, + pub(crate) positioning_context: PositioningContext, + #[conditional_malloc_size_of] + pub(crate) style: Arc<ComputedValues>, + pub(crate) taffy_level_box: TaffyItemBoxInner, +} + +#[derive(Debug, MallocSizeOf)] +pub(crate) enum TaffyItemBoxInner { + InFlowBox(IndependentFormattingContext), + OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>), +} + +impl fmt::Debug for TaffyItemBox { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TaffyItemBox") + .field("taffy_layout", &self.taffy_layout) + .field("child_fragments", &self.child_fragments.len()) + .field("style", &self.style) + .field("taffy_level_box", &self.taffy_level_box) + .finish() + } +} + +impl TaffyItemBox { + fn new(inner: TaffyItemBoxInner) -> Self { + let style: Arc<ComputedValues> = match &inner { + TaffyItemBoxInner::InFlowBox(item) => item.style().clone(), + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(absbox) => { + (*absbox).borrow().context.style().clone() + }, + }; + + Self { + taffy_layout: Default::default(), + child_fragments: Vec::new(), + positioning_context: PositioningContext::new_for_containing_block_for_all_descendants(), + style, + taffy_level_box: inner, + } + } + + pub(crate) fn invalidate_cached_fragment(&mut self) { + self.taffy_layout = Default::default(); + self.positioning_context = + PositioningContext::new_for_containing_block_for_all_descendants(); + match self.taffy_level_box { + TaffyItemBoxInner::InFlowBox(ref independent_formatting_context) => { + independent_formatting_context + .base + .invalidate_cached_fragment() + }, + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => { + positioned_box + .borrow() + .context + .base + .invalidate_cached_fragment() + }, + } + } + + pub(crate) fn fragments(&self) -> Vec<Fragment> { + match self.taffy_level_box { + TaffyItemBoxInner::InFlowBox(ref independent_formatting_context) => { + independent_formatting_context.base.fragments() + }, + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => { + positioned_box.borrow().context.base.fragments() + }, + } + } +} + +/// Details from Taffy grid layout that will be stored +#[derive(Clone, Debug, MallocSizeOf)] +pub(crate) struct SpecificTaffyGridInfo { + pub rows: SpecificTaffyGridTrackInfo, + pub columns: SpecificTaffyGridTrackInfo, +} + +impl SpecificTaffyGridInfo { + fn from_detailed_grid_layout(grid_info: taffy::DetailedGridInfo) -> Self { + Self { + rows: SpecificTaffyGridTrackInfo { + sizes: grid_info + .rows + .sizes + .iter() + .map(|size| Au::from_f32_px(*size)) + .collect(), + }, + columns: SpecificTaffyGridTrackInfo { + sizes: grid_info + .columns + .sizes + .iter() + .map(|size| Au::from_f32_px(*size)) + .collect(), + }, + } + } +} + +#[derive(Clone, Debug, MallocSizeOf)] +pub(crate) struct SpecificTaffyGridTrackInfo { + pub sizes: Box<[Au]>, +} diff --git a/components/layout/taffy/stylo_taffy/convert.rs b/components/layout/taffy/stylo_taffy/convert.rs new file mode 100644 index 00000000000..03fbec292a4 --- /dev/null +++ b/components/layout/taffy/stylo_taffy/convert.rs @@ -0,0 +1,347 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +/// Private module of type aliases so we can refer to stylo types with nicer names +mod stylo { + pub(crate) use style::properties::generated::longhands::box_sizing::computed_value::T as BoxSizing; + pub(crate) use style::properties::longhands::aspect_ratio::computed_value::T as AspectRatio; + pub(crate) use style::properties::longhands::position::computed_value::T as Position; + pub(crate) use style::values::computed::{LengthPercentage, Percentage}; + pub(crate) use style::values::generics::NonNegative; + pub(crate) use style::values::generics::length::{ + GenericLengthPercentageOrNormal, GenericMargin, GenericMaxSize, GenericSize, + }; + pub(crate) use style::values::generics::position::{Inset as GenericInset, PreferredRatio}; + pub(crate) use style::values::specified::align::{AlignFlags, ContentDistribution}; + pub(crate) use style::values::specified::box_::{ + Display, DisplayInside, DisplayOutside, Overflow, + }; + pub(crate) type MarginVal = GenericMargin<LengthPercentage>; + pub(crate) type InsetVal = GenericInset<Percentage, LengthPercentage>; + pub(crate) type Size = GenericSize<NonNegative<LengthPercentage>>; + pub(crate) type MaxSize = GenericMaxSize<NonNegative<LengthPercentage>>; + + pub(crate) type Gap = GenericLengthPercentageOrNormal<NonNegative<LengthPercentage>>; + + pub(crate) use style::computed_values::grid_auto_flow::T as GridAutoFlow; + pub(crate) use style::values::computed::{GridLine, GridTemplateComponent, ImplicitGridTracks}; + pub(crate) use style::values::generics::grid::{ + RepeatCount, TrackBreadth, TrackListValue, TrackSize, + }; + pub(crate) use style::values::specified::GenericGridTemplateComponent; +} + +#[inline] +pub fn length_percentage(val: &stylo::LengthPercentage) -> taffy::LengthPercentage { + if let Some(length) = val.to_length() { + taffy::LengthPercentage::Length(length.px()) + } else if let Some(val) = val.to_percentage() { + taffy::LengthPercentage::Percent(val.0) + } else { + // TODO: Support calc + taffy::LengthPercentage::Percent(0.0) + } +} + +#[inline] +pub fn dimension(val: &stylo::Size) -> taffy::Dimension { + match val { + stylo::Size::LengthPercentage(val) => length_percentage(&val.0).into(), + stylo::Size::Auto => taffy::Dimension::Auto, + + // TODO: implement other values in Taffy + stylo::Size::MaxContent => taffy::Dimension::Auto, + stylo::Size::MinContent => taffy::Dimension::Auto, + stylo::Size::FitContent => taffy::Dimension::Auto, + stylo::Size::FitContentFunction(_) => taffy::Dimension::Auto, + stylo::Size::Stretch => taffy::Dimension::Auto, + + // Anchor positioning will be flagged off for time being + stylo::Size::AnchorSizeFunction(_) => unreachable!(), + } +} + +#[inline] +pub fn max_size_dimension(val: &stylo::MaxSize) -> taffy::Dimension { + match val { + stylo::MaxSize::LengthPercentage(val) => length_percentage(&val.0).into(), + stylo::MaxSize::None => taffy::Dimension::Auto, + + // TODO: implement other values in Taffy + stylo::MaxSize::MaxContent => taffy::Dimension::Auto, + stylo::MaxSize::MinContent => taffy::Dimension::Auto, + stylo::MaxSize::FitContent => taffy::Dimension::Auto, + stylo::MaxSize::FitContentFunction(_) => taffy::Dimension::Auto, + stylo::MaxSize::Stretch => taffy::Dimension::Auto, + + // Anchor positioning will be flagged off for time being + stylo::MaxSize::AnchorSizeFunction(_) => unreachable!(), + } +} + +#[inline] +pub fn margin(val: &stylo::MarginVal) -> taffy::LengthPercentageAuto { + match val { + stylo::MarginVal::Auto => taffy::LengthPercentageAuto::Auto, + stylo::MarginVal::LengthPercentage(val) => length_percentage(val).into(), + + // Anchor positioning will be flagged off for time being + stylo::MarginVal::AnchorSizeFunction(_) => unreachable!(), + } +} + +#[inline] +pub fn inset(val: &stylo::InsetVal) -> taffy::LengthPercentageAuto { + match val { + stylo::InsetVal::Auto => taffy::LengthPercentageAuto::Auto, + stylo::InsetVal::LengthPercentage(val) => length_percentage(val).into(), + + // Anchor positioning will be flagged off for time being + stylo::InsetVal::AnchorSizeFunction(_) => unreachable!(), + stylo::InsetVal::AnchorFunction(_) => unreachable!(), + } +} + +#[inline] +pub fn is_block(input: stylo::Display) -> bool { + matches!(input.outside(), stylo::DisplayOutside::Block) && + matches!( + input.inside(), + stylo::DisplayInside::Flow | stylo::DisplayInside::FlowRoot + ) +} + +#[inline] +pub fn box_generation_mode(input: stylo::Display) -> taffy::BoxGenerationMode { + match input.inside() { + stylo::DisplayInside::None => taffy::BoxGenerationMode::None, + _ => taffy::BoxGenerationMode::Normal, + } +} + +#[inline] +pub fn box_sizing(input: stylo::BoxSizing) -> taffy::BoxSizing { + match input { + stylo::BoxSizing::BorderBox => taffy::BoxSizing::BorderBox, + stylo::BoxSizing::ContentBox => taffy::BoxSizing::ContentBox, + } +} + +#[inline] +pub fn position(input: stylo::Position) -> taffy::Position { + match input { + // TODO: support position:static + stylo::Position::Relative => taffy::Position::Relative, + stylo::Position::Static => taffy::Position::Relative, + + // TODO: support position:fixed and sticky + stylo::Position::Absolute => taffy::Position::Absolute, + stylo::Position::Fixed => taffy::Position::Absolute, + stylo::Position::Sticky => taffy::Position::Relative, + } +} + +#[inline] +pub fn overflow(input: stylo::Overflow) -> taffy::Overflow { + // TODO: Enable Overflow::Clip in servo configuration of stylo + match input { + stylo::Overflow::Visible => taffy::Overflow::Visible, + stylo::Overflow::Hidden => taffy::Overflow::Hidden, + stylo::Overflow::Scroll => taffy::Overflow::Scroll, + stylo::Overflow::Clip => taffy::Overflow::Clip, + // TODO: Support Overflow::Auto in Taffy + stylo::Overflow::Auto => taffy::Overflow::Scroll, + } +} + +#[inline] +pub fn aspect_ratio(input: stylo::AspectRatio) -> Option<f32> { + match input.ratio { + stylo::PreferredRatio::None => None, + stylo::PreferredRatio::Ratio(val) => Some(val.0.0 / val.1.0), + } +} + +#[inline] +pub fn content_alignment(input: stylo::ContentDistribution) -> Option<taffy::AlignContent> { + match input.primary().value() { + stylo::AlignFlags::NORMAL => None, + stylo::AlignFlags::AUTO => None, + stylo::AlignFlags::START => Some(taffy::AlignContent::Start), + stylo::AlignFlags::END => Some(taffy::AlignContent::End), + stylo::AlignFlags::LEFT => Some(taffy::AlignContent::Start), + stylo::AlignFlags::RIGHT => Some(taffy::AlignContent::End), + stylo::AlignFlags::FLEX_START => Some(taffy::AlignContent::FlexStart), + stylo::AlignFlags::STRETCH => Some(taffy::AlignContent::Stretch), + stylo::AlignFlags::FLEX_END => Some(taffy::AlignContent::FlexEnd), + stylo::AlignFlags::CENTER => Some(taffy::AlignContent::Center), + stylo::AlignFlags::SPACE_BETWEEN => Some(taffy::AlignContent::SpaceBetween), + stylo::AlignFlags::SPACE_AROUND => Some(taffy::AlignContent::SpaceAround), + stylo::AlignFlags::SPACE_EVENLY => Some(taffy::AlignContent::SpaceEvenly), + // Should never be hit. But no real reason to panic here. + _ => None, + } +} + +#[inline] +pub fn item_alignment(input: stylo::AlignFlags) -> Option<taffy::AlignItems> { + match input.value() { + stylo::AlignFlags::AUTO => None, + stylo::AlignFlags::NORMAL => Some(taffy::AlignItems::Stretch), + stylo::AlignFlags::STRETCH => Some(taffy::AlignItems::Stretch), + stylo::AlignFlags::FLEX_START => Some(taffy::AlignItems::FlexStart), + stylo::AlignFlags::FLEX_END => Some(taffy::AlignItems::FlexEnd), + stylo::AlignFlags::SELF_START => Some(taffy::AlignItems::Start), + stylo::AlignFlags::SELF_END => Some(taffy::AlignItems::End), + stylo::AlignFlags::START => Some(taffy::AlignItems::Start), + stylo::AlignFlags::END => Some(taffy::AlignItems::End), + stylo::AlignFlags::LEFT => Some(taffy::AlignItems::Start), + stylo::AlignFlags::RIGHT => Some(taffy::AlignItems::End), + stylo::AlignFlags::CENTER => Some(taffy::AlignItems::Center), + stylo::AlignFlags::BASELINE => Some(taffy::AlignItems::Baseline), + // Should never be hit. But no real reason to panic here. + _ => None, + } +} + +#[inline] +pub fn gap(input: &stylo::Gap) -> taffy::LengthPercentage { + match input { + // For Flexbox and CSS Grid the "normal" value is 0px. This may need to be updated + // if we ever implement multi-column layout. + stylo::Gap::Normal => taffy::LengthPercentage::Length(0.0), + stylo::Gap::LengthPercentage(val) => length_percentage(&val.0), + } +} + +// CSS Grid styles +// =============== + +#[inline] +pub fn grid_auto_flow(input: stylo::GridAutoFlow) -> taffy::GridAutoFlow { + let is_row = input.contains(stylo::GridAutoFlow::ROW); + let is_dense = input.contains(stylo::GridAutoFlow::DENSE); + + match (is_row, is_dense) { + (true, false) => taffy::GridAutoFlow::Row, + (true, true) => taffy::GridAutoFlow::RowDense, + (false, false) => taffy::GridAutoFlow::Column, + (false, true) => taffy::GridAutoFlow::ColumnDense, + } +} + +#[inline] +pub fn grid_line(input: &stylo::GridLine) -> taffy::GridPlacement { + if input.is_auto() { + taffy::GridPlacement::Auto + } else if input.is_span { + taffy::style_helpers::span(input.line_num.try_into().unwrap()) + } else if input.line_num == 0 { + taffy::GridPlacement::Auto + } else { + taffy::style_helpers::line(input.line_num.try_into().unwrap()) + } +} + +#[inline] +pub fn grid_template_tracks( + input: &stylo::GridTemplateComponent, +) -> Vec<taffy::TrackSizingFunction> { + match input { + stylo::GenericGridTemplateComponent::None => Vec::new(), + stylo::GenericGridTemplateComponent::TrackList(list) => list + .values + .iter() + .map(|track| match track { + stylo::TrackListValue::TrackSize(size) => { + taffy::TrackSizingFunction::Single(track_size(size)) + }, + stylo::TrackListValue::TrackRepeat(repeat) => taffy::TrackSizingFunction::Repeat( + track_repeat(repeat.count), + repeat.track_sizes.iter().map(track_size).collect(), + ), + }) + .collect(), + + // TODO: Implement subgrid and masonry + stylo::GenericGridTemplateComponent::Subgrid(_) => Vec::new(), + stylo::GenericGridTemplateComponent::Masonry => Vec::new(), + } +} + +#[inline] +pub fn grid_auto_tracks( + input: &stylo::ImplicitGridTracks, +) -> Vec<taffy::NonRepeatedTrackSizingFunction> { + input.0.iter().map(track_size).collect() +} + +#[inline] +pub fn track_repeat(input: stylo::RepeatCount<i32>) -> taffy::GridTrackRepetition { + match input { + stylo::RepeatCount::Number(val) => { + taffy::GridTrackRepetition::Count(val.try_into().unwrap()) + }, + stylo::RepeatCount::AutoFill => taffy::GridTrackRepetition::AutoFill, + stylo::RepeatCount::AutoFit => taffy::GridTrackRepetition::AutoFit, + } +} + +#[inline] +pub fn track_size( + input: &stylo::TrackSize<stylo::LengthPercentage>, +) -> taffy::NonRepeatedTrackSizingFunction { + match input { + stylo::TrackSize::Breadth(breadth) => taffy::MinMax { + min: min_track(breadth), + max: max_track(breadth), + }, + stylo::TrackSize::Minmax(min, max) => taffy::MinMax { + min: min_track(min), + max: max_track(max), + }, + stylo::TrackSize::FitContent(limit) => taffy::MinMax { + min: taffy::MinTrackSizingFunction::Auto, + max: taffy::MaxTrackSizingFunction::FitContent(match limit { + stylo::TrackBreadth::Breadth(lp) => length_percentage(lp), + + // Are these valid? Taffy doesn't support this in any case + stylo::TrackBreadth::Fr(_) => unreachable!(), + stylo::TrackBreadth::Auto => unreachable!(), + stylo::TrackBreadth::MinContent => unreachable!(), + stylo::TrackBreadth::MaxContent => unreachable!(), + }), + }, + } +} + +#[inline] +pub fn min_track( + input: &stylo::TrackBreadth<stylo::LengthPercentage>, +) -> taffy::MinTrackSizingFunction { + match input { + stylo::TrackBreadth::Breadth(lp) => { + taffy::MinTrackSizingFunction::Fixed(length_percentage(lp)) + }, + stylo::TrackBreadth::Fr(_) => taffy::MinTrackSizingFunction::Auto, + stylo::TrackBreadth::Auto => taffy::MinTrackSizingFunction::Auto, + stylo::TrackBreadth::MinContent => taffy::MinTrackSizingFunction::MinContent, + stylo::TrackBreadth::MaxContent => taffy::MinTrackSizingFunction::MaxContent, + } +} + +#[inline] +pub fn max_track( + input: &stylo::TrackBreadth<stylo::LengthPercentage>, +) -> taffy::MaxTrackSizingFunction { + match input { + stylo::TrackBreadth::Breadth(lp) => { + taffy::MaxTrackSizingFunction::Fixed(length_percentage(lp)) + }, + stylo::TrackBreadth::Fr(val) => taffy::MaxTrackSizingFunction::Fraction(*val), + stylo::TrackBreadth::Auto => taffy::MaxTrackSizingFunction::Auto, + stylo::TrackBreadth::MinContent => taffy::MaxTrackSizingFunction::MinContent, + stylo::TrackBreadth::MaxContent => taffy::MaxTrackSizingFunction::MaxContent, + } +} diff --git a/components/layout/taffy/stylo_taffy/mod.rs b/components/layout/taffy/stylo_taffy/mod.rs new file mode 100644 index 00000000000..05eece6ace7 --- /dev/null +++ b/components/layout/taffy/stylo_taffy/mod.rs @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Conversion functions from Stylo types to Taffy types + +mod convert; +mod wrapper; +pub use wrapper::TaffyStyloStyle; diff --git a/components/layout/taffy/stylo_taffy/wrapper.rs b/components/layout/taffy/stylo_taffy/wrapper.rs new file mode 100644 index 00000000000..35b19aa7838 --- /dev/null +++ b/components/layout/taffy/stylo_taffy/wrapper.rs @@ -0,0 +1,226 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::ops::Deref; + +use style::properties::ComputedValues; + +use super::convert; + +/// A wrapper struct for anything that Deref's to a [`ComputedValues`], which +/// implements Taffy's layout traits and can used with Taffy's layout algorithms. +pub struct TaffyStyloStyle<T: Deref<Target = ComputedValues>>(pub T); + +impl<T: Deref<Target = ComputedValues>> From<T> for TaffyStyloStyle<T> { + fn from(value: T) -> Self { + Self(value) + } +} + +impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> { + #[inline] + fn box_generation_mode(&self) -> taffy::BoxGenerationMode { + convert::box_generation_mode(self.0.get_box().display) + } + + #[inline] + fn is_block(&self) -> bool { + convert::is_block(self.0.get_box().display) + } + + #[inline] + fn box_sizing(&self) -> taffy::BoxSizing { + convert::box_sizing(self.0.get_position().box_sizing) + } + + #[inline] + fn overflow(&self) -> taffy::Point<taffy::Overflow> { + let box_styles = self.0.get_box(); + taffy::Point { + x: convert::overflow(box_styles.overflow_x), + y: convert::overflow(box_styles.overflow_y), + } + } + + #[inline] + fn scrollbar_width(&self) -> f32 { + 0.0 + } + + #[inline] + fn position(&self) -> taffy::Position { + convert::position(self.0.get_box().position) + } + + #[inline] + fn inset(&self) -> taffy::Rect<taffy::LengthPercentageAuto> { + let position_styles = self.0.get_position(); + taffy::Rect { + left: convert::inset(&position_styles.left), + right: convert::inset(&position_styles.right), + top: convert::inset(&position_styles.top), + bottom: convert::inset(&position_styles.bottom), + } + } + + #[inline] + fn size(&self) -> taffy::Size<taffy::Dimension> { + let position_styles = self.0.get_position(); + taffy::Size { + width: convert::dimension(&position_styles.width), + height: convert::dimension(&position_styles.height), + } + } + + #[inline] + fn min_size(&self) -> taffy::Size<taffy::Dimension> { + let position_styles = self.0.get_position(); + taffy::Size { + width: convert::dimension(&position_styles.min_width), + height: convert::dimension(&position_styles.min_height), + } + } + + #[inline] + fn max_size(&self) -> taffy::Size<taffy::Dimension> { + let position_styles = self.0.get_position(); + taffy::Size { + width: convert::max_size_dimension(&position_styles.max_width), + height: convert::max_size_dimension(&position_styles.max_height), + } + } + + #[inline] + fn aspect_ratio(&self) -> Option<f32> { + convert::aspect_ratio(self.0.get_position().aspect_ratio) + } + + #[inline] + fn margin(&self) -> taffy::Rect<taffy::LengthPercentageAuto> { + let margin_styles = self.0.get_margin(); + taffy::Rect { + left: convert::margin(&margin_styles.margin_left), + right: convert::margin(&margin_styles.margin_right), + top: convert::margin(&margin_styles.margin_top), + bottom: convert::margin(&margin_styles.margin_bottom), + } + } + + #[inline] + fn padding(&self) -> taffy::Rect<taffy::LengthPercentage> { + let padding_styles = self.0.get_padding(); + taffy::Rect { + left: convert::length_percentage(&padding_styles.padding_left.0), + right: convert::length_percentage(&padding_styles.padding_right.0), + top: convert::length_percentage(&padding_styles.padding_top.0), + bottom: convert::length_percentage(&padding_styles.padding_bottom.0), + } + } + + #[inline] + fn border(&self) -> taffy::Rect<taffy::LengthPercentage> { + let border_styles = self.0.get_border(); + taffy::Rect { + left: taffy::LengthPercentage::Length(border_styles.border_left_width.to_f32_px()), + right: taffy::LengthPercentage::Length(border_styles.border_right_width.to_f32_px()), + top: taffy::LengthPercentage::Length(border_styles.border_top_width.to_f32_px()), + bottom: taffy::LengthPercentage::Length(border_styles.border_bottom_width.to_f32_px()), + } + } +} + +impl<T: Deref<Target = ComputedValues>> taffy::GridContainerStyle for TaffyStyloStyle<T> { + type TemplateTrackList<'a> + = Vec<taffy::TrackSizingFunction> + where + Self: 'a; + type AutoTrackList<'a> + = Vec<taffy::NonRepeatedTrackSizingFunction> + where + Self: 'a; + + #[inline] + fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> { + convert::grid_template_tracks(&self.0.get_position().grid_template_rows) + } + + #[inline] + fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> { + convert::grid_template_tracks(&self.0.get_position().grid_template_columns) + } + + #[inline] + fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> { + convert::grid_auto_tracks(&self.0.get_position().grid_auto_rows) + } + + #[inline] + fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> { + convert::grid_auto_tracks(&self.0.get_position().grid_auto_columns) + } + + #[inline] + fn grid_auto_flow(&self) -> taffy::GridAutoFlow { + convert::grid_auto_flow(self.0.get_position().grid_auto_flow) + } + + #[inline] + fn gap(&self) -> taffy::Size<taffy::LengthPercentage> { + let position_styles = self.0.get_position(); + taffy::Size { + width: convert::gap(&position_styles.column_gap), + height: convert::gap(&position_styles.row_gap), + } + } + + #[inline] + fn align_content(&self) -> Option<taffy::AlignContent> { + convert::content_alignment(self.0.get_position().align_content.0) + } + + #[inline] + fn justify_content(&self) -> Option<taffy::JustifyContent> { + convert::content_alignment(self.0.get_position().justify_content.0) + } + + #[inline] + fn align_items(&self) -> Option<taffy::AlignItems> { + convert::item_alignment(self.0.get_position().align_items.0) + } + + #[inline] + fn justify_items(&self) -> Option<taffy::AlignItems> { + convert::item_alignment(self.0.get_position().justify_items.computed.0) + } +} + +impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle<T> { + #[inline] + fn grid_row(&self) -> taffy::Line<taffy::GridPlacement> { + let position_styles = self.0.get_position(); + taffy::Line { + start: convert::grid_line(&position_styles.grid_row_start), + end: convert::grid_line(&position_styles.grid_row_end), + } + } + + #[inline] + fn grid_column(&self) -> taffy::Line<taffy::GridPlacement> { + let position_styles = self.0.get_position(); + taffy::Line { + start: convert::grid_line(&position_styles.grid_column_start), + end: convert::grid_line(&position_styles.grid_column_end), + } + } + + #[inline] + fn align_self(&self) -> Option<taffy::AlignSelf> { + convert::item_alignment(self.0.get_position().align_self.0.0) + } + + #[inline] + fn justify_self(&self) -> Option<taffy::AlignSelf> { + convert::item_alignment(self.0.get_position().justify_self.0.0) + } +} |