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