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