]> git.donarmstrong.com Git - lilypond.git/blob - lily/open-type-font-scheme.cc
Web-ja: update introduction
[lilypond.git] / lily / open-type-font-scheme.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 <cstdio>
21 #include "international.hh"
22 #include "modified-font-metric.hh"
23 #include "open-type-font.hh"
24 #include "freetype.hh"
25
26 #ifdef FT_FONT_FORMATS_H
27 /* FreeType 2.6+ */
28 #include FT_FONT_FORMATS_H
29 #else
30 /* FreeType 2.5.5 and earlier */
31 #include FT_XFREE86_H
32 #define FT_Get_Font_Format FT_Get_X11_Font_Format
33 #endif
34
35 LY_DEFINE (ly_font_sub_fonts, "ly:font-sub-fonts", 1, 0, 0,
36            (SCM font),
37            "Given the font metric @var{font} of an OpenType font, return the"
38            " names of the subfonts within @var{font}.")
39 {
40   LY_ASSERT_SMOB (Font_metric, font, 1);
41
42   Font_metric *fm = unsmob<Font_metric> (font);
43   return fm->sub_fonts ();
44 }
45
46 LY_DEFINE (ly_otf_font_glyph_info, "ly:otf-font-glyph-info", 2, 0, 0,
47            (SCM font, SCM glyph),
48            "Given the font metric @var{font} of an OpenType font, return the"
49            " information about named glyph @var{glyph} (a string).")
50 {
51   Modified_font_metric *fm
52     = unsmob<Modified_font_metric> (font);
53   Open_type_font *otf = fm
54                         ? dynamic_cast<Open_type_font *> (fm->original_font ())
55                         : unsmob<Open_type_font> (font);
56
57   SCM_ASSERT_TYPE (otf, font, SCM_ARG1, __FUNCTION__, "OpenType font");
58   LY_ASSERT_TYPE (scm_is_string, glyph, 2);
59
60   SCM sym = scm_string_to_symbol (glyph);
61   return scm_hashq_ref (otf->get_char_table (), sym, SCM_EOL);
62 }
63
64 LY_DEFINE (ly_otf_font_table_data, "ly:otf-font-table-data", 2, 0, 0,
65            (SCM font, SCM tag),
66            "Extract a table @var{tag} from @var{font}.  Return empty string"
67            " for non-existent @var{tag}.")
68 {
69   Modified_font_metric *fm
70     = unsmob<Modified_font_metric> (font);
71   Open_type_font *otf = fm
72                         ? dynamic_cast<Open_type_font *> (fm->original_font ())
73                         : unsmob<Open_type_font> (font);
74
75   SCM_ASSERT_TYPE (otf, font, SCM_ARG1, __FUNCTION__, "OpenType font");
76   LY_ASSERT_TYPE (scm_is_string, tag, 2);
77
78   char ctag [5] = "    ";
79
80   string tag_string = ly_scm2string (tag);
81   strncpy (ctag, tag_string.c_str (), tag_string.length ());
82
83   string tab = otf->get_otf_table (string (ctag));
84
85   return scm_from_latin1_stringn ((char const *) tab.data (), tab.length ());
86 }
87
88 LY_DEFINE (ly_otf_font_p, "ly:otf-font?", 1, 0, 0,
89            (SCM font),
90            "Is @var{font} an OpenType font?")
91 {
92   Modified_font_metric *fm
93     = unsmob<Modified_font_metric> (font);
94   Open_type_font *otf = fm
95                         ? dynamic_cast<Open_type_font *> (fm->original_font ())
96                         : unsmob<Open_type_font> (font);
97
98   return scm_from_bool (otf);
99 }
100
101 LY_DEFINE (ly_otf_glyph_count, "ly:otf-glyph-count", 1, 0, 0,
102            (SCM font),
103            "Return the number of glyphs in @var{font}.")
104 {
105   Modified_font_metric *fm
106     = unsmob<Modified_font_metric> (font);
107   Open_type_font *otf = fm
108                         ? dynamic_cast<Open_type_font *> (fm->original_font ())
109                         : unsmob<Open_type_font> (font);
110
111   SCM_ASSERT_TYPE (otf, font, SCM_ARG1, __FUNCTION__, "OpenType font");
112
113   return scm_from_int ((int) otf->count ());
114 }
115
116 LY_DEFINE (ly_otf_glyph_list, "ly:otf-glyph-list", 1, 0, 0,
117            (SCM font),
118            "Return a list of glyph names for @var{font}.")
119 {
120   Modified_font_metric *fm
121     = unsmob<Modified_font_metric> (font);
122   Open_type_font *otf = fm
123                         ? dynamic_cast<Open_type_font *> (fm->original_font ())
124                         : unsmob<Open_type_font> (font);
125
126   SCM_ASSERT_TYPE (otf, font, SCM_ARG1, __FUNCTION__, "OpenType font");
127
128   return otf->glyph_list ();
129 }
130
131 LY_DEFINE (ly_get_font_format, "ly:get-font-format",
132            1, 1, 0, (SCM font_file_name, SCM idx),
133            "Get the font format for @var{font_file_name},"
134            " returning it as a symbol.  The optional"
135            " @var{idx} argument is useful for TrueType Collections (TTC) and"
136            " OpenType/CFF collections (OTC) only;"
137            " it specifies the font index within the TTC/OTC."
138            " The default value of @var{idx} is@tie{}0.")
139 {
140   LY_ASSERT_TYPE (scm_is_string, font_file_name, 1);
141
142   int i = 0;
143   if (!SCM_UNBNDP (idx))
144     {
145       LY_ASSERT_TYPE (scm_is_integer, idx, 2);
146       i = scm_to_int (idx);
147       if (i < 0)
148         {
149           warning (_ ("font index must be non-negative, using index 0"));
150           i = 0;
151         }
152     }
153
154   string file_name = ly_scm2string (font_file_name);
155
156   FT_Face face;
157   /* check whether font index is valid */
158   if (i > 0)
159     {
160       face = open_ft_face (file_name, -1);
161       if (i >= face->num_faces)
162         {
163           warning (_f ("font index %d too large for font `%s', using index 0",
164                        i, file_name.c_str ()));
165           i = 0;
166         }
167       FT_Done_Face (face);
168     }
169
170   face = open_ft_face (file_name, i);
171   SCM asscm = scm_from_ascii_symbol (FT_Get_Font_Format (face));
172   FT_Done_Face (face);
173
174   return asscm;
175 }
176
177 LY_DEFINE (ly_has_glyph_names_p, "ly:has-glyph-names?",
178            1, 1, 0, (SCM font_file_name, SCM idx),
179            "Does the font for @var{font_file_name} have glyph names?"
180            "  The optional @var{idx} argument is useful for"
181            " TrueType Collections (TTC) and"
182            " OpenType/CFF collections (OTC) only;"
183            " it specifies the font index within the TTC/OTC."
184            "  The default value of @var{idx} is@tie{}0.")
185 {
186   LY_ASSERT_TYPE (scm_is_string, font_file_name, 1);
187
188   int i = 0;
189   if (!SCM_UNBNDP (idx))
190     {
191       LY_ASSERT_TYPE (scm_is_integer, idx, 2);
192       i = scm_to_int (idx);
193       if (i < 0)
194         {
195           warning (_ ("font index must be non-negative, using index 0"));
196           i = 0;
197         }
198     }
199
200   string file_name = ly_scm2string (font_file_name);
201
202   FT_Face face;
203   /* check whether font index is valid */
204   if (i > 0)
205     {
206       face = open_ft_face (file_name, -1);
207       if (i >= face->num_faces)
208         {
209           warning (_f ("font index %d too large for font `%s', using index 0",
210                        i, file_name.c_str ()));
211           i = 0;
212         }
213       FT_Done_Face (face);
214     }
215
216   face = open_ft_face (file_name, i);
217   bool has_glyph_names = FT_HAS_GLYPH_NAMES(face);
218   FT_Done_Face (face);
219
220   return has_glyph_names ? SCM_BOOL_T : SCM_BOOL_F;
221 }
222
223 LY_DEFINE (ly_get_cff_offset, "ly:get-cff-offset",
224            1, 1, 0, (SCM font_file_name, SCM idx),
225            "Get the offset of 'CFF' table for @var{font_file_name},"
226            " returning it as an integer.  The optional"
227            " @var{idx} argument is useful for"
228            " OpenType/CFF collections (OTC) only;"
229            " it specifies the font index within the OTC."
230            "  The default value of @var{idx} is@tie{}0.")
231 {
232   LY_ASSERT_TYPE (scm_is_string, font_file_name, 1);
233
234   int i = 0;
235   if (!SCM_UNBNDP (idx))
236     {
237       LY_ASSERT_TYPE (scm_is_integer, idx, 2);
238       i = scm_to_int (idx);
239       if (i < 0)
240         {
241           warning (_ ("font index must be non-negative, using index 0"));
242           i = 0;
243         }
244     }
245
246   string file_name = ly_scm2string (font_file_name);
247
248   FILE *fp = fopen (file_name.c_str (), "rb");
249   if (!fp)
250     {
251       warning (_f ("cannot open font filename `%s'", file_name.c_str ()));
252       return SCM_BOOL_F;
253     }
254
255   char buff[4];
256
257   // Read `sfnt version` (for OTF) or `TTCTag` (for OTC)
258   if (fread (buff, 4, 1, fp) != 1)
259     {
260       fclose (fp);
261       warning (_f ("cannot read %s of `%s'", "header", file_name.c_str ()));
262       return SCM_BOOL_F;
263     }
264
265   if (buff[0] == 't' && buff[1] == 't' && buff[2] == 'c' && buff[3] == 'f')
266     {
267       // For OTC
268       // Find subfont
269
270       // Skip `Version`
271       fseek (fp, 4, SEEK_CUR);
272
273       // Read `numFonts`
274       if (fread (buff, 4, 1, fp) != 1)
275         {
276           fclose (fp);
277           warning (_f ("cannot read %s of `%s'",
278                        "numFonts", file_name.c_str ()));
279           return SCM_BOOL_F;
280         }
281       int numfonts =
282         static_cast<unsigned char>(buff[0]) << 24 |
283         static_cast<unsigned char>(buff[1]) << 16 |
284         static_cast<unsigned char>(buff[2]) << 8 |
285         static_cast<unsigned char>(buff[3]);
286
287       if ( i > numfonts )
288         {
289           warning (_f ("font index %d too large for font `%s', using index 0",
290                        i, file_name.c_str ()));
291           i = 0;
292         }
293
294       // Read `OffsetTable[i]`
295       if (i)
296         fseek (fp, i * 4, SEEK_CUR);
297       if (fread (buff, 4, 1, fp) != 1)
298         {
299           fclose (fp);
300           warning (_f ("cannot read %s of `%s'",
301                        "OffsetTable", file_name.c_str ()));
302           return SCM_BOOL_F;
303         }
304       unsigned int offset =
305         static_cast<unsigned char>(buff[0]) << 24 |
306         static_cast<unsigned char>(buff[1]) << 16 |
307         static_cast<unsigned char>(buff[2]) << 8 |
308         static_cast<unsigned char>(buff[3]);
309
310       // Seek to subfont and skip `sfnt version`
311       fseek (fp, offset + 4, SEEK_SET);
312     }
313
314   // For OTF or subfont of OTC
315
316   // Read `numTables`
317   if (fread (buff, 2, 1, fp) != 1)
318     {
319       fclose (fp);
320       warning (_f ("cannot read %s of `%s'",
321                    "numTables", file_name.c_str ()));
322       return SCM_BOOL_F;
323     }
324   int numtables =
325     static_cast<unsigned char>(buff[0]) << 8 |
326     static_cast<unsigned char>(buff[1]);
327
328   // Skip `searchRange`, `entrySelector` and `rangeShift`
329   fseek (fp, 6, SEEK_CUR);
330
331   // Read Table Records
332   for (int t = 0; t < numtables; t++)
333     {
334       // Read `tag`
335       if (fread (buff, 4, 1, fp) != 1)
336         {
337           fclose (fp);
338           warning (_f ("cannot read %s of `%s'",
339                        "tag", file_name.c_str ()));
340           return SCM_BOOL_F;
341         }
342
343       if (buff[0] == 'C' && buff[1] == 'F' && buff[2] == 'F' && buff[3] == ' ')
344         {
345           // CFF table is found.
346
347           // Skip `checkSum`
348           fseek (fp, 4, SEEK_CUR);
349
350           // Read `offset`
351           if (fread (buff, 4, 1, fp) != 1)
352             {
353               fclose (fp);
354               warning (_f ("cannot read %s of `%s'",
355                            "CFF offset", file_name.c_str ()));
356               return SCM_BOOL_F;
357             }
358           unsigned int offset =
359             static_cast<unsigned char>(buff[0]) << 24 |
360             static_cast<unsigned char>(buff[1]) << 16 |
361             static_cast<unsigned char>(buff[2]) << 8 |
362             static_cast<unsigned char>(buff[3]);
363
364           // Done
365           fclose (fp);
366           return scm_from_unsigned_integer (offset);
367         }
368
369       // For non-CFF table
370
371       // Skip `checkSum`, `offset` and `length`
372       fseek (fp, 12, SEEK_CUR);
373     }
374
375   fclose (fp);
376   warning (_f ("font `%s' index %d does not have `CFF' table",
377                file_name.c_str (), i));
378   return SCM_BOOL_F;
379 }