1use std::cell::{Cell, LazyCell};
6use std::collections::hash_map::Entry;
7use std::rc::Rc;
8use std::sync::Arc;
9
10use crossbeam_channel::Sender;
11use dpi::PhysicalSize;
12use embedder_traits::{
13 InputEvent, InputEventAndId, InputEventId, InputEventResult, PaintHitTestResult,
14 ScreenshotCaptureError, Scroll, ViewportDetails, WebViewPoint, WebViewRect,
15};
16use euclid::{Point2D, Rect, Scale, Size2D};
17use gleam::gl::RENDERER;
18use image::RgbaImage;
19use log::{debug, error, info, warn};
20use media::WindowGLContext;
21use paint_api::display_list::{
22 PaintDisplayListInfo, PaintTimingInfo, PaintTimingReport, ScrollType,
23};
24use paint_api::rendering_context::RenderingContext;
25use paint_api::viewport_description::ViewportDescription;
26use paint_api::{
27 ImageUpdate, PipelineExitSource, SendableFrameTree, SerializableDisplayListPayload,
28 SerializableImageData, WebRenderExternalImageHandlers, WebRenderImageHandlerType, WebViewTrait,
29};
30use profile_traits::time::{ProfilerCategory, ProfilerChan};
31use profile_traits::time_profile;
32use rustc_hash::{FxHashMap, FxHashSet};
33use servo_base::Epoch;
34use servo_base::cross_process_instant::CrossProcessInstant;
35use servo_base::generic_channel::{GenericReceiver, GenericSharedMemory};
36use servo_base::id::{PainterId, PipelineId, WebViewId};
37use servo_base::threadboost::{BoostAffinity, ThreadPriority};
38use servo_config::{opts, pref};
39use servo_constellation_traits::{EmbedderToConstellationMessage, PaintMetricEvent};
40use servo_geometry::DeviceIndependentPixel;
41use smallvec::SmallVec;
42use style_traits::CSSPixel;
43use webrender::{
44 MemoryReport, ONE_TIME_USAGE_HINT, RenderApi, RenderBackendHooks, SceneBuilderHooks,
45 ShaderPrecacheFlags, Transaction, UploadMethod,
46};
47use webrender_api::units::{
48 DevicePixel, DevicePoint, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D,
49 WorldPoint,
50};
51use webrender_api::{
52 self, BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DirtyRect, DisplayListPayload,
53 DocumentId, DynamicProperties, Epoch as WebRenderEpoch, ExternalScrollId, FontInstanceFlags,
54 FontInstanceKey, FontInstanceOptions, FontInstancePlatformOptions, FontKey, FontVariation,
55 ImageData, ImageKey, NativeFontHandle, PipelineId as WebRenderPipelineId, PropertyBinding,
56 ReferenceFrameKind, RenderReasons, SampledScrollOffset, SpaceAndClipInfo, SpatialId,
57 TransformStyle,
58};
59use wr_malloc_size_of::MallocSizeOfOps;
60
61use crate::Paint;
62use crate::paint::{RepaintReason, WebRenderDebugOption};
63use crate::refresh_driver::{AnimationRefreshDriverObserver, BaseRefreshDriver};
64use crate::render_notifier::RenderNotifier;
65use crate::screenshot::ScreenshotTaker;
66use crate::web_content_animation::WebContentAnimator;
67#[cfg(feature = "webgl")]
68use crate::webrender_external_images::WebGLExternalImages;
69use crate::webview_renderer::{PinchZoomResult, ScrollResult, UnknownWebView, WebViewRenderer};
70
71pub(crate) struct Painter {
81 pub(crate) rendering_context: Rc<dyn RenderingContext>,
83
84 pub(crate) painter_id: PainterId,
86
87 pub(crate) webview_renderers: FxHashMap<WebViewId, WebViewRenderer>,
89
90 pub(crate) needs_repaint: Cell<RepaintReason>,
92
93 pub(crate) pending_frames: Cell<usize>,
95
96 refresh_driver: Rc<BaseRefreshDriver>,
98
99 animation_refresh_driver_observer: Rc<AnimationRefreshDriverObserver>,
101
102 pub(crate) webrender_api: RenderApi,
104
105 pub(crate) webrender_document: DocumentId,
107
108 pub(crate) webrender_renderer: Option<webrender::Renderer>,
110
111 webrender_gl: Rc<dyn gleam::gl::Gl>,
113
114 pub(crate) last_mouse_move_position: Option<DevicePoint>,
117
118 pub(crate) screenshot_taker: ScreenshotTaker,
120
121 pub(crate) frame_delayer: FrameDelayer,
125
126 embedder_to_constellation_sender: Sender<EmbedderToConstellationMessage>,
128
129 animation_image_cache: FxHashMap<ImageKey, Arc<Vec<u8>>>,
132
133 web_content_animator: WebContentAnimator,
136}
137
138impl Drop for Painter {
139 fn drop(&mut self) {
140 if let Err(error) = self.rendering_context.make_current() {
141 error!("Failed to make the rendering context current: {error:?}");
142 }
143
144 self.webrender_api.stop_render_backend();
145 self.webrender_api.shut_down(true);
146
147 if let Some(renderer) = self.webrender_renderer.take() {
148 renderer.deinit();
149 }
150 }
151}
152
153impl Painter {
154 pub(crate) fn new(rendering_context: Rc<dyn RenderingContext>, paint: &Paint) -> Self {
155 let webrender_gl = rendering_context.gleam_gl_api();
156
157 if let Err(err) = rendering_context.make_current() {
159 warn!("Failed to make the rendering context current: {:?}", err);
160 }
161 debug_assert_eq!(webrender_gl.get_error(), gleam::gl::NO_ERROR,);
162
163 let id_manager = paint.webrender_external_image_id_manager();
164 let mut external_image_handlers = Box::new(WebRenderExternalImageHandlers::new(id_manager));
165
166 #[cfg(feature = "webgl")]
168 {
169 let image_handler = Box::new(WebGLExternalImages::new(
170 paint.webgl_threads(),
171 rendering_context.clone(),
172 paint.webgl_paint.swap_chains.clone(),
173 paint.webgl_paint.busy_webgl_contexts_map.clone(),
174 ));
175 external_image_handlers.set_handler(image_handler, WebRenderImageHandlerType::WebGl);
176 }
177
178 #[cfg(feature = "webgpu")]
179 external_image_handlers.set_handler(
180 Box::new(webgpu::WebGpuExternalImages::new(paint.webgpu_image_map())),
181 WebRenderImageHandlerType::WebGpu,
182 );
183
184 WindowGLContext::initialize_image_handler(&mut external_image_handlers);
185
186 let embedder_to_constellation_sender = paint.embedder_to_constellation_sender.clone();
187 let timer_refresh_driver = LazyCell::default();
188 let refresh_driver = Rc::new(BaseRefreshDriver::new(
189 paint.event_loop_waker.clone_box(),
190 rendering_context.refresh_driver(),
191 &timer_refresh_driver,
192 ));
193 let animation_refresh_driver_observer = Rc::new(AnimationRefreshDriverObserver::new(
194 embedder_to_constellation_sender.clone(),
195 ));
196
197 rendering_context.prepare_for_rendering();
198 let clear_color = servo_config::pref!(shell_background_color_rgba);
199 let clear_color = ColorF::new(
200 clear_color[0] as f32,
201 clear_color[1] as f32,
202 clear_color[2] as f32,
203 clear_color[3] as f32,
204 );
205
206 let upload_method = if webrender_gl.get_string(RENDERER).starts_with("ANGLE") {
209 UploadMethod::Immediate
210 } else {
211 UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT)
212 };
213 let worker_threads = std::thread::available_parallelism()
214 .map(|i| i.get())
215 .unwrap_or(pref!(thread_pool_fallback_workers) as usize)
216 .min(pref!(thread_pool_webrender_workers_max).max(1) as usize);
217 let workers = Some(Arc::new(
218 rayon::ThreadPoolBuilder::new()
219 .num_threads(worker_threads)
220 .thread_name(|idx| format!("WRWorker#{}", idx))
221 .start_handler(|_| {
222 servo_base::threadboost::boost_thread(
223 ThreadPriority::Elevated,
224 BoostAffinity::Boost,
225 )
226 })
227 .build()
228 .expect("Unable to initialize WebRender worker pool."),
229 ));
230
231 let painter_id = PainterId::next();
232 let (mut webrender_renderer, webrender_api_sender) = webrender::create_webrender_instance(
233 webrender_gl.clone(),
234 Box::new(RenderNotifier::new(painter_id, paint.paint_proxy.clone())),
235 webrender::WebRenderOptions {
236 use_optimized_shaders: true,
241 resource_override_path: opts::get().shaders_path.clone(),
242 debug_flags: webrender::DebugFlags::empty(),
243 precache_flags: if pref!(gfx_precache_shaders) {
244 ShaderPrecacheFlags::FULL_COMPILE
245 } else {
246 ShaderPrecacheFlags::empty()
247 },
248 enable_aa: pref!(gfx_text_antialiasing_enabled),
249 enable_subpixel_aa: pref!(gfx_subpixel_text_antialiasing_enabled),
250 allow_texture_swizzling: pref!(gfx_texture_swizzling_enabled),
251 enable_dithering: true,
252 clear_color,
253 upload_method,
254 workers,
255 size_of_op: Some(servo_allocator::usable_size),
256 namespace_alloc_by_client: true,
259 render_backend_hooks: Some(Box::new(BoostWebRenderThread)),
260 scene_builder_hooks: Some(Box::new(BoostWebRenderThread)),
261 shared_font_namespace: Some(painter_id.into()),
262 ..Default::default()
263 },
264 None,
265 )
266 .expect("Unable to initialize WebRender.");
267
268 webrender_renderer.set_external_image_handler(external_image_handlers);
269
270 let webrender_api = webrender_api_sender.create_api_by_client(painter_id.into());
271 let webrender_document = webrender_api.add_document(rendering_context.size2d().to_i32());
272
273 let gl_renderer = webrender_gl.get_string(gleam::gl::RENDERER);
274 let gl_version = webrender_gl.get_string(gleam::gl::VERSION);
275 info!("Running on {gl_renderer} with OpenGL version {gl_version}");
276
277 let painter = Painter {
278 painter_id,
279 embedder_to_constellation_sender,
280 webview_renderers: Default::default(),
281 rendering_context,
282 needs_repaint: Cell::default(),
283 pending_frames: Default::default(),
284 screenshot_taker: Default::default(),
285 refresh_driver,
286 animation_refresh_driver_observer,
287 webrender_renderer: Some(webrender_renderer),
288 webrender_api,
289 webrender_document,
290 webrender_gl,
291 last_mouse_move_position: None,
292 frame_delayer: Default::default(),
293 animation_image_cache: FxHashMap::default(),
294 web_content_animator: WebContentAnimator::new(
295 paint.event_loop_waker.clone_box(),
296 (*timer_refresh_driver).clone(),
297 ),
298 };
299 painter.assert_gl_framebuffer_complete();
300 painter.clear_background();
301 painter
302 }
303
304 pub(crate) fn perform_updates(&mut self) {
305 let mut need_zoom = false;
306 let scroll_offset_updates: Vec<_> = self
307 .webview_renderers
308 .values_mut()
309 .filter_map(|webview_renderer| {
310 let (zoom, scroll_result) = webview_renderer
311 .process_pending_scroll_and_pinch_zoom_events(&self.webrender_api);
312 need_zoom = need_zoom || (zoom == PinchZoomResult::DidPinchZoom);
313 scroll_result
314 })
315 .collect();
316
317 self.send_zoom_and_scroll_offset_updates(need_zoom, scroll_offset_updates);
318
319 if let Some(colors) = self.web_content_animator.update(&self.webview_renderers) {
320 let mut transaction = Transaction::new();
321 transaction.reset_dynamic_properties();
322 transaction.append_dynamic_properties(DynamicProperties {
323 transforms: Vec::new(),
324 floats: Vec::new(),
325 colors,
326 });
327 self.generate_frame(&mut transaction, RenderReasons::ANIMATED_PROPERTY);
328 self.send_transaction(transaction);
329 }
330 }
331
332 #[track_caller]
333 fn assert_no_gl_error(&self) {
334 debug_assert_eq!(self.webrender_gl.get_error(), gleam::gl::NO_ERROR);
335 }
336
337 #[track_caller]
338 fn assert_gl_framebuffer_complete(&self) {
339 debug_assert_eq!(
340 (
341 self.webrender_gl.get_error(),
342 self.webrender_gl
343 .check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
344 ),
345 (gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
346 );
347 }
348
349 pub(crate) fn webview_renderer(&self, webview_id: WebViewId) -> Option<&WebViewRenderer> {
350 self.webview_renderers.get(&webview_id)
351 }
352
353 pub(crate) fn webview_renderer_mut(
354 &mut self,
355 webview_id: WebViewId,
356 ) -> Option<&mut WebViewRenderer> {
357 self.webview_renderers.get_mut(&webview_id)
358 }
359
360 pub(crate) fn has_pending_frames(&self) -> bool {
364 self.pending_frames.get() != 0 || self.frame_delayer.pending_frame
365 }
366
367 pub(crate) fn set_needs_repaint(&self, reason: RepaintReason) {
368 let mut needs_repaint = self.needs_repaint.get();
369 needs_repaint.insert(reason);
370 self.needs_repaint.set(needs_repaint);
371 }
372
373 pub(crate) fn needs_repaint(&self) -> bool {
374 let repaint_reason = self.needs_repaint.get();
375 if repaint_reason.is_empty() {
376 return false;
377 }
378
379 !self.refresh_driver.wait_to_paint()
380 }
381
382 pub(crate) fn animation_callbacks_running(&self) -> bool {
384 self.webview_renderers
385 .values()
386 .any(WebViewRenderer::animation_callbacks_running)
387 }
388
389 pub(crate) fn animating_webviews(&self) -> Vec<WebViewId> {
390 self.webview_renderers
391 .values()
392 .filter_map(|webview_renderer| {
393 if webview_renderer.animating() {
394 Some(webview_renderer.id)
395 } else {
396 None
397 }
398 })
399 .collect()
400 }
401
402 pub(crate) fn send_to_constellation(&self, message: EmbedderToConstellationMessage) {
403 if let Err(error) = self.embedder_to_constellation_sender.send(message) {
404 warn!("Could not send message to constellation ({error:?})");
405 }
406 }
407
408 #[servo_tracing::instrument(skip_all)]
409 pub(crate) fn render(&mut self, time_profiler_channel: &ProfilerChan) {
410 let refresh_driver = self.refresh_driver.clone();
411 refresh_driver.notify_will_paint(self);
412
413 if let Err(error) = self.rendering_context.make_current() {
414 error!("Failed to make the rendering context current: {error:?}");
415 }
416 self.assert_no_gl_error();
417
418 self.rendering_context.prepare_for_rendering();
419
420 time_profile!(
421 ProfilerCategory::Painting,
422 None,
423 time_profiler_channel.clone(),
424 || {
425 if let Some(renderer) = self.webrender_renderer.as_mut() {
426 renderer.update();
427 }
428
429 self.clear_background();
432 if let Some(renderer) = self.webrender_renderer.as_mut() {
433 let size = self.rendering_context.size2d().to_i32();
434 renderer.render(size, 0 ).ok();
435 }
436 }
437 );
438
439 self.needs_repaint.set(RepaintReason::empty());
442
443 self.screenshot_taker.maybe_take_screenshots(self);
444 self.send_pending_paint_metrics_messages_after_composite();
445 }
446
447 fn clear_background(&self) {
448 self.assert_gl_framebuffer_complete();
449
450 let color = servo_config::pref!(shell_background_color_rgba);
454 self.webrender_gl.clear_color(
455 color[0] as f32,
456 color[1] as f32,
457 color[2] as f32,
458 color[3] as f32,
459 );
460 self.webrender_gl.clear(gleam::gl::COLOR_BUFFER_BIT);
461 }
462
463 fn send_pending_paint_metrics_messages_after_composite(&mut self) {
471 let paint_time = CrossProcessInstant::now();
480 let mut paint_metric_events = Vec::new();
481
482 for webview_renderer in self.webview_renderers.values_mut() {
483 for (pipeline_id, pipeline) in webview_renderer.pipelines.iter_mut() {
484 let Some(current_epoch) = self
485 .webrender_renderer
486 .as_ref()
487 .and_then(|wr| wr.current_epoch(self.webrender_document, pipeline_id.into()))
488 else {
489 continue;
490 };
491
492 match pipeline.first_paint_metric {
493 PaintMetricState::Seen(epoch, first_reflow, paint_timing_info)
498 if epoch <= current_epoch =>
499 {
500 assert!(epoch <= current_epoch);
501 #[cfg(feature = "tracing")]
502 tracing::info!(
503 name: "FirstPaint",
504 servo_profiling = true,
505 epoch = ?epoch,
506 paint_time = ?paint_time,
507 pipeline_id = ?pipeline_id,
508 );
509
510 paint_metric_events.push((
511 *pipeline_id,
512 PaintMetricEvent::FirstPaint(
513 paint_timing_info.with_presentation_time(paint_time),
514 first_reflow,
515 ),
516 ));
517
518 pipeline.first_paint_metric = PaintMetricState::Sent;
519 },
520 _ => {},
521 }
522
523 match pipeline.first_contentful_paint_metric {
524 PaintMetricState::Seen(epoch, first_reflow, paint_timing_info)
525 if epoch <= current_epoch =>
526 {
527 #[cfg(feature = "tracing")]
528 tracing::info!(
529 name: "FirstContentfulPaint",
530 servo_profiling = true,
531 epoch = ?epoch,
532 paint_time = ?paint_time,
533 pipeline_id = ?pipeline_id,
534 );
535 paint_metric_events.push((
536 *pipeline_id,
537 PaintMetricEvent::FirstContentfulPaint(
538 paint_timing_info.with_presentation_time(paint_time),
539 first_reflow,
540 ),
541 ));
542 pipeline.first_contentful_paint_metric = PaintMetricState::Sent;
543 },
544 _ => {},
545 }
546
547 let pending_lcp_candidates = &mut pipeline.lcp_candidates;
548 while let Some((epoch, (id, area), paint_timing_info)) =
549 pending_lcp_candidates.pop_front()
550 {
551 if epoch > current_epoch {
552 pending_lcp_candidates.push_front((epoch, (id, area), paint_timing_info));
553 break;
554 }
555 #[cfg(feature = "tracing")]
556 tracing::info!(
557 name: "LargestContentfulPaint",
558 servo_profiling = true,
559 paint_time = ?paint_time,
560 area = ?area,
561 pipeline_id = ?pipeline_id,
562 );
563 paint_metric_events.push((
564 *pipeline_id,
565 PaintMetricEvent::LargestContentfulPaint(
566 paint_timing_info.with_presentation_time(paint_time),
567 id,
568 ),
569 ));
570 }
571
572 let pending_container_timing = &mut pipeline.container_timing_candidates;
573 while let Some((epoch, ids)) = pending_container_timing.pop_front() {
574 if epoch > current_epoch {
575 pending_container_timing.push_front((epoch, ids));
576 break;
577 }
578 #[cfg(feature = "tracing")]
579 tracing::info!(
580 name: "ContainerTiming",
581 servo_profiling = true,
582 paint_time = ?paint_time,
583 count = ids.len(),
584 pipeline_id = ?pipeline_id,
585 );
586 paint_metric_events.push((
587 *pipeline_id,
588 PaintMetricEvent::ContainerTiming(paint_time, ids),
589 ));
590 }
591 }
592 }
593
594 for (pipeline_id, event) in paint_metric_events {
595 self.send_to_constellation(EmbedderToConstellationMessage::PaintMetric(
596 pipeline_id,
597 event,
598 ));
599 }
600 }
601
602 pub(crate) fn generate_frame(&self, transaction: &mut Transaction, reason: RenderReasons) {
604 transaction.generate_frame(0, true , false , reason);
605 self.pending_frames.set(self.pending_frames.get() + 1);
606 }
607
608 pub(crate) fn hit_test_at_point_with_api_and_document(
609 webrender_api: &RenderApi,
610 webrender_document: DocumentId,
611 point: DevicePoint,
612 ) -> Vec<PaintHitTestResult> {
613 let world_point = WorldPoint::from_untyped(point.to_untyped());
615 let results = webrender_api.hit_test(webrender_document, world_point);
616
617 results
618 .items
619 .iter()
620 .map(|item| {
621 let pipeline_id = item.pipeline.into();
622 let external_scroll_id = ExternalScrollId(item.tag.0, item.pipeline);
623 PaintHitTestResult {
624 pipeline_id,
625 point_in_viewport: Point2D::from_untyped(item.point_in_viewport.to_untyped()),
626 external_scroll_id,
627 }
628 })
629 .collect()
630 }
631
632 pub(crate) fn send_transaction(&mut self, transaction: Transaction) {
633 let _ = self.rendering_context.make_current();
634 self.webrender_api
635 .send_transaction(self.webrender_document, transaction);
636 }
637
638 fn send_root_pipeline_display_list_in_transaction(&self, transaction: &mut Transaction) {
642 let root_pipeline = WebRenderPipelineId(0, 1);
646 transaction.set_root_pipeline(root_pipeline);
647
648 let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline);
649 builder.begin();
650
651 let root_reference_frame = SpatialId::root_reference_frame(root_pipeline);
652
653 let viewport_size = self.rendering_context.size2d().to_f32().to_untyped();
654 let viewport_rect = LayoutRect::from_origin_and_size(
655 LayoutPoint::zero(),
656 LayoutSize::from_untyped(viewport_size),
657 );
658
659 let root_clip_id = builder.define_clip_rect(root_reference_frame, viewport_rect);
660 let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
661 for webview_renderer in self.webview_renderers.values() {
662 if webview_renderer.hidden() {
663 continue;
664 }
665 let Some(pipeline_id) = webview_renderer.root_pipeline_id else {
666 continue;
667 };
668
669 let pinch_zoom_transform = webview_renderer.pinch_zoom().transform().to_untyped();
670 let device_pixels_per_page_pixel_not_including_pinch_zoom = webview_renderer
671 .device_pixels_per_page_pixel_not_including_pinch_zoom()
672 .get();
673
674 let transform = LayoutTransform::scale(
675 device_pixels_per_page_pixel_not_including_pinch_zoom,
676 device_pixels_per_page_pixel_not_including_pinch_zoom,
677 1.0,
678 )
679 .then(&LayoutTransform::from_untyped(
680 &pinch_zoom_transform.to_3d(),
681 ));
682
683 let webview_reference_frame = builder.push_reference_frame(
684 LayoutPoint::zero(),
685 root_reference_frame,
686 TransformStyle::Flat,
687 PropertyBinding::Value(transform),
688 ReferenceFrameKind::Transform {
689 is_2d_scale_translation: true,
690 should_snap: true,
691 paired_with_perspective: false,
692 },
693 );
694
695 let scaled_webview_rect = webview_renderer.rect /
696 webview_renderer.device_pixels_per_page_pixel_not_including_pinch_zoom();
697 builder.push_iframe(
698 LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
699 LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
700 &SpaceAndClipInfo {
701 spatial_id: webview_reference_frame,
702 clip_chain_id,
703 },
704 pipeline_id.into(),
705 true,
706 );
707 }
708
709 let built_display_list = builder.end();
710
711 transaction.set_display_list(WebRenderEpoch(0), built_display_list);
715 self.update_transaction_with_all_scroll_offsets(transaction);
716 }
717
718 fn send_root_pipeline_display_list(&mut self) {
722 let mut transaction = Transaction::new();
723 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
724 self.generate_frame(&mut transaction, RenderReasons::SCENE);
725 self.send_transaction(transaction);
726 }
727
728 fn update_transaction_with_all_scroll_offsets(&self, transaction: &mut Transaction) {
737 for webview_renderer in self.webview_renderers.values() {
738 for details in webview_renderer.pipelines.values() {
739 for node in details.scroll_tree.nodes.iter() {
740 let (Some(offset), Some(external_id)) = (node.offset(), node.external_id())
741 else {
742 continue;
743 };
744 if offset == LayoutVector2D::zero() {
746 continue;
747 }
748 transaction.set_scroll_offsets(
749 external_id,
750 vec![SampledScrollOffset {
751 offset,
752 generation: 0,
753 }],
754 );
755 }
756 }
757 }
758 }
759
760 fn send_zoom_and_scroll_offset_updates(
761 &mut self,
762 need_zoom: bool,
763 scroll_offset_updates: Vec<ScrollResult>,
764 ) {
765 if !need_zoom && scroll_offset_updates.is_empty() {
766 return;
767 }
768
769 let mut transaction = Transaction::new();
770 if need_zoom {
771 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
772 }
773 for update in scroll_offset_updates {
774 transaction.set_scroll_offsets(
775 update.external_scroll_id,
776 vec![SampledScrollOffset {
777 offset: update.offset,
778 generation: 0,
779 }],
780 );
781 }
782
783 self.generate_frame(&mut transaction, RenderReasons::APZ);
784 self.send_transaction(transaction);
785 }
786
787 pub(crate) fn toggle_webrender_debug(&mut self, option: WebRenderDebugOption) {
788 let Some(renderer) = self.webrender_renderer.as_mut() else {
789 return;
790 };
791 let mut flags = renderer.get_debug_flags();
792 let flag = match option {
793 WebRenderDebugOption::Profiler => {
794 webrender::DebugFlags::PROFILER_DBG |
795 webrender::DebugFlags::GPU_TIME_QUERIES |
796 webrender::DebugFlags::GPU_SAMPLE_QUERIES
797 },
798 WebRenderDebugOption::TextureCacheDebug => webrender::DebugFlags::TEXTURE_CACHE_DBG,
799 WebRenderDebugOption::RenderTargetDebug => webrender::DebugFlags::RENDER_TARGET_DBG,
800 };
801 flags.toggle(flag);
802 renderer.set_debug_flags(flags);
803
804 let mut txn = Transaction::new();
805 self.generate_frame(&mut txn, RenderReasons::TESTING);
806 self.send_transaction(txn);
807 }
808
809 pub(crate) fn decrement_pending_frames(&self) {
810 self.pending_frames.set(self.pending_frames.get() - 1);
811 }
812
813 pub(crate) fn report_memory(&self) -> MemoryReport {
814 self.webrender_api
815 .report_memory(MallocSizeOfOps::new(servo_allocator::usable_size, None))
816 }
817
818 pub(crate) fn change_running_animations_state(
819 &mut self,
820 webview_id: WebViewId,
821 pipeline_id: PipelineId,
822 animation_state: embedder_traits::AnimationState,
823 ) {
824 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
825 return;
826 };
827 if !webview_renderer.change_pipeline_running_animations_state(pipeline_id, animation_state)
828 {
829 return;
830 }
831 if !self
832 .animation_refresh_driver_observer
833 .notify_animation_state_changed(webview_renderer)
834 {
835 return;
836 }
837
838 self.refresh_driver
839 .add_observer(self.animation_refresh_driver_observer.clone());
840 }
841
842 pub(crate) fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) {
843 debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
844
845 let webview_id = frame_tree.pipeline.webview_id;
846 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
847 warn!(
848 "Attempted to set frame tree on unknown WebView (perhaps closed?): {webview_id:?}"
849 );
850 return;
851 };
852
853 webview_renderer.set_frame_tree(frame_tree);
854 self.send_root_pipeline_display_list();
855 }
856
857 pub(crate) fn set_throttled(
858 &mut self,
859 webview_id: WebViewId,
860 pipeline_id: PipelineId,
861 throttled: bool,
862 ) {
863 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
864 return;
865 };
866 if !webview_renderer.set_throttled(pipeline_id, throttled) {
867 return;
868 }
869
870 if self
871 .animation_refresh_driver_observer
872 .notify_animation_state_changed(webview_renderer)
873 {
874 self.refresh_driver
875 .add_observer(self.animation_refresh_driver_observer.clone());
876 }
877 }
878
879 pub(crate) fn notify_pipeline_exited(
880 &mut self,
881 webview_id: WebViewId,
882 pipeline_id: PipelineId,
883 pipeline_exit_source: PipelineExitSource,
884 ) {
885 debug!("Paint got pipeline exited: {webview_id:?} {pipeline_id:?}",);
886 let fully_exited =
887 self.webview_renderers
888 .get_mut(&webview_id)
889 .is_some_and(|webview_renderer| {
890 webview_renderer.pipeline_exited(pipeline_id, pipeline_exit_source)
891 });
892
893 if fully_exited {
898 let mut transaction = Transaction::new();
899 transaction.remove_pipeline(pipeline_id.into());
900 self.send_transaction(transaction);
901 }
902 }
903
904 pub(crate) fn send_initial_pipeline_transaction(
905 &mut self,
906 webview_id: WebViewId,
907 pipeline_id: WebRenderPipelineId,
908 ) {
909 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
910 return warn!("Could not find WebView for incoming display list");
911 };
912
913 let starting_epoch = Epoch(0);
914 let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
915 details.display_list_epoch = Some(starting_epoch);
916
917 let mut txn = Transaction::new();
918 txn.set_display_list(starting_epoch.into(), (pipeline_id, Default::default()));
919
920 self.generate_frame(&mut txn, RenderReasons::SCENE);
921 self.send_transaction(txn);
922 }
923
924 pub(crate) fn scroll_node_by_delta(
925 &mut self,
926 webview_id: WebViewId,
927 pipeline_id: WebRenderPipelineId,
928 offset: LayoutVector2D,
929 external_scroll_id: webrender_api::ExternalScrollId,
930 ) {
931 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
932 return;
933 };
934
935 let pipeline_id = pipeline_id.into();
936 let Some(pipeline_details) = webview_renderer.pipelines.get_mut(&pipeline_id) else {
937 return;
938 };
939
940 let Some(offset) = pipeline_details
941 .scroll_tree
942 .set_scroll_offset_for_node_with_external_scroll_id(
943 external_scroll_id,
944 offset,
945 ScrollType::Script,
946 )
947 else {
948 warn!("Could not scroll node with id: {external_scroll_id:?}");
951 return;
952 };
953
954 let mut transaction = Transaction::new();
955 transaction.set_scroll_offsets(
956 external_scroll_id,
957 vec![SampledScrollOffset {
958 offset,
959 generation: 0,
960 }],
961 );
962
963 self.generate_frame(&mut transaction, RenderReasons::APZ);
964 self.send_transaction(transaction);
965 }
966
967 pub(crate) fn scroll_viewport_by_delta(
968 &mut self,
969 webview_id: WebViewId,
970 delta: LayoutVector2D,
971 ) {
972 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
973 return;
974 };
975 let (pinch_zoom_result, scroll_results) = webview_renderer.scroll_viewport_by_delta(delta);
976 self.send_zoom_and_scroll_offset_updates(
977 pinch_zoom_result == PinchZoomResult::DidPinchZoom,
978 scroll_results,
979 );
980 }
981
982 pub(crate) fn update_epoch(
983 &mut self,
984 webview_id: WebViewId,
985 pipeline_id: PipelineId,
986 epoch: Epoch,
987 ) {
988 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
989 return warn!("Could not find WebView for Epoch update.");
990 };
991 webview_renderer
992 .ensure_pipeline_details(pipeline_id)
993 .display_list_epoch = Some(Epoch(epoch.0));
994 }
995
996 #[servo_tracing::instrument(skip_all)]
997 pub(crate) fn handle_new_display_list(
998 &mut self,
999 webview_id: WebViewId,
1000 display_list_descriptor: BuiltDisplayListDescriptor,
1001 display_list_info_receiver: GenericReceiver<PaintDisplayListInfo>,
1002 display_list_data_receiver: GenericReceiver<SerializableDisplayListPayload>,
1003 ) {
1004 let Ok(display_list_info) = display_list_info_receiver.recv() else {
1005 return log::error!("Could not receive display list info");
1006 };
1007 let Ok(display_list_data) = display_list_data_receiver.recv() else {
1008 return log::error!("Could not receive display list data");
1009 };
1010
1011 let items_data = display_list_data.items_data;
1012 let spatial_tree = display_list_data.spatial_tree;
1013
1014 let built_display_list = BuiltDisplayList::from_data(
1015 DisplayListPayload {
1016 items_data,
1017 spatial_tree,
1018 },
1019 display_list_descriptor,
1020 );
1021 let _span = profile_traits::trace_span!("PaintMessage::SendDisplayList").entered();
1022 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
1023 return warn!("Could not find WebView for incoming display list");
1024 };
1025
1026 let old_scale = webview_renderer.device_pixels_per_page_pixel();
1027 let pipeline_id = display_list_info.pipeline_id;
1028 let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
1029
1030 details.install_new_scroll_tree(display_list_info.scroll_tree);
1031 details.viewport_scale = Some(display_list_info.viewport_details.hidpi_scale_factor);
1032
1033 let epoch = display_list_info.epoch.into();
1034 let first_reflow = display_list_info.first_reflow;
1035 if details.first_paint_metric == PaintMetricState::Waiting &&
1036 display_list_info
1037 .paint_timing_report
1038 .contains(PaintTimingReport::FirstPaint)
1039 {
1040 details.first_paint_metric =
1041 PaintMetricState::Seen(epoch, first_reflow, display_list_info.paint_timing_info);
1042 }
1043
1044 if details.first_contentful_paint_metric == PaintMetricState::Waiting &&
1045 display_list_info
1046 .paint_timing_report
1047 .contains(PaintTimingReport::FirstContentfulPaint)
1048 {
1049 details.first_contentful_paint_metric =
1050 PaintMetricState::Seen(epoch, first_reflow, display_list_info.paint_timing_info);
1051 }
1052
1053 if let Some(lcp_candidate) = display_list_info.lcp_candidate {
1054 details.lcp_candidates.push_back((
1055 epoch,
1056 lcp_candidate,
1057 display_list_info.paint_timing_info,
1058 ));
1059 }
1060
1061 let container_timing_candidates = display_list_info.container_timing_candidates;
1062 if !container_timing_candidates.is_empty() {
1063 details
1064 .container_timing_candidates
1065 .push_back((epoch, container_timing_candidates));
1066 }
1067
1068 details.animations.handle_new_display_list(
1069 display_list_info.caret_property_binding,
1070 &self.web_content_animator,
1071 );
1072
1073 let mut transaction = Transaction::new();
1074 let is_root_pipeline = Some(pipeline_id.into()) == webview_renderer.root_pipeline_id;
1075 if is_root_pipeline && old_scale != webview_renderer.device_pixels_per_page_pixel() {
1076 self.send_root_pipeline_display_list_in_transaction(&mut transaction);
1077 }
1078
1079 transaction.set_display_list(epoch, (pipeline_id, built_display_list));
1080
1081 self.update_transaction_with_all_scroll_offsets(&mut transaction);
1082 self.send_transaction(transaction);
1083 }
1084
1085 pub(crate) fn generate_frame_for_script(&mut self) {
1086 self.frame_delayer.set_pending_frame(true);
1087
1088 if !self.frame_delayer.needs_new_frame() {
1089 return;
1090 }
1091
1092 let mut transaction = Transaction::new();
1093 self.generate_frame(&mut transaction, RenderReasons::SCENE);
1094 self.send_transaction(transaction);
1095
1096 let waiting_pipelines = self.frame_delayer.take_waiting_pipelines();
1097
1098 self.send_to_constellation(
1099 EmbedderToConstellationMessage::NoLongerWaitingOnAsynchronousImageUpdates(
1100 waiting_pipelines,
1101 ),
1102 );
1103
1104 self.frame_delayer.set_pending_frame(false);
1105 self.screenshot_taker
1106 .prepare_screenshot_requests_for_render(self)
1107 }
1108
1109 fn serializable_image_data_to_image_data_maybe_caching(
1110 &mut self,
1111 key: ImageKey,
1112 data: SerializableImageData,
1113 is_animated_image: bool,
1114 ) -> ImageData {
1115 match data {
1116 SerializableImageData::Raw(shared_memory) => {
1117 let data = shared_memory.into_arc_vec();
1118 if is_animated_image {
1119 self.animation_image_cache.insert(key, Arc::clone(&data));
1120 }
1121 ImageData::Raw(data)
1122 },
1123 SerializableImageData::External(image) => ImageData::External(image),
1124 }
1125 }
1126
1127 pub(crate) fn update_images(&mut self, updates: SmallVec<[ImageUpdate; 1]>) {
1128 let mut txn = Transaction::new();
1129 for update in updates {
1130 match update {
1131 ImageUpdate::AddImage(key, description, data, is_animated_image) => {
1132 txn.add_image(
1133 key,
1134 description,
1135 self.serializable_image_data_to_image_data_maybe_caching(
1136 key,
1137 data,
1138 is_animated_image,
1139 ),
1140 None,
1141 );
1142 },
1143 ImageUpdate::DeleteImage(key) => {
1144 txn.delete_image(key);
1145 self.frame_delayer.delete_image(key);
1146 self.animation_image_cache.remove(&key);
1147 },
1148 ImageUpdate::UpdateImage(key, desc, data, epoch) => {
1149 if let Some(epoch) = epoch {
1150 self.frame_delayer.update_image(key, epoch);
1151 }
1152 txn.update_image(key, desc, data.into(), &DirtyRect::All)
1153 },
1154 ImageUpdate::UpdateImageForAnimation(image_key, desc) => {
1155 let Some(image) = self.animation_image_cache.get(&image_key) else {
1156 error!("Could not find image key in image cache.");
1157 continue;
1158 };
1159 txn.update_image(
1160 image_key,
1161 desc,
1162 ImageData::new_shared(image.clone()),
1163 &DirtyRect::All,
1164 );
1165 },
1166 }
1167 }
1168
1169 if self.frame_delayer.needs_new_frame() {
1170 self.frame_delayer.set_pending_frame(false);
1171 self.generate_frame(&mut txn, RenderReasons::SCENE);
1172 let waiting_pipelines = self.frame_delayer.take_waiting_pipelines();
1173
1174 self.send_to_constellation(
1175 EmbedderToConstellationMessage::NoLongerWaitingOnAsynchronousImageUpdates(
1176 waiting_pipelines,
1177 ),
1178 );
1179
1180 self.screenshot_taker
1181 .prepare_screenshot_requests_for_render(&*self);
1182 }
1183
1184 self.send_transaction(txn);
1185 }
1186
1187 pub(crate) fn delay_new_frames_for_canvas(
1188 &mut self,
1189 pipeline_id: PipelineId,
1190 canvas_epoch: Epoch,
1191 image_keys: Vec<ImageKey>,
1192 ) {
1193 self.frame_delayer
1194 .add_delay(pipeline_id, canvas_epoch, image_keys);
1195 }
1196
1197 pub(crate) fn add_font(
1198 &mut self,
1199 font_key: FontKey,
1200 data: Arc<GenericSharedMemory>,
1201 index: u32,
1202 ) {
1203 let mut transaction = Transaction::new();
1204 transaction.add_raw_font(font_key, (**data).into(), index);
1205 self.send_transaction(transaction);
1206 }
1207
1208 pub(crate) fn add_system_font(&mut self, font_key: FontKey, native_handle: NativeFontHandle) {
1209 let mut transaction = Transaction::new();
1210 transaction.add_native_font(font_key, native_handle);
1211 self.send_transaction(transaction);
1212 }
1213
1214 pub(crate) fn add_font_instance(
1215 &mut self,
1216 instance_key: FontInstanceKey,
1217 font_key: FontKey,
1218 size: f32,
1219 flags: FontInstanceFlags,
1220 platform_options: FontInstancePlatformOptions,
1221 variations: Vec<FontVariation>,
1222 ) {
1223 let variations = if pref!(layout_css_font_variations_enabled) {
1224 variations
1225 } else {
1226 vec![]
1227 };
1228
1229 let mut transaction = Transaction::new();
1230
1231 let font_instance_options = FontInstanceOptions {
1232 flags,
1233 ..Default::default()
1234 };
1235 transaction.add_font_instance(
1236 instance_key,
1237 font_key,
1238 size,
1239 Some(font_instance_options),
1240 Some(platform_options),
1241 variations,
1242 );
1243
1244 self.send_transaction(transaction);
1245 }
1246
1247 pub(crate) fn remove_fonts(&mut self, keys: Vec<FontKey>, instance_keys: Vec<FontInstanceKey>) {
1248 let mut transaction = Transaction::new();
1249
1250 for instance in instance_keys.into_iter() {
1251 transaction.delete_font_instance(instance);
1252 }
1253 for key in keys.into_iter() {
1254 transaction.delete_font(key);
1255 }
1256
1257 self.send_transaction(transaction);
1258 }
1259
1260 pub(crate) fn set_viewport_description(
1261 &mut self,
1262 webview_id: WebViewId,
1263 viewport_description: ViewportDescription,
1264 ) {
1265 if let Some(webview) = self.webview_renderers.get_mut(&webview_id) {
1266 webview.set_viewport_description(viewport_description);
1267 }
1268 }
1269
1270 pub(crate) fn handle_screenshot_readiness_reply(
1271 &self,
1272 webview_id: WebViewId,
1273 expected_epochs: FxHashMap<PipelineId, Epoch>,
1274 ) {
1275 self.screenshot_taker
1276 .handle_screenshot_readiness_reply(webview_id, expected_epochs, self);
1277 }
1278
1279 pub(crate) fn add_webview(
1280 &mut self,
1281 webview: Box<dyn WebViewTrait>,
1282 viewport_details: ViewportDetails,
1283 ) {
1284 self.webview_renderers
1285 .entry(webview.id())
1286 .or_insert(WebViewRenderer::new(
1287 webview,
1288 viewport_details,
1289 self.embedder_to_constellation_sender.clone(),
1290 self.refresh_driver.clone(),
1291 self.webrender_document,
1292 ));
1293 }
1294
1295 pub(crate) fn remove_webview(&mut self, webview_id: WebViewId) {
1296 let Some(webview_renderer) = self.webview_renderers.remove(&webview_id) else {
1297 warn!("Tried removing unknown WebView: {webview_id:?}");
1298 return;
1299 };
1300
1301 let mut transaction = Transaction::new();
1302 for pipeline_id in webview_renderer.pipelines.keys() {
1303 transaction.remove_pipeline(pipeline_id.into());
1304 }
1305 self.send_transaction(transaction);
1306
1307 self.send_root_pipeline_display_list();
1308 }
1309
1310 pub(crate) fn is_empty(&mut self) -> bool {
1311 self.webview_renderers.is_empty()
1312 }
1313
1314 pub(crate) fn set_webview_hidden(
1315 &mut self,
1316 webview_id: WebViewId,
1317 hidden: bool,
1318 ) -> Result<(), UnknownWebView> {
1319 debug!("Setting WebView visiblity for {webview_id:?} to hidden={hidden}");
1320 let Some(webview_renderer) = self.webview_renderer_mut(webview_id) else {
1321 return Err(UnknownWebView(webview_id));
1322 };
1323 if !webview_renderer.set_hidden(hidden) {
1324 return Ok(());
1325 }
1326 self.send_root_pipeline_display_list();
1327 Ok(())
1328 }
1329
1330 pub(crate) fn set_hidpi_scale_factor(
1331 &mut self,
1332 webview_id: WebViewId,
1333 new_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
1334 ) {
1335 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
1336 return;
1337 };
1338 if !webview_renderer.set_hidpi_scale_factor(new_scale_factor) {
1339 return;
1340 }
1341 webview_renderer.webview.notify_viewport_updated();
1342
1343 self.send_root_pipeline_display_list();
1344 self.set_needs_repaint(RepaintReason::Resize);
1345 }
1346
1347 pub(crate) fn set_screen_size(
1348 &mut self,
1349 webview_id: WebViewId,
1350 new_size: Size2D<f32, DevicePixel>,
1351 ) {
1352 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
1353 return;
1354 };
1355 webview_renderer.set_screen_size(new_size);
1356 }
1357
1358 pub(crate) fn resize_rendering_context(&mut self, new_size: PhysicalSize<u32>) {
1359 if self.rendering_context.size() == new_size {
1360 return;
1361 }
1362
1363 if let Err(error) = self.rendering_context.make_current() {
1364 error!("Failed to make the rendering context current: {error:?}");
1365 }
1366 self.rendering_context.resize(new_size);
1367
1368 let new_size = Size2D::new(new_size.width as f32, new_size.height as f32);
1369 let new_viewport_rect = Rect::from(new_size).to_box2d();
1370 for webview_renderer in self.webview_renderers.values_mut() {
1371 webview_renderer.set_rect(new_viewport_rect);
1372 webview_renderer.webview.notify_viewport_updated();
1373 }
1374
1375 let mut transaction = Transaction::new();
1376 transaction.set_document_view(new_viewport_rect.to_i32());
1377 self.send_transaction(transaction);
1378
1379 self.send_root_pipeline_display_list();
1380 self.set_needs_repaint(RepaintReason::Resize);
1381 }
1382
1383 pub(crate) fn set_page_zoom(&mut self, webview_id: WebViewId, new_zoom: f32) {
1384 if let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) &&
1385 webview_renderer.set_page_zoom(Scale::new(new_zoom))
1386 {
1387 webview_renderer.webview.notify_viewport_updated();
1388 }
1389 }
1390
1391 pub(crate) fn page_zoom(&self, webview_id: WebViewId) -> f32 {
1392 self.webview_renderers
1393 .get(&webview_id)
1394 .map(|webview_renderer| webview_renderer.page_zoom.get())
1395 .unwrap_or(1.)
1396 }
1397
1398 pub(crate) fn notify_input_event(
1399 &mut self,
1400 webview_id: WebViewId,
1401 event: InputEventAndId,
1402 ) -> bool {
1403 self.webview_renderers
1404 .get_mut(&webview_id)
1405 .is_some_and(|webview_renderer| {
1406 match &event.event {
1407 InputEvent::MouseMove(event) => {
1408 if !event.is_compatibility_event_for_touch {
1410 let event_point = event
1411 .point
1412 .as_device_point(webview_renderer.device_pixels_per_page_pixel());
1413 self.last_mouse_move_position = Some(event_point);
1414 }
1415 },
1416 InputEvent::MouseLeftViewport(_) => {
1417 self.last_mouse_move_position = None;
1418 },
1419 _ => {},
1420 }
1421
1422 webview_renderer.notify_input_event(&self.webrender_api, &self.needs_repaint, event)
1423 })
1424 }
1425
1426 pub(crate) fn notify_scroll_event(
1427 &mut self,
1428 webview_id: WebViewId,
1429 scroll: Scroll,
1430 point: WebViewPoint,
1431 ) {
1432 if let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) {
1433 webview_renderer.notify_scroll_event(scroll, point);
1434 }
1435 }
1436
1437 pub(crate) fn adjust_pinch_zoom(
1438 &mut self,
1439 webview_id: WebViewId,
1440 pinch_zoom_delta: f32,
1441 center: DevicePoint,
1442 ) {
1443 if let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) {
1444 webview_renderer.adjust_pinch_zoom(pinch_zoom_delta, center);
1445 }
1446 }
1447
1448 pub(crate) fn pinch_zoom(&self, webview_id: WebViewId) -> f32 {
1449 self.webview_renderers
1450 .get(&webview_id)
1451 .map(|webview_renderer| webview_renderer.pinch_zoom().zoom_factor().0)
1452 .unwrap_or(1.)
1453 }
1454
1455 pub(crate) fn device_pixels_per_page_pixel(
1456 &self,
1457 webview_id: WebViewId,
1458 ) -> Scale<f32, CSSPixel, DevicePixel> {
1459 self.webview_renderers
1460 .get(&webview_id)
1461 .map(WebViewRenderer::device_pixels_per_page_pixel)
1462 .unwrap_or_default()
1463 }
1464
1465 pub(crate) fn request_screenshot(
1466 &self,
1467 webview_id: WebViewId,
1468 rect: Option<WebViewRect>,
1469 callback: Box<dyn FnOnce(Result<RgbaImage, ScreenshotCaptureError>) + 'static>,
1470 ) {
1471 let Some(webview) = self.webview_renderers.get(&webview_id) else {
1472 return;
1473 };
1474
1475 let rect = rect.map(|rect| rect.as_device_rect(webview.device_pixels_per_page_pixel()));
1476 self.screenshot_taker
1477 .request_screenshot(webview_id, rect, callback);
1478 self.send_to_constellation(EmbedderToConstellationMessage::RequestScreenshotReadiness(
1479 webview_id,
1480 ));
1481 }
1482
1483 pub(crate) fn notify_input_event_handled(
1484 &mut self,
1485 webview_id: WebViewId,
1486 input_event_id: InputEventId,
1487 result: InputEventResult,
1488 ) {
1489 let Some(webview_renderer) = self.webview_renderers.get_mut(&webview_id) else {
1490 warn!("Handled input event for unknown webview: {webview_id}");
1491 return;
1492 };
1493 webview_renderer.notify_input_event_handled(&self.needs_repaint, input_event_id, result);
1494 }
1495
1496 pub(crate) fn refresh_cursor(&self) {
1497 let Some(last_mouse_move_position) = self.last_mouse_move_position else {
1498 return;
1499 };
1500
1501 let Some(hit_test_result) = Self::hit_test_at_point_with_api_and_document(
1502 &self.webrender_api,
1503 self.webrender_document,
1504 last_mouse_move_position,
1505 )
1506 .first()
1507 .cloned() else {
1508 return;
1509 };
1510
1511 if let Err(error) = self.embedder_to_constellation_sender.send(
1512 EmbedderToConstellationMessage::RefreshCursor(hit_test_result.pipeline_id),
1513 ) {
1514 warn!("Sending event to constellation failed ({:?}).", error);
1515 }
1516 }
1517
1518 pub(crate) fn handle_new_webrender_frame_ready(&self, repaint_needed: bool) {
1519 if repaint_needed {
1520 self.refresh_cursor()
1521 }
1522
1523 if repaint_needed || self.animation_callbacks_running() {
1524 self.set_needs_repaint(RepaintReason::NewWebRenderFrame);
1525 }
1526
1527 if !repaint_needed {
1531 self.screenshot_taker
1532 .maybe_trigger_paint_for_screenshot(self);
1533 }
1534 }
1535
1536 pub(crate) fn webviews_needing_repaint(&self) -> Vec<WebViewId> {
1537 if self.needs_repaint() {
1538 self.webview_renderers
1539 .values()
1540 .map(|webview_renderer| webview_renderer.id)
1541 .collect()
1542 } else {
1543 Vec::new()
1544 }
1545 }
1546
1547 pub(crate) fn scroll_trees_memory_usage(
1548 &self,
1549 ops: &mut malloc_size_of::MallocSizeOfOps,
1550 ) -> usize {
1551 self.webview_renderers
1552 .values()
1553 .map(|renderer| renderer.scroll_trees_memory_usage(ops))
1554 .sum::<usize>()
1555 }
1556}
1557
1558#[derive(Default)]
1568pub(crate) struct FrameDelayer {
1569 image_epochs: FxHashMap<ImageKey, Epoch>,
1573 pending_canvas_images: FxHashMap<ImageKey, Epoch>,
1575 pub(crate) pending_frame: bool,
1577 waiting_pipelines: FxHashSet<PipelineId>,
1580}
1581
1582impl FrameDelayer {
1583 pub(crate) fn delete_image(&mut self, image_key: ImageKey) {
1584 self.image_epochs.remove(&image_key);
1585 self.pending_canvas_images.remove(&image_key);
1586 }
1587
1588 pub(crate) fn update_image(&mut self, image_key: ImageKey, epoch: Epoch) {
1589 self.image_epochs.insert(image_key, epoch);
1590 let Entry::Occupied(entry) = self.pending_canvas_images.entry(image_key) else {
1591 return;
1592 };
1593 if *entry.get() <= epoch {
1594 entry.remove();
1595 }
1596 }
1597
1598 pub(crate) fn add_delay(
1599 &mut self,
1600 pipeline_id: PipelineId,
1601 canvas_epoch: Epoch,
1602 image_keys: Vec<ImageKey>,
1603 ) {
1604 for image_key in image_keys.into_iter() {
1605 if self
1608 .image_epochs
1609 .get(&image_key)
1610 .is_some_and(|epoch_seen| *epoch_seen >= canvas_epoch)
1611 {
1612 continue;
1613 }
1614 self.pending_canvas_images.insert(image_key, canvas_epoch);
1615 }
1616 self.waiting_pipelines.insert(pipeline_id);
1617 }
1618
1619 pub(crate) fn needs_new_frame(&self) -> bool {
1620 self.pending_frame && self.pending_canvas_images.is_empty()
1621 }
1622
1623 pub(crate) fn set_pending_frame(&mut self, value: bool) {
1624 self.pending_frame = value;
1625 }
1626
1627 pub(crate) fn take_waiting_pipelines(&mut self) -> Vec<PipelineId> {
1628 self.waiting_pipelines.drain().collect()
1629 }
1630}
1631
1632#[derive(Clone, Copy, PartialEq)]
1637pub(crate) enum PaintMetricState {
1638 Waiting,
1640 Seen(
1644 WebRenderEpoch,
1645 bool, PaintTimingInfo,
1647 ),
1648 Sent,
1650}
1651
1652struct BoostWebRenderThread;
1654
1655impl RenderBackendHooks for BoostWebRenderThread {
1656 fn init_thread(&self) {
1657 servo_base::threadboost::boost_thread(ThreadPriority::Elevated, BoostAffinity::Boost);
1658 }
1659}
1660
1661impl SceneBuilderHooks for BoostWebRenderThread {
1662 fn register(&self) {
1663 servo_base::threadboost::boost_thread(ThreadPriority::Elevated, BoostAffinity::Boost);
1664 }
1665
1666 fn pre_scene_build(&self) {}
1667
1668 fn pre_scene_swap(&self) {}
1669
1670 fn post_scene_swap(
1671 &self,
1672 _document_id: &Vec<DocumentId>,
1673 _info: webrender::PipelineInfo,
1674 _schedule_frame: bool,
1675 ) {
1676 }
1677
1678 fn post_resource_update(&self, _document_ids: &Vec<DocumentId>) {}
1679
1680 fn post_empty_scene_build(&self) {}
1681
1682 fn poke(&self) {}
1683
1684 fn deregister(&self) {}
1685}