Remember to initialise the bmp array for AFM fonts, or Unicode fallbacks
[sgt/halibut] / in_afm.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "halibut.h"
4 #include "paper.h"
5
6 char *afm_read_line(input *in) {
7 int i, len = 256;
8 int c;
9 char *line;
10
11 do {
12 i = 0;
13 in->pos.line++;
14 c = getc(in->currfp);
15 if (c == EOF) {
16 error(err_afmeof, &in->pos);
17 return NULL;
18 }
19 line = snewn(len, char);
20 while (c != EOF && c != '\r' && c != '\n') {
21 if (i >= len - 1) {
22 len += 256;
23 line = sresize(line, len, char);
24 }
25 line[i++] = c;
26 c = getc(in->currfp);
27 }
28 if (c == '\r') {
29 /* Cope with CRLF terminated lines */
30 c = getc(in->currfp);
31 if (c != '\n' && c != EOF)
32 ungetc(c, in->currfp);
33 }
34 line[i] = 0;
35 } while (line[(strspn(line, " \t"))] == 0 ||
36 strncmp(line, "Comment ", 8) == 0 ||
37 strncmp(line, "Comment\t", 8) == 0);
38
39 return line;
40 }
41
42 static int afm_require_key(char *line, char const *expected, input *in) {
43 char *key = strtok(line, " \t");
44
45 if (strcmp(key, expected) == 0)
46 return TRUE;
47 error(err_afmkey, &in->pos, expected);
48 return FALSE;
49 }
50
51 void read_afm_file(input *in) {
52 char *line, *key, *val;
53 font_info *fi;
54 size_t i;
55
56 fi = snew(font_info);
57 fi->name = NULL;
58 fi->nglyphs = 0;
59 fi->glyphs = NULL;
60 fi->widths = NULL;
61 fi->fp = NULL;
62 fi->kerns = newtree234(kern_cmp);
63 fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
64 fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
65 fi->stemh = fi->stemv = fi->italicangle = 0;
66 for (i = 0; i < lenof(fi->bmp); i++)
67 fi->bmp[i] = 0xFFFF;
68 in->pos.line = 0;
69 line = afm_read_line(in);
70 if (!line || !afm_require_key(line, "StartFontMetrics", in))
71 goto giveup;
72 if (!(val = strtok(NULL, " \t"))) {
73 error(err_afmval, in->pos, "StartFontMetrics", 1);
74 goto giveup;
75 }
76 if (atof(val) >= 5.0) {
77 error(err_afmvers, &in->pos);
78 goto giveup;
79 }
80 sfree(line);
81 for (;;) {
82 line = afm_read_line(in);
83 if (line == NULL)
84 goto giveup;
85 key = strtok(line, " \t");
86 if (strcmp(key, "EndFontMetrics") == 0) {
87 fi->next = all_fonts;
88 all_fonts = fi;
89 fclose(in->currfp);
90 return;
91 } else if (strcmp(key, "FontName") == 0) {
92 if (!(val = strtok(NULL, " \t"))) {
93 error(err_afmval, &in->pos, key, 1);
94 goto giveup;
95 }
96 fi->name = dupstr(val);
97 } else if (strcmp(key, "FontBBox") == 0) {
98 int i;
99 for (i = 0; i < 3; i++) {
100 if (!(val = strtok(NULL, " \t"))) {
101 error(err_afmval, &in->pos, key, 4);
102 goto giveup;
103 }
104 fi->fontbbox[i] = atof(val);
105 }
106 } else if (strcmp(key, "CapHeight") == 0) {
107 if (!(val = strtok(NULL, " \t"))) {
108 error(err_afmval, &in->pos, key, 1);
109 goto giveup;
110 }
111 fi->capheight = atof(val);
112 } else if (strcmp(key, "XHeight") == 0) {
113 if (!(val = strtok(NULL, " \t"))) {
114 error(err_afmval, &in->pos, key, 1);
115 goto giveup;
116 }
117 fi->xheight = atof(val);
118 } else if (strcmp(key, "Ascender") == 0) {
119 if (!(val = strtok(NULL, " \t"))) {
120 error(err_afmval, &in->pos, key, 1);
121 goto giveup;
122 }
123 fi->ascent = atof(val);
124 } else if (strcmp(key, "Descender") == 0) {
125 if (!(val = strtok(NULL, " \t"))) {
126 error(err_afmval, &in->pos, key, 1);
127 goto giveup;
128 }
129 fi->descent = atof(val);
130 } else if (strcmp(key, "CapHeight") == 0) {
131 if (!(val = strtok(NULL, " \t"))) {
132 error(err_afmval, &in->pos, key, 1);
133 goto giveup;
134 }
135 fi->capheight = atof(val);
136 } else if (strcmp(key, "StdHW") == 0) {
137 if (!(val = strtok(NULL, " \t"))) {
138 error(err_afmval, &in->pos, key, 1);
139 goto giveup;
140 }
141 fi->stemh = atof(val);
142 } else if (strcmp(key, "StdVW") == 0) {
143 if (!(val = strtok(NULL, " \t"))) {
144 error(err_afmval, &in->pos, key, 1);
145 goto giveup;
146 }
147 fi->stemv = atof(val);
148 } else if (strcmp(key, "ItalicAngle") == 0) {
149 if (!(val = strtok(NULL, " \t"))) {
150 error(err_afmval, &in->pos, key, 1);
151 goto giveup;
152 }
153 fi->italicangle = atof(val);
154 } else if (strcmp(key, "StartCharMetrics") == 0) {
155 char const **glyphs;
156 int *widths;
157 int i;
158 if (!(val = strtok(NULL, " \t"))) {
159 error(err_afmval, &in->pos, key, 1);
160 goto giveup;
161 }
162 fi->nglyphs = atoi(val);
163 sfree(line);
164 glyphs = snewn(fi->nglyphs, char const *);
165 widths = snewn(fi->nglyphs, int);
166 for (i = 0; i < fi->nglyphs; i++) {
167 glyphs[i] = NULL;
168 line = afm_read_line(in);
169 if (line == NULL)
170 goto giveup;
171 key = strtok(line, " \t");
172 while (key != NULL) {
173 if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
174 if (!(val = strtok(NULL, " \t")) ||
175 !strcmp(val, ";")) {
176 error(err_afmval, &in->pos, key, 1);
177 goto giveup;
178 }
179 widths[i] = atoi(val);
180 } else if (strcmp(key, "N") == 0) {
181 if (!(val = strtok(NULL, " \t")) ||
182 !strcmp(val, ";")) {
183 error(err_afmval, &in->pos, key, 1);
184 goto giveup;
185 }
186 glyphs[i] = dupstr(val);
187 }
188 do {
189 key = strtok(NULL, " \t");
190 } while (key && strcmp(key, ";"));
191 key = strtok(NULL, " \t");
192 }
193 sfree(line);
194 }
195 line = afm_read_line(in);
196 if (!line || !afm_require_key(line, "EndCharMetrics", in))
197 goto giveup;
198 sfree(line);
199 fi->glyphs = glyphs;
200 fi->widths = widths;
201
202 for (i = 0; i < fi->nglyphs; i++) {
203 wchar_t ucs;
204 ucs = ps_glyph_to_unicode(fi->glyphs[i]);
205 if (ucs < 0xFFFF)
206 fi->bmp[ucs] = i;
207 }
208 font_index_glyphs(fi);
209 } else if (strcmp(key, "StartKernPairs") == 0 ||
210 strcmp(key, "StartKernPairs0") == 0) {
211 int nkerns, i;
212 kern_pair *kerns;
213 if (!(val = strtok(NULL, " \t"))) {
214 error(err_afmval, &in->pos, key, 1);
215 goto giveup;
216 }
217 nkerns = atoi(val);
218 sfree(line);
219 kerns = snewn(nkerns, kern_pair);
220 for (i = 0; i < nkerns; i++) {
221 line = afm_read_line(in);
222 if (line == NULL)
223 goto giveup;
224 key = strtok(line, " \t");
225 if (strcmp(key, "KPX") == 0) {
226 char *nl, *nr;
227 int l, r;
228 kern_pair *kp;
229 nl = strtok(NULL, " \t");
230 nr = strtok(NULL, " \t");
231 val = strtok(NULL, " \t");
232 if (!val) {
233 error(err_afmval, &in->pos, key, 3);
234 goto giveup;
235 }
236 l = find_glyph(fi, nl);
237 r = find_glyph(fi, nr);
238 if (l == -1 || r == -1) continue;
239 kp = snew(kern_pair);
240 kp->left = l;
241 kp->right = r;
242 kp->kern = atoi(val);
243 add234(fi->kerns, kp);
244 }
245 }
246 line = afm_read_line(in);
247 if (!line || !afm_require_key(line, "EndKernPairs", in))
248 goto giveup;
249 sfree(line);
250 }
251 }
252 giveup:
253 sfree(fi);
254 fclose(in->currfp);
255 return;
256 }