blob: 86e16c4b47556474396ef9ce0d578d3b14c6872d [file] [log] [blame] [edit]
/* 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 script::layout_dom::ServoThreadSafeLayoutNode;
use servo_arc::Arc as ServoArc;
use style::context::SharedStyleContext;
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;
use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::BaseFragmentInfo;
use crate::layout_box_base::LayoutBoxBase;
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>>,
style: ServoArc<ComputedValues>,
/// The configuration of this [`FlexContainer`].
config: FlexContainerConfig,
}
impl FlexContainer {
pub fn construct(
context: &LayoutContext,
info: &NodeAndStyleInfo<'_>,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
) -> Self {
let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
contents.traverse(context, info, &mut builder);
let items = builder.finish();
let children = items
.into_iter()
.map(|item| {
let box_ = match item.kind {
ModernItemKind::InFlow(independent_formatting_context) => ArcRefCell::new(
FlexLevelBox::FlexItem(FlexItemBox::new(independent_formatting_context)),
),
ModernItemKind::OutOfFlow(independent_formatting_context) => {
let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
independent_formatting_context,
));
ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(abs_pos_box))
},
ModernItemKind::ReusedBox(layout_box) => match layout_box {
LayoutBox::FlexLevel(flex_level_box) => flex_level_box,
_ => unreachable!(
"Undamaged flex level element should be associated with flex level 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),
}
}
pub(crate) fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) {
self.config = FlexContainerConfig::new(new_style);
self.style = new_style.clone();
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, MallocSizeOf)]
pub(crate) enum FlexLevelBox {
FlexItem(FlexItemBox),
OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
}
impl FlexLevelBox {
pub(crate) fn repair_style(
&mut self,
context: &SharedStyleContext,
node: &ServoThreadSafeLayoutNode,
new_style: &ServoArc<ComputedValues>,
) {
match self {
FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
.independent_formatting_context
.repair_style(context, node, new_style),
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
.borrow_mut()
.context
.repair_style(context, node, new_style),
}
}
pub(crate) fn clear_fragment_layout_cache(&self) {
match self {
FlexLevelBox::FlexItem(flex_item_box) => flex_item_box
.independent_formatting_context
.base
.clear_fragment_layout_cache(),
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
.borrow()
.context
.base
.clear_fragment_layout_cache(),
}
}
pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
match self {
FlexLevelBox::FlexItem(flex_item_box) => {
callback(&flex_item_box.independent_formatting_context.base)
},
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
callback(&positioned_box.borrow().context.base)
},
}
}
pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T {
match self {
FlexLevelBox::FlexItem(flex_item_box) => {
callback(&mut flex_item_box.independent_formatting_context.base)
},
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
callback(&mut positioned_box.borrow_mut().context.base)
},
}
}
}
#[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()
}
}