use crate::layout::{LayoutRect, MarginValue, Size, compute_content_area_collapsed};
use crate::style::ComputedStyle;
#[derive(Debug, Clone, Copy)]
pub(super) struct ResolvedWidth {
pub(super) margin_left: i16,
pub(super) width: u16,
}
pub(super) fn resolve_block_width(
computed: &ComputedStyle,
containing_block_width: u16,
) -> ResolvedWidth {
let cb = containing_block_width as i32;
let width_decl = &computed.width;
let ml_decl = &computed.margin.left;
let mr_decl = &computed.margin.right;
let declared_width: Option<i32> = resolve_size_to_cells(width_decl, cb);
let ml_auto = matches!(ml_decl, MarginValue::Auto);
let mr_auto = matches!(mr_decl, MarginValue::Auto);
let cb_width_u16 = containing_block_width;
let ml_cells = if ml_auto {
0i32
} else {
ml_decl.resolve(cb_width_u16) as i32
};
let mr_cells = if mr_auto {
0i32
} else {
mr_decl.resolve(cb_width_u16) as i32
};
let (ml_final, width_final, _): (i32, i32, i32) = match (declared_width, ml_auto, mr_auto) {
(None, _, _) => {
let w = cb - ml_cells - mr_cells;
(ml_cells, w.max(0), mr_cells)
}
(Some(w), true, true) => {
let leftover = cb - w;
let half = leftover.div_euclid(2);
(half, w, leftover - half)
}
(Some(w), true, false) => {
let ml = cb - w - mr_cells;
(ml, w, mr_cells)
}
(Some(w), false, true) => {
let mr = cb - w - ml_cells;
(ml_cells, w, mr)
}
(Some(w), false, false) => {
let mr = cb - w - ml_cells;
(ml_cells, w, mr)
}
};
let clamped_width = clamp_width(width_final, &computed.min_width, computed.max_width, cb);
let ml_clamped = if clamped_width != width_final {
let leftover = cb - clamped_width;
match (ml_auto, mr_auto) {
(true, true) => leftover.div_euclid(2),
(true, false) => leftover - mr_cells,
(false, true) | (false, false) => ml_cells,
}
} else {
ml_final
};
ResolvedWidth {
margin_left: ml_clamped.clamp(i16::MIN as i32, i16::MAX as i32) as i16,
width: clamped_width.max(0).min(u16::MAX as i32) as u16,
}
}
fn resolve_size_to_cells(size: &Size, basis: i32) -> Option<i32> {
match size {
Size::Auto | Size::Flex(_) => None,
Size::Fixed(n) => Some(*n as i32),
Size::Percent(p) => Some(Size::percent_of(basis, *p)),
Size::Calc(expr) => {
let v = expr.resolve(&rdom_style::calc::ResolveCtx::new(basis));
Some(v)
}
}
}
fn clamp_width(
width: i32,
min: &Option<crate::layout::MinSize>,
max: Option<u16>,
_basis: i32, ) -> i32 {
let min_cells: Option<i32> = match min {
Some(crate::layout::MinSize::Cells(n)) => Some(*n as i32),
Some(crate::layout::MinSize::Auto) | None => None, };
let max_cells = max.map(|n| n as i32);
let after_max = match max_cells {
Some(m) => width.min(m),
None => width,
};
match min_cells {
Some(m) => after_max.max(m),
None => after_max.max(0),
}
}
pub(super) fn block_content_width(computed: &ComputedStyle, containing_block_width: u16) -> u16 {
let width = resolve_block_width(computed, containing_block_width).width;
compute_content_area_collapsed(
LayoutRect::new(0, 0, width, 0),
computed.padding.clone(),
computed.border,
computed.border_collapse,
containing_block_width,
)
.width
}