1use 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#[derive(Copy, Clone)]
58pub enum WebRenderDebugOption {
59 Profiler,
60 TextureCacheDebug,
61 RenderTargetDebug,
62}
63
64pub struct Paint {
86 painters: Vec<Rc<RefCell<Painter>>>,
89
90 pub(crate) paint_proxy: PaintProxy,
93
94 pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
97
98 shutdown_state: Rc<Cell<ShutdownState>>,
101
102 paint_receiver: RoutedReceiver<PaintMessage>,
104
105 pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
107
108 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
110
111 pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
114
115 pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
119
120 webgl_threads: WebGLThreads,
122
123 webgl_join_handle: Cell<Option<JoinHandle<()>>>,
125
126 pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
128
129 time_profiler_chan: profile_time::ProfilerChan,
131
132 _mem_profiler_registration: ProfilerRegistration,
135
136 #[cfg(feature = "webxr")]
138 webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
139
140 #[cfg(feature = "webgpu")]
142 webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
143}
144
145#[derive(Clone, Copy, Default, PartialEq)]
147pub(crate) struct RepaintReason(u8);
148
149bitflags! {
150 impl RepaintReason: u8 {
151 const ReadyForScreenshot = 1 << 0;
153 const ChangedAnimationState = 1 << 1;
155 const NewWebRenderFrame = 1 << 2;
157 const Resize = 1 << 3;
159 const StartedFlinging = 1 << 4;
161 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 #[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 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 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 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 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 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 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 pub fn render(&self, webview_id: WebViewId) {
714 self.painter_mut(webview_id.into())
715 .render(&self.time_profiler_chan);
716 }
717
718 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 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 #[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 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 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 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 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}