]> git.donarmstrong.com Git - lilypond.git/blob - lily/ttf.cc
Both ly:ttf-ps-name and ly:ttf->pfa now handle font index.
[lilypond.git] / lily / ttf.cc
1 /*
2   ttf.cc --  implement ttf -> pfa routine.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include <cstdio>
10 #include "freetype.hh"
11
12 #include <freetype/tttables.h>
13
14 #include "international.hh"
15 #include "memory-stream.hh"
16 #include "warn.hh"
17 #include "lily-guile.hh"
18 #include "main.hh"
19 #include "open-type-font.hh"
20
21
22 Index_to_charcode_map
23 make_index_to_charcode_map (FT_Face face)
24 {
25   Index_to_charcode_map m;
26   FT_ULong charcode;
27   FT_UInt gindex;
28
29   FT_CharMap current_cmap = face->charmap;
30   FT_Select_Charmap (face, FT_ENCODING_UNICODE);
31
32   int j = 0;
33   for (charcode = FT_Get_First_Char (face, &gindex); gindex != 0;
34        charcode = FT_Get_Next_Char (face, charcode, &gindex))
35     {
36       m[gindex] = charcode;
37       j ++;
38     }
39   FT_Set_Charmap (face, current_cmap);
40
41   return m;
42 }
43
44 /*
45   Based on ttfps by Juliusz Chroboczek
46 */
47 static void
48 print_header (void *out, FT_Face face)
49 {
50   lily_cookie_fprintf (out, "%%!PS-TrueTypeFont\n");
51
52   TT_Postscript *pt
53     = (TT_Postscript *) FT_Get_Sfnt_Table (face, ft_sfnt_post);
54
55   if (pt->maxMemType42)
56     lily_cookie_fprintf (out, "%%%%VMUsage: %d %d\n", 0, 0);
57
58   lily_cookie_fprintf (out, "%d dict begin\n", 11);
59   lily_cookie_fprintf (out, "/FontName /%s def\n",
60                        FT_Get_Postscript_Name (face));
61
62   lily_cookie_fprintf (out, "/Encoding StandardEncoding def\n");
63   lily_cookie_fprintf (out, "/PaintType 0 def\n");
64   lily_cookie_fprintf (out, "/FontMatrix [1 0 0 1 0 0] def\n");
65
66   TT_Header *ht
67     = (TT_Header *)FT_Get_Sfnt_Table (face, ft_sfnt_head);
68
69   lily_cookie_fprintf (out, "/FontBBox [%lf %lf %lf %lf] def\n",
70                        float (ht->xMin) / ht->Units_Per_EM,
71                        float (ht->yMin) / ht->Units_Per_EM,
72                        float (ht->xMax) / ht->Units_Per_EM,
73                        float (ht->yMax) / ht->Units_Per_EM);
74
75   lily_cookie_fprintf (out, "/FontType 42 def\n");
76   lily_cookie_fprintf (out, "/FontInfo 8 dict dup begin\n");
77   lily_cookie_fprintf (out, "/version (%.3f) def\n",
78                        ht->Font_Revision / 65536.0);
79
80 #if 0
81   if (strings[0])
82     {
83       lily_cookie_fprintf (out, "/Notice (");
84       fputpss (strings[0], out);
85       lily_cookie_fprintf (out, ") def\n");
86     }
87   if (strings[4])
88     {
89       lily_cookie_fprintf (out, "/FullName (");
90       fputpss (strings[4], out);
91       lily_cookie_fprintf (out, ") def\n");
92     }
93   if (strings[1])
94     {
95       lily_cookie_fprintf (out, "/FamilyName (");
96       fputpss (strings[1], out);
97       lily_cookie_fprintf (out, ") def\n");
98     }
99 #endif
100
101   lily_cookie_fprintf (out, "/isFixedPitch %s def\n",
102                        pt->isFixedPitch ? "true" : "false");
103   lily_cookie_fprintf (out, "/UnderlinePosition %lf def\n",
104                        float (pt->underlinePosition) / ht->Units_Per_EM);
105   lily_cookie_fprintf (out, "/UnderlineThickness %lf def\n",
106                        float (pt->underlineThickness) / ht->Units_Per_EM);
107   lily_cookie_fprintf (out, "end readonly def\n");
108 }
109
110 #define CHUNKSIZE 65534
111
112 const FT_ULong FT_ENC_TAG (glyf_tag, 'g', 'l', 'y', 'f');
113 const FT_ULong FT_ENC_TAG (head_tag, 'h', 'e', 'a', 'd');
114 const FT_ULong FT_ENC_TAG (loca_tag, 'l', 'o', 'c', 'a');
115
116 static
117 void t42_write_table (void *out, FT_Face face, unsigned char const *buffer,
118                       size_t s, bool is_glyf,
119                       FT_ULong head_length, FT_ULong loca_length)
120 {
121   vector<FT_UShort> chunks;
122
123   if (is_glyf)
124     {
125       /* compute chunk sizes */
126       unsigned char *head_buf = new unsigned char[head_length];
127       FT_Error error = FT_Load_Sfnt_Table (face, head_tag, 0, head_buf, NULL);
128       if (error)
129         programming_error ("FT_Load_Sfnt_Table (): error.");
130
131       /* we access the lower byte of indexToLocFormat */
132       bool long_offsets = head_buf[4*4 + 2*2 + 2*8 + 4*2 + 3*2 + 1] == 1;
133
134       delete[] head_buf;
135
136       unsigned char *loca_buf = new unsigned char[loca_length];
137       error = FT_Load_Sfnt_Table (face, loca_tag, 0, loca_buf, NULL);
138       if (error)
139         programming_error ("FT_Load_Sfnt_Table (): error.");
140
141       unsigned char *p = loca_buf;
142       unsigned char *endp = loca_buf + loca_length;
143
144       FT_ULong offset = 0, last_offset = 0, last_chunk = 0;
145       while (p < endp)
146       {
147         if (long_offsets)
148           {
149             offset = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
150             p += 4;
151           }
152         else
153           {
154             offset = ((p[0] << 8) | p[1]) << 1;
155             p += 2;
156           }
157         if (offset > last_offset + CHUNKSIZE)
158           {
159             if (last_chunk != last_offset)
160               chunks.push_back (last_offset - last_chunk);
161             /*
162               a single glyph with more than 64k data
163               is a pathological case but...
164              */
165             FT_ULong rest = offset - last_offset;
166             while (rest > CHUNKSIZE)
167               {
168                 chunks.push_back (CHUNKSIZE);
169                 rest -= CHUNKSIZE;
170               }
171             chunks.push_back (rest);
172             last_chunk = offset;
173           }
174         else if (offset > last_chunk + CHUNKSIZE)
175           {
176             chunks.push_back (last_offset - last_chunk);
177             last_chunk = last_offset;
178           }
179
180         last_offset = offset;
181       }
182       chunks.push_back (s - last_chunk);
183
184       delete[] loca_buf;
185     }
186   else if (s > CHUNKSIZE)
187     {
188       FT_ULong rest = s;
189       while (rest > CHUNKSIZE)
190         {
191           chunks.push_back (CHUNKSIZE);
192           rest -= CHUNKSIZE;
193         }
194       chunks.push_back (rest);
195     }
196   else
197     chunks.push_back (CHUNKSIZE);
198
199   lily_cookie_fprintf (out, "\n"
200                             " <");
201
202   int l = 0;
203   static char xdigits[] = "0123456789ABCDEF";
204
205   int cur_chunk_idx = 0;
206   for (size_t j = 0; j < s; j++)
207     {
208       if (l >= chunks[cur_chunk_idx])
209         {
210           lily_cookie_fprintf (out, "\n"
211                                     " 00>\n"
212                                     " <");
213           l = 0;
214           cur_chunk_idx ++;
215         }
216
217       if (l % 31 == 0)
218         lily_cookie_fprintf (out, "\n"
219                                   "  ");
220
221       /* lily_cookie_fprintf (out,"%02X",(int)buffer[j]) is too slow */
222       lily_cookie_putc (xdigits[(buffer[j] & 0xF0) >> 4], out);
223       lily_cookie_putc (xdigits[buffer[j] & 0x0F], out);
224
225       l ++;
226     }
227
228   /* pad to four-byte boundary */
229   while ((s ++) % 4 != 0)
230     lily_cookie_fprintf (out, "00");
231
232   lily_cookie_fprintf (out, "\n"
233                             "  00\n"
234                             " >");
235 }
236
237 static void
238 print_body (void *out, FT_Face face)
239 {
240   FT_UInt idx = 0;
241   FT_ULong head_length = 0, loca_length = 0;
242   FT_ULong tag, length;
243   vector<FT_ULong> lengths, tags;
244
245   /*
246     we must build our own TTF header -- the original font
247     might be a TTC where tables are not contiguous, or the font
248     contains tables which aren't indexed at all
249    */
250   while (FT_Sfnt_Table_Info (face, idx, &tag, &length)
251          != FT_Err_Table_Missing)
252   {
253     lengths.push_back (length);
254     tags.push_back (tag);
255     if (tag == head_tag)
256       head_length = length;
257     else if (tag == loca_tag)
258       loca_length = length;
259     idx ++;
260   }
261
262   FT_ULong hlength = 12 + 16 * idx;
263
264   unsigned char *hbuf = new unsigned char[hlength];
265   unsigned char *p;
266
267   hbuf[0] = 0x00;                       /* version */
268   hbuf[1] = 0x01;
269   hbuf[2] = 0x00;
270   hbuf[3] = 0x00;
271   hbuf[4] = (idx & 0xFF00) >> 8;        /* numTables */
272   hbuf[5] = idx & 0x00FF;
273
274   FT_UInt searchRange, entrySelector, rangeShift;
275   FT_UInt i, j;
276   for (i = 1, j = 2; j <= idx; i++, j <<= 1)
277     ;
278   entrySelector = i - 1;
279   searchRange = 0x10 << entrySelector;
280   rangeShift = (idx << 4) - searchRange;
281
282   hbuf[6] = (searchRange & 0xFF00) >> 8;
283   hbuf[7] = searchRange & 0x00FF;
284   hbuf[8] = (entrySelector & 0xFF00) >> 8;
285   hbuf[9] = entrySelector & 0x00FF;
286   hbuf[10] = (rangeShift & 0xFF00) >> 8;
287   hbuf[11] = rangeShift & 0x00FF;
288
289   p = &hbuf[12];
290
291   FT_ULong checksum, font_checksum = 0;
292
293   FT_ULong offset = hlength;            /* first table offset */
294
295   for (FT_UInt i = 0; i < idx; i++)
296   {
297     /* here, the buffer length must be a multiple of 4 */
298     FT_ULong len = (lengths[i] + 3) & ~3;
299     unsigned char *buf = new unsigned char[len];
300
301     buf[len - 1] = 0x00;                /* assure padding with zeros */
302     buf[len - 2] = 0x00;
303     buf[len - 3] = 0x00;
304
305     FT_Error error = FT_Load_Sfnt_Table (face, tags[i], 0, buf, NULL);
306     if (error)
307       programming_error ("FT_Load_Sfnt_Table (): error.");
308
309     if (tag == head_tag)
310       {
311         /*
312           first pass of computing the font checksum
313           needs checkSumAdjustment = 0
314          */
315         buf[8] = 0x00;
316         buf[9] = 0x00;
317         buf[10] = 0x00;
318         buf[11] = 0x00;
319       }
320
321     checksum = 0;
322     unsigned char *endq = buf + len;
323     for (unsigned char *q = buf; q < endq; q += 4)
324       checksum += (q[0] << 24) | (q[1] << 16) | (q[2] << 8) | q[3];
325     font_checksum += checksum;
326
327     delete[] buf;
328
329     *(p++) = (tags[i] & 0xFF000000UL) >> 24;
330     *(p++) = (tags[i] & 0x00FF0000UL) >> 16;
331     *(p++) = (tags[i] & 0x0000FF00UL) >> 8;
332     *(p++) = tags[i] & 0x000000FFUL;
333
334     *(p++) = (checksum & 0xFF000000UL) >> 24;
335     *(p++) = (checksum & 0x00FF0000UL) >> 16;
336     *(p++) = (checksum & 0x0000FF00UL) >> 8;
337     *(p++) = checksum & 0x000000FFUL;
338
339     *(p++) = (offset & 0xFF000000UL) >> 24;
340     *(p++) = (offset & 0x00FF0000UL) >> 16;
341     *(p++) = (offset & 0x0000FF00UL) >> 8;
342     *(p++) = offset & 0x000000FFUL;
343
344     *(p++) = (lengths[i] & 0xFF000000UL) >> 24;
345     *(p++) = (lengths[i] & 0x00FF0000UL) >> 16;
346     *(p++) = (lengths[i] & 0x0000FF00UL) >> 8;
347     *(p++) = lengths[i] & 0x000000FFUL;
348
349     /* offset must be a multiple of 4 */
350     offset += (lengths[i] + 3) & ~3;
351   }
352
353   /* add checksum of TTF header */
354   checksum = 0;
355   for (unsigned char *q = hbuf; q < p; q += 4)
356     checksum += (q[0] << 24) | (q[1] << 16) | (q[2] << 8) | q[3];
357   font_checksum += checksum;
358   font_checksum = 0xB1B0AFBAUL - font_checksum;
359
360   /*
361     see Adobe technical note 5012.Type42_Spec.pdf for details how
362     the /sfnts array must be constructed
363    */
364   lily_cookie_fprintf (out, "/sfnts [");
365   t42_write_table (out, face, hbuf, hlength, false,
366                    head_length, loca_length);
367   delete[] hbuf;
368
369   idx = 0;
370
371   while (FT_Sfnt_Table_Info (face, idx, &tag, &length)
372          != FT_Err_Table_Missing)
373     {
374       unsigned char *buf = new unsigned char[length];
375       FT_Error error = FT_Load_Sfnt_Table (face, tag, 0, buf, NULL);
376       if (error)
377         programming_error ("FT_Load_Sfnt_Table (): error.");
378
379       if (tag == head_tag)
380         {
381           /* in the second pass simply store the computed font checksum */
382           buf[8] = (font_checksum & 0xFF000000UL) >> 24;
383           buf[9] = (font_checksum & 0x00FF0000UL) >> 16;
384           buf[10] = (font_checksum & 0x0000FF00UL) >> 8;
385           buf[11] = font_checksum & 0x000000FFUL;
386         }
387
388       bool is_glyf_table = tag == glyf_tag && length > CHUNKSIZE;
389       t42_write_table (out, face, buf, length, is_glyf_table,
390                        head_length, loca_length);
391
392       delete[] buf;
393       idx ++;
394     }
395   lily_cookie_fprintf (out, "\n] def\n");
396 }
397
398 static void
399 print_trailer (void *out,
400                FT_Face face)
401 {
402   const int GLYPH_NAME_LEN = 256;
403   char glyph_name[GLYPH_NAME_LEN];
404
405   TT_MaxProfile *mp
406     = (TT_MaxProfile *)FT_Get_Sfnt_Table (face, ft_sfnt_maxp);
407
408   lily_cookie_fprintf (out, "/CharStrings %d dict dup begin\n", mp->numGlyphs);
409
410   Index_to_charcode_map ic_map (make_index_to_charcode_map (face));
411
412   int output_count = 0;
413   for (int i = 0; i < mp->numGlyphs; i++)
414     {
415       glyph_name[0] = 0;
416       if (face->face_flags & FT_FACE_FLAG_GLYPH_NAMES)
417         {
418           FT_Error error = FT_Get_Glyph_Name (face, i, glyph_name,
419                                               GLYPH_NAME_LEN);
420           if (error)
421             {
422               programming_error ("FT_Get_Glyph_Name (): error.");
423               glyph_name[0] = 0;
424             }
425         }
426
427       if (!glyph_name[0] && ic_map.find (i) != ic_map.end ())
428         {
429           FT_ULong ucode = ic_map[i];
430           get_unicode_name (glyph_name, ucode);
431         }
432
433       if (i == 0)
434         sprintf (glyph_name, ".notdef");
435       else if (glyph_name == string (".notdef"))
436         glyph_name[0] = '\0';
437
438       if (!glyph_name[0])
439         get_glyph_index_name (glyph_name, i);
440
441       if (glyph_name[0])
442         {
443           lily_cookie_fprintf (out, "/%s %d def ", glyph_name, i);
444           output_count ++;
445         }
446       else
447         programming_error (to_string ("no name for glyph %d", i));
448                         
449       if (! (output_count % 5))
450         lily_cookie_fprintf (out, "\n");
451     }
452
453   lily_cookie_fprintf (out, "end readonly def\n");
454   lily_cookie_fprintf (out, "FontName currentdict end definefont pop\n");
455 }
456
457 static void
458 create_type42_font (void *out, string name, int idx)
459 {
460   FT_Face face;
461
462   /* check whether font index is valid */
463   if (idx > 0)
464     {
465       face = open_ft_face (name, -1);
466       if (idx >= face->num_faces)
467         {
468           warning (_f ("font index %d too large for font `%s', using index 0",
469                        idx, name.c_str()));
470           idx = 0;
471         }
472       FT_Done_Face (face);
473     }
474
475   face = open_ft_face (name, idx);
476
477   print_header (out, face);
478   print_body (out, face);
479   print_trailer (out, face);
480
481   FT_Done_Face (face);
482 }
483
484 LY_DEFINE (ly_ttf_ps_name, "ly:ttf-ps-name",
485            1, 1, 0, (SCM ttf_file_name, SCM idx),
486            "Extract the PostScript name from a TrueType font.  The optional"
487            " @var{idx} argument is useful for TrueType collections (TTC)"
488            " only; it specifies the font index within the TTC.  The default"
489            " value of @var{idx} is@tie{}0.")
490 {
491   LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
492
493   int i = 0;
494   if (idx != SCM_UNDEFINED)
495     {
496       LY_ASSERT_TYPE (scm_is_integer, idx, 2);
497       i = scm_to_int (idx);
498       if (i < 0)
499         {
500           warning (_ ("font index must be non-negative, using index 0"));
501           i = 0;
502         }
503     }
504
505   string file_name = ly_scm2string (ttf_file_name);
506   if (be_verbose_global)
507     progress_indication ("[" + file_name);
508
509   FT_Face face;
510
511   /* check whether font index is valid */
512   if (i > 0)
513     {
514       face = open_ft_face (file_name, -1);
515       if (i >= face->num_faces)
516         {
517           warning (_f ("font index %d too large for font `%s', using index 0",
518                        i, file_name.c_str()));
519           i = 0;
520         }
521       FT_Done_Face (face);
522     }
523
524   face = open_ft_face (file_name, i);
525   char const *ps_name_str0 = FT_Get_Postscript_Name (face);
526   SCM ps_name = scm_from_locale_string (ps_name_str0 ? ps_name_str0 : "");
527   FT_Done_Face (face);
528
529   if (be_verbose_global)
530     progress_indication ("]");
531
532   return ps_name;
533 }
534
535 LY_DEFINE (ly_ttf_2_pfa, "ly:ttf->pfa",
536            1, 1, 0, (SCM ttf_file_name, SCM idx),
537            "Convert the contents of a TrueType font file to PostScript"
538            " Type@tie{}42 font, returning it as a string.  The optional"
539            " @var{idx} argument is useful for TrueType collections (TTC)"
540            " only; it specifies the font index within the TTC.  The default"
541            " value of @var{idx} is@tie{}0.")
542 {
543   LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
544
545   int i = 0;
546   if (idx != SCM_UNDEFINED)
547     {
548       LY_ASSERT_TYPE (scm_is_integer, idx, 2);
549       i = scm_to_int (idx);
550       if (i < 0)
551         {
552           warning (_ ("font index must be non-negative, using index 0"));
553           i = 0;
554         }
555     }
556
557   string file_name = ly_scm2string (ttf_file_name);
558   if (be_verbose_global)
559     progress_indication ("[" + file_name);
560
561   Memory_out_stream stream;
562
563   create_type42_font (&stream, file_name, i);
564   SCM asscm = scm_from_locale_stringn (stream.get_string (),
565                                        stream.get_length ());
566
567   if (be_verbose_global)
568     progress_indication ("]");
569
570   return asscm;
571 }