paint_api/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! The interface to the `paint` crate, which helps to break dependency cycles.
6
7use std::collections::HashMap;
8use std::fmt::{Debug, Error, Formatter};
9
10use base::Epoch;
11use base::id::{PainterId, PipelineId, WebViewId};
12use crossbeam_channel::Sender;
13use embedder_traits::{AnimationState, EventLoopWaker};
14use euclid::{Rect, Scale, Size2D};
15use log::warn;
16use malloc_size_of_derive::MallocSizeOf;
17use parking_lot::RwLock;
18use rustc_hash::FxHashMap;
19use smallvec::SmallVec;
20use strum::IntoStaticStr;
21use style_traits::CSSPixel;
22use surfman::{Adapter, Connection};
23use webrender_api::{DocumentId, FontVariation};
24
25pub mod display_list;
26pub mod largest_contentful_paint_candidate;
27pub mod rendering_context;
28pub mod viewport_description;
29
30use std::sync::{Arc, Mutex};
31
32use base::generic_channel::{
33    self, GenericCallback, GenericReceiver, GenericSender, GenericSharedMemory,
34};
35use bitflags::bitflags;
36use display_list::PaintDisplayListInfo;
37use embedder_traits::ScreenGeometry;
38use euclid::default::Size2D as UntypedSize2D;
39use profile_traits::mem::{OpaqueSender, ReportsChan};
40use serde::{Deserialize, Serialize};
41pub use webrender_api::ExternalImageSource;
42use webrender_api::units::{DevicePixel, LayoutVector2D, TexelRect};
43use webrender_api::{
44    BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
45    ExternalImageHandler, ExternalImageId, ExternalScrollId, FontInstanceFlags, FontInstanceKey,
46    FontKey, ImageData, ImageDescriptor, ImageKey, NativeFontHandle,
47    PipelineId as WebRenderPipelineId,
48};
49
50use crate::largest_contentful_paint_candidate::LCPCandidate;
51use crate::viewport_description::ViewportDescription;
52
53/// Sends messages to `Paint`.
54#[derive(Clone)]
55pub struct PaintProxy {
56    pub sender: Sender<Result<PaintMessage, ipc_channel::IpcError>>,
57    /// Access to [`Self::sender`] that is possible to send across an IPC
58    /// channel. These messages are routed via the router thread to
59    /// [`Self::sender`].
60    pub cross_process_paint_api: CrossProcessPaintApi,
61    pub event_loop_waker: Box<dyn EventLoopWaker>,
62}
63
64impl OpaqueSender<PaintMessage> for PaintProxy {
65    fn send(&self, message: PaintMessage) {
66        PaintProxy::send(self, message)
67    }
68}
69
70impl PaintProxy {
71    pub fn send(&self, msg: PaintMessage) {
72        self.route_msg(Ok(msg))
73    }
74
75    /// Helper method to route a deserialized IPC message to the receiver.
76    ///
77    /// This method is a temporary solution, and will be removed when migrating
78    /// to `GenericChannel`.
79    pub fn route_msg(&self, msg: Result<PaintMessage, ipc_channel::IpcError>) {
80        if let Err(err) = self.sender.send(msg) {
81            warn!("Failed to send response ({:?}).", err);
82        }
83        self.event_loop_waker.wake();
84    }
85}
86
87/// Messages from (or via) the constellation thread to `Paint`.
88#[derive(Deserialize, IntoStaticStr, Serialize)]
89pub enum PaintMessage {
90    /// Alerts `Paint` that the given pipeline has changed whether it is running animations.
91    ChangeRunningAnimationsState(WebViewId, PipelineId, AnimationState),
92    /// Updates the frame tree for the given webview.
93    SetFrameTreeForWebView(WebViewId, SendableFrameTree),
94    /// Set whether to use less resources by stopping animations.
95    SetThrottled(WebViewId, PipelineId, bool),
96    /// WebRender has produced a new frame. This message informs `Paint` that
97    /// the frame is ready. It contains a bool to indicate if it needs to composite, the
98    /// `DocumentId` of the new frame and the `PainterId` of the associated painter.
99    NewWebRenderFrameReady(PainterId, DocumentId, bool),
100    /// Script or the Constellation is notifying the renderer that a Pipeline has finished
101    /// shutting down. The renderer will not discard the Pipeline until both report that
102    /// they have fully shut it down, to avoid recreating it due to any subsequent
103    /// messages.
104    PipelineExited(WebViewId, PipelineId, PipelineExitSource),
105    /// Inform WebRender of the existence of this pipeline.
106    SendInitialTransaction(WebViewId, WebRenderPipelineId),
107    /// Scroll the given node ([`ExternalScrollId`]) by the provided delta. This
108    /// will only adjust the node's scroll position and will *not* do panning in
109    /// the pinch zoom viewport.
110    ScrollNodeByDelta(
111        WebViewId,
112        WebRenderPipelineId,
113        LayoutVector2D,
114        ExternalScrollId,
115    ),
116    /// Scroll the WebView's viewport by the given delta. This will also do panning
117    /// in the pinch zoom viewport if possible and the remaining delta will be used
118    /// to scroll the root layer.
119    ScrollViewportByDelta(WebViewId, LayoutVector2D),
120    /// Update the rendering epoch of the given `Pipeline`.
121    UpdateEpoch {
122        /// The [`WebViewId`] that this display list belongs to.
123        webview_id: WebViewId,
124        /// The [`PipelineId`] of the `Pipeline` to update.
125        pipeline_id: PipelineId,
126        /// The new [`Epoch`] value.
127        epoch: Epoch,
128    },
129    /// Inform WebRender of a new display list for the given pipeline.
130    SendDisplayList {
131        /// The [`WebViewId`] that this display list belongs to.
132        webview_id: WebViewId,
133        /// A descriptor of this display list used to construct this display list from raw data.
134        display_list_descriptor: BuiltDisplayListDescriptor,
135        /// A [`GenericReceiver`] used to send the [`PaintDisplayListInfo`].
136        display_list_info_receiver: GenericReceiver<PaintDisplayListInfo>,
137        /// A [`GenericReceiver`] used to send the serialized  version of `DisplayListPayload.
138        display_list_data_receiver: GenericReceiver<SerializableDisplayListPayload>,
139    },
140    /// Ask the renderer to generate a frame for the current set of display lists
141    /// from the given `PainterId`s that have been sent to the renderer.
142    GenerateFrame(Vec<PainterId>),
143    /// Create a new image key. The result will be returned via the
144    /// provided channel sender.
145    GenerateImageKey(WebViewId, GenericSender<ImageKey>),
146    /// The same as the above but it will be forwarded to the pipeline instead
147    /// of send via a channel.
148    GenerateImageKeysForPipeline(WebViewId, PipelineId),
149    /// Perform a resource update operation.
150    UpdateImages(PainterId, SmallVec<[ImageUpdate; 1]>),
151    /// Pause all pipeline display list processing for the given pipeline until the
152    /// following image updates have been received. This is used to ensure that canvas
153    /// elements have had a chance to update their rendering and send the image update to
154    /// the renderer before their associated display list is actually displayed.
155    DelayNewFrameForCanvas(WebViewId, PipelineId, Epoch, Vec<ImageKey>),
156
157    /// Generate a new batch of font keys which can be used to allocate
158    /// keys asynchronously.
159    GenerateFontKeys(
160        usize,
161        usize,
162        GenericSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
163        PainterId,
164    ),
165    /// Add a font with the given data and font key.
166    AddFont(PainterId, FontKey, Arc<GenericSharedMemory>, u32),
167    /// Add a system font with the given font key and handle.
168    AddSystemFont(PainterId, FontKey, NativeFontHandle),
169    /// Add an instance of a font with the given instance key.
170    AddFontInstance(
171        PainterId,
172        FontInstanceKey,
173        FontKey,
174        f32,
175        FontInstanceFlags,
176        Vec<FontVariation>,
177    ),
178    /// Remove the given font resources from our WebRender instance.
179    RemoveFonts(PainterId, Vec<FontKey>, Vec<FontInstanceKey>),
180    /// Measure the current memory usage associated with `Paint`.
181    /// The report must be sent on the provided channel once it's complete.
182    CollectMemoryReport(ReportsChan),
183    /// A top-level frame has parsed a viewport metatag and is sending the new constraints.
184    Viewport(WebViewId, ViewportDescription),
185    /// Let `Paint` know that the given WebView is ready to have a screenshot taken
186    /// after the given pipeline's epochs have been rendered.
187    ScreenshotReadinessReponse(WebViewId, FxHashMap<PipelineId, Epoch>),
188    /// The candidate of largest-contentful-paint
189    SendLCPCandidate(LCPCandidate, WebViewId, PipelineId, Epoch),
190    /// Enable LCP calculation for the given WebView.
191    EnableLCPCalculation(WebViewId),
192}
193
194impl Debug for PaintMessage {
195    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
196        let string: &'static str = self.into();
197        write!(formatter, "{string}")
198    }
199}
200
201#[derive(Deserialize, Serialize)]
202pub struct SendableFrameTree {
203    pub pipeline: CompositionPipeline,
204    pub children: Vec<SendableFrameTree>,
205}
206
207/// The subset of the pipeline that is needed for layer composition.
208#[derive(Clone, Deserialize, Serialize)]
209pub struct CompositionPipeline {
210    pub id: PipelineId,
211    pub webview_id: WebViewId,
212}
213
214/// A serializable version of `DisplayListPayload`.
215#[derive(Serialize, Deserialize)]
216pub struct SerializableDisplayListPayload {
217    /// Serde encoded bytes of the display list' `DisplayItems` and their supporting data.
218    #[serde(with = "serde_bytes")]
219    pub items_data: Vec<u8>,
220
221    /// Serde encoded `DisplayItemCache` structs
222    #[serde(with = "serde_bytes")]
223    pub cache_data: Vec<u8>,
224
225    /// Serde encoded `SpatialTreeItem` structs.
226    #[serde(with = "serde_bytes")]
227    pub spatial_tree: Vec<u8>,
228}
229
230/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
231#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
232pub struct CrossProcessPaintApi(GenericCallback<PaintMessage>);
233
234impl CrossProcessPaintApi {
235    /// Create a new [`CrossProcessPaintApi`] struct.
236    pub fn new(callback: GenericCallback<PaintMessage>) -> Self {
237        CrossProcessPaintApi(callback)
238    }
239
240    /// Create a new [`CrossProcessPaintApi`] struct that does not have a listener on the other
241    /// end to use for unit testing.
242    pub fn dummy() -> Self {
243        Self::dummy_with_callback(None)
244    }
245
246    /// Create a new [`CrossProcessPaintApi`] struct for unit testing with an optional callback
247    /// that can respond to `PaintMessage`s.
248    pub fn dummy_with_callback(
249        callback: Option<Box<dyn Fn(PaintMessage) + Send + 'static>>,
250    ) -> Self {
251        let callback = GenericCallback::new(move |msg| {
252            if let Some(ref handler) = callback {
253                if let Ok(paint_message) = msg {
254                    handler(paint_message);
255                }
256            }
257        })
258        .unwrap();
259        Self(callback)
260    }
261
262    /// Inform WebRender of the existence of this pipeline.
263    pub fn send_initial_transaction(&self, webview_id: WebViewId, pipeline: WebRenderPipelineId) {
264        if let Err(e) = self
265            .0
266            .send(PaintMessage::SendInitialTransaction(webview_id, pipeline))
267        {
268            warn!("Error sending initial transaction: {}", e);
269        }
270    }
271
272    /// Scroll the given node ([`ExternalScrollId`]) by the provided delta. This
273    /// will only adjust the node's scroll position and will *not* do panning in
274    /// the pinch zoom viewport.
275    pub fn scroll_node_by_delta(
276        &self,
277        webview_id: WebViewId,
278        pipeline_id: WebRenderPipelineId,
279        delta: LayoutVector2D,
280        scroll_id: ExternalScrollId,
281    ) {
282        if let Err(error) = self.0.send(PaintMessage::ScrollNodeByDelta(
283            webview_id,
284            pipeline_id,
285            delta,
286            scroll_id,
287        )) {
288            warn!("Error scrolling node: {error}");
289        }
290    }
291
292    /// Scroll the WebView's viewport by the given delta. This will also do panning
293    /// in the pinch zoom viewport if possible and the remaining delta will be used
294    /// to scroll the root layer.
295    ///
296    /// Note the value provided here is in `DeviceIndependentPixels` and will first be
297    /// converted to `DevicePixels` by the renderer.
298    pub fn scroll_viewport_by_delta(&self, webview_id: WebViewId, delta: LayoutVector2D) {
299        if let Err(error) = self
300            .0
301            .send(PaintMessage::ScrollViewportByDelta(webview_id, delta))
302        {
303            warn!("Error scroll viewport: {error}");
304        }
305    }
306
307    pub fn delay_new_frame_for_canvas(
308        &self,
309        webview_id: WebViewId,
310        pipeline_id: PipelineId,
311        canvas_epoch: Epoch,
312        image_keys: Vec<ImageKey>,
313    ) {
314        if let Err(error) = self.0.send(PaintMessage::DelayNewFrameForCanvas(
315            webview_id,
316            pipeline_id,
317            canvas_epoch,
318            image_keys,
319        )) {
320            warn!("Error delaying frames for canvas image updates {error:?}");
321        }
322    }
323
324    /// Inform the renderer that the rendering epoch has advanced. This typically happens after
325    /// a new display list is sent and/or canvas and animated images are updated.
326    pub fn update_epoch(&self, webview_id: WebViewId, pipeline_id: PipelineId, epoch: Epoch) {
327        if let Err(error) = self.0.send(PaintMessage::UpdateEpoch {
328            webview_id,
329            pipeline_id,
330            epoch,
331        }) {
332            warn!("Error updating epoch for pipeline: {error:?}");
333        }
334    }
335
336    /// Inform WebRender of a new display list for the given pipeline.
337    /// We send the `PaintDisplayListInfo` and `DisplayListPayload` separately to not overwhelm
338    /// the ipc_channel (see <https://github.com/servo/servo/pull/36484>)
339    #[servo_tracing::instrument(skip_all)]
340    pub fn send_display_list(
341        &self,
342        webview_id: WebViewId,
343        display_list_info: &PaintDisplayListInfo,
344        list: BuiltDisplayList,
345    ) {
346        let (display_list_data, display_list_descriptor) = list.into_data();
347        let (display_list_data_sender, display_list_data_receiver) =
348            generic_channel::channel().unwrap();
349        let (display_list_info_sender, display_list_info_receiver) =
350            generic_channel::channel().unwrap();
351        if let Err(e) = self.0.send(PaintMessage::SendDisplayList {
352            webview_id,
353            display_list_descriptor,
354            display_list_info_receiver,
355            display_list_data_receiver,
356        }) {
357            warn!("Error sending display list: {}", e);
358        }
359
360        if let Err(error) = display_list_info_sender.send(display_list_info.clone()) {
361            warn!("Error sending display list info: {error}. Not sending the rest");
362            return;
363        }
364        let display_list_data = SerializableDisplayListPayload {
365            items_data: display_list_data.items_data,
366            cache_data: display_list_data.cache_data,
367            spatial_tree: display_list_data.spatial_tree,
368        };
369
370        if let Err(error) = display_list_data_sender.send(display_list_data) {
371            warn!("Error sending display list: {error}");
372        }
373    }
374
375    /// Send the largest contentful paint candidate to `Paint`.
376    pub fn send_lcp_candidate(
377        &self,
378        lcp_candidate: LCPCandidate,
379        webview_id: WebViewId,
380        pipeline_id: PipelineId,
381        epoch: Epoch,
382    ) {
383        if let Err(error) = self.0.send(PaintMessage::SendLCPCandidate(
384            lcp_candidate,
385            webview_id,
386            pipeline_id,
387            epoch,
388        )) {
389            warn!("Error sending LCPCandidate: {error}");
390        }
391    }
392
393    /// Ask the Servo renderer to generate a new frame after having new display lists.
394    pub fn generate_frame(&self, painter_ids: Vec<PainterId>) {
395        if let Err(error) = self.0.send(PaintMessage::GenerateFrame(painter_ids)) {
396            warn!("Error generating frame: {error}");
397        }
398    }
399
400    /// Create a new image key. Blocks until the key is available.
401    pub fn generate_image_key_blocking(&self, webview_id: WebViewId) -> Option<ImageKey> {
402        let (sender, receiver) = generic_channel::channel().unwrap();
403        self.0
404            .send(PaintMessage::GenerateImageKey(webview_id, sender))
405            .ok()?;
406        receiver.recv().ok()
407    }
408
409    /// Sends a message to `Paint` for creating new image keys.
410    /// `Paint` will then send a batch of keys over the constellation to the script_thread
411    /// and the appropriate pipeline.
412    pub fn generate_image_key_async(&self, webview_id: WebViewId, pipeline_id: PipelineId) {
413        if let Err(e) = self.0.send(PaintMessage::GenerateImageKeysForPipeline(
414            webview_id,
415            pipeline_id,
416        )) {
417            warn!("Could not send image keys to Paint {}", e);
418        }
419    }
420
421    pub fn add_image(
422        &self,
423        key: ImageKey,
424        descriptor: ImageDescriptor,
425        data: SerializableImageData,
426        is_animated_image: bool,
427    ) {
428        self.update_images(
429            key.into(),
430            [ImageUpdate::AddImage(
431                key,
432                descriptor,
433                data,
434                is_animated_image,
435            )]
436            .into(),
437        );
438    }
439
440    pub fn update_image(
441        &self,
442        key: ImageKey,
443        descriptor: ImageDescriptor,
444        data: SerializableImageData,
445        epoch: Option<Epoch>,
446    ) {
447        self.update_images(
448            key.into(),
449            [ImageUpdate::UpdateImage(key, descriptor, data, epoch)].into(),
450        );
451    }
452
453    pub fn delete_image(&self, key: ImageKey) {
454        self.update_images(key.into(), [ImageUpdate::DeleteImage(key)].into());
455    }
456
457    /// Perform an image resource update operation.
458    pub fn update_images(&self, painter_id: PainterId, updates: SmallVec<[ImageUpdate; 1]>) {
459        if let Err(e) = self.0.send(PaintMessage::UpdateImages(painter_id, updates)) {
460            warn!("error sending image updates: {}", e);
461        }
462    }
463
464    pub fn remove_unused_font_resources(
465        &self,
466        painter_id: PainterId,
467        keys: Vec<FontKey>,
468        instance_keys: Vec<FontInstanceKey>,
469    ) {
470        if keys.is_empty() && instance_keys.is_empty() {
471            return;
472        }
473        let _ = self
474            .0
475            .send(PaintMessage::RemoveFonts(painter_id, keys, instance_keys));
476    }
477
478    pub fn add_font_instance(
479        &self,
480        font_instance_key: FontInstanceKey,
481        font_key: FontKey,
482        size: f32,
483        flags: FontInstanceFlags,
484        variations: Vec<FontVariation>,
485    ) {
486        let _x = self.0.send(PaintMessage::AddFontInstance(
487            font_key.into(),
488            font_instance_key,
489            font_key,
490            size,
491            flags,
492            variations,
493        ));
494    }
495
496    pub fn add_font(&self, font_key: FontKey, data: Arc<GenericSharedMemory>, index: u32) {
497        let _ = self.0.send(PaintMessage::AddFont(
498            font_key.into(),
499            font_key,
500            data,
501            index,
502        ));
503    }
504
505    pub fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
506        let _ = self.0.send(PaintMessage::AddSystemFont(
507            font_key.into(),
508            font_key,
509            handle,
510        ));
511    }
512
513    pub fn fetch_font_keys(
514        &self,
515        number_of_font_keys: usize,
516        number_of_font_instance_keys: usize,
517        painter_id: PainterId,
518    ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
519        let (sender, receiver) = generic_channel::channel().expect("Could not create IPC channel");
520        let _ = self.0.send(PaintMessage::GenerateFontKeys(
521            number_of_font_keys,
522            number_of_font_instance_keys,
523            sender,
524            painter_id,
525        ));
526        receiver.recv().unwrap()
527    }
528
529    pub fn viewport(&self, webview_id: WebViewId, description: ViewportDescription) {
530        let _ = self.0.send(PaintMessage::Viewport(webview_id, description));
531    }
532
533    pub fn pipeline_exited(
534        &self,
535        webview_id: WebViewId,
536        pipeline_id: PipelineId,
537        source: PipelineExitSource,
538    ) {
539        let _ = self.0.send(PaintMessage::PipelineExited(
540            webview_id,
541            pipeline_id,
542            source,
543        ));
544    }
545}
546
547#[derive(Clone)]
548pub struct PainterSurfmanDetails {
549    pub connection: Connection,
550    pub adapter: Adapter,
551}
552
553#[derive(Clone, Default)]
554pub struct PainterSurfmanDetailsMap(Arc<Mutex<HashMap<PainterId, PainterSurfmanDetails>>>);
555
556impl PainterSurfmanDetailsMap {
557    pub fn get(&self, painter_id: PainterId) -> Option<PainterSurfmanDetails> {
558        let map = self.0.lock().expect("poisoned");
559        map.get(&painter_id).cloned()
560    }
561
562    pub fn insert(&self, painter_id: PainterId, details: PainterSurfmanDetails) {
563        let mut map = self.0.lock().expect("poisoned");
564        let existing = map.insert(painter_id, details);
565        assert!(existing.is_none())
566    }
567
568    pub fn remove(&self, painter_id: PainterId) {
569        let mut map = self.0.lock().expect("poisoned");
570        let details = map.remove(&painter_id);
571        assert!(details.is_some());
572    }
573}
574
575/// This trait is used as a bridge between the different GL clients
576/// in Servo that handles WebRender ExternalImages and the WebRender
577/// ExternalImageHandler API.
578//
579/// This trait is used to notify lock/unlock messages and get the
580/// required info that WR needs.
581pub trait WebRenderExternalImageApi {
582    fn lock(&mut self, id: u64) -> (ExternalImageSource<'_>, UntypedSize2D<i32>);
583    fn unlock(&mut self, id: u64);
584}
585
586/// Type of WebRender External Image Handler.
587#[derive(Clone, Copy)]
588pub enum WebRenderImageHandlerType {
589    WebGl,
590    Media,
591    WebGpu,
592}
593
594/// List of WebRender external images to be shared among all external image
595/// consumers (WebGL, Media, WebGPU).
596/// It ensures that external image identifiers are unique.
597#[derive(Default)]
598struct WebRenderExternalImageIdManagerInner {
599    /// Map of all generated external images.
600    external_images: FxHashMap<ExternalImageId, WebRenderImageHandlerType>,
601    /// Id generator for the next external image identifier.
602    next_image_id: u64,
603}
604
605#[derive(Default, Clone)]
606pub struct WebRenderExternalImageIdManager(Arc<RwLock<WebRenderExternalImageIdManagerInner>>);
607
608impl WebRenderExternalImageIdManager {
609    pub fn next_id(&mut self, handler_type: WebRenderImageHandlerType) -> ExternalImageId {
610        let mut inner = self.0.write();
611        inner.next_image_id += 1;
612        let key = ExternalImageId(inner.next_image_id);
613        inner.external_images.insert(key, handler_type);
614        key
615    }
616
617    pub fn remove(&mut self, key: &ExternalImageId) {
618        self.0.write().external_images.remove(key);
619    }
620
621    pub fn get(&self, key: &ExternalImageId) -> Option<WebRenderImageHandlerType> {
622        self.0.read().external_images.get(key).cloned()
623    }
624}
625
626/// WebRender External Image Handler implementation.
627pub struct WebRenderExternalImageHandlers {
628    /// WebGL handler.
629    webgl_handler: Option<Box<dyn WebRenderExternalImageApi>>,
630    /// Media player handler.
631    media_handler: Option<Box<dyn WebRenderExternalImageApi>>,
632    /// WebGPU handler.
633    webgpu_handler: Option<Box<dyn WebRenderExternalImageApi>>,
634    /// A [`WebRenderExternalImageIdManager`] responsible for creating new [`ExternalImageId`]s.
635    /// This is shared with the WebGL, WebGPU, and hardware-accelerated media threads and
636    /// all other instances of [`WebRenderExternalImageHandlers`] -- one per WebRender instance.
637    id_manager: WebRenderExternalImageIdManager,
638}
639
640impl WebRenderExternalImageHandlers {
641    pub fn new(id_manager: WebRenderExternalImageIdManager) -> Self {
642        Self {
643            webgl_handler: Default::default(),
644            media_handler: Default::default(),
645            webgpu_handler: Default::default(),
646            id_manager,
647        }
648    }
649
650    pub fn id_manager(&self) -> WebRenderExternalImageIdManager {
651        self.id_manager.clone()
652    }
653
654    pub fn set_handler(
655        &mut self,
656        handler: Box<dyn WebRenderExternalImageApi>,
657        handler_type: WebRenderImageHandlerType,
658    ) {
659        match handler_type {
660            WebRenderImageHandlerType::WebGl => self.webgl_handler = Some(handler),
661            WebRenderImageHandlerType::Media => self.media_handler = Some(handler),
662            WebRenderImageHandlerType::WebGpu => self.webgpu_handler = Some(handler),
663        }
664    }
665}
666
667impl ExternalImageHandler for WebRenderExternalImageHandlers {
668    /// Lock the external image. Then, WR could start to read the
669    /// image content.
670    /// The WR client should not change the image content until the
671    /// unlock() call.
672    fn lock(
673        &mut self,
674        key: ExternalImageId,
675        _channel_index: u8,
676        _is_composited: bool,
677    ) -> ExternalImage<'_> {
678        let handler_type = self
679            .id_manager()
680            .get(&key)
681            .expect("Tried to get unknown external image");
682        match handler_type {
683            WebRenderImageHandlerType::WebGl => {
684                let (source, size) = self.webgl_handler.as_mut().unwrap().lock(key.0);
685                let texture_id = match source {
686                    ExternalImageSource::NativeTexture(b) => b,
687                    _ => panic!("Wrong type"),
688                };
689                ExternalImage {
690                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
691                    source: ExternalImageSource::NativeTexture(texture_id),
692                }
693            },
694            WebRenderImageHandlerType::Media => {
695                let (source, size) = self.media_handler.as_mut().unwrap().lock(key.0);
696                let texture_id = match source {
697                    ExternalImageSource::NativeTexture(b) => b,
698                    _ => panic!("Wrong type"),
699                };
700                ExternalImage {
701                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
702                    source: ExternalImageSource::NativeTexture(texture_id),
703                }
704            },
705            WebRenderImageHandlerType::WebGpu => {
706                let (source, size) = self.webgpu_handler.as_mut().unwrap().lock(key.0);
707                ExternalImage {
708                    uv: TexelRect::new(0.0, size.height as f32, size.width as f32, 0.0),
709                    source,
710                }
711            },
712        }
713    }
714
715    /// Unlock the external image. The WR should not read the image
716    /// content after this call.
717    fn unlock(&mut self, key: ExternalImageId, _channel_index: u8) {
718        let handler_type = self
719            .id_manager()
720            .get(&key)
721            .expect("Tried to get unknown external image");
722        match handler_type {
723            WebRenderImageHandlerType::WebGl => self.webgl_handler.as_mut().unwrap().unlock(key.0),
724            WebRenderImageHandlerType::Media => self.media_handler.as_mut().unwrap().unlock(key.0),
725            WebRenderImageHandlerType::WebGpu => {
726                self.webgpu_handler.as_mut().unwrap().unlock(key.0)
727            },
728        };
729    }
730}
731
732#[derive(Deserialize, Serialize)]
733/// Serializable image updates that must be performed by WebRender.
734pub enum ImageUpdate {
735    /// Register a new image.
736    AddImage(
737        ImageKey,
738        ImageDescriptor,
739        SerializableImageData,
740        bool, /* is_animated_image */
741    ),
742    /// Delete a previously registered image registration.
743    DeleteImage(ImageKey),
744    /// Update an existing image registration.
745    UpdateImage(
746        ImageKey,
747        ImageDescriptor,
748        SerializableImageData,
749        Option<Epoch>,
750    ),
751    /// Update an [`ImageDescriptor`] for an existing image. This is used primarily
752    /// to modify the data offset for image animations.
753    UpdateImageForAnimation(ImageKey, ImageDescriptor),
754}
755
756impl Debug for ImageUpdate {
757    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
758        match self {
759            Self::AddImage(image_key, image_desc, _, is_animated_image) => f
760                .debug_tuple("AddImage")
761                .field(image_key)
762                .field(image_desc)
763                .field(is_animated_image)
764                .finish(),
765            Self::DeleteImage(image_key) => f.debug_tuple("DeleteImage").field(image_key).finish(),
766            Self::UpdateImage(image_key, image_desc, _, epoch) => f
767                .debug_tuple("UpdateImage")
768                .field(image_key)
769                .field(image_desc)
770                .field(epoch)
771                .finish(),
772            Self::UpdateImageForAnimation(image_key, image_desc) => f
773                .debug_tuple("UpdateAnimation")
774                .field(image_key)
775                .field(image_desc)
776                .finish(),
777        }
778    }
779}
780
781#[derive(Debug, Deserialize, Serialize)]
782/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too
783/// slow.
784pub enum SerializableImageData {
785    /// A simple series of bytes, provided by the embedding and owned by WebRender.
786    /// The format is stored out-of-band, currently in ImageDescriptor.
787    Raw(GenericSharedMemory),
788    /// An image owned by the embedding, and referenced by WebRender. This may
789    /// take the form of a texture or a heap-allocated buffer.
790    External(ExternalImageData),
791}
792
793impl From<SerializableImageData> for ImageData {
794    fn from(value: SerializableImageData) -> Self {
795        match value {
796            SerializableImageData::Raw(shared_memory) => ImageData::new(shared_memory.to_vec()),
797            SerializableImageData::External(image) => ImageData::External(image),
798        }
799    }
800}
801
802/// A trait that exposes the embedding layer's `WebView` to the Servo renderer.
803/// This is to prevent a dependency cycle between the renderer and the embedding
804/// layer.
805pub trait WebViewTrait {
806    fn id(&self) -> WebViewId;
807    fn screen_geometry(&self) -> Option<ScreenGeometry>;
808    fn set_animating(&self, new_value: bool);
809}
810
811/// What entity is reporting that a `Pipeline` has exited. Only when all have
812/// done this will the renderer discard its details.
813#[derive(Clone, Copy, Default, Deserialize, PartialEq, Serialize)]
814pub struct PipelineExitSource(u8);
815
816bitflags! {
817    impl PipelineExitSource: u8 {
818        const Script = 1 << 0;
819        const Constellation = 1 << 1;
820    }
821}
822
823/// A [`PinchZoomInfos`] for a root [`Pipeline`] of an [`WebView`]. For any [`Pipeline`]
824/// that is not a root, it should follow the viewport description of its pipeline since
825/// pinch-zoom and resizing due to overlay UIs are not applicable there.
826#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
827pub struct PinchZoomInfos {
828    /// The zoom factor (or pinch-zoom).
829    pub zoom_factor: Scale<f32, DevicePixel, DevicePixel>,
830
831    /// The size relative to layout viewport.
832    pub rect: Rect<f32, CSSPixel>,
833}
834
835impl PinchZoomInfos {
836    /// New initial [`PinchZoomInfos`] without any pinch-zoom or resizing from a viewport size
837    /// for a nested pipeline or newly initialized root pipeline.
838    pub fn new_from_viewport_size(size: Size2D<f32, CSSPixel>) -> Self {
839        Self {
840            zoom_factor: Scale::identity(),
841            rect: Rect::from_size(size),
842        }
843    }
844}