Open noahbald opened 1 month ago
Yeah the syntax for SVG transform attributes is completely different from CSS. For example rotate takes additional arguments for the center point instead of using transform-origin. I'd probably recommend using a different parser and value type for the presentation attributes vs CSS.
Yep, absolutely -- SVG transform seems to be a kind of superset of CSS transforms. Thought it'd be worth making this issue for awareness anyway. For what it's worth, I do have a workaround using some (yucky) regex.
use lazy_static::lazy_static;
fn svg_transform_to_css_transform(css_string: String) -> Cow<'_, str> {
// transform `rotate(r, x, y)` -> `matrix(a, b, c, d, e, f)`
// see https://github.com/svg/svgo/blob/a8472bc45fe1d92d5f848a08cf4d5c8f4a531ad9/plugins/_transforms.js#L511
let v = ROTATE_LONG.replace_all(&value, |caps: ®ex::Captures| {
let original = format!("rotate({} {} {})", &caps["r"], &caps["x"], &caps["y"]);
let Ok(deg) = caps["r"].parse::<f64>() else {
log::debug!("r failed: {}", &caps["r"]);
return original;
};
let Ok(x) = caps["x"].parse::<f64>() else {
log::debug!("x failed: {}", &caps["x"]);
return original;
};
let Ok(y) = caps["y"].parse::<f64>() else {
log::debug!("y failed: {}", &caps["y"]);
return original;
};
let rad = deg.to_radians();
let cos = rad.cos();
let sin = rad.sin();
format!(
"matrix({cos} {sin} {} {cos} {} {})",
-sin,
(1.0 - cos) * x + sin * y,
(1.0 - cos) * y - sin * x
)
});
// transform `f(a b ...)` -> `f(a, b, ...)`
let v = LIST_SEP_SPACE.replace_all(&v, "$a, ");
// transform `rotate(r)` -> `rotate(rdeg)`
value = ROTATE
.replace_all(&v, |caps: ®ex::Captures| {
format!("{}({}deg", &caps["f"], &caps["v"])
})
}
lazy_static! {
static ref LIST_SEP_SPACE: regex::Regex = regex::Regex::new(r"(?<a>\d)\s+").unwrap();
static ref ROTATE: regex::Regex =
regex::Regex::new(r"(?<f>rotate|skewX|skewY)\((?<v>\s*[^\s\),]+)").unwrap();
static ref ROTATE_LONG: regex::Regex = regex::Regex::new(
r"rotate\((?<r>[\d\.e-]+)[^\d\)]+?(?<x>[\d\.e-]+)[^\d\)]+?(?<y>[\d\.e-]+)\)"
)
.unwrap();
}
In terms of lightningcss, having a separate parser makes sense to me.
Would a separate parser mean having something similar to Property
but for HTML presentation attributes instead of CSS properties?
Because
transform="..."
tends to be unit-less and space-separated they aren't parsed correctly by lightning-css despite being a presentation attribute. For example, the following is a valid transform in HTML, but not CSSWhile the following is valid in both CSS and HTML
Yet, they are functionally equivalent.
Since in a HTML context the expected syntax is slightly difference, it might be nice to specify in the parser options whether a property being parsed is a presentation attribute