Skip to main content

paint/
paint.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::collections::HashMap;
7use std::env;
8use std::fs::create_dir_all;
9use std::rc::Rc;
10use std::thread::JoinHandle;
11use std::time::{SystemTime, UNIX_EPOCH};
12
13use bitflags::bitflags;
14use crossbeam_channel::Sender;
15use dpi::PhysicalSize;
16use embedder_traits::{
17    EventLoopWaker, InputEventAndId, InputEventId, InputEventResult, ScreenshotCaptureError,
18    Scroll, ShutdownState, ViewportDetails, WebViewPoint, WebViewRect,
19};
20use euclid::{Scale, Size2D};
21use image::RgbaImage;
22use log::{debug, warn};
23use paint_api::rendering_context::RenderingContext;
24use paint_api::{
25    PaintMessage, PaintProxy, PainterSurfmanDetails, PainterSurfmanDetailsMap,
26    WebRenderExternalImageIdManager, WebViewTrait,
27};
28use profile_traits::mem::{
29    ProcessReports, ProfilerRegistration, Report, ReportKind, perform_memory_report,
30};
31use profile_traits::path;
32use profile_traits::time::{self as profile_time};
33use servo_base::generic_channel::{self, GenericSender, RoutedReceiver};
34use servo_base::id::{PainterId, PipelineId, WebViewId};
35use servo_canvas_traits::webgl::{WebGLContextId, WebGLThreads};
36use servo_config::pref;
37use servo_constellation_traits::EmbedderToConstellationMessage;
38use servo_geometry::DeviceIndependentPixel;
39use style_traits::CSSPixel;
40use surfman::Device;
41use surfman::chains::SwapChains;
42use webgl::WebGLComm;
43use webgl::webgl_thread::WebGLContextBusyMap;
44#[cfg(feature = "webgpu")]
45use webgpu::canvas_context::WebGpuExternalImageMap;
46use webrender::{CaptureBits, MemoryReport};
47use webrender_api::units::{DevicePixel, DevicePoint};
48use webrender_api::{FontInstanceKey, FontKey, ImageKey};
49#[cfg(feature = "webxr")]
50use webxr::WebXrRegistry;
51
52use crate::InitialPaintState;
53use crate::painter::Painter;
54use crate::webview_renderer::UnknownWebView;
55
56/// An option to control what kind of WebRender debugging is enabled while Servo is running.
57#[derive(Copy, Clone)]
58pub enum WebRenderDebugOption {
59    Profiler,
60    TextureCacheDebug,
61    RenderTargetDebug,
62}
63
64/// [`Paint`] is Servo's rendering subsystem. It has a few responsibilities:
65///
66/// 1. Maintain a WebRender instance for each [`RenderingContext`] that Servo knows about.
67///    [`RenderingContext`]s are per-`WebView`, but more than one `WebView` can use the same
68///    [`RenderingContext`]. This allows multiple `WebView`s to share the same WebRender
69///    instance which is more efficient. This is useful for tabbed web browsers.
70/// 2. Receive display lists from the layout of all of the currently active `Pipeline`s
71///    (frames). These display lists are sent to WebRender, and new frames are generated.
72///    Once the frame is ready the [`Painter`] for the WebRender instance will ask libservo
73///    to inform the embedder that a new frame is ready so that it can trigger a paint.
74/// 3. Drive animation and animation callback updates. Animation updates should ideally be
75///    coordinated with the system vsync signal, so the `RefreshDriver` is exposed in the
76///    API to allow the embedder to do this. The [`Painter`] then asks its `WebView`s to
77///    update their rendering, which triggers layouts.
78/// 4. Eagerly handle scrolling and touch events. In order to avoid latency when handling
79///    these kind of actions, each [`Painter`] will eagerly process touch events and
80///    perform panning and zooming operations on their WebRender contents -- informing the
81///    WebView contents asynchronously.
82///
83/// `Paint` and all of its contained structs should **never** block on the Constellation,
84/// because sometimes the Constellation blocks on us.
85pub struct Paint {
86    /// All of the [`Painters`] for this [`Paint`]. Each [`Painter`] handles painting to
87    /// a single [`RenderingContext`].
88    painters: Vec<Rc<RefCell<Painter>>>,
89
90    /// A [`PaintProxy`] which can be used to allow other parts of Servo to communicate
91    /// with this [`Paint`].
92    pub(crate) paint_proxy: PaintProxy,
93
94    /// An [`EventLoopWaker`] used to wake up the main embedder event loop when the renderer needs
95    /// to run.
96    pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
97
98    /// Tracks whether we are in the process of shutting down, or have shut down and
99    /// should shut down `Paint`. This is shared with the `Servo` instance.
100    shutdown_state: Rc<Cell<ShutdownState>>,
101
102    /// The port on which we receive messages.
103    paint_receiver: RoutedReceiver<PaintMessage>,
104
105    /// The channel on which messages can be sent to the constellation.
106    pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
107
108    /// The [`WebRenderExternalImageIdManager`] used to generate new `ExternalImageId`s.
109    webrender_external_image_id_manager: WebRenderExternalImageIdManager,
110
111    /// A [`HashMap`] of [`PainterId`] to the Surfaman types (`Device`, `Adapter`) that
112    /// are specific to a particular [`Painter`].
113    pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
114
115    /// A [`HashMap`] of `WebGLContextId` to a usage count. This count indicates when
116    /// WebRender is still rendering the context. This is used to ensure properly clean
117    /// up of all Surfman `Surface`s.
118    pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
119
120    /// The [`WebGLThreads`] for this renderer.
121    webgl_threads: WebGLThreads,
122
123    /// A [`JoinHandle`] for joining the WebGL thread once the exit message is sent.
124    webgl_join_handle: Cell<Option<JoinHandle<()>>>,
125
126    /// The shared [`SwapChains`] used by [`WebGLThreads`] for this renderer.
127    pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
128
129    /// The channel on which messages can be sent to the time profiler.
130    time_profiler_chan: profile_time::ProfilerChan,
131
132    /// A handle to the memory profiler which will automatically unregister
133    /// when it's dropped.
134    _mem_profiler_registration: ProfilerRegistration,
135
136    /// Some XR devices want to run on the main thread.
137    #[cfg(feature = "webxr")]
138    webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
139
140    /// An map of external images shared between all `WebGpuExternalImages`.
141    #[cfg(feature = "webgpu")]
142    webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
143}
144
145/// Why we need to be repainted. This is used for debugging.
146#[derive(Clone, Copy, Default, PartialEq)]
147pub(crate) struct RepaintReason(u8);
148
149bitflags! {
150    impl RepaintReason: u8 {
151        /// We're performing the single repaint in headless mode.
152        const ReadyForScreenshot = 1 << 0;
153        /// We're performing a repaint to run an animation.
154        const ChangedAnimationState = 1 << 1;
155        /// A new WebRender frame has arrived.
156        const NewWebRenderFrame = 1 << 2;
157        /// The window has been resized and will need to be synchronously repainted.
158        const Resize = 1 << 3;
159        /// A fling has started and a repaint needs to happen to process the animation.
160        const StartedFlinging = 1 << 4;
161        /// A blinking text caret requires a redraw.
162        const BlinkingCaret = 1 << 5;
163    }
164}
165
166impl Paint {
167    pub fn new(state: InitialPaintState) -> Rc<RefCell<Self>> {
168        let registration = state.mem_profiler_chan.prepare_memory_reporting(
169            "paint".into(),
170            state.paint_proxy.clone(),
171            PaintMessage::CollectMemoryReport,
172        );
173
174        let webrender_external_image_id_manager = WebRenderExternalImageIdManager::default();
175        let painter_surfman_details_map = PainterSurfmanDetailsMap::default();
176        let WebGLComm {
177            webgl_threads,
178            swap_chains,
179            busy_webgl_context_map,
180            #[cfg(feature = "webxr")]
181            webxr_layer_grand_manager,
182            join_handle: webgl_join_handle,
183        } = WebGLComm::new(
184            state.paint_proxy.cross_process_paint_api.clone(),
185            webrender_external_image_id_manager.clone(),
186            painter_surfman_details_map.clone(),
187        );
188
189        // Create the WebXR main thread
190        #[cfg(feature = "webxr")]
191        let webxr_main_thread = webxr::MainThreadRegistry::new(
192            state.event_loop_waker.clone(),
193            webxr_layer_grand_manager,
194        )
195        .expect("Failed to create WebXR device registry");
196
197        Rc::new(RefCell::new(Paint {
198            painters: Default::default(),
199            paint_proxy: state.paint_proxy,
200            event_loop_waker: state.event_loop_waker,
201            shutdown_state: state.shutdown_state,
202            paint_receiver: state.receiver,
203            embedder_to_constellation_sender: state.embedder_to_constellation_sender.clone(),
204            webrender_external_image_id_manager,
205            webgl_threads,
206            webgl_join_handle: Cell::new(Some(webgl_join_handle)),
207            swap_chains,
208            time_profiler_chan: state.time_profiler_chan,
209            _mem_profiler_registration: registration,
210            painter_surfman_details_map,
211            busy_webgl_contexts_map: busy_webgl_context_map,
212            #[cfg(feature = "webxr")]
213            webxr_main_thread: RefCell::new(webxr_main_thread),
214            #[cfg(feature = "webgpu")]
215            webgpu_image_map: Default::default(),
216        }))
217    }
218
219    #[cfg(feature = "webxr")]
220    pub fn register_webxr_registry(&self, registry: Box<dyn WebXrRegistry>) {
221        let mut webxr_main_thread = self.webxr_main_thread.borrow_mut();
222        registry.register(&mut webxr_main_thread)
223    }
224
225    pub fn register_rendering_context(
226        &mut self,
227        rendering_context: Rc<dyn RenderingContext>,
228    ) -> PainterId {
229        if let Some(painter_id) = self.painters.iter().find_map(|painter| {
230            let painter = painter.borrow();
231            if Rc::ptr_eq(&painter.rendering_context, &rendering_context) {
232                Some(painter.painter_id)
233            } else {
234                None
235            }
236        }) {
237            return painter_id;
238        }
239
240        let painter = Painter::new(rendering_context.clone(), self);
241        let connection = rendering_context
242            .connection()
243            .expect("Failed to get connection");
244        let adapter = connection
245            .create_adapter()
246            .expect("Failed to create adapter");
247
248        let painter_surfman_details = PainterSurfmanDetails {
249            connection,
250            adapter,
251        };
252        self.painter_surfman_details_map
253            .insert(painter.painter_id, painter_surfman_details);
254
255        let painter_id = painter.painter_id;
256        self.painters.push(Rc::new(RefCell::new(painter)));
257        painter_id
258    }
259
260    fn remove_painter(&mut self, painter_id: PainterId) {
261        // The shared details map must be removed first in order to avoid the creation of new
262        // devices after `clear_painter_resources` is called.
263        self.painter_surfman_details_map.remove(painter_id);
264
265        if !self.webgl_threads.clear_painter_resources(painter_id) {
266            warn!("Could not clear {painter_id:?} resources in WebGLThread");
267        }
268
269        // This is called last so that the surfman `Device` is dropped on this thread.
270        self.painters
271            .retain(|painter| painter.borrow().painter_id != painter_id);
272    }
273
274    pub(crate) fn maybe_painter<'a>(&'a self, painter_id: PainterId) -> Option<Ref<'a, Painter>> {
275        self.painters
276            .iter()
277            .map(|painter| painter.borrow())
278            .find(|painter| painter.painter_id == painter_id)
279    }
280
281    pub(crate) fn painter<'a>(&'a self, painter_id: PainterId) -> Ref<'a, Painter> {
282        self.maybe_painter(painter_id)
283            .expect("painter_id not found")
284    }
285
286    pub(crate) fn maybe_painter_mut<'a>(
287        &'a self,
288        painter_id: PainterId,
289    ) -> Option<RefMut<'a, Painter>> {
290        self.painters
291            .iter()
292            .map(|painter| painter.borrow_mut())
293            .find(|painter| painter.painter_id == painter_id)
294    }
295
296    pub(crate) fn painter_mut<'a>(&'a self, painter_id: PainterId) -> RefMut<'a, Painter> {
297        self.maybe_painter_mut(painter_id)
298            .expect("painter_id not found")
299    }
300
301    pub fn painter_id(&self) -> PainterId {
302        self.painters[0].borrow().painter_id
303    }
304
305    pub fn rendering_context_size(&self, painter_id: PainterId) -> Size2D<u32, DevicePixel> {
306        self.painter(painter_id).rendering_context.size2d()
307    }
308
309    pub fn webgl_threads(&self) -> WebGLThreads {
310        self.webgl_threads.clone()
311    }
312
313    pub fn webrender_external_image_id_manager(&self) -> WebRenderExternalImageIdManager {
314        self.webrender_external_image_id_manager.clone()
315    }
316
317    pub fn webxr_running(&self) -> bool {
318        #[cfg(feature = "webxr")]
319        {
320            self.webxr_main_thread.borrow().running()
321        }
322        #[cfg(not(feature = "webxr"))]
323        {
324            false
325        }
326    }
327
328    #[cfg(feature = "webxr")]
329    pub fn webxr_main_thread_registry(&self) -> webxr_api::Registry {
330        self.webxr_main_thread.borrow().registry()
331    }
332
333    #[cfg(feature = "webgpu")]
334    pub fn webgpu_image_map(&self) -> WebGpuExternalImageMap {
335        self.webgpu_image_map.get_or_init(Default::default).clone()
336    }
337
338    pub fn webviews_needing_repaint(&self) -> Vec<WebViewId> {
339        self.painters
340            .iter()
341            .flat_map(|painter| painter.borrow().webviews_needing_repaint())
342            .collect()
343    }
344
345    pub fn finish_shutting_down(&self) {
346        // Drain paint port, sometimes messages contain channels that are blocking
347        // another thread from finishing (i.e. SetFrameTree).
348        while self.paint_receiver.try_recv().is_ok() {}
349
350        self.webgl_threads.exit();
351        if let Some(webgl_join_handle) = self.webgl_join_handle.take() &&
352            webgl_join_handle.join().is_err()
353        {
354            warn!("Could not join WebGLThread.");
355        }
356
357        // Tell the profiler, memory profiler, and scrolling timer to shut down.
358        if let Some((sender, receiver)) = generic_channel::channel() {
359            self.time_profiler_chan
360                .send(profile_time::ProfilerMsg::Exit(sender));
361            let _ = receiver.recv();
362        }
363    }
364
365    fn handle_browser_message(&self, msg: PaintMessage) {
366        trace_msg_from_constellation!(msg, "{msg:?}");
367
368        match self.shutdown_state() {
369            ShutdownState::NotShuttingDown => {},
370            ShutdownState::ShuttingDown => {
371                self.handle_browser_message_while_shutting_down(msg);
372                return;
373            },
374            ShutdownState::FinishedShuttingDown => {
375                // Messages to Paint are ignored after shutdown is complete.
376                return;
377            },
378        }
379
380        match msg {
381            PaintMessage::CollectMemoryReport(sender) => {
382                self.collect_memory_report(sender);
383            },
384            PaintMessage::ChangeRunningAnimationsState(
385                webview_id,
386                pipeline_id,
387                animation_state,
388            ) => {
389                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
390                    painter.change_running_animations_state(
391                        webview_id,
392                        pipeline_id,
393                        animation_state,
394                    );
395                }
396            },
397            PaintMessage::SetFrameTreeForWebView(webview_id, frame_tree) => {
398                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
399                    painter.set_frame_tree_for_webview(&frame_tree);
400                }
401            },
402            PaintMessage::SetThrottled(webview_id, pipeline_id, throttled) => {
403                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
404                    painter.set_throttled(webview_id, pipeline_id, throttled);
405                }
406            },
407            PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
408                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
409                    painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
410                }
411            },
412            PaintMessage::NewWebRenderFrameReady(..) => {
413                unreachable!("New WebRender frames should be handled in the caller.");
414            },
415            PaintMessage::SendInitialTransaction(webview_id, pipeline_id) => {
416                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
417                    painter.send_initial_pipeline_transaction(webview_id, pipeline_id);
418                }
419            },
420            PaintMessage::ScrollNodeByDelta(
421                webview_id,
422                pipeline_id,
423                offset,
424                external_scroll_id,
425            ) => {
426                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
427                    painter.scroll_node_by_delta(
428                        webview_id,
429                        pipeline_id,
430                        offset,
431                        external_scroll_id,
432                    );
433                }
434            },
435            PaintMessage::ScrollViewportByDelta(webview_id, delta) => {
436                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
437                    painter.scroll_viewport_by_delta(webview_id, delta);
438                }
439            },
440            PaintMessage::UpdateEpoch {
441                webview_id,
442                pipeline_id,
443                epoch,
444            } => {
445                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
446                    painter.update_epoch(webview_id, pipeline_id, epoch);
447                }
448            },
449            PaintMessage::SendDisplayList {
450                webview_id,
451                display_list_descriptor,
452                display_list_info_receiver,
453                display_list_data_receiver,
454            } => {
455                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
456                    painter.handle_new_display_list(
457                        webview_id,
458                        display_list_descriptor,
459                        display_list_info_receiver,
460                        display_list_data_receiver,
461                    );
462                }
463            },
464            PaintMessage::GenerateFrame(painter_ids) => {
465                for painter_id in painter_ids {
466                    if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
467                        painter.generate_frame_for_script();
468                    }
469                }
470            },
471            PaintMessage::GenerateImageKey(webview_id, result_sender) => {
472                self.handle_generate_image_key(webview_id, result_sender);
473            },
474            PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
475                self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
476            },
477            PaintMessage::UpdateImages(painter_id, updates) => {
478                if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
479                    painter.update_images(updates);
480                }
481            },
482            PaintMessage::DelayNewFrameForCanvas(
483                webview_id,
484                pipeline_id,
485                canvas_epoch,
486                image_keys,
487            ) => {
488                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
489                    painter.delay_new_frames_for_canvas(pipeline_id, canvas_epoch, image_keys);
490                }
491            },
492            PaintMessage::AddFont(painter_id, font_key, data, index) => {
493                debug_assert!(painter_id == font_key.into());
494
495                if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
496                    painter.add_font(font_key, data, index);
497                }
498            },
499            PaintMessage::AddSystemFont(painter_id, font_key, native_handle) => {
500                debug_assert!(painter_id == font_key.into());
501
502                if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
503                    painter.add_system_font(font_key, native_handle);
504                }
505            },
506            PaintMessage::AddFontInstance(
507                painter_id,
508                font_instance_key,
509                font_key,
510                size,
511                flags,
512                variations,
513            ) => {
514                debug_assert!(painter_id == font_key.into());
515                debug_assert!(painter_id == font_instance_key.into());
516
517                if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
518                    painter.add_font_instance(font_instance_key, font_key, size, flags, variations);
519                }
520            },
521            PaintMessage::RemoveFonts(painter_id, keys, instance_keys) => {
522                if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
523                    painter.remove_fonts(keys, instance_keys);
524                }
525            },
526            PaintMessage::GenerateFontKeys(
527                number_of_font_keys,
528                number_of_font_instance_keys,
529                result_sender,
530                painter_id,
531            ) => {
532                self.handle_generate_font_keys(
533                    number_of_font_keys,
534                    number_of_font_instance_keys,
535                    result_sender,
536                    painter_id,
537                );
538            },
539            PaintMessage::Viewport(webview_id, viewport_description) => {
540                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
541                    painter.set_viewport_description(webview_id, viewport_description);
542                }
543            },
544            PaintMessage::ScreenshotReadinessReponse(webview_id, pipelines_and_epochs) => {
545                if let Some(painter) = self.maybe_painter(webview_id.into()) {
546                    painter.handle_screenshot_readiness_reply(webview_id, pipelines_and_epochs);
547                }
548            },
549            PaintMessage::SendLCPCandidate(lcp_candidate, webview_id, pipeline_id, epoch) => {
550                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
551                    painter.append_lcp_candidate(lcp_candidate, webview_id, pipeline_id, epoch);
552                }
553            },
554            PaintMessage::EnableLCPCalculation(webview_id) => {
555                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
556                    painter.enable_lcp_calculation(&webview_id);
557                }
558            },
559        }
560    }
561
562    pub fn remove_webview(&mut self, webview_id: WebViewId) {
563        let painter_id = webview_id.into();
564
565        {
566            let mut painter = self.painter_mut(painter_id);
567            painter.remove_webview(webview_id);
568            if !painter.is_empty() {
569                return;
570            }
571        }
572
573        self.remove_painter(painter_id);
574    }
575
576    fn collect_memory_report(&self, sender: profile_traits::mem::ReportsChan) {
577        let mut memory_report = MemoryReport::default();
578        for painter in &self.painters {
579            memory_report += painter.borrow().report_memory();
580        }
581
582        let mut reports = vec![
583            Report {
584                path: path!["webrender", "fonts"],
585                kind: ReportKind::ExplicitJemallocHeapSize,
586                size: memory_report.fonts,
587            },
588            Report {
589                path: path!["webrender", "images"],
590                kind: ReportKind::ExplicitJemallocHeapSize,
591                size: memory_report.images,
592            },
593            Report {
594                path: path!["webrender", "display-list"],
595                kind: ReportKind::ExplicitJemallocHeapSize,
596                size: memory_report.display_list,
597            },
598        ];
599
600        perform_memory_report(|ops| {
601            let scroll_trees_memory_usage = self
602                .painters
603                .iter()
604                .map(|painter| painter.borrow().scroll_trees_memory_usage(ops))
605                .sum();
606            reports.push(Report {
607                path: path!["paint", "scroll-tree"],
608                kind: ReportKind::ExplicitJemallocHeapSize,
609                size: scroll_trees_memory_usage,
610            });
611        });
612
613        sender.send(ProcessReports::new(reports));
614    }
615
616    /// Handle messages sent to `Paint` during the shutdown process. In general,
617    /// the things `Paint` can do in this state are limited. It's very important to
618    /// answer any synchronous messages though as other threads might be waiting on the
619    /// results to finish their own shut down process. We try to do as little as possible
620    /// during this time.
621    ///
622    /// When that involves generating WebRender ids, our approach here is to simply
623    /// generate them, but assume they will never be used, since once shutting down
624    /// `Paint` no longer does any WebRender frame generation.
625    fn handle_browser_message_while_shutting_down(&self, msg: PaintMessage) {
626        match msg {
627            PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
628                if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
629                    painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
630                }
631            },
632            PaintMessage::GenerateImageKey(webview_id, result_sender) => {
633                self.handle_generate_image_key(webview_id, result_sender);
634            },
635            PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
636                self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
637            },
638            PaintMessage::GenerateFontKeys(
639                number_of_font_keys,
640                number_of_font_instance_keys,
641                result_sender,
642                painter_id,
643            ) => {
644                self.handle_generate_font_keys(
645                    number_of_font_keys,
646                    number_of_font_instance_keys,
647                    result_sender,
648                    painter_id,
649                );
650            },
651            _ => {
652                debug!("Ignoring message ({:?} while shutting down", msg);
653            },
654        }
655    }
656
657    pub fn add_webview(&self, webview: Box<dyn WebViewTrait>, viewport_details: ViewportDetails) {
658        self.painter_mut(webview.id().into())
659            .add_webview(webview, viewport_details);
660    }
661
662    pub fn show_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
663        self.painter_mut(webview_id.into())
664            .set_webview_hidden(webview_id, false)
665    }
666
667    pub fn hide_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
668        self.painter_mut(webview_id.into())
669            .set_webview_hidden(webview_id, true)
670    }
671
672    pub fn set_hidpi_scale_factor(
673        &self,
674        webview_id: WebViewId,
675        new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
676    ) {
677        if self.shutdown_state() != ShutdownState::NotShuttingDown {
678            return;
679        }
680        self.painter_mut(webview_id.into())
681            .set_hidpi_scale_factor(webview_id, new_scale_factor);
682    }
683
684    pub fn resize_rendering_context(&self, webview_id: WebViewId, new_size: PhysicalSize<u32>) {
685        if self.shutdown_state() != ShutdownState::NotShuttingDown {
686            return;
687        }
688        self.painter_mut(webview_id.into())
689            .resize_rendering_context(new_size);
690    }
691
692    pub fn set_screen_size(&self, webview_id: WebViewId, new_size: Size2D<f32, DevicePixel>) {
693        if self.shutdown_state() != ShutdownState::NotShuttingDown {
694            return;
695        }
696        self.painter_mut(webview_id.into())
697            .set_screen_size(webview_id, new_size);
698    }
699
700    pub fn set_page_zoom(&self, webview_id: WebViewId, new_zoom: f32) {
701        if self.shutdown_state() != ShutdownState::NotShuttingDown {
702            return;
703        }
704        self.painter_mut(webview_id.into())
705            .set_page_zoom(webview_id, new_zoom);
706    }
707
708    pub fn page_zoom(&self, webview_id: WebViewId) -> f32 {
709        self.painter(webview_id.into()).page_zoom(webview_id)
710    }
711
712    /// Render the WebRender scene to the active `RenderingContext`.
713    pub fn render(&self, webview_id: WebViewId) {
714        self.painter_mut(webview_id.into())
715            .render(&self.time_profiler_chan);
716    }
717
718    /// Get the message receiver for this [`Paint`].
719    pub fn receiver(&self) -> &RoutedReceiver<PaintMessage> {
720        &self.paint_receiver
721    }
722
723    #[servo_tracing::instrument(skip_all)]
724    pub fn handle_messages(&self, mut messages: Vec<PaintMessage>) {
725        // Pull out the `NewWebRenderFrameReady` messages from the list of messages and handle them
726        // at the end of this function. This prevents overdraw when more than a single message of
727        // this type of received. In addition, if any of these frames need a repaint, that reflected
728        // when calling `handle_new_webrender_frame_ready`.
729        let mut saw_webrender_frame_ready_for_painter = HashMap::new();
730        messages.retain(|message| match message {
731            PaintMessage::NewWebRenderFrameReady(painter_id, _document_id, need_repaint) => {
732                if let Some(painter) = self.maybe_painter(*painter_id) {
733                    painter.decrement_pending_frames();
734                    *saw_webrender_frame_ready_for_painter
735                        .entry(*painter_id)
736                        .or_insert(*need_repaint) |= *need_repaint;
737                }
738
739                false
740            },
741            _ => true,
742        });
743
744        for message in messages {
745            self.handle_browser_message(message);
746            if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
747                return;
748            }
749        }
750
751        for (painter_id, repaint_needed) in saw_webrender_frame_ready_for_painter.iter() {
752            if let Some(painter) = self.maybe_painter(*painter_id) {
753                painter.handle_new_webrender_frame_ready(*repaint_needed);
754            }
755        }
756    }
757
758    #[servo_tracing::instrument(skip_all)]
759    pub fn perform_updates(&self) -> bool {
760        if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
761            return false;
762        }
763
764        // Run the WebXR main thread
765        #[cfg(feature = "webxr")]
766        self.webxr_main_thread.borrow_mut().run_one_frame();
767
768        for painter in &self.painters {
769            painter.borrow_mut().perform_updates();
770        }
771
772        self.shutdown_state() != ShutdownState::FinishedShuttingDown
773    }
774
775    pub fn toggle_webrender_debug(&self, option: WebRenderDebugOption) {
776        for painter in &self.painters {
777            painter.borrow_mut().toggle_webrender_debug(option);
778        }
779    }
780
781    pub fn capture_webrender(&self, webview_id: WebViewId) {
782        let capture_id = SystemTime::now()
783            .duration_since(UNIX_EPOCH)
784            .unwrap_or_default()
785            .as_secs()
786            .to_string();
787        let available_path = [env::current_dir(), Ok(env::temp_dir())]
788            .iter()
789            .filter_map(|val| {
790                val.as_ref()
791                    .map(|dir| dir.join("webrender-captures").join(&capture_id))
792                    .ok()
793            })
794            .find(|val| create_dir_all(val).is_ok());
795
796        let Some(capture_path) = available_path else {
797            log::error!("Couldn't create a path for WebRender captures.");
798            return;
799        };
800
801        log::info!("Saving WebRender capture to {capture_path:?}");
802        self.painter(webview_id.into())
803            .webrender_api
804            .save_capture(capture_path, CaptureBits::all());
805    }
806
807    /// Returning `false` means this is not going to reach the Constellation,
808    /// and we need to directly notify the embedder that input event is handled.
809    pub fn notify_input_event(&self, webview_id: WebViewId, event: InputEventAndId) -> bool {
810        if self.shutdown_state() != ShutdownState::NotShuttingDown {
811            return false;
812        }
813        self.painter_mut(webview_id.into())
814            .notify_input_event(webview_id, event)
815    }
816
817    pub fn notify_scroll_event(&self, webview_id: WebViewId, scroll: Scroll, point: WebViewPoint) {
818        if self.shutdown_state() != ShutdownState::NotShuttingDown {
819            return;
820        }
821        self.painter_mut(webview_id.into())
822            .notify_scroll_event(webview_id, scroll, point);
823    }
824
825    pub fn adjust_pinch_zoom(
826        &self,
827        webview_id: WebViewId,
828        pinch_zoom_delta: f32,
829        center: DevicePoint,
830    ) {
831        if self.shutdown_state() != ShutdownState::NotShuttingDown {
832            return;
833        }
834        self.painter_mut(webview_id.into())
835            .adjust_pinch_zoom(webview_id, pinch_zoom_delta, center);
836    }
837
838    pub fn pinch_zoom(&self, webview_id: WebViewId) -> f32 {
839        self.painter(webview_id.into()).pinch_zoom(webview_id)
840    }
841
842    pub fn device_pixels_per_page_pixel(
843        &self,
844        webview_id: WebViewId,
845    ) -> Scale<f32, CSSPixel, DevicePixel> {
846        self.painter_mut(webview_id.into())
847            .device_pixels_per_page_pixel(webview_id)
848    }
849
850    pub(crate) fn shutdown_state(&self) -> ShutdownState {
851        self.shutdown_state.get()
852    }
853
854    pub fn request_screenshot(
855        &self,
856        webview_id: WebViewId,
857        rect: Option<WebViewRect>,
858        callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
859    ) {
860        self.painter(webview_id.into())
861            .request_screenshot(webview_id, rect, callback);
862    }
863
864    pub fn notify_input_event_handled(
865        &self,
866        webview_id: WebViewId,
867        input_event_id: InputEventId,
868        result: InputEventResult,
869    ) {
870        if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
871            painter.notify_input_event_handled(webview_id, input_event_id, result);
872        }
873    }
874
875    /// Generate an image key from the appropriate [`Painter`] or, if it is unknown, generate
876    /// a dummy image key. The unknown case needs to be handled because requests for keys
877    /// could theoretically come after a [`Painter`] has been released. A dummy key is okay
878    /// in this case because we will never render again in that case.
879    fn handle_generate_image_key(
880        &self,
881        webview_id: WebViewId,
882        result_sender: GenericSender<ImageKey>,
883    ) {
884        let painter_id = webview_id.into();
885        let image_key = self.maybe_painter(painter_id).map_or_else(
886            || ImageKey::new(painter_id.into(), 0),
887            |painter| painter.webrender_api.generate_image_key(),
888        );
889        let _ = result_sender.send(image_key);
890    }
891
892    /// Generate image keys from the appropriate [`Painter`] or, if it is unknown, generate
893    /// dummy image keys. The unknown case needs to be handled because requests for keys
894    /// could theoretically come after a [`Painter`] has been released. A dummy key is okay
895    /// in this case because we will never render again in that case.
896    fn handle_generate_image_keys_for_pipeline(
897        &self,
898        webview_id: WebViewId,
899        pipeline_id: PipelineId,
900    ) {
901        let painter_id = webview_id.into();
902        let painter = self.maybe_painter(painter_id);
903        let image_keys = (0..pref!(image_key_batch_size))
904            .map(|_| {
905                painter.as_ref().map_or_else(
906                    || ImageKey::new(painter_id.into(), 0),
907                    |painter| painter.webrender_api.generate_image_key(),
908                )
909            })
910            .collect();
911
912        let _ = self.embedder_to_constellation_sender.send(
913            EmbedderToConstellationMessage::SendImageKeysForPipeline(pipeline_id, image_keys),
914        );
915    }
916
917    /// Generate font keys from the appropriate [`Painter`] or, if it is unknown, generate
918    /// dummy font keys. The unknown case needs to be handled because requests for keys
919    /// could theoretically come after a [`Painter`] has been released. A dummy key is okay
920    /// in this case because we will never render again in that case.
921    fn handle_generate_font_keys(
922        &self,
923        number_of_font_keys: usize,
924        number_of_font_instance_keys: usize,
925        result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
926        painter_id: PainterId,
927    ) {
928        let painter = self.maybe_painter(painter_id);
929        let font_keys = (0..number_of_font_keys)
930            .map(|_| {
931                painter.as_ref().map_or_else(
932                    || FontKey::new(painter_id.into(), 0),
933                    |painter| painter.webrender_api.generate_font_key(),
934                )
935            })
936            .collect();
937        let font_instance_keys = (0..number_of_font_instance_keys)
938            .map(|_| {
939                painter.as_ref().map_or_else(
940                    || FontInstanceKey::new(painter_id.into(), 0),
941                    |painter| painter.webrender_api.generate_font_instance_key(),
942                )
943            })
944            .collect();
945
946        let _ = result_sender.send((font_keys, font_instance_keys));
947    }
948}