1use std::cell::{Cell, OnceCell};
6use std::cmp::min;
7use std::collections::hash_map::Entry::{Occupied, Vacant};
8use std::collections::{HashMap, HashSet, VecDeque};
9use std::panic::AssertUnwindSafe;
10use std::sync::Arc;
11use std::{mem, thread_local};
12
13use imsz::imsz_from_reader;
14use log::{debug, error, warn};
15use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
16use malloc_size_of_derive::MallocSizeOf;
17use mime::Mime;
18use net_traits::image_cache::{
19 FontResolver, Image, ImageCache, ImageCacheFactory, ImageCacheResponseCallback,
20 ImageCacheResponseMessage, ImageCacheResult, ImageLoadListener, ImageOrMetadataAvailable,
21 ImageResponse, PendingImageId, RasterizationCompleteResponse, VectorImage,
22};
23use net_traits::request::CorsSettings;
24use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
25use paint_api::{CrossProcessPaintApi, ImageUpdate, SerializableImageData};
26use parking_lot::Mutex;
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, FxHashSet};
33use servo_base::id::{PipelineId, WebViewId};
34use servo_base::threadpool::ThreadPool;
35use servo_url::{ImmutableOrigin, ServoUrl};
36use uuid::Uuid;
37use webrender_api::ImageKey as WebRenderImageKey;
38use webrender_api::units::DeviceIntSize;
39
40use crate::image_cache::KeyCacheState::PipelineClosed;
41
42thread_local! {
43 pub static SUPPRESS_ABORT_IN_PANIC_HOOK: Cell<bool> = const { Cell::new(false) };
44}
45
46pub fn should_panic_hook_suppress_termination() -> bool {
53 SUPPRESS_ABORT_IN_PANIC_HOOK.get()
54}
55
56const FALLBACK_RIPPY: &[u8] = include_bytes!("resources/rippy.png");
60
61const MAX_SVG_PIXMAP_DIMENSION: u32 = 5000;
69
70fn parse_svg_document_in_memory(
85 bytes: &[u8],
86 usvg_options: Arc<usvg::Options>,
87) -> Result<usvg::Tree, &'static str> {
88 usvg::Tree::from_data(bytes, &usvg_options)
89 .inspect_err(|error| {
90 warn!("Error when parsing SVG data: {error}");
91 })
92 .map_err(|_| "Not a valid SVG document")
93}
94
95fn decode_bytes_sync(
96 key: LoadKey,
97 bytes: &[u8],
98 cors: CorsStatus,
99 content_type: Option<Mime>,
100 usvg_options: Arc<usvg::Options>,
101) -> DecoderMsg {
102 let is_svg_document = content_type.is_some_and(|content_type| {
103 (
104 content_type.type_(),
105 content_type.subtype(),
106 content_type.suffix(),
107 ) == (mime::IMAGE, mime::SVG, Some(mime::XML))
108 });
109
110 let image = if is_svg_document {
111 parse_svg_document_in_memory(bytes, usvg_options)
112 .ok()
113 .map(|svg_tree| {
114 DecodedImage::Vector(VectorImageData {
115 svg_tree: Arc::new(svg_tree),
116 cors_status: cors,
117 })
118 })
119 } else {
120 load_from_memory(bytes, cors).map(DecodedImage::Raster)
121 };
122
123 DecoderMsg { key, image }
124}
125
126fn set_webrender_image_key(
127 paint_api: &CrossProcessPaintApi,
128 image: &mut RasterImage,
129 image_key: WebRenderImageKey,
130) {
131 if image.id.is_some() {
132 return;
133 }
134
135 let (descriptor, ipc_shared_memory, should_be_cached) =
136 image.webrender_image_descriptor_and_data_for_frame(0);
137 let data = SerializableImageData::Raw(ipc_shared_memory);
138
139 paint_api.add_image(image_key, descriptor, data, should_be_cached);
140 image.id = Some(image_key);
141}
142
143type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
149
150#[derive(Default, MallocSizeOf)]
153struct AllPendingLoads {
154 loads: FxHashMap<LoadKey, PendingLoad>,
157
158 url_to_load_key: HashMap<ImageKey, LoadKey>,
161
162 keygen: LoadKeyGenerator,
164}
165
166impl AllPendingLoads {
167 fn new() -> AllPendingLoads {
168 AllPendingLoads {
169 loads: FxHashMap::default(),
170 url_to_load_key: HashMap::default(),
171 keygen: LoadKeyGenerator::new(),
172 }
173 }
174
175 fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
177 self.loads.get_mut(key)
178 }
179
180 fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
181 self.loads.remove(key).inspect(|pending_load| {
182 self.url_to_load_key
183 .remove(&(
184 pending_load.url.clone(),
185 pending_load.load_origin.clone(),
186 pending_load.cors_setting,
187 ))
188 .unwrap();
189 })
190 }
191
192 fn get_cached(
193 &mut self,
194 url: ServoUrl,
195 origin: ImmutableOrigin,
196 cors_status: Option<CorsSettings>,
197 ) -> CacheResult<'_> {
198 match self
199 .url_to_load_key
200 .entry((url.clone(), origin.clone(), cors_status))
201 {
202 Occupied(url_entry) => {
203 let load_key = url_entry.get();
204 CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap())
205 },
206 Vacant(url_entry) => {
207 let load_key = self.keygen.next();
208 url_entry.insert(load_key);
209
210 let pending_load = PendingLoad::new(url, origin, cors_status);
211 match self.loads.entry(load_key) {
212 Occupied(_) => unreachable!(),
213 Vacant(load_entry) => {
214 let mut_load = load_entry.insert(pending_load);
215 CacheResult::Miss(Some((load_key, mut_load)))
216 },
217 }
218 },
219 }
220 }
221}
222
223enum CacheResult<'a> {
225 Hit(LoadKey, &'a mut PendingLoad),
227 Miss(Option<(LoadKey, &'a mut PendingLoad)>),
229}
230
231#[derive(MallocSizeOf)]
236struct CompletedLoad {
237 image_response: ImageResponse,
238 id: PendingImageId,
239}
240
241impl CompletedLoad {
242 fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
243 CompletedLoad { image_response, id }
244 }
245}
246
247#[derive(Clone, MallocSizeOf)]
248struct VectorImageData {
249 #[conditional_malloc_size_of]
250 svg_tree: Arc<usvg::Tree>,
251 cors_status: CorsStatus,
252}
253
254impl std::fmt::Debug for VectorImageData {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 f.debug_struct("VectorImageData").finish()
257 }
258}
259
260enum DecodedImage {
261 Raster(RasterImage),
262 Vector(VectorImageData),
263}
264
265struct DecoderMsg {
267 key: LoadKey,
268 image: Option<DecodedImage>,
269}
270
271#[derive(MallocSizeOf)]
272enum ImageBytes {
273 InProgress(Vec<u8>),
274 Complete(#[conditional_malloc_size_of] Arc<Vec<u8>>),
275}
276
277impl ImageBytes {
278 fn extend_from_slice(&mut self, data: &[u8]) {
279 match *self {
280 ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
281 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
282 }
283 }
284
285 fn mark_complete(&mut self) -> Arc<Vec<u8>> {
286 let mut bytes = {
287 let own_bytes = match *self {
288 ImageBytes::InProgress(ref mut bytes) => bytes,
289 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
290 };
291 mem::take(own_bytes)
292 };
293 bytes.shrink_to_fit();
294 let bytes = Arc::new(bytes);
295 *self = ImageBytes::Complete(bytes.clone());
296 bytes
297 }
298
299 fn as_slice(&self) -> &[u8] {
300 match *self {
301 ImageBytes::InProgress(ref bytes) => bytes,
302 ImageBytes::Complete(ref bytes) => bytes,
303 }
304 }
305
306 fn set_capacity(&mut self, size: usize) {
307 match self {
308 ImageBytes::InProgress(items) => items.reserve(size.saturating_sub(items.len())),
309 ImageBytes::Complete(_) => error!("Want to set capacity on already completed image."),
310 }
311 }
312}
313
314type LoadKey = PendingImageId;
316
317#[derive(Default, MallocSizeOf)]
318struct LoadKeyGenerator {
319 counter: u64,
320}
321
322impl LoadKeyGenerator {
323 fn new() -> LoadKeyGenerator {
324 LoadKeyGenerator { counter: 0 }
325 }
326 fn next(&mut self) -> PendingImageId {
327 self.counter += 1;
328 PendingImageId(self.counter)
329 }
330}
331
332#[derive(Debug)]
333enum LoadResult {
334 LoadedRasterImage(RasterImage),
335 LoadedVectorImage(VectorImageData),
336 FailedToLoadOrDecode,
337}
338
339#[derive(MallocSizeOf)]
342struct PendingLoad {
343 bytes: ImageBytes,
346
347 metadata: Option<ImageMetadata>,
349
350 result: Option<Result<(), NetworkError>>,
352
353 listeners: Vec<ImageLoadListener>,
355
356 url: ServoUrl,
359
360 load_origin: ImmutableOrigin,
362
363 cors_setting: Option<CorsSettings>,
365
366 cors_status: CorsStatus,
368
369 final_url: Option<ServoUrl>,
371
372 content_type: Option<Mime>,
374}
375
376impl PendingLoad {
377 fn new(
378 url: ServoUrl,
379 load_origin: ImmutableOrigin,
380 cors_setting: Option<CorsSettings>,
381 ) -> PendingLoad {
382 PendingLoad {
383 bytes: ImageBytes::InProgress(vec![]),
384 metadata: None,
385 result: None,
386 listeners: vec![],
387 url,
388 load_origin,
389 final_url: None,
390 cors_setting,
391 cors_status: CorsStatus::Unsafe,
392 content_type: None,
393 }
394 }
395
396 fn add_listener(&mut self, listener: ImageLoadListener) {
397 self.listeners.push(listener);
398 }
399}
400
401#[derive(Default, MallocSizeOf)]
402struct RasterizationTask {
403 #[ignore_malloc_size_of = "Fn is difficult to measure"]
404 listeners: Vec<(PipelineId, ImageCacheResponseCallback)>,
405 result: Option<RasterImage>,
406}
407
408#[derive(Debug, MallocSizeOf)]
410enum PendingKey {
411 RasterImage((LoadKey, RasterImage)),
412 Svg((LoadKey, RasterImage, DeviceIntSize)),
413}
414
415#[derive(Debug, Default, MallocSizeOf)]
417enum KeyCacheState {
418 PendingBatch,
420 Ready(Vec<WebRenderImageKey>),
422 Processing,
424 #[default]
426 PipelineClosed,
427}
428
429impl KeyCacheState {
430 fn size(&self) -> usize {
431 match self {
432 KeyCacheState::PendingBatch |
433 KeyCacheState::Processing |
434 KeyCacheState::PipelineClosed => 0,
435 KeyCacheState::Ready(items) => items.len(),
436 }
437 }
438}
439
440#[derive(Default, MallocSizeOf)]
444struct KeyCache {
445 cache: KeyCacheState,
447 images_pending_keys: VecDeque<PendingKey>,
449 evicted_images: HashSet<(LoadKey, DeviceIntSize)>,
452}
453
454impl KeyCache {
455 fn new() -> Self {
456 KeyCache {
457 cache: KeyCacheState::Ready(Vec::new()),
458 images_pending_keys: VecDeque::new(),
459 evicted_images: HashSet::new(),
460 }
461 }
462}
463
464#[derive(Debug, Default, MallocSizeOf)]
465struct SvgRasterizationTaskStore(FxHashSet<(PendingImageId, DeviceIntSize)>);
467
468impl SvgRasterizationTaskStore {
469 fn is_or_set_being_rasterized(
471 &mut self,
472 pending_image_id: PendingImageId,
473 size: DeviceIntSize,
474 ) -> bool {
475 !self.0.insert((pending_image_id, size))
476 }
477
478 fn remove_being_rasterized(&mut self, pending_image_id: PendingImageId, size: DeviceIntSize) {
480 self.0.remove(&(pending_image_id, size));
481 }
482
483 fn remove_all_for_id(&mut self, pending_image_id: PendingImageId) {
484 self.0.retain(|(id, _size)| *id != pending_image_id);
485 }
486}
487
488#[derive(MallocSizeOf)]
490struct ImageCacheStore {
491 pending_loads: AllPendingLoads,
493
494 completed_loads: HashMap<ImageKey, CompletedLoad>,
496
497 vector_images: FxHashMap<PendingImageId, VectorImageData>,
501
502 rasterized_vector_images: FxHashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
506
507 svg_rasterization_task_store: SvgRasterizationTaskStore,
509
510 #[conditional_malloc_size_of]
512 broken_image_icon_image: OnceCell<Option<Arc<RasterImage>>>,
513
514 paint_api: CrossProcessPaintApi,
516
517 webview_id: WebViewId,
519
520 pipeline_id: PipelineId,
522
523 key_cache: KeyCache,
526}
527
528impl ImageCacheStore {
529 #[cfg(feature = "test-util")]
530 fn number_of_rasterize_tasks(&self) -> usize {
531 self.svg_rasterization_task_store.0.len()
532 }
533
534 fn set_key_and_finish_load(&mut self, pending_image: PendingKey, image_key: WebRenderImageKey) {
536 match pending_image {
537 PendingKey::RasterImage((pending_id, mut raster_image)) => {
538 if self.pending_loads.get_by_key_mut(&pending_id).is_none() {
541 return;
542 }
543 set_webrender_image_key(&self.paint_api, &mut raster_image, image_key);
544 self.complete_load(pending_id, LoadResult::LoadedRasterImage(raster_image));
545 },
546 PendingKey::Svg((pending_id, mut raster_image, requested_size)) => {
547 if !self
550 .rasterized_vector_images
551 .contains_key(&(pending_id, requested_size))
552 {
553 return;
554 }
555 set_webrender_image_key(&self.paint_api, &mut raster_image, image_key);
556 self.svg_rasterization_task_store
557 .remove_being_rasterized(pending_id, requested_size);
558 self.complete_load_svg(raster_image, pending_id, requested_size);
559 },
560 }
561 }
562
563 fn load_image_with_keycache(&mut self, pending_image: PendingKey) {
566 if let PendingKey::Svg((pending_id, ref _raster_image, requested_size)) = pending_image &&
567 self.key_cache
568 .evicted_images
569 .remove(&(pending_id, requested_size))
570 {
571 self.svg_rasterization_task_store
572 .remove_being_rasterized(pending_id, requested_size);
573 return;
574 }
575 match self.key_cache.cache {
576 KeyCacheState::PendingBatch | KeyCacheState::Processing => {
577 self.key_cache.images_pending_keys.push_back(pending_image);
578 },
579 KeyCacheState::Ready(ref mut cache) => match cache.pop() {
580 Some(image_key) => {
581 self.set_key_and_finish_load(pending_image, image_key);
582 },
583 None => {
584 self.key_cache.images_pending_keys.push_back(pending_image);
585 self.fetch_more_image_keys();
586 },
587 },
588 KeyCacheState::PipelineClosed => {},
589 }
590 }
591
592 fn evict_image_from_keycache(
593 &mut self,
594 image_id: &PendingImageId,
595 requested_size: &DeviceIntSize,
596 ) {
597 self.key_cache
598 .evicted_images
599 .insert((*image_id, *requested_size));
600 }
601
602 fn fetch_more_image_keys(&mut self) {
603 self.key_cache.cache = KeyCacheState::PendingBatch;
604 self.paint_api
605 .generate_image_key_async(self.webview_id, self.pipeline_id);
606 }
607
608 fn insert_keys_and_load_images(&mut self, image_keys: Vec<WebRenderImageKey>) {
610 match &mut self.key_cache.cache {
611 KeyCacheState::Processing => {
612 self.key_cache.cache = KeyCacheState::Ready(image_keys);
614 let len = min(
615 self.key_cache.cache.size(),
616 self.key_cache.images_pending_keys.len(),
617 );
618 let images = self
619 .key_cache
620 .images_pending_keys
621 .drain(0..len)
622 .collect::<Vec<PendingKey>>();
623 for key in images {
624 self.load_image_with_keycache(key);
625 }
626 if !self.key_cache.images_pending_keys.is_empty() {
628 self.paint_api
629 .generate_image_key_async(self.webview_id, self.pipeline_id);
630 self.key_cache.cache = KeyCacheState::PendingBatch
631 }
632 },
633 KeyCacheState::PendingBatch | KeyCacheState::Ready(_) => {
634 unreachable!("A batch was received while we didn't request one")
635 },
636 PipelineClosed => {},
637 }
638 }
639
640 fn complete_load_svg(
643 &mut self,
644 rasterized_image: RasterImage,
645 pending_image_id: PendingImageId,
646 requested_size: DeviceIntSize,
647 ) {
648 let listeners = {
649 self.rasterized_vector_images
650 .get_mut(&(pending_image_id, requested_size))
651 .map(|task| {
652 task.result = Some(rasterized_image);
653 std::mem::take(&mut task.listeners)
654 })
655 .unwrap_or_default()
656 };
657
658 for (pipeline_id, callback) in listeners {
659 callback(ImageCacheResponseMessage::VectorImageRasterizationComplete(
660 RasterizationCompleteResponse {
661 pipeline_id,
662 image_id: pending_image_id,
663 requested_size,
664 },
665 ));
666 }
667 }
668
669 fn complete_load(&mut self, key: LoadKey, load_result: LoadResult) {
671 debug!("Completed decoding for {:?}", load_result);
672 let pending_load = match self.pending_loads.remove(&key) {
673 Some(load) => load,
674 None => return,
675 };
676 let url = pending_load.final_url.clone();
677 let image_response = match load_result {
678 LoadResult::LoadedRasterImage(raster_image) => {
679 assert!(raster_image.id.is_some());
680 ImageResponse::Loaded(Image::Raster(Arc::new(raster_image)), url.unwrap())
681 },
682 LoadResult::LoadedVectorImage(vector_image) => {
683 self.vector_images.insert(key, vector_image.clone());
684 let natural_dimensions = vector_image.svg_tree.size().to_int_size();
685 let metadata = ImageMetadata {
686 width: natural_dimensions.width(),
687 height: natural_dimensions.height(),
688 };
689
690 let vector_image = VectorImage {
691 id: key,
692 svg_id: None,
693 metadata,
694 cors_status: vector_image.cors_status,
695 };
696 ImageResponse::Loaded(Image::Vector(vector_image), url.unwrap())
697 },
698 LoadResult::FailedToLoadOrDecode => ImageResponse::FailedToLoadOrDecode,
699 };
700
701 let completed_load = CompletedLoad::new(image_response.clone(), key);
702 self.completed_loads.insert(
703 (
704 pending_load.url,
705 pending_load.load_origin,
706 pending_load.cors_setting,
707 ),
708 completed_load,
709 );
710
711 for listener in pending_load.listeners {
712 listener.respond(image_response.clone());
713 }
714 }
715
716 fn remove_loaded_image(
717 &mut self,
718 url: &ServoUrl,
719 origin: &ImmutableOrigin,
720 cors_setting: &Option<CorsSettings>,
721 ) {
722 if let Some(loaded_image) =
723 self.completed_loads
724 .remove(&(url.clone(), origin.clone(), *cors_setting)) &&
725 let ImageResponse::Loaded(Image::Raster(image), _) = loaded_image.image_response &&
726 let Some(id) = image.id
727 {
728 self.paint_api.update_images(
729 self.webview_id.into(),
730 vec![ImageUpdate::DeleteImage(id)].into(),
731 );
732 }
733 }
734
735 fn remove_rasterized_vector_image(
736 &mut self,
737 image_id: &PendingImageId,
738 device_size: &DeviceIntSize,
739 ) {
740 if let Some(entry) = self
741 .rasterized_vector_images
742 .remove(&(*image_id, *device_size))
743 {
744 if let Some(result) = entry.result {
745 if let Some(image_id) = result.id {
746 self.paint_api.update_images(
747 self.webview_id.into(),
748 vec![ImageUpdate::DeleteImage(image_id)].into(),
749 );
750 }
751 } else {
752 self.evict_image_from_keycache(image_id, device_size);
757 }
758 } else {
759 self.evict_image_from_keycache(image_id, device_size);
764 }
765 }
766
767 fn get_completed_image_if_available(
770 &self,
771 url: ServoUrl,
772 origin: ImmutableOrigin,
773 cors_setting: Option<CorsSettings>,
774 ) -> Option<Result<(Image, ServoUrl), ()>> {
775 self.completed_loads
776 .get(&(url, origin, cors_setting))
777 .map(|completed_load| match &completed_load.image_response {
778 ImageResponse::Loaded(image, url) => Ok((image.clone(), url.clone())),
779 ImageResponse::FailedToLoadOrDecode | ImageResponse::MetadataLoaded(_) => Err(()),
780 })
781 }
782
783 fn handle_decoder(&mut self, msg: DecoderMsg) {
786 let image = match msg.image {
787 None => LoadResult::FailedToLoadOrDecode,
788 Some(DecodedImage::Raster(raster_image)) => {
789 self.load_image_with_keycache(PendingKey::RasterImage((msg.key, raster_image)));
790 return;
791 },
792 Some(DecodedImage::Vector(vector_image_data)) => {
793 LoadResult::LoadedVectorImage(vector_image_data)
794 },
795 };
796 self.complete_load(msg.key, image);
797 }
798}
799
800pub struct ImageCacheFactoryImpl {
801 broken_image_icon_data: Arc<Vec<u8>>,
803 thread_pool: Arc<ThreadPool>,
805}
806
807impl ImageCacheFactoryImpl {
808 pub fn new(broken_image_icon_data: Vec<u8>) -> Self {
809 debug!("Creating new ImageCacheFactoryImpl");
810
811 Self {
812 broken_image_icon_data: Arc::new(broken_image_icon_data),
813 thread_pool: ThreadPool::global(),
814 }
815 }
816}
817
818impl ImageCacheFactory for ImageCacheFactoryImpl {
819 fn create(
820 &self,
821 webview_id: WebViewId,
822 pipeline_id: PipelineId,
823 paint_api: &CrossProcessPaintApi,
824 font_resolver: Arc<dyn FontResolver>,
825 ) -> Arc<dyn ImageCache> {
826 let image_string_href_resolver = Box::new(move |_: &str, _: &usvg::Options| {
827 None
829 });
830 let font_resolver2 = font_resolver.clone();
831 let font_resolver3 = font_resolver.clone();
832 let usvg_font_resolver = usvg::FontResolver {
833 select_font: Box::new(move |font, database| font_resolver2.resolve(font, database)),
834 select_fallback: Box::new(move |char, ids, database| {
835 font_resolver3.resolve_fallback(char, ids, database)
836 }),
837 };
838
839 let opt = usvg::Options {
840 image_href_resolver: usvg::ImageHrefResolver {
841 resolve_data: usvg::ImageHrefResolver::default_data_resolver(),
842 resolve_string: image_string_href_resolver,
843 },
844 font_resolver: usvg_font_resolver,
845 fontdb: Arc::new(fontdb::Database::new()),
846 ..usvg::Options::default()
847 };
848
849 Arc::new(ImageCacheImpl {
850 store: Arc::new(Mutex::new(ImageCacheStore {
851 pending_loads: AllPendingLoads::new(),
852 completed_loads: HashMap::new(),
853 vector_images: FxHashMap::default(),
854 rasterized_vector_images: FxHashMap::default(),
855 broken_image_icon_image: OnceCell::new(),
856 paint_api: paint_api.clone(),
857 pipeline_id,
858 webview_id,
859 key_cache: KeyCache::new(),
860 svg_rasterization_task_store: SvgRasterizationTaskStore::default(),
861 })),
862 svg_id_image_id_map: Arc::new(Mutex::new(FxHashMap::default())),
863 broken_image_icon_data: self.broken_image_icon_data.clone(),
864 thread_pool: self.thread_pool.clone(),
865 usvg_options: Arc::new(opt),
866 usvg_font_resolver: font_resolver.clone(),
867 })
868 }
869}
870
871pub struct ImageCacheImpl {
872 store: Arc<Mutex<ImageCacheStore>>,
874 svg_id_image_id_map: Arc<Mutex<FxHashMap<Uuid, PendingImageId>>>,
876 broken_image_icon_data: Arc<Vec<u8>>,
878 thread_pool: Arc<ThreadPool>,
881 usvg_options: Arc<usvg::Options<'static>>,
883 usvg_font_resolver: Arc<dyn FontResolver>,
887}
888
889impl ImageCache for ImageCacheImpl {
890 fn memory_reports(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Vec<Report> {
891 let store_size = self.store.lock().size_of(ops);
892 let fontdb_size = self.usvg_options.conditional_size_of(ops);
893 let broken_image_size = self.broken_image_icon_data.conditional_size_of(ops);
894 let svg_id_map = self.svg_id_image_id_map.conditional_size_of(ops);
895 let svg_font_resolver = self.usvg_font_resolver.size_of(ops);
896 vec![
897 Report {
898 path: path![prefix, "image-cache", "cache"],
899 kind: ReportKind::ExplicitSystemHeapSize,
900 size: store_size,
901 },
902 Report {
903 path: path![prefix, "image-cache", "svg_id_map"],
904 kind: ReportKind::ExplicitSystemHeapSize,
905 size: svg_id_map,
906 },
907 Report {
908 path: path![prefix, "image-cache", "broken_image_icon"],
909 kind: ReportKind::ExplicitSystemHeapSize,
910 size: broken_image_size,
911 },
912 Report {
913 path: path![prefix, "image-cache", "svg_font_resolver"],
914 kind: ReportKind::ExplicitSystemHeapSize,
915 size: svg_font_resolver,
916 },
917 Report {
918 path: path![prefix, "image-cache", "usvg_options"],
919 kind: ReportKind::ExplicitSystemHeapSize,
920 size: fontdb_size,
921 },
922 ]
923 }
924
925 #[cfg(feature = "test-util")]
926 fn number_of_rasterize_tasks(&self) -> usize {
927 self.store.lock().number_of_rasterize_tasks()
928 }
929
930 fn get_image_key(&self) -> Option<WebRenderImageKey> {
931 let mut store = self.store.lock();
932 if let KeyCacheState::Ready(ref mut cache) = store.key_cache.cache {
933 if let Some(image_key) = cache.pop() {
934 return Some(image_key);
935 }
936
937 store.fetch_more_image_keys();
938 }
939
940 store
941 .paint_api
942 .generate_image_key_blocking(store.webview_id)
943 }
944
945 fn get_image(
946 &self,
947 url: ServoUrl,
948 origin: ImmutableOrigin,
949 cors_setting: Option<CorsSettings>,
950 ) -> Option<Image> {
951 let store = self.store.lock();
952 let result = store.get_completed_image_if_available(url, origin, cors_setting);
953 match result {
954 Some(Ok((img, _))) => Some(img),
955 _ => None,
956 }
957 }
958
959 fn get_cached_image_status(
960 &self,
961 url: ServoUrl,
962 origin: ImmutableOrigin,
963 cors_setting: Option<CorsSettings>,
964 ) -> ImageCacheResult {
965 let mut store = self.store.lock();
966 if let Some(result) =
967 store.get_completed_image_if_available(url.clone(), origin.clone(), cors_setting)
968 {
969 match result {
970 Ok((image, image_url)) => {
971 debug!("{} is available", url);
972 return ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
973 image,
974 url: image_url,
975 });
976 },
977 Err(()) => {
978 debug!("{} is not available", url);
979 return ImageCacheResult::FailedToLoadOrDecode;
980 },
981 }
982 }
983
984 let result = store
985 .pending_loads
986 .get_cached(url.clone(), origin, cors_setting);
987 match result {
988 CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
989 (&Some(Ok(_)), _) => ImageCacheResult::Pending(key),
990 (&None, Some(meta)) => {
991 debug!("Metadata available for {} ({:?})", url, key);
992 ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(
993 *meta, key,
994 ))
995 },
996 (&Some(Err(_)), _) | (&None, &None) => {
997 debug!("{} ({:?}) is still pending", url, key);
998 ImageCacheResult::Pending(key)
999 },
1000 },
1001 CacheResult::Miss(Some((key, _pl))) => {
1002 debug!("Should be requesting {} ({:?})", url, key);
1003 ImageCacheResult::ReadyForRequest(key)
1004 },
1005 CacheResult::Miss(None) => {
1006 debug!("Couldn't find an entry for {}", url);
1007 ImageCacheResult::FailedToLoadOrDecode
1008 },
1009 }
1010 }
1011
1012 fn add_rasterization_complete_listener(
1013 &self,
1014 pipeline_id: PipelineId,
1015 image_id: PendingImageId,
1016 requested_size: DeviceIntSize,
1017 callback: ImageCacheResponseCallback,
1018 ) {
1019 {
1020 let mut store = self.store.lock();
1021 let key = (image_id, requested_size);
1022 if !store.vector_images.contains_key(&image_id) {
1023 warn!("Unknown image requested for rasterization for key {key:?}");
1024 return;
1025 };
1026
1027 let Some(task) = store.rasterized_vector_images.get_mut(&key) else {
1028 warn!("Image rasterization task not found in the cache for key {key:?}");
1029 return;
1030 };
1031
1032 if task.result.is_none() {
1034 task.listeners.push((pipeline_id, callback));
1035 return;
1036 }
1037 }
1038
1039 callback(ImageCacheResponseMessage::VectorImageRasterizationComplete(
1040 RasterizationCompleteResponse {
1041 pipeline_id,
1042 image_id,
1043 requested_size,
1044 },
1045 ));
1046 }
1047
1048 fn rasterize_vector_image(
1049 &self,
1050 image_id: PendingImageId,
1051 requested_size: DeviceIntSize,
1052 svg_id: Option<Uuid>,
1053 ) -> Option<RasterImage> {
1054 let mut store = self.store.lock();
1055 let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
1056 warn!("Unknown image id {image_id:?} requested for rasterization");
1057 return None;
1058 };
1059
1060 let entry = store
1064 .rasterized_vector_images
1065 .entry((image_id, requested_size))
1066 .or_default();
1067 if let Some(result) = entry.result.as_ref() {
1068 return Some(result.clone());
1069 }
1070
1071 if let Some(svg_id) = svg_id &&
1072 let Some(old_mapped_image_id) =
1073 self.svg_id_image_id_map.lock().insert(svg_id, image_id) &&
1074 old_mapped_image_id != image_id
1075 {
1076 store.vector_images.remove(&old_mapped_image_id);
1077 store
1078 .rasterized_vector_images
1079 .remove(&(old_mapped_image_id, requested_size));
1080 store
1081 .svg_rasterization_task_store
1082 .remove_all_for_id(old_mapped_image_id);
1083 }
1084
1085 if store
1086 .svg_rasterization_task_store
1087 .is_or_set_being_rasterized(image_id, requested_size)
1088 {
1089 return None;
1090 }
1091
1092 let natural_size = vector_image.svg_tree.size().to_int_size();
1093 let tinyskia_requested_size = {
1094 let width = requested_size
1095 .width
1096 .try_into()
1097 .unwrap_or(0)
1098 .min(MAX_SVG_PIXMAP_DIMENSION);
1099 let height = requested_size
1100 .height
1101 .try_into()
1102 .unwrap_or(0)
1103 .min(MAX_SVG_PIXMAP_DIMENSION);
1104 tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
1105 };
1106
1107 if tinyskia_requested_size.width() == 0 ||
1109 tinyskia_requested_size.width() > (i32::MAX / 4).try_into().unwrap() ||
1110 tinyskia_requested_size.height() == 0
1111 {
1112 debug!(
1113 "Asked for requested size {:?} which has zero size. Not returning image",
1114 requested_size
1115 );
1116 return None;
1117 }
1118
1119 let store = self.store.clone();
1120 self.thread_pool.spawn(move || {
1121 let transform = tiny_skia::Transform::from_scale(
1122 tinyskia_requested_size.width() as f32 / natural_size.width() as f32,
1123 tinyskia_requested_size.height() as f32 / natural_size.height() as f32,
1124 );
1125 let mut pixmap = tiny_skia::Pixmap::new(
1126 tinyskia_requested_size.width(),
1127 tinyskia_requested_size.height(),
1128 )
1129 .unwrap();
1130
1131 SUPPRESS_ABORT_IN_PANIC_HOOK.set(true);
1144 let resvg_result = std::panic::catch_unwind(AssertUnwindSafe(|| {
1145 resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
1146
1147 let bytes = pixmap.take();
1148 let frame = ImageFrame {
1149 delay: None,
1150 byte_range: 0..bytes.len(),
1151 width: tinyskia_requested_size.width(),
1152 height: tinyskia_requested_size.height(),
1153 };
1154
1155 RasterImage {
1156 metadata: ImageMetadata {
1157 width: tinyskia_requested_size.width(),
1158 height: tinyskia_requested_size.height(),
1159 },
1160 format: PixelFormat::RGBA8,
1161 frames: vec![frame],
1162 bytes: Arc::new(bytes),
1163 id: None,
1164 cors_status: vector_image.cors_status,
1165 is_opaque: false,
1166 loop_count: None,
1167 }
1168 }));
1169 SUPPRESS_ABORT_IN_PANIC_HOOK.set(false);
1170
1171 match resvg_result {
1172 Ok(rasterized_image) => {
1173 let mut store = store.lock();
1174 store.load_image_with_keycache(PendingKey::Svg((
1175 image_id,
1176 rasterized_image,
1177 requested_size,
1178 )));
1179 },
1180 Err(_) => {
1181 warn!("resvg panicked while rasterizing SVG image {image_id:?} at {requested_size:?}");
1182 let mut store = store.lock();
1183 store
1185 .svg_rasterization_task_store
1186 .remove_being_rasterized(image_id, requested_size);
1187 store
1188 .rasterized_vector_images
1189 .remove(&(image_id, requested_size));
1190
1191 store.vector_images.remove(&image_id);
1197 },
1198 }
1199 });
1200 None
1201 }
1202
1203 fn add_listener(&self, listener: ImageLoadListener) {
1206 let mut store = self.store.lock();
1207 self.add_listener_with_store(&mut store, listener);
1208 }
1209
1210 fn evict_completed_image(
1211 &self,
1212 url: &ServoUrl,
1213 origin: &ImmutableOrigin,
1214 cors_setting: &Option<CorsSettings>,
1215 ) {
1216 let mut store = self.store.lock();
1217 store.remove_loaded_image(url, origin, cors_setting);
1218 }
1219
1220 fn evict_rasterized_image(&self, svg_id: &Uuid) {
1221 let mut store = self.store.lock();
1222 if let Some(mapped_image_id) = self.svg_id_image_id_map.lock().remove(svg_id) {
1223 store.pending_loads.remove(&mapped_image_id);
1224 store.vector_images.remove(&mapped_image_id);
1225 let images_to_remove = store
1226 .rasterized_vector_images
1227 .keys()
1228 .filter(|(id, _size)| *id == mapped_image_id)
1229 .cloned()
1230 .collect::<Vec<_>>();
1231 for (id, requested_size) in images_to_remove {
1232 store.remove_rasterized_vector_image(&id, &requested_size);
1233 }
1234 }
1235 }
1236
1237 fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
1239 match (action, id) {
1240 (FetchResponseMsg::ProcessRequestBody(..), _) |
1241 (FetchResponseMsg::ProcessCspViolations(..), _) => (),
1242 (FetchResponseMsg::ProcessResponse(_, response), _) => {
1243 debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
1244 let mut store = self.store.lock();
1245 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1246 let (cors_status, metadata) = match response {
1247 Ok(meta) => match meta {
1248 FetchMetadata::Unfiltered(m) => (CorsStatus::Safe, Some(m)),
1249 FetchMetadata::Filtered { unsafe_, filtered } => (
1250 match filtered {
1251 FilteredMetadata::Basic(_) | FilteredMetadata::Cors(_) => {
1252 CorsStatus::Safe
1253 },
1254 FilteredMetadata::Opaque |
1255 FilteredMetadata::OpaqueRedirect(_) => CorsStatus::Unsafe,
1256 },
1257 Some(unsafe_),
1258 ),
1259 },
1260 Err(_) => (CorsStatus::Unsafe, None),
1261 };
1262 let final_url = metadata.as_ref().map(|m| m.final_url.clone());
1263 pending_load.final_url = final_url;
1264 pending_load.cors_status = cors_status;
1265 pending_load.content_type = metadata
1266 .as_ref()
1267 .and_then(|metadata| metadata.content_type.clone())
1268 .map(|content_type| content_type.into_inner().into());
1269 } else {
1270 debug!("Pending load for id {:?} already evicted from cache", id);
1271 }
1272 },
1273 (FetchResponseMsg::ProcessResponseChunk(_, data), _) => {
1274 debug!("Got some data for {:?}", id);
1275 let mut store = self.store.lock();
1276 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1277 pending_load.bytes.extend_from_slice(&data);
1278
1279 if pending_load.metadata.is_none() {
1281 let mut reader = std::io::Cursor::new(pending_load.bytes.as_slice());
1282 if let Ok(info) = imsz_from_reader(&mut reader) {
1283 let img_metadata = ImageMetadata {
1284 width: info.width as u32,
1285 height: info.height as u32,
1286 };
1287 for listener in &pending_load.listeners {
1288 listener.respond(ImageResponse::MetadataLoaded(img_metadata));
1289 }
1290 pending_load.metadata = Some(img_metadata);
1291 }
1292 }
1293 } else {
1294 debug!("Pending load for id {:?} already evicted from cache", id);
1295 }
1296 },
1297 (FetchResponseMsg::ProcessResponseEOF(_, result, _), key) => {
1298 debug!("Received EOF for {:?}", key);
1299 match result {
1300 Ok(_) => {
1301 let (bytes, cors_status, content_type) = {
1302 let mut store = self.store.lock();
1303 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1304 pending_load.result = Some(Ok(()));
1305 debug!("Async decoding {} ({:?})", pending_load.url, key);
1306 (
1307 pending_load.bytes.mark_complete(),
1308 pending_load.cors_status,
1309 pending_load.content_type.clone(),
1310 )
1311 } else {
1312 debug!("Pending load for id {:?} already evicted from cache", id);
1313 return;
1314 }
1315 };
1316
1317 let local_store = self.store.clone();
1318 let usvg_options = self.usvg_options.clone();
1319 self.thread_pool.spawn(move || {
1320 let msg = decode_bytes_sync(
1321 key,
1322 &bytes,
1323 cors_status,
1324 content_type,
1325 usvg_options,
1326 );
1327 local_store.lock().handle_decoder(msg);
1328 });
1329 },
1330 Err(error) => {
1331 debug!("Processing error for {key:?}: {error:?}");
1332 let mut store = self.store.lock();
1333 store.complete_load(id, LoadResult::FailedToLoadOrDecode)
1334 },
1335 }
1336 },
1337 (FetchResponseMsg::ProcessContentLength(_response_id, size), _key) => {
1338 let mut store = self.store.lock();
1339 if let Some(pending_load) = store.pending_loads.get_by_key_mut(&id) {
1340 pending_load.bytes.set_capacity(size);
1341 }
1342 },
1343 }
1344 }
1345
1346 fn dispatch_fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<WebRenderImageKey>) {
1348 self.store.lock().key_cache.cache = KeyCacheState::Processing;
1354
1355 let store = self.store.clone();
1356 self.thread_pool.spawn(move || {
1357 store.lock().insert_keys_and_load_images(image_keys);
1358 });
1359 }
1360
1361 fn clear(&self) {
1362 self.store.lock().clear();
1363 *self.svg_id_image_id_map.lock() = Default::default();
1364 }
1365
1366 fn get_broken_image_icon(&self) -> Option<Arc<RasterImage>> {
1367 let store = self.store.lock();
1368 store
1369 .broken_image_icon_image
1370 .get_or_init(|| {
1371 let mut image = load_from_memory(&self.broken_image_icon_data, CorsStatus::Unsafe)
1372 .or_else(|| load_from_memory(FALLBACK_RIPPY, CorsStatus::Unsafe))?;
1373 let image_key = store
1374 .paint_api
1375 .generate_image_key_blocking(store.webview_id)
1376 .expect("Could not generate image key for broken image icon");
1377 set_webrender_image_key(&store.paint_api, &mut image, image_key);
1378 Some(Arc::new(image))
1379 })
1380 .clone()
1381 }
1382}
1383
1384impl ImageCacheStore {
1385 fn clear(&mut self) {
1388 let deletions: smallvec::SmallVec<_> = self
1389 .completed_loads
1390 .values()
1391 .filter_map(|load| match &load.image_response {
1392 ImageResponse::Loaded(Image::Raster(image), _) => {
1393 image.id.map(ImageUpdate::DeleteImage)
1394 },
1395 _ => None,
1396 })
1397 .chain(
1398 self.rasterized_vector_images
1399 .values()
1400 .filter_map(|task| task.result.as_ref()?.id.map(ImageUpdate::DeleteImage)),
1401 )
1402 .chain(
1403 self.broken_image_icon_image
1404 .get()
1405 .and_then(|icon| icon.as_ref())
1406 .and_then(|icon| icon.id)
1407 .map(ImageUpdate::DeleteImage),
1408 )
1409 .collect();
1410 if !deletions.is_empty() {
1411 self.paint_api
1412 .update_images(self.webview_id.into(), deletions);
1413 }
1414 self.completed_loads = Default::default();
1418 self.vector_images = Default::default();
1419 self.rasterized_vector_images = Default::default();
1420 self.svg_rasterization_task_store = Default::default();
1421 self.pending_loads = Default::default();
1422 self.key_cache = Default::default();
1423
1424 let _ = self.broken_image_icon_image.take();
1425 }
1426}
1427
1428impl Drop for ImageCacheStore {
1429 fn drop(&mut self) {
1430 self.clear();
1431 }
1432}
1433
1434impl ImageCacheImpl {
1435 fn add_listener_with_store(&self, store: &mut ImageCacheStore, listener: ImageLoadListener) {
1437 let id = listener.id;
1438 if let Some(load) = store.pending_loads.get_by_key_mut(&id) {
1439 if let Some(ref metadata) = load.metadata {
1440 listener.respond(ImageResponse::MetadataLoaded(*metadata));
1441 }
1442 load.add_listener(listener);
1443 return;
1444 }
1445 if let Some(load) = store.completed_loads.values().find(|l| l.id == id) {
1446 listener.respond(load.image_response.clone());
1447 return;
1448 }
1449 warn!("Couldn't find cached entry for listener {:?}", id);
1450 }
1451}