documentation-lib.scm: Clarify ref-ify docstring.
[lilypond/mpolesky.git] / lily / ttf.cc
blobd8e2b56f4549340bf9ef44f192a2d0759b9a6d4c
1 /*
2 ttf.cc -- implement ttf -> pfa routine.
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include <cstdio>
10 #include "freetype.hh"
12 #include <freetype/tttables.h>
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"
22 Index_to_charcode_map
23 make_index_to_charcode_map (FT_Face face)
25 Index_to_charcode_map m;
26 FT_ULong charcode;
27 FT_UInt gindex;
29 FT_CharMap current_cmap = face->charmap;
30 FT_Select_Charmap (face, FT_ENCODING_UNICODE);
32 int j = 0;
33 for (charcode = FT_Get_First_Char (face, &gindex); gindex != 0;
34 charcode = FT_Get_Next_Char (face, charcode, &gindex))
36 m[gindex] = charcode;
37 j ++;
39 FT_Set_Charmap (face, current_cmap);
41 return m;
45 Based on ttfps by Juliusz Chroboczek
47 static void
48 print_header (void *out, FT_Face face)
50 lily_cookie_fprintf (out, "%%!PS-TrueTypeFont\n");
52 TT_Postscript *pt
53 = (TT_Postscript *) FT_Get_Sfnt_Table (face, ft_sfnt_post);
55 if (pt->maxMemType42)
56 lily_cookie_fprintf (out, "%%%%VMUsage: %d %d\n", 0, 0);
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));
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");
66 TT_Header *ht
67 = (TT_Header *)FT_Get_Sfnt_Table (face, ft_sfnt_head);
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);
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);
80 #if 0
81 if (strings[0])
83 lily_cookie_fprintf (out, "/Notice (");
84 fputpss (strings[0], out);
85 lily_cookie_fprintf (out, ") def\n");
87 if (strings[4])
89 lily_cookie_fprintf (out, "/FullName (");
90 fputpss (strings[4], out);
91 lily_cookie_fprintf (out, ") def\n");
93 if (strings[1])
95 lily_cookie_fprintf (out, "/FamilyName (");
96 fputpss (strings[1], out);
97 lily_cookie_fprintf (out, ") def\n");
99 #endif
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");
110 #define CHUNKSIZE 65534
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');
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)
121 vector<FT_UShort> chunks;
123 if (is_glyf)
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.");
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;
134 delete[] head_buf;
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.");
141 unsigned char *p = loca_buf;
142 unsigned char *endp = loca_buf + loca_length;
144 FT_ULong offset = 0, last_offset = 0, last_chunk = 0;
145 while (p < endp)
147 if (long_offsets)
149 offset = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
150 p += 4;
152 else
154 offset = ((p[0] << 8) | p[1]) << 1;
155 p += 2;
157 if (offset > last_offset + CHUNKSIZE)
159 if (last_chunk != last_offset)
160 chunks.push_back (last_offset - last_chunk);
162 a single glyph with more than 64k data
163 is a pathological case but...
165 FT_ULong rest = offset - last_offset;
166 while (rest > CHUNKSIZE)
168 chunks.push_back (CHUNKSIZE);
169 rest -= CHUNKSIZE;
171 chunks.push_back (rest);
172 last_chunk = offset;
174 else if (offset > last_chunk + CHUNKSIZE)
176 chunks.push_back (last_offset - last_chunk);
177 last_chunk = last_offset;
180 last_offset = offset;
182 chunks.push_back (s - last_chunk);
184 delete[] loca_buf;
186 else if (s > CHUNKSIZE)
188 FT_ULong rest = s;
189 while (rest > CHUNKSIZE)
191 chunks.push_back (CHUNKSIZE);
192 rest -= CHUNKSIZE;
194 chunks.push_back (rest);
196 else
197 chunks.push_back (CHUNKSIZE);
199 lily_cookie_fprintf (out, "\n"
200 " <");
202 int l = 0;
203 static char xdigits[] = "0123456789ABCDEF";
205 int cur_chunk_idx = 0;
206 for (size_t j = 0; j < s; j++)
208 if (l >= chunks[cur_chunk_idx])
210 lily_cookie_fprintf (out, "\n"
211 " 00>\n"
212 " <");
213 l = 0;
214 cur_chunk_idx ++;
217 if (l % 31 == 0)
218 lily_cookie_fprintf (out, "\n"
219 " ");
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);
225 l ++;
228 /* pad to four-byte boundary */
229 while ((s ++) % 4 != 0)
230 lily_cookie_fprintf (out, "00");
232 lily_cookie_fprintf (out, "\n"
233 " 00\n"
234 " >");
237 static void
238 print_body (void *out, FT_Face face)
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;
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
250 while (FT_Sfnt_Table_Info (face, idx, &tag, &length)
251 != FT_Err_Table_Missing)
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 ++;
262 FT_ULong hlength = 12 + 16 * idx;
264 unsigned char *hbuf = new unsigned char[hlength];
265 unsigned char *p;
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;
274 FT_UInt searchRange, entrySelector, rangeShift;
275 FT_UInt i, j;
276 for (i = 1, j = 2; j <= idx; i++, j <<= 1)
278 entrySelector = i - 1;
279 searchRange = 0x10 << entrySelector;
280 rangeShift = (idx << 4) - searchRange;
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;
289 p = &hbuf[12];
291 FT_ULong checksum, font_checksum = 0;
293 FT_ULong offset = hlength; /* first table offset */
295 for (FT_UInt i = 0; i < idx; i++)
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];
301 buf[len - 1] = 0x00; /* assure padding with zeros */
302 buf[len - 2] = 0x00;
303 buf[len - 3] = 0x00;
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.");
309 if (tag == head_tag)
312 first pass of computing the font checksum
313 needs checkSumAdjustment = 0
315 buf[8] = 0x00;
316 buf[9] = 0x00;
317 buf[10] = 0x00;
318 buf[11] = 0x00;
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;
327 delete[] buf;
329 *(p++) = (tags[i] & 0xFF000000UL) >> 24;
330 *(p++) = (tags[i] & 0x00FF0000UL) >> 16;
331 *(p++) = (tags[i] & 0x0000FF00UL) >> 8;
332 *(p++) = tags[i] & 0x000000FFUL;
334 *(p++) = (checksum & 0xFF000000UL) >> 24;
335 *(p++) = (checksum & 0x00FF0000UL) >> 16;
336 *(p++) = (checksum & 0x0000FF00UL) >> 8;
337 *(p++) = checksum & 0x000000FFUL;
339 *(p++) = (offset & 0xFF000000UL) >> 24;
340 *(p++) = (offset & 0x00FF0000UL) >> 16;
341 *(p++) = (offset & 0x0000FF00UL) >> 8;
342 *(p++) = offset & 0x000000FFUL;
344 *(p++) = (lengths[i] & 0xFF000000UL) >> 24;
345 *(p++) = (lengths[i] & 0x00FF0000UL) >> 16;
346 *(p++) = (lengths[i] & 0x0000FF00UL) >> 8;
347 *(p++) = lengths[i] & 0x000000FFUL;
349 /* offset must be a multiple of 4 */
350 offset += (lengths[i] + 3) & ~3;
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;
361 see Adobe technical note 5012.Type42_Spec.pdf for details how
362 the /sfnts array must be constructed
364 lily_cookie_fprintf (out, "/sfnts [");
365 t42_write_table (out, face, hbuf, hlength, false,
366 head_length, loca_length);
367 delete[] hbuf;
369 idx = 0;
371 while (FT_Sfnt_Table_Info (face, idx, &tag, &length)
372 != FT_Err_Table_Missing)
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.");
379 if (tag == head_tag)
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;
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);
392 delete[] buf;
393 idx ++;
395 lily_cookie_fprintf (out, "\n] def\n");
398 static void
399 print_trailer (void *out,
400 FT_Face face)
402 const int GLYPH_NAME_LEN = 256;
403 char glyph_name[GLYPH_NAME_LEN];
405 TT_MaxProfile *mp
406 = (TT_MaxProfile *)FT_Get_Sfnt_Table (face, ft_sfnt_maxp);
408 lily_cookie_fprintf (out, "/CharStrings %d dict dup begin\n", mp->numGlyphs);
410 Index_to_charcode_map ic_map (make_index_to_charcode_map (face));
412 int output_count = 0;
413 for (int i = 0; i < mp->numGlyphs; i++)
415 glyph_name[0] = 0;
416 if (face->face_flags & FT_FACE_FLAG_GLYPH_NAMES)
418 FT_Error error = FT_Get_Glyph_Name (face, i, glyph_name,
419 GLYPH_NAME_LEN);
420 if (error)
422 programming_error ("FT_Get_Glyph_Name (): error.");
423 glyph_name[0] = 0;
427 if (!glyph_name[0] && ic_map.find (i) != ic_map.end ())
429 FT_ULong ucode = ic_map[i];
430 get_unicode_name (glyph_name, ucode);
433 if (i == 0)
434 sprintf (glyph_name, ".notdef");
435 else if (glyph_name == string (".notdef"))
436 glyph_name[0] = '\0';
438 if (!glyph_name[0])
439 get_glyph_index_name (glyph_name, i);
441 if (glyph_name[0])
443 lily_cookie_fprintf (out, "/%s %d def ", glyph_name, i);
444 output_count ++;
446 else
447 programming_error (to_string ("no name for glyph %d", i));
449 if (! (output_count % 5))
450 lily_cookie_fprintf (out, "\n");
453 lily_cookie_fprintf (out, "end readonly def\n");
454 lily_cookie_fprintf (out, "FontName currentdict end definefont pop\n");
457 static void
458 create_type42_font (void *out, string name, int idx)
460 FT_Face face;
462 /* check whether font index is valid */
463 if (idx > 0)
465 face = open_ft_face (name, -1);
466 if (idx >= face->num_faces)
468 warning (_f ("font index %d too large for font `%s', using index 0",
469 idx, name.c_str()));
470 idx = 0;
472 FT_Done_Face (face);
475 face = open_ft_face (name, idx);
477 print_header (out, face);
478 print_body (out, face);
479 print_trailer (out, face);
481 FT_Done_Face (face);
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.")
491 LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
493 int i = 0;
494 if (idx != SCM_UNDEFINED)
496 LY_ASSERT_TYPE (scm_is_integer, idx, 2);
497 i = scm_to_int (idx);
498 if (i < 0)
500 warning (_ ("font index must be non-negative, using index 0"));
501 i = 0;
505 string file_name = ly_scm2string (ttf_file_name);
506 if (be_verbose_global)
507 progress_indication ("\n[" + file_name);
509 FT_Face face;
511 /* check whether font index is valid */
512 if (i > 0)
514 face = open_ft_face (file_name, -1);
515 if (i >= face->num_faces)
517 warning (_f ("font index %d too large for font `%s', using index 0",
518 i, file_name.c_str()));
519 i = 0;
521 FT_Done_Face (face);
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);
529 if (be_verbose_global)
530 progress_indication ("]");
532 return ps_name;
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.")
543 LY_ASSERT_TYPE (scm_is_string, ttf_file_name, 1);
545 int i = 0;
546 if (idx != SCM_UNDEFINED)
548 LY_ASSERT_TYPE (scm_is_integer, idx, 2);
549 i = scm_to_int (idx);
550 if (i < 0)
552 warning (_ ("font index must be non-negative, using index 0"));
553 i = 0;
557 string file_name = ly_scm2string (ttf_file_name);
558 if (be_verbose_global)
559 progress_indication ("\n[" + file_name);
561 Memory_out_stream stream;
563 create_type42_font (&stream, file_name, i);
564 SCM asscm = scm_from_locale_stringn (stream.get_string (),
565 stream.get_length ());
567 if (be_verbose_global)
568 progress_indication ("]");
570 return asscm;