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