otf: fix the mapping of cmap format 4 with offsets
[neatmkfn.git] / otf.c
blob6da8cf57420317a927f5a665d9679bd4c99bbfd7
1 #include <arpa/inet.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include "trfn.h"
9 #define NGLYPHS (1 << 14)
10 #define GNLEN (64)
11 #define BUFLEN (1 << 23)
12 #define MAX(a, b) ((a) < (b) ? (b) : (a))
14 #define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
15 #define U16(buf, off) (htons(*(u16 *) ((buf) + (off))))
16 #define U8(buf, off) (*(u8 *) ((buf) + (off)))
17 #define S16(buf, off) ((s16) htons(*(u16 *) ((buf) + (off))))
18 #define S32(buf, off) ((s32) htonl(*(u32 *) ((buf) + (off))))
20 #define OTFLEN 12 /* otf header length */
21 #define OTFRECLEN 16 /* otf header record length */
22 #define CMAPLEN 4 /* cmap header length */
23 #define CMAPRECLEN 8 /* cmap record length */
24 #define CMAP4LEN 8 /* format 4 cmap subtable header length */
26 typedef unsigned int u32;
27 typedef unsigned short u16;
28 typedef unsigned char u8;
29 typedef int s32;
30 typedef short s16;
32 static char glyph_name[NGLYPHS][GNLEN];
33 static int glyph_code[NGLYPHS];
34 static int glyph_bbox[NGLYPHS][4];
35 static int glyph_wid[NGLYPHS];
36 static int glyph_n;
37 static int upm; /* units per em */
38 static int res; /* device resolution */
39 static int kmin; /* minimum kerning value */
41 static char *macset[];
43 static int owid(int w)
45 return (w < 0 ? w * 1000 - upm / 2 : w * 1000 + upm / 2) / upm;
48 static int uwid(int w)
50 int d = 7200 / res;
51 return (w < 0 ? owid(w) - d / 2 : owid(w) + d / 2) / d;
54 /* find the otf table with the given name */
55 static void *otf_table(void *otf, char *name)
57 void *recs = otf + OTFLEN; /* otf table records */
58 void *rec; /* beginning of a table record */
59 int nrecs = U16(otf, 4);
60 int i;
61 for (i = 0; i < nrecs; i++) {
62 rec = recs + i * OTFRECLEN;
63 if (!strncmp(rec, name, 4))
64 return otf + U32(rec, 8);
66 return NULL;
69 /* parse otf cmap format 4 subtable */
70 static void otf_cmap4(void *otf, void *cmap4)
72 int nsegs;
73 void *ends, *begs, *deltas, *offsets;
74 int beg, end, delta, offset;
75 int i, j;
76 nsegs = U16(cmap4, 6) / 2;
77 ends = cmap4 + 14;
78 begs = ends + 2 * nsegs + 2;
79 deltas = begs + 2 * nsegs;
80 offsets = deltas + 2 * nsegs;
81 for (i = 0; i < nsegs; i++) {
82 beg = U16(begs, 2 * i);
83 end = U16(ends, 2 * i);
84 delta = U16(deltas, 2 * i);
85 offset = U16(offsets, 2 * i);
86 if (offset) {
87 for (j = beg; j <= end; j++)
88 glyph_code[U16(offsets,
89 offset + (j - beg) * 2)] = j;
90 } else {
91 for (j = beg; j <= end; j++)
92 glyph_code[(j + delta) & 0xffff] = j;
97 /* parse otf cmap header */
98 static void otf_cmap(void *otf, void *cmap)
100 void *recs = cmap + CMAPLEN; /* cmap records */
101 void *rec; /* a cmap record */
102 void *tab; /* a cmap subtable */
103 int plat, enc;
104 int fmt;
105 int nrecs = U16(cmap, 2);
106 int i;
107 for (i = 0; i < nrecs; i++) {
108 rec = recs + i * CMAPRECLEN;
109 plat = U16(rec, 0);
110 enc = U16(rec, 2);
111 tab = cmap + U32(rec, 4);
112 fmt = U16(tab, 0);
113 if (plat == 3 && enc == 1 && fmt == 4)
114 otf_cmap4(otf, tab);
118 static void otf_post(void *otf, void *post)
120 void *post2; /* version 2.0 header */
121 void *index; /* glyph name indices */
122 void *names; /* glyph names */
123 int i, idx;
124 int cname = 0;
125 if (U32(post, 0) != 0x00020000)
126 return;
127 post2 = post + 32;
128 glyph_n = U16(post2, 0);
129 index = post2 + 2;
130 names = index + 2 * glyph_n;
131 for (i = 0; i < glyph_n; i++) {
132 idx = U16(index, 2 * i);
133 if (idx <= 257) {
134 strcpy(glyph_name[i], macset[idx]);
135 } else {
136 memcpy(glyph_name[i], names + cname + 1,
137 U8(names, cname));
138 glyph_name[i][U8(names, cname)] = '\0';
139 cname += U8(names, cname) + 1;
144 static void otf_glyf(void *otf, void *glyf)
146 void *maxp = otf_table(otf, "maxp");
147 void *head = otf_table(otf, "head");
148 void *loca = otf_table(otf, "loca");
149 void *gdat;
150 void *gdat_next;
151 int n = U16(maxp, 4);
152 int fmt = U16(head, 50);
153 int i, j;
154 for (i = 0; i < n; i++) {
155 if (fmt) {
156 gdat = glyf + U32(loca, 4 * i);
157 gdat_next = glyf + U32(loca, 4 * (i + 1));
158 } else {
159 gdat = glyf + U16(loca, 2 * i) * 2;
160 gdat_next = glyf + U16(loca, 2 * (i + 1)) * 2;
162 if (gdat < gdat_next)
163 for (j = 0; j < 4; j++)
164 glyph_bbox[i][j] = S16(gdat, 2 + 2 * j);
168 static void otf_hmtx(void *otf, void *hmtx)
170 void *hhea = otf_table(otf, "hhea");
171 int n;
172 int i;
173 n = U16(hhea, 34);
174 for (i = 0; i < n; i++)
175 glyph_wid[i] = U16(hmtx, i * 4);
176 for (i = n; i < glyph_n; i++)
177 glyph_wid[i] = glyph_wid[n - 1];
180 static void otf_kern(void *otf, void *kern)
182 int n; /* number of kern subtables */
183 void *tab; /* a kern subtable */
184 int off = 4;
185 int npairs;
186 int cov;
187 int i, j;
188 int c1, c2, val;
189 n = U16(kern, 2);
190 for (i = 0; i < n; i++) {
191 tab = kern + off;
192 off += U16(tab, 2);
193 cov = U16(tab, 4);
194 if ((cov >> 8) == 0 && (cov & 1)) { /* format 0 */
195 npairs = U16(tab, 6);
196 for (j = 0; j < npairs; j++) {
197 c1 = U16(tab, 14 + 6 * j);
198 c2 = U16(tab, 14 + 6 * j + 2);
199 val = S16(tab, 14 + 6 * j + 4);
200 trfn_kern(glyph_name[c1], glyph_name[c2],
201 owid(val));
207 static int coverage(void *cov, int *out)
209 int fmt = U16(cov, 0);
210 int n = U16(cov, 2);
211 int beg, end;
212 int ncov = 0;
213 int i, j;
214 if (fmt == 1) {
215 for (i = 0; i < n; i++)
216 out[ncov++] = U16(cov, 4 + 2 * i);
218 if (fmt == 2) {
219 for (i = 0; i < n; i++) {
220 beg = U16(cov, 4 + 6 * i);
221 end = U16(cov, 4 + 6 * i + 2);
222 for (j = beg; j <= end; j++)
223 out[ncov++] = j;
226 return ncov;
229 static int classdef(void *tab, int *gl, int *cls)
231 int fmt = U16(tab, 0);
232 int beg, end;
233 int n, ngl = 0;
234 int i, j;
235 if (fmt == 1) {
236 beg = U16(tab, 2);
237 ngl = U16(tab, 4);
238 for (i = 0; i < ngl; i++) {
239 gl[i] = beg + i;
240 cls[i] = U16(tab, 6 + 2 * i);
243 if (fmt == 2) {
244 n = U16(tab, 2);
245 for (i = 0; i < n; i++) {
246 beg = U16(tab, 4 + 6 * i);
247 end = U16(tab, 4 + 6 * i + 2);
248 for (j = beg; j <= end; j++) {
249 gl[ngl] = j;
250 cls[ngl] = U16(tab, 4 + 6 * i + 4);
251 ngl++;
255 return ngl;
258 static int valuerecord_len(int fmt)
260 int off = 0;
261 int i;
262 for (i = 0; i < 8; i++)
263 if (fmt & (1 << i))
264 off += 2;
265 return off;
268 static void valuerecord_print(int fmt, void *rec)
270 int vals[8] = {0};
271 int off = 0;
272 int i;
273 for (i = 0; i < 8; i++) {
274 if (fmt & (1 << i)) {
275 vals[i] = uwid(S16(rec, off));
276 off += 2;
279 if (fmt)
280 printf(":%+d%+d%+d%+d", vals[0], vals[1], vals[2], vals[3]);
283 static int valuerecord_small(int fmt, void *rec)
285 int off = 0;
286 int i;
287 for (i = 0; i < 8; i++) {
288 if (fmt & (1 << i)) {
289 if (abs(uwid(S16(rec, off))) >= MAX(1, kmin))
290 return 0;
291 off += 2;
294 return 1;
297 static void otf_gpostype1(void *otf, char *feat, char *sub)
299 int fmt = U16(sub, 0);
300 int vfmt = U16(sub, 4);
301 int cov[NGLYPHS];
302 int ncov, nvals;
303 int vlen = valuerecord_len(vfmt);
304 int i;
305 ncov = coverage(sub + U16(sub, 2), cov);
306 if (fmt == 1) {
307 for (i = 0; i < ncov; i++) {
308 printf("gpos %s %s", feat, glyph_name[cov[i]]);
309 valuerecord_print(vfmt, sub + 6);
310 printf("\n");
313 if (fmt == 2) {
314 nvals = U16(sub, 6);
315 for (i = 0; i < nvals; i++) {
316 printf("gpos %s %s", feat, glyph_name[cov[i]]);
317 valuerecord_print(vfmt, sub + 8 + i * vlen);
318 printf("\n");
323 static void otf_gpostype2(void *otf, char *feat, char *sub)
325 int fmt = U16(sub, 0);
326 int vfmt1 = U16(sub, 4);
327 int vfmt2 = U16(sub, 6);
328 int fmtoff1, fmtoff2;
329 int vrlen; /* valuerecord1 and valuerecord2 length */
330 int i, j;
331 vrlen = valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
332 if (fmt == 1) {
333 int cov[NGLYPHS];
334 int nc1 = U16(sub, 8);
335 coverage(sub + U16(sub, 2), cov);
336 for (i = 0; i < nc1; i++) {
337 void *c2 = sub + U16(sub, 10 + 2 * i);
338 int nc2 = U16(c2, 0);
339 for (j = 0; j < nc2; j++) {
340 int second = U16(c2 + 2 + (2 + vrlen) * j, 0);
341 fmtoff1 = 2 + (2 + vrlen) * j + 2;
342 fmtoff2 = fmtoff1 + valuerecord_len(vfmt2);
343 if (valuerecord_small(vfmt1, c2 + fmtoff1) &&
344 valuerecord_small(vfmt2, c2 + fmtoff2))
345 continue;
346 printf("gpos %s 2", feat);
347 printf(" %s", glyph_name[cov[i]]);
348 valuerecord_print(vfmt1, c2 + fmtoff1);
349 printf(" %s", glyph_name[second]);
350 valuerecord_print(vfmt2, c2 + fmtoff2);
351 printf("\n");
355 if (fmt == 2) {
356 int gl1[NGLYPHS], gl2[NGLYPHS];
357 int cls1[NGLYPHS], cls2[NGLYPHS];
358 int ngl1 = classdef(sub + U16(sub, 8), gl1, cls1);
359 int ngl2 = classdef(sub + U16(sub, 10), gl2, cls2);
360 int ncls1 = U16(sub, 12);
361 int ncls2 = U16(sub, 14);
362 for (i = 0; i < ngl1; i++) {
363 for (j = 0; j < ngl2; j++) {
364 if (cls1[i] >= ncls1 || cls2[j] >= ncls2)
365 continue;
366 fmtoff1 = 16 + (cls1[i] * ncls2 + cls2[j]) * vrlen;
367 fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
368 if (valuerecord_small(vfmt1, sub + fmtoff1) &&
369 valuerecord_small(vfmt2, sub + fmtoff2))
370 continue;
371 printf("gpos %s 2", feat);
372 printf(" %s", glyph_name[gl1[i]]);
373 valuerecord_print(vfmt1, sub + fmtoff1);
374 printf(" %s", glyph_name[gl2[j]]);
375 valuerecord_print(vfmt2, sub + fmtoff2);
376 printf("\n");
382 static void otf_gpostype3(void *otf, char *feat, char *sub)
384 int fmt = U16(sub, 0);
385 int cov[NGLYPHS];
386 int i, n;
387 coverage(sub + U16(sub, 2), cov);
388 if (fmt != 1)
389 return;
390 n = U16(sub, 4);
391 for (i = 0; i < n; i++) {
392 int prev = U16(sub, 6 + 4 * i);
393 int next = U16(sub, 6 + 4 * i + 2);
394 printf("gcur %s %s", feat, glyph_name[cov[i]]);
395 if (prev)
396 printf(" %d %d", uwid(S16(sub, prev + 2)),
397 uwid(S16(sub, prev + 4)));
398 else
399 printf(" - -");
400 if (next)
401 printf(" %d %d", uwid(S16(sub, next + 2)),
402 uwid(S16(sub, next + 4)));
403 else
404 printf(" - -");
405 printf("\n");
409 static void otf_gposfeatrec(void *otf, void *gpos, void *featrec)
411 void *feats = gpos + U16(gpos, 6);
412 void *lookups = gpos + U16(gpos, 8);
413 void *feat, *lookup, *tab;
414 int nlookups, type, ntabs;
415 char tag[8] = "";
416 int i, j;
417 memcpy(tag, featrec, 4);
418 feat = feats + U16(featrec, 4);
419 nlookups = U16(feat, 2);
420 for (i = 0; i < nlookups; i++) {
421 lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
422 type = U16(lookup, 0);
423 ntabs = U16(lookup, 4);
424 for (j = 0; j < ntabs; j++) {
425 tab = lookup + U16(lookup, 6 + 2 * j);
426 if (type == 1)
427 otf_gpostype1(otf, tag, tab);
428 if (type == 2)
429 otf_gpostype2(otf, tag, tab);
430 if (type == 3)
431 otf_gpostype3(otf, tag, tab);
436 static void otf_gposlang(void *otf, void *gpos, void *lang)
438 void *feats = gpos + U16(gpos, 6);
439 int featidx = U16(lang, 2);
440 int nfeat = U16(lang, 4);
441 int i;
442 if (featidx != 0xffff)
443 otf_gposfeatrec(otf, gpos, feats + 2 + 6 * featidx);
444 for (i = 0; i < nfeat; i++)
445 otf_gposfeatrec(otf, gpos,
446 feats + 2 + 6 * U16(lang, 6 + 2 * i));
449 static void otf_gpos(void *otf, void *gpos)
451 void *scripts = gpos + U16(gpos, 4);
452 int nscripts, nlangs;
453 void *script;
454 void *grec;
455 int i, j;
456 nscripts = U16(scripts, 0);
457 for (i = 0; i < nscripts; i++) {
458 grec = scripts + 2 + 6 * i;
459 script = scripts + U16(grec, 4);
460 if (U16(script, 0))
461 otf_gposlang(otf, gpos, script + U16(script, 0));
462 nlangs = U16(script, 2);
463 for (j = 0; j < nlangs; j++)
464 otf_gposlang(otf, gpos, script +
465 U16(script, 4 + 6 * j + 4));
469 static void otf_gsubtype1(void *otf, char *feat, char *sub)
471 int cov[NGLYPHS];
472 int fmt = U16(sub, 0);
473 int ncov;
474 int n;
475 int i;
476 ncov = coverage(sub + U16(sub, 2), cov);
477 if (fmt == 1) {
478 for (i = 0; i < ncov; i++)
479 printf("gsub %s 2 -%s +%s\n",
480 feat, glyph_name[cov[i]],
481 glyph_name[cov[i] + S16(sub, 4)]);
483 if (fmt == 2) {
484 n = U16(sub, 4);
485 for (i = 0; i < n; i++)
486 printf("gsub %s 2 -%s +%s\n",
487 feat, glyph_name[cov[i]],
488 glyph_name[U16(sub, 6 + 2 * i)]);
492 static void otf_gsubtype3(void *otf, char *feat, char *sub)
494 int cov[NGLYPHS];
495 int fmt = U16(sub, 0);
496 int n, i, j;
497 if (fmt != 1)
498 return;
499 coverage(sub + U16(sub, 2), cov);
500 n = U16(sub, 4);
501 for (i = 0; i < n; i++) {
502 void *alt = sub + U16(sub, 6 + 2 * i);
503 int nalt = U16(alt, 0);
504 for (j = 0; j < nalt; j++)
505 printf("gsub %s 2 -%s +%s\n",
506 feat, glyph_name[cov[i]],
507 glyph_name[U16(alt, 2 + 2 * j)]);
511 static void otf_gsubtype4(void *otf, char *feat, char *sub)
513 int fmt = U16(sub, 0);
514 int cov[NGLYPHS];
515 int n, i, j, k;
516 if (fmt != 1)
517 return;
518 coverage(sub + U16(sub, 2), cov);
519 n = U16(sub, 4);
520 for (i = 0; i < n; i++) {
521 void *set = sub + U16(sub, 6 + 2 * i);
522 int nset = U16(set, 0);
523 for (j = 0; j < nset; j++) {
524 void *lig = set + U16(set, 2 + 2 * j);
525 int nlig = U16(lig, 2);
526 printf("gsub %s %d -%s",
527 feat, nlig + 1, glyph_name[cov[i]]);
528 for (k = 0; k < nlig - 1; k++)
529 printf(" -%s", glyph_name[U16(lig, 4 + 2 * k)]);
530 printf(" +%s\n", glyph_name[U16(lig, 0)]);
535 static void otf_gsubfeatrec(void *otf, void *gsub, void *featrec)
537 void *feats = gsub + U16(gsub, 6);
538 void *lookups = gsub + U16(gsub, 8);
539 void *feat, *lookup, *tab;
540 int nlookups, type, ntabs;
541 char tag[8] = "";
542 int i, j;
543 memcpy(tag, featrec, 4);
544 feat = feats + U16(featrec, 4);
545 nlookups = U16(feat, 2);
546 for (i = 0; i < nlookups; i++) {
547 lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
548 type = U16(lookup, 0);
549 ntabs = U16(lookup, 4);
550 for (j = 0; j < ntabs; j++) {
551 tab = lookup + U16(lookup, 6 + 2 * j);
552 if (type == 1)
553 otf_gsubtype1(otf, tag, tab);
554 if (type == 3)
555 otf_gsubtype3(otf, tag, tab);
556 if (type == 4)
557 otf_gsubtype4(otf, tag, tab);
562 static void otf_gsublang(void *otf, void *gsub, void *lang)
564 void *feats = gsub + U16(gsub, 6);
565 int featidx = U16(lang, 2);
566 int nfeat = U16(lang, 4);
567 int i;
568 if (featidx != 0xffff)
569 otf_gsubfeatrec(otf, gsub, feats + 2 + 6 * featidx);
570 for (i = 0; i < nfeat; i++)
571 otf_gsubfeatrec(otf, gsub,
572 feats + 2 + 6 * U16(lang, 6 + 2 * i));
575 static void otf_gsub(void *otf, void *gsub)
577 void *scripts = gsub + U16(gsub, 4);
578 int nscripts, nlangs;
579 void *script;
580 int i, j;
581 nscripts = U16(scripts, 0);
582 for (i = 0; i < nscripts; i++) {
583 script = scripts + U16(scripts + 2 + 6 * i, 4);
584 nlangs = U16(script, 2);
585 if (U16(script, 0))
586 otf_gsublang(otf, gsub, script + U16(script, 0));
587 for (j = 0; j < nlangs; j++)
588 otf_gsublang(otf, gsub, script +
589 U16(script, 4 + 6 * j + 4));
593 int xread(int fd, char *buf, int len)
595 int nr = 0;
596 while (nr < len) {
597 int ret = read(fd, buf + nr, len - nr);
598 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
599 continue;
600 if (ret <= 0)
601 break;
602 nr += ret;
604 return nr;
607 static char buf[BUFLEN];
609 int otf_read(void)
611 int i;
612 if (xread(0, buf, sizeof(buf)) <= 0)
613 return 1;
614 upm = U16(otf_table(buf, "head"), 18);
615 otf_cmap(buf, otf_table(buf, "cmap"));
616 otf_post(buf, otf_table(buf, "post"));
617 if (otf_table(buf, "glyf"))
618 otf_glyf(buf, otf_table(buf, "glyf"));
619 otf_hmtx(buf, otf_table(buf, "hmtx"));
620 for (i = 0; i < glyph_n; i++) {
621 trfn_char(glyph_name[i], -1,
622 glyph_code[i] != 0xffff ? glyph_code[i] : 0,
623 owid(glyph_wid[i]),
624 owid(glyph_bbox[i][0]), owid(glyph_bbox[i][1]),
625 owid(glyph_bbox[i][2]), owid(glyph_bbox[i][3]));
627 if (otf_table(buf, "kern"))
628 otf_kern(buf, otf_table(buf, "kern"));
629 return 0;
632 void otf_feat(int r, int k)
634 res = r;
635 kmin = k;
636 if (otf_table(buf, "GSUB"))
637 otf_gsub(buf, otf_table(buf, "GSUB"));
638 if (otf_table(buf, "GPOS"))
639 otf_gpos(buf, otf_table(buf, "GPOS"));
642 static char *macset[] = {
643 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
644 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
645 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
646 "comma", "hyphen", "period", "slash", "zero",
647 "one", "two", "three", "four", "five",
648 "six", "seven", "eight", "nine", "colon",
649 "semicolon", "less", "equal", "greater", "question",
650 "at", "A", "B", "C", "D",
651 "E", "F", "G", "H", "I",
652 "J", "K", "L", "M", "N",
653 "O", "P", "Q", "R", "S",
654 "T", "U", "V", "W", "X",
655 "Y", "Z", "bracketleft", "backslash", "bracketright",
656 "asciicircum", "underscore", "grave", "a", "b",
657 "c", "d", "e", "f", "g",
658 "h", "i", "j", "k", "l",
659 "m", "n", "o", "p", "q",
660 "r", "s", "t", "u", "v",
661 "w", "x", "y", "z", "braceleft",
662 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
663 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
664 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
665 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
666 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
667 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
668 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
669 "dagger", "degree", "cent", "sterling", "section",
670 "bullet", "paragraph", "germandbls", "registered", "copyright",
671 "trademark", "acute", "dieresis", "notequal", "AE",
672 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
673 "yen", "mu", "partialdiff", "summation", "product",
674 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
675 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
676 "radical", "florin", "approxequal", "Delta", "guillemotleft",
677 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
678 "Otilde", "OE", "oe", "endash", "emdash",
679 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
680 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
681 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
682 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
683 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
684 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
685 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
686 "dotlessi", "circumflex", "tilde", "macron", "breve",
687 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
688 "caron", "Lslash", "lslash", "Scaron", "scaron",
689 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
690 "Yacute", "yacute", "Thorn", "thorn", "minus",
691 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
692 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
693 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
694 "Ccaron", "ccaron", "dcroat",