pathfinder_renderer/
options.rs1use crate::gpu_data::RenderCommand;
14use pathfinder_geometry::rect::RectF;
15use pathfinder_geometry::transform2d::Transform2F;
16use pathfinder_geometry::transform3d::Perspective;
17use pathfinder_geometry::vector::{Vector2F, Vector4F};
18use pathfinder_content::clip::PolygonClipper3D;
19
20pub trait RenderCommandListener: Send + Sync {
21 fn send(&self, command: RenderCommand);
22}
23
24impl<F> RenderCommandListener for F
25where
26 F: Fn(RenderCommand) + Send + Sync,
27{
28 #[inline]
29 fn send(&self, command: RenderCommand) {
30 (*self)(command)
31 }
32}
33
34#[derive(Clone, Default)]
36pub struct BuildOptions {
37 pub transform: RenderTransform,
38 pub dilation: Vector2F,
39 pub subpixel_aa_enabled: bool,
40}
41
42impl BuildOptions {
43 pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions {
44 PreparedBuildOptions {
45 transform: self.transform.prepare(bounds),
46 dilation: self.dilation,
47 subpixel_aa_enabled: self.subpixel_aa_enabled,
48 }
49 }
50}
51
52#[derive(Clone)]
53pub enum RenderTransform {
54 Transform2D(Transform2F),
55 Perspective(Perspective),
56}
57
58impl Default for RenderTransform {
59 #[inline]
60 fn default() -> RenderTransform {
61 RenderTransform::Transform2D(Transform2F::default())
62 }
63}
64
65impl RenderTransform {
66 fn prepare(&self, bounds: RectF) -> PreparedRenderTransform {
67 let perspective = match self {
68 RenderTransform::Transform2D(ref transform) => {
69 if transform.is_identity() {
70 return PreparedRenderTransform::None;
71 }
72 return PreparedRenderTransform::Transform2D(*transform);
73 }
74 RenderTransform::Perspective(ref perspective) => *perspective,
75 };
76
77 let mut points = vec![
78 bounds.origin().to_4d(),
79 bounds.upper_right().to_4d(),
80 bounds.lower_right().to_4d(),
81 bounds.lower_left().to_4d(),
82 ];
83 debug!("-----");
84 debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
85 for point in &mut points {
86 *point = perspective.transform * *point;
87 }
88 debug!("... PERSPECTIVE quad={:?}", points);
89
90 let quad = [
92 points[0].to_3d().to_4d(),
93 points[1].to_3d().to_4d(),
94 points[2].to_3d().to_4d(),
95 points[3].to_3d().to_4d(),
96 ];
97 debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
98
99 points = PolygonClipper3D::new(points).clip();
100 debug!("... CLIPPED quad={:?}", points);
101 for point in &mut points {
102 *point = point.to_3d().to_4d()
103 }
104
105 let inverse_transform = perspective.transform.inverse();
106 let clip_polygon = points.into_iter()
107 .map(|point| (inverse_transform * point).to_2d())
108 .collect();
109 return PreparedRenderTransform::Perspective {
110 perspective,
111 clip_polygon,
112 quad,
113 };
114 }
115}
116
117pub(crate) struct PreparedBuildOptions {
118 pub(crate) transform: PreparedRenderTransform,
119 pub(crate) dilation: Vector2F,
120 pub(crate) subpixel_aa_enabled: bool,
121}
122
123impl PreparedBuildOptions {
124 #[inline]
125 pub(crate) fn bounding_quad(&self) -> BoundingQuad {
126 match self.transform {
127 PreparedRenderTransform::Perspective { quad, .. } => quad,
128 _ => [Vector4F::default(); 4],
129 }
130 }
131}
132
133pub(crate) type BoundingQuad = [Vector4F; 4];
134
135pub(crate) enum PreparedRenderTransform {
136 None,
137 Transform2D(Transform2F),
138 Perspective {
139 perspective: Perspective,
140 clip_polygon: Vec<Vector2F>,
141 quad: [Vector4F; 4],
142 },
143}
144
145impl PreparedRenderTransform {
146 #[inline]
147 pub(crate) fn is_2d(&self) -> bool {
148 match *self {
149 PreparedRenderTransform::Transform2D(_) => true,
150 _ => false,
151 }
152 }
153}