1use super::scene::{Path, PathVertex};
2use crate::{color::ColorU, json::ToJson};
3pub use pathfinder_geometry::*;
4use rect::RectF;
5use serde_json::json;
6use vector::{vec2f, Vector2F};
7
8pub struct PathBuilder {
9 vertices: Vec<PathVertex>,
10 start: Vector2F,
11 current: Vector2F,
12 contour_count: usize,
13 bounds: RectF,
14}
15
16enum PathVertexKind {
17 Solid,
18 Quadratic,
19}
20
21impl PathBuilder {
22 pub fn new() -> Self {
23 Self {
24 vertices: Vec::new(),
25 start: vec2f(0., 0.),
26 current: vec2f(0., 0.),
27 contour_count: 0,
28 bounds: RectF::default(),
29 }
30 }
31
32 pub fn reset(&mut self, point: Vector2F) {
33 self.vertices.clear();
34 self.start = point;
35 self.current = point;
36 self.contour_count = 0;
37 }
38
39 pub fn line_to(&mut self, point: Vector2F) {
40 self.contour_count += 1;
41 if self.contour_count > 1 {
42 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
43 }
44
45 self.current = point;
46 }
47
48 pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
49 self.contour_count += 1;
50 if self.contour_count > 1 {
51 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
52 }
53
54 self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
55 self.current = point;
56 }
57
58 pub fn build(mut self, color: ColorU, clip_bounds: Option<RectF>) -> Path {
59 if let Some(clip_bounds) = clip_bounds {
60 self.bounds = self
61 .bounds
62 .intersection(clip_bounds)
63 .unwrap_or(RectF::default());
64 }
65 Path {
66 bounds: self.bounds,
67 color,
68 vertices: self.vertices,
69 }
70 }
71
72 fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
73 if self.vertices.is_empty() {
74 self.bounds = RectF::new(a, Vector2F::zero());
75 }
76 self.bounds = self.bounds.union_point(a).union_point(b).union_point(c);
77
78 match kind {
79 PathVertexKind::Solid => {
80 self.vertices.push(PathVertex {
81 xy_position: a,
82 st_position: vec2f(0., 1.),
83 });
84 self.vertices.push(PathVertex {
85 xy_position: b,
86 st_position: vec2f(0., 1.),
87 });
88 self.vertices.push(PathVertex {
89 xy_position: c,
90 st_position: vec2f(0., 1.),
91 });
92 }
93 PathVertexKind::Quadratic => {
94 self.vertices.push(PathVertex {
95 xy_position: a,
96 st_position: vec2f(0., 0.),
97 });
98 self.vertices.push(PathVertex {
99 xy_position: b,
100 st_position: vec2f(0.5, 0.),
101 });
102 self.vertices.push(PathVertex {
103 xy_position: c,
104 st_position: vec2f(1., 1.),
105 });
106 }
107 }
108 }
109}
110
111impl ToJson for Vector2F {
112 fn to_json(&self) -> serde_json::Value {
113 json!([self.x(), self.y()])
114 }
115}
116
117impl ToJson for RectF {
118 fn to_json(&self) -> serde_json::Value {
119 json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
120 }
121}