1use crate::{ExpandedNode, TransformAndBounds};
2use kurbo::Affine;
3use pax_runtime_api::{Axis, Size, Transform2D};
4
5pub fn compute_tab(node: &ExpandedNode, container_tab: &TransformAndBounds) -> TransformAndBounds {
8 let new_accumulated_bounds_and_current_node_size =
12 { node.get_size_computed(container_tab.bounds) };
13
14 let node_transform_property_computed = {
15 node.get_common_properties()
16 .borrow()
17 .transform
18 .get()
19 .compute_transform2d_matrix(
20 new_accumulated_bounds_and_current_node_size.clone(),
21 container_tab.bounds,
22 )
23 };
24
25 let desugared_transform = {
27 let comm = node.get_common_properties();
29 let comm = comm.borrow();
30 let mut desugared_transform2d = Transform2D::default();
31
32 let translate = [
33 if let Some(ref val) = comm.x {
34 val.get().clone()
35 } else {
36 Size::ZERO()
37 },
38 if let Some(ref val) = comm.y {
39 val.get().clone()
40 } else {
41 Size::ZERO()
42 },
43 ];
44 desugared_transform2d.translate = Some(translate);
45
46 let anchor = [
47 if let Some(ref val) = comm.anchor_x {
48 val.get().clone()
49 } else {
50 Size::ZERO()
51 },
52 if let Some(ref val) = comm.anchor_y {
53 val.get().clone()
54 } else {
55 Size::ZERO()
56 },
57 ];
58 desugared_transform2d.anchor = Some(anchor);
59
60 let scale = [
61 if let Some(ref val) = comm.scale_x {
62 val.get().clone()
63 } else {
64 Size::Percent(pax_runtime_api::Numeric::from(100.0))
65 },
66 if let Some(ref val) = comm.scale_y {
67 val.get().clone()
68 } else {
69 Size::Percent(pax_runtime_api::Numeric::from(100.0))
70 },
71 ];
72 desugared_transform2d.scale = Some(scale);
73
74 let skew = [
75 if let Some(ref val) = comm.skew_x {
76 val.get().get_as_float()
77 } else {
78 0.0
79 },
80 if let Some(ref val) = comm.skew_y {
81 val.get().get_as_float()
82 } else {
83 0.0
84 },
85 ];
86 desugared_transform2d.skew = Some(skew);
87
88 let rotate = if let Some(ref val) = comm.rotate {
89 val.get().clone()
90 } else {
91 pax_runtime_api::Rotation::ZERO()
92 };
93 desugared_transform2d.rotate = Some(rotate);
94
95 desugared_transform2d.compute_transform2d_matrix(
96 new_accumulated_bounds_and_current_node_size.clone(),
97 container_tab.bounds,
98 )
99 };
100
101 let new_accumulated_transform =
102 container_tab.transform * desugared_transform * node_transform_property_computed;
103
104 TransformAndBounds {
112 transform: new_accumulated_transform,
113 bounds: new_accumulated_bounds_and_current_node_size,
114 }
115}
116
117pub trait ComputableTransform {
118 fn compute_transform2d_matrix(
119 &self,
120 node_size: (f64, f64),
121 container_bounds: (f64, f64),
122 ) -> Affine;
123}
124
125impl ComputableTransform for Transform2D {
126 fn compute_transform2d_matrix(
129 &self,
130 node_size: (f64, f64),
131 container_bounds: (f64, f64),
132 ) -> Affine {
133 let anchor_transform = match &self.anchor {
140 Some(anchor) => Affine::translate((
141 match anchor[0] {
142 Size::Pixels(pix) => -pix.get_as_float(),
143 Size::Percent(per) => -node_size.0 * (per / 100.0),
144 Size::Combined(pix, per) => {
145 -pix.get_as_float() + (-node_size.0 * (per / 100.0))
146 }
147 },
148 match anchor[1] {
149 Size::Pixels(pix) => -pix.get_as_float(),
150 Size::Percent(per) => -node_size.1 * (per / 100.0),
151 Size::Combined(pix, per) => {
152 -pix.get_as_float() + (-node_size.0 * (per / 100.0))
153 }
154 },
155 )),
156 None => Affine::default(),
158 };
159
160 let (scale_x, scale_y) = if let Some(scale) = self.scale {
162 (scale[0].expect_percent(), scale[1].expect_percent())
163 } else {
164 (1.0, 1.0)
165 };
166
167 let (skew_x, skew_y) = if let Some(skew) = self.skew {
168 (skew[0], skew[1])
169 } else {
170 (0.0, 0.0)
171 };
172
173 let (translate_x, translate_y) = if let Some(translate) = &self.translate {
174 (
175 translate[0].evaluate(container_bounds, Axis::X),
176 translate[1].evaluate(container_bounds, Axis::Y),
177 )
178 } else {
179 (0.0, 0.0)
180 };
181
182 let rotate_rads = if let Some(rotate) = &self.rotate {
183 rotate.get_as_radians()
184 } else {
185 0.0
186 };
187
188 let cos_theta = rotate_rads.cos();
189 let sin_theta = rotate_rads.sin();
190
191 let a = scale_x * cos_theta - scale_y * skew_x * sin_theta;
193 let b = scale_x * sin_theta + scale_y * skew_x * cos_theta;
194 let c = -scale_y * sin_theta + scale_x * skew_y * cos_theta;
195 let d = scale_y * cos_theta + scale_x * skew_y * sin_theta;
196
197 let e = translate_x;
199 let f = translate_y;
200
201 let coeffs = [a, b, c, d, e, f];
202 let transform = Affine::new(coeffs);
203
204 let previous_transform = match &self.previous {
206 Some(previous) => (*previous).compute_transform2d_matrix(node_size, container_bounds),
207 None => Affine::default(),
208 };
209
210 transform * anchor_transform * previous_transform
211 }
212}