use crate::{
html::css_parse::Position,
layout::{
BoxConstraint, Cursor, FormattingContext, LayoutBox, LayoutContext, Rect,
layoutbox::{
apply_relative_offset,
generation::{GeneratedBox, GeneratedBoxKind},
},
},
tdom::node::{NodeArena, NodeId},
};
mod replaced;
mod select_overlay;
pub use select_overlay::{SelectOption, SelectRow};
pub(crate) use select_overlay::{
overlay_options, select_item_indices, select_options, select_overlay_rect, select_rows,
};
use replaced::layout_replaced;
pub fn layout_generated_tree(
arena: &NodeArena,
boxes: &[GeneratedBox],
containing: BoxConstraint,
cursor: &mut Cursor,
context: LayoutContext,
) -> Vec<LayoutBox> {
boxes
.iter()
.filter_map(|generated| {
layout_generated_box(arena, generated, containing, cursor, context, None)
})
.collect()
}
pub fn layout_generated_box(
arena: &NodeArena,
generated: &GeneratedBox,
containing: BoxConstraint,
cursor: &mut Cursor,
context: LayoutContext,
pre_allocated_rect: Option<Rect>,
) -> Option<LayoutBox> {
let positioning = arena[generated.node_id].css_attr.get_positioning(
containing.width,
context.font,
context.viewport,
);
let detached = matches!(positioning.position, Position::Absolute | Position::Fixed);
let mut local_cursor = Cursor {
y: 0,
prev_bottom_margin: 0,
};
let working_cursor: &mut Cursor = if detached { &mut local_cursor } else { cursor };
let mut lb = match (
generated.kind,
generated.outer_display,
generated.inner_formatting_context,
) {
(GeneratedBoxKind::Replaced, _, _) => layout_replaced(
arena,
generated,
containing,
working_cursor,
context,
pre_allocated_rect,
)?,
(GeneratedBoxKind::Normal, _, FormattingContext::Flex) => {
crate::layout::inner_formatting_context::flex::layout_flex_dispatch(
arena,
generated.node_id,
containing,
working_cursor,
context,
pre_allocated_rect,
)?
}
(GeneratedBoxKind::Normal, _, FormattingContext::Table) => {
crate::layout::inner_formatting_context::flow::layout_table(
arena,
generated.node_id,
containing,
working_cursor,
context,
pre_allocated_rect,
)?
}
(GeneratedBoxKind::Normal, _, FormattingContext::Flow) => {
crate::layout::inner_formatting_context::flow::dispatch_flow_geometry(
arena,
generated.node_id,
containing,
working_cursor,
context,
pre_allocated_rect,
)?
}
(GeneratedBoxKind::Normal, _, FormattingContext::Grid) => {
crate::layout::inner_formatting_context::grid::layout_grid_dispatch(
arena,
generated.node_id,
containing,
working_cursor,
context,
pre_allocated_rect,
)?
}
(GeneratedBoxKind::Text | GeneratedBoxKind::Anonymous, _, _) => return None,
};
if positioning.position == Position::Relative {
apply_relative_offset(&mut lb, positioning.inset);
}
lb.positioning = positioning;
Some(lb)
}
pub fn layout_generated_box_via_node(
arena: &NodeArena,
node_id: NodeId,
containing: BoxConstraint,
cursor: &mut Cursor,
context: LayoutContext,
pre_allocated_rect: Option<Rect>,
) -> Option<LayoutBox> {
let generated = crate::layout::layoutbox::generation::generate_node(arena, node_id)?;
layout_generated_box(
arena,
&generated,
containing,
cursor,
context,
pre_allocated_rect,
)
}