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::{GenericSender, RoutedReceiver};
13use base::id::{PainterId, PipelineId, WebViewId};
14use bitflags::bitflags;
15use canvas_traits::webgl::{WebGLContextId, WebGLThreads};
16use compositing_traits::rendering_context::RenderingContext;
17use compositing_traits::{
18 PaintMessage, PaintProxy, PainterSurfmanDetails, PainterSurfmanDetailsMap,
19 WebRenderExternalImageIdManager, WebViewTrait,
20};
21use constellation_traits::EmbedderToConstellationMessage;
22use crossbeam_channel::Sender;
23use dpi::PhysicalSize;
24use embedder_traits::{
25 EventLoopWaker, InputEventAndId, InputEventId, InputEventResult, ScreenshotCaptureError,
26 Scroll, ShutdownState, ViewportDetails, WebViewPoint, WebViewRect,
27};
28use euclid::{Scale, Size2D};
29use image::RgbaImage;
30use ipc_channel::ipc::{self};
31use log::{debug, warn};
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 ipc::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_receiver,
441 } => {
442 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
443 painter.handle_new_display_list(
444 webview_id,
445 display_list_descriptor,
446 display_list_receiver,
447 );
448 }
449 },
450 PaintMessage::GenerateFrame(painter_ids) => {
451 for painter_id in painter_ids {
452 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
453 painter.generate_frame_for_script();
454 }
455 }
456 },
457 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
458 self.handle_generate_image_key(webview_id, result_sender);
459 },
460 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
461 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
462 },
463 PaintMessage::UpdateImages(painter_id, updates) => {
464 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
465 painter.update_images(updates);
466 }
467 },
468 PaintMessage::DelayNewFrameForCanvas(
469 webview_id,
470 pipeline_id,
471 canvas_epoch,
472 image_keys,
473 ) => {
474 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
475 painter.delay_new_frames_for_canvas(pipeline_id, canvas_epoch, image_keys);
476 }
477 },
478 PaintMessage::AddFont(painter_id, font_key, data, index) => {
479 debug_assert!(painter_id == font_key.into());
480
481 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
482 painter.add_font(font_key, data, index);
483 }
484 },
485 PaintMessage::AddSystemFont(painter_id, font_key, native_handle) => {
486 debug_assert!(painter_id == font_key.into());
487
488 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
489 painter.add_system_font(font_key, native_handle);
490 }
491 },
492 PaintMessage::AddFontInstance(
493 painter_id,
494 font_instance_key,
495 font_key,
496 size,
497 flags,
498 variations,
499 ) => {
500 debug_assert!(painter_id == font_key.into());
501 debug_assert!(painter_id == font_instance_key.into());
502
503 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
504 painter.add_font_instance(font_instance_key, font_key, size, flags, variations);
505 }
506 },
507 PaintMessage::RemoveFonts(painter_id, keys, instance_keys) => {
508 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
509 painter.remove_fonts(keys, instance_keys);
510 }
511 },
512 PaintMessage::GenerateFontKeys(
513 number_of_font_keys,
514 number_of_font_instance_keys,
515 result_sender,
516 painter_id,
517 ) => {
518 self.handle_generate_font_keys(
519 number_of_font_keys,
520 number_of_font_instance_keys,
521 result_sender,
522 painter_id,
523 );
524 },
525 PaintMessage::Viewport(webview_id, viewport_description) => {
526 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
527 painter.set_viewport_description(webview_id, viewport_description);
528 }
529 },
530 PaintMessage::ScreenshotReadinessReponse(webview_id, pipelines_and_epochs) => {
531 if let Some(painter) = self.maybe_painter(webview_id.into()) {
532 painter.handle_screenshot_readiness_reply(webview_id, pipelines_and_epochs);
533 }
534 },
535 PaintMessage::SendLCPCandidate(lcp_candidate, webview_id, pipeline_id, epoch) => {
536 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
537 painter.append_lcp_candidate(lcp_candidate, webview_id, pipeline_id, epoch);
538 }
539 },
540 }
541 }
542
543 pub fn remove_webview(&mut self, webview_id: WebViewId) {
544 let painter_id = webview_id.into();
545
546 {
547 let mut painter = self.painter_mut(painter_id);
548 painter.remove_webview(webview_id);
549 if !painter.is_empty() {
550 return;
551 }
552 }
553
554 self.remove_painter(painter_id);
555 }
556
557 fn collect_memory_report(&self, sender: profile_traits::mem::ReportsChan) {
558 let mut memory_report = MemoryReport::default();
559 for painter in &self.painters {
560 memory_report += painter.borrow().report_memory();
561 }
562
563 let mut reports = vec![
564 Report {
565 path: path!["webrender", "fonts"],
566 kind: ReportKind::ExplicitJemallocHeapSize,
567 size: memory_report.fonts,
568 },
569 Report {
570 path: path!["webrender", "images"],
571 kind: ReportKind::ExplicitJemallocHeapSize,
572 size: memory_report.images,
573 },
574 Report {
575 path: path!["webrender", "display-list"],
576 kind: ReportKind::ExplicitJemallocHeapSize,
577 size: memory_report.display_list,
578 },
579 ];
580
581 perform_memory_report(|ops| {
582 let scroll_trees_memory_usage = self
583 .painters
584 .iter()
585 .map(|painter| painter.borrow().scroll_trees_memory_usage(ops))
586 .sum();
587 reports.push(Report {
588 path: path!["paint", "scroll-tree"],
589 kind: ReportKind::ExplicitJemallocHeapSize,
590 size: scroll_trees_memory_usage,
591 });
592 });
593
594 sender.send(ProcessReports::new(reports));
595 }
596
597 fn handle_browser_message_while_shutting_down(&self, msg: PaintMessage) {
607 match msg {
608 PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
609 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
610 painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
611 }
612 },
613 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
614 self.handle_generate_image_key(webview_id, result_sender);
615 },
616 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
617 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
618 },
619 PaintMessage::GenerateFontKeys(
620 number_of_font_keys,
621 number_of_font_instance_keys,
622 result_sender,
623 painter_id,
624 ) => {
625 self.handle_generate_font_keys(
626 number_of_font_keys,
627 number_of_font_instance_keys,
628 result_sender,
629 painter_id,
630 );
631 },
632 _ => {
633 debug!("Ignoring message ({:?} while shutting down", msg);
634 },
635 }
636 }
637
638 pub fn add_webview(&self, webview: Box<dyn WebViewTrait>, viewport_details: ViewportDetails) {
639 self.painter_mut(webview.id().into())
640 .add_webview(webview, viewport_details);
641 }
642
643 pub fn show_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
644 self.painter_mut(webview_id.into())
645 .set_webview_hidden(webview_id, false)
646 }
647
648 pub fn hide_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
649 self.painter_mut(webview_id.into())
650 .set_webview_hidden(webview_id, true)
651 }
652
653 pub fn set_hidpi_scale_factor(
654 &self,
655 webview_id: WebViewId,
656 new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
657 ) {
658 if self.shutdown_state() != ShutdownState::NotShuttingDown {
659 return;
660 }
661 self.painter_mut(webview_id.into())
662 .set_hidpi_scale_factor(webview_id, new_scale_factor);
663 }
664
665 pub fn resize_rendering_context(&self, webview_id: WebViewId, new_size: PhysicalSize<u32>) {
666 if self.shutdown_state() != ShutdownState::NotShuttingDown {
667 return;
668 }
669 self.painter_mut(webview_id.into())
670 .resize_rendering_context(new_size);
671 }
672
673 pub fn set_page_zoom(&self, webview_id: WebViewId, new_zoom: f32) {
674 if self.shutdown_state() != ShutdownState::NotShuttingDown {
675 return;
676 }
677 self.painter_mut(webview_id.into())
678 .set_page_zoom(webview_id, new_zoom);
679 }
680
681 pub fn page_zoom(&self, webview_id: WebViewId) -> f32 {
682 self.painter(webview_id.into()).page_zoom(webview_id)
683 }
684
685 pub fn render(&self, webview_id: WebViewId) {
687 self.painter_mut(webview_id.into())
688 .render(&self.time_profiler_chan);
689 }
690
691 pub fn receiver(&self) -> &RoutedReceiver<PaintMessage> {
693 &self.paint_receiver
694 }
695
696 #[servo_tracing::instrument(skip_all)]
697 pub fn handle_messages(&self, mut messages: Vec<PaintMessage>) {
698 let mut saw_webrender_frame_ready_for_painter = HashMap::new();
703 messages.retain(|message| match message {
704 PaintMessage::NewWebRenderFrameReady(painter_id, _document_id, need_repaint) => {
705 if let Some(painter) = self.maybe_painter(*painter_id) {
706 painter.decrement_pending_frames();
707 *saw_webrender_frame_ready_for_painter
708 .entry(*painter_id)
709 .or_insert(*need_repaint) |= *need_repaint;
710 }
711
712 false
713 },
714 _ => true,
715 });
716
717 for message in messages {
718 self.handle_browser_message(message);
719 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
720 return;
721 }
722 }
723
724 for (painter_id, repaint_needed) in saw_webrender_frame_ready_for_painter.iter() {
725 if let Some(painter) = self.maybe_painter(*painter_id) {
726 painter.handle_new_webrender_frame_ready(*repaint_needed);
727 }
728 }
729 }
730
731 #[servo_tracing::instrument(skip_all)]
732 pub fn perform_updates(&self) -> bool {
733 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
734 return false;
735 }
736
737 #[cfg(feature = "webxr")]
739 self.webxr_main_thread.borrow_mut().run_one_frame();
740
741 for painter in &self.painters {
742 painter.borrow_mut().perform_updates();
743 }
744
745 self.shutdown_state() != ShutdownState::FinishedShuttingDown
746 }
747
748 pub fn toggle_webrender_debug(&self, option: WebRenderDebugOption) {
749 for painter in &self.painters {
750 painter.borrow_mut().toggle_webrender_debug(option);
751 }
752 }
753
754 pub fn capture_webrender(&self, webview_id: WebViewId) {
755 let capture_id = SystemTime::now()
756 .duration_since(UNIX_EPOCH)
757 .unwrap_or_default()
758 .as_secs()
759 .to_string();
760 let available_path = [env::current_dir(), Ok(env::temp_dir())]
761 .iter()
762 .filter_map(|val| {
763 val.as_ref()
764 .map(|dir| dir.join("webrender-captures").join(&capture_id))
765 .ok()
766 })
767 .find(|val| create_dir_all(val).is_ok());
768
769 let Some(capture_path) = available_path else {
770 log::error!("Couldn't create a path for WebRender captures.");
771 return;
772 };
773
774 log::info!("Saving WebRender capture to {capture_path:?}");
775 self.painter(webview_id.into())
776 .webrender_api
777 .save_capture(capture_path.clone(), CaptureBits::all());
778 }
779
780 pub fn notify_input_event(&self, webview_id: WebViewId, event: InputEventAndId) {
781 if self.shutdown_state() != ShutdownState::NotShuttingDown {
782 return;
783 }
784 self.painter_mut(webview_id.into())
785 .notify_input_event(webview_id, event);
786 }
787
788 pub fn notify_scroll_event(&self, webview_id: WebViewId, scroll: Scroll, point: WebViewPoint) {
789 if self.shutdown_state() != ShutdownState::NotShuttingDown {
790 return;
791 }
792 self.painter_mut(webview_id.into())
793 .notify_scroll_event(webview_id, scroll, point);
794 }
795
796 pub fn pinch_zoom(&self, webview_id: WebViewId, pinch_zoom_delta: f32, center: DevicePoint) {
797 if self.shutdown_state() != ShutdownState::NotShuttingDown {
798 return;
799 }
800 self.painter_mut(webview_id.into())
801 .pinch_zoom(webview_id, pinch_zoom_delta, center);
802 }
803
804 pub fn device_pixels_per_page_pixel(
805 &self,
806 webview_id: WebViewId,
807 ) -> Scale<f32, CSSPixel, DevicePixel> {
808 self.painter_mut(webview_id.into())
809 .device_pixels_per_page_pixel(webview_id)
810 }
811
812 pub(crate) fn shutdown_state(&self) -> ShutdownState {
813 self.shutdown_state.get()
814 }
815
816 pub fn request_screenshot(
817 &self,
818 webview_id: WebViewId,
819 rect: Option<WebViewRect>,
820 callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
821 ) {
822 self.painter(webview_id.into())
823 .request_screenshot(webview_id, rect, callback);
824 }
825
826 pub fn notify_input_event_handled(
827 &self,
828 webview_id: WebViewId,
829 input_event_id: InputEventId,
830 result: InputEventResult,
831 ) {
832 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
833 painter.notify_input_event_handled(webview_id, input_event_id, result);
834 }
835 }
836
837 fn handle_generate_image_key(
842 &self,
843 webview_id: WebViewId,
844 result_sender: GenericSender<ImageKey>,
845 ) {
846 let painter_id = webview_id.into();
847 let image_key = self.maybe_painter(painter_id).map_or_else(
848 || ImageKey::new(painter_id.into(), 0),
849 |painter| painter.webrender_api.generate_image_key(),
850 );
851 let _ = result_sender.send(image_key);
852 }
853
854 fn handle_generate_image_keys_for_pipeline(
859 &self,
860 webview_id: WebViewId,
861 pipeline_id: PipelineId,
862 ) {
863 let painter_id = webview_id.into();
864 let painter = self.maybe_painter(painter_id);
865 let image_keys = (0..pref!(image_key_batch_size))
866 .map(|_| {
867 painter.as_ref().map_or_else(
868 || ImageKey::new(painter_id.into(), 0),
869 |painter| painter.webrender_api.generate_image_key(),
870 )
871 })
872 .collect();
873
874 let _ = self.embedder_to_constellation_sender.send(
875 EmbedderToConstellationMessage::SendImageKeysForPipeline(pipeline_id, image_keys),
876 );
877 }
878
879 fn handle_generate_font_keys(
884 &self,
885 number_of_font_keys: usize,
886 number_of_font_instance_keys: usize,
887 result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
888 painter_id: PainterId,
889 ) {
890 let painter = self.maybe_painter(painter_id);
891 let font_keys = (0..number_of_font_keys)
892 .map(|_| {
893 painter.as_ref().map_or_else(
894 || FontKey::new(painter_id.into(), 0),
895 |painter| painter.webrender_api.generate_font_key(),
896 )
897 })
898 .collect();
899 let font_instance_keys = (0..number_of_font_instance_keys)
900 .map(|_| {
901 painter.as_ref().map_or_else(
902 || FontInstanceKey::new(painter_id.into(), 0),
903 |painter| painter.webrender_api.generate_font_instance_key(),
904 )
905 })
906 .collect();
907
908 let _ = result_sender.send((font_keys, font_instance_keys));
909 }
910}