use app_units::Au;
use serde::Serialize;
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::flexbox::FlexContainer;
use crate::flow::BlockFormattingContext;
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlags};
use crate::geom::LogicalSides;
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContents;
use crate::sizing::{self, ComputeInlineContentSizes, InlineContentSizesResult};
use crate::style_ext::{AspectRatio, DisplayInside};
use crate::table::Table;
use crate::taffy::TaffyContainer;
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2};
#[derive(Debug, Serialize)]
pub(crate) struct IndependentFormattingContext {
pub base: LayoutBoxBase,
pub contents: IndependentFormattingContextContents,
}
#[derive(Debug, Serialize)]
pub(crate) enum IndependentFormattingContextContents {
NonReplaced(IndependentNonReplacedContents),
Replaced(ReplacedContents),
}
#[derive(Debug, Serialize)]
pub(crate) enum IndependentNonReplacedContents {
Flow(BlockFormattingContext),
Flex(FlexContainer),
Grid(TaffyContainer),
Table(Table),
}
#[derive(Clone, Copy, Debug, Default, Serialize)]
pub(crate) struct Baselines {
pub first: Option<Au>,
pub last: Option<Au>,
}
impl Baselines {
pub(crate) fn offset(&self, block_offset: Au) -> Baselines {
Self {
first: self.first.map(|first| first + block_offset),
last: self.last.map(|last| last + block_offset),
}
}
}
pub(crate) struct IndependentLayout {
pub fragments: Vec<Fragment>,
pub content_block_size: Au,
pub content_inline_size_for_table: Option<Au>,
pub baselines: Baselines,
pub depends_on_block_constraints: bool,
}
pub(crate) struct IndependentLayoutResult {
pub fragment: BoxFragment,
pub baselines: Option<Baselines>,
pub pbm_sums: LogicalSides<Au>,
}
impl IndependentFormattingContext {
pub fn construct<'dom, Node: NodeExt<'dom>>(
context: &LayoutContext,
node_and_style_info: &NodeAndStyleInfo<Node>,
display_inside: DisplayInside,
contents: Contents,
propagated_text_decoration_line: TextDecorationLine,
) -> Self {
let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
match contents {
Contents::NonReplaced(non_replaced_contents) => {
let contents = match display_inside {
DisplayInside::Flow { is_list_item } |
DisplayInside::FlowRoot { is_list_item } => {
IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
context,
node_and_style_info,
non_replaced_contents,
propagated_text_decoration_line,
is_list_item,
))
},
DisplayInside::Grid => {
IndependentNonReplacedContents::Grid(TaffyContainer::construct(
context,
node_and_style_info,
non_replaced_contents,
propagated_text_decoration_line,
))
},
DisplayInside::Flex => {
IndependentNonReplacedContents::Flex(FlexContainer::construct(
context,
node_and_style_info,
non_replaced_contents,
propagated_text_decoration_line,
))
},
DisplayInside::Table => {
let table_grid_style = context
.shared_context()
.stylist
.style_for_anonymous::<Node::ConcreteElement>(
&context.shared_context().guards,
&PseudoElement::ServoTableGrid,
&node_and_style_info.style,
);
base_fragment_info.flags.insert(FragmentFlags::DO_NOT_PAINT);
IndependentNonReplacedContents::Table(Table::construct(
context,
node_and_style_info,
table_grid_style,
non_replaced_contents,
propagated_text_decoration_line,
))
},
};
Self {
base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(contents),
}
},
Contents::Replaced(contents) => {
base_fragment_info.flags.insert(FragmentFlags::IS_REPLACED);
Self {
base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()),
contents: IndependentFormattingContextContents::Replaced(contents),
}
},
}
}
pub fn is_replaced(&self) -> bool {
matches!(
self.contents,
IndependentFormattingContextContents::Replaced(_)
)
}
#[inline]
pub fn style(&self) -> &Arc<ComputedValues> {
&self.base.style
}
#[inline]
pub fn base_fragment_info(&self) -> BaseFragmentInfo {
self.base.base_fragment_info
}
pub(crate) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult {
match &self.contents {
IndependentFormattingContextContents::NonReplaced(contents) => self
.base
.inline_content_sizes(layout_context, constraint_space, contents),
IndependentFormattingContextContents::Replaced(contents) => self
.base
.inline_content_sizes(layout_context, constraint_space, contents),
}
}
pub(crate) fn outer_inline_content_sizes(
&self,
layout_context: &LayoutContext,
containing_block: &IndefiniteContainingBlock,
auto_minimum: &LogicalVec2<Au>,
auto_block_size_stretches_to_containing_block: bool,
) -> InlineContentSizesResult {
let is_table = matches!(
self.contents,
IndependentFormattingContextContents::NonReplaced(
IndependentNonReplacedContents::Table(_)
)
);
sizing::outer_inline(
self.style(),
containing_block,
auto_minimum,
auto_block_size_stretches_to_containing_block,
is_table,
|padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
)
}
pub(crate) fn preferred_aspect_ratio(
&self,
padding_border_sums: &LogicalVec2<Au>,
) -> Option<AspectRatio> {
match &self.contents {
IndependentFormattingContextContents::NonReplaced(content) => {
content.preferred_aspect_ratio()
},
IndependentFormattingContextContents::Replaced(content) => {
content.preferred_aspect_ratio(self.style(), padding_border_sums)
},
}
}
}
impl IndependentNonReplacedContents {
pub fn layout(
&self,
layout_context: &LayoutContext,
positioning_context: &mut PositioningContext,
containing_block_for_children: &ContainingBlock,
containing_block: &ContainingBlock,
) -> IndependentLayout {
match self {
IndependentNonReplacedContents::Flow(bfc) => bfc.layout(
layout_context,
positioning_context,
containing_block_for_children,
),
IndependentNonReplacedContents::Flex(fc) => fc.layout(
layout_context,
positioning_context,
containing_block_for_children,
containing_block,
),
IndependentNonReplacedContents::Grid(fc) => fc.layout(
layout_context,
positioning_context,
containing_block_for_children,
containing_block,
),
IndependentNonReplacedContents::Table(table) => table.layout(
layout_context,
positioning_context,
containing_block_for_children,
containing_block,
),
}
}
#[inline]
pub(crate) fn preferred_aspect_ratio(&self) -> Option<AspectRatio> {
None
}
}
impl ComputeInlineContentSizes for IndependentNonReplacedContents {
fn compute_inline_content_sizes(
&self,
layout_context: &LayoutContext,
constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult {
match self {
Self::Flow(inner) => inner
.contents
.compute_inline_content_sizes(layout_context, constraint_space),
Self::Flex(inner) => {
inner.compute_inline_content_sizes(layout_context, constraint_space)
},
Self::Grid(inner) => {
inner.compute_inline_content_sizes(layout_context, constraint_space)
},
Self::Table(inner) => {
inner.compute_inline_content_sizes(layout_context, constraint_space)
},
}
}
}