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