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