freya_core/
render_pipeline.rs1use freya_engine::prelude::{
2 Canvas,
3 ClipOp,
4 FontCollection,
5 FontMgr,
6 SaveLayerRec,
7 SkMatrix,
8 SkPoint,
9 blur,
10};
11
12use crate::{
13 element::{
14 ClipContext,
15 RenderContext,
16 },
17 prelude::Color,
18 style::shadow::ShadowPosition,
19 tree::Tree,
20};
21
22pub struct RenderPipeline<'a> {
23 pub font_collection: &'a mut FontCollection,
24 pub font_manager: &'a FontMgr,
25 pub canvas: &'a Canvas,
26 pub tree: &'a Tree,
27 pub scale_factor: f64,
28 pub background: Color,
29}
30
31impl RenderPipeline<'_> {
32 #[cfg_attr(feature = "hotpath", hotpath::measure)]
33 pub fn render(self) {
34 self.canvas.clear(self.background);
35
36 for i16 in itertools::sorted(self.tree.layers.keys()) {
38 let nodes = self.tree.layers.get(i16).unwrap();
39 'rendering: for node_id in nodes {
40 let layer = self.canvas.save();
41
42 let element = self.tree.elements.get(node_id).unwrap();
43 let text_style_state = self.tree.text_style_state.get(node_id).unwrap();
44 let layout_node = self.tree.layout.get(node_id).unwrap();
45 let effect_state = self.tree.effect_state.get(node_id);
46
47 if let Some(effect_state) = effect_state {
48 let mut visible_area = layout_node.visible_area();
49
50 for id in effect_state.scales.iter() {
52 let layout_node = self.tree.layout.get(id).unwrap();
53 let effect = self.tree.effect_state.get(id).unwrap();
54 let area = layout_node.visible_area();
55 let center = area.center();
56 let scale = effect.scale.unwrap();
57
58 visible_area = visible_area.translate(-center.to_vector());
59 visible_area = visible_area.scale(scale.x, scale.y);
60 visible_area = visible_area.translate(center.to_vector());
61 }
62
63 hotpath::measure_block!("Element Clipping", {
64 for clip_node_id in effect_state.clips.iter() {
65 let clip_element = self.tree.elements.get(clip_node_id).unwrap();
66 let clip_layout_node = self.tree.layout.get(clip_node_id).unwrap();
67 let clip_effect = self.tree.effect_state.get(clip_node_id).unwrap();
68
69 let mut transformed_clip_area = clip_layout_node.visible_area();
70
71 for id in clip_effect.scales.iter() {
74 let scale_layout_node = self.tree.layout.get(id).unwrap();
75 let scale_effect = self.tree.effect_state.get(id).unwrap();
76 let area = scale_layout_node.visible_area();
77 let center = area.center();
78 let scale = scale_effect.scale.unwrap();
79
80 transformed_clip_area =
81 transformed_clip_area.translate(-center.to_vector());
82 transformed_clip_area =
83 transformed_clip_area.scale(scale.x, scale.y);
84 transformed_clip_area =
85 transformed_clip_area.translate(center.to_vector());
86 }
87
88 if !visible_area.intersects(&transformed_clip_area) {
90 self.canvas.restore_to_count(layer);
91 continue 'rendering;
92 }
93
94 let clip_context = ClipContext {
95 canvas: self.canvas,
96 visible_area: &transformed_clip_area,
97 scale_factor: self.scale_factor,
98 };
99
100 clip_element.clip(clip_context);
101 }
102 });
103
104 for id in effect_state.rotations.iter() {
106 let layout_node = self.tree.layout.get(id).unwrap();
107 let effect = self.tree.effect_state.get(id).unwrap();
108 let area = layout_node.visible_area();
109 let mut matrix = SkMatrix::new_identity();
110 matrix.set_rotate(
111 effect.rotation.unwrap(),
112 Some(SkPoint {
113 x: area.min_x() + area.width() / 2.0,
114 y: area.min_y() + area.height() / 2.0,
115 }),
116 );
117 self.canvas.concat(&matrix);
118 }
119
120 let render_rect = element.render_rect(&visible_area, self.scale_factor as f32);
121
122 let mut layer_bounds = *render_rect.rect();
125 let scale_factor = self.scale_factor as f32;
126
127 for shadow in element.style().shadows.iter() {
128 if shadow.position == ShadowPosition::Normal {
129 let outset_x = shadow.x.abs() + shadow.spread + shadow.blur;
130 let outset_y = shadow.y.abs() + shadow.spread + shadow.blur;
131 layer_bounds = layer_bounds
132 .with_outset((outset_x * scale_factor, outset_y * scale_factor));
133 }
134 }
135
136 for opacity in effect_state.opacities.iter() {
137 self.canvas.save_layer_alpha_f(layer_bounds, *opacity);
138 }
139
140 for id in effect_state.scales.iter() {
142 let layout_node = self.tree.layout.get(id).unwrap();
143 let effect = self.tree.effect_state.get(id).unwrap();
144 let area = layout_node.visible_area();
145 let center = area.center();
146 let scale = effect.scale.unwrap();
147
148 self.canvas.translate((center.x, center.y));
149 self.canvas.scale((scale.x, scale.y));
150 self.canvas.translate((-center.x, -center.y));
151 }
152 }
153
154 let render_context = RenderContext {
155 font_collection: self.font_collection,
156 canvas: self.canvas,
157 layout_node,
158 tree: self.tree,
159 text_style_state,
160 scale_factor: self.scale_factor,
161 };
162
163 hotpath::measure_block!("Element Render", {
164 element.render(render_context);
165 });
166
167 if let Some(effect_state) = effect_state {
168 let visible_area = layout_node.visible_area();
169 let render_rect = element.render_rect(&visible_area, self.scale_factor as f32);
170 if let Some(blur_radius) = effect_state.blur {
172 let style = element.style();
173
174 let image_filter = blur(
175 (
176 blur_radius * self.scale_factor as f32,
177 blur_radius * self.scale_factor as f32,
178 ),
179 None,
180 None,
181 render_rect.rect(),
182 );
183 if let Some(image_filter) = image_filter {
184 let rec = SaveLayerRec::default()
185 .bounds(render_rect.rect())
186 .backdrop(&image_filter);
187 if style.corner_radius.is_round() {
188 self.canvas.clip_rrect(render_rect, ClipOp::Intersect, true);
189 self.canvas.save_layer(&rec);
190 } else {
191 self.canvas.save_layer(&rec);
192 }
193 }
194 }
195 }
196
197 self.canvas.restore_to_count(layer);
198 }
199 }
200 }
201}