2
Copyright (C) 2014 Johan Mattsson
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.
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.
17
/** BirdFontPart is a class for parsing .bfp files. The file format is
18
* identical to .bf but the font is split in many parts. Each part
19
* contains a few elements and all parent nodes from the root node and
20
* downwards. The .bfp files can be parsed in any order. The root directory
21
* of a .bfp tree must have a file with the name "description.bfp", this file
22
* tells the parser that bfp files in parent directories should be excluded.
24
class BirdFontPart : GLib.Object{
27
string root_directory;
29
static string FILE_ATTRIBUTES = "standard::*";
31
public BirdFontPart (Font font) {
33
parts = new List<string> ();
37
public bool load (string bfp_file) {
38
BirdFontFile bf = new BirdFontFile (font);
43
find_all_parts (bfp_file);
46
while (font.background_images.length () > 0) {
47
font.background_images.remove_link (font.background_images.first ());
50
bfp_dir = File.new_for_path (root_directory);
51
image_dir = bfp_dir.get_child ("images");
52
copy_backgrounds ((!) image_dir.get_path ());
54
foreach (string fn in parts) {
57
} catch (GLib.Error e) {
65
public string get_path () {
69
path = (!) get_destination_file (@"$(font.full_name).bfp").get_path ();
70
} catch (GLib.Error e) {
79
BirdFontFile bf = new BirdFontFile (font);
82
if (root_directory == "") {
83
warning ("No directory is created for this birdfont part.");
88
os = create_file (@"$(font.full_name).bfp");
89
bf.write_root_tag (os);
90
bf.write_closing_root_tag (os);
93
os = create_file ("description.bfp");
94
bf.write_root_tag (os);
95
bf.write_description (os);
96
bf.write_closing_root_tag (os);
99
os = create_file ("lines.bfp");
100
bf.write_root_tag (os);
102
bf.write_closing_root_tag (os);
105
os = create_file ("settings.bfp");
106
bf.write_root_tag (os);
107
bf.write_settings (os);
108
bf.write_closing_root_tag (os);
111
font.glyph_cache.for_each ((gc) => {
117
warning ("No glyph collection");
120
file_name = get_first_number_in_unicode (((!)gc).get_current ());
121
dir_name = (!)file_name.get_char ().to_string ();
123
os = create_file (@"selected_$(file_name).bfp", "glyphs", dir_name);
124
bf.write_root_tag (os);
125
bf.write_glyph_collection_start (gc, os);
126
bf.write_selected ((!) gc, os);
127
bf.write_glyph_collection_end (os);
128
bf.write_closing_root_tag (os);
131
foreach (Glyph g in gc.get_version_list ().glyphs) {
133
write_glyph (bf, gc, g);
134
write_glyph_background_image (bf, gc, g);
135
} catch (GLib.Error e) {
139
} catch (GLib.Error e) {
140
warning (@"Can not save bfp files to $root_directory\n");
141
warning (@"$(e.message) \n");
146
os = create_file ("kerning.bfp");
147
bf.write_root_tag (os);
148
bf.write_kerning (os);
149
bf.write_closing_root_tag (os);
152
} catch (GLib.Error e) {
153
warning (@"Failed to save bfp files to $root_directory\n");
154
warning (@"$(e.message) \n");
161
void copy_backgrounds (string folder) throws GLib.Error {
167
GlyphBackgroundImage bg;
171
image_dir = File.new_for_path (folder);
173
if (image_dir.query_exists ()) {
174
info = image_dir.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE);
175
if (info.get_file_type () != FileType.DIRECTORY) {
176
warning (@"$((!) image_dir.get_path ()) is not a directory.");
177
throw new FileError.NOTDIR ("Not a directory.");
180
e = image_dir.enumerate_children (FILE_ATTRIBUTES, 0);
181
while ((fi = e.next_file ()) != null) {
183
name = info.get_name ();
185
if (info.get_file_type () == FileType.DIRECTORY) {
186
found = image_dir.get_child (name);
187
copy_backgrounds ((!) found.get_path ());
190
if (name.has_suffix (".png")) {
191
found = image_dir.get_child (name);
192
dest = font.get_backgrounds_folder ().get_child ("parts").get_child (name);
193
bg = new GlyphBackgroundImage ((!) found.get_path ());
194
bg.create_background_folders (font);
195
bg.copy_if_new (dest);
201
string get_first_number_in_unicode (Glyph g) throws GLib.Error {
202
string s = Font.to_hex (g.unichar_code);
203
s = s.replace ("U+", "");
207
string get_glyph_base_file_name (Glyph g) throws GLib.Error {
208
string s = get_first_number_in_unicode (g);
209
s = @"$(s)_$(g.version_id)";
213
void write_glyph (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error {
218
file_name = get_glyph_base_file_name (g);
219
dir_name = (!)file_name.get_char ().to_string ();
221
os = create_file (@"$(file_name).bfp", "glyphs", dir_name);
222
bf.write_root_tag (os);
223
bf.write_glyph_collection_start (gc, os);
224
bf.write_glyph (g, gc, os);
225
bf.write_glyph_collection_end (os);
226
bf.write_closing_root_tag (os);
230
void write_glyph_background_image (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error {
233
GlyphBackgroundImage bg;
236
if (g.get_background_image () != null) {
237
bg = (!) g.get_background_image ();
239
if (bg.is_valid ()) {
240
file_name = @"$(bg.get_sha1 ()).png";
241
dir_name = (!)file_name.get_char ().to_string ();
242
file = get_destination_file (file_name, "images", dir_name);
243
bg.copy_if_new (file);
250
public void create_directory (string directory) throws GLib.Error {
251
File dir = File.new_for_path (directory);
255
if (directory.has_suffix (font.get_full_name ())) {
258
bfp_dir = dir.get_child (font.get_full_name ());
261
while (bfp_dir.query_exists ()) {
262
bfp_dir = dir.get_child (@"$(font.get_full_name ())_$(i)");
266
if (!dir.query_exists ()) {
267
DirUtils.create ((!) dir.get_path (), 0xFFFFFF);
270
root_directory = (!) bfp_dir.get_path ();
271
DirUtils.create (root_directory, 0xFFFFFF);
274
private void find_all_parts (string bfp_file) throws GLib.Error {
275
File start = File.new_for_path (bfp_file);
279
info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE);
280
if (info.get_file_type () != FileType.DIRECTORY) {
281
start = (!) start.get_parent ();
284
root = find_root ((!)start.get_path ());
285
root_directory = (!)root.get_path ();
287
find_parts (root_directory);
290
private void find_parts (string directory) throws GLib.Error {
291
File start = File.new_for_path (directory);
299
info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE);
300
if (info.get_file_type () != FileType.DIRECTORY) {
301
warning (@"$directory is not a directory.");
302
throw new FileError.NOTDIR ("Not a directory.");
305
e = start.enumerate_children (FILE_ATTRIBUTES, 0);
306
while ((fi = e.next_file ()) != null) {
308
name = info.get_name ();
309
if (info.get_file_type () == FileType.DIRECTORY) {
310
find_parts ((!) ((!) start.get_child (name)).get_path ());
311
} else if (name.has_suffix (".bfp")) {
312
found = start.get_child (name);
313
parts.append ((!) found.get_path ());
318
private File find_root (string directory) throws GLib.Error {
319
File start = File.new_for_path (directory);
324
info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE);
325
if (info.get_file_type () != FileType.DIRECTORY) {
326
warning ("Not a directory.");
327
throw new FileError.NOTDIR ("Not a directory.");
330
e = start.enumerate_children (FILE_ATTRIBUTES, 0);
331
while ((fi = e.next_file ()) != null) {
333
if (info.get_name () == "description.bfp") {
338
if (start.get_parent () == null) {
339
warning ("description.bfp not found");
340
throw new FileError.FAILED ("description.bfp not found");
343
return find_root ((!)((!) start.get_parent ()).get_path ());
346
private File new_subdirectory (File d, string subdir) throws GLib.Error {
351
dir = dir.get_child (subdir);
353
if (!dir.query_exists ()) {
354
DirUtils.create ((!) dir.get_path (), 0xFFFFFF);
356
info = dir.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE);
357
if (info.get_file_type () != FileType.DIRECTORY) {
358
throw new FileError.FAILED (@"Can't save font, $subdir is not a directory.");
364
private File get_destination_file (string name, string subdir1 = "", string subdir2 = "") throws GLib.Error {
368
dir = File.new_for_path (root_directory);
371
dir = new_subdirectory (dir, subdir1);
375
dir = new_subdirectory (dir, subdir2);
378
file = dir.get_child (name);
380
if (file.query_file_type (0) == FileType.DIRECTORY) {
381
throw new FileError.FAILED (@"Can't save font, $name is a directory.");
387
private DataOutputStream create_file (string name, string subdir1 = "", string subdir2 = "") throws GLib.Error {
391
file = get_destination_file (name, subdir1, subdir2);
393
if (file.query_exists ()) {
397
os = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION));