1use super::scene::{Path, PathVertex};
2use crate::{color::Color, json::ToJson};
3pub use pathfinder_geometry::*;
4use rect::RectF;
5use refineable::Refineable;
6use serde::{Deserialize, Deserializer};
7use serde_json::json;
8use vector::{vec2f, Vector2F};
9
10pub struct PathBuilder {
11 vertices: Vec<PathVertex>,
12 start: Vector2F,
13 current: Vector2F,
14 contour_count: usize,
15 bounds: RectF,
16}
17
18enum PathVertexKind {
19 Solid,
20 Quadratic,
21}
22
23impl Default for PathBuilder {
24 fn default() -> Self {
25 PathBuilder::new()
26 }
27}
28
29impl PathBuilder {
30 pub fn new() -> Self {
31 Self {
32 vertices: Vec::new(),
33 start: vec2f(0., 0.),
34 current: vec2f(0., 0.),
35 contour_count: 0,
36 bounds: RectF::default(),
37 }
38 }
39
40 pub fn reset(&mut self, point: Vector2F) {
41 self.vertices.clear();
42 self.start = point;
43 self.current = point;
44 self.contour_count = 0;
45 }
46
47 pub fn line_to(&mut self, point: Vector2F) {
48 self.contour_count += 1;
49 if self.contour_count > 1 {
50 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
51 }
52
53 self.current = point;
54 }
55
56 pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
57 self.contour_count += 1;
58 if self.contour_count > 1 {
59 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
60 }
61
62 self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
63 self.current = point;
64 }
65
66 pub fn build(mut self, color: Color, clip_bounds: Option<RectF>) -> Path {
67 if let Some(clip_bounds) = clip_bounds {
68 self.bounds = self.bounds.intersection(clip_bounds).unwrap_or_default();
69 }
70 Path {
71 bounds: self.bounds,
72 color,
73 vertices: self.vertices,
74 }
75 }
76
77 fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
78 if self.vertices.is_empty() {
79 self.bounds = RectF::new(a, Vector2F::zero());
80 }
81 self.bounds = self.bounds.union_point(a).union_point(b).union_point(c);
82
83 match kind {
84 PathVertexKind::Solid => {
85 self.vertices.push(PathVertex {
86 xy_position: a,
87 st_position: vec2f(0., 1.),
88 });
89 self.vertices.push(PathVertex {
90 xy_position: b,
91 st_position: vec2f(0., 1.),
92 });
93 self.vertices.push(PathVertex {
94 xy_position: c,
95 st_position: vec2f(0., 1.),
96 });
97 }
98 PathVertexKind::Quadratic => {
99 self.vertices.push(PathVertex {
100 xy_position: a,
101 st_position: vec2f(0., 0.),
102 });
103 self.vertices.push(PathVertex {
104 xy_position: b,
105 st_position: vec2f(0.5, 0.),
106 });
107 self.vertices.push(PathVertex {
108 xy_position: c,
109 st_position: vec2f(1., 1.),
110 });
111 }
112 }
113 }
114}
115
116pub fn deserialize_vec2f<'de, D>(deserializer: D) -> Result<Vector2F, D::Error>
117where
118 D: Deserializer<'de>,
119{
120 let [x, y]: [f32; 2] = Deserialize::deserialize(deserializer)?;
121 Ok(vec2f(x, y))
122}
123
124impl ToJson for Vector2F {
125 fn to_json(&self) -> serde_json::Value {
126 json!([self.x(), self.y()])
127 }
128}
129
130impl ToJson for RectF {
131 fn to_json(&self) -> serde_json::Value {
132 json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
133 }
134}
135
136#[derive(Refineable)]
137pub struct Point<T: Clone + Default> {
138 pub x: T,
139 pub y: T,
140}
141
142impl<T: Clone + Default> Clone for Point<T> {
143 fn clone(&self) -> Self {
144 Self {
145 x: self.x.clone(),
146 y: self.y.clone(),
147 }
148 }
149}
150
151impl<T: Clone + Default> Into<taffy::geometry::Point<T>> for Point<T> {
152 fn into(self) -> taffy::geometry::Point<T> {
153 taffy::geometry::Point {
154 x: self.x,
155 y: self.y,
156 }
157 }
158}
159
160#[derive(Clone, Refineable)]
161pub struct Size<T: Clone + Default> {
162 pub width: T,
163 pub height: T,
164}
165
166impl<S, T: Clone + Default> From<taffy::geometry::Size<S>> for Size<T>
167where
168 S: Into<T>,
169{
170 fn from(value: taffy::geometry::Size<S>) -> Self {
171 Self {
172 width: value.width.into(),
173 height: value.height.into(),
174 }
175 }
176}
177
178impl<S, T: Clone + Default> Into<taffy::geometry::Size<S>> for Size<T>
179where
180 T: Into<S>,
181{
182 fn into(self) -> taffy::geometry::Size<S> {
183 taffy::geometry::Size {
184 width: self.width.into(),
185 height: self.height.into(),
186 }
187 }
188}
189
190impl Size<DefiniteLength> {
191 pub fn zero() -> Self {
192 Self {
193 width: pixels(0.),
194 height: pixels(0.),
195 }
196 }
197
198 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Size<taffy::style::LengthPercentage> {
199 taffy::geometry::Size {
200 width: self.width.to_taffy(rem_size),
201 height: self.height.to_taffy(rem_size),
202 }
203 }
204}
205
206impl Size<Length> {
207 pub fn auto() -> Self {
208 Self {
209 width: Length::Auto,
210 height: Length::Auto,
211 }
212 }
213
214 pub fn to_taffy<T: From<taffy::prelude::LengthPercentageAuto>>(
215 &self,
216 rem_size: f32,
217 ) -> taffy::geometry::Size<T> {
218 taffy::geometry::Size {
219 width: self.width.to_taffy(rem_size).into(),
220 height: self.height.to_taffy(rem_size).into(),
221 }
222 }
223}
224
225#[derive(Clone, Default, Refineable)]
226pub struct Edges<T: Clone + Default> {
227 pub top: T,
228 pub right: T,
229 pub bottom: T,
230 pub left: T,
231}
232
233impl Edges<DefiniteLength> {
234 pub fn zero() -> Self {
235 Self {
236 top: pixels(0.),
237 right: pixels(0.),
238 bottom: pixels(0.),
239 left: pixels(0.),
240 }
241 }
242
243 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
244 taffy::geometry::Rect {
245 top: self.top.to_taffy(rem_size),
246 right: self.right.to_taffy(rem_size),
247 bottom: self.bottom.to_taffy(rem_size),
248 left: self.left.to_taffy(rem_size),
249 }
250 }
251}
252
253impl Edges<Length> {
254 pub fn auto() -> Self {
255 Self {
256 top: Length::Auto,
257 right: Length::Auto,
258 bottom: Length::Auto,
259 left: Length::Auto,
260 }
261 }
262
263 pub fn zero() -> Self {
264 Self {
265 top: pixels(0.),
266 right: pixels(0.),
267 bottom: pixels(0.),
268 left: pixels(0.),
269 }
270 }
271
272 pub fn to_taffy(
273 &self,
274 rem_size: f32,
275 ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
276 taffy::geometry::Rect {
277 top: self.top.to_taffy(rem_size),
278 right: self.right.to_taffy(rem_size),
279 bottom: self.bottom.to_taffy(rem_size),
280 left: self.left.to_taffy(rem_size),
281 }
282 }
283}
284
285#[derive(Clone, Copy)]
286pub enum AbsoluteLength {
287 Pixels(f32),
288 Rems(f32),
289}
290
291impl AbsoluteLength {
292 pub fn to_pixels(&self, rem_size: f32) -> f32 {
293 match self {
294 AbsoluteLength::Pixels(pixels) => *pixels,
295 AbsoluteLength::Rems(rems) => rems * rem_size,
296 }
297 }
298}
299
300impl Default for AbsoluteLength {
301 fn default() -> Self {
302 Self::Pixels(0.0)
303 }
304}
305
306/// A non-auto length that can be defined in pixels, rems, or percent of parent.
307#[derive(Clone, Copy)]
308pub enum DefiniteLength {
309 Absolute(AbsoluteLength),
310 Relative(f32), // Percent, from 0 to 100.
311}
312
313impl DefiniteLength {
314 fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
315 match self {
316 DefiniteLength::Absolute(length) => match length {
317 AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
318 AbsoluteLength::Rems(rems) => {
319 taffy::style::LengthPercentage::Length(rems * rem_size)
320 }
321 },
322 DefiniteLength::Relative(fraction) => {
323 taffy::style::LengthPercentage::Percent(*fraction)
324 }
325 }
326 }
327}
328
329impl From<AbsoluteLength> for DefiniteLength {
330 fn from(length: AbsoluteLength) -> Self {
331 Self::Absolute(length)
332 }
333}
334
335impl Default for DefiniteLength {
336 fn default() -> Self {
337 Self::Absolute(AbsoluteLength::default())
338 }
339}
340
341/// A length that can be defined in pixels, rems, percent of parent, or auto.
342#[derive(Clone, Copy)]
343pub enum Length {
344 Definite(DefiniteLength),
345 Auto,
346}
347
348pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
349 DefiniteLength::Relative(fraction).into()
350}
351
352pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
353 AbsoluteLength::Rems(rems).into()
354}
355
356pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
357 AbsoluteLength::Pixels(pixels).into()
358}
359
360pub fn auto() -> Length {
361 Length::Auto
362}
363
364impl Length {
365 pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
366 match self {
367 Length::Definite(length) => length.to_taffy(rem_size).into(),
368 Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
369 }
370 }
371}
372
373impl From<DefiniteLength> for Length {
374 fn from(length: DefiniteLength) -> Self {
375 Self::Definite(length)
376 }
377}
378
379impl From<AbsoluteLength> for Length {
380 fn from(length: AbsoluteLength) -> Self {
381 Self::Definite(length.into())
382 }
383}
384
385impl Default for Length {
386 fn default() -> Self {
387 Self::Definite(DefiniteLength::default())
388 }
389}