layout::{LayoutDisplay, LayoutFlexDirection, LayoutFlexWrap, LayoutFloat, LayoutHeight, LayoutPosition, LayoutWidth, LayoutWritingMode},
// +spec:containing-block:723eee - Percentages specify sizing with respect to the containing block
// +spec:containing-block:8ad6f4 - Percentage resolution against containing block (editorial note: transferred percentages)
// +spec:containing-block:f1344e - percentage min/max-width resolved against containing block width; negative CB width yields zero
// +spec:containing-block:b3388b - percentage resolved against containing block size without re-resolution (css-sizing-3 §5.2.1)
/// // +spec:display-contents:f12d4e - intrinsic sizing: size determined by contents, not context
let mut intrinsic = self.calculate_node_intrinsic_sizes(tree, node_index, &child_intrinsics)?;
// +spec:min-max-sizing:970fef - if min-width/min-height is a <length>, use as floor for intrinsic sizes
let node_state = &self.ctx.styled_dom.styled_nodes.as_container()[dom_id].styled_node_state;
if let MultiValue::Exact(mw) = get_css_min_width(self.ctx.styled_dom, dom_id, node_state) {
if let MultiValue::Exact(mh) = get_css_min_height(self.ctx.styled_dom, dom_id, node_state) {
// +spec:block-formatting-context:30def2 - replaced elements use physical 300x150 default, not re-oriented by writing-mode
// +spec:display-property:015c41 - replaced elements default to 300x150 intrinsic size per css-sizing-3 §5.1
// +spec:display-property:2c6af3 - replaced elements with auto width/height use max-content size
// +spec:replaced-elements:6d6030 - Intrinsic sizes for replaced elements (images, virtual views)
// +spec:containing-block:bb5a12 - replaced element intrinsic sizes using initial containing block
// +spec:display-property:7127f9 - intrinsic sizes of replaced elements without natural sizes (300x150 fallback, aspect ratio)
// +spec:display-property:f9cede - replaced elements derive intrinsic size from natural dimensions
// +spec:writing-modes:b18121 - stretch fit inline size from available space, calculate block size via aspect ratio
// +spec:containing-block:1da6dc - use initial CB inline size for replaced elements with aspect ratio but no intrinsic size
// +spec:intrinsic-sizing:ea2c2c - §5.1 min-content size = size as float with auto; max-content = no wrapping
// +spec:intrinsic-sizing:8f3c0c - hanging glyphs must be excluded from intrinsic size measurement
// +spec:intrinsic-sizing:8c94e2 - min-content/max-content intrinsic size determination via constrained layout
// +spec:display-property:c587fd - min-content block size equals max-content block size for block containers, tables, inline boxes
// +spec:intrinsic-sizing:02eedc - min-content block size equals max-content block size for block containers
// +spec:containing-block:bb0658 - percentage block-sizes behave as auto during intrinsic computation (no CSS height resolution here)
// +spec:display-contents:84fe7f - cyclic percentage contributions: percentage-sized children use auto during intrinsic sizing
// +spec:min-max-sizing:411904 - percentage block-sizes treated as auto during intrinsic sizing (content-sized CB)
// +spec:min-max-sizing:737e62 - percentage heights don't resolve inside content-sized containing blocks
// +spec:height-calculation:d9ca8d - cyclic percentage contributions: percentage min-height/max-height on children should behave as auto when computing intrinsic contributions (not yet implemented)
if let Some(child_intrinsic) = child_intrinsics.iter().find(|(k, _)| k == &child_index).map(|(_, v)| v) {
// +spec:intrinsic-sizing:ed72bb - intrinsic contributions based on outer size, auto margins as zero
MultiValue::Exact(dir) => matches!(dir, LayoutFlexDirection::Row | LayoutFlexDirection::RowReverse),
if let Some(child_intrinsic) = child_intrinsics.iter().find(|(k, _)| k == &child_index).map(|(_, v)| v) {
let cell_intrinsic = child_intrinsics.iter().find(|(k, _)| k == &cell_idx).map(|(_, v)| *v)
let style_props = Arc::new(get_style_properties(ctx.styled_dom, dom_id, ctx.system_style.as_ref(), azul_css::props::basic::PhysicalSize::new(ctx.viewport_size.width, ctx.viewport_size.height)));
let style_props = Arc::new(get_style_properties(ctx.styled_dom, child_id, ctx.system_style.as_ref(), azul_css::props::basic::PhysicalSize::new(ctx.viewport_size.width, ctx.viewport_size.height)));
let intrinsic_sizes = tree.warm(child_index).and_then(|w| w.intrinsic_sizes).unwrap_or_default();
// +spec:containing-block:495930 - percentages in intrinsic sizing fall back to intrinsic contribution (css-sizing-3 §5.2.1)
// +spec:containing-block:5246c0 - cyclic percentage: when containing block size depends on this box's intrinsic contribution, percentages fall back to intrinsic size
// +spec:height-calculation:ca9f19 - percentage-sized boxes use intrinsic size as contribution during intrinsic sizing
// +spec:width-calculation:7a384a - percentage-sized boxes behave as width:auto for intrinsic contributions (cyclic percentage)
// +spec:containing-block:5145c5 - percentage block-size ignored in content-sized containing blocks during intrinsic sizing
// +spec:containing-block:7d5e79 - percentages behave as auto when containing block height is auto (cyclic percentage contribution)
// +spec:height-calculation:7d807b - css-sizing-3 §5.2.1: percentage heights behave as auto during intrinsic sizing (cyclic percentage contribution)
"Found atomic inline child at node {}: display={:?}, intrinsic_width={}, used_width={}, css_width={:?}",
alignment: crate::solver3::getters::get_vertical_align_for_node(ctx.styled_dom, child_dom_id),
// +spec:height-calculation:1c899b - width and height properties specify the preferred size of the box
/// // +spec:display-contents:71ccde - extrinsic sizing: size determined by context (containing block), not contents
/// 1. `width` and `height` CSS properties are resolved to pixel values. Percentages are calculated
// +spec:width-calculation:fb0629 - width/margin used values depend on box type, auto replaced by suitable value
// +spec:width-calculation:972e86 - §10.3.1: width property does not apply to inline non-replaced elements
let width_is_auto = css_width.is_auto() || matches!(&css_width, MultiValue::Exact(LayoutWidth::Auto));
let height_is_auto = css_height.is_auto() || matches!(&css_height, MultiValue::Exact(LayoutHeight::Auto));
// +spec:intrinsic-sizing:9e1c9d - non-quantitative values (auto, min-content, max-content) are not influenced by box-sizing
// +spec:width-calculation:febf0c - width/height "behaves as auto" when computed auto or percentage resolves against indefinite
// +spec:replaced-elements:992ea5 - block-level replaced elements use inline replaced width rules
// +spec:replaced-elements:36de3e - §10.3.2/§10.3.4: auto width for inline/block replaced elements uses intrinsic width
// +spec:replaced-elements:b9a780 - §10.3.2: inline replaced auto width = intrinsic width (conditions resolved during intrinsic size calc)
// +spec:width-calculation:c62d35 - §10.3.2: auto width for replaced elements uses intrinsic width
// +spec:intrinsic-sizing:560697 - shrink-to-fit = clamp(min-content, stretch-fit, max-content)
else if get_float(styled_dom, id, node_state).unwrap_or(LayoutFloat::None) != LayoutFloat::None {
// +spec:width-calculation:a6fd29 - shrink-to-fit width for floats: min(max(preferred minimum, available), preferred)
// +spec:width-calculation:1661b4 - abs-pos non-replaced auto width uses shrink-to-fit (§10.3.7)
// +spec:box-model:5ed651 - stretch fit: size minus margins (auto=0), border, padding, floored at 0
// +spec:box-model:33b951 - stretch-fit inline size: available space minus margins/border/padding, floored at zero
// +spec:box-model:30b4d0 - stretch fit: available size minus margins (auto as zero), border, padding, floored at zero
// +spec:width-calculation:e2c8f6 - auto width for non-replaced blocks in normal flow per CSS2.1§10.3.3
// +spec:width-calculation:aef2da - auto width: other auto values become 0, width follows from constraint equality
SizeMetric::Vmin => Some(px.number.get() / 100.0 * viewport_size.width.min(viewport_size.height)),
SizeMetric::Vmax => Some(px.number.get() / 100.0 * viewport_size.width.max(viewport_size.height)),
// +spec:intrinsic-sizing:069c75 - min-content, max-content, fit-content() sizing value keywords
// +spec:width-calculation:7b2128 - fit-content formula and non-negative inner size flooring (css-sizing-3 §3.2)
// css-sizing-3 §3.2: fit-content(<length-percentage>) = min(max-content, max(min-content, <length-percentage>))
// +spec:height-calculation:7880e3 - Distinction between box types for height/margin calculation
// +spec:height-calculation:6a6cac - §10.5 content height resolution (auto, length, percentage)
// +spec:height-calculation:d398e4 - §10.5/10.6 height property resolution for different box types
// +spec:width-calculation:be5eb1 - auto height means available block space is infinite (unconstrained)
// +spec:replaced-elements:994ac6 - §10.6.2: auto height for replaced elements uses intrinsic height or (used width)/ratio
SizeMetric::Vmin => Some(px.number.get() / 100.0 * viewport_size.width.min(viewport_size.height)),
SizeMetric::Vmax => Some(px.number.get() / 100.0 * viewport_size.width.max(viewport_size.height)),
// +spec:height-calculation:37bc8c - percentage heights resolve against definite containing block height
// css-sizing-3 §3.2: fit-content(<length-percentage>) = min(max-content, max(min-content, <length-percentage>))
// +spec:replaced-elements:5a85ce - abs-pos replaced: derive auto width from height × intrinsic ratio
// +spec:replaced-elements:aedb26 - abs-pos replaced: both auto, ratio but no intrinsic w/h → block constraint
// +spec:min-max-sizing:58869e - sizing properties width/height/min-width/min-height/max-width/max-height applied here
// +spec:min-max-sizing:2e2414 - max-width/max-height specify maximum box dimensions, applied here
// +spec:width-calculation:ef71c4 - replaced elements with both width/height auto use constraint violation table
// +spec:box-model:cc170b - box-sizing: border-box includes padding+border in specified size; content-box adds them outside; content size floored at zero
// +spec:box-model:e2a773 - box-sizing: border-box includes padding+border in width/height; content-box adds them outside
// +spec:box-sizing:8159a8 - box-sizing property indicates whether content-box or border-box is measured
// +spec:box-sizing:b0ff05 - border-box sets border-box to specified size, content-box calculated from it
// +spec:box-sizing:e2e28c - width/height refer to content-box size by default (content-box); box-sizing: border-box makes them refer to border-box size
// +spec:box-sizing:3ba6d3 - content-box floors at 0px, so border-box can't be less than padding+border
// +spec:box-sizing:fead70 - content-box: width/height set content size, border+padding added outside
// +spec:min-max-sizing:d97870 - width/height/min/max refer to physical dimensions; layout rules are logical
// +spec:min-max-sizing:2f66a6 - direction-dependent layout rules abstracted to logical start/end via writing mode
// +spec:min-max-sizing:b02ebc - sizing properties min-width/max-width/min-height/max-height and preferred aspect ratio
// +spec:replaced-elements:740f3e - constraint violation table for replaced elements with intrinsic ratio and both width/height auto
// +spec:min-max-sizing:939f2c - use min-width/min-height <length> with aspect ratio for replaced elements
// +spec:min-max-sizing:07620d - CSS 2.2 §10.4 constraint violation table for replaced elements with intrinsic ratios
// width and height together to preserve the aspect ratio while respecting min/max constraints.
fn resolve_px(px: &azul_css::props::basic::pixel::PixelValue, containing: f32, box_props: &BoxProps, is_horizontal: bool) -> Option<f32> {
// +spec:min-max-sizing:92ab8d - constraint violation table for replaced elements with intrinsic ratio (cyclic percentage contributions use auto fallback)
// +spec:min-max-sizing:ad8605 - min-height/max-height interact with percentage heights; percentages behave as auto in intrinsic contribution calc
// +spec:positioning:c0af55 - automatic minimum size of abspos box is always zero (default 0.0)
MultiValue::Exact(mw) => resolve_px(&mw.inner, containing_block_width, box_props, true).unwrap_or(0.0),
MultiValue::Exact(mh) => resolve_px(&mh.inner, containing_block_height, box_props, false).unwrap_or(0.0),
// +spec:min-max-sizing:713560 - constraint violation table for replaced elements with intrinsic ratio
// +spec:min-max-sizing:114b53 - min-width/max-width/min-height/max-height property definitions: initial values, percentage resolution against containing block, applies to elements accepting width/height
// +spec:min-max-sizing:12667d - width/height/min-width/min-height/max-width/max-height properties from CSS Sizing 3
/// +spec:min-max-sizing:205e9e - intrinsic size constraints (min/max-content contributions, min/max sizing properties)
// +spec:min-max-sizing:cac146 - min-width/min-height specify minimum box dimensions; max overridden by min
// +spec:height-calculation:22a77a - percentage min/max-height resolved against containing block; if CB height depends on content and element is not absolutely positioned, percentage treated as 0 (min-height) or none (max-height)
// +spec:height-calculation:c6c33a - min-height and max-height property resolution and application
pub fn extract_text_from_node(styled_dom: &StyledDom, node_id: NodeId) -> Option<String> {