@@ -10,7 +10,7 @@ use crate::object_tree::*;
1010use image:: GenericImageView ;
1111use smol_str:: SmolStr ;
1212use std:: cell:: RefCell ;
13- use std:: collections:: HashMap ;
13+ use std:: collections:: { HashMap , HashSet } ;
1414use std:: future:: Future ;
1515use std:: pin:: Pin ;
1616use std:: rc:: Rc ;
@@ -20,31 +20,54 @@ use typed_index_collections::TiVec;
2020pub trait ResourcePreloader {
2121 fn load < ' a > (
2222 & self ,
23- urls : impl Iterator < Item = & ' a str > ,
24- push : impl FnMut ( /* url */ & ' a str , /* extension */ String , /* data */ Arc < [ u8 ] > ) ,
23+ paths : impl Iterator < Item = & ' a str > ,
24+ push : Rc < impl Fn ( /* path */ & ' a str , /* extension */ String , /* data */ Arc < [ u8 ] > ) > ,
2525 ) -> impl Future < Output = ( ) > ;
2626}
2727
2828impl ResourcePreloader for ( ) {
2929 fn load < ' a > (
3030 & self ,
31- _urls : impl Iterator < Item = & ' a str > ,
32- _push : impl FnMut (
33- /* url */ & ' a str ,
34- /* extension */ String ,
35- /* data */ Arc < [ u8 ] > ,
36- ) ,
31+ _paths : impl Iterator < Item = & ' a str > ,
32+ _push : Rc < impl Fn ( & ' a str , String , Arc < [ u8 ] > ) > ,
3733 ) -> impl Future < Output = ( ) > {
3834 std:: future:: ready ( ( ) )
3935 }
4036}
4137
38+ pub async fn preload_images ( doc : & Document , resource_preloader : impl ResourcePreloader ) {
39+ let mut all_components = Vec :: new ( ) ;
40+ doc. visit_all_used_components ( |c| all_components. push ( c. clone ( ) ) ) ;
41+
42+ let mut urls = HashSet :: < SmolStr > :: new ( ) ;
43+ for component in & all_components {
44+ visit_all_expressions ( component, |e, _| {
45+ foreach_image_url_from_expression ( e, & mut |path| {
46+ urls. insert ( path. clone ( ) ) ;
47+ } )
48+ } ) ;
49+ }
50+
51+ let global_embedded_resources = & doc. embedded_file_resources ;
52+ resource_preloader
53+ . load (
54+ urls. iter ( ) . map ( SmolStr :: as_str) ,
55+ Rc :: new ( |url : & str , extension, data : Arc < [ u8 ] > | {
56+ let mut resources = global_embedded_resources. borrow_mut ( ) ;
57+ resources. push ( EmbeddedResources {
58+ path : Some ( url. into ( ) ) ,
59+ kind : EmbeddedResourcesKind :: DataUriPayload ( data. to_vec ( ) , extension) ,
60+ } ) ;
61+ } ) ,
62+ )
63+ . await ;
64+ }
65+
4266pub async fn embed_images (
4367 doc : & Document ,
4468 embed_files : EmbedResourcesKind ,
4569 scale_factor : f32 ,
4670 resource_url_mapper : & Option < Rc < dyn Fn ( & str ) -> Pin < Box < dyn Future < Output = Option < String > > > > > > ,
47- resource_preloader : impl ResourcePreloader ,
4871 diag : & mut BuildDiagnostics ,
4972) {
5073 if embed_files == EmbedResourcesKind :: Nothing && resource_url_mapper. is_none ( ) {
@@ -53,6 +76,11 @@ pub async fn embed_images(
5376
5477 let global_embedded_resources = & doc. embedded_file_resources ;
5578 let mut path_to_id = HashMap :: < SmolStr , EmbeddedResourcesIdx > :: new ( ) ;
79+ for ( id, resource) in global_embedded_resources. borrow ( ) . iter_enumerated ( ) {
80+ if let Some ( path) = & resource. path {
81+ path_to_id. insert ( path. clone ( ) , id) ;
82+ }
83+ }
5684
5785 let mut all_components = Vec :: new ( ) ;
5886 doc. visit_all_used_components ( |c| all_components. push ( c. clone ( ) ) ) ;
@@ -65,7 +93,9 @@ pub async fn embed_images(
6593 // Collect URLs (sync!):
6694 for component in & all_components {
6795 visit_all_expressions ( component, |e, _| {
68- collect_image_urls_from_expression ( e, & mut urls)
96+ foreach_image_url_from_expression ( e, & mut |path| {
97+ urls. insert ( path. clone ( ) , None ) ;
98+ } )
6999 } ) ;
70100 }
71101
@@ -78,20 +108,6 @@ pub async fn embed_images(
78108 urls
79109 } ;
80110
81- resource_preloader
82- . load (
83- mapped_urls. values ( ) . filter_map ( |url| url. as_ref ( ) . map ( SmolStr :: as_str) ) ,
84- |url : & str , extension, data| {
85- let mut resources = global_embedded_resources. borrow_mut ( ) ;
86- let id = resources. push_and_get_key ( EmbeddedResources {
87- path : Some ( url. into ( ) ) ,
88- kind : EmbeddedResourcesKind :: DataUriPayload ( data. to_vec ( ) , extension) ,
89- } ) ;
90- path_to_id. insert ( url. into ( ) , id) ;
91- } ,
92- )
93- . await ;
94-
95111 // Use URLs (sync!):
96112 for component in & all_components {
97113 visit_all_expressions ( component, |e, _| {
@@ -108,17 +124,14 @@ pub async fn embed_images(
108124 }
109125}
110126
111- fn collect_image_urls_from_expression (
112- e : & Expression ,
113- urls : & mut HashMap < SmolStr , Option < SmolStr > > ,
114- ) {
127+ fn foreach_image_url_from_expression ( e : & Expression , f : & mut impl FnMut ( & SmolStr ) ) {
115128 if let Expression :: ImageReference { resource_ref, .. } = e
116129 && let ImageReference :: AbsolutePath ( path) = resource_ref
117130 {
118- urls . insert ( path. clone ( ) , None ) ;
131+ f ( path) ;
119132 } ;
120133
121- e. visit ( |e| collect_image_urls_from_expression ( e, urls ) ) ;
134+ e. visit ( |e| foreach_image_url_from_expression ( e, f ) ) ;
122135}
123136
124137fn embed_images_from_expression (
@@ -133,6 +146,10 @@ fn embed_images_from_expression(
133146 if let Expression :: ImageReference { resource_ref, source_location, nine_slice : _ } = e
134147 && let ImageReference :: AbsolutePath ( path) = resource_ref
135148 {
149+ if path_to_id. contains_key ( path) {
150+ return ;
151+ }
152+
136153 if path. starts_with ( "data:" ) {
137154 let image_ref = embed_data_uri (
138155 global_embedded_resources,
0 commit comments