1use std::rc::Rc;
6
7use inset_embedder::{Offset, ViewId, ViewRef};
8use inset_foundation::{App, Handle, Listener};
9use inset_gestures::{GestureBinding, GestureBindingOverridesObject, HitTestResult, PointerEvent};
10use inset_scheduler::{FrameCallback, SchedulerBinding};
11
12use crate::mouse_tracker::MouseTracker;
13use crate::object::RenderHandle;
14use crate::pipeline_owner::{PipelineManifold, PipelineOwner};
15use crate::view::{RenderView, ViewConfiguration};
16
17pub trait RendererBindingOverridesObject: Sized + 'static {
22 fn will_draw_frame(self: Handle<Self>, app: &mut App);
24
25 fn did_draw_frame(self: Handle<Self>, app: &mut App);
27
28 fn did_handle_metrics_changed(self: Handle<Self>, app: &mut App) {
31 let _ = app;
32 }
33}
34
35pub trait RendererBindingOverrides {
37 fn will_draw_frame(&self, app: &mut App);
39
40 fn did_draw_frame(&self, app: &mut App);
42
43 fn did_handle_metrics_changed(&self, app: &mut App);
45}
46
47impl<T: RendererBindingOverridesObject> RendererBindingOverrides for Handle<T> {
48 fn will_draw_frame(&self, app: &mut App) {
49 T::will_draw_frame(*self, app);
50 }
51
52 fn did_draw_frame(&self, app: &mut App) {
53 T::did_draw_frame(*self, app);
54 }
55
56 fn did_handle_metrics_changed(&self, app: &mut App) {
57 T::did_handle_metrics_changed(*self, app);
58 }
59}
60
61struct BindingPipelineManifold;
64
65impl PipelineManifold for BindingPipelineManifold {
66 fn request_visual_update(&self, app: &mut App) {
67 SchedulerBinding::ensure_visual_update(app);
68 }
69}
70
71#[derive(Default)]
72pub struct RendererBinding {
73 overrides: Option<Rc<dyn RendererBindingOverrides>>,
74 root_pipeline_owner: Option<Handle<PipelineOwner>>,
75 test_render_view: Option<RenderHandle<RenderView>>,
77 render_views: Vec<(ViewId, RenderHandle<RenderView>)>,
78 mouse_tracker: Option<Handle<MouseTracker>>,
79 debug_mouse_tracker_update_scheduled: bool,
80 first_frame_deferred_count: u32,
81 first_frame_sent: bool,
82}
83
84impl RendererBinding {
85 pub fn instance(app: &mut App) -> Handle<RendererBinding> {
87 let this: Handle<RendererBinding> = app.singleton();
88 if app.get(this).root_pipeline_owner.is_none() {
89 let root_pipeline_owner = this.create_root_pipeline_owner(app);
90 app.get_mut(this).root_pipeline_owner = Some(root_pipeline_owner);
91 root_pipeline_owner.attach(app, Rc::new(BindingPipelineManifold));
92 SchedulerBinding::add_persistent_frame_callback(
93 app,
94 FrameCallback::new(|app, _time_stamp| {
95 RendererBinding::instance(app).handle_persistent_frame_callback(app)
96 }),
97 );
98 this.init_mouse_tracker(app, None);
99 GestureBinding::instance(app).set_overrides(app, Rc::new(this));
102 }
103 this
104 }
105
106 pub fn mouse_tracker(self: Handle<Self>, app: &App) -> Handle<MouseTracker> {
109 app.get(self)
110 .mouse_tracker
111 .expect("RendererBinding::instance must run first")
112 }
113
114 pub fn init_mouse_tracker(
119 self: Handle<Self>,
120 app: &mut App,
121 tracker: Option<Handle<MouseTracker>>,
122 ) {
123 if let Some(previous) = app.get(self).mouse_tracker {
124 previous.dispose(app);
125 }
126 let tracker = tracker.unwrap_or_else(|| {
127 MouseTracker::new(
128 app,
129 Rc::new(move |app: &mut App, position: Offset, view_id: ViewId| {
130 let mut result = HitTestResult::new();
131 self.hit_test_in_view(app, &mut result, position, view_id);
132 result
133 }),
134 )
135 });
136 app.get_mut(self).mouse_tracker = Some(tracker);
137 }
138
139 pub fn root_pipeline_owner(self: Handle<Self>, app: &App) -> Handle<PipelineOwner> {
145 app.get(self)
146 .root_pipeline_owner
147 .expect("RendererBinding::instance must run first")
148 }
149
150 fn create_root_pipeline_owner(self: Handle<Self>, app: &mut App) -> Handle<PipelineOwner> {
152 PipelineOwner::new(
153 app,
154 Some(Listener::new(|app| {
155 SchedulerBinding::ensure_visual_update(app);
156 })),
157 )
158 }
159
160 pub fn render_views(self: Handle<Self>, app: &App) -> Vec<RenderHandle<RenderView>> {
162 app.get(self)
163 .render_views
164 .iter()
165 .map(|(_, view)| *view)
166 .collect()
167 }
168
169 pub fn add_render_view(self: Handle<Self>, app: &mut App, view: RenderHandle<RenderView>) {
176 let view_id = view.flutter_view(app).id();
177 debug_assert!(
178 !app.get(self)
179 .render_views
180 .iter()
181 .any(|(id, existing)| *id == view_id || *existing == view)
182 );
183 app.get_mut(self).render_views.push((view_id, view));
184 let configuration = self.create_view_configuration_for(app, view);
185 view.set_configuration(app, configuration);
186 }
187
188 pub fn remove_render_view(self: Handle<Self>, app: &mut App, view: RenderHandle<RenderView>) {
190 let view_id = view.flutter_view(app).id();
191 let views = &mut app.get_mut(self).render_views;
192 debug_assert!(
193 views
194 .iter()
195 .any(|(id, existing)| *id == view_id && *existing == view)
196 );
197 views.retain(|(id, _)| *id != view_id);
198 }
199
200 pub fn create_view_configuration_for(
203 self: Handle<Self>,
204 app: &App,
205 render_view: RenderHandle<RenderView>,
206 ) -> ViewConfiguration {
207 ViewConfiguration::from_view(&*render_view.flutter_view(app))
208 }
209
210 pub fn handle_metrics_changed(self: Handle<Self>, app: &mut App) {
214 let mut force_frame = false;
215 for view in self.render_views(app) {
216 force_frame = force_frame || view.child(app).is_some();
217 let configuration = self.create_view_configuration_for(app, view);
218 view.set_configuration(app, configuration);
219 }
220 if force_frame {
221 SchedulerBinding::schedule_forced_frame(app);
222 }
223 if let Some(overrides) = app.get(self).overrides.clone() {
224 overrides.did_handle_metrics_changed(app);
225 }
226 }
227
228 fn handle_persistent_frame_callback(self: Handle<Self>, app: &mut App) {
229 self.draw_frame(app);
230 self.schedule_mouse_tracker_update(app);
231 }
232
233 fn schedule_mouse_tracker_update(self: Handle<Self>, app: &mut App) {
234 debug_assert!(!app.get(self).debug_mouse_tracker_update_scheduled);
235 if cfg!(debug_assertions) {
236 app.get_mut(self).debug_mouse_tracker_update_scheduled = true;
237 }
238 SchedulerBinding::add_post_frame_callback(
239 app,
240 FrameCallback::new(move |app, _duration| {
241 debug_assert!(app.get(self).debug_mouse_tracker_update_scheduled);
242 if cfg!(debug_assertions) {
243 app.get_mut(self).debug_mouse_tracker_update_scheduled = false;
244 }
245 self.mouse_tracker(app).update_all_devices(app);
246 }),
247 );
248 }
249
250 pub fn send_frames_to_engine(self: Handle<Self>, app: &App) -> bool {
255 let data = app.get(self);
256 data.first_frame_sent || data.first_frame_deferred_count == 0
257 }
258
259 pub fn defer_first_frame(self: Handle<Self>, app: &mut App) {
262 app.get_mut(self).first_frame_deferred_count += 1;
263 }
264
265 pub fn allow_first_frame(self: Handle<Self>, app: &mut App) {
268 debug_assert!(app.get(self).first_frame_deferred_count > 0);
269 app.get_mut(self).first_frame_deferred_count -= 1;
270 if !app.get(self).first_frame_sent {
271 SchedulerBinding::schedule_forced_frame(app);
272 }
273 }
274
275 pub fn reset_first_frame_sent(self: Handle<Self>, app: &mut App) {
277 app.get_mut(self).first_frame_sent = false;
278 }
279
280 pub fn set_overrides(
290 self: Handle<Self>,
291 app: &mut App,
292 overrides: Rc<dyn RendererBindingOverrides>,
293 ) {
294 app.get_mut(self).overrides = Some(overrides);
295 }
296
297 pub fn draw_frame(self: Handle<Self>, app: &mut App) {
298 let overrides = app.get(self).overrides.clone();
299 if let Some(overrides) = &overrides {
300 overrides.will_draw_frame(app);
301 }
302 let root_pipeline_owner = self.root_pipeline_owner(app);
303 root_pipeline_owner.flush_layout(app);
304 root_pipeline_owner.flush_compositing_bits(app);
305 root_pipeline_owner.flush_paint(app);
306 if self.send_frames_to_engine(app) {
307 for render_view in self.render_views(app) {
308 render_view.composite_frame(app); }
310 app.get_mut(self).first_frame_sent = true;
311 }
312 if let Some(overrides) = &overrides {
313 overrides.did_draw_frame(app);
314 }
315 }
316
317 pub fn init_render_view(
322 self: Handle<Self>,
323 app: &mut App,
324 view: ViewRef,
325 ) -> RenderHandle<RenderView> {
326 if let Some(render_view) = app.get(self).test_render_view {
327 return render_view;
328 }
329 let render_view = RenderView::new(app, None, None, view);
330 app.get_mut(self).test_render_view = Some(render_view);
331 self.root_pipeline_owner(app)
332 .set_root_node(app, Some(render_view.as_object()));
333 self.add_render_view(app, render_view);
334 render_view.prepare_initial_frame(app);
335 render_view
336 }
337}
338
339impl GestureBindingOverridesObject for RendererBinding {
344 fn hit_test_in_view(
345 self: Handle<Self>,
346 app: &mut App,
347 result: &mut HitTestResult,
348 position: Offset,
349 view_id: ViewId,
350 ) {
351 let render_view = app
352 .get(self)
353 .render_views
354 .iter()
355 .find(|(id, _)| *id == view_id)
356 .map(|(_, view)| *view);
357 if let Some(render_view) = render_view {
358 render_view.hit_test(app, result, position);
359 }
360 }
361
362 fn will_dispatch_event(
363 self: Handle<Self>,
364 app: &mut App,
365 event: &PointerEvent,
366 hit_test_result: Option<&HitTestResult>,
367 ) {
368 let result = match event {
372 PointerEvent::Move(_) => None,
373 _ => hit_test_result,
374 };
375 self.mouse_tracker(app)
376 .update_with_event(app, event, result);
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use inset_foundation::AppCell;
383 use std::time::Duration;
384
385 use inset_embedder::{Size, TargetPlatform};
386 use inset_test::{TestPlatform, TestView};
387
388 use super::*;
389 use crate::box_::{BoxConstraints, RenderBox};
390 use crate::proxy_box::RenderConstrainedBox;
391
392 fn app_with_view() -> (Rc<AppCell>, Rc<TestView>, Rc<TestPlatform>) {
394 let view = Rc::new(TestView::with_pixel_ratio(800.0, 600.0, 2.0));
395 let platform = Rc::new(
396 TestPlatform::new()
397 .on(TargetPlatform::MacOS)
398 .with_view(view.clone()),
399 );
400 (AppCell::with_platform(platform.clone()), view, platform)
401 }
402
403 #[test]
404 fn a_frame_lays_out_paints_and_presents_the_view() {
405 let (cell, view, _platform) = app_with_view();
406 let mut app = cell.borrow_mut();
407 let binding = RendererBinding::instance(&mut app);
408 let render_view = binding.init_render_view(&mut app, view.clone());
409 assert_eq!(
410 render_view.configuration(&app).logical_constraints,
411 BoxConstraints::tight(Size::new(400.0, 300.0))
412 );
413 let child =
414 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
415 render_view.set_child(&mut app, Some(child.as_box()));
416
417 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
418 SchedulerBinding::handle_draw_frame(&mut app);
419
420 assert_eq!(render_view.size(&app), Size::new(400.0, 300.0));
421 assert_eq!(child.size(&app), Size::new(400.0, 300.0));
422 assert_eq!(view.presented(), 1);
423 assert!(!child.debug_needs_layout(&app));
424 assert!(!child.as_object().debug_needs_paint(&app));
425 }
426
427 #[test]
428 fn a_dirty_node_requests_a_visual_update() {
429 let (cell, view, platform) = app_with_view();
430 let mut app = cell.borrow_mut();
431 let binding = RendererBinding::instance(&mut app);
432 let render_view = binding.init_render_view(&mut app, view.clone());
433 let child =
434 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
435 render_view.set_child(&mut app, Some(child.as_box()));
436 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
437 SchedulerBinding::handle_draw_frame(&mut app);
438 let before = platform.frames_requested();
439
440 child.mark_needs_layout(&mut app);
441 assert!(
442 platform.frames_requested() > before,
443 "the root owner's visual update reaches the host"
444 );
445 }
446
447 #[test]
448 fn a_pointer_down_reaches_a_pointer_listener_through_the_gesture_binding() {
449 use inset_gestures::{PointerDownEvent, PointerEvent};
450
451 use crate::proxy_box::{HitTestBehavior, RenderPointerListener};
452
453 let (cell, view, _platform) = app_with_view();
454 let mut app = cell.borrow_mut();
455 let binding = RendererBinding::instance(&mut app);
456 let render_view = binding.init_render_view(&mut app, view.clone());
457 let listener = RenderPointerListener::new(&mut app, HitTestBehavior::Opaque, None);
458 let positions = Rc::new(std::cell::RefCell::new(Vec::new()));
459 let recorded = Rc::clone(&positions);
460 listener.set_on_pointer_down(
461 &mut app,
462 Some(Rc::new(move |_app: &mut App, event: PointerDownEvent| {
463 recorded.borrow_mut().push(event.local_position());
464 })),
465 );
466 render_view.set_child(&mut app, Some(listener.as_box()));
467 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
468 SchedulerBinding::handle_draw_frame(&mut app);
469
470 GestureBinding::instance(&mut app).handle_pointer_event(
471 &mut app,
472 PointerEvent::Down(PointerDownEvent {
473 position: Offset::new(30.0, 40.0),
474 ..PointerDownEvent::default()
475 }),
476 );
477 assert_eq!(*positions.borrow(), [Offset::new(30.0, 40.0)]);
478 }
479
480 #[test]
481 fn a_mouse_hover_enters_a_mouse_region_and_a_frame_notices_it_moving_away() {
482 use inset_embedder::PointerDeviceKind;
483 use inset_gestures::{
484 PointerAddedEvent, PointerEnterEvent, PointerEvent, PointerExitEvent,
485 };
486 use inset_painting::EdgeInsetsGeometry;
487
488 use crate::proxy_box::RenderMouseRegion;
489 use crate::shifted_box::RenderPadding;
490
491 let (cell, view, _platform) = app_with_view();
492 let mut app = cell.borrow_mut();
493 let binding = RendererBinding::instance(&mut app);
494 let render_view = binding.init_render_view(&mut app, view.clone());
495 let region = RenderMouseRegion::new(&mut app, true, None);
496 let log = Rc::new(std::cell::RefCell::new(Vec::new()));
497 let entered = Rc::clone(&log);
498 region.set_on_enter(
499 &mut app,
500 Some(Rc::new(move |_app: &mut App, event: PointerEnterEvent| {
501 entered
502 .borrow_mut()
503 .push(format!("enter {:?}", event.local_position()));
504 })),
505 );
506 let exited = Rc::clone(&log);
507 region.set_on_exit(
508 &mut app,
509 Some(Rc::new(move |_app: &mut App, event: PointerExitEvent| {
510 exited
511 .borrow_mut()
512 .push(format!("exit {:?}", event.local_position()));
513 })),
514 );
515 let padding = RenderPadding::new(
516 &mut app,
517 EdgeInsetsGeometry::all(100.0),
518 None,
519 Some(region.as_box()),
520 );
521 render_view.set_child(&mut app, Some(padding.as_box()));
522 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
523 SchedulerBinding::handle_draw_frame(&mut app);
524
525 GestureBinding::instance(&mut app).handle_pointer_event(
526 &mut app,
527 PointerEvent::Added(PointerAddedEvent {
528 kind: PointerDeviceKind::Mouse,
529 position: Offset::new(150.0, 150.0),
530 ..PointerAddedEvent::default()
531 }),
532 );
533 assert_eq!(*log.borrow(), ["enter Offset(50.0, 50.0)"]);
534 assert!(binding.mouse_tracker(&app).mouse_is_connected(&app));
535
536 padding.set_padding(&mut app, EdgeInsetsGeometry::only(300.0, 0.0, 0.0, 0.0));
538 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::from_millis(16)));
539 SchedulerBinding::handle_draw_frame(&mut app);
540 assert_eq!(
541 *log.borrow(),
542 ["enter Offset(50.0, 50.0)", "exit Offset(50.0, 50.0)"],
543 "the exit is placed with the transform recorded when the region was entered"
544 );
545 }
546
547 #[test]
548 fn deferred_first_frame_is_not_presented() {
549 let (cell, view, _platform) = app_with_view();
550 let mut app = cell.borrow_mut();
551 let binding = RendererBinding::instance(&mut app);
552 binding.init_render_view(&mut app, view.clone());
553 binding.defer_first_frame(&mut app);
554 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
555 SchedulerBinding::handle_draw_frame(&mut app);
556 assert_eq!(view.presented(), 0);
557
558 binding.allow_first_frame(&mut app);
559 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
560 SchedulerBinding::handle_draw_frame(&mut app);
561 assert_eq!(view.presented(), 1);
562 }
563}