]> git.donarmstrong.com Git - lilypond.git/blob - lily/ttf.cc
Fix compile
[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--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "freetype.hh"
10
11 #include <freetype/tttables.h>
12
13 #include "memory-stream.hh"
14 #include "warn.hh"
15 #include "lily-guile.hh"
16 #include "main.hh"
17 #include "open-type-font.hh"
18
19
20 Index_to_charcode_map
21 make_index_to_charcode_map (FT_Face face)
22 {
23   Index_to_charcode_map m;
24   FT_ULong charcode;
25   FT_UInt gindex;
26
27   FT_CharMap current_cmap = face->charmap;
28   FT_Select_Charmap (face, FT_ENCODING_UNICODE);
29
30   int j = 0;
31   for (charcode = FT_Get_First_Char (face, &gindex); gindex != 0;
32        charcode = FT_Get_Next_Char (face, charcode, &gindex))
33     {
34       m[gindex] = charcode;
35       j ++;
36     }
37   FT_Set_Charmap (face, current_cmap);
38
39   return m;
40 }
41
42 /*
43   Based on ttfps by Juliusz Chroboczek
44 */
45 static void
46 print_header (void *out, FT_Face face)
47 {
48   lily_cookie_fprintf (out, "%%!PS-TrueTypeFont\n");
49
50   TT_Postscript *pt
51     = (TT_Postscript *) FT_Get_Sfnt_Table (face, ft_sfnt_post);
52
53   if (pt->maxMemType42)
54     lily_cookie_fprintf (out, "%%%%VMUsage: %d %d\n", 0, 0);
55
56   lily_cookie_fprintf (out, "%d dict begin\n", 11);
57   lily_cookie_fprintf (out, "/FontName /%s def\n",
58                        FT_Get_Postscript_Name (face));
59
60   lily_cookie_fprintf (out, "/Encoding StandardEncoding def\n");
61   lily_cookie_fprintf (out, "/PaintType 0 def\n");
62   lily_cookie_fprintf (out, "/FontMatrix [1 0 0 1 0 0] def\n");
63
64   TT_Header *ht
65     = (TT_Header *)FT_Get_Sfnt_Table (face, ft_sfnt_head);
66
67   lily_cookie_fprintf (out, "/FontBBox [%lf %lf %lf %lf] def\n",
68                        float (ht->xMin) / ht->Units_Per_EM,
69                        float (ht->yMin) / ht->Units_Per_EM,
70                        float (ht->xMax) / ht->Units_Per_EM,
71                        float (ht->yMax) / ht->Units_Per_EM);
72
73   lily_cookie_fprintf (out, "/FontType 42 def\n");
74   lily_cookie_fprintf (out, "/FontInfo 8 dict dup begin\n");
75   lily_cookie_fprintf (out, "/version (%.3f) def\n",
76                        ht->Font_Revision / 65536.0);
77
78 #if 0
79   if (strings[0])
80     {
81       lily_cookie_fprintf (out, "/Notice (");
82       fputpss (strings[0], out);
83       lily_cookie_fprintf (out, ") def\n");
84     }
85   if (strings[4])
86     {
87       lily_cookie_fprintf (out, "/FullName (");
88       fputpss (strings[4], out);
89       lily_cookie_fprintf (out, ") def\n");
90     }
91   if (strings[1])
92     {
93       lily_cookie_fprintf (out, "/FamilyName (");
94       fputpss (strings[1], out);
95       lily_cookie_fprintf (out, ") def\n");
96     }
97 #endif
98
99   lily_cookie_fprintf (out, "/isFixedPitch %s def\n",
100                        pt->isFixedPitch ? "true" : "false");
101   lily_cookie_fprintf (out, "/UnderlinePosition %lf def\n",
102                        float (pt->underlinePosition) / ht->Units_Per_EM);
103   lily_cookie_fprintf (out, "/UnderlineThickness %lf def\n",
104                        float (pt->underlineThickness) / ht->Units_Per_EM);
105   lily_cookie_fprintf (out, "end readonly def\n");
106 }
107
108 #define CHUNKSIZE 65534
109
110 const FT_ULong FT_ENC_TAG (glyf_tag, 'g', 'l', 'y', 'f');
111 const FT_ULong FT_ENC_TAG (head_tag, 'h', 'e', 'a', 'd');
112 const FT_ULong FT_ENC_TAG (loca_tag, 'l', 'o', 'c', 'a');
113
114 static
115 void t42_write_table (void *out, FT_Face face, unsigned char const *buffer,
116                       size_t s, bool is_glyf,
117                       FT_ULong head_length, FT_ULong loca_length)
118 {
119   vector<FT_UShort> chunks;             /* FIXME: use dynamic array */
120
121   if (is_glyf)
122     {
123       /* compute chunk sizes */
124       unsigned char *head_buf = new unsigned char[head_length];
125       FT_Error error = FT_Load_Sfnt_Table (face, head_tag, 0, head_buf, NULL);
126       if (error)
127         programming_error ("FT_Load_Sfnt_Table (): error.");
128
129       /* we access the lower byte of indexToLocFormat */
130       bool long_offsets = head_buf[4*4 + 2*2 + 2*8 + 4*2 + 3*2 + 1] == 1;
131
132       delete[] head_buf;
133
134       unsigned char *loca_buf = new unsigned char[loca_length];
135       error = FT_Load_Sfnt_Table (face, loca_tag, 0, loca_buf, NULL);
136       if (error)
137         programming_error ("FT_Load_Sfnt_Table (): error.");
138
139       unsigned char *p = loca_buf;
140       unsigned char *endp = loca_buf + loca_length;
141
142       FT_ULong offset = 0, last_offset = 0, last_chunk = 0;
143       while (p < endp)
144       {
145         if (long_offsets)
146           {
147             offset = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
148             p += 4;
149           }
150         else
151           {
152             offset = ((p[0] << 8) | p[1]) << 1;
153             p += 2;
154           }
155         if (offset > last_offset + CHUNKSIZE)
156           {
157             if (last_chunk != last_offset)
158               {
159                 chunks.push_back (last_offset - last_chunk);
160               }
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   FT_ULong lengths[100], tags[100];     /* FIXME: use dynamic arrays */
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     assert (idx < 100);                 /* FIXME: only for static arrays */
254     lengths[idx] = length;
255     tags[idx ++] = tag;
256     if (tag == head_tag)
257       head_length = length;
258     else if (tag == loca_tag)
259       loca_length = length;
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)
459 {
460   FT_Face face = open_ft_face (name);
461
462   print_header (out, face);
463   print_body (out, face);
464   print_trailer (out, face);
465
466   FT_Done_Face (face);
467 }
468
469
470 LY_DEFINE (ly_ttf_ps_name, "ly:ttf-ps-name",
471            1, 0, 0, (SCM ttf_file_name),
472            "Extract the PostScript name from a TrueType font.")
473 {
474   LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
475   string file_name = ly_scm2string (ttf_file_name);
476   if (be_verbose_global)
477     progress_indication ("[" + file_name);
478
479   FT_Face face = open_ft_face (file_name);
480   char const *ps_name_str0 = FT_Get_Postscript_Name (face);
481   SCM ps_name = scm_from_locale_string (ps_name_str0 ? ps_name_str0 : "");
482
483   FT_Done_Face (face);
484
485   if (be_verbose_global)
486     progress_indication ("]");
487
488   return ps_name;
489 }
490
491
492
493 LY_DEFINE (ly_ttf_2_pfa, "ly:ttf->pfa",
494            1, 0, 0, (SCM ttf_file_name),
495            "Convert the contents of a TTF file to Type42 PFA, returning it as"
496            " a string.")
497 {
498   LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
499
500   string file_name = ly_scm2string (ttf_file_name);
501   if (be_verbose_global)
502     progress_indication ("[" + file_name);
503
504   Memory_out_stream stream;
505
506   create_type42_font (&stream, file_name);
507   SCM asscm = scm_from_locale_stringn (stream.get_string (),
508                                        stream.get_length ());
509
510   if (be_verbose_global)
511     progress_indication ("]");
512
513   return asscm;
514 }