2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005,
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
35 const char *const WS = " \t\n\r";
37 struct font_char_metric {
44 int italic_correction;
45 int subscript_correction;
46 char *special_device_coding;
49 struct font_kern_list {
55 font_kern_list(glyph *, glyph *, int, font_kern_list * = 0);
58 struct font_widths_cache {
59 font_widths_cache *next;
63 font_widths_cache(int, int, font_widths_cache * = 0);
77 text_file(FILE *fp, char *p);
80 void error(const char *format,
81 const errarg &arg1 = empty_errarg,
82 const errarg &arg2 = empty_errarg,
83 const errarg &arg3 = empty_errarg);
86 text_file::text_file(FILE *p, char *s)
87 : fp(p), path(s), lineno(0), size(0), skip_comments(1), silent(0), buf(0)
91 text_file::~text_file()
113 if (invalid_input_char(c))
114 error("invalid input character code `%1'", int(c));
118 buf = new char[size*2];
119 memcpy(buf, old_buf, size);
133 while (csspace(*ptr))
135 if (*ptr != 0 && (!skip_comments || *ptr != '#'))
141 void text_file::error(const char *format,
147 error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
153 font::font(const char *s)
154 : ligatures(0), kern_hash_table(0), space_width(0), special(0),
155 ch_index(0), nindices(0), ch(0), ch_used(0), ch_size(0), widths_cache(0)
157 name = new char[strlen(s) + 1];
162 // load(); // for testing
167 for (int i = 0; i < ch_used; i++)
168 if (ch[i].special_device_coding)
169 a_delete ch[i].special_device_coding;
172 if (kern_hash_table) {
173 for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) {
174 font_kern_list *kerns = kern_hash_table[i];
176 font_kern_list *tem = kerns;
181 a_delete kern_hash_table;
184 a_delete internalname;
185 while (widths_cache) {
186 font_widths_cache *tem = widths_cache;
187 widths_cache = widths_cache->next;
192 static int scale_round(int n, int x, int y)
194 assert(x >= 0 && y > 0);
199 if (n <= (INT_MAX - y2) / x)
200 return (n * x + y2) / y;
201 return int(n * double(x) / double(y) + .5);
204 if (-(unsigned)n <= (-(unsigned)INT_MIN - y2) / x)
205 return (n * x - y2) / y;
206 return int(n * double(x) / double(y) - .5);
210 static int scale_round(int n, int x, int y, int z)
212 assert(x >= 0 && y > 0 && z > 0);
216 return int((n * double(x) / double(y)) * (double(z) / 1000.0) + .5);
218 return int((n * double(x) / double(y)) * (double(z) / 1000.0) - .5);
221 inline int font::scale(int w, int sz)
224 return scale_round(w, sz, unitwidth, zoom);
226 return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
229 int font::unit_scale(double *value, char unit)
231 // we scale everything to inch
257 int font::get_skew(glyph *g, int point_size, int sl)
259 int h = get_height(g, point_size);
260 return int(h * tan((slant + sl) * PI / 180.0) + .5);
263 int font::contains(glyph *g)
265 int idx = glyph_to_index(g);
267 // Explicitly enumerated glyph?
268 if (idx < nindices && ch_index[idx] >= 0)
272 const char *nm = glyph_to_name(g);
275 if (nm[0] == 'c' && nm[1] == 'h' && nm[2] == 'a' && nm[3] == 'r'
276 && (nm[4] >= '0' && nm[4] <= '9')) {
277 int n = (nm[4] - '0');
280 if (n > 0 && (nm[5] >= '0' && nm[5] <= '9')) {
281 n = 10*n + (nm[5] - '0');
284 if (nm[6] >= '0' && nm[6] <= '9') {
285 n = 10*n + (nm[6] - '0');
286 if (nm[7] == '\0' && n < 128)
291 // Unicode character?
292 if (check_unicode_name(nm))
294 // If `nm' is a single letter `x', the glyph name is `\x'.
295 char buf[] = { '\\', '\0', '\0' };
300 // groff glyph name that maps to Unicode?
301 const char *unicode = glyph_name_to_unicode(nm);
302 if (unicode != NULL && strchr(unicode, '_') == NULL)
305 // Numbered character?
306 int n = glyph_to_number(g);
313 int font::is_special()
318 font_widths_cache::font_widths_cache(int ps, int ch_size,
319 font_widths_cache *p)
320 : next(p), point_size(ps)
322 width = new int[ch_size];
323 for (int i = 0; i < ch_size; i++)
327 font_widths_cache::~font_widths_cache()
332 int font::get_width(glyph *g, int point_size)
334 int idx = glyph_to_index(g);
338 real_size = point_size;
341 if (point_size <= (INT_MAX - 500) / zoom)
342 real_size = (point_size * zoom + 500) / 1000;
344 real_size = int(point_size * double(zoom) / 1000.0 + .5);
346 if (idx < nindices && ch_index[idx] >= 0) {
347 // Explicitly enumerated glyph
348 int i = ch_index[idx];
349 if (real_size == unitwidth || font::unscaled_charwidths)
353 widths_cache = new font_widths_cache(real_size, ch_size);
354 else if (widths_cache->point_size != real_size) {
355 font_widths_cache **p;
356 for (p = &widths_cache; *p; p = &(*p)->next)
357 if ((*p)->point_size == real_size)
360 font_widths_cache *tem = *p;
362 tem->next = widths_cache;
366 widths_cache = new font_widths_cache(real_size, ch_size,
369 int &w = widths_cache->width[i];
371 w = scale(ch[i].width, point_size);
376 int width = 24; // value found in the original font files
377 // XXX: this must be eventually moved back to the
378 // font description file!
379 if (real_size == unitwidth || font::unscaled_charwidths)
382 return scale(width, point_size);
387 int font::get_height(glyph *g, int point_size)
389 int idx = glyph_to_index(g);
391 if (idx < nindices && ch_index[idx] >= 0) {
392 // Explicitly enumerated glyph
393 return scale(ch[ch_index[idx]].height, point_size);
397 return 0; // value found in the original font files
398 // XXX: this must be eventually moved back to the
399 // font description file!
404 int font::get_depth(glyph *g, int point_size)
406 int idx = glyph_to_index(g);
408 if (idx < nindices && ch_index[idx] >= 0) {
409 // Explicitly enumerated glyph
410 return scale(ch[ch_index[idx]].depth, point_size);
414 return 0; // value found in the original font files
415 // XXX: this must be eventually moved back to the
416 // font description file!
421 int font::get_italic_correction(glyph *g, int point_size)
423 int idx = glyph_to_index(g);
425 if (idx < nindices && ch_index[idx] >= 0) {
426 // Explicitly enumerated glyph
427 return scale(ch[ch_index[idx]].italic_correction, point_size);
431 return 0; // value found in the original font files
432 // XXX: this must be eventually moved back to the
433 // font description file!
438 int font::get_left_italic_correction(glyph *g, int point_size)
440 int idx = glyph_to_index(g);
442 if (idx < nindices && ch_index[idx] >= 0) {
443 // Explicitly enumerated glyph
444 return scale(ch[ch_index[idx]].pre_math_space, point_size);
448 return 0; // value found in the original font files
449 // XXX: this must be eventually moved back to the
450 // font description file!
455 int font::get_subscript_correction(glyph *g, int point_size)
457 int idx = glyph_to_index(g);
459 if (idx < nindices && ch_index[idx] >= 0) {
460 // Explicitly enumerated glyph
461 return scale(ch[ch_index[idx]].subscript_correction, point_size);
465 return 0; // value found in the original font files
466 // XXX: this must be eventually moved back to the
467 // font description file!
472 void font::set_zoom(int factor)
486 int font::get_space_width(int point_size)
488 return scale(space_width, point_size);
491 font_kern_list::font_kern_list(glyph *g1, glyph *g2, int n, font_kern_list *p)
492 : glyph1(g1), glyph2(g2), amount(n), next(p)
496 inline int font::hash_kern(glyph *g1, glyph *g2)
498 int n = ((glyph_to_index(g1) << 10) + glyph_to_index(g2))
499 % KERN_HASH_TABLE_SIZE;
500 return n < 0 ? -n : n;
503 void font::add_kern(glyph *g1, glyph *g2, int amount)
505 if (!kern_hash_table) {
506 kern_hash_table = new font_kern_list *[int(KERN_HASH_TABLE_SIZE)];
507 for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
508 kern_hash_table[i] = 0;
510 font_kern_list **p = kern_hash_table + hash_kern(g1, g2);
511 *p = new font_kern_list(g1, g2, amount, *p);
514 int font::get_kern(glyph *g1, glyph *g2, int point_size)
516 if (kern_hash_table) {
517 for (font_kern_list *p = kern_hash_table[hash_kern(g1, g2)]; p;
519 if (g1 == p->glyph1 && g2 == p->glyph2)
520 return scale(p->amount, point_size);
525 int font::has_ligature(int mask)
527 return mask & ligatures;
530 int font::get_character_type(glyph *g)
532 int idx = glyph_to_index(g);
534 if (idx < nindices && ch_index[idx] >= 0) {
535 // Explicitly enumerated glyph
536 return ch[ch_index[idx]].type;
540 return 0; // value found in the original font files
541 // XXX: this must be eventually moved back to the
542 // font description file!
547 int font::get_code(glyph *g)
549 int idx = glyph_to_index(g);
551 if (idx < nindices && ch_index[idx] >= 0) {
552 // Explicitly enumerated glyph
553 return ch[ch_index[idx]].code;
557 const char *nm = glyph_to_name(g);
560 if (nm[0] == 'c' && nm[1] == 'h' && nm[2] == 'a' && nm[3] == 'r'
561 && (nm[4] >= '0' && nm[4] <= '9')) {
562 int n = (nm[4] - '0');
565 if (n > 0 && (nm[5] >= '0' && nm[5] <= '9')) {
566 n = 10*n + (nm[5] - '0');
569 if (nm[6] >= '0' && nm[6] <= '9') {
570 n = 10*n + (nm[6] - '0');
571 if (nm[7] == '\0' && n < 128)
576 // Unicode character?
577 if (check_unicode_name(nm)) {
579 return (int)strtol(nm + 1, &ignore, 16);
581 // If `nm' is a single letter `x', the glyph name is `\x'.
582 char buf[] = { '\\', '\0', '\0' };
587 // groff glyphs that map to Unicode?
588 const char *unicode = glyph_name_to_unicode(nm);
589 if (unicode != NULL && strchr(unicode, '_') == NULL) {
591 return (int)strtol(unicode, &ignore, 16);
594 // Numbered character?
595 int n = glyph_to_number(g);
599 // The caller must check `contains(g)' before calling get_code(g).
603 const char *font::get_name()
608 const char *font::get_internal_name()
613 const char *font::get_special_device_encoding(glyph *g)
615 int idx = glyph_to_index(g);
617 if (idx < nindices && ch_index[idx] >= 0) {
618 // Explicitly enumerated glyph
619 return ch[ch_index[idx]].special_device_coding;
628 const char *font::get_image_generator()
630 return image_generator;
633 void font::alloc_ch_index(int idx)
639 ch_index = new int[nindices];
640 for (int i = 0; i < nindices; i++)
644 int old_nindices = nindices;
648 int *old_ch_index = ch_index;
649 ch_index = new int[nindices];
650 memcpy(ch_index, old_ch_index, sizeof(int)*old_nindices);
651 for (int i = old_nindices; i < nindices; i++)
653 a_delete old_ch_index;
657 void font::extend_ch()
660 ch = new font_char_metric[ch_size = 16];
662 int old_ch_size = ch_size;
664 font_char_metric *old_ch = ch;
665 ch = new font_char_metric[ch_size];
666 memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
674 for (i = nindices - 1; i >= 0; i--)
675 if (ch_index[i] >= 0)
679 int *old_ch_index = ch_index;
680 ch_index = new int[i];
681 memcpy(ch_index, old_ch_index, i*sizeof(int));
682 a_delete old_ch_index;
685 if (ch_used < ch_size) {
686 font_char_metric *old_ch = ch;
687 ch = new font_char_metric[ch_used];
688 memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
694 void font::add_entry(glyph *g, const font_char_metric &metric)
696 int idx = glyph_to_index(g);
700 assert(idx < nindices);
701 if (ch_used + 1 >= ch_size)
703 assert(ch_used + 1 < ch_size);
704 ch_index[idx] = ch_used;
705 ch[ch_used++] = metric;
708 void font::copy_entry(glyph *new_glyph, glyph *old_glyph)
710 int new_index = glyph_to_index(new_glyph);
711 int old_index = glyph_to_index(old_glyph);
712 assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
713 if (new_index >= nindices)
714 alloc_ch_index(new_index);
715 ch_index[new_index] = ch_index[old_index];
718 font *font::load_font(const char *s, int *not_found, int head_only)
720 font *f = new font(s);
721 if (!f->load(not_found, head_only)) {
728 static char *trim_arg(char *p)
734 char *q = strchr(p, '\0');
735 while (q > p && csspace(q[-1]))
741 int font::scan_papersize(const char *p,
742 const char **size, double *length, double *width)
751 if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4
753 && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) {
765 for (i = 0; i < NUM_PAPERSIZES; i++)
766 if (strcasecmp(papersizes[i].name, pp) == 0) {
768 *length = papersizes[i].length;
770 *width = papersizes[i].width;
772 *size = papersizes[i].name;
776 FILE *f = fopen(p, "r");
781 char *linep = strchr(line, '\0');
782 // skip final newline, if any
783 if (*(--linep) == '\n')
793 // If the font can't be found, then if not_found is non-NULL, it will be set
794 // to 1 otherwise a message will be printed.
796 int font::load(int *not_found, int head_only)
798 if (strcmp(name, "DESC") == 0) {
802 error("`DESC' is not a valid font file name");
807 if ((fp = open_file(name, &path)) == NULL) {
811 error("can't find font file `%1'", name);
814 text_file t(fp, path);
816 t.silent = head_only;
823 p = strtok(t.buf, WS);
824 if (strcmp(p, "name") == 0) {
826 else if (strcmp(p, "spacewidth") == 0) {
829 if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
830 t.error("bad argument for `spacewidth' command");
835 else if (strcmp(p, "slant") == 0) {
838 if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
839 t.error("bad argument for `slant' command", p);
844 else if (strcmp(p, "ligatures") == 0) {
847 if (p == 0 || strcmp(p, "0") == 0)
849 if (strcmp(p, "ff") == 0)
851 else if (strcmp(p, "fi") == 0)
853 else if (strcmp(p, "fl") == 0)
855 else if (strcmp(p, "ffi") == 0)
856 ligatures |= LIG_ffi;
857 else if (strcmp(p, "ffl") == 0)
858 ligatures |= LIG_ffl;
860 t.error("unrecognised ligature `%1'", p);
865 else if (strcmp(p, "internalname") == 0) {
868 t.error("`internalname' command requires argument");
871 internalname = new char[strlen(p) + 1];
872 strcpy(internalname, p);
874 else if (strcmp(p, "special") == 0) {
877 else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
880 handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
888 t.error("missing charset command");
895 if (strcmp(command, "kernpairs") == 0) {
903 char *c1 = strtok(t.buf, WS);
906 char *c2 = strtok(0, WS);
913 t.error("missing kern amount");
917 if (sscanf(p, "%d", &n) != 1) {
918 t.error("bad kern amount `%1'", p);
921 glyph *g1 = name_to_glyph(c1);
922 glyph *g2 = name_to_glyph(c2);
926 else if (strcmp(command, "charset") == 0) {
930 glyph *last_glyph = NULL;
936 char *nm = strtok(t.buf, WS);
938 continue; // I dont think this should happen
945 if (last_glyph == NULL) {
946 t.error("first charset entry is duplicate");
949 if (strcmp(nm, "---") == 0) {
950 t.error("unnamed character cannot be duplicate");
953 glyph *g = name_to_glyph(nm);
954 copy_entry(g, last_glyph);
957 font_char_metric metric;
960 metric.pre_math_space = 0;
961 metric.italic_correction = 0;
962 metric.subscript_correction = 0;
963 int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
964 &metric.width, &metric.height, &metric.depth,
965 &metric.italic_correction,
966 &metric.pre_math_space,
967 &metric.subscript_correction);
969 t.error("bad width for `%1'", nm);
974 t.error("missing character type for `%1'", nm);
978 if (sscanf(p, "%d", &type) != 1) {
979 t.error("bad character type for `%1'", nm);
982 if (type < 0 || type > 255) {
983 t.error("character type `%1' out of range", type);
989 t.error("missing code for `%1'", nm);
993 metric.code = (int)strtol(p, &ptr, 0);
994 if (metric.code == 0 && ptr == p) {
995 t.error("bad code `%1' for character `%2'", p, nm);
999 if ((p == NULL) || (strcmp(p, "--") == 0)) {
1000 metric.special_device_coding = NULL;
1003 char *nam = new char[strlen(p) + 1];
1005 metric.special_device_coding = nam;
1007 if (strcmp(nm, "---") == 0) {
1008 last_glyph = number_to_glyph(metric.code);
1009 add_entry(last_glyph, metric);
1012 last_glyph = name_to_glyph(nm);
1013 add_entry(last_glyph, metric);
1014 copy_entry(number_to_glyph(metric.code), last_glyph);
1018 if (last_glyph == NULL) {
1019 t.error("I didn't seem to find any characters");
1024 t.error("unrecognised command `%1' "
1025 "after `kernpairs' or `charset' command",
1032 if (!is_unicode && !had_charset) {
1033 t.error("missing `charset' command");
1036 if (space_width == 0) {
1038 space_width = scale_round(unitwidth, res, 72 * 3 * sizescale, zoom);
1040 space_width = scale_round(unitwidth, res, 72 * 3 * sizescale);
1046 const char *command;
1049 { "res", &font::res },
1050 { "hor", &font::hor },
1051 { "vert", &font::vert },
1052 { "unitwidth", &font::unitwidth },
1053 { "paperwidth", &font::paperwidth },
1054 { "paperlength", &font::paperlength },
1055 { "spare1", &font::biggestfont },
1056 { "biggestfont", &font::biggestfont },
1057 { "spare2", &font::spare2 },
1058 { "sizescale", &font::sizescale },
1061 int font::load_desc()
1066 if ((fp = open_file("DESC", &path)) == 0) {
1067 error("can't find `DESC' file");
1070 text_file t(fp, path);
1071 t.skip_comments = 1;
1074 char *p = strtok(t.buf, WS);
1077 for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++)
1078 if (strcmp(table[idx].command, p) == 0)
1081 char *q = strtok(0, WS);
1083 t.error("missing value for command `%1'", p);
1086 //int *ptr = &(this->*(table[idx-1].ptr));
1087 int *ptr = table[idx-1].ptr;
1088 if (sscanf(q, "%d", ptr) != 1) {
1089 t.error("bad number `%1'", q);
1093 else if (strcmp("family", p) == 0) {
1096 t.error("family command requires an argument");
1099 char *tem = new char[strlen(p)+1];
1103 else if (strcmp("fonts", p) == 0) {
1105 if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
1106 t.error("bad number of fonts `%1'", p);
1109 font_name_table = (const char **)new char *[nfonts+1];
1110 for (int i = 0; i < nfonts; i++) {
1114 t.error("end of file while reading list of fonts");
1117 p = strtok(t.buf, WS);
1119 char *temp = new char[strlen(p)+1];
1121 font_name_table[i] = temp;
1125 t.error("font count does not match number of fonts");
1128 font_name_table[nfonts] = 0;
1130 else if (strcmp("papersize", p) == 0) {
1133 t.error("papersize command requires an argument");
1136 int found_paper = 0;
1138 double unscaled_paperwidth, unscaled_paperlength;
1139 if (scan_papersize(p, &papersize, &unscaled_paperlength,
1140 &unscaled_paperwidth)) {
1141 paperwidth = int(unscaled_paperwidth * res + 0.5);
1142 paperlength = int(unscaled_paperlength * res + 0.5);
1149 t.error("bad paper size");
1153 else if (strcmp("unscaled_charwidths", p) == 0)
1154 unscaled_charwidths = 1;
1155 else if (strcmp("pass_filenames", p) == 0)
1157 else if (strcmp("sizes", p) == 0) {
1165 t.error("list of sizes must be terminated by `0'");
1168 p = strtok(t.buf, WS);
1171 switch (sscanf(p, "%d-%d", &lower, &upper)) {
1176 if (lower <= upper && lower >= 0)
1180 t.error("bad size range `%1'", p);
1184 int *old_sizes = sizes;
1185 sizes = new int[n*2];
1186 memcpy(sizes, old_sizes, n*sizeof(int));
1196 t.error("must have some sizes");
1200 else if (strcmp("styles", p) == 0) {
1201 int style_table_size = 5;
1202 style_table = (const char **)new char *[style_table_size];
1204 for (j = 0; j < style_table_size; j++)
1211 // leave room for terminating 0
1212 if (i + 1 >= style_table_size) {
1213 const char **old_style_table = style_table;
1214 style_table_size *= 2;
1215 style_table = (const char **)new char*[style_table_size];
1216 for (j = 0; j < i; j++)
1217 style_table[j] = old_style_table[j];
1218 for (; j < style_table_size; j++)
1220 a_delete old_style_table;
1222 char *tem = new char[strlen(p) + 1];
1224 style_table[i++] = tem;
1227 else if (strcmp("tcommand", p) == 0)
1229 else if (strcmp("use_charnames_in_special", p) == 0)
1230 use_charnames_in_special = 1;
1231 else if (strcmp("unicode", p) == 0)
1233 else if (strcmp("image_generator", p) == 0) {
1236 t.error("image_generator command requires an argument");
1239 image_generator = strsave(p);
1241 else if (strcmp("charset", p) == 0)
1243 else if (unknown_desc_command_handler) {
1245 p = strtok(0, "\n");
1246 (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
1250 t.error("missing `res' command");
1253 if (unitwidth == 0) {
1254 t.error("missing `unitwidth' command");
1257 if (font_name_table == 0) {
1258 t.error("missing `fonts' command");
1262 t.error("missing `sizes' command");
1265 if (sizescale < 1) {
1266 t.error("bad `sizescale' value");
1270 t.error("bad `hor' value");
1274 t.error("bad `vert' value");
1280 void font::handle_unknown_font_command(const char *, const char *,
1285 FONT_COMMAND_HANDLER
1286 font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
1288 FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
1289 unknown_desc_command_handler = func;