use euclid::default::Rect;
use kurbo::{Affine, Vec2};
use style::{
properties::generated::style_structs::Box as BoxStyleStruct,
values::{
computed::{CSSPixelLength, Rotate},
generics::transform::{Scale, Translate},
},
};
pub fn resolve_2d_transform(
box_styles: &BoxStyleStruct,
reference_box: Rect<CSSPixelLength>,
scale: f64,
) -> Option<Affine> {
let translate = match &box_styles.translate {
Translate::None => None,
Translate::Translate(x, y, _z) => Some(Vec2 {
x: x.resolve(reference_box.width()).px() as f64,
y: y.resolve(reference_box.height()).px() as f64,
}),
};
let rotate = match &box_styles.rotate {
Rotate::None => None,
Rotate::Rotate(angle) => Some(angle.degrees() as f64),
Rotate::Rotate3D(_, _, _, _) => None,
};
let scale_transform = match &box_styles.scale {
Scale::None => None,
Scale::Scale(x, y, _z) => Some(Vec2 {
x: *x as f64 * scale,
y: *y as f64 * scale,
}),
};
let transform = if box_styles.transform.0.is_empty() {
None
} else {
box_styles
.transform
.to_transform_3d_matrix(Some(&reference_box))
.ok()
.filter(|(_t, has_3d)| !has_3d)
.map(|(t, _has_3d)| {
Affine::new(
[
t.m11,
t.m12,
t.m21,
t.m22,
t.m41 * scale as f32,
t.m42 * scale as f32,
]
.map(|v| v as f64),
)
})
};
if translate.is_none() && rotate.is_none() && scale_transform.is_none() && transform.is_none() {
return None;
}
let transform_origin = &box_styles.transform_origin;
let origin_translation = Affine::translate(Vec2 {
x: transform_origin
.horizontal
.resolve(reference_box.width())
.px() as f64,
y: transform_origin
.vertical
.resolve(reference_box.height())
.px() as f64,
});
let mut resolved = Affine::IDENTITY;
if let Some(translation) = translate {
resolved = resolved.then_translate(translation)
}
if let Some(rotation) = rotate {
resolved = resolved.then_rotate(rotation)
}
if let Some(scale_transform) = scale_transform {
resolved = resolved.then_scale_non_uniform(scale_transform.x, scale_transform.y)
}
if let Some(transform) = transform {
resolved *= transform;
}
resolved = origin_translation * resolved * origin_translation.inverse();
if resolved != Affine::IDENTITY {
Some(resolved)
} else {
None
}
}