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;
8use compositing_traits::CrossProcessCompositorApi;
9use ipc_channel::ipc::IpcSender;
10use log::debug;
11use malloc_size_of::MallocSizeOfOps;
12use malloc_size_of_derive::MallocSizeOf;
13use pixels::{CorsStatus, ImageMetadata, RasterImage};
14use profile_traits::mem::Report;
15use serde::{Deserialize, Serialize};
16use servo_url::{ImmutableOrigin, ServoUrl};
17use webrender_api::ImageKey;
18use webrender_api::units::DeviceIntSize;
19
20use crate::FetchResponseMsg;
21use crate::request::CorsSettings;
22
23// ======================================================================
24// Aux structs and enums.
25// ======================================================================
26
27pub type VectorImageId = PendingImageId;
28
29// Represents either a raster image for which the pixel data is available
30// or a vector image for which only the natural dimensions are available
31// and thus requires a further rasterization step to render.
32#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
33pub enum Image {
34    Raster(#[conditional_malloc_size_of] Arc<RasterImage>),
35    Vector(VectorImage),
36}
37
38#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
39pub struct VectorImage {
40    pub id: VectorImageId,
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, Deserialize, MallocSizeOf, Serialize)]
70pub enum ImageOrMetadataAvailable {
71    ImageAvailable {
72        image: Image,
73        url: ServoUrl,
74        is_placeholder: bool,
75    },
76    MetadataAvailable(ImageMetadata, PendingImageId),
77}
78
79/// This is optionally passed to the image cache when requesting
80/// and image, and returned to the specified event loop when the
81/// image load completes. It is typically used to trigger a reflow
82/// and/or repaint.
83#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
84pub struct ImageLoadListener {
85    pipeline_id: PipelineId,
86    pub id: PendingImageId,
87    sender: IpcSender<ImageCacheResponseMessage>,
88}
89
90impl ImageLoadListener {
91    pub fn new(
92        sender: IpcSender<ImageCacheResponseMessage>,
93        pipeline_id: PipelineId,
94        id: PendingImageId,
95    ) -> ImageLoadListener {
96        ImageLoadListener {
97            pipeline_id,
98            sender,
99            id,
100        }
101    }
102
103    pub fn respond(&self, response: ImageResponse) {
104        debug!("Notifying listener");
105        // This send can fail if thread waiting for this notification has panicked.
106        // That's not a case that's worth warning about.
107        // TODO(#15501): are there cases in which we should perform cleanup?
108        let _ = self
109            .sender
110            .send(ImageCacheResponseMessage::NotifyPendingImageLoadStatus(
111                PendingImageResponse {
112                    pipeline_id: self.pipeline_id,
113                    response,
114                    id: self.id,
115                },
116            ));
117    }
118}
119
120/// The returned image.
121#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
122pub enum ImageResponse {
123    /// The requested image was loaded.
124    Loaded(Image, ServoUrl),
125    /// The request image metadata was loaded.
126    MetadataLoaded(ImageMetadata),
127    /// The requested image failed to load, so a placeholder was loaded instead.
128    PlaceholderLoaded(#[conditional_malloc_size_of] Arc<RasterImage>, ServoUrl),
129    /// Neither the requested image nor the placeholder could be loaded.
130    None,
131}
132
133/// The unique id for an image that has previously been requested.
134#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
135pub struct PendingImageId(pub u64);
136
137#[derive(Clone, Debug, Deserialize, Serialize)]
138pub struct PendingImageResponse {
139    pub pipeline_id: PipelineId,
140    pub response: ImageResponse,
141    pub id: PendingImageId,
142}
143
144#[derive(Clone, Debug, Deserialize, Serialize)]
145pub struct RasterizationCompleteResponse {
146    pub pipeline_id: PipelineId,
147    pub image_id: PendingImageId,
148    pub requested_size: DeviceIntSize,
149}
150
151#[derive(Clone, Debug, Deserialize, Serialize)]
152pub enum ImageCacheResponseMessage {
153    NotifyPendingImageLoadStatus(PendingImageResponse),
154    VectorImageRasterizationComplete(RasterizationCompleteResponse),
155}
156
157#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
158pub enum UsePlaceholder {
159    No,
160    Yes,
161}
162
163// ======================================================================
164// ImageCache public API.
165// ======================================================================
166
167pub enum ImageCacheResult {
168    Available(ImageOrMetadataAvailable),
169    LoadError,
170    Pending(PendingImageId),
171    ReadyForRequest(PendingImageId),
172}
173
174pub trait ImageCache: Sync + Send {
175    fn new(compositor_api: CrossProcessCompositorApi, rippy_data: Vec<u8>) -> Self
176    where
177        Self: Sized;
178
179    fn memory_report(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Report;
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        use_placeholder: UsePlaceholder,
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    ) -> Option<RasterImage>;
206
207    /// Adds a new listener to be notified once the given `image_id` has been rasterized at
208    /// the given `size`. The listener will receive a `VectorImageRasterizationComplete`
209    /// message on the given `sender`, even if the listener is called after rasterization
210    /// at has already completed.
211    fn add_rasterization_complete_listener(
212        &self,
213        pipeline_id: PipelineId,
214        image_id: VectorImageId,
215        size: DeviceIntSize,
216        sender: IpcSender<ImageCacheResponseMessage>,
217    );
218
219    /// Add a new listener for the given pending image id. If the image is already present,
220    /// the responder will still receive the expected response.
221    fn add_listener(&self, listener: ImageLoadListener);
222
223    /// Inform the image cache about a response for a pending request.
224    fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg);
225
226    /// Create new image cache based on this one, while reusing the existing thread_pool.
227    fn create_new_image_cache(
228        &self,
229        pipeline_id: Option<PipelineId>,
230        compositor_api: CrossProcessCompositorApi,
231    ) -> Arc<dyn ImageCache>;
232
233    /// Fills the image cache with a batch of keys.
234    fn fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<ImageKey>);
235}