11mod font_cache;
22mod to_path;
33
4+ use std:: {
5+ borrow:: Cow ,
6+ collections:: { HashMap , hash_map:: Entry } ,
7+ fmt,
8+ sync:: { Arc , Mutex } ,
9+ } ;
10+
411use dyn_any:: DynAny ;
512pub use font_cache:: * ;
13+ use graphene_core_shaders:: color:: Color ;
14+ use parley:: { Layout , StyleProperty } ;
15+ use rustc_hash:: FxBuildHasher ;
16+ use std:: hash:: BuildHasher ;
17+ use std:: hash:: { Hash , Hasher } ;
618pub use to_path:: * ;
719
20+ use crate :: { consts:: * , table:: Table , vector:: Vector } ;
21+
822/// Alignment of lines of type within a text block.
923#[ repr( C ) ]
1024#[ derive( Debug , Clone , Copy , Default , PartialEq , Eq , serde:: Serialize , serde:: Deserialize , Hash , DynAny , specta:: Type , node_macro:: ChoiceType ) ]
@@ -29,3 +43,139 @@ impl From<TextAlign> for parley::Alignment {
2943 }
3044 }
3145}
46+
47+ #[ derive( Clone , DynAny ) ]
48+ pub struct Typography {
49+ pub layout : Layout < ( ) > ,
50+ pub font_family : String ,
51+ pub color : Color ,
52+ pub stroke : Option < ( Color , f64 ) > ,
53+ }
54+
55+ impl fmt:: Debug for Typography {
56+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
57+ f. debug_struct ( "Typography" )
58+ . field ( "font_family" , & self . font_family )
59+ . field ( "color" , & self . color )
60+ . field ( "stroke" , & self . stroke )
61+ . finish ( )
62+ }
63+ }
64+
65+ impl PartialEq for Typography {
66+ fn eq ( & self , _other : & Self ) -> bool {
67+ true
68+ }
69+ }
70+
71+ impl Hash for Typography {
72+ fn hash < H : Hasher > ( & self , state : & mut H ) {
73+ self . layout . len ( ) . hash ( state) ;
74+ }
75+ }
76+
77+ impl Typography {
78+ pub fn to_vector ( & self ) -> Table < Vector > {
79+ // To implement this function, a clone of the `NewFontCacheWrapper` must be included in the typography data type
80+ Table :: new ( )
81+ }
82+ }
83+
84+ #[ derive( Clone ) ]
85+ pub struct NewFontCacheWrapper ( pub Arc < Mutex < NewFontCache > > ) ;
86+
87+ impl fmt:: Debug for NewFontCacheWrapper {
88+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
89+ f. debug_struct ( "font cache" ) . finish ( )
90+ }
91+ }
92+
93+ impl PartialEq for NewFontCacheWrapper {
94+ fn eq ( & self , _other : & Self ) -> bool {
95+ log:: error!( "Font cache should not be compared" ) ;
96+ false
97+ }
98+ }
99+
100+ unsafe impl dyn_any:: StaticType for NewFontCacheWrapper {
101+ type Static = NewFontCacheWrapper ;
102+ }
103+
104+ pub struct NewFontCache {
105+ pub font_context : parley:: FontContext ,
106+ pub layout_context : parley:: LayoutContext < ( ) > ,
107+ pub font_mapping : HashMap < Font , ( String , parley:: fontique:: FontInfo ) > ,
108+ pub hash : u64 ,
109+ }
110+
111+ impl NewFontCache {
112+ pub fn new ( ) -> Self {
113+ let mut new = NewFontCache {
114+ font_context : parley:: FontContext :: new ( ) ,
115+ layout_context : parley:: LayoutContext :: new ( ) ,
116+ font_mapping : HashMap :: new ( ) ,
117+ hash : 0 ,
118+ } ;
119+
120+ let source_sans_font = Font :: new ( SOURCE_SANS_FONT_FAMILY . to_string ( ) , SOURCE_SANS_FONT_STYLE . to_string ( ) ) ;
121+ new. register_font ( source_sans_font, SOURCE_SANS_FONT_DATA . to_vec ( ) ) ;
122+ new
123+ }
124+
125+ pub fn register_font ( & mut self , font : Font , data : Vec < u8 > ) {
126+ match self . font_mapping . entry ( font) {
127+ Entry :: Occupied ( occupied_entry) => {
128+ log:: error!( "Trying to register font that already is added: {:?}" , occupied_entry. key( ) ) ;
129+ }
130+ Entry :: Vacant ( vacant_entry) => {
131+ let registered_font = self . font_context . collection . register_fonts ( parley:: fontique:: Blob :: from ( data) , None ) ;
132+ if registered_font. len ( ) > 1 {
133+ log:: error!( "Registered multiple fonts for {:?}. Only the first is accessible" , vacant_entry. key( ) ) ;
134+ } ;
135+ match registered_font. into_iter ( ) . next ( ) {
136+ Some ( ( family_id, font_info) ) => {
137+ let Some ( family_name) = self . font_context . collection . family_name ( family_id) else {
138+ log:: error!( "Could not get family name for font: {:?}" , vacant_entry. key( ) ) ;
139+ return ;
140+ } ;
141+ let Some ( font_info) = font_info. into_iter ( ) . next ( ) else {
142+ log:: error!( "Could not get font info for font: {:?}" , vacant_entry. key( ) ) ;
143+ return ;
144+ } ;
145+ // Hash the Font for a unique id and add it to the cached hash
146+ let hash_value = FxBuildHasher . hash_one ( vacant_entry. key ( ) ) ;
147+ self . hash = self . hash . wrapping_add ( hash_value) ;
148+
149+ vacant_entry. insert ( ( family_name. to_string ( ) , font_info) ) ;
150+ }
151+ None => log:: error!( "Could not register font for {:?}" , vacant_entry. key( ) ) ,
152+ }
153+ }
154+ }
155+ }
156+
157+ pub fn generate_typography ( & mut self , font : & Font , font_size : f32 , text : & str ) -> Option < Typography > {
158+ let Some ( ( font_family, font_info) ) = self . font_mapping . get ( font) else {
159+ log:: error!( "Font not loaded: {:?}" , font) ;
160+ return None ;
161+ } ;
162+ let font_family = font_family. to_string ( ) ;
163+
164+ let mut builder = self . layout_context . ranged_builder ( & mut self . font_context , text, 1. , false ) ;
165+
166+ builder. push_default ( StyleProperty :: FontStack ( parley:: FontStack :: Single ( parley:: FontFamily :: Named ( Cow :: Owned ( font_family. clone ( ) ) ) ) ) ) ;
167+ builder. push_default ( StyleProperty :: FontSize ( font_size) ) ;
168+ builder. push_default ( StyleProperty :: FontWeight ( font_info. weight ( ) ) ) ;
169+ builder. push_default ( StyleProperty :: FontStyle ( font_info. style ( ) ) ) ;
170+ builder. push_default ( StyleProperty :: FontWidth ( font_info. width ( ) ) ) ;
171+
172+ let mut layout: Layout < ( ) > = builder. build ( text) ;
173+ layout. break_all_lines ( None ) ;
174+ Some ( Typography {
175+ layout,
176+ font_family,
177+ color : Color :: BLACK ,
178+ stroke : None ,
179+ } )
180+ }
181+ }
0 commit comments