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