1use std::cmp::min;
6use std::collections::hash_map::Entry::{Occupied, Vacant};
7use std::collections::{HashMap, VecDeque};
8use std::sync::{Arc, Mutex};
9use std::{mem, thread};
10
11use base::id::PipelineId;
12use compositing_traits::{CrossProcessCompositorApi, ImageUpdate, SerializableImageData};
13use imsz::imsz_from_reader;
14use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
15use log::{debug, error, warn};
16use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
17use malloc_size_of_derive::MallocSizeOf;
18use mime::Mime;
19use net_traits::image_cache::{
20 Image, ImageCache, ImageCacheResponseMessage, ImageCacheResult, ImageLoadListener,
21 ImageOrMetadataAvailable, ImageResponse, PendingImageId, RasterizationCompleteResponse,
22 UsePlaceholder, VectorImage,
23};
24use net_traits::request::CorsSettings;
25use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
26use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage, load_from_memory};
27use profile_traits::mem::{Report, ReportKind};
28use profile_traits::path;
29use resvg::{tiny_skia, usvg};
30use rustc_hash::FxHashMap;
31use servo_config::pref;
32use servo_url::{ImmutableOrigin, ServoUrl};
33use webrender_api::units::DeviceIntSize;
34use webrender_api::{
35 ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey as WebRenderImageKey,
36};
37
38use crate::resource_thread::CoreResourceThreadPool;
39
40const FALLBACK_RIPPY: &[u8] = include_bytes!("../../resources/rippy.png");
44
45const MAX_SVG_PIXMAP_DIMENSION: u32 = 5000;
53
54fn parse_svg_document_in_memory(bytes: &[u8]) -> Result<usvg::Tree, &'static str> {
69 let image_string_href_resolver = Box::new(move |_: &str, _: &usvg::Options| {
70 None
72 });
73
74 let mut opt = usvg::Options {
75 image_href_resolver: usvg::ImageHrefResolver {
76 resolve_data: usvg::ImageHrefResolver::default_data_resolver(),
77 resolve_string: image_string_href_resolver,
78 },
79 ..usvg::Options::default()
80 };
81
82 opt.fontdb_mut().load_system_fonts();
83
84 usvg::Tree::from_data(bytes, &opt)
85 .inspect_err(|error| {
86 warn!("Error when parsing SVG data: {error}");
87 })
88 .map_err(|_| "Not a valid SVG document")
89}
90
91fn decode_bytes_sync(
92 key: LoadKey,
93 bytes: &[u8],
94 cors: CorsStatus,
95 content_type: Option<Mime>,
96) -> DecoderMsg {
97 let image = if content_type == Some(mime::IMAGE_SVG) {
98 parse_svg_document_in_memory(bytes).ok().map(|svg_tree| {
99 DecodedImage::Vector(VectorImageData {
100 svg_tree: Arc::new(svg_tree),
101 cors_status: cors,
102 })
103 })
104 } else {
105 load_from_memory(bytes, cors).map(DecodedImage::Raster)
106 };
107
108 DecoderMsg { key, image }
109}
110
111fn get_placeholder_image(
114 compositor_api: &CrossProcessCompositorApi,
115 data: &[u8],
116) -> Arc<RasterImage> {
117 let mut image = load_from_memory(data, CorsStatus::Unsafe)
118 .or_else(|| load_from_memory(FALLBACK_RIPPY, CorsStatus::Unsafe))
119 .expect("load fallback image failed");
120 let image_key = compositor_api
121 .generate_image_key_blocking()
122 .expect("Could not generate image key");
123 set_webrender_image_key(compositor_api, &mut image, image_key);
124 Arc::new(image)
125}
126
127fn set_webrender_image_key(
128 compositor_api: &CrossProcessCompositorApi,
129 image: &mut RasterImage,
130 image_key: WebRenderImageKey,
131) {
132 if image.id.is_some() {
133 return;
134 }
135 let mut bytes = Vec::new();
136 let frame_bytes = image.first_frame().bytes;
137 let is_opaque = match image.format {
138 PixelFormat::BGRA8 | PixelFormat::RGBA8 => {
139 bytes.extend_from_slice(frame_bytes);
140 pixels::rgba8_premultiply_inplace(bytes.as_mut_slice())
141 },
142 PixelFormat::RGB8 => {
143 bytes.reserve(frame_bytes.len() / 3 * 4);
144 for bgr in frame_bytes.chunks(3) {
145 bytes.extend_from_slice(&[bgr[2], bgr[1], bgr[0], 0xff]);
146 }
147
148 true
149 },
150 PixelFormat::K8 | PixelFormat::KA8 => {
151 panic!("Not support by webrender yet");
152 },
153 };
154 let format = if matches!(image.format, PixelFormat::RGBA8) {
155 ImageFormat::RGBA8
156 } else {
157 ImageFormat::BGRA8
158 };
159
160 let mut flags = ImageDescriptorFlags::ALLOW_MIPMAPS;
161 flags.set(ImageDescriptorFlags::IS_OPAQUE, is_opaque);
162
163 let size = DeviceIntSize::new(image.metadata.width as i32, image.metadata.height as i32);
164 let descriptor = ImageDescriptor {
165 size,
166 stride: None,
167 format,
168 offset: 0,
169 flags,
170 };
171 let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(&bytes));
172 compositor_api.add_image(image_key, descriptor, data);
173 image.id = Some(image_key);
174}
175
176type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
182
183#[derive(MallocSizeOf)]
186struct AllPendingLoads {
187 loads: FxHashMap<LoadKey, PendingLoad>,
190
191 url_to_load_key: HashMap<ImageKey, LoadKey>,
194
195 keygen: LoadKeyGenerator,
197}
198
199impl AllPendingLoads {
200 fn new() -> AllPendingLoads {
201 AllPendingLoads {
202 loads: FxHashMap::default(),
203 url_to_load_key: HashMap::default(),
204 keygen: LoadKeyGenerator::new(),
205 }
206 }
207
208 fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
210 self.loads.get_mut(key)
211 }
212
213 fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
214 self.loads.remove(key).inspect(|pending_load| {
215 self.url_to_load_key
216 .remove(&(
217 pending_load.url.clone(),
218 pending_load.load_origin.clone(),
219 pending_load.cors_setting,
220 ))
221 .unwrap();
222 })
223 }
224
225 fn get_cached(
226 &mut self,
227 url: ServoUrl,
228 origin: ImmutableOrigin,
229 cors_status: Option<CorsSettings>,
230 ) -> CacheResult<'_> {
231 match self
232 .url_to_load_key
233 .entry((url.clone(), origin.clone(), cors_status))
234 {
235 Occupied(url_entry) => {
236 let load_key = url_entry.get();
237 CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap())
238 },
239 Vacant(url_entry) => {
240 let load_key = self.keygen.next();
241 url_entry.insert(load_key);
242
243 let pending_load = PendingLoad::new(url, origin, cors_status);
244 match self.loads.entry(load_key) {
245 Occupied(_) => unreachable!(),
246 Vacant(load_entry) => {
247 let mut_load = load_entry.insert(pending_load);
248 CacheResult::Miss(Some((load_key, mut_load)))
249 },
250 }
251 },
252 }
253 }
254}
255
256enum CacheResult<'a> {
258 Hit(LoadKey, &'a mut PendingLoad),
260 Miss(Option<(LoadKey, &'a mut PendingLoad)>),
262}
263
264#[derive(MallocSizeOf)]
269struct CompletedLoad {
270 image_response: ImageResponse,
271 id: PendingImageId,
272}
273
274impl CompletedLoad {
275 fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
276 CompletedLoad { image_response, id }
277 }
278}
279
280#[derive(Clone, MallocSizeOf)]
281struct VectorImageData {
282 #[conditional_malloc_size_of]
283 svg_tree: Arc<usvg::Tree>,
284 cors_status: CorsStatus,
285}
286
287impl std::fmt::Debug for VectorImageData {
288 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289 f.debug_struct("VectorImageData").finish()
290 }
291}
292
293enum DecodedImage {
294 Raster(RasterImage),
295 Vector(VectorImageData),
296}
297
298struct DecoderMsg {
300 key: LoadKey,
301 image: Option<DecodedImage>,
302}
303
304#[derive(MallocSizeOf)]
305enum ImageBytes {
306 InProgress(Vec<u8>),
307 Complete(#[conditional_malloc_size_of] Arc<Vec<u8>>),
308}
309
310impl ImageBytes {
311 fn extend_from_slice(&mut self, data: &[u8]) {
312 match *self {
313 ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
314 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
315 }
316 }
317
318 fn mark_complete(&mut self) -> Arc<Vec<u8>> {
319 let bytes = {
320 let own_bytes = match *self {
321 ImageBytes::InProgress(ref mut bytes) => bytes,
322 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
323 };
324 mem::take(own_bytes)
325 };
326 let bytes = Arc::new(bytes);
327 *self = ImageBytes::Complete(bytes.clone());
328 bytes
329 }
330
331 fn as_slice(&self) -> &[u8] {
332 match *self {
333 ImageBytes::InProgress(ref bytes) => bytes,
334 ImageBytes::Complete(ref bytes) => bytes,
335 }
336 }
337}
338
339type LoadKey = PendingImageId;
341
342#[derive(MallocSizeOf)]
343struct LoadKeyGenerator {
344 counter: u64,
345}
346
347impl LoadKeyGenerator {
348 fn new() -> LoadKeyGenerator {
349 LoadKeyGenerator { counter: 0 }
350 }
351 fn next(&mut self) -> PendingImageId {
352 self.counter += 1;
353 PendingImageId(self.counter)
354 }
355}
356
357#[derive(Debug)]
358enum LoadResult {
359 LoadedRasterImage(RasterImage),
360 LoadedVectorImage(VectorImageData),
361 PlaceholderLoaded(Arc<RasterImage>),
362 None,
363}
364
365#[derive(MallocSizeOf)]
368struct PendingLoad {
369 bytes: ImageBytes,
372
373 metadata: Option<ImageMetadata>,
375
376 result: Option<Result<(), NetworkError>>,
378
379 listeners: Vec<ImageLoadListener>,
381
382 url: ServoUrl,
385
386 load_origin: ImmutableOrigin,
388
389 cors_setting: Option<CorsSettings>,
391
392 cors_status: CorsStatus,
394
395 final_url: Option<ServoUrl>,
397
398 content_type: Option<Mime>,
400}
401
402impl PendingLoad {
403 fn new(
404 url: ServoUrl,
405 load_origin: ImmutableOrigin,
406 cors_setting: Option<CorsSettings>,
407 ) -> PendingLoad {
408 PendingLoad {
409 bytes: ImageBytes::InProgress(vec![]),
410 metadata: None,
411 result: None,
412 listeners: vec![],
413 url,
414 load_origin,
415 final_url: None,
416 cors_setting,
417 cors_status: CorsStatus::Unsafe,
418 content_type: None,
419 }
420 }
421
422 fn add_listener(&mut self, listener: ImageLoadListener) {
423 self.listeners.push(listener);
424 }
425}
426
427#[derive(Default, MallocSizeOf)]
428struct RasterizationTask {
429 listeners: Vec<(PipelineId, IpcSender<ImageCacheResponseMessage>)>,
430 result: Option<RasterImage>,
431}
432
433#[derive(Debug, MallocSizeOf)]
435enum PendingKey {
436 RasterImage((LoadKey, RasterImage)),
437 Svg((LoadKey, RasterImage, DeviceIntSize)),
438}
439
440#[derive(Debug, MallocSizeOf)]
442enum KeyCacheState {
443 PendingBatch,
445 Ready(Vec<WebRenderImageKey>),
447}
448
449impl KeyCacheState {
450 fn size(&self) -> usize {
451 match self {
452 KeyCacheState::PendingBatch => 0,
453 KeyCacheState::Ready(items) => items.len(),
454 }
455 }
456}
457
458#[derive(MallocSizeOf)]
462struct KeyCache {
463 cache: KeyCacheState,
465 images_pending_keys: VecDeque<PendingKey>,
467}
468
469impl KeyCache {
470 fn new() -> Self {
471 KeyCache {
472 cache: KeyCacheState::Ready(Vec::new()),
473 images_pending_keys: VecDeque::new(),
474 }
475 }
476}
477
478#[derive(MallocSizeOf)]
480struct ImageCacheStore {
481 pending_loads: AllPendingLoads,
483
484 completed_loads: HashMap<ImageKey, CompletedLoad>,
486
487 vector_images: FxHashMap<PendingImageId, VectorImageData>,
491
492 rasterized_vector_images: FxHashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
496
497 #[conditional_malloc_size_of]
499 placeholder_image: Arc<RasterImage>,
500
501 placeholder_url: ServoUrl,
503
504 #[ignore_malloc_size_of = "Channel from another crate"]
506 compositor_api: CrossProcessCompositorApi,
507
508 pipeline_id: Option<PipelineId>,
511
512 key_cache: KeyCache,
515}
516
517impl ImageCacheStore {
518 fn set_key_and_finish_load(&mut self, pending_image: PendingKey, image_key: WebRenderImageKey) {
520 match pending_image {
521 PendingKey::RasterImage((pending_id, mut raster_image)) => {
522 set_webrender_image_key(&self.compositor_api, &mut raster_image, image_key);
523 self.complete_load(pending_id, LoadResult::LoadedRasterImage(raster_image));
524 },
525 PendingKey::Svg((pending_id, mut raster_image, requested_size)) => {
526 set_webrender_image_key(&self.compositor_api, &mut raster_image, image_key);
527 self.complete_load_svg(raster_image, pending_id, requested_size);
528 },
529 }
530 }
531
532 fn load_image_with_keycache(&mut self, pending_image: PendingKey) {
535 if let Some(pipeline_id) = self.pipeline_id {
536 match self.key_cache.cache {
537 KeyCacheState::PendingBatch => {
538 self.key_cache.images_pending_keys.push_back(pending_image);
539 },
540 KeyCacheState::Ready(ref mut cache) => match cache.pop() {
541 Some(image_key) => {
542 self.set_key_and_finish_load(pending_image, image_key);
543 },
544 None => {
545 self.key_cache.images_pending_keys.push_back(pending_image);
546 self.compositor_api.generate_image_key_async(pipeline_id);
547 self.key_cache.cache = KeyCacheState::PendingBatch
548 },
549 },
550 }
551 } else {
552 error!("No pipeline id for this image key cache.");
553 }
554 }
555
556 fn insert_keys_and_load_images(&mut self, image_keys: Vec<WebRenderImageKey>) {
558 if let KeyCacheState::PendingBatch = self.key_cache.cache {
559 self.key_cache.cache = KeyCacheState::Ready(image_keys);
560 let len = min(
561 self.key_cache.cache.size(),
562 self.key_cache.images_pending_keys.len(),
563 );
564 let images = self
565 .key_cache
566 .images_pending_keys
567 .drain(0..len)
568 .collect::<Vec<PendingKey>>();
569 for key in images {
570 self.load_image_with_keycache(key);
571 }
572 if !self.key_cache.images_pending_keys.is_empty() {
573 self.compositor_api
574 .generate_image_key_async(self.pipeline_id.unwrap());
575 self.key_cache.cache = KeyCacheState::PendingBatch
576 }
577 } else {
578 unreachable!("A batch was received while we didn't request one")
579 }
580 }
581
582 fn complete_load_svg(
585 &mut self,
586 rasterized_image: RasterImage,
587 pending_image_id: PendingImageId,
588 requested_size: DeviceIntSize,
589 ) {
590 let listeners = {
591 self.rasterized_vector_images
592 .get_mut(&(pending_image_id, requested_size))
593 .map(|task| {
594 task.result = Some(rasterized_image);
595 std::mem::take(&mut task.listeners)
596 })
597 .unwrap_or_default()
598 };
599
600 for (pipeline_id, sender) in listeners {
601 let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
602 RasterizationCompleteResponse {
603 pipeline_id,
604 image_id: pending_image_id,
605 requested_size,
606 },
607 ));
608 }
609 }
610
611 fn complete_load(&mut self, key: LoadKey, load_result: LoadResult) {
613 debug!("Completed decoding for {:?}", load_result);
614 let pending_load = match self.pending_loads.remove(&key) {
615 Some(load) => load,
616 None => return,
617 };
618
619 let url = pending_load.final_url.clone();
620 let image_response = match load_result {
621 LoadResult::LoadedRasterImage(raster_image) => {
622 assert!(raster_image.id.is_some());
623 ImageResponse::Loaded(Image::Raster(Arc::new(raster_image)), url.unwrap())
624 },
625 LoadResult::LoadedVectorImage(vector_image) => {
626 self.vector_images.insert(key, vector_image.clone());
627 let natural_dimensions = vector_image.svg_tree.size().to_int_size();
628 let metadata = ImageMetadata {
629 width: natural_dimensions.width(),
630 height: natural_dimensions.height(),
631 };
632
633 let vector_image = VectorImage {
634 id: key,
635 metadata,
636 cors_status: vector_image.cors_status,
637 };
638 ImageResponse::Loaded(Image::Vector(vector_image), url.unwrap())
639 },
640 LoadResult::PlaceholderLoaded(image) => {
641 ImageResponse::PlaceholderLoaded(image, self.placeholder_url.clone())
642 },
643 LoadResult::None => ImageResponse::None,
644 };
645
646 let completed_load = CompletedLoad::new(image_response.clone(), key);
647 self.completed_loads.insert(
648 (
649 pending_load.url,
650 pending_load.load_origin,
651 pending_load.cors_setting,
652 ),
653 completed_load,
654 );
655
656 for listener in pending_load.listeners {
657 listener.respond(image_response.clone());
658 }
659 }
660
661 fn get_completed_image_if_available(
664 &self,
665 url: ServoUrl,
666 origin: ImmutableOrigin,
667 cors_setting: Option<CorsSettings>,
668 placeholder: UsePlaceholder,
669 ) -> Option<Result<(Image, ServoUrl), ()>> {
670 self.completed_loads
671 .get(&(url, origin, cors_setting))
672 .map(
673 |completed_load| match (&completed_load.image_response, placeholder) {
674 (ImageResponse::Loaded(image, url), _) => Ok((image.clone(), url.clone())),
675 (ImageResponse::PlaceholderLoaded(image, url), UsePlaceholder::Yes) => {
676 Ok((Image::Raster(image.clone()), url.clone()))
677 },
678 (ImageResponse::PlaceholderLoaded(_, _), UsePlaceholder::No) |
679 (ImageResponse::None, _) |
680 (ImageResponse::MetadataLoaded(_), _) => Err(()),
681 },
682 )
683 }
684
685 fn handle_decoder(&mut self, msg: DecoderMsg) {
688 let image = match msg.image {
689 None => LoadResult::None,
690 Some(DecodedImage::Raster(raster_image)) => {
691 self.load_image_with_keycache(PendingKey::RasterImage((msg.key, raster_image)));
692 return;
693 },
694 Some(DecodedImage::Vector(vector_image_data)) => {
695 LoadResult::LoadedVectorImage(vector_image_data)
696 },
697 };
698 self.complete_load(msg.key, image);
699 }
700}
701
702pub struct ImageCacheImpl {
703 store: Arc<Mutex<ImageCacheStore>>,
704
705 thread_pool: Arc<CoreResourceThreadPool>,
707}
708
709impl ImageCache for ImageCacheImpl {
710 fn new(compositor_api: CrossProcessCompositorApi, rippy_data: Vec<u8>) -> ImageCacheImpl {
711 debug!("New image cache");
712
713 let thread_count = thread::available_parallelism()
717 .map(|i| i.get())
718 .unwrap_or(pref!(threadpools_fallback_worker_num) as usize)
719 .min(pref!(threadpools_image_cache_workers_max).max(1) as usize);
720
721 ImageCacheImpl {
722 store: Arc::new(Mutex::new(ImageCacheStore {
723 pending_loads: AllPendingLoads::new(),
724 completed_loads: HashMap::new(),
725 vector_images: FxHashMap::default(),
726 rasterized_vector_images: FxHashMap::default(),
727 placeholder_image: get_placeholder_image(&compositor_api, &rippy_data),
728 placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
729 compositor_api: compositor_api.clone(),
730 pipeline_id: None,
731 key_cache: KeyCache::new(),
732 })),
733 thread_pool: Arc::new(CoreResourceThreadPool::new(
734 thread_count,
735 "ImageCache".to_string(),
736 )),
737 }
738 }
739
740 fn memory_report(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Report {
741 let size = self.store.lock().unwrap().size_of(ops);
742 Report {
743 path: path![prefix, "image-cache"],
744 kind: ReportKind::ExplicitSystemHeapSize,
745 size,
746 }
747 }
748
749 fn get_image(
750 &self,
751 url: ServoUrl,
752 origin: ImmutableOrigin,
753 cors_setting: Option<CorsSettings>,
754 ) -> Option<Image> {
755 let store = self.store.lock().unwrap();
756 let result =
757 store.get_completed_image_if_available(url, origin, cors_setting, UsePlaceholder::No);
758 match result {
759 Some(Ok((img, _))) => Some(img),
760 _ => None,
761 }
762 }
763
764 fn get_cached_image_status(
765 &self,
766 url: ServoUrl,
767 origin: ImmutableOrigin,
768 cors_setting: Option<CorsSettings>,
769 use_placeholder: UsePlaceholder,
770 ) -> ImageCacheResult {
771 let mut store = self.store.lock().unwrap();
772 if let Some(result) = store.get_completed_image_if_available(
773 url.clone(),
774 origin.clone(),
775 cors_setting,
776 use_placeholder,
777 ) {
778 match result {
779 Ok((image, image_url)) => {
780 debug!("{} is available", url);
781 let is_placeholder = image_url == store.placeholder_url;
782 return ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
783 image,
784 url: image_url,
785 is_placeholder,
786 });
787 },
788 Err(()) => {
789 debug!("{} is not available", url);
790 return ImageCacheResult::LoadError;
791 },
792 }
793 }
794
795 let (key, decoded) = {
796 let result = store
797 .pending_loads
798 .get_cached(url.clone(), origin.clone(), cors_setting);
799 match result {
800 CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
801 (&Some(Ok(_)), _) => {
802 debug!("Sync decoding {} ({:?})", url, key);
803 (
804 key,
805 decode_bytes_sync(
806 key,
807 pl.bytes.as_slice(),
808 pl.cors_status,
809 pl.content_type.clone(),
810 ),
811 )
812 },
813 (&None, Some(meta)) => {
814 debug!("Metadata available for {} ({:?})", url, key);
815 return ImageCacheResult::Available(
816 ImageOrMetadataAvailable::MetadataAvailable(*meta, key),
817 );
818 },
819 (&Some(Err(_)), _) | (&None, &None) => {
820 debug!("{} ({:?}) is still pending", url, key);
821 return ImageCacheResult::Pending(key);
822 },
823 },
824 CacheResult::Miss(Some((key, _pl))) => {
825 debug!("Should be requesting {} ({:?})", url, key);
826 return ImageCacheResult::ReadyForRequest(key);
827 },
828 CacheResult::Miss(None) => {
829 debug!("Couldn't find an entry for {}", url);
830 return ImageCacheResult::LoadError;
831 },
832 }
833 };
834
835 store.handle_decoder(decoded);
840 match store.get_completed_image_if_available(url, origin, cors_setting, use_placeholder) {
841 Some(Ok((image, image_url))) => {
842 let is_placeholder = image_url == store.placeholder_url;
843 ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
844 image,
845 url: image_url,
846 is_placeholder,
847 })
848 },
849 _ => ImageCacheResult::Pending(key),
851 }
852 }
853
854 fn add_rasterization_complete_listener(
855 &self,
856 pipeline_id: PipelineId,
857 image_id: PendingImageId,
858 requested_size: DeviceIntSize,
859 sender: IpcSender<ImageCacheResponseMessage>,
860 ) {
861 let completed = {
862 let mut store = self.store.lock().unwrap();
863 let key = (image_id, requested_size);
864 if !store.vector_images.contains_key(&image_id) {
865 warn!("Unknown image requested for rasterization for key {key:?}");
866 return;
867 };
868
869 let Some(task) = store.rasterized_vector_images.get_mut(&key) else {
870 warn!("Image rasterization task not found in the cache for key {key:?}");
871 return;
872 };
873
874 match task.result {
875 Some(_) => true,
876 None => {
877 task.listeners.push((pipeline_id, sender.clone()));
878 false
879 },
880 }
881 };
882
883 if completed {
884 let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
885 RasterizationCompleteResponse {
886 pipeline_id,
887 image_id,
888 requested_size,
889 },
890 ));
891 }
892 }
893
894 fn rasterize_vector_image(
895 &self,
896 image_id: PendingImageId,
897 requested_size: DeviceIntSize,
898 ) -> Option<RasterImage> {
899 let mut store = self.store.lock().unwrap();
900 let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
901 warn!("Unknown image id {image_id:?} requested for rasterization");
902 return None;
903 };
904
905 let entry = store
909 .rasterized_vector_images
910 .entry((image_id, requested_size))
911 .or_default();
912 if let Some(result) = entry.result.as_ref() {
913 return Some(result.clone());
914 }
915
916 let store = self.store.clone();
917 self.thread_pool.spawn(move || {
918 let natural_size = vector_image.svg_tree.size().to_int_size();
919 let tinyskia_requested_size = {
920 let width = requested_size
921 .width
922 .try_into()
923 .unwrap_or(0)
924 .min(MAX_SVG_PIXMAP_DIMENSION);
925 let height = requested_size
926 .height
927 .try_into()
928 .unwrap_or(0)
929 .min(MAX_SVG_PIXMAP_DIMENSION);
930 tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
931 };
932 let transform = tiny_skia::Transform::from_scale(
933 tinyskia_requested_size.width() as f32 / natural_size.width() as f32,
934 tinyskia_requested_size.height() as f32 / natural_size.height() as f32,
935 );
936 let mut pixmap = tiny_skia::Pixmap::new(
937 tinyskia_requested_size.width(),
938 tinyskia_requested_size.height(),
939 )
940 .unwrap();
941 resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
942
943 let bytes = pixmap.take();
944 let frame = ImageFrame {
945 delay: None,
946 byte_range: 0..bytes.len(),
947 width: tinyskia_requested_size.width(),
948 height: tinyskia_requested_size.height(),
949 };
950
951 let rasterized_image = RasterImage {
952 metadata: ImageMetadata {
953 width: tinyskia_requested_size.width(),
954 height: tinyskia_requested_size.height(),
955 },
956 format: PixelFormat::RGBA8,
957 frames: vec![frame],
958 bytes: IpcSharedMemory::from_bytes(&bytes),
959 id: None,
960 cors_status: vector_image.cors_status,
961 };
962
963 let mut store = store.lock().unwrap();
964 store.load_image_with_keycache(PendingKey::Svg((
965 image_id,
966 rasterized_image,
967 requested_size,
968 )));
969 });
970
971 None
972 }
973
974 fn add_listener(&self, listener: ImageLoadListener) {
977 let mut store = self.store.lock().unwrap();
978 self.add_listener_with_store(&mut store, listener);
979 }
980
981 fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
983 match (action, id) {
984 (FetchResponseMsg::ProcessRequestBody(..), _) |
985 (FetchResponseMsg::ProcessRequestEOF(..), _) |
986 (FetchResponseMsg::ProcessCspViolations(..), _) => (),
987 (FetchResponseMsg::ProcessResponse(_, response), _) => {
988 debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
989 let mut store = self.store.lock().unwrap();
990 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
991 let (cors_status, metadata) = match response {
992 Ok(meta) => match meta {
993 FetchMetadata::Unfiltered(m) => (CorsStatus::Safe, Some(m)),
994 FetchMetadata::Filtered { unsafe_, filtered } => (
995 match filtered {
996 FilteredMetadata::Basic(_) | FilteredMetadata::Cors(_) => {
997 CorsStatus::Safe
998 },
999 FilteredMetadata::Opaque | FilteredMetadata::OpaqueRedirect(_) => {
1000 CorsStatus::Unsafe
1001 },
1002 },
1003 Some(unsafe_),
1004 ),
1005 },
1006 Err(_) => (CorsStatus::Unsafe, None),
1007 };
1008 let final_url = metadata.as_ref().map(|m| m.final_url.clone());
1009 pending_load.final_url = final_url;
1010 pending_load.cors_status = cors_status;
1011 pending_load.content_type = metadata
1012 .as_ref()
1013 .and_then(|metadata| metadata.content_type.clone())
1014 .map(|content_type| content_type.into_inner().into());
1015 },
1016 (FetchResponseMsg::ProcessResponseChunk(_, data), _) => {
1017 debug!("Got some data for {:?}", id);
1018 let mut store = self.store.lock().unwrap();
1019 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
1020 pending_load.bytes.extend_from_slice(&data);
1021
1022 if pending_load.metadata.is_none() {
1024 let mut reader = std::io::Cursor::new(pending_load.bytes.as_slice());
1025 if let Ok(info) = imsz_from_reader(&mut reader) {
1026 let img_metadata = ImageMetadata {
1027 width: info.width as u32,
1028 height: info.height as u32,
1029 };
1030 for listener in &pending_load.listeners {
1031 listener.respond(ImageResponse::MetadataLoaded(img_metadata));
1032 }
1033 pending_load.metadata = Some(img_metadata);
1034 }
1035 }
1036 },
1037 (FetchResponseMsg::ProcessResponseEOF(_, result), key) => {
1038 debug!("Received EOF for {:?}", key);
1039 match result {
1040 Ok(_) => {
1041 let (bytes, cors_status, content_type) = {
1042 let mut store = self.store.lock().unwrap();
1043 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
1044 pending_load.result = Some(Ok(()));
1045 debug!("Async decoding {} ({:?})", pending_load.url, key);
1046 (
1047 pending_load.bytes.mark_complete(),
1048 pending_load.cors_status,
1049 pending_load.content_type.clone(),
1050 )
1051 };
1052
1053 let local_store = self.store.clone();
1054 self.thread_pool.spawn(move || {
1055 let msg = decode_bytes_sync(key, &bytes, cors_status, content_type);
1056 debug!("Image decoded");
1057 local_store.lock().unwrap().handle_decoder(msg);
1058 });
1059 },
1060 Err(_) => {
1061 debug!("Processing error for {:?}", key);
1062 let mut store = self.store.lock().unwrap();
1063 let placeholder_image = store.placeholder_image.clone();
1064 store.complete_load(id, LoadResult::PlaceholderLoaded(placeholder_image))
1065 },
1066 }
1067 },
1068 }
1069 }
1070
1071 fn create_new_image_cache(
1072 &self,
1073 pipeline_id: Option<PipelineId>,
1074 compositor_api: CrossProcessCompositorApi,
1075 ) -> Arc<dyn ImageCache> {
1076 let store = self.store.lock().unwrap();
1077 let placeholder_image = store.placeholder_image.clone();
1078 let placeholder_url = store.placeholder_url.clone();
1079 Arc::new(ImageCacheImpl {
1080 store: Arc::new(Mutex::new(ImageCacheStore {
1081 pending_loads: AllPendingLoads::new(),
1082 completed_loads: HashMap::new(),
1083 placeholder_image,
1084 placeholder_url,
1085 compositor_api,
1086 vector_images: FxHashMap::default(),
1087 rasterized_vector_images: FxHashMap::default(),
1088 key_cache: KeyCache::new(),
1089 pipeline_id,
1090 })),
1091 thread_pool: self.thread_pool.clone(),
1092 })
1093 }
1094
1095 fn fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<WebRenderImageKey>) {
1096 let mut store = self.store.lock().unwrap();
1097 store.insert_keys_and_load_images(image_keys);
1098 }
1099}
1100
1101impl Drop for ImageCacheStore {
1102 fn drop(&mut self) {
1103 let image_updates = self
1104 .completed_loads
1105 .values()
1106 .filter_map(|load| match &load.image_response {
1107 ImageResponse::Loaded(Image::Raster(image), _) => {
1108 image.id.map(ImageUpdate::DeleteImage)
1109 },
1110 _ => None,
1111 })
1112 .chain(
1113 self.rasterized_vector_images
1114 .values()
1115 .filter_map(|task| task.result.as_ref()?.id.map(ImageUpdate::DeleteImage)),
1116 )
1117 .collect();
1118 self.compositor_api.update_images(image_updates);
1119 }
1120}
1121
1122impl ImageCacheImpl {
1123 fn add_listener_with_store(&self, store: &mut ImageCacheStore, listener: ImageLoadListener) {
1125 let id = listener.id;
1126 if let Some(load) = store.pending_loads.get_by_key_mut(&id) {
1127 if let Some(ref metadata) = load.metadata {
1128 listener.respond(ImageResponse::MetadataLoaded(*metadata));
1129 }
1130 load.add_listener(listener);
1131 return;
1132 }
1133 if let Some(load) = store.completed_loads.values().find(|l| l.id == id) {
1134 listener.respond(load.image_response.clone());
1135 return;
1136 }
1137 warn!("Couldn't find cached entry for listener {:?}", id);
1138 }
1139}