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