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