net_traits/
image_cache.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
5use std::sync::Arc;
6
7use base::id::{PipelineId, WebViewId};
8use compositing_traits::CrossProcessCompositorApi;
9use log::debug;
10use malloc_size_of::MallocSizeOfOps;
11use malloc_size_of_derive::MallocSizeOf;
12use pixels::{CorsStatus, ImageMetadata, RasterImage};
13use profile_traits::mem::Report;
14use serde::{Deserialize, Serialize};
15use servo_url::{ImmutableOrigin, ServoUrl};
16use webrender_api::ImageKey;
17use webrender_api::units::DeviceIntSize;
18
19use crate::FetchResponseMsg;
20use crate::request::CorsSettings;
21
22// ======================================================================
23// Aux structs and enums.
24// ======================================================================
25
26pub type VectorImageId = PendingImageId;
27
28// Represents either a raster image for which the pixel data is available
29// or a vector image for which only the natural dimensions are available
30// and thus requires a further rasterization step to render.
31#[derive(Clone, Debug, MallocSizeOf)]
32pub enum Image {
33    Raster(#[conditional_malloc_size_of] Arc<RasterImage>),
34    Vector(VectorImage),
35}
36
37#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
38pub struct VectorImage {
39    pub id: VectorImageId,
40    pub metadata: ImageMetadata,
41    pub cors_status: CorsStatus,
42}
43
44impl Image {
45    pub fn metadata(&self) -> ImageMetadata {
46        match self {
47            Image::Vector(image, ..) => image.metadata,
48            Image::Raster(image) => image.metadata,
49        }
50    }
51
52    pub fn cors_status(&self) -> CorsStatus {
53        match self {
54            Image::Vector(image) => image.cors_status,
55            Image::Raster(image) => image.cors_status,
56        }
57    }
58
59    pub fn as_raster_image(&self) -> Option<Arc<RasterImage>> {
60        match self {
61            Image::Raster(image) => Some(image.clone()),
62            Image::Vector(..) => None,
63        }
64    }
65}
66
67/// Indicating either entire image or just metadata availability
68#[derive(Clone, Debug, MallocSizeOf)]
69pub enum ImageOrMetadataAvailable {
70    ImageAvailable { image: Image, url: ServoUrl },
71    MetadataAvailable(ImageMetadata, PendingImageId),
72}
73
74pub type ImageCacheResponseCallback = Box<dyn Fn(ImageCacheResponseMessage) + Send + 'static>;
75
76/// This is optionally passed to the image cache when requesting
77/// and image, and returned to the specified event loop when the
78/// image load completes. It is typically used to trigger a reflow
79/// and/or repaint.
80#[derive(MallocSizeOf)]
81pub struct ImageLoadListener {
82    pipeline_id: PipelineId,
83    pub id: PendingImageId,
84    #[ignore_malloc_size_of = "Difficult to measure FnOnce"]
85    callback: ImageCacheResponseCallback,
86}
87
88impl ImageLoadListener {
89    pub fn new(
90        callback: ImageCacheResponseCallback,
91        pipeline_id: PipelineId,
92        id: PendingImageId,
93    ) -> ImageLoadListener {
94        ImageLoadListener {
95            pipeline_id,
96            callback,
97            id,
98        }
99    }
100
101    pub fn respond(&self, response: ImageResponse) {
102        debug!("Notifying listener");
103        (self.callback)(ImageCacheResponseMessage::NotifyPendingImageLoadStatus(
104            PendingImageResponse {
105                pipeline_id: self.pipeline_id,
106                response,
107                id: self.id,
108            },
109        ));
110    }
111}
112
113/// The returned image.
114#[derive(Clone, Debug, MallocSizeOf)]
115pub enum ImageResponse {
116    /// The requested image was loaded.
117    Loaded(Image, ServoUrl),
118    /// The request image metadata was loaded.
119    MetadataLoaded(ImageMetadata),
120    /// The requested image failed to load or decode.
121    FailedToLoadOrDecode,
122}
123
124/// The unique id for an image that has previously been requested.
125#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
126pub struct PendingImageId(pub u64);
127
128#[derive(Clone, Debug)]
129pub struct PendingImageResponse {
130    pub pipeline_id: PipelineId,
131    pub response: ImageResponse,
132    pub id: PendingImageId,
133}
134
135#[derive(Clone, Debug, Deserialize, Serialize)]
136pub struct RasterizationCompleteResponse {
137    pub pipeline_id: PipelineId,
138    pub image_id: PendingImageId,
139    pub requested_size: DeviceIntSize,
140}
141
142#[derive(Clone, Debug)]
143pub enum ImageCacheResponseMessage {
144    NotifyPendingImageLoadStatus(PendingImageResponse),
145    VectorImageRasterizationComplete(RasterizationCompleteResponse),
146}
147
148// ======================================================================
149// ImageCache public API.
150// ======================================================================
151
152pub enum ImageCacheResult {
153    Available(ImageOrMetadataAvailable),
154    FailedToLoadOrDecode,
155    Pending(PendingImageId),
156    ReadyForRequest(PendingImageId),
157}
158
159/// A shared [`ImageCacheFactory`] is a per-process data structure used to create an [`ImageCache`]
160/// inside that process in any `ScriptThread`. This allows sharing the same font database (for
161/// SVGs) and also decoding thread pool among all [`ImageCache`]s in the same process.
162pub trait ImageCacheFactory: Sync + Send {
163    fn create(
164        &self,
165        webview_id: WebViewId,
166        pipeline_id: PipelineId,
167        compositor_api: &CrossProcessCompositorApi,
168    ) -> Arc<dyn ImageCache>;
169}
170
171/// An [`ImageCache`] manages fetching and decoding images for a single `Pipeline` for its
172/// `Document` and all of its associated `Worker`s.
173pub trait ImageCache: Sync + Send {
174    fn memory_report(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Report;
175
176    /// Get an [`ImageKey`] to be used for external WebRender image management for
177    /// things like canvas rendering. Returns `None` when an [`ImageKey`] cannot
178    /// be generated properly.
179    fn get_image_key(&self) -> Option<ImageKey>;
180
181    /// Definitively check whether there is a cached, fully loaded image available.
182    fn get_image(
183        &self,
184        url: ServoUrl,
185        origin: ImmutableOrigin,
186        cors_setting: Option<CorsSettings>,
187    ) -> Option<Image>;
188
189    fn get_cached_image_status(
190        &self,
191        url: ServoUrl,
192        origin: ImmutableOrigin,
193        cors_setting: Option<CorsSettings>,
194    ) -> ImageCacheResult;
195
196    /// Returns `Some` if the given `image_id` has already been rasterized at the given `size`.
197    /// Otherwise, triggers a new job to perform the rasterization. If a notification
198    /// is needed after rasterization is completed, the `add_rasterization_complete_listener`
199    /// API below can be used to add a listener.
200    fn rasterize_vector_image(
201        &self,
202        image_id: VectorImageId,
203        size: DeviceIntSize,
204    ) -> Option<RasterImage>;
205
206    /// Adds a new listener to be notified once the given `image_id` has been rasterized at
207    /// the given `size`. The listener will receive a `VectorImageRasterizationComplete`
208    /// message on the given `sender`, even if the listener is called after rasterization
209    /// at has already completed.
210    fn add_rasterization_complete_listener(
211        &self,
212        pipeline_id: PipelineId,
213        image_id: VectorImageId,
214        size: DeviceIntSize,
215        callback: ImageCacheResponseCallback,
216    );
217
218    /// Synchronously get the broken image icon for this [`ImageCache`]. This will
219    /// allocate space for this icon and upload it to WebRender.
220    fn get_broken_image_icon(&self) -> Option<Arc<RasterImage>>;
221
222    /// Add a new listener for the given pending image id. If the image is already present,
223    /// the responder will still receive the expected response.
224    fn add_listener(&self, listener: ImageLoadListener);
225
226    /// Inform the image cache about a response for a pending request.
227    fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg);
228
229    /// Fills the image cache with a batch of keys.
230    fn fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<ImageKey>);
231}