1use std::cell::{Cell, Ref, RefCell};
6use std::collections::hash_map::Entry;
7use std::env;
8use std::fs::create_dir_all;
9use std::iter::once;
10use std::rc::Rc;
11use std::sync::Arc;
12use std::time::{SystemTime, UNIX_EPOCH};
13
14use base::Epoch;
15use base::cross_process_instant::CrossProcessInstant;
16use base::generic_channel::{GenericSender, RoutedReceiver};
17use base::id::{PipelineId, RenderingGroupId, WebViewId};
18use bitflags::bitflags;
19use compositing_traits::display_list::{CompositorDisplayListInfo, ScrollTree, ScrollType};
20use compositing_traits::rendering_context::RenderingContext;
21use compositing_traits::{
22 CompositionPipeline, CompositorMsg, ImageUpdate, PipelineExitSource, SendableFrameTree,
23 WebViewTrait,
24};
25use constellation_traits::{EmbedderToConstellationMessage, PaintMetricEvent};
26use crossbeam_channel::Sender;
27use dpi::PhysicalSize;
28use embedder_traits::{
29 CompositorHitTestResult, InputEventAndId, ScreenshotCaptureError, ShutdownState,
30 ViewportDetails,
31};
32use euclid::{Point2D, Scale, Size2D, Transform3D};
33use image::RgbaImage;
34use ipc_channel::ipc::{self, IpcSharedMemory};
35use log::{debug, info, trace, warn};
36use profile_traits::mem::{
37 ProcessReports, ProfilerRegistration, Report, ReportKind, perform_memory_report,
38};
39use profile_traits::time::{self as profile_time, ProfilerCategory};
40use profile_traits::{path, time_profile};
41use rustc_hash::{FxHashMap, FxHashSet};
42use servo_config::pref;
43use servo_geometry::DeviceIndependentPixel;
44use style_traits::CSSPixel;
45use webrender::{CaptureBits, RenderApi, Transaction};
46use webrender_api::units::{
47 DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutPoint, LayoutRect,
48 LayoutSize, WorldPoint,
49};
50use webrender_api::{
51 self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch,
52 ExternalScrollId, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey,
53 FontVariation, ImageKey, PipelineId as WebRenderPipelineId, PropertyBinding,
54 ReferenceFrameKind, RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo,
55 SpatialId, SpatialTreeItemKey, TransformStyle,
56};
57
58use crate::InitialCompositorState;
59use crate::refresh_driver::RefreshDriver;
60use crate::screenshot::ScreenshotTaker;
61use crate::webview_manager::WebViewManager;
62use crate::webview_renderer::{PinchZoomResult, UnknownWebView, WebViewRenderer};
63
64#[derive(Clone)]
66pub enum WebRenderDebugOption {
67 Profiler,
68 TextureCacheDebug,
69 RenderTargetDebug,
70}
71
72pub struct ServoRenderer {
74 refresh_driver: RefreshDriver,
76
77 shutdown_state: Rc<Cell<ShutdownState>>,
80
81 compositor_receiver: RoutedReceiver<CompositorMsg>,
83
84 pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>,
86
87 time_profiler_chan: profile_time::ProfilerChan,
89
90 pub(crate) webrender_api: RenderApi,
92
93 pub(crate) webrender_document: DocumentId,
95
96 webrender_gl: Rc<dyn gleam::gl::Gl>,
98
99 #[cfg(feature = "webxr")]
100 webxr_main_thread: webxr::MainThreadRegistry,
102
103 pub(crate) last_mouse_move_position: Option<DevicePoint>,
106
107 frame_delayer: FrameDelayer,
111}
112
113pub struct IOCompositor {
115 global: Rc<RefCell<ServoRenderer>>,
117
118 webview_renderers: WebViewManager<WebViewRenderer>,
120
121 needs_repaint: Cell<RepaintReason>,
123
124 webrender: Option<webrender::Renderer>,
126
127 rendering_context: Rc<dyn RenderingContext>,
129
130 pending_frames: Cell<usize>,
132
133 screenshot_taker: ScreenshotTaker,
135
136 _mem_profiler_registration: ProfilerRegistration,
139}
140
141#[derive(Clone, Copy, Default, PartialEq)]
143pub(crate) struct RepaintReason(u8);
144
145bitflags! {
146 impl RepaintReason: u8 {
147 const ReadyForScreenshot = 1 << 0;
149 const ChangedAnimationState = 1 << 1;
151 const NewWebRenderFrame = 1 << 2;
153 const Resize = 1 << 3;
155 }
156}
157
158#[derive(PartialEq)]
163pub(crate) enum PaintMetricState {
164 Waiting,
166 Seen(WebRenderEpoch, bool ),
169 Sent,
171}
172
173pub(crate) struct PipelineDetails {
174 pub pipeline: Option<CompositionPipeline>,
176
177 pub parent_pipeline_id: Option<PipelineId>,
179
180 pub animations_running: bool,
182
183 pub animation_callbacks_running: bool,
185
186 pub throttled: bool,
188
189 pub scroll_tree: ScrollTree,
192
193 pub first_paint_metric: PaintMetricState,
195
196 pub first_contentful_paint_metric: PaintMetricState,
198
199 pub viewport_scale: Option<Scale<f32, CSSPixel, DevicePixel>>,
203
204 pub exited: PipelineExitSource,
207
208 pub display_list_epoch: Option<Epoch>,
211}
212
213impl PipelineDetails {
214 pub(crate) fn animation_callbacks_running(&self) -> bool {
215 self.animation_callbacks_running
216 }
217
218 pub(crate) fn animating(&self) -> bool {
219 !self.throttled && (self.animation_callbacks_running || self.animations_running)
220 }
221}
222
223impl PipelineDetails {
224 pub(crate) fn new() -> PipelineDetails {
225 PipelineDetails {
226 pipeline: None,
227 parent_pipeline_id: None,
228 viewport_scale: None,
229 animations_running: false,
230 animation_callbacks_running: false,
231 throttled: false,
232 scroll_tree: ScrollTree::default(),
233 first_paint_metric: PaintMetricState::Waiting,
234 first_contentful_paint_metric: PaintMetricState::Waiting,
235 exited: PipelineExitSource::empty(),
236 display_list_epoch: None,
237 }
238 }
239
240 fn install_new_scroll_tree(&mut self, new_scroll_tree: ScrollTree) {
241 let old_scroll_offsets = self.scroll_tree.scroll_offsets();
242 self.scroll_tree = new_scroll_tree;
243 self.scroll_tree.set_all_scroll_offsets(&old_scroll_offsets);
244 }
245}
246
247impl ServoRenderer {
248 pub fn shutdown_state(&self) -> ShutdownState {
249 self.shutdown_state.get()
250 }
251
252 pub(crate) fn hit_test_at_point(&self, point: DevicePoint) -> Vec<CompositorHitTestResult> {
253 let world_point = WorldPoint::from_untyped(point.to_untyped());
255 let results = self
256 .webrender_api
257 .hit_test(self.webrender_document, world_point);
258
259 results
260 .items
261 .iter()
262 .map(|item| {
263 let pipeline_id = item.pipeline.into();
264 let external_scroll_id = ExternalScrollId(item.tag.0, item.pipeline);
265 CompositorHitTestResult {
266 pipeline_id,
267 point_in_viewport: Point2D::from_untyped(item.point_in_viewport.to_untyped()),
268 external_scroll_id,
269 }
270 })
271 .collect()
272 }
273
274 pub(crate) fn send_transaction(&mut self, transaction: Transaction) {
275 self.webrender_api
276 .send_transaction(self.webrender_document, transaction);
277 }
278}
279
280impl IOCompositor {
281 pub fn new(state: InitialCompositorState) -> Self {
282 let registration = state.mem_profiler_chan.prepare_memory_reporting(
283 "compositor".into(),
284 state.sender.clone(),
285 CompositorMsg::CollectMemoryReport,
286 );
287 let compositor = IOCompositor {
288 global: Rc::new(RefCell::new(ServoRenderer {
289 refresh_driver: RefreshDriver::new(
290 state.constellation_chan.clone(),
291 state.event_loop_waker,
292 ),
293 shutdown_state: state.shutdown_state,
294 compositor_receiver: state.receiver,
295 constellation_sender: state.constellation_chan,
296 time_profiler_chan: state.time_profiler_chan,
297 webrender_api: state.webrender_api,
298 webrender_document: state.webrender_document,
299 webrender_gl: state.webrender_gl,
300 #[cfg(feature = "webxr")]
301 webxr_main_thread: state.webxr_main_thread,
302 last_mouse_move_position: None,
303 frame_delayer: Default::default(),
304 })),
305 webview_renderers: WebViewManager::default(),
306 needs_repaint: Cell::default(),
307 webrender: Some(state.webrender),
308 rendering_context: state.rendering_context,
309 pending_frames: Default::default(),
310 screenshot_taker: Default::default(),
311 _mem_profiler_registration: registration,
312 };
313
314 {
315 let gl = &compositor.global.borrow().webrender_gl;
316 info!("Running on {}", gl.get_string(gleam::gl::RENDERER));
317 info!("OpenGL Version {}", gl.get_string(gleam::gl::VERSION));
318 }
319 compositor.assert_gl_framebuffer_complete();
320 compositor
321 }
322
323 pub fn deinit(&mut self) {
324 if let Err(err) = self.rendering_context.make_current() {
325 warn!("Failed to make the rendering context current: {:?}", err);
326 }
327 if let Some(webrender) = self.webrender.take() {
328 webrender.deinit();
329 }
330 }
331
332 pub(crate) fn rendering_context(&self) -> &dyn RenderingContext {
333 &*self.rendering_context
334 }
335
336 pub fn rendering_context_size(&self) -> Size2D<u32, DevicePixel> {
337 self.rendering_context.size2d()
338 }
339
340 pub fn webxr_running(&self) -> bool {
341 #[cfg(feature = "webxr")]
342 {
343 self.global.borrow().webxr_main_thread.running()
344 }
345 #[cfg(not(feature = "webxr"))]
346 {
347 false
348 }
349 }
350
351 pub(crate) fn webview_renderer(&self, webview_id: WebViewId) -> Option<&WebViewRenderer> {
352 self.webview_renderers.get(webview_id)
353 }
354
355 pub(crate) fn set_needs_repaint(&self, reason: RepaintReason) {
356 let mut needs_repaint = self.needs_repaint.get();
357 needs_repaint.insert(reason);
358 self.needs_repaint.set(needs_repaint);
359 }
360
361 pub fn needs_repaint(&self) -> bool {
362 let repaint_reason = self.needs_repaint.get();
363 if repaint_reason.is_empty() {
364 return false;
365 }
366
367 !self
368 .global
369 .borrow()
370 .refresh_driver
371 .wait_to_paint(repaint_reason)
372 }
373
374 pub fn finish_shutting_down(&mut self) {
375 while self
378 .global
379 .borrow_mut()
380 .compositor_receiver
381 .try_recv()
382 .is_ok()
383 {}
384
385 if let Ok((sender, receiver)) = ipc::channel() {
387 self.global
388 .borrow()
389 .time_profiler_chan
390 .send(profile_time::ProfilerMsg::Exit(sender));
391 let _ = receiver.recv();
392 }
393 }
394
395 fn handle_browser_message(&mut self, msg: CompositorMsg) {
396 trace_msg_from_constellation!(msg, "{msg:?}");
397
398 match self.shutdown_state() {
399 ShutdownState::NotShuttingDown => {},
400 ShutdownState::ShuttingDown => {
401 self.handle_browser_message_while_shutting_down(msg);
402 return;
403 },
404 ShutdownState::FinishedShuttingDown => {
405 return;
407 },
408 }
409
410 match msg {
411 CompositorMsg::CollectMemoryReport(sender) => {
412 let ops =
413 wr_malloc_size_of::MallocSizeOfOps::new(servo_allocator::usable_size, None);
414 let report = self.global.borrow().webrender_api.report_memory(ops);
415 let mut reports = vec![
416 Report {
417 path: path!["webrender", "fonts"],
418 kind: ReportKind::ExplicitJemallocHeapSize,
419 size: report.fonts,
420 },
421 Report {
422 path: path!["webrender", "images"],
423 kind: ReportKind::ExplicitJemallocHeapSize,
424 size: report.images,
425 },
426 Report {
427 path: path!["webrender", "display-list"],
428 kind: ReportKind::ExplicitJemallocHeapSize,
429 size: report.display_list,
430 },
431 ];
432
433 perform_memory_report(|ops| {
434 reports.push(Report {
435 path: path!["compositor", "scroll-tree"],
436 kind: ReportKind::ExplicitJemallocHeapSize,
437 size: self.webview_renderers.scroll_trees_memory_usage(ops),
438 });
439 });
440
441 sender.send(ProcessReports::new(reports));
442 },
443
444 CompositorMsg::ChangeRunningAnimationsState(
445 webview_id,
446 pipeline_id,
447 animation_state,
448 ) => {
449 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
450 return;
451 };
452
453 if webview_renderer
454 .change_pipeline_running_animations_state(pipeline_id, animation_state)
455 {
456 self.global
457 .borrow()
458 .refresh_driver
459 .notify_animation_state_changed(webview_renderer);
460 }
461 },
462
463 CompositorMsg::CreateOrUpdateWebView(frame_tree) => {
464 self.set_frame_tree_for_webview(&frame_tree);
465 },
466
467 CompositorMsg::RemoveWebView(webview_id) => {
468 self.remove_webview(webview_id);
469 },
470
471 CompositorMsg::TouchEventProcessed(webview_id, result) => {
472 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
473 warn!("Handling input event for unknown webview: {webview_id}");
474 return;
475 };
476 webview_renderer.on_touch_event_processed(result);
477 },
478
479 CompositorMsg::SetThrottled(webview_id, pipeline_id, throttled) => {
480 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
481 return;
482 };
483
484 if webview_renderer.set_throttled(pipeline_id, throttled) {
485 self.global
486 .borrow()
487 .refresh_driver
488 .notify_animation_state_changed(webview_renderer);
489 }
490 },
491
492 CompositorMsg::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
493 debug!(
494 "Compositor got pipeline exited: {:?} {:?}",
495 webview_id, pipeline_id
496 );
497 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
498 webview_renderer.pipeline_exited(pipeline_id, pipeline_exit_source);
499 }
500 },
501
502 CompositorMsg::NewWebRenderFrameReady(..) => {
503 unreachable!("New WebRender frames should be handled in the caller.");
504 },
505
506 CompositorMsg::SendInitialTransaction(webview_id, pipeline_id) => {
507 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
508 return warn!("Could not find WebView for incoming display list");
509 };
510
511 let starting_epoch = Epoch(0);
512 let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
513 details.display_list_epoch = Some(starting_epoch);
514
515 let mut txn = Transaction::new();
516 txn.set_display_list(starting_epoch.into(), (pipeline_id, Default::default()));
517 self.generate_frame(&mut txn, RenderReasons::SCENE);
518 self.global.borrow_mut().send_transaction(txn);
519 },
520
521 CompositorMsg::SendScrollNode(webview_id, pipeline_id, offset, external_scroll_id) => {
522 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
523 return;
524 };
525
526 let pipeline_id = pipeline_id.into();
527 let Some(pipeline_details) = webview_renderer.pipelines.get_mut(&pipeline_id)
528 else {
529 return;
530 };
531
532 let Some(offset) = pipeline_details
533 .scroll_tree
534 .set_scroll_offset_for_node_with_external_scroll_id(
535 external_scroll_id,
536 offset,
537 ScrollType::Script,
538 )
539 else {
540 warn!("Could not scroll node with id: {external_scroll_id:?}");
543 return;
544 };
545
546 let mut txn = Transaction::new();
547 txn.set_scroll_offsets(
548 external_scroll_id,
549 vec![SampledScrollOffset {
550 offset,
551 generation: 0,
552 }],
553 );
554 self.generate_frame(&mut txn, RenderReasons::APZ);
555 self.global.borrow_mut().send_transaction(txn);
556 },
557
558 CompositorMsg::UpdateEpoch {
559 webview_id,
560 pipeline_id,
561 epoch,
562 } => {
563 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
564 return warn!("Could not find WebView for Epoch update.");
565 };
566 webview_renderer
567 .ensure_pipeline_details(pipeline_id)
568 .display_list_epoch = Some(Epoch(epoch.0));
569 },
570
571 CompositorMsg::SendDisplayList {
572 webview_id,
573 display_list_descriptor,
574 display_list_receiver,
575 } => {
576 let display_list_info = match display_list_receiver.recv() {
578 Ok(display_list_info) => display_list_info,
579 Err(error) => {
580 return warn!("Could not receive display list info: {error}");
581 },
582 };
583 let display_list_info: CompositorDisplayListInfo =
584 match bincode::deserialize(&display_list_info) {
585 Ok(display_list_info) => display_list_info,
586 Err(error) => {
587 return warn!("Could not deserialize display list info: {error}");
588 },
589 };
590 let items_data = match display_list_receiver.recv() {
591 Ok(display_list_data) => display_list_data,
592 Err(error) => {
593 return warn!(
594 "Could not receive WebRender display list items data: {error}"
595 );
596 },
597 };
598 let cache_data = match display_list_receiver.recv() {
599 Ok(display_list_data) => display_list_data,
600 Err(error) => {
601 return warn!(
602 "Could not receive WebRender display list cache data: {error}"
603 );
604 },
605 };
606 let spatial_tree = match display_list_receiver.recv() {
607 Ok(display_list_data) => display_list_data,
608 Err(error) => {
609 return warn!(
610 "Could not receive WebRender display list spatial tree: {error}."
611 );
612 },
613 };
614 let built_display_list = BuiltDisplayList::from_data(
615 DisplayListPayload {
616 items_data,
617 cache_data,
618 spatial_tree,
619 },
620 display_list_descriptor,
621 );
622
623 #[cfg(feature = "tracing")]
624 let _span = tracing::trace_span!(
625 "ScriptToCompositorMsg::BuiltDisplayList",
626 servo_profiling = true,
627 )
628 .entered();
629
630 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
631 return warn!("Could not find WebView for incoming display list");
632 };
633
634 let old_scale = webview_renderer.device_pixels_per_page_pixel();
635
636 let pipeline_id = display_list_info.pipeline_id;
637 let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
638 details.install_new_scroll_tree(display_list_info.scroll_tree);
639 details.viewport_scale =
640 Some(display_list_info.viewport_details.hidpi_scale_factor);
641
642 let epoch = display_list_info.epoch.into();
643 let first_reflow = display_list_info.first_reflow;
644 if details.first_paint_metric == PaintMetricState::Waiting {
645 details.first_paint_metric = PaintMetricState::Seen(epoch, first_reflow);
646 }
647 if details.first_contentful_paint_metric == PaintMetricState::Waiting &&
648 display_list_info.is_contentful
649 {
650 details.first_contentful_paint_metric =
651 PaintMetricState::Seen(epoch, first_reflow);
652 }
653
654 let mut transaction = Transaction::new();
655 let is_root_pipeline =
656 Some(pipeline_id.into()) == webview_renderer.root_pipeline_id;
657 if is_root_pipeline && old_scale != webview_renderer.device_pixels_per_page_pixel()
658 {
659 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
660 }
661
662 transaction.set_display_list(epoch, (pipeline_id, built_display_list));
663 self.update_transaction_with_all_scroll_offsets(&mut transaction);
664 self.global.borrow_mut().send_transaction(transaction);
665 },
666
667 CompositorMsg::GenerateFrame => {
668 let mut global = self.global.borrow_mut();
669 global.frame_delayer.set_pending_frame(true);
670
671 if !global.frame_delayer.needs_new_frame() {
672 return;
673 }
674
675 let mut transaction = Transaction::new();
676 self.generate_frame(&mut transaction, RenderReasons::SCENE);
677 global.send_transaction(transaction);
678
679 let waiting_pipelines = global.frame_delayer.take_waiting_pipelines();
680 let _ = global.constellation_sender.send(
681 EmbedderToConstellationMessage::NoLongerWaitingOnAsynchronousImageUpdates(
682 waiting_pipelines,
683 ),
684 );
685 global.frame_delayer.set_pending_frame(false);
686 self.screenshot_taker
687 .prepare_screenshot_requests_for_render(self)
688 },
689
690 CompositorMsg::GenerateImageKey(sender) => {
691 let _ = sender.send(self.global.borrow().webrender_api.generate_image_key());
692 },
693
694 CompositorMsg::GenerateImageKeysForPipeline(pipeline_id) => {
695 let image_keys = (0..pref!(image_key_batch_size))
696 .map(|_| self.global.borrow().webrender_api.generate_image_key())
697 .collect();
698 if let Err(error) = self.global.borrow().constellation_sender.send(
699 EmbedderToConstellationMessage::SendImageKeysForPipeline(
700 pipeline_id,
701 image_keys,
702 ),
703 ) {
704 warn!("Sending Image Keys to Constellation failed with({error:?}).");
705 }
706 },
707 CompositorMsg::UpdateImages(updates) => {
708 let mut global = self.global.borrow_mut();
709 let mut txn = Transaction::new();
710 for update in updates {
711 match update {
712 ImageUpdate::AddImage(key, desc, data) => {
713 txn.add_image(key, desc, data.into(), None)
714 },
715 ImageUpdate::DeleteImage(key) => {
716 txn.delete_image(key);
717 global.frame_delayer.delete_image(key);
718 },
719 ImageUpdate::UpdateImage(key, desc, data, epoch) => {
720 if let Some(epoch) = epoch {
721 global.frame_delayer.update_image(key, epoch);
722 }
723 txn.update_image(key, desc, data.into(), &DirtyRect::All)
724 },
725 }
726 }
727
728 if global.frame_delayer.needs_new_frame() {
729 global.frame_delayer.set_pending_frame(false);
730 self.generate_frame(&mut txn, RenderReasons::SCENE);
731 let waiting_pipelines = global.frame_delayer.take_waiting_pipelines();
732 let _ = global.constellation_sender.send(
733 EmbedderToConstellationMessage::NoLongerWaitingOnAsynchronousImageUpdates(
734 waiting_pipelines,
735 ),
736 );
737 self.screenshot_taker
738 .prepare_screenshot_requests_for_render(self);
739 }
740
741 global.send_transaction(txn);
742 },
743
744 CompositorMsg::DelayNewFrameForCanvas(pipeline_id, canvas_epoch, image_keys) => self
745 .global
746 .borrow_mut()
747 .frame_delayer
748 .add_delay(pipeline_id, canvas_epoch, image_keys),
749
750 CompositorMsg::AddFont(font_key, data, index) => {
751 self.add_font(font_key, index, data);
752 },
753
754 CompositorMsg::AddSystemFont(font_key, native_handle) => {
755 let mut transaction = Transaction::new();
756 transaction.add_native_font(font_key, native_handle);
757 self.global.borrow_mut().send_transaction(transaction);
758 },
759
760 CompositorMsg::AddFontInstance(
761 font_instance_key,
762 font_key,
763 size,
764 flags,
765 variations,
766 ) => {
767 self.add_font_instance(font_instance_key, font_key, size, flags, variations);
768 },
769
770 CompositorMsg::RemoveFonts(keys, instance_keys) => {
771 let mut transaction = Transaction::new();
772
773 for instance in instance_keys.into_iter() {
774 transaction.delete_font_instance(instance);
775 }
776 for key in keys.into_iter() {
777 transaction.delete_font(key);
778 }
779
780 self.global.borrow_mut().send_transaction(transaction);
781 },
782
783 CompositorMsg::GenerateFontKeys(
784 number_of_font_keys,
785 number_of_font_instance_keys,
786 result_sender,
787 rendering_group_id,
788 ) => {
789 self.handle_generate_font_keys(
790 number_of_font_keys,
791 number_of_font_instance_keys,
792 result_sender,
793 rendering_group_id,
794 );
795 },
796 CompositorMsg::Viewport(webview_id, viewport_description) => {
797 if let Some(webview) = self.webview_renderers.get_mut(webview_id) {
798 webview.set_viewport_description(viewport_description);
799 }
800 },
801 CompositorMsg::ScreenshotReadinessReponse(webview_id, pipelines_and_epochs) => {
802 self.screenshot_taker.handle_screenshot_readiness_reply(
803 webview_id,
804 pipelines_and_epochs,
805 self,
806 );
807 },
808 }
809 }
810
811 fn handle_browser_message_while_shutting_down(&mut self, msg: CompositorMsg) {
821 match msg {
822 CompositorMsg::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
823 debug!(
824 "Compositor got pipeline exited: {:?} {:?}",
825 webview_id, pipeline_id
826 );
827 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
828 webview_renderer.pipeline_exited(pipeline_id, pipeline_exit_source);
829 }
830 },
831 CompositorMsg::GenerateImageKey(sender) => {
832 let _ = sender.send(self.global.borrow().webrender_api.generate_image_key());
833 },
834 CompositorMsg::GenerateFontKeys(
835 number_of_font_keys,
836 number_of_font_instance_keys,
837 result_sender,
838 rendering_group_id,
839 ) => {
840 self.handle_generate_font_keys(
841 number_of_font_keys,
842 number_of_font_instance_keys,
843 result_sender,
844 rendering_group_id,
845 );
846 },
847 _ => {
848 debug!("Ignoring message ({:?} while shutting down", msg);
849 },
850 }
851 }
852
853 fn handle_generate_font_keys(
856 &self,
857 number_of_font_keys: usize,
858 number_of_font_instance_keys: usize,
859 result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
860 _rendering_group_id: RenderingGroupId,
861 ) {
862 let font_keys = (0..number_of_font_keys)
863 .map(|_| self.global.borrow().webrender_api.generate_font_key())
864 .collect();
865 let font_instance_keys = (0..number_of_font_instance_keys)
866 .map(|_| {
867 self.global
868 .borrow()
869 .webrender_api
870 .generate_font_instance_key()
871 })
872 .collect();
873 let _ = result_sender.send((font_keys, font_instance_keys));
874 }
875
876 pub(crate) fn generate_frame(&self, transaction: &mut Transaction, reason: RenderReasons) {
878 transaction.generate_frame(0, true , false , reason);
879 self.pending_frames.set(self.pending_frames.get() + 1);
880 }
881
882 fn send_root_pipeline_display_list(&mut self) {
886 let mut transaction = Transaction::new();
887 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
888 self.generate_frame(&mut transaction, RenderReasons::SCENE);
889 self.global.borrow_mut().send_transaction(transaction);
890 }
891
892 pub(crate) fn send_root_pipeline_display_list_in_transaction(
896 &self,
897 transaction: &mut Transaction,
898 ) {
899 let root_pipeline = WebRenderPipelineId(0, 1);
903 transaction.set_root_pipeline(root_pipeline);
904
905 let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline);
906 builder.begin();
907
908 let root_reference_frame = SpatialId::root_reference_frame(root_pipeline);
909
910 let viewport_size = self.rendering_context.size2d().to_f32().to_untyped();
911 let viewport_rect = LayoutRect::from_origin_and_size(
912 LayoutPoint::zero(),
913 LayoutSize::from_untyped(viewport_size),
914 );
915
916 let root_clip_id = builder.define_clip_rect(root_reference_frame, viewport_rect);
917 let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
918 for (_, webview_renderer) in self.webview_renderers.painting_order() {
919 let Some(pipeline_id) = webview_renderer.root_pipeline_id else {
920 continue;
921 };
922
923 let device_pixels_per_page_pixel = webview_renderer.device_pixels_per_page_pixel().0;
924 let webview_reference_frame = builder.push_reference_frame(
925 LayoutPoint::zero(),
926 root_reference_frame,
927 TransformStyle::Flat,
928 PropertyBinding::Value(Transform3D::scale(
929 device_pixels_per_page_pixel,
930 device_pixels_per_page_pixel,
931 1.,
932 )),
933 ReferenceFrameKind::Transform {
934 is_2d_scale_translation: true,
935 should_snap: true,
936 paired_with_perspective: false,
937 },
938 SpatialTreeItemKey::new(0, 0),
939 );
940
941 let scaled_webview_rect = webview_renderer.rect / device_pixels_per_page_pixel;
942 builder.push_iframe(
943 LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
944 LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
945 &SpaceAndClipInfo {
946 spatial_id: webview_reference_frame,
947 clip_chain_id,
948 },
949 pipeline_id.into(),
950 true,
951 );
952 }
953
954 let built_display_list = builder.end();
955
956 transaction.set_display_list(WebRenderEpoch(0), built_display_list);
960 self.update_transaction_with_all_scroll_offsets(transaction);
961 }
962
963 fn update_transaction_with_all_scroll_offsets(&self, transaction: &mut Transaction) {
972 for webview_renderer in self.webview_renderers.iter() {
973 for details in webview_renderer.pipelines.values() {
974 for node in details.scroll_tree.nodes.iter() {
975 let (Some(offset), Some(external_id)) = (node.offset(), node.external_id())
976 else {
977 continue;
978 };
979
980 transaction.set_scroll_offsets(
981 external_id,
982 vec![SampledScrollOffset {
983 offset,
984 generation: 0,
985 }],
986 );
987 }
988 }
989 }
990 }
991
992 pub fn add_webview(
993 &mut self,
994 webview: Box<dyn WebViewTrait>,
995 viewport_details: ViewportDetails,
996 ) {
997 self.webview_renderers
998 .entry(webview.id())
999 .or_insert(WebViewRenderer::new(
1000 self.global.clone(),
1001 webview,
1002 viewport_details,
1003 ));
1004 }
1005
1006 fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) {
1007 debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
1008
1009 let webview_id = frame_tree.pipeline.webview_id;
1010 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
1011 warn!(
1012 "Attempted to set frame tree on unknown WebView (perhaps closed?): {webview_id:?}"
1013 );
1014 return;
1015 };
1016
1017 webview_renderer.set_frame_tree(frame_tree);
1018 self.send_root_pipeline_display_list();
1019 }
1020
1021 fn remove_webview(&mut self, webview_id: WebViewId) {
1022 debug!("{}: Removing", webview_id);
1023 if self.webview_renderers.remove(webview_id).is_err() {
1024 warn!("{webview_id}: Removing unknown webview");
1025 return;
1026 };
1027
1028 self.send_root_pipeline_display_list();
1029 }
1030
1031 pub fn show_webview(
1032 &mut self,
1033 webview_id: WebViewId,
1034 hide_others: bool,
1035 ) -> Result<(), UnknownWebView> {
1036 debug!("{webview_id}: Showing webview; hide_others={hide_others}");
1037 let painting_order_changed = if hide_others {
1038 let result = self
1039 .webview_renderers
1040 .painting_order()
1041 .map(|(&id, _)| id)
1042 .ne(once(webview_id));
1043 self.webview_renderers.hide_all();
1044 self.webview_renderers.show(webview_id)?;
1045 result
1046 } else {
1047 self.webview_renderers.show(webview_id)?
1048 };
1049 if painting_order_changed {
1050 self.send_root_pipeline_display_list();
1051 }
1052 Ok(())
1053 }
1054
1055 pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
1056 debug!("{webview_id}: Hiding webview");
1057 if self.webview_renderers.hide(webview_id)? {
1058 self.send_root_pipeline_display_list();
1059 }
1060 Ok(())
1061 }
1062
1063 pub fn raise_webview_to_top(
1064 &mut self,
1065 webview_id: WebViewId,
1066 hide_others: bool,
1067 ) -> Result<(), UnknownWebView> {
1068 debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
1069 let painting_order_changed = if hide_others {
1070 let result = self
1071 .webview_renderers
1072 .painting_order()
1073 .map(|(&id, _)| id)
1074 .ne(once(webview_id));
1075 self.webview_renderers.hide_all();
1076 self.webview_renderers.raise_to_top(webview_id)?;
1077 result
1078 } else {
1079 self.webview_renderers.raise_to_top(webview_id)?
1080 };
1081 if painting_order_changed {
1082 self.send_root_pipeline_display_list();
1083 }
1084 Ok(())
1085 }
1086
1087 pub fn move_resize_webview(&mut self, webview_id: WebViewId, rect: DeviceRect) {
1088 if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
1089 return;
1090 }
1091 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
1092 return;
1093 };
1094 if !webview_renderer.set_rect(rect) {
1095 return;
1096 }
1097
1098 self.send_root_pipeline_display_list();
1099 self.set_needs_repaint(RepaintReason::Resize);
1100 }
1101
1102 pub fn set_hidpi_scale_factor(
1103 &mut self,
1104 webview_id: WebViewId,
1105 new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
1106 ) {
1107 if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
1108 return;
1109 }
1110 let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
1111 return;
1112 };
1113 if !webview_renderer.set_hidpi_scale_factor(new_scale_factor) {
1114 return;
1115 }
1116
1117 self.send_root_pipeline_display_list();
1118 self.set_needs_repaint(RepaintReason::Resize);
1119 }
1120
1121 pub fn resize_rendering_context(&mut self, new_size: PhysicalSize<u32>) {
1122 if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
1123 return;
1124 }
1125 if self.rendering_context.size() == new_size {
1126 return;
1127 }
1128
1129 self.rendering_context.resize(new_size);
1130
1131 let mut transaction = Transaction::new();
1132 let output_region = DeviceIntRect::new(
1133 Point2D::zero(),
1134 Point2D::new(new_size.width as i32, new_size.height as i32),
1135 );
1136 transaction.set_document_view(output_region);
1137 self.global.borrow_mut().send_transaction(transaction);
1138
1139 self.send_root_pipeline_display_list();
1140 self.set_needs_repaint(RepaintReason::Resize);
1141 }
1142
1143 pub fn on_zoom_window_event(&mut self, webview_id: WebViewId, new_zoom: f32) {
1144 if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
1145 return;
1146 }
1147
1148 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
1149 webview_renderer.set_page_zoom(Scale::new(new_zoom));
1150 }
1151 }
1152
1153 fn animation_callbacks_running(&self) -> bool {
1155 self.webview_renderers
1156 .iter()
1157 .any(WebViewRenderer::animation_callbacks_running)
1158 }
1159
1160 pub fn render(&mut self) {
1162 self.global
1163 .borrow()
1164 .refresh_driver
1165 .notify_will_paint(self.webview_renderers.iter());
1166
1167 self.render_inner();
1168
1169 self.needs_repaint.set(RepaintReason::empty());
1172 }
1173
1174 #[servo_tracing::instrument(skip_all)]
1175 fn render_inner(&mut self) {
1176 if let Err(err) = self.rendering_context.make_current() {
1177 warn!("Failed to make the rendering context current: {:?}", err);
1178 }
1179 self.assert_no_gl_error();
1180
1181 if let Some(webrender) = self.webrender.as_mut() {
1182 webrender.update();
1183 }
1184
1185 self.rendering_context.prepare_for_rendering();
1186
1187 let time_profiler_chan = self.global.borrow().time_profiler_chan.clone();
1188 time_profile!(
1189 ProfilerCategory::Compositing,
1190 None,
1191 time_profiler_chan,
1192 || {
1193 trace!("Compositing");
1194
1195 self.clear_background();
1198 if let Some(webrender) = self.webrender.as_mut() {
1199 let size = self.rendering_context.size2d().to_i32();
1200 webrender.render(size, 0 ).ok();
1201 }
1202 },
1203 );
1204
1205 self.send_pending_paint_metrics_messages_after_composite();
1206 self.screenshot_taker.maybe_take_screenshots(self);
1207 }
1208
1209 fn send_pending_paint_metrics_messages_after_composite(&mut self) {
1217 let paint_time = CrossProcessInstant::now();
1218 let document_id = self.webrender_document();
1219 for webview_renderer in self.webview_renderers.iter_mut() {
1220 for (pipeline_id, pipeline) in webview_renderer.pipelines.iter_mut() {
1221 let Some(current_epoch) = self
1222 .webrender
1223 .as_ref()
1224 .and_then(|wr| wr.current_epoch(document_id, pipeline_id.into()))
1225 else {
1226 continue;
1227 };
1228
1229 match pipeline.first_paint_metric {
1230 PaintMetricState::Seen(epoch, first_reflow) if epoch <= current_epoch => {
1235 assert!(epoch <= current_epoch);
1236 #[cfg(feature = "tracing")]
1237 tracing::info!(
1238 name: "FirstPaint",
1239 servo_profiling = true,
1240 epoch = ?epoch,
1241 paint_time = ?paint_time,
1242 pipeline_id = ?pipeline_id,
1243 );
1244 if let Err(error) = self.global.borrow().constellation_sender.send(
1245 EmbedderToConstellationMessage::PaintMetric(
1246 *pipeline_id,
1247 PaintMetricEvent::FirstPaint(paint_time, first_reflow),
1248 ),
1249 ) {
1250 warn!(
1251 "Sending paint metric event to constellation failed ({error:?})."
1252 );
1253 }
1254 pipeline.first_paint_metric = PaintMetricState::Sent;
1255 },
1256 _ => {},
1257 }
1258
1259 match pipeline.first_contentful_paint_metric {
1260 PaintMetricState::Seen(epoch, first_reflow) if epoch <= current_epoch => {
1261 #[cfg(feature = "tracing")]
1262 tracing::info!(
1263 name: "FirstContentfulPaint",
1264 servo_profiling = true,
1265 epoch = ?epoch,
1266 paint_time = ?paint_time,
1267 pipeline_id = ?pipeline_id,
1268 );
1269 if let Err(error) = self.global.borrow().constellation_sender.send(
1270 EmbedderToConstellationMessage::PaintMetric(
1271 *pipeline_id,
1272 PaintMetricEvent::FirstContentfulPaint(paint_time, first_reflow),
1273 ),
1274 ) {
1275 warn!(
1276 "Sending paint metric event to constellation failed ({error:?})."
1277 );
1278 }
1279 pipeline.first_contentful_paint_metric = PaintMetricState::Sent;
1280 },
1281 _ => {},
1282 }
1283 }
1284 }
1285 }
1286
1287 fn clear_background(&self) {
1288 let gl = &self.global.borrow().webrender_gl;
1289 self.assert_gl_framebuffer_complete();
1290
1291 let color = servo_config::pref!(shell_background_color_rgba);
1295 gl.clear_color(
1296 color[0] as f32,
1297 color[1] as f32,
1298 color[2] as f32,
1299 color[3] as f32,
1300 );
1301 gl.clear(gleam::gl::COLOR_BUFFER_BIT);
1302 }
1303
1304 #[track_caller]
1305 fn assert_no_gl_error(&self) {
1306 debug_assert_eq!(
1307 self.global.borrow().webrender_gl.get_error(),
1308 gleam::gl::NO_ERROR
1309 );
1310 }
1311
1312 #[track_caller]
1313 fn assert_gl_framebuffer_complete(&self) {
1314 debug_assert_eq!(
1315 (
1316 self.global.borrow().webrender_gl.get_error(),
1317 self.global
1318 .borrow()
1319 .webrender_gl
1320 .check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
1321 ),
1322 (gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
1323 );
1324 }
1325
1326 pub fn receiver(&self) -> Ref<'_, RoutedReceiver<CompositorMsg>> {
1328 Ref::map(self.global.borrow(), |global| &global.compositor_receiver)
1329 }
1330
1331 #[servo_tracing::instrument(skip_all)]
1332 pub fn handle_messages(&mut self, mut messages: Vec<CompositorMsg>) {
1333 let mut repaint_needed = false;
1338 let mut saw_webrender_frame_ready = false;
1339
1340 messages.retain(|message| match message {
1341 CompositorMsg::NewWebRenderFrameReady(_, need_repaint) => {
1342 self.pending_frames.set(self.pending_frames.get() - 1);
1343 repaint_needed |= need_repaint;
1344 saw_webrender_frame_ready = true;
1345
1346 false
1347 },
1348 _ => true,
1349 });
1350
1351 for message in messages {
1352 self.handle_browser_message(message);
1353 if self.global.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
1354 return;
1355 }
1356 }
1357
1358 if saw_webrender_frame_ready {
1359 self.handle_new_webrender_frame_ready(repaint_needed);
1360 }
1361 }
1362
1363 #[servo_tracing::instrument(skip_all)]
1364 pub fn perform_updates(&mut self) -> bool {
1365 if self.global.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
1366 return false;
1367 }
1368
1369 #[cfg(feature = "webxr")]
1370 self.global.borrow_mut().webxr_main_thread.run_one_frame();
1372
1373 if let Err(err) = self.rendering_context.make_current() {
1375 warn!("Failed to make the rendering context current: {:?}", err);
1376 }
1377
1378 let mut need_zoom = false;
1379 let scroll_offset_updates: Vec<_> = self
1380 .webview_renderers
1381 .iter_mut()
1382 .filter_map(|webview_renderer| {
1383 let (zoom, scroll_result) =
1384 webview_renderer.process_pending_scroll_and_pinch_zoom_events();
1385 need_zoom = need_zoom || (zoom == PinchZoomResult::DidPinchZoom);
1386 scroll_result
1387 })
1388 .collect();
1389
1390 if need_zoom || !scroll_offset_updates.is_empty() {
1391 let mut transaction = Transaction::new();
1392 if need_zoom {
1393 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
1394 }
1395 for update in scroll_offset_updates {
1396 transaction.set_scroll_offsets(
1397 update.external_scroll_id,
1398 vec![SampledScrollOffset {
1399 offset: update.offset,
1400 generation: 0,
1401 }],
1402 );
1403 }
1404
1405 self.generate_frame(&mut transaction, RenderReasons::APZ);
1406 self.global.borrow_mut().send_transaction(transaction);
1407 }
1408
1409 self.global.borrow().shutdown_state() != ShutdownState::FinishedShuttingDown
1410 }
1411
1412 pub fn toggle_webrender_debug(&mut self, option: WebRenderDebugOption) {
1413 let Some(webrender) = self.webrender.as_mut() else {
1414 return;
1415 };
1416 let mut flags = webrender.get_debug_flags();
1417 let flag = match option {
1418 WebRenderDebugOption::Profiler => {
1419 webrender::DebugFlags::PROFILER_DBG |
1420 webrender::DebugFlags::GPU_TIME_QUERIES |
1421 webrender::DebugFlags::GPU_SAMPLE_QUERIES
1422 },
1423 WebRenderDebugOption::TextureCacheDebug => webrender::DebugFlags::TEXTURE_CACHE_DBG,
1424 WebRenderDebugOption::RenderTargetDebug => webrender::DebugFlags::RENDER_TARGET_DBG,
1425 };
1426 flags.toggle(flag);
1427 webrender.set_debug_flags(flags);
1428
1429 let mut txn = Transaction::new();
1430 self.generate_frame(&mut txn, RenderReasons::TESTING);
1431 self.global.borrow_mut().send_transaction(txn);
1432 }
1433
1434 pub fn capture_webrender(&mut self) {
1435 let capture_id = SystemTime::now()
1436 .duration_since(UNIX_EPOCH)
1437 .unwrap_or_default()
1438 .as_secs()
1439 .to_string();
1440 let available_path = [env::current_dir(), Ok(env::temp_dir())]
1441 .iter()
1442 .filter_map(|val| {
1443 val.as_ref()
1444 .map(|dir| dir.join("webrender-captures").join(&capture_id))
1445 .ok()
1446 })
1447 .find(|val| create_dir_all(val).is_ok());
1448
1449 let Some(capture_path) = available_path else {
1450 eprintln!("Couldn't create a path for WebRender captures.");
1451 return;
1452 };
1453
1454 println!("Saving WebRender capture to {capture_path:?}");
1455 self.global
1456 .borrow()
1457 .webrender_api
1458 .save_capture(capture_path.clone(), CaptureBits::all());
1459 }
1460
1461 fn add_font_instance(
1462 &mut self,
1463 instance_key: FontInstanceKey,
1464 font_key: FontKey,
1465 size: f32,
1466 flags: FontInstanceFlags,
1467 variations: Vec<FontVariation>,
1468 ) {
1469 let variations = if pref!(layout_variable_fonts_enabled) {
1470 variations
1471 } else {
1472 vec![]
1473 };
1474
1475 let mut transaction = Transaction::new();
1476
1477 let font_instance_options = FontInstanceOptions {
1478 flags,
1479 ..Default::default()
1480 };
1481 transaction.add_font_instance(
1482 instance_key,
1483 font_key,
1484 size,
1485 Some(font_instance_options),
1486 None,
1487 variations,
1488 );
1489
1490 self.global.borrow_mut().send_transaction(transaction);
1491 }
1492
1493 fn add_font(&mut self, font_key: FontKey, index: u32, data: Arc<IpcSharedMemory>) {
1494 let mut transaction = Transaction::new();
1495 transaction.add_raw_font(font_key, (**data).into(), index);
1496 self.global.borrow_mut().send_transaction(transaction);
1497 }
1498
1499 pub fn notify_input_event(&mut self, webview_id: WebViewId, event: InputEventAndId) {
1500 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
1501 webview_renderer.notify_input_event(event);
1502 }
1503 }
1504
1505 pub fn notify_scroll_event(
1506 &mut self,
1507 webview_id: WebViewId,
1508 scroll_location: ScrollLocation,
1509 cursor: DeviceIntPoint,
1510 ) {
1511 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
1512 webview_renderer.notify_scroll_event(scroll_location, cursor);
1513 }
1514 }
1515
1516 pub fn on_vsync(&mut self, webview_id: WebViewId) {
1517 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
1518 webview_renderer.on_vsync();
1519 }
1520 }
1521
1522 pub fn set_pinch_zoom(&mut self, webview_id: WebViewId, magnification: f32) {
1523 if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
1524 webview_renderer.set_pinch_zoom(magnification);
1525 }
1526 }
1527
1528 pub fn device_pixels_per_page_pixel(
1529 &self,
1530 webview_id: WebViewId,
1531 ) -> Scale<f32, CSSPixel, DevicePixel> {
1532 self.webview_renderers
1533 .get(webview_id)
1534 .map(WebViewRenderer::device_pixels_per_page_pixel)
1535 .unwrap_or_default()
1536 }
1537
1538 fn webrender_document(&self) -> DocumentId {
1539 self.global.borrow().webrender_document
1540 }
1541
1542 fn shutdown_state(&self) -> ShutdownState {
1543 self.global.borrow().shutdown_state()
1544 }
1545
1546 fn refresh_cursor(&self) {
1547 let global = self.global.borrow();
1548 let Some(last_mouse_move_position) = global.last_mouse_move_position else {
1549 return;
1550 };
1551
1552 let Some(hit_test_result) = global
1553 .hit_test_at_point(last_mouse_move_position)
1554 .first()
1555 .cloned()
1556 else {
1557 return;
1558 };
1559
1560 if let Err(error) =
1561 global
1562 .constellation_sender
1563 .send(EmbedderToConstellationMessage::RefreshCursor(
1564 hit_test_result.pipeline_id,
1565 ))
1566 {
1567 warn!("Sending event to constellation failed ({:?}).", error);
1568 }
1569 }
1570
1571 fn handle_new_webrender_frame_ready(&mut self, repaint_needed: bool) {
1572 if repaint_needed {
1573 self.refresh_cursor();
1574 }
1575 if repaint_needed || self.animation_callbacks_running() {
1576 self.set_needs_repaint(RepaintReason::NewWebRenderFrame);
1577 }
1578
1579 if !repaint_needed {
1583 self.screenshot_taker
1584 .maybe_trigger_paint_for_screenshot(self);
1585 }
1586 }
1587
1588 pub(crate) fn has_pending_frames(&self) -> bool {
1592 self.pending_frames.get() != 0 || self.global.borrow().frame_delayer.pending_frame
1593 }
1594
1595 pub fn request_screenshot(
1596 &self,
1597 webview_id: WebViewId,
1598 rect: Option<DeviceRect>,
1599 callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
1600 ) {
1601 self.screenshot_taker
1602 .request_screenshot(webview_id, rect, callback);
1603 let _ = self.global.borrow().constellation_sender.send(
1604 EmbedderToConstellationMessage::RequestScreenshotReadiness(webview_id),
1605 );
1606 }
1607}
1608
1609#[derive(Default)]
1619struct FrameDelayer {
1620 image_epochs: FxHashMap<ImageKey, Epoch>,
1624 pending_canvas_images: FxHashMap<ImageKey, Epoch>,
1626 pending_frame: bool,
1628 waiting_pipelines: FxHashSet<PipelineId>,
1631}
1632
1633impl FrameDelayer {
1634 fn delete_image(&mut self, image_key: ImageKey) {
1635 self.image_epochs.remove(&image_key);
1636 self.pending_canvas_images.remove(&image_key);
1637 }
1638
1639 fn update_image(&mut self, image_key: ImageKey, epoch: Epoch) {
1640 self.image_epochs.insert(image_key, epoch);
1641 let Entry::Occupied(entry) = self.pending_canvas_images.entry(image_key) else {
1642 return;
1643 };
1644 if *entry.get() <= epoch {
1645 entry.remove();
1646 }
1647 }
1648
1649 fn add_delay(
1650 &mut self,
1651 pipeline_id: PipelineId,
1652 canvas_epoch: Epoch,
1653 image_keys: Vec<ImageKey>,
1654 ) {
1655 for image_key in image_keys.into_iter() {
1656 if self
1659 .image_epochs
1660 .get(&image_key)
1661 .is_some_and(|epoch_seen| *epoch_seen >= canvas_epoch)
1662 {
1663 continue;
1664 }
1665 self.pending_canvas_images.insert(image_key, canvas_epoch);
1666 }
1667 self.waiting_pipelines.insert(pipeline_id);
1668 }
1669
1670 fn needs_new_frame(&self) -> bool {
1671 self.pending_frame && self.pending_canvas_images.is_empty()
1672 }
1673
1674 fn set_pending_frame(&mut self, value: bool) {
1675 self.pending_frame = value;
1676 }
1677
1678 fn take_waiting_pipelines(&mut self) -> Vec<PipelineId> {
1679 self.waiting_pipelines.drain().collect()
1680 }
1681}