1use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::collections::HashMap;
7use std::env;
8use std::fs::create_dir_all;
9use std::rc::Rc;
10#[cfg(feature = "webgl")]
11use std::thread::JoinHandle;
12use std::time::{SystemTime, UNIX_EPOCH};
13
14use bitflags::bitflags;
15use crossbeam_channel::Sender;
16use dpi::PhysicalSize;
17use embedder_traits::{
18 EventLoopWaker, InputEventAndId, InputEventId, InputEventResult, ScreenshotCaptureError,
19 Scroll, ShutdownState, ViewportDetails, WebViewPoint, WebViewRect,
20};
21use euclid::{Scale, Size2D};
22use image::RgbaImage;
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::{self, GenericSender, RoutedReceiver};
35use servo_base::id::{PainterId, PipelineId, WebViewId};
36#[cfg(feature = "webgl")]
37use servo_canvas_traits::webgl::{WebGLContextId, WebGLThreads};
38use servo_config::pref;
39use servo_constellation_traits::EmbedderToConstellationMessage;
40use servo_geometry::DeviceIndependentPixel;
41use style_traits::CSSPixel;
42#[cfg(feature = "webgl")]
43use surfman::Device;
44#[cfg(feature = "webgl")]
45use surfman::chains::SwapChains;
46#[cfg(feature = "webgl")]
47use webgl::WebGLComm;
48#[cfg(feature = "webgl")]
49use webgl::webgl_thread::WebGLContextBusyMap;
50#[cfg(feature = "webgpu")]
51use webgpu::canvas_context::WebGpuExternalImageMap;
52use webrender::{CaptureBits, MemoryReport};
53use webrender_api::units::{DevicePixel, DevicePoint};
54use webrender_api::{FontInstanceKey, FontKey, ImageKey};
55#[cfg(feature = "webxr")]
56use webxr::WebXrRegistry;
57
58use crate::InitialPaintState;
59use crate::painter::Painter;
60use crate::webview_renderer::UnknownWebView;
61
62#[derive(Copy, Clone)]
64pub enum WebRenderDebugOption {
65 Profiler,
66 TextureCacheDebug,
67 RenderTargetDebug,
68}
69
70#[cfg(feature = "webgl")]
72pub struct WebGLPaint {
73 pub(crate) busy_webgl_contexts_map: WebGLContextBusyMap,
77
78 webgl_threads: WebGLThreads,
80
81 webgl_join_handle: Cell<Option<JoinHandle<()>>>,
83
84 pub(crate) swap_chains: SwapChains<WebGLContextId, Device>,
86}
87
88#[cfg(feature = "webgl")]
89impl WebGLPaint {
90 fn shutdown(&self) {
91 self.webgl_threads.exit();
92 if let Some(webgl_join_handle) = self.webgl_join_handle.take() &&
93 webgl_join_handle.join().is_err()
94 {
95 warn!("Could not join WebGLThread.");
96 }
97 }
98}
99
100pub struct Paint {
122 painters: Vec<Rc<RefCell<Painter>>>,
125
126 pub(crate) paint_proxy: PaintProxy,
129
130 pub(crate) event_loop_waker: Box<dyn EventLoopWaker>,
133
134 shutdown_state: Rc<Cell<ShutdownState>>,
137
138 paint_receiver: RoutedReceiver<PaintMessage>,
140
141 pub(crate) embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
143
144 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
146
147 pub(crate) painter_surfman_details_map: PainterSurfmanDetailsMap,
150
151 #[cfg(feature = "webgl")]
152 pub(crate) webgl_paint: WebGLPaint,
154
155 time_profiler_chan: profile_time::ProfilerChan,
157
158 _mem_profiler_registration: ProfilerRegistration,
161
162 #[cfg(feature = "webxr")]
164 webxr_main_thread: RefCell<webxr::MainThreadRegistry>,
165
166 #[cfg(feature = "webgpu")]
168 webgpu_image_map: std::cell::OnceCell<WebGpuExternalImageMap>,
169}
170
171#[derive(Clone, Copy, Default, PartialEq)]
173pub(crate) struct RepaintReason(u8);
174
175bitflags! {
176 impl RepaintReason: u8 {
177 const ReadyForScreenshot = 1 << 0;
179 const ChangedAnimationState = 1 << 1;
181 const NewWebRenderFrame = 1 << 2;
183 const Resize = 1 << 3;
185 const StartedFlinging = 1 << 4;
187 const BlinkingCaret = 1 << 5;
189 }
190}
191
192impl Paint {
193 pub fn new(state: InitialPaintState) -> Rc<RefCell<Self>> {
194 let registration = state.mem_profiler_chan.prepare_memory_reporting(
195 "paint".into(),
196 state.paint_proxy.clone(),
197 PaintMessage::CollectMemoryReport,
198 );
199
200 let webrender_external_image_id_manager = WebRenderExternalImageIdManager::default();
201 let painter_surfman_details_map = PainterSurfmanDetailsMap::default();
202 #[cfg(feature = "webgl")]
203 let WebGLComm {
204 webgl_threads,
205 swap_chains,
206 busy_webgl_context_map,
207 #[cfg(feature = "webxr")]
208 webxr_layer_grand_manager,
209 join_handle: webgl_join_handle,
210 } = WebGLComm::new(
211 state.paint_proxy.cross_process_paint_api.clone(),
212 webrender_external_image_id_manager.clone(),
213 painter_surfman_details_map.clone(),
214 );
215
216 #[cfg(feature = "webxr")]
218 let webxr_main_thread = webxr::MainThreadRegistry::new(
219 state.event_loop_waker.clone(),
220 webxr_layer_grand_manager,
221 )
222 .expect("Failed to create WebXR device registry");
223
224 #[cfg(feature = "webgl")]
225 let webgl_paint = WebGLPaint {
226 busy_webgl_contexts_map: busy_webgl_context_map,
227 webgl_threads,
228 webgl_join_handle: Cell::new(Some(webgl_join_handle)),
229 swap_chains,
230 };
231 Rc::new(RefCell::new(Paint {
232 painters: Default::default(),
233 paint_proxy: state.paint_proxy,
234 event_loop_waker: state.event_loop_waker,
235 shutdown_state: state.shutdown_state,
236 paint_receiver: state.receiver,
237 embedder_to_constellation_sender: state.embedder_to_constellation_sender.clone(),
238 webrender_external_image_id_manager,
239 #[cfg(feature = "webgl")]
240 webgl_paint,
241 time_profiler_chan: state.time_profiler_chan,
242 _mem_profiler_registration: registration,
243 painter_surfman_details_map,
244 #[cfg(feature = "webxr")]
245 webxr_main_thread: RefCell::new(webxr_main_thread),
246 #[cfg(feature = "webgpu")]
247 webgpu_image_map: Default::default(),
248 }))
249 }
250
251 #[cfg(feature = "webxr")]
252 pub fn register_webxr_registry(&self, registry: Box<dyn WebXrRegistry>) {
253 let mut webxr_main_thread = self.webxr_main_thread.borrow_mut();
254 registry.register(&mut webxr_main_thread)
255 }
256
257 pub fn register_rendering_context(
258 &mut self,
259 rendering_context: Rc<dyn RenderingContext>,
260 ) -> PainterId {
261 if let Some(painter_id) = self.painters.iter().find_map(|painter| {
262 let painter = painter.borrow();
263 if Rc::ptr_eq(&painter.rendering_context, &rendering_context) {
264 Some(painter.painter_id)
265 } else {
266 None
267 }
268 }) {
269 return painter_id;
270 }
271
272 let painter = Painter::new(rendering_context.clone(), self);
273 let painter_id = painter.painter_id;
274 self.painters.push(Rc::new(RefCell::new(painter)));
275
276 let Some(connection) = rendering_context.connection() else {
279 warn!("The rendering context has no surfman connection, WebGL will be unavailable");
280 return painter_id;
281 };
282 let Ok(adapter) = connection.create_adapter().inspect_err(|error| {
283 warn!("Could not create a surfman adapter, WebGL will be unavailable: {error:?}")
284 }) else {
285 return painter_id;
286 };
287
288 self.painter_surfman_details_map.insert(
289 painter_id,
290 PainterSurfmanDetails {
291 connection,
292 adapter,
293 },
294 );
295
296 painter_id
297 }
298
299 fn remove_painter(&mut self, painter_id: PainterId) {
300 self.painter_surfman_details_map.remove(painter_id);
303
304 #[cfg(feature = "webgl")]
305 if !self
306 .webgl_paint
307 .webgl_threads
308 .clear_painter_resources(painter_id)
309 {
310 warn!("Could not clear {painter_id:?} resources in WebGLThread");
311 }
312
313 self.painters
315 .retain(|painter| painter.borrow().painter_id != painter_id);
316 }
317
318 pub(crate) fn maybe_painter<'a>(&'a self, painter_id: PainterId) -> Option<Ref<'a, Painter>> {
319 self.painters
320 .iter()
321 .map(|painter| painter.borrow())
322 .find(|painter| painter.painter_id == painter_id)
323 }
324
325 pub(crate) fn painter<'a>(&'a self, painter_id: PainterId) -> Ref<'a, Painter> {
326 self.maybe_painter(painter_id)
327 .expect("painter_id not found")
328 }
329
330 pub(crate) fn maybe_painter_mut<'a>(
331 &'a self,
332 painter_id: PainterId,
333 ) -> Option<RefMut<'a, Painter>> {
334 self.painters
335 .iter()
336 .map(|painter| painter.borrow_mut())
337 .find(|painter| painter.painter_id == painter_id)
338 }
339
340 pub(crate) fn painter_mut<'a>(&'a self, painter_id: PainterId) -> RefMut<'a, Painter> {
341 self.maybe_painter_mut(painter_id)
342 .expect("painter_id not found")
343 }
344
345 pub fn painter_id(&self) -> PainterId {
346 self.painters[0].borrow().painter_id
347 }
348
349 pub fn rendering_context_size(&self, painter_id: PainterId) -> Size2D<u32, DevicePixel> {
350 self.painter(painter_id).rendering_context.size2d()
351 }
352
353 #[cfg(feature = "webgl")]
354 pub fn webgl_threads(&self) -> WebGLThreads {
355 self.webgl_paint.webgl_threads.clone()
356 }
357
358 pub fn webrender_external_image_id_manager(&self) -> WebRenderExternalImageIdManager {
359 self.webrender_external_image_id_manager.clone()
360 }
361
362 pub fn webxr_running(&self) -> bool {
363 #[cfg(feature = "webxr")]
364 {
365 self.webxr_main_thread.borrow().running()
366 }
367 #[cfg(not(feature = "webxr"))]
368 {
369 false
370 }
371 }
372
373 #[cfg(feature = "webxr")]
374 pub fn webxr_main_thread_registry(&self) -> webxr_api::Registry {
375 self.webxr_main_thread.borrow().registry()
376 }
377
378 #[cfg(feature = "webgpu")]
379 pub fn webgpu_image_map(&self) -> WebGpuExternalImageMap {
380 self.webgpu_image_map.get_or_init(Default::default).clone()
381 }
382
383 pub fn webviews_needing_repaint(&self) -> Vec<WebViewId> {
384 self.painters
385 .iter()
386 .flat_map(|painter| painter.borrow().webviews_needing_repaint())
387 .collect()
388 }
389
390 pub fn finish_shutting_down(&self) {
391 while self.paint_receiver.try_recv().is_ok() {}
394
395 #[cfg(feature = "webgl")]
396 self.webgl_paint.shutdown();
397
398 if let Some((sender, receiver)) = generic_channel::channel() {
400 self.time_profiler_chan
401 .send(profile_time::ProfilerMsg::Exit(sender));
402 let _ = receiver.recv();
403 }
404 }
405
406 fn handle_browser_message(&self, msg: PaintMessage) {
407 trace_msg_from_constellation!(msg, "{msg:?}");
408
409 match self.shutdown_state() {
410 ShutdownState::NotShuttingDown => {},
411 ShutdownState::ShuttingDown => {
412 self.handle_browser_message_while_shutting_down(msg);
413 return;
414 },
415 ShutdownState::FinishedShuttingDown => {
416 return;
418 },
419 }
420
421 match msg {
422 PaintMessage::CollectMemoryReport(sender) => {
423 self.collect_memory_report(sender);
424 },
425 PaintMessage::ChangeRunningAnimationsState(
426 webview_id,
427 pipeline_id,
428 animation_state,
429 ) => {
430 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
431 painter.change_running_animations_state(
432 webview_id,
433 pipeline_id,
434 animation_state,
435 );
436 }
437 },
438 PaintMessage::SetFrameTreeForWebView(webview_id, frame_tree) => {
439 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
440 painter.set_frame_tree_for_webview(&frame_tree);
441 }
442 },
443 PaintMessage::SetThrottled(webview_id, pipeline_id, throttled) => {
444 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
445 painter.set_throttled(webview_id, pipeline_id, throttled);
446 }
447 },
448 PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
449 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
450 painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
451 }
452 },
453 PaintMessage::NewWebRenderFrameReady(..) => {
454 unreachable!("New WebRender frames should be handled in the caller.");
455 },
456 PaintMessage::SendInitialTransaction(webview_id, pipeline_id) => {
457 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
458 painter.send_initial_pipeline_transaction(webview_id, pipeline_id);
459 }
460 },
461 PaintMessage::ScrollNodeByDelta(
462 webview_id,
463 pipeline_id,
464 offset,
465 external_scroll_id,
466 ) => {
467 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
468 painter.scroll_node_by_delta(
469 webview_id,
470 pipeline_id,
471 offset,
472 external_scroll_id,
473 );
474 }
475 },
476 PaintMessage::ScrollViewportByDelta(webview_id, delta) => {
477 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
478 painter.scroll_viewport_by_delta(webview_id, delta);
479 }
480 },
481 PaintMessage::UpdateEpoch {
482 webview_id,
483 pipeline_id,
484 epoch,
485 } => {
486 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
487 painter.update_epoch(webview_id, pipeline_id, epoch);
488 }
489 },
490 PaintMessage::SendDisplayList {
491 webview_id,
492 display_list_descriptor,
493 display_list_info_receiver,
494 display_list_data_receiver,
495 } => {
496 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
497 painter.handle_new_display_list(
498 webview_id,
499 display_list_descriptor,
500 display_list_info_receiver,
501 display_list_data_receiver,
502 );
503 }
504 },
505 PaintMessage::GenerateFrame(painter_ids) => {
506 for painter_id in painter_ids {
507 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
508 painter.generate_frame_for_script();
509 }
510 }
511 },
512 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
513 self.handle_generate_image_key(webview_id, result_sender);
514 },
515 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
516 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
517 },
518 PaintMessage::UpdateImages(painter_id, updates) => {
519 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
520 painter.update_images(updates);
521 }
522 },
523 PaintMessage::DelayNewFrameForCanvas(
524 webview_id,
525 pipeline_id,
526 canvas_epoch,
527 image_keys,
528 ) => {
529 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
530 painter.delay_new_frames_for_canvas(pipeline_id, canvas_epoch, image_keys);
531 }
532 },
533 PaintMessage::AddFont(painter_id, font_key, data, index) => {
534 debug_assert!(painter_id == font_key.into());
535
536 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
537 painter.add_font(font_key, data, index);
538 }
539 },
540 PaintMessage::AddSystemFont(painter_id, font_key, native_handle) => {
541 debug_assert!(painter_id == font_key.into());
542
543 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
544 painter.add_system_font(font_key, native_handle);
545 }
546 },
547 PaintMessage::AddFontInstance(
548 painter_id,
549 font_instance_key,
550 font_key,
551 size,
552 flags,
553 variations,
554 ) => {
555 debug_assert!(painter_id == font_key.into());
556 debug_assert!(painter_id == font_instance_key.into());
557
558 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
559 painter.add_font_instance(font_instance_key, font_key, size, flags, variations);
560 }
561 },
562 PaintMessage::RemoveFonts(painter_id, keys, instance_keys) => {
563 if let Some(mut painter) = self.maybe_painter_mut(painter_id) {
564 painter.remove_fonts(keys, instance_keys);
565 }
566 },
567 PaintMessage::GenerateFontKeys(
568 number_of_font_keys,
569 number_of_font_instance_keys,
570 result_sender,
571 painter_id,
572 ) => {
573 self.handle_generate_font_keys(
574 number_of_font_keys,
575 number_of_font_instance_keys,
576 result_sender,
577 painter_id,
578 );
579 },
580 PaintMessage::Viewport(webview_id, viewport_description) => {
581 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
582 painter.set_viewport_description(webview_id, viewport_description);
583 }
584 },
585 PaintMessage::ScreenshotReadinessReponse(webview_id, pipelines_and_epochs) => {
586 if let Some(painter) = self.maybe_painter(webview_id.into()) {
587 painter.handle_screenshot_readiness_reply(webview_id, pipelines_and_epochs);
588 }
589 },
590 }
591 }
592
593 pub fn remove_webview(&mut self, webview_id: WebViewId) {
594 let painter_id = webview_id.into();
595
596 {
597 let mut painter = self.painter_mut(painter_id);
598 painter.remove_webview(webview_id);
599 if !painter.is_empty() {
600 return;
601 }
602 }
603
604 self.remove_painter(painter_id);
605 }
606
607 fn collect_memory_report(&self, sender: profile_traits::mem::ReportsChan) {
608 let mut memory_report = MemoryReport::default();
609 for painter in &self.painters {
610 memory_report += painter.borrow().report_memory();
611 }
612
613 let mut reports = vec![
614 Report {
615 path: path!["webrender", "fonts"],
616 kind: ReportKind::ExplicitJemallocHeapSize,
617 size: memory_report.fonts,
618 },
619 Report {
620 path: path!["webrender", "images"],
621 kind: ReportKind::ExplicitJemallocHeapSize,
622 size: memory_report.images,
623 },
624 Report {
625 path: path!["webrender", "display-list"],
626 kind: ReportKind::ExplicitJemallocHeapSize,
627 size: memory_report.display_list,
628 },
629 ];
630
631 perform_memory_report(|ops| {
632 let scroll_trees_memory_usage = self
633 .painters
634 .iter()
635 .map(|painter| painter.borrow().scroll_trees_memory_usage(ops))
636 .sum();
637 reports.push(Report {
638 path: path!["paint", "scroll-tree"],
639 kind: ReportKind::ExplicitJemallocHeapSize,
640 size: scroll_trees_memory_usage,
641 });
642 });
643
644 sender.send(ProcessReports::new(reports));
645 }
646
647 fn handle_browser_message_while_shutting_down(&self, msg: PaintMessage) {
657 match msg {
658 PaintMessage::PipelineExited(webview_id, pipeline_id, pipeline_exit_source) => {
659 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
660 painter.notify_pipeline_exited(webview_id, pipeline_id, pipeline_exit_source);
661 }
662 },
663 PaintMessage::GenerateImageKey(webview_id, result_sender) => {
664 self.handle_generate_image_key(webview_id, result_sender);
665 },
666 PaintMessage::GenerateImageKeysForPipeline(webview_id, pipeline_id) => {
667 self.handle_generate_image_keys_for_pipeline(webview_id, pipeline_id);
668 },
669 PaintMessage::GenerateFontKeys(
670 number_of_font_keys,
671 number_of_font_instance_keys,
672 result_sender,
673 painter_id,
674 ) => {
675 self.handle_generate_font_keys(
676 number_of_font_keys,
677 number_of_font_instance_keys,
678 result_sender,
679 painter_id,
680 );
681 },
682 _ => {
683 debug!("Ignoring message ({:?} while shutting down", msg);
684 },
685 }
686 }
687
688 pub fn add_webview(&self, webview: Box<dyn WebViewTrait>, viewport_details: ViewportDetails) {
689 self.painter_mut(webview.id().into())
690 .add_webview(webview, viewport_details);
691 }
692
693 pub fn show_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
694 self.painter_mut(webview_id.into())
695 .set_webview_hidden(webview_id, false)
696 }
697
698 pub fn hide_webview(&self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
699 self.painter_mut(webview_id.into())
700 .set_webview_hidden(webview_id, true)
701 }
702
703 pub fn set_hidpi_scale_factor(
704 &self,
705 webview_id: WebViewId,
706 new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
707 ) {
708 if self.shutdown_state() != ShutdownState::NotShuttingDown {
709 return;
710 }
711 self.painter_mut(webview_id.into())
712 .set_hidpi_scale_factor(webview_id, new_scale_factor);
713 }
714
715 pub fn resize_rendering_context(&self, webview_id: WebViewId, new_size: PhysicalSize<u32>) {
716 if self.shutdown_state() != ShutdownState::NotShuttingDown {
717 return;
718 }
719 self.painter_mut(webview_id.into())
720 .resize_rendering_context(new_size);
721 }
722
723 pub fn set_screen_size(&self, webview_id: WebViewId, new_size: Size2D<f32, DevicePixel>) {
724 if self.shutdown_state() != ShutdownState::NotShuttingDown {
725 return;
726 }
727 self.painter_mut(webview_id.into())
728 .set_screen_size(webview_id, new_size);
729 }
730
731 pub fn set_page_zoom(&self, webview_id: WebViewId, new_zoom: f32) {
732 if self.shutdown_state() != ShutdownState::NotShuttingDown {
733 return;
734 }
735 self.painter_mut(webview_id.into())
736 .set_page_zoom(webview_id, new_zoom);
737 }
738
739 pub fn page_zoom(&self, webview_id: WebViewId) -> f32 {
740 self.painter(webview_id.into()).page_zoom(webview_id)
741 }
742
743 pub fn render(&self, webview_id: WebViewId) {
745 self.painter_mut(webview_id.into())
746 .render(&self.time_profiler_chan);
747 }
748
749 pub fn receiver(&self) -> &RoutedReceiver<PaintMessage> {
751 &self.paint_receiver
752 }
753
754 #[servo_tracing::instrument(skip_all)]
755 pub fn handle_messages(&self, mut messages: Vec<PaintMessage>) {
756 let mut saw_webrender_frame_ready_for_painter = HashMap::new();
761 messages.retain(|message| match message {
762 PaintMessage::NewWebRenderFrameReady(painter_id, _document_id, need_repaint) => {
763 if let Some(painter) = self.maybe_painter(*painter_id) {
764 painter.decrement_pending_frames();
765 *saw_webrender_frame_ready_for_painter
766 .entry(*painter_id)
767 .or_insert(*need_repaint) |= *need_repaint;
768 }
769
770 false
771 },
772 _ => true,
773 });
774
775 for message in messages {
776 self.handle_browser_message(message);
777 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
778 return;
779 }
780 }
781
782 for (painter_id, repaint_needed) in saw_webrender_frame_ready_for_painter.iter() {
783 if let Some(painter) = self.maybe_painter(*painter_id) {
784 painter.handle_new_webrender_frame_ready(*repaint_needed);
785 }
786 }
787 }
788
789 #[servo_tracing::instrument(skip_all)]
790 pub fn perform_updates(&self) -> bool {
791 if self.shutdown_state() == ShutdownState::FinishedShuttingDown {
792 return false;
793 }
794
795 #[cfg(feature = "webxr")]
797 self.webxr_main_thread.borrow_mut().run_one_frame();
798
799 for painter in &self.painters {
800 painter.borrow_mut().perform_updates();
801 }
802
803 self.shutdown_state() != ShutdownState::FinishedShuttingDown
804 }
805
806 pub fn toggle_webrender_debug(&self, option: WebRenderDebugOption) {
807 for painter in &self.painters {
808 painter.borrow_mut().toggle_webrender_debug(option);
809 }
810 }
811
812 pub fn capture_webrender(&self, webview_id: WebViewId) {
813 let capture_id = SystemTime::now()
814 .duration_since(UNIX_EPOCH)
815 .unwrap_or_default()
816 .as_secs()
817 .to_string();
818 let available_path = [env::current_dir(), Ok(env::temp_dir())]
819 .iter()
820 .filter_map(|val| {
821 val.as_ref()
822 .map(|dir| dir.join("webrender-captures").join(&capture_id))
823 .ok()
824 })
825 .find(|val| create_dir_all(val).is_ok());
826
827 let Some(capture_path) = available_path else {
828 log::error!("Couldn't create a path for WebRender captures.");
829 return;
830 };
831
832 log::info!("Saving WebRender capture to {capture_path:?}");
833 self.painter(webview_id.into())
834 .webrender_api
835 .save_capture(capture_path, CaptureBits::all());
836 }
837
838 pub fn notify_input_event(&self, webview_id: WebViewId, event: InputEventAndId) -> bool {
841 if self.shutdown_state() != ShutdownState::NotShuttingDown {
842 return false;
843 }
844 self.painter_mut(webview_id.into())
845 .notify_input_event(webview_id, event)
846 }
847
848 pub fn notify_scroll_event(&self, webview_id: WebViewId, scroll: Scroll, point: WebViewPoint) {
849 if self.shutdown_state() != ShutdownState::NotShuttingDown {
850 return;
851 }
852 self.painter_mut(webview_id.into())
853 .notify_scroll_event(webview_id, scroll, point);
854 }
855
856 pub fn adjust_pinch_zoom(
857 &self,
858 webview_id: WebViewId,
859 pinch_zoom_delta: f32,
860 center: DevicePoint,
861 ) {
862 if self.shutdown_state() != ShutdownState::NotShuttingDown {
863 return;
864 }
865 self.painter_mut(webview_id.into())
866 .adjust_pinch_zoom(webview_id, pinch_zoom_delta, center);
867 }
868
869 pub fn pinch_zoom(&self, webview_id: WebViewId) -> f32 {
870 self.painter(webview_id.into()).pinch_zoom(webview_id)
871 }
872
873 pub fn device_pixels_per_page_pixel(
874 &self,
875 webview_id: WebViewId,
876 ) -> Scale<f32, CSSPixel, DevicePixel> {
877 self.painter_mut(webview_id.into())
878 .device_pixels_per_page_pixel(webview_id)
879 }
880
881 pub(crate) fn shutdown_state(&self) -> ShutdownState {
882 self.shutdown_state.get()
883 }
884
885 pub fn request_screenshot(
886 &self,
887 webview_id: WebViewId,
888 rect: Option<WebViewRect>,
889 callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
890 ) {
891 self.painter(webview_id.into())
892 .request_screenshot(webview_id, rect, callback);
893 }
894
895 pub fn notify_input_event_handled(
896 &self,
897 webview_id: WebViewId,
898 input_event_id: InputEventId,
899 result: InputEventResult,
900 ) {
901 if let Some(mut painter) = self.maybe_painter_mut(webview_id.into()) {
902 painter.notify_input_event_handled(webview_id, input_event_id, result);
903 }
904 }
905
906 fn handle_generate_image_key(
911 &self,
912 webview_id: WebViewId,
913 result_sender: GenericSender<ImageKey>,
914 ) {
915 let painter_id = webview_id.into();
916 let image_key = self.maybe_painter(painter_id).map_or_else(
917 || ImageKey::new(painter_id.into(), 0),
918 |painter| painter.webrender_api.generate_image_key(),
919 );
920 let _ = result_sender.send(image_key);
921 }
922
923 fn handle_generate_image_keys_for_pipeline(
928 &self,
929 webview_id: WebViewId,
930 pipeline_id: PipelineId,
931 ) {
932 let painter_id = webview_id.into();
933 let painter = self.maybe_painter(painter_id);
934 let image_keys = (0..pref!(image_key_batch_size))
935 .map(|_| {
936 painter.as_ref().map_or_else(
937 || ImageKey::new(painter_id.into(), 0),
938 |painter| painter.webrender_api.generate_image_key(),
939 )
940 })
941 .collect();
942
943 let _ = self.embedder_to_constellation_sender.send(
944 EmbedderToConstellationMessage::SendImageKeysForPipeline(pipeline_id, image_keys),
945 );
946 }
947
948 fn handle_generate_font_keys(
953 &self,
954 number_of_font_keys: usize,
955 number_of_font_instance_keys: usize,
956 result_sender: GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
957 painter_id: PainterId,
958 ) {
959 let painter = self.maybe_painter(painter_id);
960 let font_keys = (0..number_of_font_keys)
961 .map(|_| {
962 painter.as_ref().map_or_else(
963 || FontKey::new(painter_id.into(), 0),
964 |painter| painter.webrender_api.generate_font_key(),
965 )
966 })
967 .collect();
968 let font_instance_keys = (0..number_of_font_instance_keys)
969 .map(|_| {
970 painter.as_ref().map_or_else(
971 || FontInstanceKey::new(painter_id.into(), 0),
972 |painter| painter.webrender_api.generate_font_instance_key(),
973 )
974 })
975 .collect();
976
977 let _ = result_sender.send((font_keys, font_instance_keys));
978 }
979}