1use std::cmp::min;
6use std::collections::hash_map::Entry::{Occupied, Vacant};
7use std::collections::{HashMap, VecDeque};
8use std::sync::{Arc, Mutex};
9use std::{mem, thread};
10
11use base::id::PipelineId;
12use base::threadpool::ThreadPool;
13use compositing_traits::{CrossProcessCompositorApi, ImageUpdate, SerializableImageData};
14use imsz::imsz_from_reader;
15use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
16use log::{debug, error, warn};
17use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
18use malloc_size_of_derive::MallocSizeOf;
19use mime::Mime;
20use net_traits::image_cache::{
21 Image, ImageCache, ImageCacheResponseMessage, ImageCacheResult, ImageLoadListener,
22 ImageOrMetadataAvailable, ImageResponse, PendingImageId, RasterizationCompleteResponse,
23 UsePlaceholder, VectorImage,
24};
25use net_traits::request::CorsSettings;
26use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
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;
33use servo_config::pref;
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 image = if content_type == Some(mime::IMAGE_SVG) {
99 parse_svg_document_in_memory(bytes, fontdb)
100 .ok()
101 .map(|svg_tree| {
102 DecodedImage::Vector(VectorImageData {
103 svg_tree: Arc::new(svg_tree),
104 cors_status: cors,
105 })
106 })
107 } else {
108 load_from_memory(bytes, cors).map(DecodedImage::Raster)
109 };
110
111 DecoderMsg { key, image }
112}
113
114fn get_placeholder_image(
117 compositor_api: &CrossProcessCompositorApi,
118 data: &[u8],
119) -> Arc<RasterImage> {
120 let mut image = load_from_memory(data, CorsStatus::Unsafe)
121 .or_else(|| load_from_memory(FALLBACK_RIPPY, CorsStatus::Unsafe))
122 .expect("load fallback image failed");
123 let image_key = compositor_api
124 .generate_image_key_blocking()
125 .expect("Could not generate image key");
126 set_webrender_image_key(compositor_api, &mut image, image_key);
127 Arc::new(image)
128}
129
130fn set_webrender_image_key(
131 compositor_api: &CrossProcessCompositorApi,
132 image: &mut RasterImage,
133 image_key: WebRenderImageKey,
134) {
135 if image.id.is_some() {
136 return;
137 }
138
139 let (descriptor, ipc_shared_memory) = image.webrender_image_descriptor_and_data_for_frame(0);
140 let data = SerializableImageData::Raw(ipc_shared_memory);
141
142 compositor_api.add_image(image_key, descriptor, data);
143 image.id = Some(image_key);
144}
145
146type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
152
153#[derive(MallocSizeOf)]
156struct AllPendingLoads {
157 loads: FxHashMap<LoadKey, PendingLoad>,
160
161 url_to_load_key: HashMap<ImageKey, LoadKey>,
164
165 keygen: LoadKeyGenerator,
167}
168
169impl AllPendingLoads {
170 fn new() -> AllPendingLoads {
171 AllPendingLoads {
172 loads: FxHashMap::default(),
173 url_to_load_key: HashMap::default(),
174 keygen: LoadKeyGenerator::new(),
175 }
176 }
177
178 fn get_by_key_mut(&mut self, key: &LoadKey) -> Option<&mut PendingLoad> {
180 self.loads.get_mut(key)
181 }
182
183 fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
184 self.loads.remove(key).inspect(|pending_load| {
185 self.url_to_load_key
186 .remove(&(
187 pending_load.url.clone(),
188 pending_load.load_origin.clone(),
189 pending_load.cors_setting,
190 ))
191 .unwrap();
192 })
193 }
194
195 fn get_cached(
196 &mut self,
197 url: ServoUrl,
198 origin: ImmutableOrigin,
199 cors_status: Option<CorsSettings>,
200 ) -> CacheResult<'_> {
201 match self
202 .url_to_load_key
203 .entry((url.clone(), origin.clone(), cors_status))
204 {
205 Occupied(url_entry) => {
206 let load_key = url_entry.get();
207 CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap())
208 },
209 Vacant(url_entry) => {
210 let load_key = self.keygen.next();
211 url_entry.insert(load_key);
212
213 let pending_load = PendingLoad::new(url, origin, cors_status);
214 match self.loads.entry(load_key) {
215 Occupied(_) => unreachable!(),
216 Vacant(load_entry) => {
217 let mut_load = load_entry.insert(pending_load);
218 CacheResult::Miss(Some((load_key, mut_load)))
219 },
220 }
221 },
222 }
223 }
224}
225
226enum CacheResult<'a> {
228 Hit(LoadKey, &'a mut PendingLoad),
230 Miss(Option<(LoadKey, &'a mut PendingLoad)>),
232}
233
234#[derive(MallocSizeOf)]
239struct CompletedLoad {
240 image_response: ImageResponse,
241 id: PendingImageId,
242}
243
244impl CompletedLoad {
245 fn new(image_response: ImageResponse, id: PendingImageId) -> CompletedLoad {
246 CompletedLoad { image_response, id }
247 }
248}
249
250#[derive(Clone, MallocSizeOf)]
251struct VectorImageData {
252 #[conditional_malloc_size_of]
253 svg_tree: Arc<usvg::Tree>,
254 cors_status: CorsStatus,
255}
256
257impl std::fmt::Debug for VectorImageData {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 f.debug_struct("VectorImageData").finish()
260 }
261}
262
263enum DecodedImage {
264 Raster(RasterImage),
265 Vector(VectorImageData),
266}
267
268struct DecoderMsg {
270 key: LoadKey,
271 image: Option<DecodedImage>,
272}
273
274#[derive(MallocSizeOf)]
275enum ImageBytes {
276 InProgress(Vec<u8>),
277 Complete(#[conditional_malloc_size_of] Arc<Vec<u8>>),
278}
279
280impl ImageBytes {
281 fn extend_from_slice(&mut self, data: &[u8]) {
282 match *self {
283 ImageBytes::InProgress(ref mut bytes) => bytes.extend_from_slice(data),
284 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
285 }
286 }
287
288 fn mark_complete(&mut self) -> Arc<Vec<u8>> {
289 let bytes = {
290 let own_bytes = match *self {
291 ImageBytes::InProgress(ref mut bytes) => bytes,
292 ImageBytes::Complete(_) => panic!("attempted modification of complete image bytes"),
293 };
294 mem::take(own_bytes)
295 };
296 let bytes = Arc::new(bytes);
297 *self = ImageBytes::Complete(bytes.clone());
298 bytes
299 }
300
301 fn as_slice(&self) -> &[u8] {
302 match *self {
303 ImageBytes::InProgress(ref bytes) => bytes,
304 ImageBytes::Complete(ref bytes) => bytes,
305 }
306 }
307}
308
309type LoadKey = PendingImageId;
311
312#[derive(MallocSizeOf)]
313struct LoadKeyGenerator {
314 counter: u64,
315}
316
317impl LoadKeyGenerator {
318 fn new() -> LoadKeyGenerator {
319 LoadKeyGenerator { counter: 0 }
320 }
321 fn next(&mut self) -> PendingImageId {
322 self.counter += 1;
323 PendingImageId(self.counter)
324 }
325}
326
327#[derive(Debug)]
328enum LoadResult {
329 LoadedRasterImage(RasterImage),
330 LoadedVectorImage(VectorImageData),
331 PlaceholderLoaded(Arc<RasterImage>),
332 None,
333}
334
335#[derive(MallocSizeOf)]
338struct PendingLoad {
339 bytes: ImageBytes,
342
343 metadata: Option<ImageMetadata>,
345
346 result: Option<Result<(), NetworkError>>,
348
349 listeners: Vec<ImageLoadListener>,
351
352 url: ServoUrl,
355
356 load_origin: ImmutableOrigin,
358
359 cors_setting: Option<CorsSettings>,
361
362 cors_status: CorsStatus,
364
365 final_url: Option<ServoUrl>,
367
368 content_type: Option<Mime>,
370}
371
372impl PendingLoad {
373 fn new(
374 url: ServoUrl,
375 load_origin: ImmutableOrigin,
376 cors_setting: Option<CorsSettings>,
377 ) -> PendingLoad {
378 PendingLoad {
379 bytes: ImageBytes::InProgress(vec![]),
380 metadata: None,
381 result: None,
382 listeners: vec![],
383 url,
384 load_origin,
385 final_url: None,
386 cors_setting,
387 cors_status: CorsStatus::Unsafe,
388 content_type: None,
389 }
390 }
391
392 fn add_listener(&mut self, listener: ImageLoadListener) {
393 self.listeners.push(listener);
394 }
395}
396
397#[derive(Default, MallocSizeOf)]
398struct RasterizationTask {
399 listeners: Vec<(PipelineId, IpcSender<ImageCacheResponseMessage>)>,
400 result: Option<RasterImage>,
401}
402
403#[derive(Debug, MallocSizeOf)]
405enum PendingKey {
406 RasterImage((LoadKey, RasterImage)),
407 Svg((LoadKey, RasterImage, DeviceIntSize)),
408}
409
410#[derive(Debug, MallocSizeOf)]
412enum KeyCacheState {
413 PendingBatch,
415 Ready(Vec<WebRenderImageKey>),
417}
418
419impl KeyCacheState {
420 fn size(&self) -> usize {
421 match self {
422 KeyCacheState::PendingBatch => 0,
423 KeyCacheState::Ready(items) => items.len(),
424 }
425 }
426}
427
428#[derive(MallocSizeOf)]
432struct KeyCache {
433 cache: KeyCacheState,
435 images_pending_keys: VecDeque<PendingKey>,
437}
438
439impl KeyCache {
440 fn new() -> Self {
441 KeyCache {
442 cache: KeyCacheState::Ready(Vec::new()),
443 images_pending_keys: VecDeque::new(),
444 }
445 }
446}
447
448#[derive(MallocSizeOf)]
450struct ImageCacheStore {
451 pending_loads: AllPendingLoads,
453
454 completed_loads: HashMap<ImageKey, CompletedLoad>,
456
457 vector_images: FxHashMap<PendingImageId, VectorImageData>,
461
462 rasterized_vector_images: FxHashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
466
467 #[conditional_malloc_size_of]
469 placeholder_image: Arc<RasterImage>,
470
471 placeholder_url: ServoUrl,
473
474 #[ignore_malloc_size_of = "Channel from another crate"]
476 compositor_api: CrossProcessCompositorApi,
477
478 pipeline_id: Option<PipelineId>,
481
482 key_cache: KeyCache,
485}
486
487impl ImageCacheStore {
488 fn set_key_and_finish_load(&mut self, pending_image: PendingKey, image_key: WebRenderImageKey) {
490 match pending_image {
491 PendingKey::RasterImage((pending_id, mut raster_image)) => {
492 set_webrender_image_key(&self.compositor_api, &mut raster_image, image_key);
493 self.complete_load(pending_id, LoadResult::LoadedRasterImage(raster_image));
494 },
495 PendingKey::Svg((pending_id, mut raster_image, requested_size)) => {
496 set_webrender_image_key(&self.compositor_api, &mut raster_image, image_key);
497 self.complete_load_svg(raster_image, pending_id, requested_size);
498 },
499 }
500 }
501
502 fn load_image_with_keycache(&mut self, pending_image: PendingKey) {
505 if let Some(pipeline_id) = self.pipeline_id {
506 match self.key_cache.cache {
507 KeyCacheState::PendingBatch => {
508 self.key_cache.images_pending_keys.push_back(pending_image);
509 },
510 KeyCacheState::Ready(ref mut cache) => match cache.pop() {
511 Some(image_key) => {
512 self.set_key_and_finish_load(pending_image, image_key);
513 },
514 None => {
515 self.key_cache.images_pending_keys.push_back(pending_image);
516 self.compositor_api.generate_image_key_async(pipeline_id);
517 self.key_cache.cache = KeyCacheState::PendingBatch
518 },
519 },
520 }
521 } else {
522 error!("No pipeline id for this image key cache.");
523 }
524 }
525
526 fn insert_keys_and_load_images(&mut self, image_keys: Vec<WebRenderImageKey>) {
528 if let KeyCacheState::PendingBatch = self.key_cache.cache {
529 self.key_cache.cache = KeyCacheState::Ready(image_keys);
530 let len = min(
531 self.key_cache.cache.size(),
532 self.key_cache.images_pending_keys.len(),
533 );
534 let images = self
535 .key_cache
536 .images_pending_keys
537 .drain(0..len)
538 .collect::<Vec<PendingKey>>();
539 for key in images {
540 self.load_image_with_keycache(key);
541 }
542 if !self.key_cache.images_pending_keys.is_empty() {
543 self.compositor_api
544 .generate_image_key_async(self.pipeline_id.unwrap());
545 self.key_cache.cache = KeyCacheState::PendingBatch
546 }
547 } else {
548 unreachable!("A batch was received while we didn't request one")
549 }
550 }
551
552 fn complete_load_svg(
555 &mut self,
556 rasterized_image: RasterImage,
557 pending_image_id: PendingImageId,
558 requested_size: DeviceIntSize,
559 ) {
560 let listeners = {
561 self.rasterized_vector_images
562 .get_mut(&(pending_image_id, requested_size))
563 .map(|task| {
564 task.result = Some(rasterized_image);
565 std::mem::take(&mut task.listeners)
566 })
567 .unwrap_or_default()
568 };
569
570 for (pipeline_id, sender) in listeners {
571 let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
572 RasterizationCompleteResponse {
573 pipeline_id,
574 image_id: pending_image_id,
575 requested_size,
576 },
577 ));
578 }
579 }
580
581 fn complete_load(&mut self, key: LoadKey, load_result: LoadResult) {
583 debug!("Completed decoding for {:?}", load_result);
584 let pending_load = match self.pending_loads.remove(&key) {
585 Some(load) => load,
586 None => return,
587 };
588
589 let url = pending_load.final_url.clone();
590 let image_response = match load_result {
591 LoadResult::LoadedRasterImage(raster_image) => {
592 assert!(raster_image.id.is_some());
593 ImageResponse::Loaded(Image::Raster(Arc::new(raster_image)), url.unwrap())
594 },
595 LoadResult::LoadedVectorImage(vector_image) => {
596 self.vector_images.insert(key, vector_image.clone());
597 let natural_dimensions = vector_image.svg_tree.size().to_int_size();
598 let metadata = ImageMetadata {
599 width: natural_dimensions.width(),
600 height: natural_dimensions.height(),
601 };
602
603 let vector_image = VectorImage {
604 id: key,
605 metadata,
606 cors_status: vector_image.cors_status,
607 };
608 ImageResponse::Loaded(Image::Vector(vector_image), url.unwrap())
609 },
610 LoadResult::PlaceholderLoaded(image) => {
611 ImageResponse::PlaceholderLoaded(image, self.placeholder_url.clone())
612 },
613 LoadResult::None => ImageResponse::None,
614 };
615
616 let completed_load = CompletedLoad::new(image_response.clone(), key);
617 self.completed_loads.insert(
618 (
619 pending_load.url,
620 pending_load.load_origin,
621 pending_load.cors_setting,
622 ),
623 completed_load,
624 );
625
626 for listener in pending_load.listeners {
627 listener.respond(image_response.clone());
628 }
629 }
630
631 fn get_completed_image_if_available(
634 &self,
635 url: ServoUrl,
636 origin: ImmutableOrigin,
637 cors_setting: Option<CorsSettings>,
638 placeholder: UsePlaceholder,
639 ) -> Option<Result<(Image, ServoUrl), ()>> {
640 self.completed_loads
641 .get(&(url, origin, cors_setting))
642 .map(
643 |completed_load| match (&completed_load.image_response, placeholder) {
644 (ImageResponse::Loaded(image, url), _) => Ok((image.clone(), url.clone())),
645 (ImageResponse::PlaceholderLoaded(image, url), UsePlaceholder::Yes) => {
646 Ok((Image::Raster(image.clone()), url.clone()))
647 },
648 (ImageResponse::PlaceholderLoaded(_, _), UsePlaceholder::No) |
649 (ImageResponse::None, _) |
650 (ImageResponse::MetadataLoaded(_), _) => Err(()),
651 },
652 )
653 }
654
655 fn handle_decoder(&mut self, msg: DecoderMsg) {
658 let image = match msg.image {
659 None => LoadResult::None,
660 Some(DecodedImage::Raster(raster_image)) => {
661 self.load_image_with_keycache(PendingKey::RasterImage((msg.key, raster_image)));
662 return;
663 },
664 Some(DecodedImage::Vector(vector_image_data)) => {
665 LoadResult::LoadedVectorImage(vector_image_data)
666 },
667 };
668 self.complete_load(msg.key, image);
669 }
670}
671
672pub struct ImageCacheImpl {
673 store: Arc<Mutex<ImageCacheStore>>,
674
675 thread_pool: Arc<ThreadPool>,
677
678 fontdb: Arc<fontdb::Database>,
679}
680
681impl ImageCache for ImageCacheImpl {
682 fn new(compositor_api: CrossProcessCompositorApi, rippy_data: Vec<u8>) -> ImageCacheImpl {
683 debug!("New image cache");
684
685 let thread_count = thread::available_parallelism()
689 .map(|i| i.get())
690 .unwrap_or(pref!(threadpools_fallback_worker_num) as usize)
691 .min(pref!(threadpools_image_cache_workers_max).max(1) as usize);
692
693 let mut fontdb = fontdb::Database::new();
694 fontdb.load_system_fonts();
695
696 ImageCacheImpl {
697 store: Arc::new(Mutex::new(ImageCacheStore {
698 pending_loads: AllPendingLoads::new(),
699 completed_loads: HashMap::new(),
700 vector_images: FxHashMap::default(),
701 rasterized_vector_images: FxHashMap::default(),
702 placeholder_image: get_placeholder_image(&compositor_api, &rippy_data),
703 placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
704 compositor_api: compositor_api.clone(),
705 pipeline_id: None,
706 key_cache: KeyCache::new(),
707 })),
708 thread_pool: Arc::new(ThreadPool::new(thread_count, "ImageCache".to_string())),
709 fontdb: Arc::new(fontdb),
710 }
711 }
712
713 fn memory_report(&self, prefix: &str, ops: &mut MallocSizeOfOps) -> Report {
714 let size = self.store.lock().unwrap().size_of(ops);
715 Report {
716 path: path![prefix, "image-cache"],
717 kind: ReportKind::ExplicitSystemHeapSize,
718 size,
719 }
720 }
721
722 fn get_image(
723 &self,
724 url: ServoUrl,
725 origin: ImmutableOrigin,
726 cors_setting: Option<CorsSettings>,
727 ) -> Option<Image> {
728 let store = self.store.lock().unwrap();
729 let result =
730 store.get_completed_image_if_available(url, origin, cors_setting, UsePlaceholder::No);
731 match result {
732 Some(Ok((img, _))) => Some(img),
733 _ => None,
734 }
735 }
736
737 fn get_cached_image_status(
738 &self,
739 url: ServoUrl,
740 origin: ImmutableOrigin,
741 cors_setting: Option<CorsSettings>,
742 use_placeholder: UsePlaceholder,
743 ) -> ImageCacheResult {
744 let mut store = self.store.lock().unwrap();
745 if let Some(result) = store.get_completed_image_if_available(
746 url.clone(),
747 origin.clone(),
748 cors_setting,
749 use_placeholder,
750 ) {
751 match result {
752 Ok((image, image_url)) => {
753 debug!("{} is available", url);
754 let is_placeholder = image_url == store.placeholder_url;
755 return ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
756 image,
757 url: image_url,
758 is_placeholder,
759 });
760 },
761 Err(()) => {
762 debug!("{} is not available", url);
763 return ImageCacheResult::LoadError;
764 },
765 }
766 }
767
768 let (key, decoded) = {
769 let result = store
770 .pending_loads
771 .get_cached(url.clone(), origin.clone(), cors_setting);
772 match result {
773 CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
774 (&Some(Ok(_)), _) => {
775 debug!("Sync decoding {} ({:?})", url, key);
776 (
777 key,
778 decode_bytes_sync(
779 key,
780 pl.bytes.as_slice(),
781 pl.cors_status,
782 pl.content_type.clone(),
783 self.fontdb.clone(),
784 ),
785 )
786 },
787 (&None, Some(meta)) => {
788 debug!("Metadata available for {} ({:?})", url, key);
789 return ImageCacheResult::Available(
790 ImageOrMetadataAvailable::MetadataAvailable(*meta, key),
791 );
792 },
793 (&Some(Err(_)), _) | (&None, &None) => {
794 debug!("{} ({:?}) is still pending", url, key);
795 return ImageCacheResult::Pending(key);
796 },
797 },
798 CacheResult::Miss(Some((key, _pl))) => {
799 debug!("Should be requesting {} ({:?})", url, key);
800 return ImageCacheResult::ReadyForRequest(key);
801 },
802 CacheResult::Miss(None) => {
803 debug!("Couldn't find an entry for {}", url);
804 return ImageCacheResult::LoadError;
805 },
806 }
807 };
808
809 store.handle_decoder(decoded);
814 match store.get_completed_image_if_available(url, origin, cors_setting, use_placeholder) {
815 Some(Ok((image, image_url))) => {
816 let is_placeholder = image_url == store.placeholder_url;
817 ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable {
818 image,
819 url: image_url,
820 is_placeholder,
821 })
822 },
823 _ => ImageCacheResult::Pending(key),
825 }
826 }
827
828 fn add_rasterization_complete_listener(
829 &self,
830 pipeline_id: PipelineId,
831 image_id: PendingImageId,
832 requested_size: DeviceIntSize,
833 sender: IpcSender<ImageCacheResponseMessage>,
834 ) {
835 let completed = {
836 let mut store = self.store.lock().unwrap();
837 let key = (image_id, requested_size);
838 if !store.vector_images.contains_key(&image_id) {
839 warn!("Unknown image requested for rasterization for key {key:?}");
840 return;
841 };
842
843 let Some(task) = store.rasterized_vector_images.get_mut(&key) else {
844 warn!("Image rasterization task not found in the cache for key {key:?}");
845 return;
846 };
847
848 match task.result {
849 Some(_) => true,
850 None => {
851 task.listeners.push((pipeline_id, sender.clone()));
852 false
853 },
854 }
855 };
856
857 if completed {
858 let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
859 RasterizationCompleteResponse {
860 pipeline_id,
861 image_id,
862 requested_size,
863 },
864 ));
865 }
866 }
867
868 fn rasterize_vector_image(
869 &self,
870 image_id: PendingImageId,
871 requested_size: DeviceIntSize,
872 ) -> Option<RasterImage> {
873 let mut store = self.store.lock().unwrap();
874 let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
875 warn!("Unknown image id {image_id:?} requested for rasterization");
876 return None;
877 };
878
879 let entry = store
883 .rasterized_vector_images
884 .entry((image_id, requested_size))
885 .or_default();
886 if let Some(result) = entry.result.as_ref() {
887 return Some(result.clone());
888 }
889
890 let store = self.store.clone();
891 self.thread_pool.spawn(move || {
892 let natural_size = vector_image.svg_tree.size().to_int_size();
893 let tinyskia_requested_size = {
894 let width = requested_size
895 .width
896 .try_into()
897 .unwrap_or(0)
898 .min(MAX_SVG_PIXMAP_DIMENSION);
899 let height = requested_size
900 .height
901 .try_into()
902 .unwrap_or(0)
903 .min(MAX_SVG_PIXMAP_DIMENSION);
904 tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
905 };
906 let transform = tiny_skia::Transform::from_scale(
907 tinyskia_requested_size.width() as f32 / natural_size.width() as f32,
908 tinyskia_requested_size.height() as f32 / natural_size.height() as f32,
909 );
910 let mut pixmap = tiny_skia::Pixmap::new(
911 tinyskia_requested_size.width(),
912 tinyskia_requested_size.height(),
913 )
914 .unwrap();
915 resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
916
917 let bytes = pixmap.take();
918 let frame = ImageFrame {
919 delay: None,
920 byte_range: 0..bytes.len(),
921 width: tinyskia_requested_size.width(),
922 height: tinyskia_requested_size.height(),
923 };
924
925 let rasterized_image = RasterImage {
926 metadata: ImageMetadata {
927 width: tinyskia_requested_size.width(),
928 height: tinyskia_requested_size.height(),
929 },
930 format: PixelFormat::RGBA8,
931 frames: vec![frame],
932 bytes: Arc::new(IpcSharedMemory::from_bytes(&bytes)),
933 id: None,
934 cors_status: vector_image.cors_status,
935 is_opaque: false,
936 };
937
938 let mut store = store.lock().unwrap();
939 store.load_image_with_keycache(PendingKey::Svg((
940 image_id,
941 rasterized_image,
942 requested_size,
943 )));
944 });
945
946 None
947 }
948
949 fn add_listener(&self, listener: ImageLoadListener) {
952 let mut store = self.store.lock().unwrap();
953 self.add_listener_with_store(&mut store, listener);
954 }
955
956 fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg) {
958 match (action, id) {
959 (FetchResponseMsg::ProcessRequestBody(..), _) |
960 (FetchResponseMsg::ProcessRequestEOF(..), _) |
961 (FetchResponseMsg::ProcessCspViolations(..), _) => (),
962 (FetchResponseMsg::ProcessResponse(_, response), _) => {
963 debug!("Received {:?} for {:?}", response.as_ref().map(|_| ()), id);
964 let mut store = self.store.lock().unwrap();
965 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
966 let (cors_status, metadata) = match response {
967 Ok(meta) => match meta {
968 FetchMetadata::Unfiltered(m) => (CorsStatus::Safe, Some(m)),
969 FetchMetadata::Filtered { unsafe_, filtered } => (
970 match filtered {
971 FilteredMetadata::Basic(_) | FilteredMetadata::Cors(_) => {
972 CorsStatus::Safe
973 },
974 FilteredMetadata::Opaque | FilteredMetadata::OpaqueRedirect(_) => {
975 CorsStatus::Unsafe
976 },
977 },
978 Some(unsafe_),
979 ),
980 },
981 Err(_) => (CorsStatus::Unsafe, None),
982 };
983 let final_url = metadata.as_ref().map(|m| m.final_url.clone());
984 pending_load.final_url = final_url;
985 pending_load.cors_status = cors_status;
986 pending_load.content_type = metadata
987 .as_ref()
988 .and_then(|metadata| metadata.content_type.clone())
989 .map(|content_type| content_type.into_inner().into());
990 },
991 (FetchResponseMsg::ProcessResponseChunk(_, data), _) => {
992 debug!("Got some data for {:?}", id);
993 let mut store = self.store.lock().unwrap();
994 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
995 pending_load.bytes.extend_from_slice(&data);
996
997 if pending_load.metadata.is_none() {
999 let mut reader = std::io::Cursor::new(pending_load.bytes.as_slice());
1000 if let Ok(info) = imsz_from_reader(&mut reader) {
1001 let img_metadata = ImageMetadata {
1002 width: info.width as u32,
1003 height: info.height as u32,
1004 };
1005 for listener in &pending_load.listeners {
1006 listener.respond(ImageResponse::MetadataLoaded(img_metadata));
1007 }
1008 pending_load.metadata = Some(img_metadata);
1009 }
1010 }
1011 },
1012 (FetchResponseMsg::ProcessResponseEOF(_, result), key) => {
1013 debug!("Received EOF for {:?}", key);
1014 match result {
1015 Ok(_) => {
1016 let (bytes, cors_status, content_type) = {
1017 let mut store = self.store.lock().unwrap();
1018 let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
1019 pending_load.result = Some(Ok(()));
1020 debug!("Async decoding {} ({:?})", pending_load.url, key);
1021 (
1022 pending_load.bytes.mark_complete(),
1023 pending_load.cors_status,
1024 pending_load.content_type.clone(),
1025 )
1026 };
1027
1028 let local_store = self.store.clone();
1029 let fontdb = self.fontdb.clone();
1030 self.thread_pool.spawn(move || {
1031 let msg =
1032 decode_bytes_sync(key, &bytes, cors_status, content_type, fontdb);
1033 debug!("Image decoded");
1034 local_store.lock().unwrap().handle_decoder(msg);
1035 });
1036 },
1037 Err(_) => {
1038 debug!("Processing error for {:?}", key);
1039 let mut store = self.store.lock().unwrap();
1040 let placeholder_image = store.placeholder_image.clone();
1041 store.complete_load(id, LoadResult::PlaceholderLoaded(placeholder_image))
1042 },
1043 }
1044 },
1045 }
1046 }
1047
1048 fn create_new_image_cache(
1049 &self,
1050 pipeline_id: Option<PipelineId>,
1051 compositor_api: CrossProcessCompositorApi,
1052 ) -> Arc<dyn ImageCache> {
1053 let store = self.store.lock().unwrap();
1054 let placeholder_image = store.placeholder_image.clone();
1055 let placeholder_url = store.placeholder_url.clone();
1056 Arc::new(ImageCacheImpl {
1057 store: Arc::new(Mutex::new(ImageCacheStore {
1058 pending_loads: AllPendingLoads::new(),
1059 completed_loads: HashMap::new(),
1060 placeholder_image,
1061 placeholder_url,
1062 compositor_api,
1063 vector_images: FxHashMap::default(),
1064 rasterized_vector_images: FxHashMap::default(),
1065 key_cache: KeyCache::new(),
1066 pipeline_id,
1067 })),
1068 thread_pool: self.thread_pool.clone(),
1069 fontdb: self.fontdb.clone(),
1070 })
1071 }
1072
1073 fn fill_key_cache_with_batch_of_keys(&self, image_keys: Vec<WebRenderImageKey>) {
1074 let mut store = self.store.lock().unwrap();
1075 store.insert_keys_and_load_images(image_keys);
1076 }
1077}
1078
1079impl Drop for ImageCacheStore {
1080 fn drop(&mut self) {
1081 let image_updates = self
1082 .completed_loads
1083 .values()
1084 .filter_map(|load| match &load.image_response {
1085 ImageResponse::Loaded(Image::Raster(image), _) => {
1086 image.id.map(ImageUpdate::DeleteImage)
1087 },
1088 _ => None,
1089 })
1090 .chain(
1091 self.rasterized_vector_images
1092 .values()
1093 .filter_map(|task| task.result.as_ref()?.id.map(ImageUpdate::DeleteImage)),
1094 )
1095 .collect();
1096 self.compositor_api.update_images(image_updates);
1097 }
1098}
1099
1100impl ImageCacheImpl {
1101 fn add_listener_with_store(&self, store: &mut ImageCacheStore, listener: ImageLoadListener) {
1103 let id = listener.id;
1104 if let Some(load) = store.pending_loads.get_by_key_mut(&id) {
1105 if let Some(ref metadata) = load.metadata {
1106 listener.respond(ImageResponse::MetadataLoaded(*metadata));
1107 }
1108 load.add_listener(listener);
1109 return;
1110 }
1111 if let Some(load) = store.completed_loads.values().find(|l| l.id == id) {
1112 listener.respond(load.image_response.clone());
1113 return;
1114 }
1115 warn!("Couldn't find cached entry for listener {:?}", id);
1116 }
1117}