2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Only compile this if the FreeType library is available.
29 #include FT_SFNT_NAMES_H
30 #include FT_TRUETYPE_TABLES_H
33 #define MAX(h, i) ((h) > (i) ? (h) : (i))
36 #define MIN(l, o) ((l) < (o) ? (l) : (o))
38 /**************************************************************************
42 **************************************************************************/
44 static char *platform_names[] = {
45 "Apple Unicode", "Macintosh", "ISO", "Microsoft", "Unknown"
47 static int nplatform_names =
48 sizeof(platform_names) / sizeof(platform_names[0]);
51 * Mac encoding names used when creating the BDF XLFD font name and when
52 * selecting an encoding from a font.
54 static char *mac_encodings[] = {
55 "MacRoman", "MacJapanese", "MacChinese", "MacKorean",
56 "MacArabic", "MacHebrew", "MacGreek", "MacRussian",
57 "MacRSymbol", "MacDevanagari", "MacGurmukhi", "MacGujarati",
58 "MacOriya", "MacBengali", "MacTamil", "MacTelugu",
59 "MacKannada", "MacMalayalam", "MacSinhalese", "MacBurmese",
60 "MacKhmer", "MacThai", "MacLaotian", "MacGeorgian",
61 "MacArmenian", "MacMaldivian", "MacTibetan", "MacMongolian",
62 "MacGeez", "MacSlavic", "MacVietnamese","MacSindhi",
65 static int nmac_encodings = sizeof(mac_encodings) / sizeof(mac_encodings[0]);
68 * ISO encoding names used when creating the BDF XLFD font name and when
69 * selecting an encoding from a font.
71 static char *iso_encodings[] = {
72 "ASCII", "ISO10646", "ISO8859-1"
74 static int niso_encodings = sizeof(iso_encodings) / sizeof(iso_encodings[0]);
77 * Microsoft encoding names used when creating the BDF XLFD font name and
78 * when selecting an encoding from a font.
80 static char *ms_encodings[] = {
81 "Symbol", "ISO10646", "ShiftJIS", "GB2312.1980", "Big5",
82 "KSC5601.1987", "KSC5601.1992"
84 static int nms_encodings = sizeof(ms_encodings) / sizeof(ms_encodings[0]);
86 /**************************************************************************
90 **************************************************************************/
93 * Routine to get the platform name from the platform ID.
96 bdfotf_platform_name(short pid)
98 return (pid < nplatform_names) ?
99 platform_names[pid] : platform_names[nplatform_names - 1];
103 * Routine to get the encoding name from the platform and encoding IDs.
106 bdfotf_encoding_name(short pid, short eid)
112 case 0: return "ISO10646";
114 nnames = nmac_encodings;
115 names = mac_encodings;
118 nnames = niso_encodings;
119 names = iso_encodings;
122 nnames = nms_encodings;
123 names = ms_encodings;
125 default: return "Unknown";
128 return (eid < nnames) ? names[eid] : "Unknown";
132 * A generic routine to get a name from the TT name table. This routine
133 * always looks for English language names and checks three possibilities:
134 * 1. English names with the MS Unicode encoding ID.
135 * 2. English names with the MS unknown encoding ID.
136 * 3. English names with the Apple Unicode encoding ID.
138 * The particular name ID mut be provided (e.g. nameID = 0 for copyright
139 * string, nameID = 6 for Postscript name, nameID = 1 for typeface name.
141 * If the `dash_to_space' flag is set, all dashes (-) in the name will be
142 * replaced with spaces.
144 * Returns the number of bytes added.
147 bdfotf_get_english_string(FT_Face face, int nameID, int dash_to_space,
152 FT_SfntName sfntName;
156 nrec = FT_Get_Sfnt_Name_Count(face);
158 for (encid = 1, j = 0; j < 2; j++, encid--) {
160 * Locate one of the MS English font names.
162 for (i = 0; i < nrec; i++) {
163 FT_Get_Sfnt_Name(face, i, &sfntName);
164 if (sfntName.platform_id == 3 &&
165 sfntName.encoding_id == encid &&
166 sfntName.name_id == nameID &&
167 (sfntName.language_id == 0x0409 ||
168 sfntName.language_id == 0x0809 ||
169 sfntName.language_id == 0x0c09 ||
170 sfntName.language_id == 0x1009 ||
171 sfntName.language_id == 0x1409 ||
172 sfntName.language_id == 0x1809)) {
174 slen = sfntName.string_len;
181 * Found one of the MS English font names. The name is by
182 * definition encoded in Unicode, so copy every second byte into
183 * the `name' parameter, assuming there is enough space.
185 for (i = 1; i < slen; i += 2) {
187 *name++ = (s[i] != '-') ? s[i] : ' ';
188 else if (s[i] == '\r' || s[i] == '\n') {
189 if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
202 * No MS English name found, attempt to find an Apple Unicode English
205 for (i = 0; i < nrec; i++) {
206 FT_Get_Sfnt_Name(face, i, &sfntName);
207 if (sfntName.platform_id == 0 && sfntName.language_id == 0 &&
208 sfntName.name_id == nameID) {
210 slen = sfntName.string_len;
217 * Found the Apple Unicode English name. The name is by definition
218 * encoded in Unicode, so copy every second byte into the `name'
219 * parameter, assuming there is enough space.
221 for (i = 1; i < slen; i += 2) {
223 *name++ = (s[i] != '-') ? s[i] : ' ';
224 else if (s[i] == '\r' || s[i] == '\n') {
225 if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
240 _bdfotf_generate(FT_Face face, int nocmap, bdf_options_t *opts,
241 bdf_callback_t callback, void *data, bdf_font_t *fp)
244 int awidth, code, idx;
245 short maxrb, maxlb, minlb, y, x;
246 short x_off, y_off, maxas, maxds;
247 int upm, bpr, wd, ht, sx, ex, sy, ey;
251 bdf_callback_struct_t cb;
254 FT_Size_Metrics imetrics;
255 TT_HoriHeader *horizontal = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
258 * Set the instance resolution and point size.
260 FT_Set_Char_Size(face, 0, opts->point_size * 64,
261 opts->resolution_x, opts->resolution_y);
262 imetrics = face->size->metrics;
265 * Set up the initialization callback.
268 cb.reason = BDF_LOAD_START;
270 cb.total = face->num_glyphs;
271 (*callback)(&cb, data);
275 * Get the units per em value.
277 upm = face->units_per_EM;
282 maxrb = maxlb = maxas = maxds = 0;
286 * Calculate the SWIDTH scaling factor.
288 swscale = ((double) opts->resolution_y) * ((double) opts->point_size);
290 for (code = fp->glyphs_used = 0; code < 0xffff; code++) {
293 * No cmap is being used, so do each index in turn.
295 if (code >= face->num_glyphs)
299 idx = FT_Get_Char_Index(face, code);
302 FT_Load_Glyph(face, idx, opts->otf_flags))
305 if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO))
309 * Increase the amount of storage by 128 every time.
311 if (fp->glyphs_used == fp->glyphs_size) {
312 fp->glyphs = (bdf_glyph_t *)
313 realloc((char *) fp->glyphs,
314 sizeof(bdf_glyph_t) * (fp->glyphs_size + 128));
315 gp = fp->glyphs + fp->glyphs_size;
316 (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) << 7);
317 fp->glyphs_size += 128;
321 * Point at the next glyph.
323 gp = fp->glyphs + fp->glyphs_used++;
325 gp->dwidth = face->glyph->metrics.horiAdvance >> 6;
326 gp->swidth = (unsigned short)
327 (((double) gp->dwidth) * 72000.0) / swscale;
330 * Determine the actual bounding box of the glyph bitmap. Do not
331 * forget that the glyph is rendered upside down!
335 bmap = face->glyph->bitmap.buffer;
336 for (y = 0; y < face->glyph->bitmap.rows; y++) {
337 for (x = 0; x < face->glyph->bitmap.width; x++) {
338 if (bmap[x >> 3] & (0x80 >> (x & 7))) {
345 bmap += face->glyph->bitmap.pitch;
349 * If the glyph is actually an empty bitmap, set the size to 0 all
352 if (sx == 0xffff && sy == 0xffff && ex == 0 && ey == 0)
353 sx = ex = sy = ey = 0;
356 * Adjust the end points.
363 * Test to see if the font is going to be monowidth or not by
364 * comparing the current glyph width against the last one.
366 if (ismono && (ex - sx) + 1 != wd)
370 * Set the initial metrics.
374 x_off = sx + face->glyph->bitmap_left;
375 y_off = sy + face->glyph->bitmap_top - face->glyph->bitmap.rows;
378 * Adjust the overall bounding box.
380 maxas = MAX(maxas, ht + y_off);
381 maxds = MAX(maxds, -y_off);
382 maxrb = MAX(maxrb, wd + x_off);
383 minlb = MIN(minlb, x_off);
384 maxlb = MAX(maxlb, x_off);
387 * Accumulate the average width value.
392 * Set the glyph metrics.
396 gp->bbx.x_offset = x_off;
397 gp->bbx.y_offset = y_off;
398 gp->bbx.ascent = ht + y_off;
399 gp->bbx.descent = -y_off;
402 * Allocate the bitmap for the glyph.
405 gp->bytes = bpr * ht;
406 gp->bitmap = (unsigned char *) malloc(gp->bytes);
407 (void) memset((char *) gp->bitmap, 0, gp->bytes);
410 * Shift the bits into the glyph bitmap.
412 bmap = face->glyph->bitmap.buffer + sy * face->glyph->bitmap.pitch;
413 for (y = 0; y < ey - sy; y++) {
414 for (x = 0; x < ex - sx; x++) {
415 if (bmap[(x+sx) >> 3] & (0x80 >> ((x+sx) & 7)))
416 gp->bitmap[(y * bpr) + (x >> 3)] |= (0x80 >> (x & 7));
418 bmap += face->glyph->bitmap.pitch;
422 * Call the callback if it was provided.
425 cb.reason = BDF_LOADING;
426 cb.current = fp->glyphs_used;
427 cb.total = face->num_glyphs;
428 (*callback)(&cb, data);
433 * Calculate the font average width.
436 (int) ((((double) awidth / (double) fp->glyphs_used) + 0.5) * 10.0);
439 * Set the font bounding box.
441 fp->bbx.width = maxrb - minlb;
442 fp->bbx.height = maxas + maxds;
443 fp->bbx.x_offset = minlb;
444 fp->bbx.y_offset = -maxds;
445 fp->bbx.ascent = maxas;
446 fp->bbx.descent = maxds;
449 * Set the font ascent and descent.
452 (horizontal->Ascender * imetrics.y_ppem) / upm;
454 -((horizontal->Descender * imetrics.y_ppem) / upm);
457 * Determine if the font is monowidth.
460 fp->spacing = BDF_MONOWIDTH;
461 fp->monowidth = fp->bbx.width;
465 * Add the properties needed for the XLFD name.
467 prop.name = "POINT_SIZE";
468 prop.format = BDF_INTEGER;
469 prop.value.int32 = fp->point_size * 10;
470 bdf_add_font_property(fp, &prop);
472 prop.name = "PIXEL_SIZE";
473 prop.format = BDF_INTEGER;
474 prop.value.int32 = (int)
475 ((((double) (fp->point_size * 10) *
476 (double) fp->resolution_y) / 722.7) + 0.5);
477 bdf_add_font_property(fp, &prop);
479 prop.name = "RESOLUTION_X";
480 prop.format = BDF_CARDINAL;
481 prop.value.card32 = (unsigned int) fp->resolution_x;
482 bdf_add_font_property(fp, &prop);
484 prop.name = "RESOLUTION_Y";
485 prop.format = BDF_CARDINAL;
486 prop.value.card32 = (unsigned int) fp->resolution_y;
487 bdf_add_font_property(fp, &prop);
489 prop.name = "FONT_ASCENT";
490 prop.format = BDF_INTEGER;
491 prop.value.int32 = fp->font_ascent;
492 bdf_add_font_property(fp, &prop);
494 prop.name = "FONT_DESCENT";
495 prop.format = BDF_INTEGER;
496 prop.value.int32 = fp->font_descent;
497 bdf_add_font_property(fp, &prop);
499 prop.name = "AVERAGE_WIDTH";
500 prop.format = BDF_INTEGER;
501 prop.value.int32 = awidth;
502 bdf_add_font_property(fp, &prop);
504 prop.name = "SPACING";
505 prop.format = BDF_ATOM;
506 prop.value.atom = "P";
507 switch (fp->spacing) {
508 case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
509 case BDF_MONOWIDTH: prop.value.atom = "M"; break;
510 case BDF_CHARCELL: prop.value.atom = "C"; break;
512 bdf_add_font_property(fp, &prop);
518 bdfotf_load_font(FT_Face face, short pid, short eid, bdf_options_t *opts,
519 bdf_callback_t callback, void *data, bdf_font_t **font)
521 int i, nocmap, res, slen;
525 bdf_callback_struct_t cb;
526 TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
529 * First get the requested cmap from the font.
531 for (nocmap = i = 0; i < face->num_charmaps; i++) {
532 if (face->charmaps[i]->platform_id == pid &&
533 face->charmaps[i]->encoding_id == eid)
538 * If the requested cmap was not found, attempt to fall back on the
539 * Microsoft Unicode cmap.
541 if (i == face->num_charmaps) {
542 for (i = 0; i < face->num_charmaps; i++) {
543 if (face->charmaps[i]->platform_id == 3 &&
544 face->charmaps[i]->encoding_id == 1)
547 if (i == face->num_charmaps) {
555 * Found the Microsoft Unicode cmap.
559 FT_Set_Charmap(face, face->charmaps[i]);
562 FT_Set_Charmap(face, face->charmaps[i]);
567 *font = fp = (bdf_font_t *) malloc(sizeof(bdf_font_t));
568 (void) memset((char *) fp, 0, sizeof(bdf_font_t));
571 * Do some initializations by defaulting to proportional spacing and
572 * allocate at least the reported number of glyphs so reallocations will
576 fp->default_glyph = -1;
577 fp->spacing = BDF_PROPORTIONAL;
578 fp->glyphs_size = face->num_glyphs;
579 fp->glyphs = (bdf_glyph_t *)
580 malloc(sizeof(bdf_glyph_t) * face->num_glyphs);
581 (void) memset((char *) fp->glyphs, 0,
582 sizeof(bdf_glyph_t) * face->num_glyphs);
587 fp->point_size = opts->point_size;
588 fp->resolution_x = opts->resolution_x;
589 fp->resolution_y = opts->resolution_y;
592 * Actually generate the font.
594 res = _bdfotf_generate(face, nocmap, opts, callback, data, fp);
597 * If the number of glyphs loaded is less than the reported number of
598 * glyphs, force a callback if one was provided.
600 if (callback != 0 && fp->glyphs_used < face->num_glyphs) {
601 cb.reason = BDF_LOADING;
602 cb.total = cb.current = face->num_glyphs;
603 (*callback)(&cb, data);
607 * If the font did not load successfully, free up the font.
614 * Add other sundry properties so the XLFD name can be generated.
616 prop.name = "FOUNDRY";
617 prop.format = BDF_ATOM;
618 prop.value.atom = "FreeType";
619 bdf_add_font_property(fp, &prop);
622 * Get the typeface name.
624 slen = bdfotf_get_english_string(face, BDFOTF_FAMILY_STRING, 1, str);
625 prop.name = "FAMILY_NAME";
626 prop.format = BDF_ATOM;
628 prop.value.atom = str;
630 prop.value.atom = "Unknown";
631 bdf_add_font_property(fp, &prop);
634 * Add the CHARSET_REGISTRY and CHARSET_ENCODING properties.
636 np = bdfotf_encoding_name(pid, eid);
637 if (strcmp(np, "ISO8859-1") == 0) {
638 prop.name = "CHARSET_REGISTRY";
639 prop.format = BDF_ATOM;
640 prop.value.atom = "ISO8859";
641 bdf_add_font_property(fp, &prop);
642 prop.name = "CHARSET_ENCODING";
643 prop.format = BDF_ATOM;
644 prop.value.atom = "1";
645 bdf_add_font_property(fp, &prop);
646 } else if (strcmp(np, "ISO10646") == 0) {
647 prop.name = "CHARSET_REGISTRY";
648 prop.format = BDF_ATOM;
649 prop.value.atom = np;
650 bdf_add_font_property(fp, &prop);
651 prop.name = "CHARSET_ENCODING";
652 prop.format = BDF_ATOM;
653 prop.value.atom = "1";
654 bdf_add_font_property(fp, &prop);
656 prop.name = "CHARSET_REGISTRY";
657 prop.format = BDF_ATOM;
658 prop.value.atom = np;
659 bdf_add_font_property(fp, &prop);
660 prop.name = "CHARSET_ENCODING";
661 prop.format = BDF_ATOM;
662 prop.value.atom = "0";
663 bdf_add_font_property(fp, &prop);
667 * Determine the weight name.
669 prop.name = "WEIGHT_NAME";
670 prop.format = BDF_ATOM;
671 slen = bdfotf_get_english_string(face, BDFOTF_SUBFAMILY_STRING,
673 if (strcmp(str, "Regular") == 0)
674 prop.value.atom = "Medium";
675 else if (os2->fsSelection & 0x20)
676 prop.value.atom = "Bold";
678 prop.value.atom = str;
680 prop.value.atom = "Medium";
681 bdf_add_font_property(fp, &prop);
684 * Determine the slant name.
687 prop.format = BDF_ATOM;
688 if (os2->fsSelection & 0x01)
689 prop.value.atom = "I";
691 prop.value.atom = "R";
692 bdf_add_font_property(fp, &prop);
695 * Add the default SETWIDTH_NAME.
697 prop.name = "SETWIDTH_NAME";
698 prop.format = BDF_ATOM;
699 prop.value.atom = "Normal";
700 bdf_add_font_property(fp, &prop);
703 * Create the XLFD font name for the font.
705 fp->name = bdf_make_xlfd_name(fp, 0, 0);
708 * Add the COPYRIGHT notice.
710 slen = bdfotf_get_english_string(face, BDFOTF_COPYRIGHT_STRING,
713 prop.name = "COPYRIGHT";
714 prop.format = BDF_ATOM;
715 prop.value.atom = str;
716 bdf_add_font_property(fp, &prop);
720 * Add the special _TTF_PSNAME atom with the font Postscript name.
722 slen = bdfotf_get_english_string(face, BDFOTF_POSTSCRIPT_STRING,
725 prop.name = "_TTF_PSNAME";
726 prop.format = BDF_ATOM;
727 prop.value.atom = str;
728 bdf_add_font_property(fp, &prop);
732 * Add a message indicating the font was converted.
734 _bdf_add_comment(fp, "Font converted from OTF to BDF.", 31);
735 _bdf_add_acmsg(fp, "Font converted from OTF to BDF.", 31);
738 * Finally, mark the font as being modified.
746 #endif /* HAVE_FREETYPE */