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