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::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#[derive(Copy, Clone)]
56pub enum WebRenderDebugOption {
57 Profiler,
58 TextureCacheDebug,
59 RenderTargetDebug,
60}
61
62pub struct Paint {
84 painters: Vec<Rc<RefCell<Painter>>>,
87
88 pub(crate) paint_proxy: PaintProxy,
91
92 pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
95
96 shutdown_state: Rc<Cell<ShutdownState>>,
99
100 paint_receiver: RoutedReceiver<PaintMessage>,
102
103 pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
105
106 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
108
109 pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
112
113 pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
117
118 webgl_threads: WebGLThreads,
120
121 pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
123
124 time_profiler_chan: profile_time::ProfilerChan,
126
127 _mem_profiler_registration: ProfilerRegistration,
130
131 #[cfg(feature = "webxr")]
133 webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
134
135 #[cfg(feature = "webgpu")]
137 webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
138}
139
140#[derive(Clone, Copy, Default, PartialEq)]
142pub(crate) struct RepaintReason(u8);
143
144bitflags! {
145 impl RepaintReason: u8 {
146 const ReadyForScreenshot = 1 << 0;
148 const ChangedAnimationState = 1 << 1;
150 const NewWebRenderFrame = 1 << 2;
152 const Resize = 1 << 3;
154 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 #[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 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 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 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 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 pub fn render(&self, webview_id: WebViewId) {
689 self.painter_mut(webview_id.into())
690 .render(&self.time_profiler_chan);
691 }
692
693 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 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 #[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 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 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 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}