carnelian/render/generic/forma/
composition.rs1use euclid::default::{Transform2D, Vector2D};
6use forma::{Color as FormaColor, GeomPresTransform, Order as FormaOrder};
7
8use crate::color::Color;
9use crate::geometry::Coord;
10use crate::render::generic::forma::{Forma, FormaRaster};
11use crate::render::generic::{BlendMode, Composition, Fill, FillRule, GradientType, Layer, Order};
12
13#[derive(Debug)]
14pub struct FormaComposition {
15 pub(crate) id: Option<usize>,
16 pub(crate) composition: forma::Composition,
17 cached_display_transform: Option<Transform2D<Coord>>,
18 pub(crate) background_color: Color,
19}
20
21impl FormaComposition {
22 fn insert_in_composition(&mut self, order: FormaOrder, raster: &FormaRaster) {
23 let mut option = raster.layer_details.borrow_mut();
24 let layer_details = option
25 .filter(|&(id, layer_translation)| {
26 self.composition.get_order_if_stored(id) == Some(order)
27 && raster.translation == layer_translation
28 })
29 .unwrap_or_else(|| {
30 let layer = self.composition.get_mut_or_insert_default(order);
31
32 layer.clear();
33
34 for print in &raster.prints {
35 let transform: [f32; 9] = [
36 print.transform.m11,
37 print.transform.m21,
38 print.transform.m31,
39 print.transform.m12,
40 print.transform.m22,
41 print.transform.m32,
42 0.0,
43 0.0,
44 1.0,
45 ];
46 layer.insert(&print.path.transform(&transform));
47 }
48
49 (layer.geom_id(), raster.translation)
50 });
51
52 *option = Some(layer_details);
53 }
54
55 fn forma_transform(&self, translation: Vector2D<Coord>) -> [f32; 6] {
56 if let Some(display_transform) = self.cached_display_transform {
57 let transform = display_transform.pre_translate(translation);
58
59 [
60 transform.m11,
61 transform.m21,
62 transform.m12,
63 transform.m22,
64 transform.m31,
65 transform.m32,
66 ]
67 } else {
68 [1.0, 0.0, 0.0, 1.0, translation.x, translation.y]
69 }
70 }
71
72 pub(crate) fn set_cached_display_transform(&mut self, transform: Transform2D<Coord>) {
73 if Some(&transform) != self.cached_display_transform.as_ref() {
74 let inverted =
75 self.cached_display_transform.and_then(|t| t.inverse()).unwrap_or_default();
76 let new_transform = inverted.then(&transform);
77
78 self.cached_display_transform = Some(new_transform);
79
80 for (_, layer) in self.composition.layers_mut() {
81 let transform = layer.transform().as_slice();
82 let transform = Transform2D {
83 m11: transform[0],
84 m21: transform[1],
85 m12: transform[2],
86 m22: transform[3],
87 m31: transform[4],
88 m32: transform[5],
89 ..Default::default()
90 }
91 .then(&new_transform);
92
93 layer.set_transform(
94 GeomPresTransform::try_from([
95 transform.m11,
96 transform.m21,
97 transform.m12,
98 transform.m22,
99 transform.m31,
100 transform.m32,
101 ])
102 .unwrap_or_else(|e| panic!("{}", e)),
103 );
104 }
105 }
106 }
107}
108
109impl Composition<Forma> for FormaComposition {
110 fn new(background_color: Color) -> Self {
111 Self {
112 id: None,
113 composition: forma::Composition::new(),
114 cached_display_transform: None,
115 background_color,
116 }
117 }
118
119 fn clear(&mut self) {
120 for (_, layer) in self.composition.layers_mut() {
121 layer.clear();
122 }
123 }
124
125 fn insert(&mut self, order: Order, layer: Layer<Forma>) {
126 let forma_order =
127 FormaOrder::try_from(order.as_u32() * 2).unwrap_or_else(|e| panic!("{}", e));
128 if let Some(ref clip) = layer.clip {
129 self.insert_in_composition(forma_order, clip);
130
131 let forma_transform = self.forma_transform(layer.raster.translation);
132 let forma_layer = self.composition.get_mut(forma_order).unwrap();
133
134 forma_layer.set_props(forma::Props {
135 fill_rule: match layer.style.fill_rule {
136 FillRule::NonZero => forma::FillRule::NonZero,
137 FillRule::EvenOdd => forma::FillRule::EvenOdd,
138 },
139 func: forma::Func::Clip(1),
140 });
141
142 forma_layer.set_transform(
143 GeomPresTransform::try_from(forma_transform).unwrap_or_else(|e| panic!("{}", e)),
144 );
145 } else {
146 self.composition.remove(forma_order);
147 }
148
149 let forma_order =
150 FormaOrder::try_from(order.as_u32() * 2 + 1).unwrap_or_else(|e| panic!("{}", e));
151
152 if layer.raster.prints.is_empty() {
153 self.composition.remove(forma_order);
154 return;
155 }
156
157 self.insert_in_composition(forma_order, &layer.raster);
158
159 let forma_transform = self.forma_transform(layer.raster.translation);
160 let forma_layer = self.composition.get_mut(forma_order).unwrap();
161
162 forma_layer.set_props(forma::Props {
163 fill_rule: match layer.style.fill_rule {
164 FillRule::NonZero => forma::FillRule::NonZero,
165 FillRule::EvenOdd => forma::FillRule::EvenOdd,
166 },
167 func: forma::Func::Draw(forma::Style {
168 fill: match &layer.style.fill {
169 Fill::Solid(color) => forma::Fill::Solid(FormaColor::from(color)),
170 Fill::Gradient(gradient) => {
171 let mut builder = forma::GradientBuilder::new(
172 forma::Point::new(gradient.start.x, gradient.start.y),
173 forma::Point::new(gradient.end.x, gradient.end.y),
174 );
175 builder.r#type(match gradient.r#type {
176 GradientType::Linear => forma::GradientType::Linear,
177 GradientType::Radial => forma::GradientType::Radial,
178 });
179
180 for &(color, stop) in &gradient.stops {
181 builder.color_with_stop(FormaColor::from(&color), stop);
182 }
183
184 forma::Fill::Gradient(builder.build().unwrap())
185 }
186 },
187 is_clipped: layer.clip.is_some(),
188 blend_mode: match layer.style.blend_mode {
189 BlendMode::Over => forma::BlendMode::Over,
190 BlendMode::Screen => forma::BlendMode::Screen,
191 BlendMode::Overlay => forma::BlendMode::Overlay,
192 BlendMode::Darken => forma::BlendMode::Darken,
193 BlendMode::Lighten => forma::BlendMode::Lighten,
194 BlendMode::ColorDodge => forma::BlendMode::ColorDodge,
195 BlendMode::ColorBurn => forma::BlendMode::ColorBurn,
196 BlendMode::HardLight => forma::BlendMode::HardLight,
197 BlendMode::SoftLight => forma::BlendMode::SoftLight,
198 BlendMode::Difference => forma::BlendMode::Difference,
199 BlendMode::Exclusion => forma::BlendMode::Exclusion,
200 BlendMode::Multiply => forma::BlendMode::Multiply,
201 BlendMode::Hue => forma::BlendMode::Hue,
202 BlendMode::Saturation => forma::BlendMode::Saturation,
203 BlendMode::Color => forma::BlendMode::Color,
204 BlendMode::Luminosity => forma::BlendMode::Luminosity,
205 },
206 ..Default::default()
207 }),
208 });
209
210 forma_layer.set_transform(
211 GeomPresTransform::try_from(forma_transform).unwrap_or_else(|e| panic!("{}", e)),
212 );
213 }
214
215 fn remove(&mut self, order: Order) {
216 for i in 0..2 {
217 let order =
218 FormaOrder::try_from(order.as_u32() * 2 + i).unwrap_or_else(|e| panic!("{}", e));
219 self.composition.remove(order);
220 }
221 }
222}