@@ -111,21 +111,51 @@ pub struct TextRasterizer {
111111 swash_cache : RefCell < SwashCache > ,
112112}
113113
114- /// Ajoute `files` (`crate::text_fonts`) a la base `fontdb` de ce rasteriseur, sans rien
115- /// installer sur la machine. Un fichier illisible ne coute que sa police : le texte retombe
116- /// sur celles du systeme.
117- fn load_fonts ( font_system : & mut FontSystem , files : & [ std:: path:: PathBuf ] ) {
114+ /// Ajoute `files` (`crate::text_fonts`) a `db`, sans rien installer sur la machine, et
115+ /// retire de `db` toute autre face qui porte le nom d'une famille embarquee.
116+ ///
117+ /// Le retrait est ce qui fait gagner nos fichiers. Une police installee du meme nom (Inter
118+ /// est courante sous Linux) passait devant la notre : `fontdb` ne documente aucune priorite
119+ /// entre deux faces egales, et en pratique la premiere chargee, celle du systeme, l'emportait.
120+ /// Le rendu dependait alors a nouveau de la machine. Sans face concurrente, il n'y a plus
121+ /// d'ordre dont dependre. Les autres familles du systeme restent, pour le repli des
122+ /// ecritures que nos polices ne couvrent pas.
123+ ///
124+ /// Un fichier illisible ne coute que sa police : sa famille retombe sur celles du systeme.
125+ fn with_embedded_fonts (
126+ mut db : cosmic_text:: fontdb:: Database ,
127+ files : & [ std:: path:: PathBuf ] ,
128+ ) -> cosmic_text:: fontdb:: Database {
129+ let before: std:: collections:: HashSet < _ > = db. faces ( ) . map ( |f| f. id ) . collect ( ) ;
118130 for path in files {
119- if let Err ( e) = font_system . db_mut ( ) . load_font_file ( path) {
131+ if let Err ( e) = db . load_font_file ( path) {
120132 eprintln ! ( "[text] police non chargee ({e}) : {}" , path. display( ) ) ;
121133 }
122134 }
135+ let shipped: std:: collections:: HashSet < String > = db
136+ . faces ( )
137+ . filter ( |f| !before. contains ( & f. id ) )
138+ . flat_map ( |f| f. families . iter ( ) . map ( |( name, _) | name. to_lowercase ( ) ) )
139+ . collect ( ) ;
140+ let shadowed: Vec < _ > = db
141+ . faces ( )
142+ . filter ( |f| before. contains ( & f. id ) )
143+ . filter ( |f| f. families . iter ( ) . any ( |( name, _) | shipped. contains ( & name. to_lowercase ( ) ) ) )
144+ . map ( |f| f. id )
145+ . collect ( ) ;
146+ for id in shadowed {
147+ db. remove_face ( id) ;
148+ }
149+ db
123150}
124151
125152impl TextRasterizer {
126153 pub fn new ( ) -> Result < TextRasterizer > {
127- let mut font_system = FontSystem :: new ( ) ;
128- load_fonts ( & mut font_system, & crate :: text_fonts:: embedded_font_files ( ) ) ;
154+ // Reconstruit le `FontSystem` sur la base modifiee, plutot que de la retoucher en
155+ // place : il indexe ses faces (monospace, repli) a la construction.
156+ let ( locale, db) = FontSystem :: new ( ) . into_locale_and_db ( ) ;
157+ let db = with_embedded_fonts ( db, & crate :: text_fonts:: embedded_font_files ( ) ) ;
158+ let font_system = FontSystem :: new_with_locale_and_db ( locale, db) ;
129159 Ok ( TextRasterizer {
130160 font_system : RefCell :: new ( font_system) ,
131161 swash_cache : RefCell :: new ( SwashCache :: new ( ) ) ,
@@ -453,10 +483,29 @@ mod tests {
453483 /// qu'un controle peut produire, et deux familles ne se confondent jamais a l'ecran.
454484 #[ test]
455485 fn every_shipped_family_draws_from_its_own_files ( ) {
456- use cosmic_text:: fontdb:: { Family , Query , Stretch , Style , Weight } ;
457- let mut font_system = FontSystem :: new ( ) ;
458- let files = crate :: text_fonts:: font_files_in ( & crate :: text_fonts:: repo_fonts_dir ( ) ) ;
459- load_fonts ( & mut font_system, & files) ;
486+ use cosmic_text:: fontdb:: { Database , Family , Query , Source , Stretch , Style , Weight } ;
487+ let repo = crate :: text_fonts:: repo_fonts_dir ( ) ;
488+ let files = crate :: text_fonts:: font_files_in ( & repo) ;
489+
490+ // La collision : une police « installee » qui porte EXACTEMENT les memes familles,
491+ // graisses et styles, chargee AVANT les notres comme `FontSystem::new` le fait des
492+ // polices du systeme. Ce sont nos fichiers, copies ailleurs : seul le chemin distingue
493+ // le gagnant.
494+ let system =
495+ std:: env:: temp_dir ( ) . join ( format ! ( "openscreen-sysfonts-{}" , std:: process:: id( ) ) ) ;
496+ std:: fs:: create_dir_all ( & system) . unwrap ( ) ;
497+ let mut db = Database :: new ( ) ;
498+ db. load_system_fonts ( ) ;
499+ for file in & files {
500+ let copy = system. join ( file. file_name ( ) . unwrap ( ) ) ;
501+ std:: fs:: copy ( file, & copy) . unwrap ( ) ;
502+ db. load_font_file ( & copy) . unwrap ( ) ;
503+ }
504+ let db = with_embedded_fonts ( db, & files) ;
505+ let font_system = FontSystem :: new_with_locale_and_db ( "en-US" . into ( ) , db) ;
506+ std:: fs:: remove_dir_all ( & system) . ok ( ) ;
507+
508+ let repo = std:: fs:: canonicalize ( & repo) . unwrap ( ) ;
460509 for family in crate :: text_fonts:: SHIPPED_FAMILIES {
461510 for weight in [ Weight :: NORMAL , Weight :: BOLD ] {
462511 let query = Query {
@@ -469,8 +518,17 @@ mod tests {
469518 . db ( )
470519 . query ( & query)
471520 . unwrap_or_else ( || panic ! ( "{family} introuvable" ) ) ;
521+ let face = font_system. db ( ) . face ( id) . unwrap ( ) ;
472522 // Un vrai fichier de cette graisse, pas le regulier epaissi ou non.
473- assert_eq ! ( font_system. db( ) . face( id) . unwrap( ) . weight, weight, "{family}" ) ;
523+ assert_eq ! ( face. weight, weight, "{family}" ) ;
524+ // Et c'est NOTRE fichier, pas la face du systeme qui porte le meme nom.
525+ let path = match & face. source {
526+ Source :: File ( p) | Source :: SharedFile ( p, _) => p. clone ( ) ,
527+ Source :: Binary ( _) => panic ! ( "{family} : face sans fichier" ) ,
528+ } ;
529+ let path = std:: fs:: canonicalize ( & path) . unwrap_or ( path) ;
530+ let from = path. display ( ) ;
531+ assert ! ( path. starts_with( & repo) , "{family} {weight:?} tire de {from}" ) ;
474532 }
475533 }
476534
0 commit comments