ferroui_base/rendering/composition/drawing/
render_data_stream_replay.rs1use super::{draw_with_painted_brushes, IRenderDataVisitor, PaintedShape, RenderDataStream};
2use crate::media::{BoxShadows, IBrush, IPen, ImmediateDrawingContext, RenderOptions, TextOptions};
3use crate::media::imaging::BitmapBlendingMode;
4use crate::platform::{IDrawingContextImpl, IGeometryImpl, IGlyphRunImpl};
5use crate::rendering::scene_graph::ICustomDrawOperation;
6use crate::{Matrix, Point, Rect, RoundedRect};
7use std::sync::Arc;
8
9#[derive(Clone, Copy, PartialEq, Eq)]
10enum ReplayScopeKind {
11 Clip,
12 GeometryClip,
13 Opacity,
14 OpacityMask,
15 Transform,
16 RenderOptions,
17 TextOptions,
18 Effect,
19 CompositingLayer,
20}
21
22#[derive(Clone, Copy)]
24pub struct ReplayScope {
25 kind: ReplayScopeKind,
26 active: bool,
27 saved_transform: Matrix,
28}
29
30impl ReplayScope {
31 fn new(kind: ReplayScopeKind, active: bool) -> Self {
32 Self { kind, active, saved_transform: Matrix::IDENTITY }
33 }
34}
35
36pub struct ReplayVisitor<'a> {
38 context: &'a mut dyn IDrawingContextImpl,
39}
40
41impl<'a> ReplayVisitor<'a> {
42 pub fn new(context: &'a mut dyn IDrawingContextImpl) -> Self {
43 Self { context }
44 }
45}
46
47impl IRenderDataVisitor for ReplayVisitor<'_> {
48 type Scope = ReplayScope;
49
50 fn stop_visiting(&self) -> bool {
51 false
52 }
53
54 fn on_draw_line(&mut self, server_pen: Option<&dyn IPen>, _client_pen: Option<&dyn IPen>, p1: Point, p2: Point) {
55 if !draw_with_painted_brushes(self.context, None, server_pen, PaintedShape::Line(p1, p2), None) {
56 self.context.draw_line(server_pen, p1, p2);
57 }
58 }
59
60 fn on_draw_rectangle(
61 &mut self,
62 server_brush: Option<&dyn IBrush>,
63 server_pen: Option<&dyn IPen>,
64 _client_pen: Option<&dyn IPen>,
65 rect: RoundedRect,
66 box_shadows: &BoxShadows,
67 ) {
68 if !draw_with_painted_brushes(self.context, server_brush, server_pen, PaintedShape::Rectangle(rect), Some(box_shadows)) {
70 self.context.draw_rectangle(server_brush, server_pen, rect, box_shadows);
71 }
72 }
73
74 fn on_draw_ellipse(
75 &mut self,
76 server_brush: Option<&dyn IBrush>,
77 server_pen: Option<&dyn IPen>,
78 _client_pen: Option<&dyn IPen>,
79 rect: Rect,
80 ) {
81 if !draw_with_painted_brushes(self.context, server_brush, server_pen, PaintedShape::Ellipse(rect), None) {
82 self.context.draw_ellipse(server_brush, server_pen, rect);
83 }
84 }
85
86 fn on_draw_geometry(
87 &mut self,
88 server_brush: Option<&dyn IBrush>,
89 server_pen: Option<&dyn IPen>,
90 _client_pen: Option<&dyn IPen>,
91 geometry: Option<&Arc<dyn IGeometryImpl>>,
92 ) {
93 if let Some(geometry) = geometry {
94 if !draw_with_painted_brushes(self.context, server_brush, server_pen, PaintedShape::Geometry(&**geometry), None) {
95 self.context.draw_geometry(server_brush, server_pen, &**geometry);
96 }
97 }
98 }
99
100 fn on_draw_glyph_run(&mut self, server_brush: Option<&dyn IBrush>, glyph_run: Option<&std::sync::Arc<dyn IGlyphRunImpl>>) {
101 if let Some(glyph_run) = glyph_run {
102 if !draw_with_painted_brushes(self.context, server_brush, None, PaintedShape::GlyphRun(&**glyph_run), None) {
103 self.context.draw_glyph_run(server_brush, &**glyph_run);
104 }
105 }
106 }
107
108 fn on_draw_bitmap(&mut self, bitmap: Option<&std::sync::Arc<crate::platform::SharedBitmapImpl>>, opacity: f64, source_rect: Rect, dest_rect: Rect) {
109 if let Some(bitmap) = bitmap {
110 self.context.draw_bitmap(&**bitmap, opacity, source_rect, dest_rect);
111 }
112 }
113
114 fn on_draw_custom(&mut self, operation: Option<&std::sync::Arc<dyn ICustomDrawOperation>>) {
115 if let Some(operation) = operation {
116 let mut context = ImmediateDrawingContext::borrowed(self.context);
117 operation.render(&mut context);
118 context.dispose();
119 }
120 }
121
122 fn on_push_clip(&mut self, clip: RoundedRect) -> ReplayScope {
123 self.context.push_clip_rounded(clip);
124 ReplayScope::new(ReplayScopeKind::Clip, true)
125 }
126
127 fn on_push_geometry_clip(&mut self, geometry: Option<&Arc<dyn IGeometryImpl>>) -> ReplayScope {
128 if let Some(geometry) = geometry {
129 self.context.push_geometry_clip(&**geometry);
130 }
131 ReplayScope::new(ReplayScopeKind::GeometryClip, geometry.is_some())
132 }
133
134 fn on_push_opacity(&mut self, opacity: f64) -> ReplayScope {
135 if opacity != 1.0 {
136 self.context.push_opacity(opacity, None);
137 }
138 ReplayScope::new(ReplayScopeKind::Opacity, opacity != 1.0)
139 }
140
141 fn on_push_compositing_layer(&mut self, blend: BitmapBlendingMode, opacity: f64, bounds: Rect) -> ReplayScope {
142 if self.context.try_push_compositing_layer(blend, opacity, bounds) {
146 return ReplayScope::new(ReplayScopeKind::CompositingLayer, true);
147 }
148 self.on_push_opacity(opacity)
149 }
150
151 fn on_push_opacity_mask(&mut self, brush: Option<&dyn IBrush>, bounds: Rect) -> ReplayScope {
152 if let Some(brush) = brush {
153 self.context.push_opacity_mask(brush, bounds);
154 }
155 ReplayScope::new(ReplayScopeKind::OpacityMask, brush.is_some())
156 }
157
158 fn on_push_transform(&mut self, matrix: Matrix) -> ReplayScope {
159 let saved = self.context.transform();
160 self.context.set_transform(matrix * saved);
161 ReplayScope { kind: ReplayScopeKind::Transform, active: true, saved_transform: saved }
162 }
163
164 fn on_push_render_options(&mut self, options: RenderOptions) -> ReplayScope {
165 self.context.push_render_options(options);
166 ReplayScope::new(ReplayScopeKind::RenderOptions, true)
167 }
168
169 fn on_push_text_options(&mut self, options: TextOptions) -> ReplayScope {
170 self.context.push_text_options(options);
171 ReplayScope::new(ReplayScopeKind::TextOptions, true)
172 }
173
174 fn on_push_effect(&mut self, effect: Option<&std::sync::Arc<dyn crate::media::IImmutableEffect>>, bounds: Rect) -> ReplayScope {
175 let mut active = false;
176 if let Some(effect) = effect {
177 if let Some(effect_impl) = self.context.as_drawing_context_impl_with_effects() {
178 effect_impl.push_effect(Some(bounds), &**effect);
179 active = true;
180 }
181 }
182 ReplayScope::new(ReplayScopeKind::Effect, active)
183 }
184
185 fn on_pop(&mut self, scope: ReplayScope) {
186 if !scope.active {
187 return;
188 }
189 match scope.kind {
190 ReplayScopeKind::Clip => self.context.pop_clip(),
191 ReplayScopeKind::GeometryClip => self.context.pop_geometry_clip(),
192 ReplayScopeKind::Opacity => self.context.pop_opacity(),
193 ReplayScopeKind::CompositingLayer => self.context.pop_compositing_layer(),
194 ReplayScopeKind::OpacityMask => self.context.pop_opacity_mask(),
195 ReplayScopeKind::Transform => self.context.set_transform(scope.saved_transform),
196 ReplayScopeKind::RenderOptions => self.context.pop_render_options(),
197 ReplayScopeKind::TextOptions => self.context.pop_text_options(),
198 ReplayScopeKind::Effect => {
199 if let Some(effect_impl) = self.context.as_drawing_context_impl_with_effects() {
200 effect_impl.pop_effect();
201 }
202 }
203 }
204 }
205}
206
207impl RenderDataStream {
208 pub fn replay(&self, context: &mut dyn IDrawingContextImpl) {
210 let mut visitor = ReplayVisitor::new(context);
211 self.visit(&mut visitor);
212 }
213
214 pub fn replay_with_scopes(&self, context: &mut dyn IDrawingContextImpl, scopes: &mut Vec<ReplayScope>) {
216 let mut visitor = ReplayVisitor::new(context);
217 self.visit_with_scopes(&mut visitor, scopes);
218 }
219}