otf: read pairwise kerning values for glyph classes
[neatmkfn.git] / otf.c
blob3e9b5e116df8e09834f28e23c189862800ed3510
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 void *idarray;
75 int beg, end, delta, offset;
76 int i, j;
77 nsegs = U16(cmap4, 6) / 2;
78 ends = cmap4 + 14;
79 begs = ends + 2 * nsegs + 2;
80 deltas = begs + 2 * nsegs;
81 offsets = deltas + 2 * nsegs;
82 idarray = offsets + 2 * nsegs;
83 for (i = 0; i < nsegs; i++) {
84 beg = U16(begs, 2 * i);
85 end = U16(ends, 2 * i);
86 delta = U16(deltas, 2 * i);
87 offset = U16(offsets, 2 * i);
88 if (offset) {
89 for (j = beg; j <= end; j++)
90 glyph_code[U16(offsets + i * 2,
91 offset + (j - beg) * 2)] = j;
92 } else {
93 for (j = beg; j <= end; j++)
94 glyph_code[(j + delta) & 0xffff] = j;
99 /* parse otf cmap header */
100 static void otf_cmap(void *otf, void *cmap)
102 void *recs = cmap + CMAPLEN; /* cmap records */
103 void *rec; /* a cmap record */
104 void *tab; /* a cmap subtable */
105 int plat, enc;
106 int fmt;
107 int nrecs = U16(cmap, 2);
108 int i;
109 for (i = 0; i < nrecs; i++) {
110 rec = recs + i * CMAPRECLEN;
111 plat = U16(rec, 0);
112 enc = U16(rec, 2);
113 tab = cmap + U32(rec, 4);
114 fmt = U16(tab, 0);
115 if (plat == 3 && enc == 1 && fmt == 4)
116 otf_cmap4(otf, tab);
120 static void otf_post(void *otf, void *post)
122 void *post2; /* version 2.0 header */
123 void *index; /* glyph name indices */
124 void *names; /* glyph names */
125 int i, idx;
126 int cname = 0;
127 if (U32(post, 0) != 0x00020000)
128 return;
129 post2 = post + 32;
130 glyph_n = U16(post2, 0);
131 index = post2 + 2;
132 names = index + 2 * glyph_n;
133 for (i = 0; i < glyph_n; i++) {
134 idx = U16(index, 2 * i);
135 if (idx <= 257) {
136 strcpy(glyph_name[i], macset[idx]);
137 } else {
138 memcpy(glyph_name[i], names + cname + 1,
139 U8(names, cname));
140 glyph_name[i][U8(names, cname)] = '\0';
141 cname += U8(names, cname) + 1;
146 static void otf_glyf(void *otf, void *glyf)
148 void *maxp = otf_table(otf, "maxp");
149 void *head = otf_table(otf, "head");
150 void *loca = otf_table(otf, "loca");
151 void *gdat;
152 void *gdat_next;
153 int n = U16(maxp, 4);
154 int fmt = U16(head, 50);
155 int i, j;
156 for (i = 0; i < n; i++) {
157 if (fmt) {
158 gdat = glyf + U32(loca, 4 * i);
159 gdat_next = glyf + U32(loca, 4 * (i + 1));
160 } else {
161 gdat = glyf + U16(loca, 2 * i) * 2;
162 gdat_next = glyf + U16(loca, 2 * (i + 1)) * 2;
164 if (gdat < gdat_next)
165 for (j = 0; j < 4; j++)
166 glyph_bbox[i][j] = S16(gdat, 2 + 2 * j);
170 static void otf_hmtx(void *otf, void *hmtx)
172 void *hhea = otf_table(otf, "hhea");
173 int n;
174 int i;
175 n = U16(hhea, 34);
176 for (i = 0; i < n; i++)
177 glyph_wid[i] = U16(hmtx, i * 4);
178 for (i = n; i < glyph_n; i++)
179 glyph_wid[i] = glyph_wid[n - 1];
182 static void otf_kern(void *otf, void *kern)
184 int n; /* number of kern subtables */
185 void *tab; /* a kern subtable */
186 int off = 4;
187 int npairs;
188 int cov;
189 int i, j;
190 int c1, c2, val;
191 n = U16(kern, 2);
192 for (i = 0; i < n; i++) {
193 tab = kern + off;
194 off += U16(tab, 2);
195 cov = U16(tab, 4);
196 if ((cov >> 8) == 0 && (cov & 1)) { /* format 0 */
197 npairs = U16(tab, 6);
198 for (j = 0; j < npairs; j++) {
199 c1 = U16(tab, 14 + 6 * j);
200 c2 = U16(tab, 14 + 6 * j + 2);
201 val = S16(tab, 14 + 6 * j + 4);
202 trfn_kern(glyph_name[c1], glyph_name[c2],
203 owid(val));
209 static int coverage(void *cov, int *out)
211 int fmt = U16(cov, 0);
212 int n = U16(cov, 2);
213 int beg, end;
214 int ncov = 0;
215 int i, j;
216 if (fmt == 1) {
217 for (i = 0; i < n; i++)
218 out[ncov++] = U16(cov, 4 + 2 * i);
220 if (fmt == 2) {
221 for (i = 0; i < n; i++) {
222 beg = U16(cov, 4 + 6 * i);
223 end = U16(cov, 4 + 6 * i + 2);
224 for (j = beg; j <= end; j++)
225 out[ncov++] = j;
228 return ncov;
231 static int classdef(void *tab, int *gl, int *cls)
233 int fmt = U16(tab, 0);
234 int beg, end;
235 int n, ngl = 0;
236 int i, j;
237 if (fmt == 1) {
238 beg = U16(tab, 2);
239 ngl = U16(tab, 4);
240 for (i = 0; i < ngl; i++) {
241 gl[i] = beg + i;
242 cls[i] = U16(tab, 6 + 2 * i);
245 if (fmt == 2) {
246 n = U16(tab, 2);
247 for (i = 0; i < n; i++) {
248 beg = U16(tab, 4 + 6 * i);
249 end = U16(tab, 4 + 6 * i + 2);
250 for (j = beg; j <= end; j++) {
251 gl[ngl] = j;
252 cls[ngl] = U16(tab, 4 + 6 * i + 4);
253 ngl++;
257 return ngl;
260 static int valuerecord_len(int fmt)
262 int off = 0;
263 int i;
264 for (i = 0; i < 8; i++)
265 if (fmt & (1 << i))
266 off += 2;
267 return off;
270 static void valuerecord_print(int fmt, void *rec)
272 int vals[8] = {0};
273 int off = 0;
274 int i;
275 for (i = 0; i < 8; i++) {
276 if (fmt & (1 << i)) {
277 vals[i] = uwid(S16(rec, off));
278 off += 2;
281 if (fmt)
282 printf(":%+d%+d%+d%+d", vals[0], vals[1], vals[2], vals[3]);
285 static int valuerecord_small(int fmt, void *rec)
287 int off = 0;
288 int i;
289 for (i = 0; i < 8; i++) {
290 if (fmt & (1 << i)) {
291 if (abs(uwid(S16(rec, off))) >= MAX(1, kmin))
292 return 0;
293 off += 2;
296 return 1;
299 static void otf_gpostype1(void *otf, char *feat, char *sub)
301 int fmt = U16(sub, 0);
302 int vfmt = U16(sub, 4);
303 int cov[NGLYPHS];
304 int ncov, nvals;
305 int vlen = valuerecord_len(vfmt);
306 int i;
307 ncov = coverage(sub + U16(sub, 2), cov);
308 if (fmt == 1) {
309 for (i = 0; i < ncov; i++) {
310 printf("gpos %s %s", feat, glyph_name[cov[i]]);
311 valuerecord_print(vfmt, sub + 6);
312 printf("\n");
315 if (fmt == 2) {
316 nvals = U16(sub, 6);
317 for (i = 0; i < nvals; i++) {
318 printf("gpos %s %s", feat, glyph_name[cov[i]]);
319 valuerecord_print(vfmt, sub + 8 + i * vlen);
320 printf("\n");
325 static void otf_gpostype2(void *otf, char *feat, char *sub)
327 int fmt = U16(sub, 0);
328 int vfmt1 = U16(sub, 4);
329 int vfmt2 = U16(sub, 6);
330 int fmtoff1, fmtoff2;
331 int vrlen; /* valuerecord1 and valuerecord2 length */
332 int i, j;
333 vrlen = valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
334 if (fmt == 1) {
335 int cov[NGLYPHS];
336 int nc1 = U16(sub, 8);
337 coverage(sub + U16(sub, 2), cov);
338 for (i = 0; i < nc1; i++) {
339 void *c2 = sub + U16(sub, 10 + 2 * i);
340 int nc2 = U16(c2, 0);
341 for (j = 0; j < nc2; j++) {
342 int second = U16(c2 + 2 + (2 + vrlen) * j, 0);
343 fmtoff1 = 2 + (2 + vrlen) * j + 2;
344 fmtoff2 = fmtoff1 + valuerecord_len(vfmt2);
345 if (valuerecord_small(vfmt1, c2 + fmtoff1) &&
346 valuerecord_small(vfmt2, c2 + fmtoff2))
347 continue;
348 printf("gpos %s 2", feat);
349 printf(" %s", glyph_name[cov[i]]);
350 valuerecord_print(vfmt1, c2 + fmtoff1);
351 printf(" %s", glyph_name[second]);
352 valuerecord_print(vfmt2, c2 + fmtoff2);
353 printf("\n");
357 if (fmt == 2) {
358 int gl1[NGLYPHS], gl2[NGLYPHS];
359 int cls1[NGLYPHS], cls2[NGLYPHS];
360 int ngl1 = classdef(sub + U16(sub, 8), gl1, cls1);
361 int ngl2 = classdef(sub + U16(sub, 10), gl2, cls2);
362 int ncls1 = U16(sub, 12);
363 int ncls2 = U16(sub, 14);
364 for (i = 0; i < ngl1; i++) {
365 for (j = 0; j < ngl2; j++) {
366 if (cls1[i] >= ncls1 || cls2[j] >= ncls2)
367 continue;
368 fmtoff1 = 16 + (cls1[i] * ncls2 + cls2[j]) * vrlen;
369 fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
370 if (valuerecord_small(vfmt1, sub + fmtoff1) &&
371 valuerecord_small(vfmt2, sub + fmtoff2))
372 continue;
373 printf("gpos %s 2", feat);
374 printf(" %s", glyph_name[gl1[i]]);
375 valuerecord_print(vfmt1, sub + fmtoff1);
376 printf(" %s", glyph_name[gl2[j]]);
377 valuerecord_print(vfmt2, sub + fmtoff2);
378 printf("\n");
384 static void otf_gpostype3(void *otf, char *feat, char *sub)
386 int fmt = U16(sub, 0);
387 int cov[NGLYPHS];
388 int ncov, i, n;
389 ncov = coverage(sub + U16(sub, 2), cov);
390 if (fmt != 1)
391 return;
392 n = U16(sub, 4);
393 for (i = 0; i < n; i++) {
394 int prev = U16(sub, 6 + 4 * i);
395 int next = U16(sub, 6 + 4 * i + 2);
396 printf("gcur %s %s", feat, glyph_name[cov[i]]);
397 if (prev)
398 printf(" %d %d", uwid(S16(sub, prev + 2)),
399 uwid(S16(sub, prev + 4)));
400 else
401 printf(" - -");
402 if (next)
403 printf(" %d %d", uwid(S16(sub, next + 2)),
404 uwid(S16(sub, next + 4)));
405 else
406 printf(" - -");
407 printf("\n");
411 static void otf_gposfeatrec(void *otf, void *gpos, void *featrec)
413 void *feats = gpos + U16(gpos, 6);
414 void *lookups = gpos + U16(gpos, 8);
415 void *feat, *lookup, *tab;
416 int nlookups, type, flag, ntabs;
417 char tag[8] = "";
418 int i, j;
419 memcpy(tag, featrec, 4);
420 feat = feats + U16(featrec, 4);
421 nlookups = U16(feat, 2);
422 for (i = 0; i < nlookups; i++) {
423 lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
424 type = U16(lookup, 0);
425 flag = U16(lookup, 2);
426 ntabs = U16(lookup, 4);
427 for (j = 0; j < ntabs; j++) {
428 tab = lookup + U16(lookup, 6 + 2 * j);
429 if (type == 1)
430 otf_gpostype1(otf, tag, tab);
431 if (type == 2)
432 otf_gpostype2(otf, tag, tab);
433 if (type == 3)
434 otf_gpostype3(otf, tag, tab);
439 static void otf_gposlang(void *otf, void *gpos, void *lang)
441 void *feats = gpos + U16(gpos, 6);
442 int featidx = U16(lang, 2);
443 int nfeat = U16(lang, 4);
444 int i;
445 if (featidx != 0xffff)
446 otf_gposfeatrec(otf, gpos, feats + 2 + 6 * featidx);
447 for (i = 0; i < nfeat; i++)
448 otf_gposfeatrec(otf, gpos,
449 feats + 2 + 6 * U16(lang, 6 + 2 * i));
452 static void otf_gpos(void *otf, void *gpos)
454 void *scripts = gpos + U16(gpos, 4);
455 int nscripts, nlangs;
456 void *script;
457 void *grec;
458 int i, j;
459 nscripts = U16(scripts, 0);
460 for (i = 0; i < nscripts; i++) {
461 grec = scripts + 2 + 6 * i;
462 script = scripts + U16(grec, 4);
463 if (U16(script, 0))
464 otf_gposlang(otf, gpos, script + U16(script, 0));
465 nlangs = U16(script, 2);
466 for (j = 0; j < nlangs; j++)
467 otf_gposlang(otf, gpos, script +
468 U16(script, 4 + 6 * j + 4));
472 static void otf_gsubtype1(void *otf, char *feat, char *sub)
474 int cov[NGLYPHS];
475 int fmt = U16(sub, 0);
476 int ncov;
477 int n;
478 int i;
479 ncov = coverage(sub + U16(sub, 2), cov);
480 if (fmt == 1) {
481 for (i = 0; i < ncov; i++)
482 printf("gsub %s 2 -%s +%s\n",
483 feat, glyph_name[cov[i]],
484 glyph_name[cov[i] + S16(sub, 4)]);
486 if (fmt == 2) {
487 n = U16(sub, 4);
488 for (i = 0; i < n; i++)
489 printf("gsub %s 2 -%s +%s\n",
490 feat, glyph_name[cov[i]],
491 glyph_name[U16(sub, 6 + 2 * i)]);
495 static void otf_gsubtype3(void *otf, char *feat, char *sub)
497 int cov[NGLYPHS];
498 int fmt = U16(sub, 0);
499 int ncov, n, i, j;
500 if (fmt != 1)
501 return;
502 ncov = coverage(sub + U16(sub, 2), cov);
503 n = U16(sub, 4);
504 for (i = 0; i < n; i++) {
505 void *alt = sub + U16(sub, 6 + 2 * i);
506 int nalt = U16(alt, 0);
507 for (j = 0; j < nalt; j++)
508 printf("gsub %s 2 -%s +%s\n",
509 feat, glyph_name[cov[i]],
510 glyph_name[U16(alt, 2 + 2 * j)]);
514 static void otf_gsubtype4(void *otf, char *feat, char *sub)
516 int fmt = U16(sub, 0);
517 int cov[NGLYPHS];
518 int ncov, n, i, j, k;
519 if (fmt != 1)
520 return;
521 ncov = coverage(sub + U16(sub, 2), cov);
522 n = U16(sub, 4);
523 for (i = 0; i < n; i++) {
524 void *set = sub + U16(sub, 6 + 2 * i);
525 int nset = U16(set, 0);
526 for (j = 0; j < nset; j++) {
527 void *lig = set + U16(set, 2 + 2 * j);
528 int nlig = U16(lig, 2);
529 printf("gsub %s %d -%s",
530 feat, nlig + 1, glyph_name[cov[i]]);
531 for (k = 0; k < nlig - 1; k++)
532 printf(" -%s", glyph_name[U16(lig, 4 + 2 * k)]);
533 printf(" +%s\n", glyph_name[U16(lig, 0)]);
538 static void otf_gsubfeatrec(void *otf, void *gsub, void *featrec)
540 void *feats = gsub + U16(gsub, 6);
541 void *lookups = gsub + U16(gsub, 8);
542 void *feat, *lookup, *tab;
543 int nlookups, type, flag, ntabs;
544 char tag[8] = "";
545 int i, j;
546 memcpy(tag, featrec, 4);
547 feat = feats + U16(featrec, 4);
548 nlookups = U16(feat, 2);
549 for (i = 0; i < nlookups; i++) {
550 lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
551 type = U16(lookup, 0);
552 flag = U16(lookup, 2);
553 ntabs = U16(lookup, 4);
554 for (j = 0; j < ntabs; j++) {
555 tab = lookup + U16(lookup, 6 + 2 * j);
556 if (type == 1)
557 otf_gsubtype1(otf, tag, tab);
558 if (type == 3)
559 otf_gsubtype3(otf, tag, tab);
560 if (type == 4)
561 otf_gsubtype4(otf, tag, tab);
566 static void otf_gsublang(void *otf, void *gsub, void *lang)
568 void *feats = gsub + U16(gsub, 6);
569 int featidx = U16(lang, 2);
570 int nfeat = U16(lang, 4);
571 int i;
572 if (featidx != 0xffff)
573 otf_gsubfeatrec(otf, gsub, feats + 2 + 6 * featidx);
574 for (i = 0; i < nfeat; i++)
575 otf_gsubfeatrec(otf, gsub,
576 feats + 2 + 6 * U16(lang, 6 + 2 * i));
579 static void otf_gsub(void *otf, void *gsub)
581 void *scripts = gsub + U16(gsub, 4);
582 int nscripts, nlangs;
583 void *script;
584 int i, j;
585 nscripts = U16(scripts, 0);
586 for (i = 0; i < nscripts; i++) {
587 script = scripts + U16(scripts + 2 + 6 * i, 4);
588 nlangs = U16(script, 2);
589 if (U16(script, 0))
590 otf_gsublang(otf, gsub, script + U16(script, 0));
591 for (j = 0; j < nlangs; j++)
592 otf_gsublang(otf, gsub, script +
593 U16(script, 4 + 6 * j + 4));
597 int xread(int fd, char *buf, int len)
599 int nr = 0;
600 while (nr < len) {
601 int ret = read(fd, buf + nr, len - nr);
602 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
603 continue;
604 if (ret <= 0)
605 break;
606 nr += ret;
608 return nr;
611 static char buf[BUFLEN];
613 int otf_read(void)
615 int i;
616 if (xread(0, buf, sizeof(buf)) <= 0)
617 return 1;
618 upm = U16(otf_table(buf, "head"), 18);
619 otf_cmap(buf, otf_table(buf, "cmap"));
620 otf_post(buf, otf_table(buf, "post"));
621 if (otf_table(buf, "glyf"))
622 otf_glyf(buf, otf_table(buf, "glyf"));
623 otf_hmtx(buf, otf_table(buf, "hmtx"));
624 for (i = 0; i < glyph_n; i++) {
625 trfn_char(glyph_name[i], -1,
626 glyph_code[i] != 0xffff ? glyph_code[i] : 0,
627 owid(glyph_wid[i]),
628 owid(glyph_bbox[i][0]), owid(glyph_bbox[i][1]),
629 owid(glyph_bbox[i][2]), owid(glyph_bbox[i][3]));
631 if (otf_table(buf, "kern"))
632 otf_kern(buf, otf_table(buf, "kern"));
633 return 0;
636 void otf_feat(int r, int k)
638 res = r;
639 kmin = k;
640 if (otf_table(buf, "GSUB"))
641 otf_gsub(buf, otf_table(buf, "GSUB"));
642 if (otf_table(buf, "GPOS"))
643 otf_gpos(buf, otf_table(buf, "GPOS"));
646 static char *macset[] = {
647 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
648 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
649 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
650 "comma", "hyphen", "period", "slash", "zero",
651 "one", "two", "three", "four", "five",
652 "six", "seven", "eight", "nine", "colon",
653 "semicolon", "less", "equal", "greater", "question",
654 "at", "A", "B", "C", "D",
655 "E", "F", "G", "H", "I",
656 "J", "K", "L", "M", "N",
657 "O", "P", "Q", "R", "S",
658 "T", "U", "V", "W", "X",
659 "Y", "Z", "bracketleft", "backslash", "bracketright",
660 "asciicircum", "underscore", "grave", "a", "b",
661 "c", "d", "e", "f", "g",
662 "h", "i", "j", "k", "l",
663 "m", "n", "o", "p", "q",
664 "r", "s", "t", "u", "v",
665 "w", "x", "y", "z", "braceleft",
666 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
667 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
668 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
669 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
670 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
671 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
672 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
673 "dagger", "degree", "cent", "sterling", "section",
674 "bullet", "paragraph", "germandbls", "registered", "copyright",
675 "trademark", "acute", "dieresis", "notequal", "AE",
676 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
677 "yen", "mu", "partialdiff", "summation", "product",
678 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
679 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
680 "radical", "florin", "approxequal", "Delta", "guillemotleft",
681 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
682 "Otilde", "OE", "oe", "endash", "emdash",
683 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
684 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
685 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
686 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
687 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
688 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
689 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
690 "dotlessi", "circumflex", "tilde", "macron", "breve",
691 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
692 "caron", "Lslash", "lslash", "Scaron", "scaron",
693 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
694 "Yacute", "yacute", "Thorn", "thorn", "minus",
695 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
696 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
697 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
698 "Ccaron", "ccaron", "dcroat",