// Admitted candidate `model_0` (claude-code:default, 105/105); provenance: stacking.provenance.json use crate::stacking::{StackingBox, StackingInputs, StackingOutputs}; use dom::computed::{Position, ZIndex}; use std::collections::HashMap; fn is_positioned(b: &StackingBox) -> bool { !matches!(b.position, Position::Static) } fn establishes_context(b: &StackingBox) -> bool { b.parent.is_none() || b.opacity < 1.0 || (is_positioned(b) && matches!(b.z_index, ZIndex::Integer(_))) } fn stack_level(b: &StackingBox) -> i32 { if is_positioned(b) { if let ZIndex::Integer(n) = b.z_index { return n; } } 0 } /// Collects, into `neg`/`zero`/`pos`, the ids of every descendant of `node` that belongs /// to `node`'s stacking context as a positioned/opacity/context-establishing member -- /// walking straight through ordinary in-flow boxes and through positioned /// `z-index: auto` "pseudo" boxes (whose own positioned descendants bubble up to this /// same context per Appendix E), but never descending past a box that establishes a /// real stacking context of its own (that box is recorded here, its subtree handled by /// its own recursive `paint_context` call instead). Preserves document tree order. fn collect_members( node: usize, boxes: &[StackingBox], children_map: &HashMap>, neg: &mut Vec, zero: &mut Vec, pos: &mut Vec, ) { if let Some(kids) = children_map.get(&node) { for &child in kids { let cb = &boxes[child]; if establishes_context(cb) { let level = stack_level(cb); if level < 0 { neg.push(child); } else if level == 0 { zero.push(child); } else { pos.push(child); } } else if is_positioned(cb) { zero.push(child); collect_members(child, boxes, children_map, neg, zero, pos); } else { collect_members(child, boxes, children_map, neg, zero, pos); } } } } /// Collects the in-flow, non-positioned, non-context-establishing descendants of /// `node`, in tree order, stopping (without descending) at any positioned box or any /// box that establishes its own stacking context -- Appendix E's layer 3, scoped to /// whichever atomic unit `node` is (a real stacking context or a pseudo one). fn collect_layer3( node: usize, boxes: &[StackingBox], children_map: &HashMap>, out: &mut Vec, ) { if let Some(kids) = children_map.get(&node) { for &child in kids { let cb = &boxes[child]; if establishes_context(cb) || is_positioned(cb) { continue; } out.push(child); collect_layer3(child, boxes, children_map, out); } } } /// Appendix E's per-stacking-context paint order: this context's own background, /// negative-`z-index` child contexts (most negative first, then tree order), this /// context's own in-flow non-positioned descendants, its `z-index: auto`/`0` (and /// opacity-triggered) descendants in tree order -- each painted atomically -- then its /// positive-`z-index` child contexts (least positive first, then tree order). fn paint_context( ctx: usize, boxes: &[StackingBox], children_map: &HashMap>, out: &mut Vec, ) { out.push(ctx); let mut neg = Vec::new(); let mut zero = Vec::new(); let mut pos = Vec::new(); collect_members(ctx, boxes, children_map, &mut neg, &mut zero, &mut pos); neg.sort_by_key(|&id| stack_level(&boxes[id])); pos.sort_by_key(|&id| stack_level(&boxes[id])); for id in &neg { paint_context(*id, boxes, children_map, out); } collect_layer3(ctx, boxes, children_map, out); for id in &zero { let b = &boxes[*id]; if establishes_context(b) { paint_context(*id, boxes, children_map, out); } else { out.push(*id); collect_layer3(*id, boxes, children_map, out); } } for id in &pos { paint_context(*id, boxes, children_map, out); } } pub fn resolve(inputs: &StackingInputs) -> StackingOutputs { let boxes = &inputs.boxes; let mut children_map: HashMap> = HashMap::new(); for b in boxes { if let Some(p) = b.parent { children_map.entry(p).or_default().push(b.id); } } let root = boxes.iter().find(|b| b.parent.is_none()).map(|b| b.id); let mut out = Vec::with_capacity(boxes.len()); if let Some(root_id) = root { paint_context(root_id, boxes, &children_map, &mut out); } StackingOutputs { order: out } }