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::time::Duration;
417
418 use inset_embedder::{Size, TargetPlatform};
419 use inset_test::{TestPlatform, TestView};
420
421 use super::*;
422 use crate::box_::{BoxConstraints, RenderBox};
423 use crate::proxy_box::RenderConstrainedBox;
424
425 fn app_with_view() -> (Rc<AppCell>, Rc<TestView>, Rc<TestPlatform>) {
427 let view = Rc::new(TestView::with_pixel_ratio(800.0, 600.0, 2.0));
428 let platform = Rc::new(
429 TestPlatform::new()
430 .on(TargetPlatform::MacOS)
431 .with_view(view.clone()),
432 );
433 (AppCell::with_platform(platform.clone()), view, platform)
434 }
435
436 #[test]
437 fn a_frame_lays_out_paints_and_presents_the_implicit_view() {
438 let (cell, view, _platform) = app_with_view();
439 let mut app = cell.borrow_mut();
440 let binding = RendererBinding::instance(&mut app);
441 let render_view = binding.init_render_view(&mut app);
442 assert_eq!(
443 render_view.configuration(&app).logical_constraints,
444 BoxConstraints::tight(Size::new(400.0, 300.0))
445 );
446 let child =
447 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
448 render_view.set_child(&mut app, Some(child.as_box()));
449
450 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
451 SchedulerBinding::handle_draw_frame(&mut app);
452
453 assert_eq!(render_view.size(&app), Size::new(400.0, 300.0));
454 assert_eq!(child.size(&app), Size::new(400.0, 300.0));
455 assert_eq!(view.presented(), 1);
456 assert!(!child.debug_needs_layout(&app));
457 assert!(!child.as_object().debug_needs_paint(&app));
458 }
459
460 #[test]
461 fn a_dirty_node_requests_a_visual_update() {
462 let (cell, _view, platform) = app_with_view();
463 let mut app = cell.borrow_mut();
464 let binding = RendererBinding::instance(&mut app);
465 let render_view = binding.init_render_view(&mut app);
466 let child =
467 RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
468 render_view.set_child(&mut app, Some(child.as_box()));
469 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
470 SchedulerBinding::handle_draw_frame(&mut app);
471 let before = platform.frames_requested();
472
473 child.mark_needs_layout(&mut app);
474 assert!(
475 platform.frames_requested() > before,
476 "the root owner's visual update reaches the host"
477 );
478 }
479
480 #[test]
481 fn a_pointer_down_reaches_a_pointer_listener_through_the_gesture_binding() {
482 use inset_gestures::{PointerDownEvent, PointerEvent};
483
484 use crate::proxy_box::{HitTestBehavior, RenderPointerListener};
485
486 let (cell, _view, _platform) = app_with_view();
487 let mut app = cell.borrow_mut();
488 let binding = RendererBinding::instance(&mut app);
489 let render_view = binding.init_render_view(&mut app);
490 let listener = RenderPointerListener::new(&mut app, HitTestBehavior::Opaque, None);
491 let positions = Rc::new(std::cell::RefCell::new(Vec::new()));
492 let recorded = Rc::clone(&positions);
493 listener.set_on_pointer_down(
494 &mut app,
495 Some(Rc::new(move |_app: &mut App, event: PointerDownEvent| {
496 recorded.borrow_mut().push(event.local_position());
497 })),
498 );
499 render_view.set_child(&mut app, Some(listener.as_box()));
500 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
501 SchedulerBinding::handle_draw_frame(&mut app);
502
503 GestureBinding::instance(&mut app).handle_pointer_event(
504 &mut app,
505 PointerEvent::Down(PointerDownEvent {
506 position: Offset::new(30.0, 40.0),
507 ..PointerDownEvent::default()
508 }),
509 );
510 assert_eq!(*positions.borrow(), [Offset::new(30.0, 40.0)]);
511 }
512
513 #[test]
514 fn a_mouse_hover_enters_a_mouse_region_and_a_frame_notices_it_moving_away() {
515 use inset_embedder::PointerDeviceKind;
516 use inset_gestures::{
517 PointerAddedEvent, PointerEnterEvent, PointerEvent, PointerExitEvent,
518 };
519 use inset_painting::EdgeInsetsGeometry;
520
521 use crate::proxy_box::RenderMouseRegion;
522 use crate::shifted_box::RenderPadding;
523
524 let (cell, _view, _platform) = app_with_view();
525 let mut app = cell.borrow_mut();
526 let binding = RendererBinding::instance(&mut app);
527 let render_view = binding.init_render_view(&mut app);
528 let region = RenderMouseRegion::new(&mut app, true, None);
529 let log = Rc::new(std::cell::RefCell::new(Vec::new()));
530 let entered = Rc::clone(&log);
531 region.set_on_enter(
532 &mut app,
533 Some(Rc::new(move |_app: &mut App, event: PointerEnterEvent| {
534 entered
535 .borrow_mut()
536 .push(format!("enter {:?}", event.local_position()));
537 })),
538 );
539 let exited = Rc::clone(&log);
540 region.set_on_exit(
541 &mut app,
542 Some(Rc::new(move |_app: &mut App, event: PointerExitEvent| {
543 exited
544 .borrow_mut()
545 .push(format!("exit {:?}", event.local_position()));
546 })),
547 );
548 let padding = RenderPadding::new(
549 &mut app,
550 EdgeInsetsGeometry::all(100.0),
551 None,
552 Some(region.as_box()),
553 );
554 render_view.set_child(&mut app, Some(padding.as_box()));
555 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
556 SchedulerBinding::handle_draw_frame(&mut app);
557
558 GestureBinding::instance(&mut app).handle_pointer_event(
559 &mut app,
560 PointerEvent::Added(PointerAddedEvent {
561 kind: PointerDeviceKind::Mouse,
562 position: Offset::new(150.0, 150.0),
563 ..PointerAddedEvent::default()
564 }),
565 );
566 assert_eq!(*log.borrow(), ["enter Offset(50.0, 50.0)"]);
567 assert!(binding.mouse_tracker(&app).mouse_is_connected(&app));
568
569 padding.set_padding(&mut app, EdgeInsetsGeometry::only(300.0, 0.0, 0.0, 0.0));
571 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::from_millis(16)));
572 SchedulerBinding::handle_draw_frame(&mut app);
573 assert_eq!(
574 *log.borrow(),
575 ["enter Offset(50.0, 50.0)", "exit Offset(50.0, 50.0)"],
576 "the exit is placed with the transform recorded when the region was entered"
577 );
578 }
579
580 #[test]
581 fn deferred_first_frame_is_not_presented() {
582 let (cell, view, _platform) = app_with_view();
583 let mut app = cell.borrow_mut();
584 let binding = RendererBinding::instance(&mut app);
585 binding.init_render_view(&mut app);
586 binding.defer_first_frame(&mut app);
587 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
588 SchedulerBinding::handle_draw_frame(&mut app);
589 assert_eq!(view.presented(), 0);
590
591 binding.allow_first_frame(&mut app);
592 SchedulerBinding::handle_begin_frame(&mut app, Some(Duration::ZERO));
593 SchedulerBinding::handle_draw_frame(&mut app);
594 assert_eq!(view.presented(), 1);
595 }
596}