1use std::cell::OnceCell;
6use std::cmp::min;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::mem;
10use std::sync::Arc;
11
12use imsz::imsz_from_reader;
13use log::{debug, warn};
14use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
15use malloc_size_of_derive::MallocSizeOf;
16use mime::Mime;
17use net_traits::image_cache::{
18 Image, ImageCache, ImageCacheFactory, ImageCacheResponseCallback, ImageCacheResponseMessage,
19 ImageCacheResult, ImageLoadListener, ImageOrMetadataAvailable, ImageResponse, PendingImageId,
20 RasterizationCompleteResponse, VectorImage,
21};
22use net_traits::request::CorsSettings;
23use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
24use paint_api::{CrossProcessPaintApi, ImageUpdate, SerializableImageData};
25use parking_lot::Mutex;
26use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage, load_from_memory};
27use profile_traits::mem::{Report, ReportKind};
28use profile_traits::path;
29use resvg::tiny_skia;
30use resvg::usvg::{self, fontdb};
31use rustc_hash::FxHashMap;
32use servo_base::id::{PipelineId, WebViewId};
33use servo_base::threadpool::ThreadPool;
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 is_svg_document = content_type.is_some_and(|content_type| {
99 (
100 content_type.type_(),
101 content_type.subtype(),
102 content_type.suffix(),
103 ) == (mime::IMAGE, mime::SVG, Some(mime::XML))
104 });
105
106 let image = if is_svg_document {
107 parse_svg_document_in_memory(bytes, fontdb)
108 .ok()
109 .map(|svg_tree| {
110 DecodedImage::Vector(VectorImageData {
111 svg_tree: Arc::new(svg_tree),
112 cors_status: cors,
113 })
114 })
115 } else {
116 load_from_memory(bytes, cors).map(DecodedImage::Raster)
117 };
118
119 DecoderMsg { key, image }
120}
121
122fn set_webrender_image_key(
123 paint_api: &CrossProcessPaintApi,
124 image: &mut RasterImage,
125 image_key: WebRenderImageKey,
126) {
127 if image.id.is_some() {
128 return;
129 }
130
131 let (descriptor, ipc_shared_memory) = image.webrender_image_descriptor_and_data_for_frame(0);
132 let data = SerializableImageData::Raw(ipc_shared_memory);
133
134 paint_api.add_image(image_key, descriptor, data, image.should_animate());
135 image.id = Some(image_key);
136}
137
138type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
144
145#[derive(MallocSizeOf)]
148struct AllPendingLoads {
149 loads: FxHashMap<LoadKey, PendingLoad>,
152
153 url_to_load_key: HashMap<ImageKey, LoadKey>,
156
157 keygen: LoadKeyGenerator,
159}
160
161impl AllPendingLoads {
162 fn new() -> AllPendingLoads {
163 AllPendingLoads {
164 loads: FxHashMap::default(),
165 url_to_load_key: HashMap::default(),
166 keygen: LoadKeyGenerator::new(),
167 }
168 }
169
170 fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
172 self.loads.get_mut(key)
173 }
174
175 fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
176 self.loads.remove(key).inspect(|pending_load| {
177 self.url_to_load_key
178 .remove(&(
179 pending_load.url.clone(),
180 pending_load.load_origin.clone(),
181 pending_load.cors_setting,
182 ))
183 .unwrap();
184 })
185 }
186
187 fn get_cached(
188 &mut self,
189 url: ServoUrl,
190 origin: ImmutableOrigin,
191 cors_status: Option<CorsSettings>,
192 ) -> CacheResult<'_> {
193 match self
194 .url_to_load_key
195 .entry((url.clone(), origin.clone(), cors_status))
196 {
197 Occupied(url_entry) => {
198 let load_key = url_entry.get();
199 CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap())
200 },
201 Vacant(url_entry) => {
202 let load_key = self.keygen.next();
203 url_entry.insert(load_key);
204
205 let pending_load = PendingLoad::new(url, origin, cors_status);
206 match self.loads.entry(load_key) {
207 Occupied(_) => unreachable!(),
208 Vacant(load_entry) => {
209 let mut_load = load_entry.insert(pending_load);
210 CacheResult::Miss(Some((load_key, mut_load)))
211 },
212 }
213 },
214 }
215 }
216}
217
218enum CacheResult<'a> {
220 Hit(LoadKey, &'a mut PendingLoad),
222 Miss(Option<(LoadKey, &'a mut PendingLoad)>),
224}
225
226#[derive(MallocSizeOf)]
231struct CompletedLoad {
232 image_response: ImageResponse,
233 id: PendingImageId,
234}
235
236impl CompletedLoad {
237 fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
238 CompletedLoad { image_response, id }
239 }
240}
241
242#[derive(Clone, MallocSizeOf)]
243struct VectorImageData {
244 #[conditional_malloc_size_of]
245 svg_tree: Arc<usvg::Tree>,
246 cors_status: CorsStatus,
247}
248
249impl std::fmt::Debug for VectorImageData {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 f.debug_struct("VectorImageData").finish()
252 }
253}
254
255enum DecodedImage {
256 Raster(RasterImage),
257 Vector(VectorImageData),
258}
259
260struct DecoderMsg {
262 key: LoadKey,
263 image: Option<DecodedImage>,
264}
265
266#[derive(MallocSizeOf)]
267enum ImageBytes {
268 InProgress(Vec<u8>),
269 Complete(#[conditional_malloc_size_of] Arc<Vec<u8>>),
270}
271
272impl ImageBytes {
273 fn extend_from_slice(&mut self, data: &[u8]) {
274 match *self {
275 ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
276 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
277 }
278 }
279
280 fn mark_complete(&mut self) -> Arc<Vec<u8>> {
281 let bytes = {
282 let own_bytes = match *self {
283 ImageBytes::InProgress(ref mut bytes) => bytes,
284 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
285 };
286 mem::take(own_bytes)
287 };
288 let bytes = Arc::new(bytes);
289 *self = ImageBytes::Complete(bytes.clone());
290 bytes
291 }
292
293 fn as_slice(&self) -> &[u8] {
294 match *self {
295 ImageBytes::InProgress(ref bytes) => bytes,
296 ImageBytes::Complete(ref bytes) => bytes,
297 }
298 }
299}
300
301type LoadKey = PendingImageId;
303
304#[derive(MallocSizeOf)]
305struct LoadKeyGenerator {
306 counter: u64,
307}
308
309impl LoadKeyGenerator {
310 fn new() -> LoadKeyGenerator {
311 LoadKeyGenerator { counter: 0 }
312 }
313 fn next(&mut self) -> PendingImageId {
314 self.counter += 1;
315 PendingImageId(self.counter)
316 }
317}
318
319#[derive(Debug)]
320enum LoadResult {
321 LoadedRasterImage(RasterImage),
322 LoadedVectorImage(VectorImageData),
323 FailedToLoadOrDecode,
324}
325
326#[derive(MallocSizeOf)]
329struct PendingLoad {
330 bytes: ImageBytes,
333
334 metadata: Option<ImageMetadata>,
336
337 result: Option<Result<(), NetworkError>>,
339
340 listeners: Vec<ImageLoadListener>,
342
343 url: ServoUrl,
346
347 load_origin: ImmutableOrigin,
349
350 cors_setting: Option<CorsSettings>,
352
353 cors_status: CorsStatus,
355
356 final_url: Option<ServoUrl>,
358
359 content_type: Option<Mime>,
361}
362
363impl PendingLoad {
364 fn new(
365 url: ServoUrl,
366 load_origin: ImmutableOrigin,
367 cors_setting: Option<CorsSettings>,
368 ) -> PendingLoad {
369 PendingLoad {
370 bytes: ImageBytes::InProgress(vec![]),
371 metadata: None,
372 result: None,
373 listeners: vec![],
374 url,
375 load_origin,
376 final_url: None,
377 cors_setting,
378 cors_status: CorsStatus::Unsafe,
379 content_type: None,
380 }
381 }
382
383 fn add_listener(&mut self, listener: ImageLoadListener) {
384 self.listeners.push(listener);
385 }
386}
387
388#[derive(Default, MallocSizeOf)]
389struct RasterizationTask {
390 #[ignore_malloc_size_of = "Fn is difficult to measure"]
391 listeners: Vec<(PipelineId, ImageCacheResponseCallback)>,
392 result: Option<RasterImage>,
393}
394
395#[derive(Debug, MallocSizeOf)]
397enum PendingKey {
398 RasterImage((LoadKey, RasterImage)),
399 Svg((LoadKey, RasterImage, DeviceIntSize)),
400}
401
402#[derive(Debug, MallocSizeOf)]
404enum KeyCacheState {
405 PendingBatch,
407 Ready(Vec<WebRenderImageKey>),
409}
410
411impl KeyCacheState {
412 fn size(&self) -> usize {
413 match self {
414 KeyCacheState::PendingBatch => 0,
415 KeyCacheState::Ready(items) => items.len(),
416 }
417 }
418}
419
420#[derive(MallocSizeOf)]
424struct KeyCache {
425 cache: KeyCacheState,
427 images_pending_keys: VecDeque<PendingKey>,
429 evicted_images: HashSet<(LoadKey, DeviceIntSize)>,
432}
433
434impl KeyCache {
435 fn new() -> Self {
436 KeyCache {
437 cache: KeyCacheState::Ready(Vec::new()),
438 images_pending_keys: VecDeque::new(),
439 evicted_images: HashSet::new(),
440 }
441 }
442}
443
444#[derive(MallocSizeOf)]
446struct ImageCacheStore {
447 pending_loads: AllPendingLoads,
449
450 completed_loads: HashMap<ImageKey, CompletedLoad>,
452
453 vector_images: FxHashMap<PendingImageId, VectorImageData>,
457
458 rasterized_vector_images: FxHashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
462
463 #[conditional_malloc_size_of]
465 broken_image_icon_image: OnceCell<Option<Arc<RasterImage>>>,
466
467 paint_api: CrossProcessPaintApi,
469
470 webview_id: WebViewId,
472
473 pipeline_id: PipelineId,
475
476 key_cache: KeyCache,
479}
480
481impl ImageCacheStore {
482 fn set_key_and_finish_load(&mut self, pending_image: PendingKey, image_key: WebRenderImageKey) {
484 match pending_image {
485 PendingKey::RasterImage((pending_id, mut raster_image)) => {
486 set_webrender_image_key(&self.paint_api, &mut raster_image, image_key);
487 self.complete_load(pending_id, LoadResult::LoadedRasterImage(raster_image));
488 },
489 PendingKey::Svg((pending_id, mut raster_image, requested_size)) => {
490 set_webrender_image_key(&self.paint_api, &mut raster_image, image_key);
491 self.complete_load_svg(raster_image, pending_id, requested_size);
492 },
493 }
494 }
495
496 fn load_image_with_keycache(&mut self, pending_image: PendingKey) {
499 if let PendingKey::Svg((pending_id, ref _raster_image, requested_size)) = pending_image &&
500 self.key_cache
501 .evicted_images
502 .remove(&(pending_id, requested_size))
503 {
504 return;
505 };
506 match self.key_cache.cache {
507 KeyCacheState::PendingBatch => {
508 self.key_cache.images_pending_keys.push_back(pending_image);
509 },
510 KeyCacheState::Ready(ref mut cache) => match cache.pop() {
511 Some(image_key) => {
512 self.set_key_and_finish_load(pending_image, image_key);
513 },
514 None => {
515 self.key_cache.images_pending_keys.push_back(pending_image);
516 self.fetch_more_image_keys();
517 },
518 },
519 }
520 }
521
522 fn evict_image_from_keycache(
523 &mut self,
524 image_id: &PendingImageId,
525 requested_size: &DeviceIntSize,
526 ) {
527 self.key_cache
528 .evicted_images
529 .insert((*image_id, *requested_size));
530 }
531
532 fn fetch_more_image_keys(&mut self) {
533 self.key_cache.cache = KeyCacheState::PendingBatch;
534 self.paint_api
535 .generate_image_key_async(self.webview_id, self.pipeline_id);
536 }
537
538 fn insert_keys_and_load_images(&mut self, image_keys: Vec<WebRenderImageKey>) {
540 if let KeyCacheState::PendingBatch = self.key_cache.cache {
541 self.key_cache.cache = KeyCacheState::Ready(image_keys);
542 let len = min(
543 self.key_cache.cache.size(),
544 self.key_cache.images_pending_keys.len(),
545 );
546 let images = self
547 .key_cache
548 .images_pending_keys
549 .drain(0..len)
550 .collect::<Vec<PendingKey>>();
551 for key in images {
552 self.load_image_with_keycache(key);
553 }
554 if !self.key_cache.images_pending_keys.is_empty() {
555 self.paint_api
556 .generate_image_key_async(self.webview_id, self.pipeline_id);
557 self.key_cache.cache = KeyCacheState::PendingBatch
558 }
559 } else {
560 unreachable!("A batch was received while we didn't request one")
561 }
562 }
563
564 fn complete_load_svg(
567 &mut self,
568 rasterized_image: RasterImage,
569 pending_image_id: PendingImageId,
570 requested_size: DeviceIntSize,
571 ) {
572 let listeners = {
573 self.rasterized_vector_images
574 .get_mut(&(pending_image_id, requested_size))
575 .map(|task| {
576 task.result = Some(rasterized_image);
577 std::mem::take(&mut task.listeners)
578 })
579 .unwrap_or_default()
580 };
581
582 for (pipeline_id, callback) in listeners {
583 callback(ImageCacheResponseMessage::VectorImageRasterizationComplete(
584 RasterizationCompleteResponse {
585 pipeline_id,
586 image_id: pending_image_id,
587 requested_size,
588 },
589 ));
590 }
591 }
592
593 fn complete_load(&mut self, key: LoadKey, load_result: LoadResult) {
595 debug!("Completed decoding for {:?}", load_result);
596 let pending_load = match self.pending_loads.remove(&key) {
597 Some(load) => load,
598 None => return,
599 };
600 let url = pending_load.final_url.clone();
601 let image_response = match load_result {
602 LoadResult::LoadedRasterImage(raster_image) => {
603 assert!(raster_image.id.is_some());
604 ImageResponse::Loaded(Image::Raster(Arc::new(raster_image)), url.unwrap())
605 },
606 LoadResult::LoadedVectorImage(vector_image) => {
607 self.vector_images.insert(key, vector_image.clone());
608 let natural_dimensions = vector_image.svg_tree.size().to_int_size();
609 let metadata = ImageMetadata {
610 width: natural_dimensions.width(),
611 height: natural_dimensions.height(),
612 };
613
614 let vector_image = VectorImage {
615 id: key,
616 svg_id: None,
617 metadata,
618 cors_status: vector_image.cors_status,
619 };
620 ImageResponse::Loaded(Image::Vector(vector_image), url.unwrap())
621 },
622 LoadResult::FailedToLoadOrDecode => ImageResponse::FailedToLoadOrDecode,
623 };
624
625 let completed_load = CompletedLoad::new(image_response.clone(), key);
626 self.completed_loads.insert(
627 (
628 pending_load.url,
629 pending_load.load_origin,
630 pending_load.cors_setting,
631 ),
632 completed_load,
633 );
634
635 for listener in pending_load.listeners {
636 listener.respond(image_response.clone());
637 }
638 }
639
640 fn remove_loaded_image(
641 &mut self,
642 url: &ServoUrl,
643 origin: &ImmutableOrigin,
644 cors_setting: &Option<CorsSettings>,
645 ) {
646 if let Some(loaded_image) =
647 self.completed_loads
648 .remove(&(url.clone(), origin.clone(), *cors_setting)) &&
649 let ImageResponse::Loaded(Image::Raster(image), _) = loaded_image.image_response &&
650 let Some(id) = image.id
651 {
652 self.paint_api.update_images(
653 self.webview_id.into(),
654 vec![ImageUpdate::DeleteImage(id)].into(),
655 );
656 }
657 }
658
659 fn remove_rasterized_vector_image(
660 &mut self,
661 image_id: &PendingImageId,
662 device_size: &DeviceIntSize,
663 ) {
664 if let Some(entry) = self
665 .rasterized_vector_images
666 .remove(&(*image_id, *device_size))
667 {
668 if let Some(result) = entry.result {
669 if let Some(image_id) = result.id {
670 self.paint_api.update_images(
671 self.webview_id.into(),
672 vec![ImageUpdate::DeleteImage(image_id)].into(),
673 );
674 }
675 } else {
676 self.evict_image_from_keycache(image_id, device_size);
681 }
682 }
683 }
684
685 fn get_completed_image_if_available(
688 &self,
689 url: ServoUrl,
690 origin: ImmutableOrigin,
691 cors_setting: Option<CorsSettings>,
692 ) -> Option<Result<(Image, ServoUrl), ()>> {
693 self.completed_loads
694 .get(&(url, origin, cors_setting))
695 .map(|completed_load| match &completed_load.image_response {
696 ImageResponse::Loaded(image, url) => Ok((image.clone(), url.clone())),
697 ImageResponse::FailedToLoadOrDecode | ImageResponse::MetadataLoaded(_) => Err(()),
698 })
699 }
700
701 fn handle_decoder(&mut self, msg: DecoderMsg) {
704 let image = match msg.image {
705 None => LoadResult::FailedToLoadOrDecode,
706 Some(DecodedImage::Raster(raster_image)) => {
707 self.load_image_with_keycache(PendingKey::RasterImage((msg.key, raster_image)));
708 return;
709 },
710 Some(DecodedImage::Vector(vector_image_data)) => {
711 LoadResult::LoadedVectorImage(vector_image_data)
712 },
713 };
714 self.complete_load(msg.key, image);
715 }
716}
717
718pub struct ImageCacheFactoryImpl {
719 broken_image_icon_data: Arc<Vec<u8>>,
721 thread_pool: Arc<ThreadPool>,
723 fontdb: Arc<fontdb::Database>,
726}
727
728impl ImageCacheFactoryImpl {
729 pub fn new(broken_image_icon_data: Vec<u8>) -> Self {
730 debug!("Creating new ImageCacheFactoryImpl");
731 let mut fontdb = fontdb::Database::new();
732 fontdb.load_system_fonts();
733
734 Self {
735 broken_image_icon_data: Arc::new(broken_image_icon_data),
736 thread_pool: ThreadPool::global(),
737 fontdb: Arc::new(fontdb),
738 }
739 }
740}
741
742impl ImageCacheFactory for ImageCacheFactoryImpl {
743 fn create(
744 &self,
745 webview_id: WebViewId,
746 pipeline_id: PipelineId,
747 paint_api: &CrossProcessPaintApi,
748 ) -> Arc<dyn ImageCache> {
749 Arc::new(ImageCacheImpl {
750 store: Arc::new(Mutex::new(ImageCacheStore {
751 pending_loads: AllPendingLoads::new(),
752 completed_loads: HashMap::new(),
753 vector_images: FxHashMap::default(),
754 rasterized_vector_images: FxHashMap::default(),
755 broken_image_icon_image: OnceCell::new(),
756 paint_api: paint_api.clone(),
757 pipeline_id,
758 webview_id,
759 key_cache: KeyCache::new(),
760 })),
761 svg_id_image_id_map: Arc::new(Mutex::new(FxHashMap::default())),
762 image_id_size_map: Arc::new(Mutex::new(FxHashMap::default())),
763 broken_image_icon_data: self.broken_image_icon_data.clone(),
764 thread_pool: self.thread_pool.clone(),
765 fontdb: self.fontdb.clone(),
766 })
767 }
768}
769
770pub struct ImageCacheImpl {
771 store: Arc<Mutex<ImageCacheStore>>,
773 svg_id_image_id_map: Arc<Mutex<FxHashMap<String, PendingImageId>>>,
775 image_id_size_map: Arc<Mutex<FxHashMap<PendingImageId, Vec<DeviceIntSize>>>>,
777 broken_image_icon_data: Arc<Vec<u8>>,
779 thread_pool: Arc<ThreadPool>,
782 fontdb: Arc<fontdb::Database>,
785}
786
787impl ImageCache for ImageCacheImpl {
788 fn memory_reports(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Vec<Report> {
789 let store_size = self.store.lock().size_of(ops);
790 let fontdb_size = self.fontdb.conditional_size_of(ops);
791 vec![
792 Report {
793 path: path![prefix, "image-cache"],
794 kind: ReportKind::ExplicitSystemHeapSize,
795 size: store_size,
796 },
797 Report {
798 path: path![prefix, "image-cache", "fontdb"],
799 kind: ReportKind::ExplicitSystemHeapSize,
800 size: fontdb_size,
801 },
802 ]
803 }
804
805 fn get_image_key(&self) -> Option<WebRenderImageKey> {
806 let mut store = self.store.lock();
807 if let KeyCacheState::Ready(ref mut cache) = store.key_cache.cache {
808 if let Some(image_key) = cache.pop() {
809 return Some(image_key);
810 }
811
812 store.fetch_more_image_keys();
813 }
814
815 store
816 .paint_api
817 .generate_image_key_blocking(store.webview_id)
818 }
819
820 fn get_image(
821 &self,
822 url: ServoUrl,
823 origin: ImmutableOrigin,
824 cors_setting: Option<CorsSettings>,
825 ) -> Option<Image> {
826 let store = self.store.lock();
827 let result = store.get_completed_image_if_available(url, origin, cors_setting);
828 match result {
829 Some(Ok((img, _))) => Some(img),
830 _ => None,
831 }
832 }
833
834 fn get_cached_image_status(
835 &self,
836 url: ServoUrl,
837 origin: ImmutableOrigin,
838 cors_setting: Option<CorsSettings>,
839 ) -> ImageCacheResult {
840 let mut store = self.store.lock();
841 if let Some(result) =
842 store.get_completed_image_if_available(url.clone(), origin.clone(), cors_setting)
843 {
844 match result {
845 Ok((image, image_url)) => {
846 debug!("{} is available", url);
847 return ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
848 image,
849 url: image_url,
850 });
851 },
852 Err(()) => {
853 debug!("{} is not available", url);
854 return ImageCacheResult::FailedToLoadOrDecode;
855 },
856 }
857 }
858
859 let (key, decoded) = {
860 let result = store
861 .pending_loads
862 .get_cached(url.clone(), origin.clone(), cors_setting);
863 match result {
864 CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
865 (&Some(Ok(_)), _) => {
866 debug!("Sync decoding {} ({:?})", url, key);
867 (
868 key,
869 decode_bytes_sync(
870 key,
871 pl.bytes.as_slice(),
872 pl.cors_status,
873 pl.content_type.clone(),
874 self.fontdb.clone(),
875 ),
876 )
877 },
878 (&None, Some(meta)) => {
879 debug!("Metadata available for {} ({:?})", url, key);
880 return ImageCacheResult::Available(
881 ImageOrMetadataAvailable::MetadataAvailable(*meta, key),
882 );
883 },
884 (&Some(Err(_)), _) | (&None, &None) => {
885 debug!("{} ({:?}) is still pending", url, key);
886 return ImageCacheResult::Pending(key);
887 },
888 },
889 CacheResult::Miss(Some((key, _pl))) => {
890 debug!("Should be requesting {} ({:?})", url, key);
891 return ImageCacheResult::ReadyForRequest(key);
892 },
893 CacheResult::Miss(None) => {
894 debug!("Couldn't find an entry for {}", url);
895 return ImageCacheResult::FailedToLoadOrDecode;
896 },
897 }
898 };
899
900 store.handle_decoder(decoded);
905 match store.get_completed_image_if_available(url, origin, cors_setting) {
906 Some(Ok((image, image_url))) => {
907 ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
908 image,
909 url: image_url,
910 })
911 },
912 _ => ImageCacheResult::Pending(key),
914 }
915 }
916
917 fn add_rasterization_complete_listener(
918 &self,
919 pipeline_id: PipelineId,
920 image_id: PendingImageId,
921 requested_size: DeviceIntSize,
922 callback: ImageCacheResponseCallback,
923 ) {
924 {
925 let mut store = self.store.lock();
926 let key = (image_id, requested_size);
927 if !store.vector_images.contains_key(&image_id) {
928 warn!("Unknown image requested for rasterization for key {key:?}");
929 return;
930 };
931
932 let Some(task) = store.rasterized_vector_images.get_mut(&key) else {
933 warn!("Image rasterization task not found in the cache for key {key:?}");
934 return;
935 };
936
937 if task.result.is_none() {
939 task.listeners.push((pipeline_id, callback));
940 return;
941 }
942 }
943
944 callback(ImageCacheResponseMessage::VectorImageRasterizationComplete(
945 RasterizationCompleteResponse {
946 pipeline_id,
947 image_id,
948 requested_size,
949 },
950 ));
951 }
952
953 fn rasterize_vector_image(
954 &self,
955 image_id: PendingImageId,
956 requested_size: DeviceIntSize,
957 svg_id: Option<String>,
958 ) -> Option<RasterImage> {
959 let mut store = self.store.lock();
960 let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
961 warn!("Unknown image id {image_id:?} requested for rasterization");
962 return None;
963 };
964
965 let entry = store
969 .rasterized_vector_images
970 .entry((image_id, requested_size))
971 .or_default();
972 if let Some(result) = entry.result.as_ref() {
973 return Some(result.clone());
974 }
975
976 if let Some(svg_id) = svg_id &&
977 let Some(old_mapped_image_id) =
978 self.svg_id_image_id_map.lock().insert(svg_id, image_id) &&
979 old_mapped_image_id != image_id
980 {
981 store.vector_images.remove(&old_mapped_image_id);
982 store
983 .rasterized_vector_images
984 .remove(&(old_mapped_image_id, requested_size));
985 }
986 if let Some(requested_sizes_for_id) = self.image_id_size_map.lock().get_mut(&image_id) {
987 requested_sizes_for_id.push(requested_size);
988 } else {
989 self.image_id_size_map
990 .lock()
991 .insert(image_id, vec![requested_size]);
992 }
993
994 let store = self.store.clone();
995 self.thread_pool.spawn(move || {
996 let natural_size = vector_image.svg_tree.size().to_int_size();
997 let tinyskia_requested_size = {
998 let width = requested_size
999 .width
1000 .try_into()
1001 .unwrap_or(0)
1002 .min(MAX_SVG_PIXMAP_DIMENSION);
1003 let height = requested_size
1004 .height
1005 .try_into()
1006 .unwrap_or(0)
1007 .min(MAX_SVG_PIXMAP_DIMENSION);
1008 tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
1009 };
1010 let transform = tiny_skia::Transform::from_scale(
1011 tinyskia_requested_size.width() as f32 / natural_size.width() as f32,
1012 tinyskia_requested_size.height() as f32 / natural_size.height() as f32,
1013 );
1014 let mut pixmap = tiny_skia::Pixmap::new(
1015 tinyskia_requested_size.width(),
1016 tinyskia_requested_size.height(),
1017 )
1018 .unwrap();
1019 resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
1020
1021 let bytes = pixmap.take();
1022 let frame = ImageFrame {
1023 delay: None,
1024 byte_range: 0..bytes.len(),
1025 width: tinyskia_requested_size.width(),
1026 height: tinyskia_requested_size.height(),
1027 };
1028
1029 let rasterized_image = RasterImage {
1030 metadata: ImageMetadata {
1031 width: tinyskia_requested_size.width(),
1032 height: tinyskia_requested_size.height(),
1033 },
1034 format: PixelFormat::RGBA8,
1035 frames: vec![frame],
1036 bytes: Arc::new(bytes),
1037 id: None,
1038 cors_status: vector_image.cors_status,
1039 is_opaque: false,
1040 };
1041
1042 let mut store = store.lock();
1043 store.load_image_with_keycache(PendingKey::Svg((
1044 image_id,
1045 rasterized_image,
1046 requested_size,
1047 )));
1048 });
1049
1050 None
1051 }
1052
1053 fn add_listener(&self, listener: ImageLoadListener) {
1056 let mut store = self.store.lock();
1057 self.add_listener_with_store(&mut store, listener);
1058 }
1059
1060 fn evict_completed_image(
1061 &self,
1062 url: &ServoUrl,
1063 origin: &ImmutableOrigin,
1064 cors_setting: &Option<CorsSettings>,
1065 ) {
1066 let mut store = self.store.lock();
1067 store.remove_loaded_image(url, origin, cors_setting);
1068 }
1069
1070 fn evict_rasterized_image(&self, svg_id: &str) {
1071 let mut store = self.store.lock();
1072 if let Some(mapped_image_id) = self.svg_id_image_id_map.lock().remove(svg_id) {
1073 store.pending_loads.remove(&mapped_image_id);
1074 store.vector_images.remove(&mapped_image_id);
1075 if let Some(requested_sizes) = self.image_id_size_map.lock().remove(&mapped_image_id) {
1076 for requested_size in requested_sizes.iter() {
1077 store.remove_rasterized_vector_image(&mapped_image_id, requested_size);
1078 }
1079 }
1080 }
1081 }
1082
1083 fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
1085 match (action, id) {
1086 (FetchResponseMsg::ProcessRequestBody(..), _) |
1087 (FetchResponseMsg::ProcessCspViolations(..), _) => (),
1088 (FetchResponseMsg::ProcessResponse(_, response), _) => {
1089 debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
1090 let mut store = self.store.lock();
1091 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1092 let (cors_status, metadata) = match response {
1093 Ok(meta) => match meta {
1094 FetchMetadata::Unfiltered(m) => (CorsStatus::Safe, Some(m)),
1095 FetchMetadata::Filtered { unsafe_, filtered } => (
1096 match filtered {
1097 FilteredMetadata::Basic(_) | FilteredMetadata::Cors(_) => {
1098 CorsStatus::Safe
1099 },
1100 FilteredMetadata::Opaque |
1101 FilteredMetadata::OpaqueRedirect(_) => CorsStatus::Unsafe,
1102 },
1103 Some(unsafe_),
1104 ),
1105 },
1106 Err(_) => (CorsStatus::Unsafe, None),
1107 };
1108 let final_url = metadata.as_ref().map(|m| m.final_url.clone());
1109 pending_load.final_url = final_url;
1110 pending_load.cors_status = cors_status;
1111 pending_load.content_type = metadata
1112 .as_ref()
1113 .and_then(|metadata| metadata.content_type.clone())
1114 .map(|content_type| content_type.into_inner().into());
1115 } else {
1116 debug!("Pending load for id {:?} already evicted from cache", id);
1117 }
1118 },
1119 (FetchResponseMsg::ProcessResponseChunk(_, data), _) => {
1120 debug!("Got some data for {:?}", id);
1121 let mut store = self.store.lock();
1122 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1123 pending_load.bytes.extend_from_slice(&data);
1124
1125 if pending_load.metadata.is_none() {
1127 let mut reader = std::io::Cursor::new(pending_load.bytes.as_slice());
1128 if let Ok(info) = imsz_from_reader(&mut reader) {
1129 let img_metadata = ImageMetadata {
1130 width: info.width as u32,
1131 height: info.height as u32,
1132 };
1133 for listener in &pending_load.listeners {
1134 listener.respond(ImageResponse::MetadataLoaded(img_metadata));
1135 }
1136 pending_load.metadata = Some(img_metadata);
1137 }
1138 }
1139 } else {
1140 debug!("Pending load for id {:?} already evicted from cache", id);
1141 }
1142 },
1143 (FetchResponseMsg::ProcessResponseEOF(_, result, _), key) => {
1144 debug!("Received EOF for {:?}", key);
1145 match result {
1146 Ok(_) => {
1147 let (bytes, cors_status, content_type) = {
1148 let mut store = self.store.lock();
1149 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1150 pending_load.result = Some(Ok(()));
1151 debug!("Async decoding {} ({:?})", pending_load.url, key);
1152 (
1153 pending_load.bytes.mark_complete(),
1154 pending_load.cors_status,
1155 pending_load.content_type.clone(),
1156 )
1157 } else {
1158 debug!("Pending load for id {:?} already evicted from cache", id);
1159 return;
1160 }
1161 };
1162
1163 let local_store = self.store.clone();
1164 let fontdb = self.fontdb.clone();
1165 self.thread_pool.spawn(move || {
1166 let msg =
1167 decode_bytes_sync(key, &bytes, cors_status, content_type, fontdb);
1168 local_store.lock().handle_decoder(msg);
1169 });
1170 },
1171 Err(error) => {
1172 debug!("Processing error for {key:?}: {error:?}");
1173 let mut store = self.store.lock();
1174 store.complete_load(id, LoadResult::FailedToLoadOrDecode)
1175 },
1176 }
1177 },
1178 }
1179 }
1180
1181 fn fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<WebRenderImageKey>) {
1182 let mut store = self.store.lock();
1183 store.insert_keys_and_load_images(image_keys);
1184 }
1185
1186 fn get_broken_image_icon(&self) -> Option<Arc<RasterImage>> {
1187 let store = self.store.lock();
1188 store
1189 .broken_image_icon_image
1190 .get_or_init(|| {
1191 let mut image = load_from_memory(&self.broken_image_icon_data, CorsStatus::Unsafe)
1192 .or_else(|| load_from_memory(FALLBACK_RIPPY, CorsStatus::Unsafe))?;
1193 let image_key = store
1194 .paint_api
1195 .generate_image_key_blocking(store.webview_id)
1196 .expect("Could not generate image key for broken image icon");
1197 set_webrender_image_key(&store.paint_api, &mut image, image_key);
1198 Some(Arc::new(image))
1199 })
1200 .clone()
1201 }
1202}
1203
1204impl Drop for ImageCacheStore {
1205 fn drop(&mut self) {
1206 let image_updates = self
1207 .completed_loads
1208 .values()
1209 .filter_map(|load| match &load.image_response {
1210 ImageResponse::Loaded(Image::Raster(image), _) => {
1211 image.id.map(ImageUpdate::DeleteImage)
1212 },
1213 _ => None,
1214 })
1215 .chain(
1216 self.rasterized_vector_images
1217 .values()
1218 .filter_map(|task| task.result.as_ref()?.id.map(ImageUpdate::DeleteImage)),
1219 )
1220 .collect();
1221 self.paint_api
1222 .update_images(self.webview_id.into(), image_updates);
1223 }
1224}
1225
1226impl ImageCacheImpl {
1227 fn add_listener_with_store(&self, store: &mut ImageCacheStore, listener: ImageLoadListener) {
1229 let id = listener.id;
1230 if let Some(load) = store.pending_loads.get_by_key_mut(&id) {
1231 if let Some(ref metadata) = load.metadata {
1232 listener.respond(ImageResponse::MetadataLoaded(*metadata));
1233 }
1234 load.add_listener(listener);
1235 return;
1236 }
1237 if let Some(load) = store.completed_loads.values().find(|l| l.id == id) {
1238 listener.respond(load.image_response.clone());
1239 return;
1240 }
1241 warn!("Couldn't find cached entry for listener {:?}", id);
1242 }
1243}