Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135//! The `width` generated function's place in the engine: 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"). The types a candidate implements against are re-exported from//! [`crate::width_types`] so `layout::width::...` names them; this module says how the//! engine fills them, and holds the baseline the engine runs when the committed function//! does not build against a new types file. A candidate crate compiles independently of the//! DOM/style layer, and the runner swaps resolvers without touching anything else in//! `fragment.rs`.//!//! **Written against any types file.** A job's types file is model-written and chooses its//! inputs from the engine's fixed list ([`crate::width_engine`]), so nothing here names an//! input field. The engine builds a [`WidthEngineValues`] and calls through [`call`], which//! fills the inputs with [`inputs_from`] (written by `build.rs` from the types file in//! place). The baseline reads the engine's values rather than the inputs, which may not//! hold what it needs, so [`resolve_block_width_baseline`] answers only a call made through//! [`call`]. The committed generated function (`generated/width.rs`) is the one part written//! against one types file: it and that file are replaced together.//!//! [`baseline`] is this function's deliberately wrong starting candidate: every box is zero//! wide with zero margins, whatever its `width`, margins or containing block.
use std::cell::Cell;
pub use crate::width_engine::{WidthEngineAnswer, WidthEngineValues};pub use crate::width_types::{WidthInputs, WidthOutputs, WidthResolver};
use dom::node::NodeId;
include!(concat!(env!("OUT_DIR"), "/width_inputs_from.rs"));
/// 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,}
thread_local! { /// The engine's values for the call [`call`] is making, so /// [`resolve_block_width_baseline`] can answer it; `None` outside a call. static CALL_VALUES: Cell<Option<WidthEngineValues>> = const { Cell::new(None) };}
/// One call the engine made to the function for a box's own width, as `fragment.rs`/// `layout_box_styled` records it (`crate::call_recording`): the box and the engine's values/// for it. The call a ratio box makes again for its margins, the float path (which does not/// call) and a box whose width a table or a ratio replaces are not recorded, because their/// answer is not the width the browsers measure for the box.#[derive(Debug, Clone, Copy, PartialEq)]pub struct WidthCall { pub node: NodeId, /// The engine's values at the call (`inputs_from` turns them into what the resolver /// was handed). pub values: WidthEngineValues,}
/// Asks `resolver` about the box `values` describes: fills the types file's inputs from/// `values` ([`inputs_from`]) and returns the answer. How the engine calls every `width`/// resolver.pub fn call(resolver: WidthResolver, values: &WidthEngineValues) -> WidthOutputs { let previous = CALL_VALUES.with(|v| v.replace(Some(*values))); let out = resolver(&inputs_from(values)); CALL_VALUES.with(|v| v.set(previous)); out}
/// Deliberately wrong starting candidate: a box is zero wide with zero margins.pub fn baseline(_values: &WidthEngineValues) -> WidthOutputs { WidthOutputs { used_width: 0.0, used_margin_left: 0.0, used_margin_right: 0.0 }}
/// [`baseline`] as a resolver, for the engine's tables of resolvers/// (`fragment::Resolvers::baselines`). It ignores `inputs` and reads the values of the call/// in progress, so it answers only a call made through [`call`], which is every call the/// engine makes; called any other way it panics.pub fn resolve_block_width_baseline(_inputs: &WidthInputs) -> WidthOutputs { let values = CALL_VALUES .with(Cell::get) .expect("width::resolve_block_width_baseline answers only a call made through width::call"); baseline(&values)}
#[cfg(test)]mod tests { use super::*; use dom::computed::LengthPercentageOrAuto;
fn values(containing_block_width: f64, width: LengthPercentageOrAuto) -> WidthEngineValues { WidthEngineValues { 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, } }
fn answer(v: &WidthEngineValues) -> WidthOutputs { call(resolve_block_width_baseline, v) }
#[test] fn the_starting_candidate_makes_every_box_zero_wide() { assert_eq!( answer(&values(800.0, LengthPercentageOrAuto::Length(220.0))), WidthOutputs { used_width: 0.0, used_margin_left: 0.0, used_margin_right: 0.0 } ); assert_eq!(answer(&values(800.0, LengthPercentageOrAuto::Auto)).used_width, 0.0); }
#[test] fn the_baseline_resolver_answers_a_call_with_the_values_of_that_call() { let v = values(800.0, LengthPercentageOrAuto::Auto); assert_eq!(call(resolve_block_width_baseline, &v), baseline(&v)); assert!(CALL_VALUES.with(Cell::get).is_none(), "the values outlive the call"); }
#[test] #[should_panic(expected = "answers only a call made through width::call")] fn the_baseline_resolver_refuses_a_call_the_engine_did_not_make() { resolve_block_width_baseline(&inputs_from(&values(800.0, LengthPercentageOrAuto::Auto))); }}