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