diff options
Diffstat (limited to 'components/layout/flexbox/mod.rs')
-rw-r--r-- | components/layout/flexbox/mod.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/components/layout/flexbox/mod.rs b/components/layout/flexbox/mod.rs new file mode 100644 index 00000000000..e1f8213f1e9 --- /dev/null +++ b/components/layout/flexbox/mod.rs @@ -0,0 +1,201 @@ +/* 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 geom::{FlexAxis, MainStartCrossStart}; +use malloc_size_of_derive::MallocSizeOf; +use servo_arc::Arc as ServoArc; +use style::logical_geometry::WritingMode; +use style::properties::ComputedValues; +use style::properties::longhands::align_items::computed_value::T as AlignItems; +use style::properties::longhands::flex_direction::computed_value::T as FlexDirection; +use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap; +use style::values::computed::{AlignContent, JustifyContent}; +use style::values::specified::align::AlignFlags; + +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::{BaseFragmentInfo, Fragment}; +use crate::positioned::AbsolutelyPositionedBox; + +mod geom; +mod layout; + +/// A structure to hold the configuration of a flex container for use during layout +/// and preferred width calculation. +#[derive(Clone, Debug, MallocSizeOf)] +pub(crate) struct FlexContainerConfig { + container_is_single_line: bool, + writing_mode: WritingMode, + flex_axis: FlexAxis, + flex_direction: FlexDirection, + flex_direction_is_reversed: bool, + flex_wrap: FlexWrap, + flex_wrap_is_reversed: bool, + main_start_cross_start_sides_are: MainStartCrossStart, + align_content: AlignContent, + align_items: AlignItems, + justify_content: JustifyContent, +} + +impl FlexContainerConfig { + fn new(container_style: &ComputedValues) -> FlexContainerConfig { + let flex_direction = container_style.clone_flex_direction(); + let flex_axis = FlexAxis::from(flex_direction); + let flex_wrap = container_style.get_position().flex_wrap; + let container_is_single_line = match flex_wrap { + FlexWrap::Nowrap => true, + FlexWrap::Wrap | FlexWrap::WrapReverse => false, + }; + let flex_direction_is_reversed = match flex_direction { + FlexDirection::Row | FlexDirection::Column => false, + FlexDirection::RowReverse | FlexDirection::ColumnReverse => true, + }; + let flex_wrap_reverse = match flex_wrap { + FlexWrap::Nowrap | FlexWrap::Wrap => false, + FlexWrap::WrapReverse => true, + }; + + let align_content = container_style.clone_align_content(); + let align_items = AlignItems(match container_style.clone_align_items().0 { + AlignFlags::AUTO | AlignFlags::NORMAL => AlignFlags::STRETCH, + align => align, + }); + let justify_content = container_style.clone_justify_content(); + let main_start_cross_start_sides_are = + MainStartCrossStart::from(flex_direction, flex_wrap_reverse); + + FlexContainerConfig { + container_is_single_line, + writing_mode: container_style.writing_mode, + flex_axis, + flex_direction, + flex_direction_is_reversed, + flex_wrap, + flex_wrap_is_reversed: flex_wrap_reverse, + main_start_cross_start_sides_are, + align_content, + align_items, + justify_content, + } + } +} + +#[derive(Debug, MallocSizeOf)] +pub(crate) struct FlexContainer { + children: Vec<ArcRefCell<FlexLevelBox>>, + + #[conditional_malloc_size_of] + style: ServoArc<ComputedValues>, + + /// The configuration of this [`FlexContainer`]. + config: FlexContainerConfig, +} + +impl FlexContainer { + 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(FlexLevelBox::FlexItem( + FlexItemBox::new(item.formatting_context), + )), + ModernItemKind::OutOfFlow => { + let abs_pos_box = + ArcRefCell::new(AbsolutelyPositionedBox::new(item.formatting_context)); + ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(abs_pos_box)) + }, + }; + + if let Some(box_slot) = item.box_slot { + box_slot.set(LayoutBox::FlexLevel(box_.clone())); + } + + box_ + }) + .collect(); + + Self { + children, + style: info.style.clone(), + config: FlexContainerConfig::new(&info.style), + } + } +} + +#[derive(Debug, MallocSizeOf)] +pub(crate) enum FlexLevelBox { + FlexItem(FlexItemBox), + OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>), +} + +impl FlexLevelBox { + pub(crate) fn invalidate_cached_fragment(&self) { + match self { + FlexLevelBox::FlexItem(flex_item_box) => flex_item_box + .independent_formatting_context + .base + .invalidate_cached_fragment(), + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box + .borrow() + .context + .base + .invalidate_cached_fragment(), + } + } + + pub(crate) fn fragments(&self) -> Vec<Fragment> { + match self { + FlexLevelBox::FlexItem(flex_item_box) => flex_item_box + .independent_formatting_context + .base + .fragments(), + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => { + positioned_box.borrow().context.base.fragments() + }, + } + } +} + +#[derive(MallocSizeOf)] +pub(crate) struct FlexItemBox { + independent_formatting_context: IndependentFormattingContext, +} + +impl std::fmt::Debug for FlexItemBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("FlexItemBox") + } +} + +impl FlexItemBox { + fn new(independent_formatting_context: IndependentFormattingContext) -> Self { + Self { + independent_formatting_context, + } + } + + fn style(&self) -> &ServoArc<ComputedValues> { + self.independent_formatting_context.style() + } + + fn base_fragment_info(&self) -> BaseFragmentInfo { + self.independent_formatting_context.base_fragment_info() + } +} |