1use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::collections::HashMap;
7use std::env;
8use std::fs::create_dir_all;
9use std::rc::Rc;
10#[cfg(feature = "webgl")]
11use std::thread::JoinHandle;
12use std::time::{SystemTime, UNIX_EPOCH};
13
14use bitflags::bitflags;
15use crossbeam_channel::Sender;
16use dpi::PhysicalSize;
17use embedder_traits::{
18 EventLoopWaker, InputEventAndId, InputEventId, InputEventResult, ScreenshotCaptureError,
19 Scroll, ShutdownState, ViewportDetails, WebViewPoint, WebViewRect,
20};
21use euclid::{Scale, Size2D};
22use image::RgbaImage;
23use log::debug;
24#[cfg(feature = "webgl")]
25use log::warn;
26use paint_api::rendering_context::RenderingContext;
27use paint_api::{
28 PaintMessage, PaintProxy, PainterSurfmanDetails, PainterSurfmanDetailsMap,
29 WebRenderExternalImageIdManager, WebViewTrait,
30};
31use profile_traits::mem::{
32 ProcessReports, ProfilerRegistration, Report, ReportKind, perform_memory_report,
33};
34use profile_traits::path;
35use profile_traits::time::{self as profile_time};
36use servo_base::generic_channel::{self, GenericSender, RoutedReceiver};
37use servo_base::id::{PainterId, PipelineId, WebViewId};
38#[cfg(feature = "webgl")]
39use servo_canvas_traits::webgl::{WebGLContextId, WebGLThreads};
40use servo_config::pref;
41use servo_constellation_traits::EmbedderToConstellationMessage;
42use servo_geometry::DeviceIndependentPixel;
43use style_traits::CSSPixel;
44#[cfg(feature = "webgl")]
45use surfman::Device;
46#[cfg(feature = "webgl")]
47use surfman::chains::SwapChains;
48#[cfg(feature = "webgl")]
49use webgl::WebGLComm;
50#[cfg(feature = "webgl")]
51use webgl::webgl_thread::WebGLContextBusyMap;
52#[cfg(feature = "webgpu")]
53use webgpu::canvas_context::WebGpuExternalImageMap;
54use webrender::{CaptureBits, MemoryReport};
55use webrender_api::units::{DevicePixel, DevicePoint};
56use webrender_api::{FontInstanceKey, FontKey, ImageKey};
57#[cfg(feature = "webxr")]
58use webxr::WebXrRegistry;
59
60use crate::InitialPaintState;
61use crate::painter::Painter;
62use crate::webview_renderer::UnknownWebView;
63
64#[derive(Copy, Clone)]
66pub enum WebRenderDebugOption {
67 Profiler,
68 TextureCacheDebug,
69 RenderTargetDebug,
70}
71
72#[cfg(feature = "webgl")]
74pub struct WebGLPaint {
75 pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
79
80 webgl_threads: WebGLThreads,
82
83 webgl_join_handle: Cell<Option<JoinHandle<()>>>,
85
86 pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
88}
89
90#[cfg(feature = "webgl")]
91impl WebGLPaint {
92 fn shutdown(&self) {
93 self.webgl_threads.exit();
94 if let Some(webgl_join_handle) = self.webgl_join_handle.take() &&
95 webgl_join_handle.join().is_err()
96 {
97 warn!("Could not join WebGLThread.");
98 }
99 }
100}
101
102pub struct Paint {
124 painters: Vec<Rc<RefCell<Painter>>>,
127
128 pub(crate) paint_proxy: PaintProxy,
131
132 pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
135
136 shutdown_state: Rc<Cell<ShutdownState>>,
139
140 paint_receiver: RoutedReceiver<PaintMessage>,
142
143 pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
145
146 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
148
149 pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
152
153 #[cfg(feature = "webgl")]
154 pub(crate) webgl_paint: WebGLPaint,
156
157 time_profiler_chan: profile_time::ProfilerChan,
159
160 _mem_profiler_registration: ProfilerRegistration,
163
164 #[cfg(feature = "webxr")]
166 webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
167
168 #[cfg(feature = "webgpu")]
170 webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
171}
172
173#[derive(Clone, Copy, Default, PartialEq)]
175pub(crate) struct RepaintReason(u8);
176
177bitflags! {
178 impl RepaintReason: u8 {
179 const ReadyForScreenshot = 1 << 0;
181 const ChangedAnimationState = 1 << 1;
183 const NewWebRenderFrame = 1 << 2;
185 const Resize = 1 << 3;
187 const StartedFlinging = 1 << 4;
189 const BlinkingCaret = 1 << 5;
191 }
192}
193
194impl Paint {
195 pub fn new(state: InitialPaintState) -> Rc<RefCell<Self>> {
196 let registration = state.mem_profiler_chan.prepare_memory_reporting(
197 "paint".into(),
198 state.paint_proxy.clone(),
199 PaintMessage::CollectMemoryReport,
200 );
201
202 let webrender_external_image_id_manager = WebRenderExternalImageIdManager::default();
203 let painter_surfman_details_map = PainterSurfmanDetailsMap::default();
204 #[cfg(feature = "webgl")]
205 let WebGLComm {
206 webgl_threads,
207 swap_chains,
208 busy_webgl_context_map,
209 #[cfg(feature = "webxr")]
210 webxr_layer_grand_manager,
211 join_handle: webgl_join_handle,
212 } = WebGLComm::new(
213 state.paint_proxy.cross_process_paint_api.clone(),
214 webrender_external_image_id_manager.clone(),
215 painter_surfman_details_map.clone(),
216 );
217
218 #[cfg(feature = "webxr")]
220 let webxr_main_thread = webxr::MainThreadRegistry::new(
221 state.event_loop_waker.clone(),
222 webxr_layer_grand_manager,
223 )
224 .expect("Failed to create WebXR device registry");
225
226 #[cfg(feature = "webgl")]
227 let webgl_paint = WebGLPaint {
228 busy_webgl_contexts_map: busy_webgl_context_map,
229 webgl_threads,
230 webgl_join_handle: Cell::new(Some(webgl_join_handle)),
231 swap_chains,
232 };
233 Rc::new(RefCell::new(Paint {
234 painters: Default::default(),
235 paint_proxy: state.paint_proxy,
236 event_loop_waker: state.event_loop_waker,
237 shutdown_state: state.shutdown_state,
238 paint_receiver: state.receiver,
239 embedder_to_constellation_sender: state.embedder_to_constellation_sender.clone(),
240 webrender_external_image_id_manager,
241 #[cfg(feature = "webgl")]
242 webgl_paint,
243 time_profiler_chan: state.time_profiler_chan,
244 _mem_profiler_registration: registration,
245 painter_surfman_details_map,
246 #[cfg(feature = "webxr")]
247 webxr_main_thread: RefCell::new(webxr_main_thread),
248 #[cfg(feature = "webgpu")]
249 webgpu_image_map: Default::default(),
250 }))
251 }
252
253 #[cfg(feature = "webxr")]
254 pub fn register_webxr_registry(&self, registry: Box<dyn WebXrRegistry>) {
255 let mut webxr_main_thread = self.webxr_main_thread.borrow_mut();
256 registry.register(&mut webxr_main_thread)
257 }
258
259 pub fn register_rendering_context(
260 &mut self,
261 rendering_context: Rc<dyn RenderingContext>,
262 ) -> PainterId {
263 if let Some(painter_id) = self.painters.iter().find_map(|painter| {
264 let painter = painter.borrow();
265 if Rc::ptr_eq(&painter.rendering_context, &rendering_context) {
266 Some(painter.painter_id)
267 } else {
268 None
269 }
270 }) {
271 return painter_id;
272 }
273
274 let painter = Painter::new(rendering_context.clone(), self);
275 let connection = rendering_context
276 .connection()
277 .expect("Failed to get connection");
278 let adapter = connection
279 .create_adapter()
280 .expect("Failed to create adapter");
281
282 let painter_surfman_details = PainterSurfmanDetails {
283 connection,
284 adapter,
285 };
286 self.painter_surfman_details_map
287 .insert(painter.painter_id, painter_surfman_details);
288
289 let painter_id = painter.painter_id;
290 self.painters.push(Rc::new(RefCell::new(painter)));
291 painter_id
292 }
293
294 fn remove_painter(&mut self, painter_id: PainterId) {
295 self.painter_surfman_details_map.remove(painter_id);
298
299 #[cfg(feature = "webgl")]
300 if !self
301 .webgl_paint
302 .webgl_threads
303 .clear_painter_resources(painter_id)
304 {
305 warn!("Could not clear {painter_id:?} resources in WebGLThread");
306 }
307
308 self.painters
310 .retain(|painter| painter.borrow().painter_id != painter_id);
311 }
312
313 pub(crate) fn maybe_painter<'a>(&'a self, painter_id: PainterId) -> Option<Ref<'a, Painter>> {
314 self.painters
315 .iter()
316 .map(|painter| painter.borrow())
317 .find(|painter| painter.painter_id == painter_id)
318 }
319
320 pub(crate) fn painter<'a>(&'a self, painter_id: PainterId) -> Ref<'a, Painter> {
321 self.maybe_painter(painter_id)
322 .expect("painter_id not found")
323 }
324
325 pub(crate) fn maybe_painter_mut<'a>(
326 &'a self,
327 painter_id: PainterId,
328 ) -> Option<RefMut<'a, Painter>> {
329 self.painters
330 .iter()
331 .map(|painter| painter.borrow_mut())
332 .find(|painter| painter.painter_id == painter_id)
333 }
334
335 pub(crate) fn painter_mut<'a>(&'a self, painter_id: PainterId) -> RefMut<'a, Painter> {
336 self.maybe_painter_mut(painter_id)
337 .expect("painter_id not found")
338 }
339
340 pub fn painter_id(&self) -> PainterId {
341 self.painters[0].borrow().painter_id
342 }
343
344 pub fn rendering_context_size(&self, painter_id: PainterId) -> Size2D<u32, DevicePixel> {
345 self.painter(painter_id).rendering_context.size2d()
346 }
347
348 #[cfg(feature = "webgl")]
349 pub fn webgl_threads(&self) -> WebGLThreads {
350 self.webgl_paint.webgl_threads.clone()
351 }
352
353 pub fn webrender_external_image_id_manager(&self) -> WebRenderExternalImageIdManager {
354 self.webrender_external_image_id_manager.clone()
355 }
356
357 pub fn webxr_running(&self) -> bool {
358 #[cfg(feature = "webxr")]
359 {
360 self.webxr_main_thread.borrow().running()
361 }
362 #[cfg(not(feature = "webxr"))]
363 {
364 false
365 }
366 }
367
368 #[cfg(feature = "webxr")]
369 pub fn webxr_main_thread_registry(&self) -> webxr_api::Registry {
370 self.webxr_main_thread.borrow().registry()
371 }
372
373 #[cfg(feature = "webgpu")]
374 pub fn webgpu_image_map(&self) -> WebGpuExternalImageMap {
375 self.webgpu_image_map.get_or_init(Default::default).clone()
376 }
377
378 pub fn webviews_needing_repaint(&self) -> Vec<WebViewId> {
379 self.painters
380 .iter()
381 .flat_map(|painter| painter.borrow().webviews_needing_repaint())
382 .collect()
383 }
384
385 pub fn finish_shutting_down(&self) {
386 while self.paint_receiver.try_recv().is_ok() {}
389
390 #[cfg(feature = "webgl")]
391 self.webgl_paint.shutdown();
392
393 if let Some((sender, receiver)) = generic_channel::channel() {
395 self.time_profiler_chan
396 .send(profile_time::ProfilerMsg::Exit(sender));
397 let _ = receiver.recv();
398 }
399 }
400
401 fn handle_browser_message(&self, msg: PaintMessage) {
402 trace_msg_from_constellation!(msg, "{msg:?}");
403
404 match self.shutdown_state() {
405 ShutdownState::NotShuttingDown => {},
406 ShutdownState::ShuttingDown => {
407 self.handle_browser_message_while_shutting_down(msg);
408 return;
409 },
410 ShutdownState::FinishedShuttingDown => {
411 return;
413 },
414 }
415
416 match msg {
417 PaintMessage::CollectMemoryReport(sender) => {
418 self.collect_memory_report(sender);
419 },
420 PaintMessage::ChangeRunningAnimationsState(
421 webview_id,
422 pipeline_id,
423 animation_state,
424 ) => {
425 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
426 painter.change_running_animations_state(
427 webview_id,
428 pipeline_id,
429 animation_state,
430 );
431 }
432 },
433 PaintMessage::SetFrameTreeForWebView(webview_id, frame_tree) => {
434 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
435 painter.set_frame_tree_for_webview(&frame_tree);
436 }
437 },
438 PaintMessage::SetThrottled(webview_id, pipeline_id, throttled) => {
439 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
440 painter.set_throttled(webview_id, pipeline_id, throttled);
441 }
442 },
443 PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
444 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
445 painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
446 }
447 },
448 PaintMessage::NewWebRenderFrameReady(..) => {
449 unreachable!("New WebRender frames should be handled in the caller.");
450 },
451 PaintMessage::SendInitialTransaction(webview_id, pipeline_id) => {
452 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
453 painter.send_initial_pipeline_transaction(webview_id, pipeline_id);
454 }
455 },
456 PaintMessage::ScrollNodeByDelta(
457 webview_id,
458 pipeline_id,
459 offset,
460 external_scroll_id,
461 ) => {
462 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
463 painter.scroll_node_by_delta(
464 webview_id,
465 pipeline_id,
466 offset,
467 external_scroll_id,
468 );
469 }
470 },
471 PaintMessage::ScrollViewportByDelta(webview_id, delta) => {
472 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
473 painter.scroll_viewport_by_delta(webview_id, delta);
474 }
475 },
476 PaintMessage::UpdateEpoch {
477 webview_id,
478 pipeline_id,
479 epoch,
480 } => {
481 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
482 painter.update_epoch(webview_id, pipeline_id, epoch);
483 }
484 },
485 PaintMessage::SendDisplayList {
486 webview_id,
487 display_list_descriptor,
488 display_list_info_receiver,
489 display_list_data_receiver,
490 } => {
491 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
492 painter.handle_new_display_list(
493 webview_id,
494 display_list_descriptor,
495 display_list_info_receiver,
496 display_list_data_receiver,
497 );
498 }
499 },
500 PaintMessage::GenerateFrame(painter_ids) => {
501 for painter_id in painter_ids {
502 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
503 painter.generate_frame_for_script();
504 }
505 }
506 },
507 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
508 self.handle_generate_image_key(webview_id, result_sender);
509 },
510 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
511 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
512 },
513 PaintMessage::UpdateImages(painter_id, updates) => {
514 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
515 painter.update_images(updates);
516 }
517 },
518 PaintMessage::DelayNewFrameForCanvas(
519 webview_id,
520 pipeline_id,
521 canvas_epoch,
522 image_keys,
523 ) => {
524 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
525 painter.delay_new_frames_for_canvas(pipeline_id, canvas_epoch, image_keys);
526 }
527 },
528 PaintMessage::AddFont(painter_id, font_key, data, index) => {
529 debug_assert!(painter_id == font_key.into());
530
531 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
532 painter.add_font(font_key, data, index);
533 }
534 },
535 PaintMessage::AddSystemFont(painter_id, font_key, native_handle) => {
536 debug_assert!(painter_id == font_key.into());
537
538 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
539 painter.add_system_font(font_key, native_handle);
540 }
541 },
542 PaintMessage::AddFontInstance(
543 painter_id,
544 font_instance_key,
545 font_key,
546 size,
547 flags,
548 variations,
549 ) => {
550 debug_assert!(painter_id == font_key.into());
551 debug_assert!(painter_id == font_instance_key.into());
552
553 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
554 painter.add_font_instance(font_instance_key, font_key, size, flags, variations);
555 }
556 },
557 PaintMessage::RemoveFonts(painter_id, keys, instance_keys) => {
558 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
559 painter.remove_fonts(keys, instance_keys);
560 }
561 },
562 PaintMessage::GenerateFontKeys(
563 number_of_font_keys,
564 number_of_font_instance_keys,
565 result_sender,
566 painter_id,
567 ) => {
568 self.handle_generate_font_keys(
569 number_of_font_keys,
570 number_of_font_instance_keys,
571 result_sender,
572 painter_id,
573 );
574 },
575 PaintMessage::Viewport(webview_id, viewport_description) => {
576 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
577 painter.set_viewport_description(webview_id, viewport_description);
578 }
579 },
580 PaintMessage::ScreenshotReadinessReponse(webview_id, pipelines_and_epochs) => {
581 if let Some(painter) = self.maybe_painter(webview_id.into()) {
582 painter.handle_screenshot_readiness_reply(webview_id, pipelines_and_epochs);
583 }
584 },
585 PaintMessage::SendLCPCandidate(lcp_candidate, webview_id, pipeline_id, epoch) => {
586 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
587 painter.append_lcp_candidate(lcp_candidate, webview_id, pipeline_id, epoch);
588 }
589 },
590 }
591 }
592
593 pub fn remove_webview(&mut self, webview_id: WebViewId) {
594 let painter_id = webview_id.into();
595
596 {
597 let mut painter = self.painter_mut(painter_id);
598 painter.remove_webview(webview_id);
599 if !painter.is_empty() {
600 return;
601 }
602 }
603
604 self.remove_painter(painter_id);
605 }
606
607 fn collect_memory_report(&self, sender: profile_traits::mem::ReportsChan) {
608 let mut memory_report = MemoryReport::default();
609 for painter in &self.painters {
610 memory_report += painter.borrow().report_memory();
611 }
612
613 let mut reports = vec![
614 Report {
615 path: path!["webrender", "fonts"],
616 kind: ReportKind::ExplicitJemallocHeapSize,
617 size: memory_report.fonts,
618 },
619 Report {
620 path: path!["webrender", "images"],
621 kind: ReportKind::ExplicitJemallocHeapSize,
622 size: memory_report.images,
623 },
624 Report {
625 path: path!["webrender", "display-list"],
626 kind: ReportKind::ExplicitJemallocHeapSize,
627 size: memory_report.display_list,
628 },
629 ];
630
631 perform_memory_report(|ops| {
632 let scroll_trees_memory_usage = self
633 .painters
634 .iter()
635 .map(|painter| painter.borrow().scroll_trees_memory_usage(ops))
636 .sum();
637 reports.push(Report {
638 path: path!["paint", "scroll-tree"],
639 kind: ReportKind::ExplicitJemallocHeapSize,
640 size: scroll_trees_memory_usage,
641 });
642 });
643
644 sender.send(ProcessReports::new(reports));
645 }
646
647 fn handle_browser_message_while_shutting_down(&self, msg: PaintMessage) {
657 match msg {
658 PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
659 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
660 painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
661 }
662 },
663 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
664 self.handle_generate_image_key(webview_id, result_sender);
665 },
666 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
667 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
668 },
669 PaintMessage::GenerateFontKeys(
670 number_of_font_keys,
671 number_of_font_instance_keys,
672 result_sender,
673 painter_id,
674 ) => {
675 self.handle_generate_font_keys(
676 number_of_font_keys,
677 number_of_font_instance_keys,
678 result_sender,
679 painter_id,
680 );
681 },
682 _ => {
683 debug!("Ignoring message ({:?} while shutting down", msg);
684 },
685 }
686 }
687
688 pub fn add_webview(&self, webview: Box<dyn WebViewTrait>, viewport_details: ViewportDetails) {
689 self.painter_mut(webview.id().into())
690 .add_webview(webview, viewport_details);
691 }
692
693 pub fn show_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
694 self.painter_mut(webview_id.into())
695 .set_webview_hidden(webview_id, false)
696 }
697
698 pub fn hide_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
699 self.painter_mut(webview_id.into())
700 .set_webview_hidden(webview_id, true)
701 }
702
703 pub fn set_hidpi_scale_factor(
704 &self,
705 webview_id: WebViewId,
706 new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
707 ) {
708 if self.shutdown_state() != ShutdownState::NotShuttingDown {
709 return;
710 }
711 self.painter_mut(webview_id.into())
712 .set_hidpi_scale_factor(webview_id, new_scale_factor);
713 }
714
715 pub fn resize_rendering_context(&self, webview_id: WebViewId, new_size: PhysicalSize<u32>) {
716 if self.shutdown_state() != ShutdownState::NotShuttingDown {
717 return;
718 }
719 self.painter_mut(webview_id.into())
720 .resize_rendering_context(new_size);
721 }
722
723 pub fn set_screen_size(&self, webview_id: WebViewId, new_size: Size2D<f32, DevicePixel>) {
724 if self.shutdown_state() != ShutdownState::NotShuttingDown {
725 return;
726 }
727 self.painter_mut(webview_id.into())
728 .set_screen_size(webview_id, new_size);
729 }
730
731 pub fn set_page_zoom(&self, webview_id: WebViewId, new_zoom: f32) {
732 if self.shutdown_state() != ShutdownState::NotShuttingDown {
733 return;
734 }
735 self.painter_mut(webview_id.into())
736 .set_page_zoom(webview_id, new_zoom);
737 }
738
739 pub fn page_zoom(&self, webview_id: WebViewId) -> f32 {
740 self.painter(webview_id.into()).page_zoom(webview_id)
741 }
742
743 pub fn render(&self, webview_id: WebViewId) {
745 self.painter_mut(webview_id.into())
746 .render(&self.time_profiler_chan);
747 }
748
749 pub fn receiver(&self) -> &RoutedReceiver<PaintMessage> {
751 &self.paint_receiver
752 }
753
754 #[servo_tracing::instrument(skip_all)]
755 pub fn handle_messages(&self, mut messages: Vec<PaintMessage>) {
756 let mut saw_webrender_frame_ready_for_painter = HashMap::new();
761 messages.retain(|message| match message {
762 PaintMessage::NewWebRenderFrameReady(painter_id, _document_id, need_repaint) => {
763 if let Some(painter) = self.maybe_painter(*painter_id) {
764 painter.decrement_pending_frames();
765 *saw_webrender_frame_ready_for_painter
766 .entry(*painter_id)
767 .or_insert(*need_repaint) |= *need_repaint;
768 }
769
770 false
771 },
772 _ => true,
773 });
774
775 for message in messages {
776 self.handle_browser_message(message);
777 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
778 return;
779 }
780 }
781
782 for (painter_id, repaint_needed) in saw_webrender_frame_ready_for_painter.iter() {
783 if let Some(painter) = self.maybe_painter(*painter_id) {
784 painter.handle_new_webrender_frame_ready(*repaint_needed);
785 }
786 }
787 }
788
789 #[servo_tracing::instrument(skip_all)]
790 pub fn perform_updates(&self) -> bool {
791 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
792 return false;
793 }
794
795 #[cfg(feature = "webxr")]
797 self.webxr_main_thread.borrow_mut().run_one_frame();
798
799 for painter in &self.painters {
800 painter.borrow_mut().perform_updates();
801 }
802
803 self.shutdown_state() != ShutdownState::FinishedShuttingDown
804 }
805
806 pub fn toggle_webrender_debug(&self, option: WebRenderDebugOption) {
807 for painter in &self.painters {
808 painter.borrow_mut().toggle_webrender_debug(option);
809 }
810 }
811
812 pub fn capture_webrender(&self, webview_id: WebViewId) {
813 let capture_id = SystemTime::now()
814 .duration_since(UNIX_EPOCH)
815 .unwrap_or_default()
816 .as_secs()
817 .to_string();
818 let available_path = [env::current_dir(), Ok(env::temp_dir())]
819 .iter()
820 .filter_map(|val| {
821 val.as_ref()
822 .map(|dir| dir.join("webrender-captures").join(&capture_id))
823 .ok()
824 })
825 .find(|val| create_dir_all(val).is_ok());
826
827 let Some(capture_path) = available_path else {
828 log::error!("Couldn't create a path for WebRender captures.");
829 return;
830 };
831
832 log::info!("Saving WebRender capture to {capture_path:?}");
833 self.painter(webview_id.into())
834 .webrender_api
835 .save_capture(capture_path, CaptureBits::all());
836 }
837
838 pub fn notify_input_event(&self, webview_id: WebViewId, event: InputEventAndId) -> bool {
841 if self.shutdown_state() != ShutdownState::NotShuttingDown {
842 return false;
843 }
844 self.painter_mut(webview_id.into())
845 .notify_input_event(webview_id, event)
846 }
847
848 pub fn notify_scroll_event(&self, webview_id: WebViewId, scroll: Scroll, point: WebViewPoint) {
849 if self.shutdown_state() != ShutdownState::NotShuttingDown {
850 return;
851 }
852 self.painter_mut(webview_id.into())
853 .notify_scroll_event(webview_id, scroll, point);
854 }
855
856 pub fn adjust_pinch_zoom(
857 &self,
858 webview_id: WebViewId,
859 pinch_zoom_delta: f32,
860 center: DevicePoint,
861 ) {
862 if self.shutdown_state() != ShutdownState::NotShuttingDown {
863 return;
864 }
865 self.painter_mut(webview_id.into())
866 .adjust_pinch_zoom(webview_id, pinch_zoom_delta, center);
867 }
868
869 pub fn pinch_zoom(&self, webview_id: WebViewId) -> f32 {
870 self.painter(webview_id.into()).pinch_zoom(webview_id)
871 }
872
873 pub fn device_pixels_per_page_pixel(
874 &self,
875 webview_id: WebViewId,
876 ) -> Scale<f32, CSSPixel, DevicePixel> {
877 self.painter_mut(webview_id.into())
878 .device_pixels_per_page_pixel(webview_id)
879 }
880
881 pub(crate) fn shutdown_state(&self) -> ShutdownState {
882 self.shutdown_state.get()
883 }
884
885 pub fn request_screenshot(
886 &self,
887 webview_id: WebViewId,
888 rect: Option<WebViewRect>,
889 callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
890 ) {
891 self.painter(webview_id.into())
892 .request_screenshot(webview_id, rect, callback);
893 }
894
895 pub fn notify_input_event_handled(
896 &self,
897 webview_id: WebViewId,
898 input_event_id: InputEventId,
899 result: InputEventResult,
900 ) {
901 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
902 painter.notify_input_event_handled(webview_id, input_event_id, result);
903 }
904 }
905
906 fn handle_generate_image_key(
911 &self,
912 webview_id: WebViewId,
913 result_sender: GenericSender<ImageKey>,
914 ) {
915 let painter_id = webview_id.into();
916 let image_key = self.maybe_painter(painter_id).map_or_else(
917 || ImageKey::new(painter_id.into(), 0),
918 |painter| painter.webrender_api.generate_image_key(),
919 );
920 let _ = result_sender.send(image_key);
921 }
922
923 fn handle_generate_image_keys_for_pipeline(
928 &self,
929 webview_id: WebViewId,
930 pipeline_id: PipelineId,
931 ) {
932 let painter_id = webview_id.into();
933 let painter = self.maybe_painter(painter_id);
934 let image_keys = (0..pref!(image_key_batch_size))
935 .map(|_| {
936 painter.as_ref().map_or_else(
937 || ImageKey::new(painter_id.into(), 0),
938 |painter| painter.webrender_api.generate_image_key(),
939 )
940 })
941 .collect();
942
943 let _ = self.embedder_to_constellation_sender.send(
944 EmbedderToConstellationMessage::SendImageKeysForPipeline(pipeline_id, image_keys),
945 );
946 }
947
948 fn handle_generate_font_keys(
953 &self,
954 number_of_font_keys: usize,
955 number_of_font_instance_keys: usize,
956 result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
957 painter_id: PainterId,
958 ) {
959 let painter = self.maybe_painter(painter_id);
960 let font_keys = (0..number_of_font_keys)
961 .map(|_| {
962 painter.as_ref().map_or_else(
963 || FontKey::new(painter_id.into(), 0),
964 |painter| painter.webrender_api.generate_font_key(),
965 )
966 })
967 .collect();
968 let font_instance_keys = (0..number_of_font_instance_keys)
969 .map(|_| {
970 painter.as_ref().map_or_else(
971 || FontInstanceKey::new(painter_id.into(), 0),
972 |painter| painter.webrender_api.generate_font_instance_key(),
973 )
974 })
975 .collect();
976
977 let _ = result_sender.send((font_keys, font_instance_keys));
978 }
979}