Implement calc-mix()
LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-mix-computed.tentative-expected.txt
WebKit's CSS calc system uses two parallel tree representations: CSSCalcTree (parsed/CSS-level form, used during parsing, validation, and serialization) and StyleCalculationTree (resolved/style-level form, used during cascade and computed-value resolution). Every new calc function must be threaded through all passes on both trees: copying, simplification, evaluation, serialization, and computed-style dependency tracking.
This commit implements the CSS calc-mix() function from CSS Values Level 5 — a weighted average across a list of calc terms — across the entire pipeline: parser, simplification, evaluation, serialization, type resolution, and style resolution. The implementation is gated behind a new CSSCalcMixEnabled preference flag. calc-mix() introduces a weighted-average node whose semantics require normalizing percentage weights that may not sum to 100%, may be omitted entirely, or may all be 0% — and resolving the result type across potentially heterogeneous operands. The commit explicitly links csswg-drafts issue #13839, acknowledging open spec questions that force the implementation to make judgment calls in undefined territory.
Significance
This adds substantial new attack surface across WebKit's most complex CSS subsystem, with the spec itself carrying open questions about simplification semantics. Weight normalization, heterogeneous type mixing, and tree-context functions inside weight arguments each create underspecified edge cases the implementation must handle unilaterally.
Audit directions
- Weight normalization logic. Tests reveal the implementation renormalizes when weights exceed 100% (
calc-mix(1 75%, 3 75%)→ 2) but silently discards remainder when they fall short (calc-mix(1 25%, 3 25%)→ 1). The algorithm boundary between these behaviors and its interaction with auto-distributed weights (calc-mix(1 25%, 3 25%, 5, 7)→ 4) is ripe for floating-point precision bugs and off-by-one errors. - Zero-weight type resolution. When all weights are 0%, the function must still produce a correctly-typed zero (
0%vs0px) based on operand type analysis. This is a degenerate path that combines type resolution with zero-value semantics — the ordering of type-resolution decisions here is subtle and could produce unexpected results with mixed-unit inputs. - Heterogeneous type mixing. Combining
em,px, and%in a singlecalc-mix()requires the simplification pass to handle mixed-unit weighted sums duringCSSCalcTree+Simplification. This same code region has historically been a source of type confusion bugs incalc(). sibling-index()inside weight arguments. The spec allows tree-context functions inside weight percentages. The dependency tracker inCSSCalcTree+ComputedStyleDependencies.cppmust correctly propagate these dependencies upward. Missing dependency annotations would cause stale computed values.- Simplification under spec ambiguity. With csswg-drafts #13839 open, the simplification pass makes unilateral decisions the spec may later contradict. The tests show
calc-mix()is expected to compose withsign(),max(), and nestedcalc()— any simplification assumption baked into the implementation could produce wrong results at these composition points.