Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458// Admitted candidate `model_0` (qwen3.8-flash-next, 111/111); provenance: inline_atomic.provenance.jsonuse crate::inline_atomic::{AtomicInline, InlineAtomicInputs, InlineAtomicOutputs, InlinePlacement, LineBox};use dom::computed::{LengthPercentage, TextAlign, VerticalAlign};
/// One candidate's implementation: plain data in, plain data out.pub fn resolve(inputs: &InlineAtomicInputs) -> InlineAtomicOutputs { let content_width = inputs.content_width; let line_height = inputs.line_height; let strut_baseline = line_height / 2.0;
let mut placements: Vec<InlinePlacement> = Vec::with_capacity(inputs.inlines.len()); let mut lines: Vec<LineBox> = Vec::new();
if inputs.inlines.is_empty() { return InlineAtomicOutputs { placements, lines, total_height: 0.0, last_baseline: None, }; }
// Group inlines into lines let mut current_line_indices: Vec<usize> = Vec::new(); let mut current_line_width: f64 = 0.0; let mut line_groups: Vec<Vec<usize>> = Vec::new();
for (i, inline) in inputs.inlines.iter().enumerate() { let w = inline.margin_box_width; // If the current line is empty, always add the box (even if wider than container) if current_line_indices.is_empty() { current_line_indices.push(i); current_line_width = w; } else { // Check if adding this box would exceed content_width if current_line_width + w > content_width { // Start a new line line_groups.push(std::mem::take(&mut current_line_indices)); current_line_width = 0.0; current_line_indices.push(i); current_line_width = w; } else { current_line_indices.push(i); current_line_width += w; } } } // Push the last line if it has items if !current_line_indices.is_empty() { line_groups.push(current_line_indices); }
let mut y_offset = 0.0;
for group in line_groups { // For each line, we need to: // 1. Determine the baseline position relative to the line box top. // 2. Calculate the height of the line box. // 3. Place each box horizontally (text-align) and vertically.
// Step 1 & 2: Determine baseline and height. // The strut is always present. Its baseline is at strut_baseline from the top of the strut. // The strut's top is at some offset. Let's define the line box top as 0 for now, // and find where the baseline sits within it. // We need to find the vertical position of the baseline for the line. // Let B be the baseline position from the top of the line box. // The strut occupies [B - strut_baseline, B - strut_baseline + line_height]. // For baseline-aligned boxes: their baseline is at B. // Box top = B - inline.baseline // Box bottom = B - inline.baseline + inline.margin_box_height // For top-aligned boxes: top edge at 0. // For bottom-aligned boxes: bottom edge at H (line height). // For middle-aligned boxes: midpoint at B. // Top = B - margin_box_height / 2 // Bottom = B + margin_box_height / 2 // For length-aligned boxes: baseline at B - shift (shift positive raises box, so baseline moves up?) // Wait, spec says: "raise (positive value) ... above the baseline". // If baseline is at B, and we raise the box by shift, the box's baseline moves to B - shift. // So Box top = (B - shift) - inline.baseline // We need to find B and H such that: // - All boxes fit within [0, H] // - H >= line_height // - The strut fits: [B - strut_baseline, B - strut_baseline + line_height] within [0, H] // So B >= strut_baseline and B - strut_baseline + line_height <= H => B <= H - line_height + strut_baseline // Strategy: // 1. Compute preliminary extents assuming baseline alignment for baseline/middle/length boxes. // Top-aligned boxes have top=0. Bottom-aligned boxes have bottom=H. // This is circular for Top/Bottom because H depends on them and they depend on H. // Let's separate boxes into: // - Baseline-relative: Baseline, Middle, Length, Other (treated as Baseline) // - Top-aligned: Top // - Bottom-aligned: Bottom // Let's compute the constraints on B (baseline position from line top) and H (line height). let mut min_top_from_baseline: f64 = 0.0; // Maximum distance ABOVE baseline (negative offset from baseline) let mut max_bottom_from_baseline: f64 = 0.0; // Maximum distance BELOW baseline // Actually, let's track: // For each baseline-relative box, its top relative to baseline is -inline.baseline. // Its bottom relative to baseline is -inline.baseline + inline.margin_box_height. let mut min_rel_top: f64 = -strut_baseline; // Strut top relative to baseline let mut max_rel_bottom: f64 = line_height - strut_baseline; // Strut bottom relative to baseline let mut has_top_aligned = false; let mut has_bottom_aligned = false; // First pass: baseline-relative boxes for &idx in &group { let inline = &inputs.inlines[idx]; match inline.vertical_align { VerticalAlign::Baseline | VerticalAlign::Other => { let rel_top = -inline.baseline; let rel_bottom = -inline.baseline + inline.margin_box_height; if rel_top < min_rel_top { min_rel_top = rel_top; } if rel_bottom > max_rel_bottom { max_rel_bottom = rel_bottom; } } VerticalAlign::Length(lp) => { let shift = match lp { LengthPercentage::Length(px) => px, _ => 0.0, }; // Positive shift raises the box. So the box's baseline is at B - shift. // Top relative to B: (B - shift) - inline.baseline - B = -shift - inline.baseline let rel_top = -shift - inline.baseline; let rel_bottom = -shift - inline.baseline + inline.margin_box_height; if rel_top < min_rel_top { min_rel_top = rel_top; } if rel_bottom > max_rel_bottom { max_rel_bottom = rel_bottom; } } VerticalAlign::Middle => { // Midpoint at B. // Top = B - h/2. Rel top = -h/2. // Bottom = B + h/2. Rel bottom = h/2. let rel_top = -inline.margin_box_height / 2.0; let rel_bottom = inline.margin_box_height / 2.0; if rel_top < min_rel_top { min_rel_top = rel_top; } if rel_bottom > max_rel_bottom { max_rel_bottom = rel_bottom; } } VerticalAlign::Top => { has_top_aligned = true; } VerticalAlign::Bottom => { has_bottom_aligned = true; } } } // Now determine B and H. // The line box top is 0. The baseline is at B. // The strut occupies [B - strut_baseline, B - strut_baseline + line_height]. // Baseline-relative boxes occupy [B + rel_top, B + rel_bottom]. // If there are no Top/Bottom aligned boxes: // The line box must contain the strut and all baseline-relative boxes. // Top of line box = min(0, min(B + rel_top for all boxes)) // But we define line box top as 0. So we shift everything so the topmost point is 0. // Let Top_extent = min(min_rel_top, -strut_baseline) (already included in min_rel_top) // Let Bottom_extent = max(max_rel_bottom, line_height - strut_baseline) (already included) // The height H = Bottom_extent - Top_extent. // The baseline B relative to line box top = -Top_extent. // Because Top_extent is the most negative offset from baseline. // If Top_extent is -10, then baseline is 10 units below the top of the line box. let mut top_extent = min_rel_top; // Most negative offset from baseline let mut bottom_extent = max_rel_bottom; // Most positive offset from baseline // Handle Top-aligned boxes: // They align their top edge with the line box top (0). // Their bottom is at inline.margin_box_height. // This box contributes a bottom extent of H - B (distance from baseline to bottom of box). // Wait, if top is at 0, and baseline is at B, then top relative to baseline is -B. // Bottom relative to baseline is H - B. // So this box extends from -B to H-B relative to baseline. // This imposes constraints on B and H. // Handle Bottom-aligned boxes: // They align their bottom edge with the line box bottom (H). // Their top is at H - inline.margin_box_height. // Top relative to baseline: H - h - B. // Bottom relative to baseline: H - B. // This is circular. Let's solve iteratively or analytically. // Let's assume we know B and H. // For Top-aligned box i: // Top at 0. Bottom at h_i. // Constraint: h_i <= H (box fits in line) // It affects bottom_extent: max(bottom_extent, H - B) // It affects top_extent: min(top_extent, -B) // For Bottom-aligned box j: // Bottom at H. Top at H - h_j. // Constraint: H - h_j >= 0 => H >= h_j // It affects bottom_extent: max(bottom_extent, H - B) // It affects top_extent: min(top_extent, H - h_j - B) // We need to find B and H such that: // 1. H >= line_height // 2. H >= max_height_of_top_aligned_boxes (if any) // 3. H >= max_height_of_bottom_aligned_boxes (if any) // 4. The line box contains all boxes. // Let's try to find B first, assuming no Top/Bottom boxes, then adjust. // If no Top/Bottom boxes: // H = bottom_extent - top_extent // B = -top_extent // Check if H >= line_height. If not, H = line_height. // If H increases, B might need to adjust? // The strut is fixed relative to baseline. // If we just set H = max(bottom_extent - top_extent, line_height), // and B = -top_extent, // Then the strut is at [B - strut_baseline, B - strut_baseline + line_height]. // The line box is [0, H]. // We need B - strut_baseline >= 0 => B >= strut_baseline. // And B - strut_baseline + line_height <= H. // Let's compute B and H for baseline-relative boxes first. let mut B = -top_extent; let mut H = bottom_extent - top_extent; if H < line_height { H = line_height; // If we increase H, we might need to adjust B to keep the strut centered? // No, the strut's position is defined by the baseline. // The baseline position B is determined by the content. // If H > bottom_extent - top_extent, we have extra space. // Where does it go? // The spec says "minimize the line box height". // So H should be exactly the extent of the content. // But H must be at least line_height. // If the content extent is less than line_height, the strut dictates the height. // The strut is [B - strut_baseline, B - strut_baseline + line_height]. // The line box is [0, H]. // If H = line_height, and the content is smaller, the content is centered? // No, the baseline is fixed by the content. // If the content extent is 10px, and line_height is 20px. // top_extent = -5, bottom_extent = 5. B = 5. H = 10. // But H must be >= 20. So H = 20. // The strut is at [5 - 10, 5 - 10 + 20] = [-5, 15]. // The line box is [0, 20]. // The strut overflows the top? No, the line box must contain the strut. // So we must adjust B so that the strut fits in [0, H]. // Strut top = B - strut_baseline >= 0 => B >= strut_baseline. // Strut bottom = B - strut_baseline + line_height <= H => B <= H - line_height + strut_baseline. // If we set H = line_height, then B must be strut_baseline. // Then the content is positioned relative to B = strut_baseline. // So we recalculate top_extent and bottom_extent relative to this new B? // No, the content's position relative to its own baseline is fixed. // The baseline's position in the line box is B. // If we force B = strut_baseline, then the content might overflow. // Correct approach: // The line box height H is determined by the tallest content. // If the content (including strut) requires more than line_height, H is that height. // If the content requires less, H is line_height. // In the latter case, the baseline is positioned such that the strut is centered? // "The half-leading above and below the strut's content area is distributed equally". // This implies the strut is centered in the line box if the line box is exactly line_height. // So B = line_height / 2 = strut_baseline. if bottom_extent - top_extent < line_height { B = strut_baseline; H = line_height; // Recalculate extents relative to this B? // The content's position relative to B is fixed. // So the actual top of content is B + min_rel_top. // The actual bottom is B + max_rel_bottom. // We need to ensure these are within [0, H]. // Since the content extent is less than line_height, and B is centered, // it should fit. } } // Now handle Top and Bottom aligned boxes. // We need to adjust B and H to accommodate them. // For Top-aligned boxes: // They want their top at 0. // If their top relative to current B is T_rel = -B, then the box top is at B + T_rel = 0. // This is consistent with B being the baseline position. // The box bottom is at H_box = h_i. // This box extends from 0 to h_i. // Relative to baseline B, it extends from -B to h_i - B. // So it contributes to top_extent: min(top_extent, -B) // And bottom_extent: max(bottom_extent, h_i - B) // For Bottom-aligned boxes: // They want their bottom at H. // Box top is at H - h_j. // Relative to baseline B, top is H - h_j - B. // Bottom is H - B. // Contributes to top_extent: min(top_extent, H - h_j - B) // Contributes to bottom_extent: max(bottom_extent, H - B) // We need to find B and H that satisfy all constraints. // Let's iterate. let mut changed = true; let mut iterations = 0; while changed && iterations < 100 { changed = false; iterations += 1; let mut new_top_extent = min_rel_top; let mut new_bottom_extent = max_rel_bottom; // Include strut if -strut_baseline < new_top_extent { new_top_extent = -strut_baseline; } if line_height - strut_baseline > new_bottom_extent { new_bottom_extent = line_height - strut_baseline; } // Include baseline-relative boxes (already in min/max_rel) // Include Top-aligned for &idx in &group { let inline = &inputs.inlines[idx]; if inline.vertical_align == VerticalAlign::Top { let h = inline.margin_box_height; // Top at 0. Relative to B: -B. // Bottom at h. Relative to B: h - B. if -B < new_top_extent { new_top_extent = -B; } if h - B > new_bottom_extent { new_bottom_extent = h - B; } } } // Include Bottom-aligned for &idx in &group { let inline = &inputs.inlines[idx]; if inline.vertical_align == VerticalAlign::Bottom { let h = inline.margin_box_height; // Bottom at H. Top at H - h. // Relative to B: H - h - B, H - B. if H - h - B < new_top_extent { new_top_extent = H - h - B; } if H - B > new_bottom_extent { new_bottom_extent = H - B; } } } let new_B = -new_top_extent; let new_H = new_bottom_extent - new_top_extent; if (new_B - B).abs() > 1e-9 || (new_H - H).abs() > 1e-9 { B = new_B; H = new_H; changed = true; } } // Ensure H >= line_height if H < line_height { H = line_height; // Re-center strut? // If we just increase H, the baseline B might need to shift. // The strut must fit. // Strut top = B - strut_baseline >= 0 // Strut bottom = B - strut_baseline + line_height <= H // If we increase H, we can keep B the same if it still fits. // If B - strut_baseline < 0, we need to increase B. // If B - strut_baseline + line_height > H, we need to decrease B. if B - strut_baseline < 0.0 { B = strut_baseline; } if B - strut_baseline + line_height > H { B = H - line_height + strut_baseline; } } // Now we have B (baseline from line top) and H (line height). // Calculate horizontal placement let total_width: f64 = group.iter().map(|&i| inputs.inlines[i].margin_box_width).sum(); let remaining = content_width - total_width; let mut x_start = 0.0; match inputs.text_align { TextAlign::Left | TextAlign::Other => { x_start = 0.0; } TextAlign::Right => { x_start = remaining; } TextAlign::Center => { x_start = remaining / 2.0; } } let mut current_x = x_start; for &idx in &group { let inline = &inputs.inlines[idx]; let w = inline.margin_box_width; let h = inline.margin_box_height; let y_pos; match inline.vertical_align { VerticalAlign::Baseline | VerticalAlign::Other => { // Baseline at B. Box baseline at B. // Box top = B - inline.baseline y_pos = B - inline.baseline; } VerticalAlign::Length(lp) => { let shift = match lp { LengthPercentage::Length(px) => px, _ => 0.0, }; // Baseline at B - shift. // Box top = (B - shift) - inline.baseline y_pos = B - shift - inline.baseline; } VerticalAlign::Middle => { // Midpoint at B. // Top = B - h/2 y_pos = B - h / 2.0; } VerticalAlign::Top => { // Top at 0 y_pos = 0.0; } VerticalAlign::Bottom => { // Bottom at H y_pos = H - h; } } placements.push(InlinePlacement { x: current_x, y: y_offset + y_pos, }); current_x += w; } lines.push(LineBox { top: y_offset, height: H, baseline: B, }); y_offset += H; } let total_height = y_offset; let last_baseline = lines.last().map(|l| l.top + l.baseline); InlineAtomicOutputs { placements, lines, total_height, last_baseline, }}