use crate::{
layout::{
Border, BorderSides, BorderStyle, BoxConstraint, Cursor, EdgeSizes, LayoutBox,
LayoutContext,
inner_formatting_context::flow::{LayoutBlockOptions, layout_block},
},
tdom::node::{NodeArena, NodeId, NodeType},
};
struct BlockElementConfig {
node_type: NodeType,
opts: fn() -> LayoutBlockOptions,
}
fn default_opts() -> LayoutBlockOptions {
LayoutBlockOptions::default()
}
fn p_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_margins: Some(EdgeSizes::new(1, 0, 1, 0)),
..Default::default()
}
}
fn aside_opts() -> LayoutBlockOptions {
LayoutBlockOptions::default()
}
fn header_footer_opts() -> LayoutBlockOptions {
LayoutBlockOptions::default()
}
fn address_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_italic: true,
..Default::default()
}
}
const BLOCKQUOTE_MARGIN_BLOCK: usize = 1;
const BLOCKQUOTE_MARGIN_INLINE: usize = 4;
fn blockquote_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_margins: Some(EdgeSizes::new(
BLOCKQUOTE_MARGIN_BLOCK,
BLOCKQUOTE_MARGIN_INLINE,
BLOCKQUOTE_MARGIN_BLOCK,
BLOCKQUOTE_MARGIN_INLINE,
)),
..Default::default()
}
}
const DL_MARGIN_BLOCK: usize = 1;
const DD_MARGIN_INLINE: usize = 4;
fn dl_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_margins: Some(EdgeSizes::new(DL_MARGIN_BLOCK, 0, DL_MARGIN_BLOCK, 0)),
..Default::default()
}
}
fn dd_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_margins: Some(EdgeSizes::new(0, 0, 0, DD_MARGIN_INLINE)),
..Default::default()
}
}
fn dialog_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_border: Some(BorderSides::all(Border::new(1, BorderStyle::Solid, None))),
..Default::default()
}
}
fn fieldset_opts() -> LayoutBlockOptions {
LayoutBlockOptions {
ua_border: Some(BorderSides::all(Border::new(1, BorderStyle::Solid, None))),
ua_margins: Some(EdgeSizes::new(1, 0, 1, 0)),
..Default::default()
}
}
static STANDARD_BLOCK_ELEMENTS: &[BlockElementConfig] = &[
BlockElementConfig {
node_type: NodeType::Div,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::Body,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::Html,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::P,
opts: p_opts,
},
BlockElementConfig {
node_type: NodeType::Aside,
opts: aside_opts,
},
BlockElementConfig {
node_type: NodeType::Header,
opts: header_footer_opts,
},
BlockElementConfig {
node_type: NodeType::Footer,
opts: header_footer_opts,
},
BlockElementConfig {
node_type: NodeType::HGroup,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::Address,
opts: address_opts,
},
BlockElementConfig {
node_type: NodeType::BlockQuote,
opts: blockquote_opts,
},
BlockElementConfig {
node_type: NodeType::Dl,
opts: dl_opts,
},
BlockElementConfig {
node_type: NodeType::Dt,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::Dd,
opts: dd_opts,
},
BlockElementConfig {
node_type: NodeType::Search,
opts: default_opts,
},
BlockElementConfig {
node_type: NodeType::Dialog,
opts: dialog_opts,
},
BlockElementConfig {
node_type: NodeType::Fieldset,
opts: fieldset_opts,
},
BlockElementConfig {
node_type: NodeType::Legend,
opts: default_opts,
},
];
pub fn layout_standard_block(
arena: &NodeArena,
node_id: NodeId,
containing: BoxConstraint,
cursor: &mut Cursor,
context: LayoutContext,
pre_allocated_rect: Option<crate::layout::Rect>,
) -> Option<LayoutBox> {
let node = &arena[node_id];
let config = STANDARD_BLOCK_ELEMENTS
.iter()
.find(|config| config.node_type == node.node_type)?;
Some(layout_block(
arena,
node,
node_id,
containing,
cursor,
(config.opts)(),
context,
pre_allocated_rect,
))
}