The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

BirdFontPart.vala in libbirdfont

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/BirdFontPart.vala.
Ignore case in key bindings
1 /* 2 Copyright (C) 2014 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 namespace BirdFont { 16 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. 23 */ 24 public class BirdFontPart : GLib.Object{ 25 unowned Font font; 26 Gee.ArrayList<string> parts; 27 string root_directory; 28 29 static string FILE_ATTRIBUTES = "standard::*"; 30 31 public BirdFontPart (Font font) { 32 this.font = font; 33 34 font.font_deleted.connect (() => { 35 this.font = Font.empty; 36 }); 37 38 parts = new Gee.ArrayList<string> (); 39 root_directory = ""; 40 } 41 42 public bool load (string bfp_file) { 43 BirdFontFile bf = new BirdFontFile (font); 44 File bfp_dir; 45 File image_dir; 46 47 try { 48 find_all_parts (bfp_file); 49 font.set_bfp (true); 50 51 font.background_images.clear (); 52 53 bfp_dir = File.new_for_path (root_directory); 54 image_dir = get_child (bfp_dir, "images"); 55 copy_backgrounds ((!) image_dir.get_path ()); 56 57 foreach (string fn in parts) { 58 bf.load_part (fn); 59 } 60 } catch (GLib.Error e) { 61 warning (e.message); 62 return false; 63 } 64 65 return true; 66 } 67 68 public string get_path () { 69 string path = ""; 70 71 try { 72 path = (!) get_destination_file (@"$(font.full_name).bfp").get_path (); 73 } catch (GLib.Error e) { 74 warning (e.message); 75 } 76 77 return path; 78 } 79 80 public bool save () { 81 DataOutputStream os; 82 BirdFontFile bf = new BirdFontFile (font); 83 bool error = false; 84 string file_name; 85 string glyph_dir_name; 86 File glyph_file; 87 88 if (root_directory == "") { 89 warning ("No directory is created for this birdfont part."); 90 return false; 91 } 92 93 try { 94 // remove deleted glyphs 95 foreach (Glyph g in font.deleted_glyphs) { 96 file_name = get_glyph_base_file_name (g) + ".bfp"; 97 glyph_dir_name = get_subdir_name (file_name); 98 glyph_file = get_destination_file (file_name, "glyphs", glyph_dir_name); 99 100 if (glyph_file.query_exists ()) { 101 glyph_file.delete (); 102 } 103 104 print (@"$((!)glyph_file.get_path ())\n"); 105 } 106 107 os = create_file (@"$(font.full_name).bfp"); 108 bf.write_root_tag (os); 109 bf.write_closing_root_tag (os); 110 os.close (); 111 112 os = create_file ("description.bfp"); 113 bf.write_root_tag (os); 114 bf.write_description (os); 115 bf.write_closing_root_tag (os); 116 os.close (); 117 118 os = create_file ("lines.bfp"); 119 bf.write_root_tag (os); 120 bf.write_lines (os); 121 bf.write_closing_root_tag (os); 122 os.close (); 123 124 os = create_file ("settings.bfp"); 125 bf.write_root_tag (os); 126 bf.write_settings (os); 127 bf.write_closing_root_tag (os); 128 os.close (); 129 130 os = create_file ("spacing.bfp"); 131 bf.write_root_tag (os); 132 bf.write_spacing_classes (os); 133 bf.write_closing_root_tag (os); 134 os.close (); 135 136 os = create_file ("ligatures.bfp"); 137 bf.write_root_tag (os); 138 bf.write_ligatures (os); 139 bf.write_closing_root_tag (os); 140 os.close (); 141 142 font.glyph_cache.for_each ((gc) => { 143 try { 144 string selected_file_name; 145 string dir_name; 146 147 if (is_null (gc)) { 148 warning ("No glyph collection"); 149 } 150 151 selected_file_name = get_first_number_in_unicode (((!)gc).get_current ()); 152 dir_name = get_subdir_name (selected_file_name); 153 154 os = create_file (@"selected_$(selected_file_name).bfp", "glyphs", dir_name); 155 bf.write_root_tag (os); 156 bf.write_glyph_collection_start (gc, os); 157 bf.write_selected ((!) gc, os); 158 bf.write_glyph_collection_end (os); 159 bf.write_closing_root_tag (os); 160 os.close (); 161 162 foreach (Glyph g in gc.glyphs) { 163 try { 164 write_glyph (bf, gc, g); 165 write_glyph_background_image (bf, gc, g); 166 } catch (GLib.Error e) { 167 warning (e.message); 168 } 169 } 170 } catch (GLib.Error e) { 171 warning (@"Can not save bfp files to $root_directory\n"); 172 warning (@"$(e.message) \n"); 173 error = true; 174 } 175 }); 176 177 os = create_file ("kerning.bfp"); 178 bf.write_root_tag (os); 179 bf.write_kerning (os); 180 bf.write_closing_root_tag (os); 181 os.close (); 182 183 os = create_file ("images.bfp"); 184 bf.write_root_tag (os); 185 bf.write_images (os); 186 bf.write_closing_root_tag (os); 187 os.close (); 188 189 } catch (GLib.Error e) { 190 warning (@"Failed to save bfp files to $root_directory\n"); 191 warning (@"$(e.message) \n"); 192 error = true; 193 } 194 195 return !error; 196 } 197 198 void copy_backgrounds (string folder) throws GLib.Error { 199 FileInfo info; 200 FileInfo? fi; 201 FileEnumerator e; 202 string name; 203 File image_dir; 204 BackgroundImage bg; 205 File found; 206 File parts; 207 File dest; 208 209 image_dir = File.new_for_path (folder); 210 211 if (image_dir.query_exists ()) { 212 info = image_dir.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); 213 if (info.get_file_type () != FileType.DIRECTORY) { 214 warning (@"$((!) image_dir.get_path ()) is not a directory."); 215 throw new FileError.NOTDIR ("Not a directory."); 216 } 217 218 e = image_dir.enumerate_children (FILE_ATTRIBUTES, 0); 219 while ((fi = e.next_file ()) != null) { 220 info = (!) fi; 221 name = info.get_name (); 222 223 if (info.get_file_type () == FileType.DIRECTORY) { 224 found = get_child (image_dir, name); 225 copy_backgrounds ((!) found.get_path ()); 226 } 227 228 if (name.has_suffix (".png")) { 229 found = get_child (image_dir, name); 230 parts = get_child (font.get_backgrounds_folder (), "parts"); 231 dest = get_child (parts, name); 232 bg = new BackgroundImage ((!) found.get_path ()); 233 bg.create_background_folders (font); 234 bg.copy_if_new (dest); 235 } 236 } 237 } 238 } 239 240 string get_first_number_in_unicode (Glyph g) throws GLib.Error { 241 string s = Font.to_hex (g.unichar_code); 242 s = s.replace ("U+", ""); 243 return s; 244 } 245 246 string get_glyph_base_file_name (Glyph g) throws GLib.Error { 247 string s = get_first_number_in_unicode (g); 248 s = @"U+$(s)_$(g.version_id)"; 249 return s; 250 } 251 252 public string get_subdir_name (string file_name) { 253 string d = file_name; 254 255 if (file_name.has_prefix ("U+")) { 256 d = file_name.replace ("U+", ""); 257 } 258 259 return (!) d.get_char ().to_string (); 260 } 261 262 void write_glyph (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error { 263 string file_name; 264 string dir_name; 265 DataOutputStream os; 266 267 file_name = get_glyph_base_file_name (g); 268 dir_name = get_subdir_name (file_name); 269 270 os = create_file (@"$(file_name).bfp", "glyphs", dir_name); 271 bf.write_root_tag (os); 272 bf.write_glyph_collection_start (gc, os); 273 bf.write_glyph (g, os); 274 bf.write_glyph_collection_end (os); 275 bf.write_closing_root_tag (os); 276 os.close (); 277 } 278 279 void write_glyph_background_image (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error { 280 string file_name; 281 string dir_name; 282 BackgroundImage bg; 283 File file; 284 285 if (g.get_background_image () != null) { 286 bg = (!) g.get_background_image (); 287 288 if (bg.is_valid ()) { 289 file_name = @"$(bg.get_sha1 ()).png"; 290 dir_name = get_subdir_name (file_name); 291 file = get_destination_file (file_name, "images", dir_name); 292 bg.copy_if_new (file); 293 294 // FIXME: GIT ADD 295 } 296 } 297 } 298 299 public void create_directory (string directory) throws GLib.Error { 300 File dir = File.new_for_path (directory); 301 File bfp_dir; 302 int i = 2; 303 304 if (directory.has_suffix (font.get_full_name ())) { 305 bfp_dir = dir; 306 } else { 307 bfp_dir = get_child (dir, font.get_full_name ()); 308 } 309 310 while (bfp_dir.query_exists ()) { 311 bfp_dir = get_child (dir, @"$(font.get_full_name ())_$(i)"); 312 i++; 313 } 314 315 if (!dir.query_exists ()) { 316 DirUtils.create ((!) dir.get_path (), 0755); 317 } 318 319 root_directory = (!) bfp_dir.get_path (); 320 DirUtils.create (root_directory, 0755); 321 } 322 323 private void find_all_parts (string bfp_file) throws GLib.Error { 324 File start = File.new_for_path (bfp_file); 325 FileInfo info; 326 File root; 327 328 info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); 329 if (info.get_file_type () != FileType.DIRECTORY) { 330 start = (!) start.get_parent (); 331 } 332 333 root = find_root ((!)start.get_path ()); 334 root_directory = (!)root.get_path (); 335 336 find_parts (root_directory); 337 } 338 339 private void find_parts (string directory) throws GLib.Error { 340 File start = File.new_for_path (directory); 341 File found; 342 FileInfo info; 343 FileInfo? fi; 344 FileEnumerator e; 345 string name; 346 347 348 info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); 349 if (info.get_file_type () != FileType.DIRECTORY) { 350 warning (@"$directory is not a directory."); 351 throw new FileError.NOTDIR ("Not a directory."); 352 } 353 354 e = start.enumerate_children (FILE_ATTRIBUTES, 0); 355 while ((fi = e.next_file ()) != null) { 356 info = (!) fi; 357 name = info.get_name (); 358 if (info.get_file_type () == FileType.DIRECTORY) { 359 find_parts ((!) ((!) get_child (start, name)).get_path ()); 360 } else if (name.has_suffix (".bfp")) { 361 found = get_child (start, name); 362 parts.add ((!) found.get_path ()); 363 } 364 } 365 } 366 367 private File find_root (string directory) throws GLib.Error { 368 File start = File.new_for_path (directory); 369 FileInfo info; 370 FileInfo? fi; 371 FileEnumerator e; 372 373 info = start.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); 374 if (info.get_file_type () != FileType.DIRECTORY) { 375 warning ("Not a directory."); 376 throw new FileError.NOTDIR ("Not a directory."); 377 } 378 379 e = start.enumerate_children (FILE_ATTRIBUTES, 0); 380 while ((fi = e.next_file ()) != null) { 381 info = (!) fi; 382 if (info.get_name () == "description.bfp") { 383 return start; 384 } 385 } 386 387 if (start.get_parent () == null) { 388 warning ("description.bfp not found"); 389 throw new FileError.FAILED ("description.bfp not found"); 390 } 391 392 return find_root ((!)((!) start.get_parent ()).get_path ()); 393 } 394 395 private File new_subdirectory (File d, string subdir) throws GLib.Error { 396 FileInfo info; 397 File dir; 398 399 dir = d; 400 dir = get_child (dir, subdir); 401 402 if (!dir.query_exists ()) { 403 DirUtils.create ((!) dir.get_path (), 0755); 404 } else { 405 info = dir.query_info (FILE_ATTRIBUTES, FileQueryInfoFlags.NONE); 406 if (info.get_file_type () != FileType.DIRECTORY) { 407 throw new FileError.FAILED (@"Can't save font, $subdir is not a directory."); 408 } 409 } 410 return dir; 411 } 412 413 private File get_destination_file (string name, string subdir1 = "", string subdir2 = "") throws GLib.Error { 414 File file; 415 File dir; 416 417 dir = File.new_for_path (root_directory); 418 419 if (subdir1 != "") { 420 dir = new_subdirectory (dir, subdir1); 421 } 422 423 if (subdir2 != "") { 424 dir = new_subdirectory (dir, subdir2); 425 } 426 427 file = get_child (dir, name); 428 429 if (file.query_file_type (0) == FileType.DIRECTORY) { 430 throw new FileError.FAILED (@"Can't save font, $name is a directory."); 431 } 432 433 return file; 434 } 435 436 private DataOutputStream create_file (string name, string subdir1 = "", string subdir2 = "") throws GLib.Error { 437 DataOutputStream os; 438 File file; 439 string git_path; 440 441 file = get_destination_file (name, subdir1, subdir2); 442 443 if (file.query_exists ()) { 444 file.delete (); 445 } 446 447 os = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION)); 448 449 if (subdir2 != "") { 450 git_path = subdir1 + "/" + subdir2 + "/" + name; 451 } else if (subdir1 != "") { 452 git_path = subdir1 + "/" + name; 453 } else { 454 git_path = name; 455 } 456 457 // FIXME: git_index.add_path (git_path); 458 459 return os; 460 } 461 } 462 463 } 464