Fairly ropey font-embedding support. In particular, the PDF output is
[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
55 fi = snew(font_info);
56 fi->name = NULL;
57 fi->nglyphs = 0;
58 fi->glyphs = NULL;
59 fi->widths = NULL;
60 fi->fp = NULL;
61 fi->kerns = newtree234(kern_cmp);
62 fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
63 fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
64 fi->stemh = fi->stemv = fi->italicangle = 0;
65 in->pos.line = 0;
66 line = afm_read_line(in);
67 if (!line || !afm_require_key(line, "StartFontMetrics", in))
68 goto giveup;
69 if (!(val = strtok(NULL, " \t"))) {
70 error(err_afmval, in->pos, "StartFontMetrics", 1);
71 goto giveup;
72 }
73 if (atof(val) >= 5.0) {
74 error(err_afmvers, &in->pos);
75 goto giveup;
76 }
77 sfree(line);
78 for (;;) {
79 line = afm_read_line(in);
80 if (line == NULL)
81 goto giveup;
82 key = strtok(line, " \t");
83 if (strcmp(key, "EndFontMetrics") == 0) {
84 fi->next = all_fonts;
85 all_fonts = fi;
86 fclose(in->currfp);
87 return;
88 } else if (strcmp(key, "FontName") == 0) {
89 if (!(val = strtok(NULL, " \t"))) {
90 error(err_afmval, &in->pos, key, 1);
91 goto giveup;
92 }
93 fi->name = dupstr(val);
94 } else if (strcmp(key, "FontBBox") == 0) {
95 int i;
96 for (i = 0; i < 3; i++) {
97 if (!(val = strtok(NULL, " \t"))) {
98 error(err_afmval, &in->pos, key, 4);
99 goto giveup;
100 }
101 fi->fontbbox[i] = atof(val);
102 }
103 } else if (strcmp(key, "CapHeight") == 0) {
104 if (!(val = strtok(NULL, " \t"))) {
105 error(err_afmval, &in->pos, key, 1);
106 goto giveup;
107 }
108 fi->capheight = atof(val);
109 } else if (strcmp(key, "XHeight") == 0) {
110 if (!(val = strtok(NULL, " \t"))) {
111 error(err_afmval, &in->pos, key, 1);
112 goto giveup;
113 }
114 fi->xheight = atof(val);
115 } else if (strcmp(key, "Ascender") == 0) {
116 if (!(val = strtok(NULL, " \t"))) {
117 error(err_afmval, &in->pos, key, 1);
118 goto giveup;
119 }
120 fi->ascent = atof(val);
121 } else if (strcmp(key, "Descender") == 0) {
122 if (!(val = strtok(NULL, " \t"))) {
123 error(err_afmval, &in->pos, key, 1);
124 goto giveup;
125 }
126 fi->descent = atof(val);
127 } else if (strcmp(key, "CapHeight") == 0) {
128 if (!(val = strtok(NULL, " \t"))) {
129 error(err_afmval, &in->pos, key, 1);
130 goto giveup;
131 }
132 fi->capheight = atof(val);
133 } else if (strcmp(key, "StdHW") == 0) {
134 if (!(val = strtok(NULL, " \t"))) {
135 error(err_afmval, &in->pos, key, 1);
136 goto giveup;
137 }
138 fi->stemh = atof(val);
139 } else if (strcmp(key, "StdVW") == 0) {
140 if (!(val = strtok(NULL, " \t"))) {
141 error(err_afmval, &in->pos, key, 1);
142 goto giveup;
143 }
144 fi->stemv = atof(val);
145 } else if (strcmp(key, "ItalicAngle") == 0) {
146 if (!(val = strtok(NULL, " \t"))) {
147 error(err_afmval, &in->pos, key, 1);
148 goto giveup;
149 }
150 fi->italicangle = atof(val);
151 } else if (strcmp(key, "StartCharMetrics") == 0) {
152 char const **glyphs;
153 int *widths;
154 int i;
155 if (!(val = strtok(NULL, " \t"))) {
156 error(err_afmval, &in->pos, key, 1);
157 goto giveup;
158 }
159 fi->nglyphs = atoi(val);
160 sfree(line);
161 glyphs = snewn(fi->nglyphs, char const *);
162 widths = snewn(fi->nglyphs, int);
163 for (i = 0; i < fi->nglyphs; i++) {
164 glyphs[i] = NULL;
165 line = afm_read_line(in);
166 if (line == NULL)
167 goto giveup;
168 key = strtok(line, " \t");
169 while (key != NULL) {
170 if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
171 if (!(val = strtok(NULL, " \t")) ||
172 !strcmp(val, ";")) {
173 error(err_afmval, &in->pos, key, 1);
174 goto giveup;
175 }
176 widths[i] = atoi(val);
177 } else if (strcmp(key, "N") == 0) {
178 if (!(val = strtok(NULL, " \t")) ||
179 !strcmp(val, ";")) {
180 error(err_afmval, &in->pos, key, 1);
181 goto giveup;
182 }
183 glyphs[i] = dupstr(val);
184 }
185 do {
186 key = strtok(NULL, " \t");
187 } while (key && strcmp(key, ";"));
188 key = strtok(NULL, " \t");
189 }
190 sfree(line);
191 }
192 line = afm_read_line(in);
193 if (!line || !afm_require_key(line, "EndCharMetrics", in))
194 goto giveup;
195 sfree(line);
196 fi->glyphs = glyphs;
197 fi->widths = widths;
198
199 for (i = 0; i < fi->nglyphs; i++) {
200 wchar_t ucs;
201 ucs = ps_glyph_to_unicode(fi->glyphs[i]);
202 if (ucs < 0xFFFF)
203 fi->bmp[ucs] = i;
204 }
205 font_index_glyphs(fi);
206 } else if (strcmp(key, "StartKernPairs") == 0 ||
207 strcmp(key, "StartKernPairs0") == 0) {
208 int nkerns, i;
209 kern_pair *kerns;
210 if (!(val = strtok(NULL, " \t"))) {
211 error(err_afmval, &in->pos, key, 1);
212 goto giveup;
213 }
214 nkerns = atoi(val);
215 sfree(line);
216 kerns = snewn(nkerns, kern_pair);
217 for (i = 0; i < nkerns; i++) {
218 line = afm_read_line(in);
219 if (line == NULL)
220 goto giveup;
221 key = strtok(line, " \t");
222 if (strcmp(key, "KPX") == 0) {
223 char *nl, *nr;
224 int l, r;
225 kern_pair *kp;
226 nl = strtok(NULL, " \t");
227 nr = strtok(NULL, " \t");
228 val = strtok(NULL, " \t");
229 if (!val) {
230 error(err_afmval, &in->pos, key, 3);
231 goto giveup;
232 }
233 l = find_glyph(fi, nl);
234 r = find_glyph(fi, nr);
235 if (l == -1 || r == -1) continue;
236 kp = snew(kern_pair);
237 kp->left = l;
238 kp->right = r;
239 kp->kern = atoi(val);
240 add234(fi->kerns, kp);
241 }
242 }
243 line = afm_read_line(in);
244 if (!line || !afm_require_key(line, "EndKernPairs", in))
245 goto giveup;
246 sfree(line);
247 }
248 }
249 giveup:
250 sfree(fi);
251 fclose(in->currfp);
252 return;
253 }