.
1 /*
2 Copyright (C) 2012, 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 [SimpleType]
16 [CCode (cname = "FontFace")]
17 public extern class FontFace {
18 }
19
20 [CCode (cname = "load_freetype_font")]
21 public extern static StringBuilder? load_freetype_font (string file, out int error);
22
23 [CCode (cname = "validate_freetype_font")]
24 public extern static bool validate_freetype_font (string file);
25
26 [CCode (cname = "load_glyph")]
27 public extern static StringBuilder? load_glyph (FontFace font, uint unicode);
28
29 [CCode (cname = "open_font")]
30 public extern static FontFace* open_font (string font_file);
31
32 [CCode (cname = "close_ft_font")]
33 public extern static void close_font (FontFace* font);
34
35 namespace BirdFont {
36
37 [SimpleType]
38 [CCode (has_type_id = false)] // Vala bug
39 public struct Fixed : uint32 {
40
41 public bool @equals (uint16 upper, uint16 lower) {
42 uint32 t = (upper << 16) + lower;
43 return (t == this);
44 }
45
46 public string get_string () {
47 uint a = this >> 16;
48 return @"$(a).$(this - (a << 16))";
49 }
50 }
51
52 [SimpleType]
53 [CCode (has_type_id = false)] // same as above
54 public struct F2Dot14 : uint32 {
55 }
56
57 errordomain BadFormat {
58 PARSE
59 }
60
61 public class OpenFontFormatReader : Object {
62
63 public DirectoryTable directory_table;
64 public FontData font_data = new FontData ();
65
66 OtfInputStream dis;
67 File file;
68
69 public OpenFontFormatReader () {
70 directory_table = new DirectoryTable ();
71 }
72
73 public void close () {
74 dis.close ();
75 }
76
77 public void parse_index (string file_name) throws Error {
78 file = File.new_for_path (file_name);
79 if (!file.query_exists ()) {
80 throw new FileError.EXIST(@"OpenFontFormatReader: file does not exist. $((!) file.get_path ())");
81 }
82
83 dis = new OtfInputStream (file.read ());
84
85 parse_index_tables ();
86 }
87
88 void parse_index_tables () throws Error {
89 OffsetTable offset_table;
90
91 FileInfo file_info = file.query_info ("*", FileQueryInfoFlags.NONE);
92 uint32 file_size = (uint32) file_info.get_size ();
93
94 try {
95 font_data.write_table (dis, 0, file_size);
96 } catch (GLib.Error e) {
97 warning (@"Failed to read font data. $(e.message)");
98 }
99
100 offset_table = new OffsetTable (directory_table);
101 offset_table.parse (font_data);
102
103 directory_table = new DirectoryTable ();
104 directory_table.set_offset_table (offset_table);
105 directory_table.parse (font_data, this);
106 }
107
108 public void parse_all_tables () throws Error {
109 directory_table.parse_all_tables (font_data, this);
110
111 if (!directory_table.validate_tables (font_data, file)) {
112 warning ("Missing required table or bad checksum.");
113 }
114 }
115
116 public void parse_kern_table () throws Error {
117 directory_table.parse_kern_table (font_data);
118 }
119
120 public void parse_cmap_table () throws Error {
121 directory_table.parse_cmap_table (font_data);
122 }
123
124 public void parse_head_table () throws Error {
125 directory_table.parse_head_table (font_data);
126 }
127
128 public void set_limits () {
129 Font f = OpenFontFormatWriter.font;
130
131 if (is_null (f)) {
132 f = BirdFont.get_current_font ();
133 }
134
135 // FIXME: set guides to ascent & descent
136 }
137
138 public uint32 get_head_checksum () {
139 return directory_table.head_table.get_adjusted_checksum ();
140 }
141
142 public static void append_kerning (StringBuilder bf_data, string file_name) {
143 string s = parse_kerning (file_name);
144 bf_data.append (s);
145 }
146
147 public static string parse_kerning (string file_name) {
148 KernTable kern_table;
149 CmapTable cmap_table;
150 HeadTable head_table;
151 OpenFontFormatReader reader = new OpenFontFormatReader ();
152 StringBuilder bf_kerning = new StringBuilder ();
153 unichar left, right;
154 double kerning, units_per_em;
155 uint npairs = 0;
156
157 try {
158 reader.parse_index (file_name);
159 reader.parse_kern_table ();
160 reader.parse_cmap_table ();
161 reader.parse_head_table ();
162
163 kern_table = reader.directory_table.kern_table;
164 cmap_table = reader.directory_table.cmap_table;
165 head_table = reader.directory_table.head_table;
166
167 npairs = kern_table.kerning.size;
168
169 units_per_em = HeadTable.units_per_em;
170
171 foreach (Kern k in kern_table.kerning) {
172 left = cmap_table.get_char (k.left);
173 right = cmap_table.get_char (k.right);
174 kerning = 100 * (k.kerning / units_per_em);
175
176 if (left <= 0x1F || right <= 0x1F) {
177 warning ("Ignoring kerning of control character.");
178 } else {
179 if (@"$kerning" != "0") {
180 bf_kerning.append ("<kerning left=\"");
181 bf_kerning.append (BirdFontFile.serialize_unichar (left));
182 bf_kerning.append ("\" ");
183 bf_kerning.append ("right=\"");
184 bf_kerning.append (BirdFontFile.serialize_unichar (right));
185 bf_kerning.append ("\" ");
186 bf_kerning.append ("hadjustment=\"");
187 bf_kerning.append (@"$kerning".replace (",", "."));
188 bf_kerning.append ("\" />\n");
189 }
190 }
191 }
192 } catch (GLib.Error e) {
193 warning (@"Failed to parse font. $(e.message)");
194 }
195
196 return bf_kerning.str;
197 }
198 }
199 }
200