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