Skip to main content

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