]> git.donarmstrong.com Git - lilypond.git/blob - lily/open-type-font.cc
* flower/include/international.hh: Bugfix: include "string.hh".
[lilypond.git] / lily / open-type-font.cc
1 /*
2   open-type-font.cc -- implement Open_type_font
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004--2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "open-type-font.hh"
10
11 #include <freetype/tttables.h>
12 #include <stdio.h>
13
14 #include "dimensions.hh"
15 #include "modified-font-metric.hh"
16 #include "warn.hh"
17
18 FT_Byte *
19 load_table (char const *tag_str, FT_Face face, FT_ULong *length)
20 {
21   FT_ULong tag = FT_MAKE_TAG (tag_str[0], tag_str[1], tag_str[2], tag_str[3]);
22
23   int error_code = FT_Load_Sfnt_Table (face, tag, 0, NULL, length);
24   if (!error_code)
25     {
26       FT_Byte *buffer = (FT_Byte *) malloc (*length);
27       if (buffer == NULL)
28         error (_f ("can't allocate %d bytes", *length));
29
30       error_code = FT_Load_Sfnt_Table (face, tag, 0, buffer, length);
31       if (error_code)
32         error (_f ("can't load font table: %s", tag_str));
33
34       return buffer;
35     }
36
37   return 0;
38 }
39
40 SCM
41 load_scheme_table (char const *tag_str, FT_Face face)
42 {
43   FT_ULong length = 0;
44   FT_Byte *buffer = load_table (tag_str, face, &length);
45
46   SCM tab = SCM_EOL;
47   if (buffer)
48     {
49       String contents ((Byte const *)buffer, length);
50       contents = "(quote (" + contents + "))";
51
52       tab = scm_c_eval_string (contents.to_str0 ());
53       free (buffer);
54     }
55   return tab;
56 }
57
58 Index_to_charcode_map
59 make_index_to_charcode_map (FT_Face face)
60 {
61   Index_to_charcode_map m;
62   FT_ULong charcode;
63   FT_UInt gindex;
64
65   for (charcode = FT_Get_First_Char (face, &gindex); gindex != 0;
66        charcode = FT_Get_Next_Char (face, charcode, &gindex))
67     m[gindex] = charcode;
68   return m;
69 }
70
71 Open_type_font::~Open_type_font ()
72 {
73   FT_Done_Face (face_);
74 }
75
76 SCM
77 Open_type_font::make_otf (String str)
78 {
79   FT_Face face;
80   int error_code = FT_New_Face (freetype2_library, str.to_str0 (), 0, &face);
81
82   if (error_code == FT_Err_Unknown_File_Format)
83     error (_f ("unsupported font format: %s", str.to_str0 ()));
84   else if (error_code)
85     error (_f ("unknown error: %d reading font file: %s", error_code,
86                str.to_str0 ()));
87
88   Open_type_font *otf = new Open_type_font (face);
89
90   return otf->self_scm ();
91 }
92
93 Open_type_font::Open_type_font (FT_Face face)
94 {
95   face_ = face;
96   lily_character_table_ = SCM_EOL;
97   lily_global_table_ = SCM_EOL;
98   lily_subfonts_ = SCM_EOL;
99
100   lily_character_table_ = alist_to_hashq (load_scheme_table ("LILC", face_));
101   lily_global_table_ = alist_to_hashq (load_scheme_table ("LILY", face_));
102   lily_subfonts_ = load_scheme_table ("LILF", face_);
103   index_to_charcode_map_ = make_index_to_charcode_map (face_);
104 }
105
106 void
107 Open_type_font::derived_mark () const
108 {
109   scm_gc_mark (lily_character_table_);
110   scm_gc_mark (lily_global_table_);
111   scm_gc_mark (lily_subfonts_);
112 }
113
114 Offset
115 Open_type_font::attachment_point (String glyph_name) const
116 {
117   SCM sym = ly_symbol2scm (glyph_name.to_str0 ());
118   SCM entry = scm_hashq_ref (lily_character_table_, sym, SCM_BOOL_F);
119
120   Offset o;
121   if (entry == SCM_BOOL_F)
122     return o;
123
124   SCM char_alist = entry;
125   SCM att_scm = scm_cdr (scm_assq (ly_symbol2scm ("attachment"), char_alist));
126
127   return point_constant * ly_scm2offset (att_scm);
128 }
129
130 Box
131 Open_type_font::get_indexed_char (int signed_idx) const
132 {
133   if (SCM_HASHTABLE_P (lily_character_table_))
134     {
135       const int len = 256;
136       char name[len];
137       int code = FT_Get_Glyph_Name (face_, signed_idx, name, len);
138       if (code)
139         warning (_f ("FT_Get_Glyph_Name() returned error: %d", code));
140
141       SCM sym = ly_symbol2scm (name);
142       SCM alist = scm_hashq_ref (lily_character_table_, sym, SCM_BOOL_F);
143
144       if (alist != SCM_BOOL_F)
145         {
146           SCM bbox = scm_cdr (scm_assq (ly_symbol2scm ("bbox"), alist));
147
148           Box b;
149           b[X_AXIS][LEFT] = scm_to_double (scm_car (bbox));
150           bbox = scm_cdr (bbox);
151           b[Y_AXIS][LEFT] = scm_to_double (scm_car (bbox));
152           bbox = scm_cdr (bbox);
153           b[X_AXIS][RIGHT] = scm_to_double (scm_car (bbox));
154           bbox = scm_cdr (bbox);
155           b[Y_AXIS][RIGHT] = scm_to_double (scm_car (bbox));
156           bbox = scm_cdr (bbox);
157
158           b.scale (point_constant);
159           return b;
160         }
161     }
162
163   FT_UInt idx = signed_idx;
164   FT_Load_Glyph (face_,
165                  idx,
166                  FT_LOAD_NO_SCALE);
167
168   FT_Glyph_Metrics m = face_->glyph->metrics;
169   int hb = m.horiBearingX;
170   int vb = m.horiBearingY;
171   Box b (Interval (-hb, m.width - hb),
172          Interval (-vb, m.height - vb));
173
174   b.scale (design_size () / Real (face_->units_per_EM));
175   return b;
176 }
177
178 int
179 Open_type_font::name_to_index (String nm) const
180 {
181   char *nm_str = (char *) nm.to_str0 ();
182   if (int idx = FT_Get_Name_Index (face_, nm_str))
183     return idx;
184   return -1;
185 }
186
187 unsigned
188 Open_type_font::index_to_charcode (int i) const
189 {
190   return ((Open_type_font *) this)->index_to_charcode_map_[i];
191 }
192
193 int
194 Open_type_font::count () const
195 {
196   return ((Open_type_font *) this)->index_to_charcode_map_.size ();
197 }
198
199 Real
200 Open_type_font::design_size () const
201 {
202   SCM entry = scm_hashq_ref (lily_global_table_,
203                              ly_symbol2scm ("design_size"),
204
205                              /*
206                                Hmm. Design size is arbitrary for
207                                non-design-size fonts. I vote for 1 -
208                                which will trip errors more
209                                quickly. --hwn.
210                              */
211                              scm_from_int (1));
212   return scm_to_double (entry) * Real (point_constant);
213 }
214
215 SCM
216 Open_type_font::sub_fonts () const
217 {
218   return lily_subfonts_;
219 }
220
221 SCM
222 Open_type_font::get_char_table () const
223 {
224   return lily_character_table_;
225 }
226
227 SCM
228 Open_type_font::get_subfonts () const
229 {
230   return lily_subfonts_;
231 }
232
233 SCM
234 Open_type_font::get_global_table () const
235 {
236   return lily_global_table_;
237 }
238
239 String
240 Open_type_font::font_name () const
241 {
242   return FT_Get_Postscript_Name (face_);
243 }
244