1use std::rc::Rc;
6
7use inset_embedder::{Offset, ViewId};
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 pipeline_owner: Option<Handle<PipelineOwner>>,
77 render_view: Option<RenderHandle<RenderView>>,
79 render_view_initial_frame_prepared: bool,
80 render_views: Vec<(ViewId, RenderHandle<RenderView>)>,
81 mouse_tracker: Option<Handle<MouseTracker>>,
82 debug_mouse_tracker_update_scheduled: bool,
83 first_frame_deferred_count: u32,
84 first_frame_sent: bool,
85}
86
87impl RendererBinding {
88 pub fn instance(app: &mut App) -> Handle<RendererBinding> {
90 let this: Handle<RendererBinding> = app.singleton();
91 if app.get(this).root_pipeline_owner.is_none() {
92 let root_pipeline_owner = this.create_root_pipeline_owner(app);
93 app.get_mut(this).root_pipeline_owner = Some(root_pipeline_owner);
94 root_pipeline_owner.attach(app, Rc::new(BindingPipelineManifold));
95 SchedulerBinding::add_persistent_frame_callback(
96 app,
97 FrameCallback::new(|app, _time_stamp| {
98 RendererBinding::instance(app).handle_persistent_frame_callback(app)
99 }),
100 );
101 this.init_mouse_tracker(app, None);
102 GestureBinding::instance(app).set_overrides(app, Rc::new(this));
105 }
106 this
107 }
108
109 pub fn mouse_tracker(self: Handle<Self>, app: &App) -> Handle<MouseTracker> {
112 app.get(self)
113 .mouse_tracker
114 .expect("RendererBinding::instance must run first")
115 }
116
117 pub fn init_mouse_tracker(
122 self: Handle<Self>,
123 app: &mut App,
124 tracker: Option<Handle<MouseTracker>>,
125 ) {
126 if let Some(previous) = app.get(self).mouse_tracker {
127 previous.dispose(app);
128 }
129 let tracker = tracker.unwrap_or_else(|| {
130 MouseTracker::new(
131 app,
132 Rc::new(move |app: &mut App, position: Offset, view_id: ViewId| {
133 let mut result = HitTestResult::new();
134 self.hit_test_in_view(app, &mut result, position, view_id);
135 result
136 }),
137 )
138 });
139 app.get_mut(self).mouse_tracker = Some(tracker);
140 }
141
142 pub fn root_pipeline_owner(self: Handle<Self>, app: &App) -> Handle<PipelineOwner> {
148 app.get(self)
149 .root_pipeline_owner
150 .expect("RendererBinding::instance must run first")
151 }
152
153 fn create_root_pipeline_owner(self: Handle<Self>, app: &mut App) -> Handle<PipelineOwner> {
155 PipelineOwner::new(
156 app,
157 Some(Listener::new(|app| {
158 SchedulerBinding::ensure_visual_update(app);
159 })),
160 )
161 }
162
163 pub fn pipeline_owner(self: Handle<Self>, app: &mut App) -> Handle<PipelineOwner> {
165 if let Some(owner) = app.get(self).pipeline_owner {
166 return owner;
167 }
168 let owner = PipelineOwner::new(app, None);
169 app.get_mut(self).pipeline_owner = Some(owner);
170 owner
171 }
172
173 pub fn render_view(self: Handle<Self>, app: &mut App) -> RenderHandle<RenderView> {
179 if let Some(view) = app.get(self).render_view {
180 return view;
181 }
182 let implicit_view = app
183 .platform()
184 .implicit_view()
185 .expect("the platform has no implicit view");
186 let view = RenderView::new(app, None, None, implicit_view);
187 app.get_mut(self).render_view = Some(view);
188 view
189 }
190
191 pub fn render_views(self: Handle<Self>, app: &App) -> Vec<RenderHandle<RenderView>> {
193 app.get(self)
194 .render_views
195 .iter()
196 .map(|(_, view)| *view)
197 .collect()
198 }
199
200 pub fn add_render_view(self: Handle<Self>, app: &mut App, view: RenderHandle<RenderView>) {
207 let view_id = view.flutter_view(app).id();
208 debug_assert!(
209 !app.get(self)
210 .render_views
211 .iter()
212 .any(|(id, existing)| *id == view_id || *existing == view)
213 );
214 app.get_mut(self).render_views.push((view_id, view));
215 let configuration = self.create_view_configuration_for(app, view);
216 view.set_configuration(app, configuration);
217 }
218
219 pub fn remove_render_view(self: Handle<Self>, app: &mut App, view: RenderHandle<RenderView>) {
221 let view_id = view.flutter_view(app).id();
222 let views = &mut app.get_mut(self).render_views;
223 debug_assert!(
224 views
225 .iter()
226 .any(|(id, existing)| *id == view_id && *existing == view)
227 );
228 views.retain(|(id, _)| *id != view_id);
229 }
230
231 pub fn create_view_configuration_for(
234 self: Handle<Self>,
235 app: &App,
236 render_view: RenderHandle<RenderView>,
237 ) -> ViewConfiguration {
238 ViewConfiguration::from_view(&*render_view.flutter_view(app))
239 }
240
241 pub fn handle_metrics_changed(self: Handle<Self>, app: &mut App) {
245 let mut force_frame = false;
246 for view in self.render_views(app) {
247 force_frame = force_frame || view.child(app).is_some();
248 let configuration = self.create_view_configuration_for(app, view);
249 view.set_configuration(app, configuration);
250 }
251 if force_frame {
252 SchedulerBinding::schedule_forced_frame(app);
253 }
254 if let Some(overrides) = app.get(self).overrides.clone() {
255 overrides.did_handle_metrics_changed(app);
256 }
257 }
258
259 fn handle_persistent_frame_callback(self: Handle<Self>, app: &mut App) {
260 self.draw_frame(app);
261 self.schedule_mouse_tracker_update(app);
262 }
263
264 fn schedule_mouse_tracker_update(self: Handle<Self>, app: &mut App) {
265 debug_assert!(!app.get(self).debug_mouse_tracker_update_scheduled);
266 if cfg!(debug_assertions) {
267 app.get_mut(self).debug_mouse_tracker_update_scheduled = true;
268 }
269 SchedulerBinding::add_post_frame_callback(
270 app,
271 FrameCallback::new(move |app, _duration| {
272 debug_assert!(app.get(self).debug_mouse_tracker_update_scheduled);
273 if cfg!(debug_assertions) {
274 app.get_mut(self).debug_mouse_tracker_update_scheduled = false;
275 }
276 self.mouse_tracker(app).update_all_devices(app);
277 }),
278 );
279 }
280
281 pub fn send_frames_to_engine(self: Handle<Self>, app: &App) -> bool {
286 let data = app.get(self);
287 data.first_frame_sent || data.first_frame_deferred_count == 0
288 }
289
290 pub fn defer_first_frame(self: Handle<Self>, app: &mut App) {
293 app.get_mut(self).first_frame_deferred_count += 1;
294 }
295
296 pub fn allow_first_frame(self: Handle<Self>, app: &mut App) {
299 debug_assert!(app.get(self).first_frame_deferred_count > 0);
300 app.get_mut(self).first_frame_deferred_count -= 1;
301 if !app.get(self).first_frame_sent {
302 SchedulerBinding::schedule_forced_frame(app);
303 }
304 }
305
306 pub fn reset_first_frame_sent(self: Handle<Self>, app: &mut App) {
308 app.get_mut(self).first_frame_sent = false;
309 }
310
311 pub fn set_overrides(
321 self: Handle<Self>,
322 app: &mut App,
323 overrides: Rc<dyn RendererBindingOverrides>,
324 ) {
325 app.get_mut(self).overrides = Some(overrides);
326 }
327
328 pub fn draw_frame(self: Handle<Self>, app: &mut App) {
329 let overrides = app.get(self).overrides.clone();
330 if let Some(overrides) = &overrides {
331 overrides.will_draw_frame(app);
332 }
333 let root_pipeline_owner = self.root_pipeline_owner(app);
334 root_pipeline_owner.flush_layout(app);
335 root_pipeline_owner.flush_compositing_bits(app);
336 root_pipeline_owner.flush_paint(app);
337 if self.send_frames_to_engine(app) {
338 for render_view in self.render_views(app) {
339 render_view.composite_frame(app); }
341 app.get_mut(self).first_frame_sent = true;
342 }
343 if let Some(overrides) = &overrides {
344 overrides.did_draw_frame(app);
345 }
346 }
347
348 pub fn init_render_view(self: Handle<Self>, app: &mut App) -> RenderHandle<RenderView> {
352 let render_view = self.render_view(app);
353 if app.get(self).render_view_initial_frame_prepared {
354 return render_view;
355 }
356 self.root_pipeline_owner(app)
357 .set_root_node(app, Some(render_view.as_object()));
358 self.add_render_view(app, render_view);
359 render_view.prepare_initial_frame(app);
360 app.get_mut(self).render_view_initial_frame_prepared = true;
361 render_view
362 }
363}
364
365impl GestureBindingOverridesObject for RendererBinding {
370 fn hit_test(self: Handle<Self>, app: &mut App, result: &mut HitTestResult, position: Offset) {
371 let Some(view) = app.platform().implicit_view() else {
372 return;
373 };
374 self.hit_test_in_view(app, result, position, view.id());
375 }
376
377 fn hit_test_in_view(
378 self: Handle<Self>,
379 app: &mut App,
380 result: &mut HitTestResult,
381 position: Offset,
382 view_id: ViewId,
383 ) {
384 let render_view = app
385 .get(self)
386 .render_views
387 .iter()
388 .find(|(id, _)| *id == view_id)
389 .map(|(_, view)| *view);
390 if let Some(render_view) = render_view {
391 render_view.hit_test(app, result, position);
392 }
393 }
394
395 fn will_dispatch_event(
396 self: Handle<Self>,
397 app: &mut App,
398 event: &PointerEvent,
399 hit_test_result: Option<&HitTestResult>,
400 ) {
401 let result = match event {
405 PointerEvent::Move(_) => None,
406 _ => hit_test_result,
407 };
408 self.mouse_tracker(app)
409 .update_with_event(app, event, result);
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use inset_foundation::AppCell;
416 use std::cell::Cell;
417 use std::time::Duration;
418
419 use inset_embedder::{
420 Picture, Platform, PlatformRef, Size, TargetPlatform, View, ViewMetrics, ViewRef,
421 };
422
423 use super::*;
424 use crate::box_::{BoxConstraints, RenderBox};
425 use crate::proxy_box::RenderConstrainedBox;
426
427 struct TestView {
428 presented: Rc<Cell<u32>>,
429 }
430
431 impl View for TestView {
432 fn id(&self) -> ViewId {
433 ViewId(0)
434 }
435
436 fn metrics(&self) -> ViewMetrics {
437 ViewMetrics {
438 physical_size: [800.0, 600.0],
439 physical_constraints: inset_embedder::ViewConstraints::tight(800.0, 600.0),
440 device_pixel_ratio: 2.0,
441 ..ViewMetrics::default()
442 }
443 }
444
445 fn present(&self, _picture: &Picture) {
446 self.presented.set(self.presented.get() + 1);
447 }
448 }
449
450 struct TestPlatform {
451 view: ViewRef,
452 frames: Rc<Cell<u32>>,
453 }
454
455 impl Platform for TestPlatform {
456 fn target_platform(&self) -> TargetPlatform {
457 TargetPlatform::MacOS
458 }
459
460 fn request_frame(&self) {
461 self.frames.set(self.frames.get() + 1);
462 }
463
464 fn now(&self) -> std::time::Instant {
465 std::time::Instant::now()
466 }
467
468 fn wake_at(&self, _deadline: std::time::Instant) {}
469
470 fn views(&self) -> Vec<ViewRef> {
471 vec![Rc::clone(&self.view)]
472 }
473
474 fn view(&self, id: ViewId) -> Option<ViewRef> {
475 (self.view.id() == id).then(|| Rc::clone(&self.view))
476 }
477
478 fn implicit_view(&self) -> Option<ViewRef> {
479 Some(Rc::clone(&self.view))
480 }
481 }
482
483 fn app_with_view() -> (Rc<AppCell>, Rc<Cell<u32>>, Rc<Cell<u32>>) {
484 let presented = Rc::new(Cell::new(0));
485 let frames = Rc::new(Cell::new(0));
486 let platform: PlatformRef = Rc::new(TestPlatform {
487 view: Rc::new(TestView {
488 presented: Rc::clone(&presented),
489 }),
490 frames: Rc::clone(&frames),
491 });
492 (AppCell::with_platform(platform), presented, frames)
493 }
494
495 #[test]
496 fn a_frame_lays_out_paints_and_presents_the_implicit_view() {
497 let (cell, presented, _frames) = app_with_view();
498 let mut app = cell.borrow_mut();
499 let binding = RendererBinding::instance(&mut app);
500 let render_view = binding.init_render_view(&mut app);
501 assert_eq!(
502 render_view.configuration(&app).logical_constraints,
503 BoxConstraints::tight(Size::new(400.0, 300.0))
504 );
505 let child =
506 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
507 render_view.set_child(&mut app, Some(child.as_box()));
508
509 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
510 SchedulerBinding::handle_draw_frame(&mut app);
511
512 assert_eq!(render_view.size(&app), Size::new(400.0, 300.0));
513 assert_eq!(child.size(&app), Size::new(400.0, 300.0));
514 assert_eq!(presented.get(), 1);
515 assert!(!child.debug_needs_layout(&app));
516 assert!(!child.as_object().debug_needs_paint(&app));
517 }
518
519 #[test]
520 fn a_dirty_node_requests_a_visual_update() {
521 let (cell, _presented, frames) = app_with_view();
522 let mut app = cell.borrow_mut();
523 let binding = RendererBinding::instance(&mut app);
524 let render_view = binding.init_render_view(&mut app);
525 let child =
526 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
527 render_view.set_child(&mut app, Some(child.as_box()));
528 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
529 SchedulerBinding::handle_draw_frame(&mut app);
530 let before = frames.get();
531
532 child.mark_needs_layout(&mut app);
533 assert!(
534 frames.get() > before,
535 "the root owner's visual update reaches the host"
536 );
537 }
538
539 #[test]
540 fn a_pointer_down_reaches_a_pointer_listener_through_the_gesture_binding() {
541 use inset_gestures::{PointerDownEvent, PointerEvent};
542
543 use crate::proxy_box::{HitTestBehavior, RenderPointerListener};
544
545 let (cell, _presented, _frames) = app_with_view();
546 let mut app = cell.borrow_mut();
547 let binding = RendererBinding::instance(&mut app);
548 let render_view = binding.init_render_view(&mut app);
549 let listener = RenderPointerListener::new(&mut app, HitTestBehavior::Opaque, None);
550 let positions = Rc::new(std::cell::RefCell::new(Vec::new()));
551 let recorded = Rc::clone(&positions);
552 listener.set_on_pointer_down(
553 &mut app,
554 Some(Rc::new(move |_app: &mut App, event: PointerDownEvent| {
555 recorded.borrow_mut().push(event.local_position());
556 })),
557 );
558 render_view.set_child(&mut app, Some(listener.as_box()));
559 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
560 SchedulerBinding::handle_draw_frame(&mut app);
561
562 GestureBinding::instance(&mut app).handle_pointer_event(
563 &mut app,
564 PointerEvent::Down(PointerDownEvent {
565 position: Offset::new(30.0, 40.0),
566 ..PointerDownEvent::default()
567 }),
568 );
569 assert_eq!(*positions.borrow(), [Offset::new(30.0, 40.0)]);
570 }
571
572 #[test]
573 fn a_mouse_hover_enters_a_mouse_region_and_a_frame_notices_it_moving_away() {
574 use inset_embedder::PointerDeviceKind;
575 use inset_gestures::{
576 PointerAddedEvent, PointerEnterEvent, PointerEvent, PointerExitEvent,
577 };
578 use inset_painting::EdgeInsetsGeometry;
579
580 use crate::proxy_box::RenderMouseRegion;
581 use crate::shifted_box::RenderPadding;
582
583 let (cell, _presented, _frames) = app_with_view();
584 let mut app = cell.borrow_mut();
585 let binding = RendererBinding::instance(&mut app);
586 let render_view = binding.init_render_view(&mut app);
587 let region = RenderMouseRegion::new(&mut app, true, None);
588 let log = Rc::new(std::cell::RefCell::new(Vec::new()));
589 let entered = Rc::clone(&log);
590 region.set_on_enter(
591 &mut app,
592 Some(Rc::new(move |_app: &mut App, event: PointerEnterEvent| {
593 entered
594 .borrow_mut()
595 .push(format!("enter {:?}", event.local_position()));
596 })),
597 );
598 let exited = Rc::clone(&log);
599 region.set_on_exit(
600 &mut app,
601 Some(Rc::new(move |_app: &mut App, event: PointerExitEvent| {
602 exited
603 .borrow_mut()
604 .push(format!("exit {:?}", event.local_position()));
605 })),
606 );
607 let padding = RenderPadding::new(
608 &mut app,
609 EdgeInsetsGeometry::all(100.0),
610 None,
611 Some(region.as_box()),
612 );
613 render_view.set_child(&mut app, Some(padding.as_box()));
614 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
615 SchedulerBinding::handle_draw_frame(&mut app);
616
617 GestureBinding::instance(&mut app).handle_pointer_event(
618 &mut app,
619 PointerEvent::Added(PointerAddedEvent {
620 kind: PointerDeviceKind::Mouse,
621 position: Offset::new(150.0, 150.0),
622 ..PointerAddedEvent::default()
623 }),
624 );
625 assert_eq!(*log.borrow(), ["enter Offset(50.0, 50.0)"]);
626 assert!(binding.mouse_tracker(&app).mouse_is_connected(&app));
627
628 padding.set_padding(&mut app, EdgeInsetsGeometry::only(300.0, 0.0, 0.0, 0.0));
630 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::from_millis(16)));
631 SchedulerBinding::handle_draw_frame(&mut app);
632 assert_eq!(
633 *log.borrow(),
634 ["enter Offset(50.0, 50.0)", "exit Offset(50.0, 50.0)"],
635 "the exit is placed with the transform recorded when the region was entered"
636 );
637 }
638
639 #[test]
640 fn deferred_first_frame_is_not_presented() {
641 let (cell, presented, _frames) = app_with_view();
642 let mut app = cell.borrow_mut();
643 let binding = RendererBinding::instance(&mut app);
644 binding.init_render_view(&mut app);
645 binding.defer_first_frame(&mut app);
646 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
647 SchedulerBinding::handle_draw_frame(&mut app);
648 assert_eq!(presented.get(), 0);
649
650 binding.allow_first_frame(&mut app);
651 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
652 SchedulerBinding::handle_draw_frame(&mut app);
653 assert_eq!(presented.get(), 1);
654 }
655}