Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132//! CSS 2.1 10.3.3 block width resolution, isolated behind one function with plain-data//! inputs and outputs (`roadmap.md` -> "Phase 1 — Engine bootstrap" step 4, "Generated//! algorithms, one category at a time"). A generated candidate implements//! [`WidthResolver`] against the types in this module alone -- no `dom`, no Stylo -- which//! is what lets a candidate crate compile independently of the DOM/style layer and lets//! the runner swap resolvers without touching anything else in `fragment.rs`.//!//! [`resolve_block_width_baseline`] is the hand rule `fragment.rs` used before this//! extraction, unchanged: `auto` fills the containing block minus this box's own margins//! and edges, and every other `auto` combination (a single auto margin, both auto//! margins, over-constraint) falls back to each margin's own definite value rather than//! being resolved. It is this seam's baseline candidate.
use dom::computed::LengthPercentageOrAuto;
/// The containing block's `direction`, the one property CSS 2.1 10.3.3's over-constraint/// rule branches on. The current corpus is exclusively left-to-right/// (`crates/layout/src/fragment.rs`'s module doc), so `Ltr` is the only value any case/// exercises today; a candidate's handling of `Rtl` is unverified by this corpus.#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum Direction { Ltr, Rtl,}
/// Plain-data inputs to the width equation, narrowed to what CSS 2.1 10.3.3 reads: the/// containing block's inline size, the box's own computed `width` and margins, its/// padding/border/box-sizing (needed to convert a `border-box`-sized `width` back to a/// content width), `direction` (which margin over-constraint discards), and min/max width/// (10.4's clamping, which no candidate at this seam's first landing implements yet --/// carried here so the signature does not have to change when one does).#[derive(Debug, Clone, Copy, PartialEq)]pub struct WidthInputs { pub containing_block_width: f64, pub width: LengthPercentageOrAuto, pub margin_left: LengthPercentageOrAuto, pub margin_right: LengthPercentageOrAuto, pub padding_left: f64, pub padding_right: f64, pub border_left: f64, pub border_right: f64, pub border_box_sizing: bool, pub direction: Direction, /// `None` when `min-width` is not a definite length (`auto`, an intrinsic-sizing /// keyword, or a percentage) -- everything this seam's first candidates leave /// unclamped (`dom::computed::min_width`). pub min_width: Option<f64>, /// Same resolution boundary as `min_width`, for `max-width` /// (`dom::computed::max_width`). pub max_width: Option<f64>,}
/// The used width (content-box, independent of `box-sizing` -- CSS 2.1's box model/// predates it) and used margins CSS 2.1 10.3.3 resolves.#[derive(Debug, Clone, Copy, PartialEq)]pub struct WidthOutputs { pub used_width: f64, pub used_margin_left: f64, pub used_margin_right: f64,}
/// One candidate's implementation of the seam: plain data in, plain data out. Every/// candidate module the generation loop compiles exports a function of this type named/// `resolve`.pub type WidthResolver = fn(&WidthInputs) -> WidthOutputs;
/// The hand rule `fragment.rs` shipped before this extraction: `auto` fills the/// containing block minus this box's own margins and edges, the one width-equation/// branch with no auto-margin balancing to do; every other `auto` combination falls back/// to treating each margin's own definite value as final. This is the seam's baseline/// candidate, not a spec-complete implementation.pub fn resolve_block_width_baseline(inputs: &WidthInputs) -> WidthOutputs { let edge_lr = inputs.padding_left + inputs.padding_right + inputs.border_left + inputs.border_right; let margin_left = length_or_auto_zero(inputs.margin_left); let margin_right = length_or_auto_zero(inputs.margin_right); let used_width = match inputs.width { LengthPercentageOrAuto::Length(w) if inputs.border_box_sizing => (w - edge_lr).max(0.0), LengthPercentageOrAuto::Length(w) => w, LengthPercentageOrAuto::Auto => { (inputs.containing_block_width - margin_left - margin_right - edge_lr).max(0.0) } // A percentage width is not resolved at this seam -- that is the // percentage-resolution seam's job -- so it falls back to the same zero every // other not-yet-modelled shape (`calc()`, an intrinsic-sizing keyword) does. LengthPercentageOrAuto::Percentage(_) | LengthPercentageOrAuto::Unresolved => 0.0, }; WidthOutputs { used_width, used_margin_left: margin_left, used_margin_right: margin_right }}
fn length_or_auto_zero(lp: LengthPercentageOrAuto) -> f64 { match lp { LengthPercentageOrAuto::Length(px) => px, LengthPercentageOrAuto::Auto | LengthPercentageOrAuto::Percentage(_) | LengthPercentageOrAuto::Unresolved => 0.0, }}
#[cfg(test)]mod tests { use super::*;
fn inputs(containing_block_width: f64, width: LengthPercentageOrAuto) -> WidthInputs { WidthInputs { containing_block_width, width, margin_left: LengthPercentageOrAuto::Length(0.0), margin_right: LengthPercentageOrAuto::Length(0.0), padding_left: 0.0, padding_right: 0.0, border_left: 0.0, border_right: 0.0, border_box_sizing: false, direction: Direction::Ltr, min_width: None, max_width: None, } }
#[test] fn baseline_fills_available_width_when_auto() { let out = resolve_block_width_baseline(&inputs(800.0, LengthPercentageOrAuto::Auto)); assert_eq!(out.used_width, 800.0); }
#[test] fn baseline_passes_an_explicit_content_box_width_through() { let out = resolve_block_width_baseline(&inputs(800.0, LengthPercentageOrAuto::Length(220.0))); assert_eq!(out.used_width, 220.0); }}