@@ -7,18 +7,19 @@ use skia_safe::font_style::Slant;
77use skia_safe:: textlayout:: { FontCollection , TextStyle , TypefaceFontProvider } ;
88use skia_safe:: { FontArguments , FontMgr , Typeface } ;
99use std:: sync:: LazyLock ;
10+ use ustr:: Ustr ;
1011
1112#[ derive( PartialEq , Eq , Hash ) ]
1213struct CollectionKey {
13- families : String ,
14+ families : Vec < Ustr > ,
1415 weight : i32 ,
1516 slant : Slant ,
1617}
1718
1819impl CollectionKey {
1920 pub fn new ( style : & TextStyle ) -> Self {
2021 let families = style. font_families ( ) ;
21- let families = families. iter ( ) . collect :: < Vec < & str > > ( ) . join ( ", " ) ;
22+ let families: Vec < Ustr > = families. iter ( ) . map ( Ustr :: from ) . collect ( ) ;
2223 let weight = * style. font_style ( ) . weight ( ) ;
2324 let slant = style. font_style ( ) . slant ( ) ;
2425 CollectionKey {
@@ -33,17 +34,16 @@ impl CollectionKey {
3334// Font collection management
3435//
3536
36- pub static FONT_LIBRARY : LazyLock < Mutex < FontLibrary > > = LazyLock :: new ( || FontLibrary :: shared ( ) ) ;
37+ pub static FONT_LIBRARY : LazyLock < Mutex < FontLibrary > > = LazyLock :: new ( FontLibrary :: shared) ;
3738
3839pub struct FontLibrary {
3940 pub fonts : Vec < ( Typeface , Option < String > ) > ,
4041 pub collection : FontCollection ,
4142 collection_cache : HashMap < CollectionKey , FontCollection > ,
43+ font_mgr : FontMgr ,
4244}
4345
44- unsafe impl Send for FontLibrary {
45- // famous last words: this ‘should’ be safe in practice because the singleton is behind a mutex
46- }
46+ unsafe impl Send for FontLibrary { }
4747
4848pub enum CanvasFontWeight {
4949 Thin ,
@@ -82,14 +82,14 @@ pub struct FontDescriptors {
8282
8383impl FontLibrary {
8484 pub fn shared ( ) -> Mutex < Self > {
85- let fonts = vec ! [ ] ;
86- let collection_cache = HashMap :: new ( ) ;
85+ let font_mgr = FontMgr :: new ( ) ;
8786 let mut collection = FontCollection :: new ( ) ;
88- collection. set_default_font_manager ( FontMgr :: new ( ) , None ) ;
87+ collection. set_default_font_manager ( font_mgr . clone ( ) , None ) ;
8988 Mutex :: new ( FontLibrary {
9089 collection,
91- collection_cache,
92- fonts,
90+ collection_cache : HashMap :: new ( ) ,
91+ fonts : vec ! [ ] ,
92+ font_mgr,
9393 } )
9494 }
9595
@@ -100,36 +100,39 @@ impl FontLibrary {
100100 }
101101
102102 let mut collection = FontCollection :: new ( ) ;
103- collection. set_default_font_manager ( FontMgr :: new ( ) , None ) ;
103+ collection. set_default_font_manager ( self . font_mgr . clone ( ) , None ) ;
104104 collection. set_asset_font_manager ( Some ( assets. into ( ) ) ) ;
105105 self . collection = collection;
106- self . collection_cache . drain ( ) ;
106+ self . collection_cache . clear ( ) ;
107107 }
108108
109- fn add_typeface ( & mut self , font : Typeface , alias : Option < String > ) {
109+ /// Inserts or replaces a typeface **without** rebuilding the collection.
110+ /// Callers must call `register_fonts()` when all additions are done.
111+ fn add_typeface_no_rebuild ( & mut self , font : Typeface , alias : Option < String > ) {
110112 if let Some ( idx) = self . fonts . iter ( ) . position ( |( old_font, old_alias) |
111113 match alias. is_some ( ) {
112114 true => old_alias. as_deref ( ) == alias. as_deref ( ) ,
113115 false => old_font. family_name ( ) == font. family_name ( )
114116 } && old_font. font_style ( ) == font. font_style ( )
115117 ) {
116- self . fonts . remove ( idx) ;
118+ self . fonts [ idx] = ( font, alias) ;
119+ } else {
120+ self . fonts . push ( ( font, alias) ) ;
117121 }
122+ }
118123
119- self . fonts . push ( ( font, alias) ) ;
124+ fn add_typeface ( & mut self , font : Typeface , alias : Option < String > ) {
125+ self . add_typeface_no_rebuild ( font, alias) ;
120126 self . register_fonts ( ) ;
121127 }
122128
123129 fn remove_typeface ( & mut self , font : & Typeface , alias : Option < & str > ) {
124- if let Some ( idx ) = self . fonts . iter ( ) . position ( |( old_font, old_alias) |
125- match alias. is_some ( ) {
130+ self . fonts . retain ( |( old_font, old_alias) | {
131+ ! ( match alias. is_some ( ) {
126132 true => old_alias. as_deref ( ) == alias,
127133 false => old_font. family_name ( ) == font. family_name ( )
128- } && old_font. font_style ( ) == font. font_style ( )
129- ) {
130- self . fonts . remove ( idx) ;
131- }
132-
134+ } && old_font. font_style ( ) == font. font_style ( ) )
135+ } ) ;
133136 self . register_fonts ( ) ;
134137 }
135138
@@ -140,18 +143,14 @@ impl FontLibrary {
140143 . collection
141144 . find_typefaces ( & families, style. font_style ( ) ) ;
142145
143- // if the matched typeface is a variable font, create an instance that matches
144- // the current weight settings and return early with a new FontCollection that
145- // contains just that single font instance
146+
146147 if let Some ( font) = matches. first ( ) {
147148 if let Some ( params) = font. variation_design_parameters ( ) {
148- // memoize the generation of single-weight FontCollections for variable fonts
149149 let key = CollectionKey :: new ( style) ;
150150 if let Some ( collection) = self . collection_cache . get ( & key) {
151151 return collection. clone ( ) ;
152152 }
153153
154- // reconnect to the user-specified family name (if provided)
155154 let alias = self . fonts . iter ( ) . find_map ( |( face, alias) | {
156155 if Typeface :: equal ( font, face) {
157156 alias. clone ( )
@@ -164,11 +163,6 @@ impl FontLibrary {
164163 let chars = vec ! [ param. tag. a( ) , param. tag. b( ) , param. tag. c( ) , param. tag. d( ) ] ;
165164 let tag = String :: from_utf8 ( chars) . unwrap ( ) ;
166165 if tag == "wght" {
167- // NB: currently setting the value to *one less* than what was requested
168- // to work around weird Skia behavior that returns something nonlinearly
169- // weighted in many cases (but not for ±1 of that value). This makes it so
170- // that n × 100 values will render correctly (and the bug will manifest at
171- // n × 100 + 1 instead)
172166 let weight = * style. font_style ( ) . weight ( ) - 1 ;
173167 let value = ( weight as f32 ) . max ( param. min ) . min ( param. max ) ;
174168 let coords = [ Coordinate {
@@ -185,7 +179,7 @@ impl FontLibrary {
185179 dynamic. register_typeface ( face, alias. as_deref ( ) ) ;
186180
187181 let mut collection = FontCollection :: new ( ) ;
188- collection. set_default_font_manager ( FontMgr :: new ( ) , None ) ;
182+ collection. set_default_font_manager ( self . font_mgr . clone ( ) , None ) ;
189183 collection. set_asset_font_manager ( Some ( dynamic. into ( ) ) ) ;
190184 self . collection_cache . insert ( key, collection. clone ( ) ) ;
191185 return collection;
@@ -194,46 +188,50 @@ impl FontLibrary {
194188 }
195189 }
196190
197- // if the matched font wasn't variable, then just return the standard collection
198191 self . collection . clone ( )
199192 }
200193
201194 pub fn add_family ( alias : Option < & str > , filenames : & [ & str ] ) -> Result < ( ) , String > {
195+ let decode_mgr = FontMgr :: new ( ) ;
196+ let mut typefaces = Vec :: with_capacity ( filenames. len ( ) ) ;
202197 for filename in filenames. iter ( ) {
203- let path = std:: path:: Path :: new ( & filename) ;
204- let typeface = match std:: fs:: read ( path) {
198+ let path = std:: path:: Path :: new ( filename) ;
199+ let bytes = match std:: fs:: read ( path) {
205200 Err ( why) => return Err ( format ! ( "{}: \" {}\" " , why, path. display( ) ) ) ,
206- Ok ( bytes ) => FontMgr :: new ( ) . new_from_data ( bytes . as_slice ( ) , None ) ,
201+ Ok ( b ) => b ,
207202 } ;
208-
209- match typeface {
210- Some ( font) => {
211- // register the typeface
212- let mut library = FONT_LIBRARY . lock ( ) ;
213- let alias = alias. map ( |v| v. to_owned ( ) ) ;
214- library. add_typeface ( font, alias) ;
215- }
203+ match decode_mgr. new_from_data ( bytes. as_slice ( ) , None ) {
204+ Some ( font) => typefaces. push ( font) ,
216205 None => return Err ( format ! ( "Could not decode font data in {}" , path. display( ) ) ) ,
217206 }
218207 }
208+ let mut library = FONT_LIBRARY . lock ( ) ;
209+ let alias_owned = alias. map ( |v| v. to_owned ( ) ) ;
210+ for font in typefaces {
211+ library. add_typeface_no_rebuild ( font, alias_owned. clone ( ) ) ;
212+ }
213+ library. register_fonts ( ) ;
219214
220215 Ok ( ( ) )
221216 }
222217
223218 pub fn add_family_bytes ( alias : Option < & str > , data : & [ & [ u8 ] ] ) -> Result < ( ) , String > {
224- let mgr = FontMgr :: new ( ) ;
219+ let decode_mgr = FontMgr :: new ( ) ;
220+ let mut typefaces = Vec :: with_capacity ( data. len ( ) ) ;
225221 for bytes in data. iter ( ) {
226- match mgr. new_from_data ( bytes, None ) {
227- Some ( font) => {
228- // register the typeface
229- let mut library = FONT_LIBRARY . lock ( ) ;
230- let alias = alias. map ( |v| v. to_owned ( ) ) ;
231- library. add_typeface ( font, alias) ;
232- }
222+ match decode_mgr. new_from_data ( bytes, None ) {
223+ Some ( font) => typefaces. push ( font) ,
233224 None => return Err ( "Could not decode font data" . to_string ( ) ) ,
234225 }
235226 }
236227
228+ let mut library = FONT_LIBRARY . lock ( ) ;
229+ let alias_owned = alias. map ( |v| v. to_owned ( ) ) ;
230+ for font in typefaces {
231+ library. add_typeface_no_rebuild ( font, alias_owned. clone ( ) ) ;
232+ }
233+ library. register_fonts ( ) ;
234+
237235 Ok ( ( ) )
238236 }
239237
@@ -242,8 +240,8 @@ impl FontLibrary {
242240 library. fonts . clear ( ) ;
243241
244242 let mut collection = FontCollection :: new ( ) ;
245- collection. set_default_font_manager ( FontMgr :: new ( ) , None ) ;
243+ collection. set_default_font_manager ( library . font_mgr . clone ( ) , None ) ;
246244 library. collection = collection;
247- library. collection_cache . drain ( ) ;
245+ library. collection_cache . clear ( ) ;
248246 }
249247}
0 commit comments