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 },
89}
90
91#[derive(Clone, Copy, Debug)]
92pub enum ResolveImageError {
93 LoadError,
94 ImagePending,
95 OnlyMetadata,
96 InvalidUrl,
97 MissingNode,
98 ImageMissingFromImageSet,
99 NotImplementedYet,
100 None,
101}
102
103pub(crate) enum LayoutImageCacheResult {
104 Pending,
105 DataAvailable(ImageOrMetadataAvailable),
106 LoadError,
107}
108
109pub(crate) struct ImageResolver {
110 pub origin: ImmutableOrigin,
112
113 pub image_cache: Arc<dyn ImageCache>,
115
116 pub pending_images: Mutex<Vec<PendingImage>>,
118
119 pub pending_rasterization_images: Mutex<Vec<PendingRasterizationImage>>,
122
123 pub pending_svg_elements_for_serialization: Mutex<Vec<UntrustedNodeAddress>>,
129
130 pub animating_images: Arc<RwLock<AnimatingImages>>,
134
135 pub resolved_images_cache: Arc<RwLock<HashMap<ServoUrl, CachedImageOrError>>>,
138
139 pub animation_timeline_value: f64,
141}
142
143impl Drop for ImageResolver {
144 fn drop(&mut self) {
145 if !std::thread::panicking() {
146 assert!(self.pending_images.lock().is_empty());
147 assert!(self.pending_rasterization_images.lock().is_empty());
148 assert!(
149 self.pending_svg_elements_for_serialization
150 .lock()
151 .is_empty()
152 );
153 }
154 }
155}
156
157impl ImageResolver {
158 pub(crate) fn get_or_request_image_or_meta(
159 &self,
160 node: OpaqueNode,
161 url: ServoUrl,
162 destination: LayoutImageDestination,
163 is_internal_request: InternalRequest,
164 ) -> LayoutImageCacheResult {
165 let cache_result =
167 self.image_cache
168 .get_cached_image_status(url.clone(), self.origin.clone(), None);
169
170 match cache_result {
171 ImageCacheResult::Available(img_or_meta) => {
172 LayoutImageCacheResult::DataAvailable(img_or_meta)
173 },
174 ImageCacheResult::Pending(id) => {
177 let image = PendingImage {
178 state: PendingImageState::PendingResponse,
179 node: node.into(),
180 id,
181 origin: self.origin.clone(),
182 destination,
183 is_internal_request,
184 };
185 self.pending_images.lock().push(image);
186 LayoutImageCacheResult::Pending
187 },
188 ImageCacheResult::ReadyForRequest(id) => {
190 let image = PendingImage {
191 state: PendingImageState::Unrequested(url),
192 node: node.into(),
193 id,
194 origin: self.origin.clone(),
195 destination,
196 is_internal_request,
197 };
198 self.pending_images.lock().push(image);
199 LayoutImageCacheResult::Pending
200 },
201 ImageCacheResult::FailedToLoadOrDecode => LayoutImageCacheResult::LoadError,
203 }
204 }
205
206 pub(crate) fn handle_animated_image(&self, node: OpaqueNode, image: Arc<RasterImage>) {
207 let mut animating_images = self.animating_images.write();
208 if !image.should_animate() {
209 animating_images.remove(node);
210 } else {
211 animating_images.maybe_insert_or_update(node, image, self.animation_timeline_value);
212 }
213 }
214
215 pub(crate) fn get_cached_image_for_url(
216 &self,
217 node: OpaqueNode,
218 url: ServoUrl,
219 destination: LayoutImageDestination,
220 is_internal_request: InternalRequest,
221 ) -> Result<CachedImage, ResolveImageError> {
222 if let Some(cached_image) = self.resolved_images_cache.read().get(&url) {
223 return cached_image.clone();
224 }
225
226 let result =
227 self.get_or_request_image_or_meta(node, url.clone(), destination, is_internal_request);
228 match result {
229 LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
230 ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
231 if let Some(image) = image.as_raster_image() {
232 self.handle_animated_image(node, image);
233 }
234
235 let mut resolved_images_cache = self.resolved_images_cache.write();
236 resolved_images_cache.insert(url, Ok(image.clone()));
237 Ok(image)
238 },
239 ImageOrMetadataAvailable::MetadataAvailable(..) => {
240 Result::Err(ResolveImageError::OnlyMetadata)
241 },
242 },
243 LayoutImageCacheResult::Pending => Result::Err(ResolveImageError::ImagePending),
244 LayoutImageCacheResult::LoadError => {
245 let error = Err(ResolveImageError::LoadError);
246 self.resolved_images_cache
247 .write()
248 .insert(url, error.clone());
249 error
250 },
251 }
252 }
253
254 pub(crate) fn rasterize_vector_image(
255 &self,
256 image_id: PendingImageId,
257 size: DeviceIntSize,
258 node: OpaqueNode,
259 svg_id: Option<Uuid>,
260 ) -> Option<RasterImage> {
261 let result = self
262 .image_cache
263 .rasterize_vector_image(image_id, size, svg_id);
264 if result.is_none() {
265 self.pending_rasterization_images
266 .lock()
267 .push(PendingRasterizationImage {
268 id: image_id,
269 node: node.into(),
270 size,
271 });
272 }
273 result
274 }
275
276 pub(crate) fn image_key_from_cached_image(
278 &self,
279 image: &CachedImage,
280 size: DeviceIntSize,
281 node: Option<OpaqueNode>,
282 ) -> Option<ImageKey> {
283 match image {
284 CachedImage::Raster(raster_image) => raster_image.id,
285 CachedImage::Vector(vector_image) => node.and_then(|node| {
286 self.rasterize_vector_image(vector_image.id, size, node, vector_image.svg_id)
287 .and_then(|rasterized_image| rasterized_image.id)
288 }),
289 }
290 }
291
292 pub(crate) fn queue_svg_element_for_serialization(&self, element: ServoLayoutNode<'_>) {
293 self.pending_svg_elements_for_serialization
294 .lock()
295 .push(element.opaque().into())
296 }
297
298 pub(crate) fn resolve_image<'a>(
299 &self,
300 node: Option<OpaqueNode>,
301 image: &'a Image,
302 ) -> Result<ResolvedImage<'a>, ResolveImageError> {
303 match image {
304 Image::None => Result::Err(ResolveImageError::None),
306 Image::CrossFade(_) => Result::Err(ResolveImageError::NotImplementedYet),
307 Image::PaintWorklet(_) => Result::Err(ResolveImageError::NotImplementedYet),
308 Image::Gradient(gradient) => Ok(ResolvedImage::Gradient(gradient)),
309 Image::Image(color) => Ok(ResolvedImage::Color(color)),
310 Image::Url(image_url) => {
311 let image_url = image_url.url().ok_or(ResolveImageError::InvalidUrl)?;
318 let node = node.ok_or(ResolveImageError::MissingNode)?;
319 let image = self.get_cached_image_for_url(
320 node,
321 image_url.clone().into(),
322 LayoutImageDestination::DisplayListBuilding,
323 InternalRequest::No,
324 )?;
325 let metadata = image.metadata();
326 let size = Size2D::new(metadata.width, metadata.height).to_f32();
327 Ok(ResolvedImage::Image { image, size })
328 },
329 Image::ImageSet(image_set) => {
330 image_set
331 .items
332 .get(image_set.selected_index)
333 .ok_or(ResolveImageError::ImageMissingFromImageSet)
334 .and_then(|image| {
335 self.resolve_image(node, &image.image)
336 .map(|info| match info {
337 ResolvedImage::Image {
338 image: cached_image,
339 ..
340 } => {
341 let image_metadata = cached_image.metadata();
348 let size = if cached_image.as_raster_image().is_some() {
349 let scale_factor = image.resolution.dppx();
350 Size2D::new(
351 image_metadata.width as f32 / scale_factor,
352 image_metadata.height as f32 / scale_factor,
353 )
354 } else {
355 Size2D::new(image_metadata.width, image_metadata.height)
356 .to_f32()
357 };
358
359 ResolvedImage::Image {
360 image: cached_image,
361 size,
362 }
363 },
364 _ => info,
365 })
366 })
367 },
368 Image::LightDark(..) => unreachable!("light-dark() should be disabled"),
369 }
370 }
371}