otf: parse ttf files
[neatmkfn.git] / otf.c
blobc7fc4a4607ec0fd40c1bf061ab080a13abbe4c15
1 #include <arpa/inet.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include "trfn.h"
8 #define NGLYPHS (1 << 14)
9 #define GNLEN (64)
10 #define BUFLEN (1 << 23)
11 #define OWID(w) ((w) * 1000 / (upm))
13 #define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
14 #define U16(buf, off) (htons(*(u16 *) ((buf) + (off))))
15 #define U8(buf, off) (*(u8 *) ((buf) + (off)))
16 #define S16(buf, off) ((s16) htons(*(u16 *) ((buf) + (off))))
17 #define S32(buf, off) ((s32) htonl(*(u32 *) ((buf) + (off))))
19 #define OTFLEN 12 /* otf header length */
20 #define OTFRECLEN 16 /* otf header record length */
21 #define CMAPLEN 4 /* cmap header length */
22 #define CMAPRECLEN 8 /* cmap record length */
23 #define CMAP4LEN 8 /* format 4 cmap subtable header length */
25 typedef unsigned int u32;
26 typedef unsigned short u16;
27 typedef unsigned char u8;
28 typedef int s32;
29 typedef short s16;
31 static char glyph_name[NGLYPHS][GNLEN];
32 static int glyph_code[NGLYPHS];
33 static int glyph_bbox[NGLYPHS][4];
34 static int glyph_wid[NGLYPHS];
35 static int glyph_n;
36 static int upm; /* units per em */
38 static char *macset[];
40 /* find the otf table with the given name */
41 static void *otf_table(void *otf, char *name)
43 void *recs = otf + OTFLEN; /* otf table records */
44 void *rec; /* beginning of a table record */
45 int nrecs = U16(otf, 4);
46 int i;
47 for (i = 0; i < nrecs; i++) {
48 rec = recs + i * OTFRECLEN;
49 if (!strncmp(rec, name, 4))
50 return otf + U32(rec, 8);
52 return NULL;
55 /* parse otf cmap format 4 subtable */
56 static void otf_cmap4(void *otf, void *cmap4)
58 int nsegs;
59 void *ends, *begs, *deltas, *offsets;
60 void *idarray;
61 int beg, end, delta, offset;
62 int i, j;
63 nsegs = U16(cmap4, 6) / 2;
64 ends = cmap4 + 14;
65 begs = ends + 2 * nsegs + 2;
66 deltas = begs + 2 * nsegs;
67 offsets = deltas + 2 * nsegs;
68 idarray = offsets + 2 * nsegs;
69 for (i = 0; i < nsegs; i++) {
70 beg = U16(begs, 2 * i);
71 end = U16(ends, 2 * i);
72 delta = U16(deltas, 2 * i);
73 offset = U16(offsets, 2 * i);
74 if (offset) {
75 for (j = beg; j <= end; j++)
76 glyph_code[U16(offsets + i * 2,
77 offset + (j - beg) * 2)] = j;
78 } else {
79 for (j = beg; j <= end; j++)
80 glyph_code[(j + delta) & 0xffff] = j;
85 /* parse otf cmap header */
86 static void otf_cmap(void *otf, void *cmap)
88 void *recs = cmap + CMAPLEN; /* cmap records */
89 void *rec; /* a cmap record */
90 void *tab; /* a cmap subtable */
91 int plat, enc;
92 int fmt;
93 int nrecs = U16(cmap, 2);
94 int i;
95 for (i = 0; i < nrecs; i++) {
96 rec = recs + i * CMAPRECLEN;
97 plat = U16(rec, 0);
98 enc = U16(rec, 2);
99 tab = cmap + U32(rec, 4);
100 fmt = U16(tab, 0);
101 if (plat == 3 && enc == 1 && fmt == 4)
102 otf_cmap4(otf, tab);
106 static void otf_post(void *otf, void *post)
108 void *post2; /* version 2.0 header */
109 void *index; /* glyph name indices */
110 void *names; /* glyph names */
111 int i, idx;
112 int cname = 0;
113 if (U32(post, 0) != 0x00020000)
114 return;
115 post2 = post + 32;
116 glyph_n = U16(post2, 0);
117 index = post2 + 2;
118 names = index + 2 * glyph_n;
119 for (i = 0; i < glyph_n; i++) {
120 idx = U16(index, 2 * i);
121 if (idx <= 257) {
122 strcpy(glyph_name[i], macset[idx]);
123 } else {
124 memcpy(glyph_name[i], names + cname + 1,
125 U8(names, cname));
126 glyph_name[i][U8(names, cname)] = '\0';
127 cname += U8(names, cname) + 1;
132 static void otf_glyf(void *otf, void *glyf)
134 void *maxp = otf_table(otf, "maxp");
135 void *head = otf_table(otf, "head");
136 void *loca = otf_table(otf, "loca");
137 void *gdat;
138 void *gdat_next;
139 int n = U16(maxp, 4);
140 int fmt = U16(head, 50);
141 int i, j;
142 for (i = 0; i < n; i++) {
143 if (fmt) {
144 gdat = glyf + U32(loca, 4 * i);
145 gdat_next = glyf + U32(loca, 4 * (i + 1));
146 } else {
147 gdat = glyf + U16(loca, 2 * i) * 2;
148 gdat_next = glyf + U16(loca, 2 * (i + 1)) * 2;
150 if (gdat < gdat_next)
151 for (j = 0; j < 4; j++)
152 glyph_bbox[i][j] = S16(gdat, 2 + 2 * j);
156 static void otf_hmtx(void *otf, void *hmtx)
158 void *hhea = otf_table(otf, "hhea");
159 int n;
160 int i;
161 n = U16(hhea, 34);
162 for (i = 0; i < n; i++)
163 glyph_wid[i] = U16(hmtx, i * 4);
164 for (i = n; i < glyph_n; i++)
165 glyph_wid[i] = glyph_wid[n - 1];
168 static void otf_kern(void *otf, void *kern)
170 int n; /* number of kern subtables */
171 void *tab; /* a kern subtable */
172 int off = 4;
173 int npairs;
174 int cov;
175 int i, j;
176 int c1, c2, val;
177 n = U16(kern, 2);
178 for (i = 0; i < n; i++) {
179 tab = kern + off;
180 off += U16(tab, 2);
181 cov = U16(tab, 4);
182 if ((cov >> 8) == 0 && (cov & 1)) { /* format 0 */
183 npairs = U16(tab, 6);
184 for (j = 0; j < npairs; j++) {
185 c1 = U16(tab, 14 + 6 * j);
186 c2 = U16(tab, 14 + 6 * j + 2);
187 val = S16(tab, 14 + 6 * j + 4);
188 trfn_kern(glyph_name[c1], glyph_name[c2],
189 OWID(val));
195 int xread(int fd, char *buf, int len)
197 int nr = 0;
198 while (nr < len) {
199 int ret = read(fd, buf + nr, len - nr);
200 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
201 continue;
202 if (ret <= 0)
203 break;
204 nr += ret;
206 return nr;
209 static char buf[BUFLEN];
211 int otf_read(void)
213 int i;
214 if (xread(0, buf, sizeof(buf)) <= 0)
215 return 1;
216 upm = U16(otf_table(buf, "head"), 18);
217 otf_cmap(buf, otf_table(buf, "cmap"));
218 otf_post(buf, otf_table(buf, "post"));
219 if (otf_table(buf, "glyf"))
220 otf_glyf(buf, otf_table(buf, "glyf"));
221 otf_hmtx(buf, otf_table(buf, "hmtx"));
222 for (i = 0; i < glyph_n; i++) {
223 trfn_char(glyph_name[i], -1,
224 glyph_code[i] != 0xffff ? glyph_code[i] : 0,
225 OWID(glyph_wid[i]),
226 OWID(glyph_bbox[i][0]), OWID(glyph_bbox[i][1]),
227 OWID(glyph_bbox[i][2]), OWID(glyph_bbox[i][3]));
229 otf_kern(buf, otf_table(buf, "kern"));
230 return 0;
233 static char *macset[] = {
234 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
235 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
236 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
237 "comma", "hyphen", "period", "slash", "zero",
238 "one", "two", "three", "four", "five",
239 "six", "seven", "eight", "nine", "colon",
240 "semicolon", "less", "equal", "greater", "question",
241 "at", "A", "B", "C", "D",
242 "E", "F", "G", "H", "I",
243 "J", "K", "L", "M", "N",
244 "O", "P", "Q", "R", "S",
245 "T", "U", "V", "W", "X",
246 "Y", "Z", "bracketleft", "backslash", "bracketright",
247 "asciicircum", "underscore", "grave", "a", "b",
248 "c", "d", "e", "f", "g",
249 "h", "i", "j", "k", "l",
250 "m", "n", "o", "p", "q",
251 "r", "s", "t", "u", "v",
252 "w", "x", "y", "z", "braceleft",
253 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
254 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
255 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
256 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
257 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
258 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
259 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
260 "dagger", "degree", "cent", "sterling", "section",
261 "bullet", "paragraph", "germandbls", "registered", "copyright",
262 "trademark", "acute", "dieresis", "notequal", "AE",
263 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
264 "yen", "mu", "partialdiff", "summation", "product",
265 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
266 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
267 "radical", "florin", "approxequal", "Delta", "guillemotleft",
268 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
269 "Otilde", "OE", "oe", "endash", "emdash",
270 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
271 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
272 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
273 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
274 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
275 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
276 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
277 "dotlessi", "circumflex", "tilde", "macron", "breve",
278 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
279 "caron", "Lslash", "lslash", "Scaron", "scaron",
280 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
281 "Yacute", "yacute", "Thorn", "thorn", "minus",
282 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
283 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
284 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
285 "Ccaron", "ccaron", "dcroat",