1use crate::app::MessageInternal;
6use crate::app::strategies::framebuffer::DisplayId;
7use crate::geometry::{IntPoint, Size};
8use crate::input::{self, UserInputMessage};
9use crate::message::Message;
10use crate::render::Context;
11use crate::scene::facets::FacetId;
12use crate::scene::scene::Scene;
13use crate::view::strategies::base::ViewStrategyPtr;
14use crate::{IdFromRaw, MessageTarget};
15use anyhow::{Error, ensure};
16use euclid::size2;
17use fuchsia_framebuffer::ImageId;
18use fuchsia_trace::instant;
19use futures::channel::mpsc::{UnboundedSender, unbounded};
20use std::fmt::{Display, Formatter};
21use zx::{Event, MonotonicInstant};
22
23pub(crate) mod strategies;
24
25#[derive(Debug, Clone)]
26pub struct DisplayInfo {
27 pub id: DisplayId,
28 pub horizontal_size_mm: u32,
29 pub vertical_size_mm: u32,
30 pub using_fallback_size: bool,
31 pub max_layer_count: u32,
32}
33
34impl From<&fidl_fuchsia_hardware_display::Info> for DisplayInfo {
35 fn from(info: &fidl_fuchsia_hardware_display::Info) -> Self {
36 Self {
37 id: info.id.into(),
38 horizontal_size_mm: info.horizontal_size_mm,
39 vertical_size_mm: info.vertical_size_mm,
40 using_fallback_size: info.using_fallback_size,
41 max_layer_count: info.max_layer_count,
42 }
43 }
44}
45
46pub struct ViewAssistantContext {
48 pub key: ViewKey,
50 pub size: Size,
52 pub metrics: Size,
55 pub presentation_time: MonotonicInstant,
58 pub buffer_count: Option<usize>,
61 pub image_id: ImageId,
66 pub image_index: u32,
70 pub mouse_cursor_position: Option<IntPoint>,
73 pub display_info: Option<DisplayInfo>,
76
77 app_sender: UnboundedSender<MessageInternal>,
78}
79
80impl ViewAssistantContext {
81 pub fn new_for_testing() -> Self {
83 let (unbounded_sender, _) = unbounded::<MessageInternal>();
84 Self {
85 key: Default::default(),
86 size: Default::default(),
87 metrics: Default::default(),
88 presentation_time: Default::default(),
89 buffer_count: Default::default(),
90 image_id: Default::default(),
91 image_index: Default::default(),
92 mouse_cursor_position: Default::default(),
93 display_info: Default::default(),
94 app_sender: unbounded_sender,
95 }
96 }
97
98 pub fn queue_message(&mut self, message: Message) {
100 self.app_sender
101 .unbounded_send(MessageInternal::TargetedMessage(
102 MessageTarget::View(self.key),
103 message,
104 ))
105 .expect("ViewAssistantContext::queue_message - unbounded_send");
106 }
107
108 pub fn request_render(&self) {
111 self.app_sender
112 .unbounded_send(MessageInternal::RequestRender(self.key))
113 .expect("unbounded_send");
114 }
115}
116
117pub trait ViewAssistant {
119 #[allow(unused_variables)]
121 fn setup(&mut self, context: &ViewAssistantContext) -> Result<(), Error> {
122 Ok(())
123 }
124
125 #[allow(unused_variables)]
126 fn resize(&mut self, new_size: &Size) -> Result<(), Error> {
128 Ok(())
129 }
130
131 #[allow(unused_variables)]
132 fn get_scene(&mut self, size: Size) -> Option<&mut Scene> {
135 None
136 }
137
138 #[allow(unused_variables)]
139 fn get_scene_with_contexts(
143 &mut self,
144 render_context: &mut Context,
145 view_context: &ViewAssistantContext,
146 ) -> Option<&mut Scene> {
147 self.get_scene(view_context.size)
148 }
149
150 fn render(
153 &mut self,
154 render_context: &mut Context,
155 buffer_ready_event: Event,
156 view_context: &ViewAssistantContext,
157 ) -> Result<(), Error> {
158 if let Some(scene) = self.get_scene_with_contexts(render_context, view_context) {
159 scene.layout(view_context.size);
160 scene.render(render_context, buffer_ready_event, view_context)?;
161 if scene.is_animated() {
162 view_context.request_render();
163 }
164 Ok(())
165 } else {
166 anyhow::bail!("Assistant has ViewMode::Render but doesn't implement render or scene.")
167 }
168 }
169
170 fn handle_input_event(
176 &mut self,
177 context: &mut ViewAssistantContext,
178 event: &input::Event,
179 ) -> Result<(), Error> {
180 match &event.event_type {
181 input::EventType::Mouse(mouse_event) => {
182 self.handle_mouse_event(context, event, mouse_event)
183 }
184 input::EventType::Touch(touch_event) => {
185 self.handle_touch_event(context, event, touch_event)
186 }
187 input::EventType::Keyboard(keyboard_event) => {
188 self.handle_keyboard_event(context, event, keyboard_event)
189 }
190 input::EventType::ConsumerControl(consumer_control_event) => {
191 self.handle_consumer_control_event(context, event, consumer_control_event)
192 }
193 }
194 }
195
196 fn handle_mouse_event(
230 &mut self,
231 context: &mut ViewAssistantContext,
232 event: &input::Event,
233 mouse_event: &input::mouse::Event,
234 ) -> Result<(), Error> {
235 if self.uses_pointer_events() {
236 if let Some(mouse_event) =
237 input::pointer::Event::new_from_mouse_event(&event.device_id, mouse_event)
238 {
239 self.handle_pointer_event(context, event, &mouse_event)
240 } else {
241 Ok(())
242 }
243 } else {
244 Ok(())
245 }
246 }
247
248 fn handle_touch_event(
272 &mut self,
273 context: &mut ViewAssistantContext,
274 event: &input::Event,
275 touch_event: &input::touch::Event,
276 ) -> Result<(), Error> {
277 if self.uses_pointer_events() {
278 for contact in &touch_event.contacts {
279 self.handle_pointer_event(
280 context,
281 event,
282 &input::pointer::Event::new_from_contact(contact),
283 )?;
284 }
285 Ok(())
286 } else {
287 Ok(())
288 }
289 }
290
291 #[allow(unused_variables)]
332 fn handle_pointer_event(
333 &mut self,
334 context: &mut ViewAssistantContext,
335 event: &input::Event,
336 pointer_event: &input::pointer::Event,
337 ) -> Result<(), Error> {
338 Ok(())
339 }
340
341 #[allow(unused_variables)]
343 fn handle_keyboard_event(
344 &mut self,
345 context: &mut ViewAssistantContext,
346 event: &input::Event,
347 keyboard_event: &input::keyboard::Event,
348 ) -> Result<(), Error> {
349 Ok(())
350 }
351
352 #[allow(unused_variables)]
354 fn handle_consumer_control_event(
355 &mut self,
356 context: &mut ViewAssistantContext,
357 event: &input::Event,
358 consumer_control_event: &input::consumer_control::Event,
359 ) -> Result<(), Error> {
360 Ok(())
361 }
362
363 #[allow(unused_variables)]
367 fn handle_focus_event(
368 &mut self,
369 context: &mut ViewAssistantContext,
370 focused: bool,
371 ) -> Result<(), Error> {
372 Ok(())
373 }
374
375 #[allow(unused_variables)]
402 fn handle_message(&mut self, message: Message) {}
403
404 fn uses_pointer_events(&self) -> bool {
407 true
408 }
409
410 fn ownership_changed(&mut self, _owned: bool) -> Result<(), Error> {
413 Ok(())
414 }
415
416 fn get_render_offset(&mut self) -> Option<i64> {
419 None
420 }
421}
422
423pub type ViewAssistantPtr = Box<dyn ViewAssistant>;
426
427#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
429pub struct ViewKey(pub u64);
430
431impl IdFromRaw for ViewKey {
432 fn from_raw(id: u64) -> ViewKey {
433 ViewKey(id)
434 }
435}
436
437impl Display for ViewKey {
438 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
439 write!(f, "ViewKey({})", self.0)
440 }
441}
442
443#[derive(Debug)]
444pub(crate) struct ViewDetails {
445 key: ViewKey,
446 metrics: Size,
447 physical_size: Size,
448 logical_size: Size,
449}
450
451pub(crate) struct ViewController {
455 key: ViewKey,
456 assistant: ViewAssistantPtr,
457 metrics: Size,
458 physical_size: Size,
459 logical_size: Size,
460 render_requested: bool,
461 strategy: ViewStrategyPtr,
462 app_sender: UnboundedSender<MessageInternal>,
463}
464
465impl ViewController {
466 pub async fn new_with_strategy(
467 key: ViewKey,
468 view_assistant: ViewAssistantPtr,
469 strategy: ViewStrategyPtr,
470 app_sender: UnboundedSender<MessageInternal>,
471 ) -> Result<ViewController, Error> {
472 let metrics = strategy.initial_metrics();
473 let physical_size = strategy.initial_physical_size();
474 let logical_size = strategy.initial_logical_size();
475
476 let mut view_controller = ViewController {
477 key,
478 metrics,
479 physical_size,
480 logical_size,
481 render_requested: true,
482 assistant: view_assistant,
483 strategy,
484 app_sender,
485 };
486
487 view_controller
488 .strategy
489 .setup(&view_controller.make_view_details(), &mut view_controller.assistant);
490
491 Ok(view_controller)
492 }
493
494 fn make_view_details(&self) -> ViewDetails {
495 ViewDetails {
496 key: self.key,
497 metrics: self.metrics,
498 physical_size: self.physical_size,
499 logical_size: self.logical_size,
500 }
501 }
502
503 pub fn present(&mut self) {
505 self.strategy.present(&self.make_view_details());
506 }
507
508 pub fn send_update_message(&mut self) {
509 self.app_sender.unbounded_send(MessageInternal::Render(self.key)).expect("unbounded_send");
510 }
511
512 pub fn ownership_changed(&mut self, owned: bool) {
513 self.strategy.ownership_changed(owned);
514 self.assistant
515 .ownership_changed(owned)
516 .unwrap_or_else(|e| println!("ownership_changed error: {}", e));
517 }
518
519 pub fn drop_display_resources(&mut self) {
520 self.strategy.drop_display_resources();
521 }
522
523 pub fn request_render(&mut self) {
524 self.render_requested = true;
525 self.strategy.render_requested();
526 }
527
528 pub async fn render(&mut self) {
529 if self.render_requested {
530 self.physical_size = size2(
532 self.logical_size.width * self.metrics.width,
533 self.logical_size.height * self.metrics.height,
534 );
535
536 if self.strategy.render(&self.make_view_details(), &mut self.assistant).await {
537 self.render_requested = false;
538 }
539 self.present();
540 }
541 }
542
543 pub fn present_done(&mut self, info: fidl_fuchsia_scenic_scheduling::FramePresentedInfo) {
544 self.strategy.present_done(&self.make_view_details(), &mut self.assistant, info);
545 }
546
547 pub fn handle_metrics_changed(&mut self, metrics: Size) {
548 if self.metrics != metrics {
549 instant!(
550 c"gfx",
551 c"ViewController::metrics_changed",
552 fuchsia_trace::Scope::Process,
553 "old_device_pixel_ratio_x" => self.metrics.width as f64,
554 "old_device_pixel_ratio_y" => self.metrics.height as f64,
555 "new_device_pixel_ratio_x" => metrics.width as f64,
556 "new_device_pixel_ratio_y" => metrics.height as f64
557 );
558 self.metrics = metrics;
559 self.render_requested = true;
560 self.send_update_message();
561 }
562 }
563
564 pub fn handle_size_changed(&mut self, new_size: Size) {
565 if self.logical_size != new_size {
566 instant!(
567 c"gfx",
568 c"ViewController::size_changed",
569 fuchsia_trace::Scope::Process,
570 "old_logical_width" => self.logical_size.width as f64,
571 "old_logical_height" => self.logical_size.height as f64,
572 "new_logical_width" => new_size.width as f64,
573 "new_logical_height" => new_size.height as f64
574 );
575 self.logical_size = new_size;
576 self.assistant
577 .resize(&new_size)
578 .unwrap_or_else(|e| println!("handle_size_changed error: {}", e));
579 self.render_requested = true;
580 self.send_update_message();
581 }
582 }
583
584 pub fn focus(&mut self, focus: bool) {
585 self.strategy.handle_focus(&self.make_view_details(), &mut self.assistant, focus);
586 }
587
588 fn handle_input_events_internal(
589 &mut self,
590 view_details: &ViewDetails,
591 events: Vec<input::Event>,
592 ) -> Result<(), Error> {
593 let mut view_assistant_context = self.strategy.create_view_assistant_context(&view_details);
594 for event in events {
595 self.strategy.inspect_event(view_details, &event);
596 self.assistant.handle_input_event(&mut view_assistant_context, &event)?;
597 }
598 Ok(())
599 }
600
601 pub fn handle_user_input_message(
602 &mut self,
603 user_input_message: UserInputMessage,
604 ) -> Result<(), Error> {
605 let view_details = self.make_view_details();
606 let events = self.strategy.convert_user_input_message(&view_details, user_input_message)?;
607 self.handle_input_events_internal(&view_details, events)?;
608 Ok(())
609 }
610
611 pub fn handle_input_events(&mut self, events: Vec<input::Event>) -> Result<(), Error> {
613 let view_details = self.make_view_details();
614 self.handle_input_events_internal(&view_details, events)?;
615 Ok(())
616 }
617
618 pub fn send_message(&mut self, msg: Message) {
621 self.assistant.handle_message(msg);
622 }
623
624 pub fn send_facet_message(&mut self, facet_id: FacetId, msg: Message) -> Result<(), Error> {
627 let scene = self.assistant.get_scene(self.physical_size);
628 ensure!(scene.is_some(), "send_facet_message called on view not providing a scene");
629 let scene = scene.unwrap();
630 scene.send_message(&facet_id, msg);
631 Ok(())
632 }
633
634 pub fn image_freed(&mut self, image_id: u64, collection_id: u32) {
635 self.strategy.image_freed(image_id, collection_id);
636 }
637
638 pub fn handle_on_next_frame_begin(
639 &mut self,
640 info: &fidl_fuchsia_ui_composition::OnNextFrameBeginValues,
641 ) {
642 self.strategy.handle_on_next_frame_begin(info);
643 }
644
645 pub async fn handle_display_coordinator_listener_request(
646 &mut self,
647 event: fidl_fuchsia_hardware_display::CoordinatorListenerRequest,
648 ) {
649 self.strategy.handle_display_coordinator_listener_request(event).await;
650 }
651
652 pub fn is_hosted_on_display(&self, display_id: DisplayId) -> bool {
653 self.strategy.is_hosted_on_display(display_id)
654 }
655
656 pub fn close(&mut self) {
657 self.strategy.close();
658 }
659}