carnelian/render/generic/forma/
composition.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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}