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.
Better parsing of TrueType outlines
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 FcConfig* font_config = null; 38 FontFace* default_font = null; 39 40 string default_font_file_name = "Roboto-Regular.ttf"; 41 string default_font_family_name = "Roboto"; 42 43 Gee.HashMap<unichar, CachePair> glyphs; 44 Gee.ArrayList<CachePair> cached; 45 46 public int max_cached_fonts = 300; 47 48 public FallbackFont () { 49 string home = Environment.get_home_dir (); 50 51 font_directories = new Gee.ArrayList<File> (); 52 font_config = FcInitLoadConfigAndFonts (); 53 54 add_font_folder ("/usr/share/fonts/"); 55 add_font_folder ("/usr/local/share/fonts/"); 56 add_font_folder (home + "/.local/share/fonts"); 57 add_font_folder (home + "/.fonts"); 58 add_font_folder ("C:\\Windows\\Fonts"); 59 add_font_folder (home + "/Library/Fonts"); 60 add_font_folder ("/Library/Fonts"); 61 add_font_folder ("/Network/Library/Fonts"); 62 add_font_folder ("/System/Library/Fonts"); 63 add_font_folder ("/System Folder/Fonts"); 64 65 glyphs = new Gee.HashMap<unichar, CachePair> (); 66 cached = new Gee.ArrayList<CachePair> (); 67 68 open_default_font (); 69 } 70 71 ~FallbackFont () { 72 if (default_font != null) { 73 close_font (default_font); 74 } 75 } 76 77 public Font get_single_glyph_font (unichar c) { 78 Font f; 79 unichar last; 80 CachePair p; 81 82 if (likely (glyphs.has_key (c))) { 83 p = glyphs.get (c); 84 85 if (p.referenced < int.MAX) { 86 p.referenced++; 87 } 88 89 return p.font; 90 } 91 92 // remove glyphs from cache if it is full 93 if (cached.size > max_cached_fonts - 100) { 94 95 cached.sort ((a, b) => { 96 CachePair pa = (CachePair) a; 97 CachePair pb = (CachePair) b; 98 return pb.referenced - pa.referenced; 99 }); 100 101 int j = 0; 102 for (int i = cached.size - 1; i > 0; i--) { 103 if (j > 100) { 104 break; 105 } 106 107 j++; 108 109 last = cached.get (i).character; 110 glyphs.unset (last); 111 cached.remove_at (i); 112 } 113 } 114 115 f = get_single_fallback_glyph_font (c); 116 p = new CachePair (f, c); 117 118 glyphs.set (c, p); 119 cached.add (p); 120 121 return (Font) f; 122 } 123 124 Font get_single_fallback_glyph_font (unichar c) { 125 string? font_file; 126 BirdFontFile bf_parser; 127 Font bf_font; 128 StringBuilder? glyph_data; 129 FontFace* font; 130 131 bf_font = new Font (); 132 font_file = null; 133 glyph_data = null; 134 135 // don't use fallback font in private use area 136 if (0xe000 <= c <= 0xf8ff) { 137 return bf_font; 138 } 139 140 // control characters 141 if (c <= 0x001f || (0x007f <= c <= 0x008d)) { 142 return bf_font; 143 } 144 145 // check if glyph is available in roboto 146 if (default_font != null) { 147 glyph_data = get_glyph_in_font ((!) default_font, c); 148 } 149 150 // use fontconfig to find a fallback font 151 if (glyph_data == null) { 152 font_file = find_font (font_config, (!) c.to_string ()); 153 if (font_file != null) { 154 printd ((!) font_file); // FIXME: DELETE 155 printd ("\n"); 156 157 font = open_font ((!) font_file); 158 glyph_data = get_glyph_in_font (font, c); 159 close_font (font); 160 } 161 } 162 163 if (glyph_data != null) { 164 bf_parser = new BirdFontFile (bf_font); 165 bf_parser.load_data (((!) glyph_data).str); 166 } 167 168 return bf_font; 169 } 170 171 public StringBuilder? get_glyph_in_font (FontFace* font, unichar c) { 172 StringBuilder? glyph_data = null; 173 GlyphCollection gc; 174 175 gc = new GlyphCollection (c, (!)c.to_string ()); 176 glyph_data = load_glyph (font, (uint) c); 177 178 return glyph_data; 179 } 180 181 void add_font_folder (string f) { 182 File folder = File.new_for_path (f); 183 FileInfo? file_info; 184 string fn; 185 string file_attributes; 186 try { 187 if (folder.query_exists ()) { 188 font_directories.add (folder); 189 190 file_attributes = FileAttribute.STANDARD_NAME; 191 file_attributes += ","; 192 file_attributes += FileAttribute.STANDARD_TYPE; 193 var enumerator = folder.enumerate_children (file_attributes, 0); 194 195 while ((file_info = enumerator.next_file ()) != null) { 196 fn = ((!) file_info).get_name (); 197 198 if (((!)file_info).get_file_type () == FileType.DIRECTORY) { 199 add_font_folder ((!) get_child (folder, fn).get_path ()); 200 } 201 } 202 } 203 } catch (GLib.Error e) { 204 warning (e.message); 205 } 206 } 207 208 File search_font_file (string font_file) { 209 File d, f; 210 211 for (int i = font_directories.size - 1; i >= 0; i--) { 212 d = font_directories.get (i); 213 f = get_child (d, font_file); 214 215 if (f.query_exists ()) { 216 return f; 217 } 218 } 219 220 warning (@"The font $font_file not found"); 221 return File.new_for_path (font_file); 222 } 223 224 void open_default_font () { 225 File font_file; 226 string? fn = null; 227 228 font_file = SearchPaths.search_file (null, default_font_file_name); 229 230 if (font_file.query_exists ()) { 231 fn = (!) font_file.get_path (); 232 } else { 233 font_file = search_font_file (default_font_file_name); 234 235 if (font_file.query_exists ()) { 236 fn = (!) font_file.get_path (); 237 } else { 238 fn = find_font_file (font_config, default_font_family_name); 239 } 240 } 241 242 if (fn != null) { 243 default_font = open_font ((!) fn); 244 } 245 } 246 247 class CachePair : GLib.Object { 248 public Font font; 249 public unichar character; 250 public int referenced = 1; 251 252 public CachePair (Font f, unichar c) { 253 font = f; 254 character = c; 255 } 256 } 257 } 258 259 } 260