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 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#[derive(Copy, Clone)]
57pub enum WebRenderDebugOption {
58 Profiler,
59 TextureCacheDebug,
60 RenderTargetDebug,
61}
62
63pub struct Paint {
85 painters: Vec<Rc<RefCell<Painter>>>,
88
89 pub(crate) paint_proxy: PaintProxy,
92
93 pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
96
97 shutdown_state: Rc<Cell<ShutdownState>>,
100
101 paint_receiver: RoutedReceiver<PaintMessage>,
103
104 pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
106
107 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
109
110 pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
113
114 pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
118
119 webgl_threads: WebGLThreads,
121
122 webgl_join_handle: Cell<Option<JoinHandle<()>>>,
124
125 pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
127
128 time_profiler_chan: profile_time::ProfilerChan,
130
131 _mem_profiler_registration: ProfilerRegistration,
134
135 #[cfg(feature = "webxr")]
137 webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
138
139 #[cfg(feature = "webgpu")]
141 webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
142}
143
144#[derive(Clone, Copy, Default, PartialEq)]
146pub(crate) struct RepaintReason(u8);
147
148bitflags! {
149 impl RepaintReason: u8 {
150 const ReadyForScreenshot = 1 << 0;
152 const ChangedAnimationState = 1 << 1;
154 const NewWebRenderFrame = 1 << 2;
156 const Resize = 1 << 3;
158 const StartedFlinging = 1 << 4;
160 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 #[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 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 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 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 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 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 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 pub fn render(&self, webview_id: WebViewId) {
715 self.painter_mut(webview_id.into())
716 .render(&self.time_profiler_chan);
717 }
718
719 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 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 #[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 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 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 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 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}