The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

FallbackFont.vala in libbirdfont/Renderer

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/Renderer/FallbackFont.vala.
Disable font config
1 /* 2 Copyright (C) 2015 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Gee; 16 17 [SimpleType] 18 [CCode (has_type_id = false)] 19 extern struct FcConfig { 20 } 21 22 [CCode (cname = "FcInitLoadConfigAndFonts")] 23 extern FcConfig* FcInitLoadConfigAndFonts (); 24 25 [CCode (cname = "find_font")] 26 extern string? find_font (FcConfig* font_config, string characters); 27 28 [CCode (cname = "find_font_file")] 29 extern string? find_font_file (FcConfig* font_config, string font_name); 30 31 namespace BirdFont { 32 33 // TODO: use font config 34 public class FallbackFont : GLib.Object { 35 Gee.ArrayList<File> font_directories; 36 37 FontFace* default_font = null; 38 static FcConfig* font_config = null; 39 static bool font_config_stated = false; 40 41 string default_font_file_name = "Roboto-Regular.ttf"; 42 string default_font_family_name = "Roboto"; 43 44 Gee.HashMap<unichar, CachePair> glyphs; 45 Gee.ArrayList<CachePair> cached; 46 47 public int max_cached_fonts = 300; 48 49 public FallbackFont () { 50 string home = Environment.get_home_dir (); 51 font_directories = new Gee.ArrayList<File> (); 52 53 if (!font_config_stated && ! BirdFont.has_argument ("--no-fontconfig")) { 54 font_config_stated = true; 55 56 IdleSource idle = new IdleSource (); 57 idle.set_callback (() => { 58 Task t = new Task (init_font_config); 59 MainWindow.native_window.run_non_blocking_background_thread (t); 60 return false; 61 }); 62 idle.attach (null); 63 } 64 65 add_font_folder ("/usr/share/fonts/"); 66 add_font_folder ("/usr/local/share/fonts/"); 67 add_font_folder (home + "/.local/share/fonts"); 68 add_font_folder (home + "/.fonts"); 69 add_font_folder ("C:\\Windows\\Fonts"); 70 add_font_folder (home + "/Library/Fonts"); 71 add_font_folder ("/Library/Fonts"); 72 add_font_folder ("/Network/Library/Fonts"); 73 add_font_folder ("/System/Library/Fonts"); 74 add_font_folder ("/System Folder/Fonts"); 75 76 glyphs = new Gee.HashMap<unichar, CachePair> (); 77 cached = new Gee.ArrayList<CachePair> (); 78 79 open_default_font (); 80 } 81 82 ~FallbackFont () { 83 if (default_font != null) { 84 close_font (default_font); 85 } 86 } 87 88 public void init_font_config () { 89 FcConfig* fc = FcInitLoadConfigAndFonts (); 90 IdleSource idle = new IdleSource (); 91 92 idle.set_callback (() => { 93 font_config = fc; 94 return false; 95 }); 96 idle.attach (null); 97 } 98 99 public Font get_single_glyph_font (unichar c) { 100 Font f; 101 unichar last; 102 CachePair p; 103 104 if (likely (glyphs.has_key (c))) { 105 p = glyphs.get (c); 106 107 if (p.referenced < int.MAX) { 108 p.referenced++; 109 } 110 111 return p.font; 112 } 113 114 // remove glyphs from cache if it is full 115 if (cached.size > max_cached_fonts - 100) { 116 117 cached.sort ((a, b) => { 118 CachePair pa = (CachePair) a; 119 CachePair pb = (CachePair) b; 120 return pb.referenced - pa.referenced; 121 }); 122 123 int j = 0; 124 for (int i = cached.size - 1; i > 0; i--) { 125 if (j > 100) { 126 break; 127 } 128 129 j++; 130 131 last = cached.get (i).character; 132 glyphs.unset (last); 133 cached.remove_at (i); 134 } 135 } 136 137 f = get_single_fallback_glyph_font (c); 138 p = new CachePair (f, c); 139 140 glyphs.set (c, p); 141 cached.add (p); 142 143 return (Font) f; 144 } 145 146 Font get_single_fallback_glyph_font (unichar c) { 147 string? font_file; 148 BirdFontFile bf_parser; 149 Font bf_font; 150 StringBuilder? glyph_data; 151 FontFace* font; 152 153 bf_font = new Font (); 154 font_file = null; 155 glyph_data = null; 156 157 // don't use fallback font in private use area 158 if (0xe000 <= c <= 0xf8ff) { 159 return bf_font; 160 } 161 162 // control characters 163 if (c <= 0x001f || (0x007f <= c <= 0x008d)) { 164 return bf_font; 165 } 166 167 // check if glyph is available in roboto 168 if (default_font != null) { 169 glyph_data = get_glyph_in_font ((!) default_font, c); 170 } 171 172 // use fontconfig to find a fallback font 173 if (glyph_data == null) { 174 font_file = find_font (font_config, (!) c.to_string ()); 175 if (font_file != null) { 176 font = open_font ((!) font_file); 177 glyph_data = get_glyph_in_font (font, c); 178 close_font (font); 179 } 180 } 181 182 if (glyph_data != null) { 183 bf_parser = new BirdFontFile (bf_font); 184 bf_parser.load_data (((!) glyph_data).str); 185 } 186 187 return bf_font; 188 } 189 190 public StringBuilder? get_glyph_in_font (FontFace* font, unichar c) { 191 StringBuilder? glyph_data = null; 192 GlyphCollection gc; 193 194 gc = new GlyphCollection (c, (!)c.to_string ()); 195 glyph_data = load_glyph (font, (uint) c); 196 197 return glyph_data; 198 } 199 200 void add_font_folder (string f) { 201 File folder = File.new_for_path (f); 202 FileInfo? file_info; 203 string fn; 204 string file_attributes; 205 try { 206 if (folder.query_exists ()) { 207 font_directories.add (folder); 208 209 file_attributes = FileAttribute.STANDARD_NAME; 210 file_attributes += ","; 211 file_attributes += FileAttribute.STANDARD_TYPE; 212 var enumerator = folder.enumerate_children (file_attributes, 0); 213 214 while ((file_info = enumerator.next_file ()) != null) { 215 fn = ((!) file_info).get_name (); 216 217 if (((!)file_info).get_file_type () == FileType.DIRECTORY) { 218 add_font_folder ((!) get_child (folder, fn).get_path ()); 219 } 220 } 221 } 222 } catch (GLib.Error e) { 223 warning (e.message); 224 } 225 } 226 227 File search_font_file (string font_file) { 228 File d, f; 229 230 for (int i = font_directories.size - 1; i >= 0; i--) { 231 d = font_directories.get (i); 232 f = get_child (d, font_file); 233 234 if (f.query_exists ()) { 235 return f; 236 } 237 } 238 239 warning (@"The font $font_file not found"); 240 return File.new_for_path (font_file); 241 } 242 243 void open_default_font () { 244 File font_file; 245 string? fn = null; 246 247 font_file = SearchPaths.search_file (null, default_font_file_name); 248 249 if (font_file.query_exists ()) { 250 fn = (!) font_file.get_path (); 251 } else { 252 font_file = search_font_file (default_font_file_name); 253 254 if (font_file.query_exists ()) { 255 fn = (!) font_file.get_path (); 256 } else { 257 fn = find_font_file (font_config, default_font_family_name); 258 } 259 } 260 261 if (fn != null) { 262 default_font = open_font ((!) fn); 263 } 264 } 265 266 class CachePair : GLib.Object { 267 public Font font; 268 public unichar character; 269 public int referenced = 1; 270 271 public CachePair (Font f, unichar c) { 272 font = f; 273 character = c; 274 } 275 } 276 } 277 278 } 279