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