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