1use std::collections::HashMap;
6use std::sync::Arc;
7
8use embedder_traits::UntrustedNodeAddress;
9use euclid::Size2D;
10use fonts::FontContext;
11use layout_api::{
12 AnimatingImages, IFrameSizes, LayoutImageDestination, LayoutNode, PendingImage,
13 PendingImageState, PendingRasterizationImage,
14};
15use net_traits::image_cache::{
16 Image as CachedImage, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, PendingImageId,
17};
18use net_traits::request::InternalRequest;
19use parking_lot::{Mutex, RwLock};
20use pixels::RasterImage;
21use script::layout_dom::ServoLayoutNode;
22use servo_base::id::PainterId;
23use servo_url::{ImmutableOrigin, ServoUrl};
24use style::context::SharedStyleContext;
25use style::dom::OpaqueNode;
26use style::values::computed::color::Color;
27use style::values::computed::image::{Gradient, Image};
28use style_traits::DevicePixel;
29use uuid::Uuid;
30use webrender_api::ImageKey;
31use webrender_api::units::{DeviceIntSize, DeviceSize};
32
33pub(crate) type CachedImageOrError = Result<CachedImage, ResolveImageError>;
34
35pub(crate) struct LayoutContext<'a> {
36 pub style_context: SharedStyleContext<'a>,
38
39 pub font_context: Arc<FontContext>,
41
42 pub iframe_sizes: Mutex<IFrameSizes>,
44
45 pub image_resolver: Arc<ImageResolver>,
48
49 pub painter_id: PainterId,
51
52 pub allow_parallel_layout: bool,
54
55 pub parallelism_job_count_minimum: usize,
58
59 pub parallelism_job_size_minimum: usize,
62
63 pub device_size: Size2D<f32, DevicePixel>,
65}
66
67impl LayoutContext<'_> {
68 pub(crate) fn should_parallelize(&self, number_of_jobs: usize) -> bool {
69 self.allow_parallel_layout && number_of_jobs >= self.parallelism_job_count_minimum
70 }
71
72 pub(crate) fn should_parallelize_layout(&self, jobs: impl Iterator<Item = usize>) -> bool {
73 self.allow_parallel_layout &&
74 jobs.filter(|job| *job >= self.parallelism_job_size_minimum)
75 .count() >=
76 self.parallelism_job_count_minimum
77 }
78}
79
80pub enum ResolvedImage<'a> {
81 Gradient(&'a Gradient),
82 Color(&'a Color),
83 Image {
86 image: CachedImage,
87 size: DeviceSize,
88 url: ServoUrl,
89 },
90}
91
92#[derive(Clone, Copy, Debug)]
93pub enum ResolveImageError {
94 LoadError,
95 ImagePending,
96 OnlyMetadata,
97 InvalidUrl,
98 MissingNode,
99 ImageMissingFromImageSet,
100 NotImplementedYet,
101 None,
102}
103
104pub(crate) enum LayoutImageCacheResult {
105 Pending,
106 DataAvailable(ImageOrMetadataAvailable),
107 LoadError,
108}
109
110pub(crate) struct ImageResolver {
111 pub origin: ImmutableOrigin,
113
114 pub image_cache: Arc<dyn ImageCache>,
116
117 pub pending_images: Mutex<Vec<PendingImage>>,
119
120 pub pending_rasterization_images: Mutex<Vec<PendingRasterizationImage>>,
123
124 pub pending_svg_elements_for_serialization: Mutex<Vec<UntrustedNodeAddress>>,
130
131 pub animating_images: Arc<RwLock<AnimatingImages>>,
135
136 pub resolved_images_cache: Arc<RwLock<HashMap<ServoUrl, CachedImageOrError>>>,
139
140 pub animation_timeline_value: f64,
142}
143
144impl Drop for ImageResolver {
145 fn drop(&mut self) {
146 if !std::thread::panicking() {
147 assert!(self.pending_images.lock().is_empty());
148 assert!(self.pending_rasterization_images.lock().is_empty());
149 assert!(
150 self.pending_svg_elements_for_serialization
151 .lock()
152 .is_empty()
153 );
154 }
155 }
156}
157
158impl ImageResolver {
159 pub(crate) fn get_or_request_image_or_meta(
160 &self,
161 node: OpaqueNode,
162 url: ServoUrl,
163 destination: LayoutImageDestination,
164 is_internal_request: InternalRequest,
165 ) -> LayoutImageCacheResult {
166 let cache_result =
168 self.image_cache
169 .get_cached_image_status(url.clone(), self.origin.clone(), None);
170
171 match cache_result {
172 ImageCacheResult::Available(img_or_meta) => {
173 LayoutImageCacheResult::DataAvailable(img_or_meta)
174 },
175 ImageCacheResult::Pending(id) => {
178 let image = PendingImage {
179 state: PendingImageState::PendingResponse,
180 node: node.into(),
181 id,
182 origin: self.origin.clone(),
183 destination,
184 is_internal_request,
185 };
186 self.pending_images.lock().push(image);
187 LayoutImageCacheResult::Pending
188 },
189 ImageCacheResult::ReadyForRequest(id) => {
191 let image = PendingImage {
192 state: PendingImageState::Unrequested(url),
193 node: node.into(),
194 id,
195 origin: self.origin.clone(),
196 destination,
197 is_internal_request,
198 };
199 self.pending_images.lock().push(image);
200 LayoutImageCacheResult::Pending
201 },
202 ImageCacheResult::FailedToLoadOrDecode => LayoutImageCacheResult::LoadError,
204 }
205 }
206
207 pub(crate) fn handle_animated_image(&self, node: OpaqueNode, image: Arc<RasterImage>) {
208 let mut animating_images = self.animating_images.write();
209 if !image.should_animate() {
210 animating_images.remove(node);
211 } else {
212 animating_images.maybe_insert_or_update(node, image, self.animation_timeline_value);
213 }
214 }
215
216 pub(crate) fn get_cached_image_for_url(
217 &self,
218 node: OpaqueNode,
219 url: ServoUrl,
220 destination: LayoutImageDestination,
221 is_internal_request: InternalRequest,
222 ) -> Result<CachedImage, ResolveImageError> {
223 if let Some(cached_image) = self.resolved_images_cache.read().get(&url) {
224 return cached_image.clone();
225 }
226
227 let result =
228 self.get_or_request_image_or_meta(node, url.clone(), destination, is_internal_request);
229 match result {
230 LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
231 ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
232 if let Some(image) = image.as_raster_image() {
233 self.handle_animated_image(node, image);
234 }
235
236 let mut resolved_images_cache = self.resolved_images_cache.write();
237 resolved_images_cache.insert(url, Ok(image.clone()));
238 Ok(image)
239 },
240 ImageOrMetadataAvailable::MetadataAvailable(..) => {
241 Result::Err(ResolveImageError::OnlyMetadata)
242 },
243 },
244 LayoutImageCacheResult::Pending => Result::Err(ResolveImageError::ImagePending),
245 LayoutImageCacheResult::LoadError => {
246 let error = Err(ResolveImageError::LoadError);
247 self.resolved_images_cache
248 .write()
249 .insert(url, error.clone());
250 error
251 },
252 }
253 }
254
255 pub(crate) fn rasterize_vector_image(
256 &self,
257 image_id: PendingImageId,
258 size: DeviceIntSize,
259 node: OpaqueNode,
260 svg_id: Option<Uuid>,
261 ) -> Option<RasterImage> {
262 let result = self
263 .image_cache
264 .rasterize_vector_image(image_id, size, svg_id);
265 if result.is_none() {
266 self.pending_rasterization_images
267 .lock()
268 .push(PendingRasterizationImage {
269 id: image_id,
270 node: node.into(),
271 size,
272 });
273 }
274 result
275 }
276
277 pub(crate) fn image_key_from_cached_image(
279 &self,
280 image: &CachedImage,
281 size: DeviceIntSize,
282 node: Option<OpaqueNode>,
283 ) -> Option<ImageKey> {
284 match image {
285 CachedImage::Raster(raster_image) => raster_image.id,
286 CachedImage::Vector(vector_image) => node.and_then(|node| {
287 self.rasterize_vector_image(vector_image.id, size, node, vector_image.svg_id)
288 .and_then(|rasterized_image| rasterized_image.id)
289 }),
290 }
291 }
292
293 pub(crate) fn queue_svg_element_for_serialization(&self, element: ServoLayoutNode<'_>) {
294 self.pending_svg_elements_for_serialization
295 .lock()
296 .push(element.opaque().into())
297 }
298
299 pub(crate) fn resolve_image<'a>(
300 &self,
301 node: Option<OpaqueNode>,
302 image: &'a Image,
303 ) -> Result<ResolvedImage<'a>, ResolveImageError> {
304 match image {
305 Image::None => Result::Err(ResolveImageError::None),
307 Image::CrossFade(_) => Result::Err(ResolveImageError::NotImplementedYet),
308 Image::PaintWorklet(_) => Result::Err(ResolveImageError::NotImplementedYet),
309 Image::Gradient(gradient) => Ok(ResolvedImage::Gradient(gradient)),
310 Image::Image(color) => Ok(ResolvedImage::Color(color)),
311 Image::Url(image_url) => {
312 let image_url = image_url.url().ok_or(ResolveImageError::InvalidUrl)?;
319 let node = node.ok_or(ResolveImageError::MissingNode)?;
320 let image = self.get_cached_image_for_url(
321 node,
322 image_url.clone().into(),
323 LayoutImageDestination::DisplayListBuilding,
324 InternalRequest::No,
325 )?;
326 let metadata = image.metadata();
327 let size = Size2D::new(metadata.width, metadata.height).to_f32();
328 Ok(ResolvedImage::Image {
329 image,
330 size,
331 url: image_url.clone().into(),
332 })
333 },
334 Image::ImageSet(image_set) => {
335 image_set
336 .items
337 .get(image_set.selected_index)
338 .ok_or(ResolveImageError::ImageMissingFromImageSet)
339 .and_then(|image| {
340 self.resolve_image(node, &image.image)
341 .map(|info| match info {
342 ResolvedImage::Image {
343 image: cached_image,
344 url,
345 ..
346 } => {
347 let image_metadata = cached_image.metadata();
354 let size = if cached_image.as_raster_image().is_some() {
355 let scale_factor = image.resolution.dppx();
356 Size2D::new(
357 image_metadata.width as f32 / scale_factor,
358 image_metadata.height as f32 / scale_factor,
359 )
360 } else {
361 Size2D::new(image_metadata.width, image_metadata.height)
362 .to_f32()
363 };
364
365 ResolvedImage::Image {
366 image: cached_image,
367 size,
368 url,
369 }
370 },
371 _ => info,
372 })
373 })
374 },
375 Image::LightDark(..) => unreachable!("light-dark() should be disabled"),
376 }
377 }
378}