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