render: resolve CSS round length math

This commit is contained in:
SGavrl committed 2026-07-23 20:09:19 +00:00
1 parent e90ea7eacc
commit 94897724d8
1 file changed
+53
+53
View File
@@ -1752,9 +1752,37 @@ fn resolve_contextual(value: &str, context: &LengthContext) -> Option<f32> {
return Some(preferred.min(high).max(low));
}
}
if let Some(rest) = value.strip_prefix("round(") {
let end = find_matching_paren(rest)?;
let args = split_top_level(&rest[..end], ',');
let (strategy, value_index) = match args.first()?.trim() {
"nearest" | "up" | "down" | "to-zero" => (args[0].trim(), 1),
_ => ("nearest", 0),
};
let resolved = eval_contextual_calc(args.get(value_index)?.trim(), context)?;
let step = match args.get(value_index + 1) {
Some(step) => eval_contextual_calc(step.trim(), context)?,
None => 1.0,
};
return round_css_value(resolved, step, strategy);
}
contextual_atom(value, context)
}
fn round_css_value(value: f32, step: f32, strategy: &str) -> Option<f32> {
if !value.is_finite() || !step.is_finite() || step == 0.0 {
return None;
}
let quotient = value / step.abs();
let rounded = match strategy {
"up" => quotient.ceil(),
"down" => quotient.floor(),
"to-zero" => quotient.trunc(),
_ => quotient.round(),
};
Some(rounded * step.abs())
}
fn contextual_atom(value: &str, context: &LengthContext) -> Option<f32> {
let lower = value.trim().to_ascii_lowercase();
let parse = |number: &str| number.trim().parse::<f32>().ok();
@@ -1915,6 +1943,20 @@ fn resolve_length(value: &str) -> Option<f32> {
return Some(mid.min(hi).max(lo));
}
}
if let Some(rest) = v.strip_prefix("round(") {
let end = find_matching_paren(rest)?;
let args = split_top_level(&rest[..end], ',');
let (strategy, value_index) = match args.first()?.trim() {
"nearest" | "up" | "down" | "to-zero" => (args[0].trim(), 1),
_ => ("nearest", 0),
};
let resolved = eval_calc(args.get(value_index)?.trim())?;
let step = match args.get(value_index + 1) {
Some(step) => eval_calc(step.trim())?,
None => 1.0,
};
return round_css_value(resolved, step, strategy);
}
if v.contains('(') {
return None; // an unhandled function (env(), ...): no safe fallback
}
@@ -2965,6 +3007,17 @@ mod tests {
),
Some(122.0)
);
assert_eq!(
resolve_contextual_length(
"calc(round(247px * 1, 10px))",
context.0,
context.1,
context.2,
context.3,
context.4,
),
Some(250.0)
);
}
#[test]