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