]> git.donarmstrong.com Git - lilypond.git/blob - lily/open-type-font.cc
255f7caa0d1431e88e1c18eddb2c52284bbebca8
[lilypond.git] / lily / open-type-font.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "open-type-font.hh"
21 #include "freetype.hh"
22
23 #include <cstdio>
24
25 using namespace std;
26
27 #include FT_TRUETYPE_TABLES_H
28
29 #include "dimensions.hh"
30 #include "freetype.hh"
31 #include "international.hh"
32 #include "modified-font-metric.hh"
33 #include "warn.hh"
34
35 FT_Byte *
36 load_table (char const *tag_str, FT_Face face, FT_ULong *length)
37 {
38   *length = 0;
39   FT_ULong tag = FT_MAKE_TAG (tag_str[0], tag_str[1], tag_str[2], tag_str[3]);
40
41   FT_Error error_code = FT_Load_Sfnt_Table (face, tag, 0, NULL, length);
42   if (!error_code)
43     {
44       FT_Byte *buffer = (FT_Byte *) malloc (*length);
45       if (buffer == NULL)
46         error (_f ("cannot allocate %lu bytes", *length));
47
48       error_code = FT_Load_Sfnt_Table (face, tag, 0, buffer, length);
49       if (error_code)
50         error (_f ("cannot load font table: %s", tag_str));
51
52       return buffer;
53     }
54   else
55     programming_error (_f ("FreeType error: %s",
56                            freetype_error_string (error_code).c_str ()
57                           ));
58
59   return 0;
60 }
61
62 string
63 Open_type_font::get_otf_table (const string &tag) const
64 {
65   return ::get_otf_table (face_, tag);
66 }
67
68 SCM
69 load_scheme_table (char const *tag_str, FT_Face face)
70 {
71   FT_ULong length = 0;
72   FT_Byte *buffer = load_table (tag_str, face, &length);
73
74   SCM tab = SCM_EOL;
75   if (buffer)
76     {
77       string contents ((char const *)buffer, length);
78       contents = "(quote (" + contents + "))";
79
80 #if GUILEV2
81       tab = scm_eval_string (scm_from_utf8_string (contents.c_str ()));
82 #else
83       tab = scm_c_eval_string (contents.c_str ());
84 #endif
85       free (buffer);
86     }
87   return tab;
88 }
89
90 Open_type_font::~Open_type_font ()
91 {
92   FT_Done_Face (face_);
93 }
94
95 /*
96   UGH fix naming
97 */
98 string
99 get_otf_table (FT_Face face, const string &tag)
100 {
101   FT_ULong len;
102   FT_Byte *tab = load_table (tag.c_str (), face, &len);
103   string ret ((char const *) tab, len);
104   free (tab);
105
106   return ret;
107 }
108
109 FT_Face
110 open_ft_face (const string &str, FT_Long idx)
111 {
112   FT_Face face;
113   FT_Error error_code = FT_New_Face (freetype2_library, str.c_str (), idx, &face);
114
115   if (error_code == FT_Err_Unknown_File_Format)
116     error (_f ("unsupported font format: %s", str.c_str ()));
117   else if (error_code)
118     error (_f ("error reading font file %s: %s",
119                str.c_str (),
120                freetype_error_string (error_code).c_str ()));
121   return face;
122 }
123
124 SCM
125 Open_type_font::make_otf (const string &str)
126 {
127   FT_Face face = open_ft_face (str, 0 /* index */);
128   Open_type_font *otf = new Open_type_font (face);
129
130   return otf->self_scm ();
131 }
132
133 Open_type_font::Open_type_font (FT_Face face)
134 {
135   face_ = face;
136   lily_character_table_ = SCM_EOL;
137   lily_global_table_ = SCM_EOL;
138   lily_subfonts_ = SCM_EOL;
139   lily_index_to_bbox_table_ = SCM_EOL;
140
141   lily_character_table_ = alist_to_hashq (load_scheme_table ("LILC", face_));
142   lily_global_table_ = alist_to_hashq (load_scheme_table ("LILY", face_));
143   lily_subfonts_ = load_scheme_table ("LILF", face_);
144   index_to_charcode_map_ = make_index_to_charcode_map (face_);
145
146   lily_index_to_bbox_table_ = scm_c_make_hash_table (257);
147 }
148
149 void
150 Open_type_font::derived_mark () const
151 {
152   scm_gc_mark (lily_character_table_);
153   scm_gc_mark (lily_global_table_);
154   scm_gc_mark (lily_subfonts_);
155   scm_gc_mark (lily_index_to_bbox_table_);
156 }
157
158 Offset
159 Open_type_font::attachment_point (const string &glyph_name) const
160 {
161   SCM sym = ly_symbol2scm (glyph_name.c_str ());
162   SCM entry = scm_hashq_ref (lily_character_table_, sym, SCM_BOOL_F);
163
164   Offset o;
165   if (scm_is_false (entry))
166     return o;
167
168   SCM char_alist = entry;
169   SCM att_scm = scm_cdr (scm_assq (ly_symbol2scm ("attachment"), char_alist));
170
171   return point_constant * ly_scm2offset (att_scm);
172 }
173
174 Box
175 Open_type_font::get_indexed_char_dimensions (size_t signed_idx) const
176 {
177   if (SCM_HASHTABLE_P (lily_index_to_bbox_table_))
178     {
179       SCM box = scm_hashq_ref (lily_index_to_bbox_table_,
180                                scm_from_unsigned_integer (signed_idx), SCM_BOOL_F);
181       Box *box_ptr = Box::unsmob (box);
182       if (box_ptr)
183         return *box_ptr;
184     }
185
186   if (SCM_HASHTABLE_P (lily_character_table_))
187     {
188       const size_t len = 256;
189       char name[len];
190       FT_Error code = FT_Get_Glyph_Name (face_, FT_UInt (signed_idx),
191                                          name, FT_UInt (len));
192       if (code)
193         warning (_f ("FT_Get_Glyph_Name () Freetype error: %s",
194                      freetype_error_string (code)));
195
196       SCM sym = ly_symbol2scm (name);
197       SCM alist = scm_hashq_ref (lily_character_table_, sym, SCM_BOOL_F);
198
199       if (scm_is_true (alist))
200         {
201           SCM bbox = scm_cdr (scm_assq (ly_symbol2scm ("bbox"), alist));
202
203           Box b;
204           b[X_AXIS][LEFT] = scm_to_double (scm_car (bbox));
205           bbox = scm_cdr (bbox);
206           b[Y_AXIS][LEFT] = scm_to_double (scm_car (bbox));
207           bbox = scm_cdr (bbox);
208           b[X_AXIS][RIGHT] = scm_to_double (scm_car (bbox));
209           bbox = scm_cdr (bbox);
210           b[Y_AXIS][RIGHT] = scm_to_double (scm_car (bbox));
211           bbox = scm_cdr (bbox);
212
213           b.scale (point_constant);
214
215           scm_hashq_set_x (lily_index_to_bbox_table_,
216                            scm_from_unsigned_integer (signed_idx),
217                            b.smobbed_copy ());
218           return b;
219         }
220     }
221
222   Box b = get_unscaled_indexed_char_dimensions (signed_idx);
223
224   b.scale (design_size () / Real (face_->units_per_EM));
225   return b;
226 }
227
228 Real
229 Open_type_font::get_units_per_EM () const
230 {
231   return face_->units_per_EM;
232 }
233
234 size_t
235 Open_type_font::name_to_index (string nm) const
236 {
237   char *nm_str = (char *) nm.c_str ();
238   if (FT_UInt idx = FT_Get_Name_Index (face_, nm_str))
239     return (size_t) idx;
240
241   return (size_t) - 1;
242 }
243
244 Box
245 Open_type_font::get_unscaled_indexed_char_dimensions (size_t signed_idx) const
246 {
247   return ly_FT_get_unscaled_indexed_char_dimensions (face_, signed_idx);
248 }
249
250 Box
251 Open_type_font::get_glyph_outline_bbox (size_t signed_idx) const
252 {
253   return ly_FT_get_glyph_outline_bbox (face_, signed_idx);
254 }
255
256 SCM
257 Open_type_font::get_glyph_outline (size_t signed_idx) const
258 {
259   return ly_FT_get_glyph_outline (face_, signed_idx);
260 }
261
262 size_t
263 Open_type_font::index_to_charcode (size_t i) const
264 {
265   map<FT_UInt, FT_ULong>::const_iterator iter;
266   iter = index_to_charcode_map_.find (FT_UInt (i));
267
268   if (iter != index_to_charcode_map_.end ())
269     return (size_t) iter->second;
270   else
271     {
272       programming_error ("Invalid index for character");
273       return 0;
274     }
275 }
276
277 size_t
278 Open_type_font::count () const
279 {
280   return index_to_charcode_map_.size ();
281 }
282
283 Real
284 Open_type_font::design_size () const
285 {
286   SCM entry = scm_hashq_ref (lily_global_table_,
287                              ly_symbol2scm ("design_size"),
288
289                              /*
290                                Hmm. Design size is arbitrary for
291                                non-design-size fonts. I vote for 1 -
292                                which will trip errors more
293                                quickly. --hwn.
294                              */
295                              scm_from_unsigned_integer (1));
296   return scm_to_double (entry) * Real (point_constant);
297 }
298
299 SCM
300 Open_type_font::sub_fonts () const
301 {
302   return lily_subfonts_;
303 }
304
305 SCM
306 Open_type_font::get_char_table () const
307 {
308   return lily_character_table_;
309 }
310
311 SCM
312 Open_type_font::get_subfonts () const
313 {
314   return lily_subfonts_;
315 }
316
317 SCM
318 Open_type_font::get_global_table () const
319 {
320   return lily_global_table_;
321 }
322
323 string
324 Open_type_font::font_name () const
325 {
326   return FT_Get_Postscript_Name (face_);
327 }
328
329 SCM
330 Open_type_font::glyph_list () const
331 {
332   SCM retval = SCM_EOL;
333   SCM *tail = &retval;
334
335   for (int i = 0; i < face_->num_glyphs; i++)
336     {
337       const size_t len = 256;
338       char name[len];
339       FT_Error code = FT_Get_Glyph_Name (face_, i, name, len);
340       if (code)
341         warning (_f ("FT_Get_Glyph_Name () error: %s",
342                      freetype_error_string (code).c_str ()));
343
344       *tail = scm_cons (scm_from_ascii_string (name), SCM_EOL);
345       tail = SCM_CDRLOC (*tail);
346     }
347
348   return retval;
349 }