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