freya_core/
render_pipeline.rs1use freya_engine::prelude::{
2 Canvas,
3 FontCollection,
4 FontMgr,
5 SkMatrix,
6 SkPoint,
7 SkRect,
8};
9
10use crate::{
11 element::{
12 ClipContext,
13 RenderContext,
14 },
15 prelude::Color,
16 tree::Tree,
17};
18
19pub struct RenderPipeline<'a> {
20 pub font_collection: &'a mut FontCollection,
21 pub font_manager: &'a FontMgr,
22 pub canvas: &'a Canvas,
23 pub tree: &'a Tree,
24 pub scale_factor: f64,
25 pub background: Color,
26}
27
28impl RenderPipeline<'_> {
29 #[cfg_attr(feature = "hotpath", hotpath::measure)]
30 pub fn render(self) {
31 self.canvas.clear(self.background);
32
33 for i16 in itertools::sorted(self.tree.layers.keys()) {
35 let nodes = self.tree.layers.get(i16).unwrap();
36 'rendering: for node_id in nodes {
37 let layer = self.canvas.save();
38
39 let element = self.tree.elements.get(node_id).unwrap();
40 let text_style_state = self.tree.text_style_state.get(node_id).unwrap();
41 let layout_node = self.tree.layout.get(node_id).unwrap();
42 let effect_state = self.tree.effect_state.get(node_id);
43
44 if let Some(effect_state) = effect_state {
45 let mut visible_area = layout_node.visible_area();
46
47 for id in effect_state.scales.iter() {
49 let layout_node = self.tree.layout.get(id).unwrap();
50 let effect = self.tree.effect_state.get(id).unwrap();
51 let area = layout_node.visible_area();
52 let center = area.center();
53 let scale = effect.scale.unwrap();
54
55 visible_area = visible_area.translate(-center.to_vector());
56 visible_area = visible_area.scale(scale.x, scale.y);
57 visible_area = visible_area.translate(center.to_vector());
58 }
59
60 hotpath::measure_block!("Element Clipping", {
61 for clip_node_id in effect_state.clips.iter() {
62 let clip_element = self.tree.elements.get(clip_node_id).unwrap();
63 let clip_layout_node = self.tree.layout.get(clip_node_id).unwrap();
64 let clip_effect = self.tree.effect_state.get(clip_node_id).unwrap();
65
66 let mut transformed_clip_area = clip_layout_node.visible_area();
67
68 for id in clip_effect.scales.iter() {
71 let scale_layout_node = self.tree.layout.get(id).unwrap();
72 let scale_effect = self.tree.effect_state.get(id).unwrap();
73 let area = scale_layout_node.visible_area();
74 let center = area.center();
75 let scale = scale_effect.scale.unwrap();
76
77 transformed_clip_area =
78 transformed_clip_area.translate(-center.to_vector());
79 transformed_clip_area =
80 transformed_clip_area.scale(scale.x, scale.y);
81 transformed_clip_area =
82 transformed_clip_area.translate(center.to_vector());
83 }
84
85 if !visible_area.intersects(&transformed_clip_area) {
87 self.canvas.restore_to_count(layer);
88 continue 'rendering;
89 }
90
91 let clip_context = ClipContext {
92 canvas: self.canvas,
93 visible_area: &transformed_clip_area,
94 scale_factor: self.scale_factor,
95 };
96
97 clip_element.clip(clip_context);
98 }
99 });
100
101 for id in effect_state.rotations.iter() {
103 let layout_node = self.tree.layout.get(id).unwrap();
104 let effect = self.tree.effect_state.get(id).unwrap();
105 let area = layout_node.visible_area();
106 let mut matrix = SkMatrix::new_identity();
107 matrix.set_rotate(
108 effect.rotation.unwrap(),
109 Some(SkPoint {
110 x: area.min_x() + area.width() / 2.0,
111 y: area.min_y() + area.height() / 2.0,
112 }),
113 );
114 self.canvas.concat(&matrix);
115 }
116
117 let rect = SkRect::new(
119 visible_area.min_x(),
120 visible_area.min_y(),
121 visible_area.max_x(),
122 visible_area.max_y(),
123 );
124 for opacity in effect_state.opacities.iter() {
125 self.canvas.save_layer_alpha_f(rect, *opacity);
126 }
127
128 for id in effect_state.scales.iter() {
130 let layout_node = self.tree.layout.get(id).unwrap();
131 let effect = self.tree.effect_state.get(id).unwrap();
132 let area = layout_node.visible_area();
133 let center = area.center();
134 let scale = effect.scale.unwrap();
135
136 self.canvas.translate((center.x, center.y));
137 self.canvas.scale((scale.x, scale.y));
138 self.canvas.translate((-center.x, -center.y));
139 }
140 }
141
142 let render_context = RenderContext {
143 font_collection: self.font_collection,
144 canvas: self.canvas,
145 layout_node,
146 tree: self.tree,
147 text_style_state,
148 scale_factor: self.scale_factor,
149 };
150
151 hotpath::measure_block!("Element Render", {
152 element.render(render_context);
153 });
154
155 self.canvas.restore_to_count(layer);
156 }
157 }
158 }
159}