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