.
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 using Sqlite;
17 using Bird;
18
19 namespace BirdFont {
20
21 public class FallbackFont : GLib.Object {
22 static unowned Database db;
23 static Database? database = null;
24
25 Gee.ArrayList<File> fallback_fonts;
26 Gee.ArrayList<File> font_directories;
27
28 public FallbackFont () {
29 string home = Environment.get_home_dir ();
30
31 fallback_fonts = new Gee.ArrayList<File> ();
32 font_directories = new Gee.ArrayList<File> ();
33
34 add_font_folder ("/usr/share/fonts/");
35 add_font_folder ("/usr/local/share/fonts/");
36 add_font_folder (home + "/.local/share/fonts");
37 add_font_folder ("C:\\Windows\\Fonts");
38
39 //FIXME: MAC
40
41 open_fallback_fonts ();
42 }
43
44 void open_fallback_fonts () {
45 add_font ("times.ttf");
46 add_font ("arial.ttf");
47 add_font ("verdana.ttf");
48 add_font ("calibri.ttf");
49
50 add_font ("Ubuntu-R.ttf");
51
52 add_font ("DroidKufi.ttf");
53 add_font ("DroidSansGeorgian.ttf");
54 add_font ("DroidSansHebrew.ttf");
55 add_font ("DroidNaskh.ttf");
56 add_font ("DroidSansJapanese.ttf");
57 add_font ("DroidSansArabic.ttf");
58 add_font ("DroidSansArmenian.ttf");
59 add_font ("DroidSans.ttf");
60 add_font ("DroidSansEthiopic.ttf");
61 add_font ("DroidSansFallbackFull.ttf");
62
63 add_font ("Roboto-Regular.ttf");
64 }
65
66 void add_font (string font) {
67 File f = find_font_file (font);
68
69 if (f.query_exists ()) {
70 fallback_fonts.add (f);
71 }
72 }
73
74 File find_font_file (string font_file) {
75 File d, f;
76
77 for (int i = font_directories.size - 1; i >= 0; i--) {
78 d = font_directories.get (i);
79 f = get_child (d, font_file);
80
81 if (f.query_exists ()) {
82 return f;
83 }
84 }
85
86 return File.new_for_path (font_file);
87 }
88
89 void add_font_folder (string f) {
90 File folder = File.new_for_path (f);
91 FileInfo? file_info;
92 string fn;
93
94 try {
95 if (folder.query_exists ()) {
96 font_directories.add (folder);
97
98 var enumerator = folder.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE, 0);
99
100 while ((file_info = enumerator.next_file ()) != null) {
101 fn = ((!) file_info).get_name ();
102
103 if (((!)file_info).get_file_type () == FileType.DIRECTORY) {
104 add_font_folder ((!) get_child (folder, fn).get_path ());
105 }
106 }
107 }
108 } catch (GLib.Error e) {
109 warning (e.message);
110 }
111 }
112
113 public Font get_single_glyph_font (unichar c) {
114 Font f = load_glyph_from_ttf (c);
115 return f;
116 }
117
118 public Font load_glyph_from_ttf (unichar c) {
119 Font? bf_font;
120 File f;
121 FontFace* font;
122
123 bf_font = new Font ();
124
125 for (int i = fallback_fonts.size - 1; i >= 0; i--) {
126 f = fallback_fonts.get (i);
127
128 font = open_font ((!) f.get_path ());
129 bf_font = get_glyph_in_font ((!) font, c);
130
131 close_font (font);
132
133 if (bf_font != null) {
134 return (!) bf_font;
135 }
136 }
137
138 return bf_font != null ? (!) bf_font : new Font ();
139 }
140
141 public Font? get_glyph_in_font (FontFace font, unichar c) {
142 StringBuilder? glyph_data = null;
143 GlyphCollection gc;
144 BirdFontFile bf_parser;
145 Font bf_font = new Font ();
146
147 gc = new GlyphCollection (c, (!)c.to_string ());
148 glyph_data = load_glyph (font, (uint) c);
149
150 if (glyph_data == null) {
151 return null;
152 }
153
154 bf_parser = new BirdFontFile (bf_font);
155 bf_parser.load_data (((!) glyph_data).str);
156
157 return bf_font;
158 }
159
160 public File get_database_file () {
161 return SearchPaths.find_file (null, "fallback-font.sqlite");
162 }
163
164 public File get_new_database_file () {
165 string? fn = BirdFont.get_argument ("--fallback-font");
166
167 if (fn != null && ((!) fn) != "") {
168 return File.new_for_path ((!) fn);
169 }
170
171 return File.new_for_path ("fallback-font.sqlite");
172 }
173
174 public void generate_fallback_font () {
175 File f = get_new_database_file ();
176 string? fonts = BirdFont.get_argument ("--fonts");
177 string fallback;
178
179 if (fonts == null) {
180 stderr.printf ("Add a list of fonts to use as fallback to the \"--fonts\" argument.\n");
181 stderr.printf ("Separate each font file with \":\"\n");
182 return;
183 }
184
185 fallback = (!) fonts;
186
187 stdout.printf ("Generating fallback font: %s\n", (!) f.get_path ());
188
189 try {
190 if (f.query_exists ()) {
191 f.delete ();
192 }
193
194 open_database (f);
195 create_tables ();
196
197 foreach (string font in fallback.split (":")) {
198 add_font (font);
199 }
200 } catch (GLib.Error e) {
201 warning (e.message);
202 }
203
204 }
205
206 /* //FIXME:DELETE
207 public void add_font (string font_file) {
208 Font font;
209 Glyph g;
210 BirdFontFile bf;
211 File single_glyph_font;
212
213 font = new Font ();
214 single_glyph_font = File.new_for_path ("/tmp/fallback_glyph.bf");
215
216 font.set_file (font_file);
217 if (!font.load ()) {
218 stderr.printf ("Failed to load font: " + font_file);
219 return;
220 }
221
222 for (int i = 0; i < font.length (); i++) {
223 g = (!) font.get_glyph_indice (i);
224 bf = new BirdFontFile (font);
225 }
226 } */
227
228 public void open_database (File db_file) {
229 int rc = Database.open ((!) db_file.get_path (), out database);
230
231 db = (!) database;
232
233 if (rc != Sqlite.OK) {
234 stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());
235 }
236 }
237
238 public void create_tables () {
239 int ec;
240 string? errmsg;
241 string create_font_table = """
242 CREATE TABLE FallbackFont (
243 unicode INTEGER PRIMARY KEY NOT NULL,
244 font_data TEXT NOT NULL
245 );
246 """;
247
248 ec = db.exec (create_font_table, null, out errmsg);
249 if (ec != Sqlite.OK) {
250 warning ("Error: %s\n", (!) errmsg);
251 }
252 }
253 }
254
255 }
256