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