diff options
| -rw-r--r-- | .cvsignore | 1 | ||||
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | bk_info.c | 17 | ||||
| -rw-r--r-- | bk_man.c | 7 | ||||
| -rw-r--r-- | bk_paper.c | 884 | ||||
| -rw-r--r-- | bk_pdf.c | 467 | ||||
| -rw-r--r-- | bk_ps.c | 144 | ||||
| -rw-r--r-- | bk_text.c | 19 | ||||
| -rw-r--r-- | bk_whlp.c | 4 | ||||
| -rw-r--r-- | bk_xhtml.c | 4 | ||||
| -rw-r--r-- | halibut.h | 29 | ||||
| -rw-r--r-- | help.c | 2 | ||||
| -rw-r--r-- | main.c | 62 | ||||
| -rw-r--r-- | misc.c | 130 | ||||
| -rw-r--r-- | paper.h | 235 | ||||
| -rw-r--r-- | psdata.c | 2114 |
16 files changed, 4065 insertions, 58 deletions
@@ -5,3 +5,4 @@ build *.log *.1 *.info *.info-* +*.ps *.pdf @@ -100,8 +100,8 @@ SRC := ../ MODULES := main malloc ustring error help licence version misc tree234 MODULES += input keywords contents index style biblio -MODULES += bk_text bk_xhtml bk_whlp bk_man bk_info -MODULES += winhelp +MODULES += bk_text bk_xhtml bk_whlp bk_man bk_info bk_paper bk_ps bk_pdf +MODULES += winhelp psdata OBJECTS := $(addsuffix .o,$(MODULES)) DEPS := $(addsuffix .d,$(MODULES)) @@ -119,7 +119,7 @@ paragraph *info_config_filename(char *filename) } void info_backend(paragraph *sourceform, keywordlist *keywords, - indexdata *idx) { + indexdata *idx, void *unused) { paragraph *p; infoconfig conf; word *prefix, *body, *wp; @@ -140,8 +140,7 @@ void info_backend(paragraph *sourceform, keywordlist *keywords, int width = 70, listindentbefore = 1, listindentafter = 3; int indent_code = 2, index_width = 40; - IGNORE(keywords); /* we don't happen to need this */ - IGNORE(idx); /* or this */ + IGNORE(unused); conf = info_configure(sourceform); @@ -839,12 +838,14 @@ static int info_width_internal(word *words, int xrefs) { return 0; /* should never happen */ } -static int info_width_noxrefs(word *words) +static int info_width_noxrefs(void *ctx, word *words) { + IGNORE(ctx); return info_width_internal(words, FALSE); } -static int info_width_xrefs(word *words) +static int info_width_xrefs(void *ctx, word *words) { + IGNORE(ctx); return info_width_internal(words, TRUE); } @@ -866,7 +867,8 @@ static void info_heading(rdstringc *text, word *tprefix, firstlinewidth = width - length; wrapwidth = width; - wrapping = wrap_para(words, firstlinewidth, wrapwidth, info_width_noxrefs); + wrapping = wrap_para(words, firstlinewidth, wrapwidth, + info_width_noxrefs, NULL, 0); for (p = wrapping; p; p = p->next) { info_rdaddwc(&t, p->begin, p->end, FALSE); length = (t.text ? strlen(t.text) : 0); @@ -930,7 +932,8 @@ static void info_para(rdstringc *text, word *prefix, char *prefixextra, } else e = indent + extraindent; - wrapping = wrap_para(words, firstlinewidth, width, info_width_xrefs); + wrapping = wrap_para(words, firstlinewidth, width, info_width_xrefs, + NULL, 0); for (p = wrapping; p; p = p->next) { for (i = 0; i < e; i++) rdaddc(text, ' '); @@ -94,13 +94,14 @@ paragraph *man_config_filename(char *filename) #define QUOTE_QUOTES 2 /* quote double quotes by doubling them */ void man_backend(paragraph *sourceform, keywordlist *keywords, - indexdata *idx) { + indexdata *idx, void *unused) { paragraph *p; FILE *fp; manconfig conf; - IGNORE(keywords); /* we don't happen to need this */ - IGNORE(idx); /* or this */ + IGNORE(unused); + IGNORE(keywords); + IGNORE(idx); conf = man_configure(sourceform); diff --git a/bk_paper.c b/bk_paper.c new file mode 100644 index 0000000..0bf3ce1 --- /dev/null +++ b/bk_paper.c @@ -0,0 +1,884 @@ +/* + * Paper printing pre-backend for Halibut. + * + * This module does all the processing common to both PostScript + * and PDF output: selecting fonts, line wrapping and page breaking + * in accordance with font metrics, laying out the contents and + * index pages, generally doing all the page layout. After this, + * bk_ps.c and bk_pdf.c should only need to do linear translations + * into their literal output format. + */ + +/* + * To be done: + * + * - Text wrapping is suspicious in both PS and PDF: the space + * adjust seems to be _approximately_ working, but not exactly. + * I bet some rounding error compensation is required. + * + * - set up contents section now we know what sections begin on + * which pages + * + * - do cross-reference rectangles + * + * - do PDF outline + * + * - all the missing features in text rendering (code paragraphs, + * list bullets, indentation, section heading styles) + * + * - index + * + * That should bring us to the same level of functionality that + * original-Halibut had, and the same in PDF plus the obvious + * interactive navigation features. After that, in future work: + * + * - linearised PDF, perhaps? + * + * - I'm uncertain of whether I need to include a ToUnicode CMap + * in each of my font definitions in PDF. Currently things (by + * which I mean cut and paste out of acroread) seem to be + * working fairly happily without it, but I don't know. + * + * - configurability + * + * - title pages + */ + +#include <assert.h> +#include <stdio.h> + +#include "halibut.h" +#include "paper.h" + +static font_data *make_std_font(font_list *fontlist, char const *name); +static void wrap_paragraph(para_data *pdata, word *words, + int w, int i1, int i2); +static page_data *page_breaks(line_data *first, line_data *last, + int page_height); +static void render_line(line_data *ldata, int left_x, int top_y); + +void *paper_pre_backend(paragraph *sourceform, keywordlist *keywords, + indexdata *idx) { + paragraph *p; + document *doc; + int indent, extra_indent, firstline_indent; + para_data *pdata; + line_data *ldata, *firstline, *lastline; + font_data *tr, *ti, *cr; + page_data *pages; + font_list *fontlist; + + /* + * FIXME: All these things ought to become configurable. + */ + int paper_width = 595 * 4096; + int paper_height = 841 * 4096; + int left_margin = 72 * 4096; + int top_margin = 72 * 4096; + int right_margin = 72 * 4096; + int bottom_margin = 108 * 4096; + int indent_list_bullet = 6 * 4096; + int indent_list = 24 * 4096; + int indent_quote = 18 * 4096; + int base_leading = 4096; + int base_para_spacing = 10 * 4096; + + int base_width = paper_width - left_margin - right_margin; + int page_height = paper_height - top_margin - bottom_margin; + + IGNORE(keywords); /* FIXME */ + IGNORE(idx); /* FIXME */ + IGNORE(indent_list_bullet); /* FIXME */ + + /* + * First, set up some font structures. + */ + fontlist = mknew(font_list); + fontlist->head = fontlist->tail = NULL; + tr = make_std_font(fontlist, "Times-Roman"); + ti = make_std_font(fontlist, "Times-Italic"); + cr = make_std_font(fontlist, "Courier"); + + /* + * Go through and break up each paragraph into lines. + */ + indent = 0; + firstline = lastline = NULL; + for (p = sourceform; p; p = p->next) { + p->private_data = NULL; + + switch (p->type) { + /* + * These paragraph types are either invisible or don't + * define text in the normal sense. Either way, they + * don't require wrapping. + */ + case para_IM: + case para_BR: + case para_Rule: + case para_Biblio: + case para_NotParaType: + case para_Config: + case para_VersionID: + case para_NoCite: + break; + + /* + * These paragraph types don't require wrapping, but + * they do affect the line width to which we wrap the + * rest of the paragraphs, so we need to pay attention. + */ + case para_LcontPush: + indent += indent_list; break; + case para_LcontPop: + indent -= indent_list; assert(indent >= 0); break; + case para_QuotePush: + indent += indent_quote; break; + case para_QuotePop: + indent -= indent_quote; assert(indent >= 0); break; + + /* + * This paragraph type is special. Process it + * specially. + */ + case para_Code: + /* FIXME */ + break; + + /* + * All of these paragraph types require wrapping in the + * ordinary way. So we must supply a set of fonts, a + * line width and auxiliary information (e.g. bullet + * text) for each one. + */ + case para_Chapter: + case para_Appendix: + case para_UnnumberedChapter: + case para_Heading: + case para_Subsect: + case para_Normal: + case para_BiblioCited: + case para_Bullet: + case para_NumberedList: + case para_DescribedThing: + case para_Description: + case para_Copyright: + case para_Title: + pdata = mknew(para_data); + + /* + * FIXME: Subsidiary switch on paragraph type to decide + * what font set to use for this paragraph. + */ + pdata->fonts[FONT_NORMAL] = tr; + pdata->sizes[FONT_NORMAL] = 12; + pdata->fonts[FONT_EMPH] = ti; + pdata->sizes[FONT_EMPH] = 12; + pdata->fonts[FONT_CODE] = cr; + pdata->sizes[FONT_CODE] = 12; + + /* + * FIXME: Also select an indentation level depending on + * the paragraph type (list paragraphs other than + * para_DescribedThing need extra indent). + * + * Perhaps at some point we might even arrange for the + * user to be able to request indented first lines in + * paragraphs. + */ + extra_indent = 0; + firstline_indent = 0; + + wrap_paragraph(pdata, p->words, base_width, + indent + firstline_indent, + indent + extra_indent); + + /* + * FIXME: Also find the auxiliary data for this + * paragraph. For para_Bullet it's a bullet; for + * para_NumberedList it's the number; for some section + * headings (depending on the style of section heading + * selected) it's the section number. + * + * Assign into pdata->first->aux_*. + */ + + p->private_data = pdata; + + /* + * Set the line spacing for each line in this paragraph. + */ + for (ldata = pdata->first; ldata; ldata = ldata->next) { + if (ldata == pdata->first) + ldata->space_before = base_para_spacing / 2; + else + ldata->space_before = base_leading / 2; + if (ldata == pdata->last) + ldata->space_after = base_para_spacing / 2; + else + ldata->space_after = base_leading / 2; + ldata->page_break = FALSE; + } + + /* + * FIXME: some kinds of section heading do require a + * page break before them. + */ + + break; + } + + /* + * Link all line structures together into a big list. + */ + if (p->private_data) { + pdata = (para_data *)p->private_data; + if (pdata->first) { + if (lastline) { + lastline->next = pdata->first; + pdata->first->prev = lastline; + } else { + firstline = pdata->first; + pdata->first->prev = NULL; + } + lastline = pdata->last; + } + } + } + + /* + * Now we have an enormous linked list of every line of text in + * the document. Break it up into pages. + */ + pages = page_breaks(firstline, lastline, page_height); + + /* + * Now we're ready to actually lay out the pages. We do this by + * looping over _paragraphs_, since we may need to track cross- + * references between lines and even across pages. + */ + for (p = sourceform; p; p = p->next) { + pdata = (para_data *)p->private_data; + + if (pdata) { + for (ldata = pdata->first; ldata; ldata = ldata->next) { + render_line(ldata, left_margin, paper_height - top_margin); + if (ldata == pdata->last) + break; + } + } + } + + doc = mknew(document); + doc->fonts = fontlist; + doc->pages = pages; + doc->paper_width = paper_width; + doc->paper_height = paper_height; + return doc; +} + +static font_encoding *new_font_encoding(font_data *font) +{ + font_encoding *fe; + int i; + + fe = mknew(font_encoding); + fe->next = NULL; + + if (font->list->tail) + font->list->tail->next = fe; + else + font->list->head = fe; + font->list->tail = fe; + + fe->font = font; + fe->free_pos = 0x21; + + for (i = 0; i < 256; i++) { + fe->vector[i] = NULL; + fe->indices[i] = -1; + fe->to_unicode[i] = 0xFFFF; + } + + return fe; +} + +static font_data *make_std_font(font_list *fontlist, char const *name) +{ + const int *widths; + int nglyphs; + font_data *f; + font_encoding *fe; + int i; + + widths = ps_std_font_widths(name); + if (!widths) + return NULL; + + for (nglyphs = 0; ps_std_glyphs[nglyphs] != NULL; nglyphs++); + + f = mknew(font_data); + + f->list = fontlist; + f->name = name; + f->nglyphs = nglyphs; + f->glyphs = ps_std_glyphs; + f->widths = widths; + f->subfont_map = mknewa(subfont_map_entry, nglyphs); + + /* + * Our first subfont will contain all of US-ASCII. This isn't + * really necessary - we could just create custom subfonts + * precisely as the whim of render_string dictated - but + * instinct suggests that it might be nice to have the text in + * the output files look _marginally_ recognisable. + */ + fe = new_font_encoding(f); + fe->free_pos = 0xA1; /* only the top half is free */ + f->latest_subfont = fe; + + for (i = 0; i < (int)lenof(f->bmp); i++) + f->bmp[i] = 0xFFFF; + + for (i = 0; i < nglyphs; i++) { + wchar_t ucs; + ucs = ps_glyph_to_unicode(f->glyphs[i]); + assert(ucs != 0xFFFF); + f->bmp[ucs] = i; + if (ucs >= 0x20 && ucs <= 0x7E) { + fe->vector[ucs] = f->glyphs[i]; + fe->indices[ucs] = i; + fe->to_unicode[ucs] = ucs; + f->subfont_map[i].subfont = fe; + f->subfont_map[i].position = ucs; + } else { + /* + * This character is not yet assigned to a subfont. + */ + f->subfont_map[i].subfont = NULL; + f->subfont_map[i].position = 0; + } + } + + return f; +} + +static int string_width(font_data *font, wchar_t const *string, int *errs) +{ + int width = 0; + + if (errs) + *errs = 0; + + for (; *string; string++) { + int index; + + index = font->bmp[(unsigned short)*string]; + if (index == 0xFFFF) { + if (errs) + *errs = 1; + } else { + width += font->widths[index]; + } + } + + return width; +} + +static int paper_width(void *vctx, word *word); + +struct paper_width_ctx { + int minspacewidth; + para_data *pdata; +}; + +static int paper_width_list(void *vctx, word *text, word *end) { + int w = 0; + while (text) { + w += paper_width(vctx, text); + if (text == end) + break; + text = text->next; + } + return w; +} + +static int paper_width(void *vctx, word *word) +{ + struct paper_width_ctx *ctx = (struct paper_width_ctx *)vctx; + int style, type, findex, width, errs; + wchar_t *str; + + switch (word->type) { + case word_HyperLink: + case word_HyperEnd: + case word_UpperXref: + case word_LowerXref: + case word_XrefEnd: + case word_IndexRef: + return 0; + } + + style = towordstyle(word->type); + type = removeattr(word->type); + + findex = (style == word_Normal ? FONT_NORMAL : + style == word_Emph ? FONT_EMPH : + FONT_CODE); + + if (type == word_Normal) { + str = word->text; + } else if (type == word_WhiteSpace) { + if (findex != FONT_CODE) + return ctx->minspacewidth; + else + str = L" "; + } else /* if (type == word_Quote) */ { + if (word->aux == quote_Open) + str = L"\x2018"; /* FIXME: configurability! */ + else + str = L"\x2019"; /* FIXME: configurability! */ + } + + width = string_width(ctx->pdata->fonts[findex], str, &errs); + + if (errs && word->alt) + return paper_width_list(vctx, word->alt, NULL); + else + return ctx->pdata->sizes[findex] * width; +} + +static void wrap_paragraph(para_data *pdata, word *words, + int w, int i1, int i2) +{ + wrappedline *wrapping, *p; + int spacewidth; + struct paper_width_ctx ctx; + int line_height; + + /* + * We're going to need to store the line height in every line + * structure we generate. + */ + { + int i; + line_height = 0; + for (i = 0; i < NFONTS; i++) + if (line_height < pdata->sizes[i]) + line_height = pdata->sizes[i]; + line_height *= 4096; + } + + spacewidth = (pdata->sizes[FONT_NORMAL] * + string_width(pdata->fonts[FONT_NORMAL], L" ", NULL)); + if (spacewidth == 0) { + /* + * A font without a space?! Disturbing. I hope this never + * comes up, but I'll make a random guess anyway and set my + * space width to half the point size. + */ + spacewidth = pdata->sizes[FONT_NORMAL] * 4096 / 2; + } + + /* + * I'm going to set the _minimum_ space width to 3/5 of the + * standard one, and use the standard one as the optimum. + */ + ctx.minspacewidth = spacewidth * 3 / 5; + ctx.pdata = pdata; + + wrapping = wrap_para(words, w - i1, w - i2, paper_width, &ctx, spacewidth); + + /* + * Having done the wrapping, we now concoct a set of line_data + * structures. + */ + pdata->first = pdata->last = NULL; + + for (p = wrapping; p; p = p->next) { + line_data *ldata; + word *wd; + int len, wid, spaces; + + ldata = mknew(line_data); + + ldata->pdata = pdata; + ldata->first = p->begin; + ldata->last = p->end; + ldata->line_height = line_height; + + ldata->xpos = (p == wrapping ? i1 : i2); + + if (pdata->last) { + pdata->last->next = ldata; + ldata->prev = pdata->last; + } else { + pdata->first = ldata; + ldata->prev = NULL; + } + ldata->next = NULL; + pdata->last = ldata; + + len = paper_width_list(&ctx, ldata->first, ldata->last); + wid = (p == wrapping ? w - i1 : w - i2); + spaces = 0; + wd = ldata->first; + while (wd) { +#if 0 + switch (wd->type) { + case word_HyperLink: + case word_HyperEnd: + case word_UpperXref: + case word_LowerXref: + case word_XrefEnd: + case word_IndexRef: + break; + + default: + if (removeattr(wd->type) == word_Normal) + printf("%ls", wd->text); + else if (removeattr(wd->type) == word_WhiteSpace) + printf(" "); + else if (removeattr(wd->type) == word_Quote) + printf(wd->aux == quote_Open ? "`" : "'"); + break; + } +#endif + if (removeattr(wd->type) == word_WhiteSpace) + spaces++; + if (wd == ldata->last) + break; + wd = wd->next; + } + + if (spaces) { + ldata->space_adjust = (wid - len) / spaces; + /* + * This tells us how much the space width needs to + * change from _min_spacewidth. But we want to store + * its difference from the _natural_ space width, to + * make the text rendering easier. + */ + ldata->space_adjust += ctx.minspacewidth; + ldata->space_adjust -= spacewidth; + /* + * Special case: on the last line of a paragraph, we + * never stretch spaces. + */ + if (ldata->space_adjust > 0 && !p->next) + ldata->space_adjust = 0; + } else { + ldata->space_adjust = 0; + } + + ldata->aux_text = NULL; + ldata->aux_left_indent = 0; + } + +} + +static page_data *page_breaks(line_data *first, line_data *last, + int page_height) +{ + line_data *l, *m; + page_data *ph, *pt; + + /* + * Page breaking is done by a close analogue of the optimal + * paragraph wrapping algorithm used by wrap_para(). We work + * backwards from the end of the document line by line; for + * each line, we contemplate every possible number of lines we + * could put on a page starting with that line, determine a + * cost function for each one, add it to the pre-computed cost + * function for optimally page-breaking everything after that + * page, and pick the best option. + * + * Since my line_data structures are only used for this + * purpose, I might as well just store the algorithm data + * directly in them. + */ + + for (l = last; l; l = l->prev) { + int minheight, text = 0, space = 0; + int cost; + + l->bestcost = -1; + for (m = l; m; m = m->next) { + if (m != l && m->page_break) + break; /* we've gone as far as we can */ + + if (m != l) + space += m->prev->space_after; + if (m != l || m->page_break) + space += m->space_before; + text += m->line_height; + minheight = text + space; + + if (m != l && minheight > page_height) + break; + + /* + * Compute the cost of this arrangement, as the square + * of the amount of wasted space on the page. + * Exception: if this is the last page before a + * mandatory break or the document end, we don't + * penalise a large blank area. + */ + if (m->next && !m->next->page_break) + { + int x = page_height - minheight; + int xf; + + xf = x & 0xFF; + x >>= 8; + + cost = x*x; + cost += (x * xf) >> 8; + } else + cost = 0; + + /* + * FIXME: here I should introduce penalties for + * breaking in mid-paragraph, particularly very close + * to one end of a paragraph and particularly in code + * paragraphs. + */ + + if (m->next && !m->next->page_break) + cost += m->next->bestcost; + + if (l->bestcost == -1 || l->bestcost > cost) { + /* + * This is the best option yet for this starting + * point. + */ + l->bestcost = cost; + if (m->next && !m->next->page_break) + l->shortfall = page_height - minheight; + else + l->shortfall = 0; + l->text = text; + l->space = space; + l->page_last = m; + } + } + } + + /* + * Now go through the line list forwards and assemble the + * actual pages. + */ + ph = pt = NULL; + + l = first; + while (l) { + page_data *page; + int text, space; + + page = mknew(page_data); + page->next = NULL; + page->prev = pt; + if (pt) + pt->next = page; + else + ph = page; + pt = page; + + page->first_line = l; + page->last_line = l->page_last; + + page->first_text = page->last_text = NULL; + + /* + * Now assign a y-coordinate to each line on the page. + */ + text = space = 0; + for (l = page->first_line; l; l = l->next) { + if (l != page->first_line) + space += l->prev->space_after; + if (l != page->first_line || l->page_break) + space += l->space_before; + text += l->line_height; + + l->page = page; + l->ypos = text + space + + space * (float)page->first_line->shortfall / + page->first_line->space; + + if (l == page->last_line) + break; + } + + l = page->last_line->next; + } + + return ph; +} + +static void add_string_to_page(page_data *page, int x, int y, + font_encoding *fe, int size, char *text) +{ + text_fragment *frag; + + frag = mknew(text_fragment); + frag->next = NULL; + + if (page->last_text) + page->last_text->next = frag; + else + page->first_text = frag; + page->last_text = frag; + + frag->x = x; + frag->y = y; + frag->fe = fe; + frag->fontsize = size; + frag->text = dupstr(text); +} + +/* + * Returns the updated x coordinate. + */ +static int render_string(page_data *page, font_data *font, int fontsize, + int x, int y, wchar_t *str) +{ + char *text; + int textpos, textwid, glyph; + font_encoding *subfont = NULL, *sf; + + text = mknewa(char, 1 + ustrlen(str)); + textpos = textwid = 0; + + while (*str) { + glyph = font->bmp[*str]; + + if (glyph == 0xFFFF) + continue; /* nothing more we can do here */ + + /* + * Find which subfont this character is going in. + */ + sf = font->subfont_map[glyph].subfont; + + if (!sf) { + int c; + + /* + * This character is not yet in a subfont. Assign one. + */ + if (font->latest_subfont->free_pos >= 0x100) + font->latest_subfont = new_font_encoding(font); + + c = font->latest_subfont->free_pos++; + if (font->latest_subfont->free_pos == 0x7F) + font->latest_subfont->free_pos = 0xA1; + + font->subfont_map[glyph].subfont = font->latest_subfont; + font->subfont_map[glyph].position = c; + font->latest_subfont->vector[c] = font->glyphs[glyph]; + font->latest_subfont->indices[c] = glyph; + font->latest_subfont->to_unicode[c] = *str; + + sf = font->latest_subfont; + } + + if (!subfont || sf != subfont) { + if (subfont) { + text[textpos] = '\0'; + add_string_to_page(page, x, y, subfont, fontsize, text); + x += textwid; + } else { + assert(textpos == 0); + } + textpos = 0; + subfont = sf; + } + + text[textpos++] = font->subfont_map[glyph].position; + textwid += font->widths[glyph] * fontsize; + + str++; + } + + if (textpos > 0) { + text[textpos] = '\0'; + add_string_to_page(page, x, y, subfont, fontsize, text); + x += textwid; + } + + return x; +} + +/* + * Returns the updated x coordinate. + */ +static int render_text(page_data *page, para_data *pdata, int x, int y, + word *text, word *text_end, int space_adjust) +{ + while (text) { + int style, type, findex, errs; + wchar_t *str; + + switch (text->type) { + case word_HyperLink: + case word_HyperEnd: + case word_UpperXref: + case word_LowerXref: + case word_XrefEnd: + case word_IndexRef: + goto nextword; + /* + * FIXME: we should do something with all of these! + * Hyperlinks and xrefs have meaning in PDF, and this + * is probably the right place to nail down the index + * references too. + */ + } + + style = towordstyle(text->type); + type = removeattr(text->type); + + findex = (style == word_Normal ? FONT_NORMAL : + style == word_Emph ? FONT_EMPH : + FONT_CODE); + + if (type == word_Normal) { + str = text->text; + } else if (type == word_WhiteSpace) { + x += pdata->sizes[findex] * + string_width(pdata->fonts[findex], L" ", NULL); + x += space_adjust; + goto nextword; + } else /* if (type == word_Quote) */ { + if (text->aux == quote_Open) + str = L"\x2018"; /* FIXME: configurability! */ + else + str = L"\x2019"; /* FIXME: configurability! */ + } + + (void) string_width(pdata->fonts[findex], str, &errs); + + if (errs && text->alt) + x = render_text(page, pdata, x, y, text->alt, NULL, space_adjust); + else + x = render_string(page, pdata->fonts[findex], + pdata->sizes[findex], x, y, str); + + nextword: + if (text == text_end) + break; + text = text->next; + } + + return x; +} + +static void render_line(line_data *ldata, int left_x, int top_y) +{ + if (ldata->aux_text) + render_text(ldata->page, ldata->pdata, left_x + ldata->aux_left_indent, + top_y - ldata->ypos, ldata->aux_text, NULL, 0); + render_text(ldata->page, ldata->pdata, left_x + ldata->xpos, + top_y - ldata->ypos, ldata->first, ldata->last, + ldata->space_adjust); +} diff --git a/bk_pdf.c b/bk_pdf.c new file mode 100644 index 0000000..44f7486 --- /dev/null +++ b/bk_pdf.c @@ -0,0 +1,467 @@ +/* + * PDF backend for Halibut + */ + +#include <assert.h> +#include "halibut.h" +#include "paper.h" + +#define TREE_BRANCH 2 /* max branching factor in page tree */ + +paragraph *pdf_config_filename(char *filename) +{ + paragraph *p; + wchar_t *ufilename, *up; + int len; + + p = mknew(paragraph); + memset(p, 0, sizeof(*p)); + p->type = para_Config; + p->next = NULL; + p->fpos.filename = "<command line>"; + p->fpos.line = p->fpos.col = -1; + + ufilename = ufroma_dup(filename); + len = ustrlen(ufilename) + 2 + lenof(L"pdf-filename"); + p->keyword = mknewa(wchar_t, len); + up = p->keyword; + ustrcpy(up, L"pdf-filename"); + up = uadv(up); + ustrcpy(up, ufilename); + up = uadv(up); + *up = L'\0'; + assert(up - p->keyword < len); + sfree(ufilename); + + return p; +} + +typedef struct object_Tag object; +typedef struct objlist_Tag objlist; + +struct object_Tag { + objlist *list; + object *next; + int number; + rdstringc main, stream; + int size, fileoff; + char *final; +}; + +struct objlist_Tag { + int number; + object *head, *tail; +}; + +static object *new_object(objlist *list); +static void objtext(object *o, char const *text); +static void objstream(object *o, char const *text); +static void objref(object *o, object *dest); + +static void make_pages_node(object *node, object *parent, page_data *first, + page_data *last, object *resources); + +void pdf_backend(paragraph *sourceform, keywordlist *keywords, + indexdata *idx, void *vdoc) { + document *doc = (document *)vdoc; + int font_index; + font_encoding *fe; + page_data *page; + int pageno; + FILE *fp; + char *filename; + paragraph *p; + objlist olist; + object *o, *cat, *outlines, *pages, *resources; + int fileoff; + + IGNORE(keywords); + IGNORE(idx); + + filename = dupstr("output.pdf"); + for (p = sourceform; p; p = p->next) { + p->private_data = NULL; + if (p->type == para_Config && p->parent) { + if (!ustricmp(p->keyword, L"pdf-filename")) { + sfree(filename); + filename = utoa_dup(uadv(p->keyword)); + } + } + } + + olist.head = olist.tail = NULL; + olist.number = 1; + + cat = new_object(&olist); + outlines = new_object(&olist); + pages = new_object(&olist); + resources = new_object(&olist); + + /* + * We currently don't support outlines, so here's a null + * outlines dictionary. + */ + objtext(outlines, "<<\n/Type Outlines\n/Count 0\n>>\n"); + + /* + * The catalogue just contains references to the outlines and + * pages objects. + */ + objtext(cat, "<<\n/Type /Catalog\n/Outlines "); + objref(cat, outlines); + objtext(cat, "\n/Pages "); + objref(cat, pages); + objtext(cat, "\n>>\n"); + + /* + * Set up the resources dictionary, which mostly means + * providing all the font objects and names to call them by. + */ + font_index = 0; + objtext(resources, "<<\n/Font <<\n"); + for (fe = doc->fonts->head; fe; fe = fe->next) { + char fname[40]; + int i; + object *font; + + sprintf(fname, "f%d", font_index++); + fe->name = dupstr(fname); + + font = new_object(&olist); + + objtext(resources, "/"); + objtext(resources, fe->name); + objtext(resources, " "); + objref(resources, font); + objtext(resources, "\n"); + + objtext(font, "<<\n/Type /Font\n/Subtype /Type1\n/Name /"); + objtext(font, fe->name); + objtext(font, "\n/BaseFont /"); + objtext(font, fe->font->name); + objtext(font, "\n/Encoding <<\n/Type /Encoding\n/Differences ["); + + for (i = 0; i < 256; i++) { + char buf[20]; + if (!fe->vector[i]) + continue; + sprintf(buf, "\n%d /", i); + objtext(font, buf); + objtext(font, fe->vector[i] ? fe->vector[i] : ".notdef"); + } + + objtext(font, "\n]\n>>\n"); + + { + object *widths = new_object(&olist); + objtext(font, "/FirstChar 0\n/LastChar 255\n/Widths "); + objref(font, widths); + objtext(font, "\n"); + objtext(widths, "[\n"); + for (i = 0; i < 256; i++) { + char buf[80]; + double width; + if (fe->indices[i] < 0) + width = 0.0; + else + width = fe->font->widths[fe->indices[i]]; + sprintf(buf, "%g\n", 1000.0 * width / 4096.0); + objtext(widths, buf); + } + objtext(widths, "]\n"); + } + + objtext(font, ">>\n"); + } + objtext(resources, ">>\n>>\n"); + + /* + * Define the page objects for each page, and get each one + * ready to have a `Parent' specification added to it. + */ + for (page = doc->pages; page; page = page->next) { + object *opage; + + opage = new_object(&olist); + page->spare = opage; + objtext(opage, "<<\n/Type /Page\n"); + } + + /* + * Recursively build the page tree. + */ + make_pages_node(pages, NULL, doc->pages, NULL, resources); + + /* + * Create and render the individual pages. + */ + pageno = 0; + for (page = doc->pages; page; page = page->next) { + object *opage, *cstr; + text_fragment *frag; + char buf[256]; + + opage = (object *)page->spare; + /* + * At this point the page dictionary is already + * half-written, with /Type and /Parent already present. We + * continue from there. + */ + + /* + * The PDF spec says /Resources is required, but also says + * that it's inheritable and may be omitted if it's present + * in a Pages node. In our case it is: it's present in the + * topmost /Pages node because we carefully put it there. + * So we don't need a /Resources entry here. + */ + sprintf(buf, "/MediaBox [0 0 %g %g]\n", + doc->paper_width / 4096.0, doc->paper_height / 4096.0); + objtext(opage, buf); + + /* + * Now we're ready to define a content stream containing + * the actual text on the page. + */ + cstr = new_object(&olist); + objtext(opage, "/Contents "); + objref(opage, cstr); + objtext(opage, "\n"); + + objstream(cstr, "BT\n"); + for (frag = page->first_text; frag; frag = frag->next) { + char *c; + + objstream(cstr, "/"); + objstream(cstr, frag->fe->name); + sprintf(buf, " %d Tf 1 0 0 1 %g %g Tm (", frag->fontsize, + frag->x/4096.0, frag->y/4096.0); + objstream(cstr, buf); + + for (c = frag->text; *c; c++) { + if (*c == '(' || *c == ')' || *c == '\\') + objstream(cstr, "\\"); + buf[0] = *c; + buf[1] = '\0'; + objstream(cstr, buf); + } + + objstream(cstr, ") Tj\n"); + } + objstream(cstr, "ET"); + + objtext(opage, ">>\n"); + } + + /* + * Assemble the final linear form of every object. + */ + for (o = olist.head; o; o = o->next) { + rdstringc rs = {0, 0, NULL}; + char text[80]; + + sprintf(text, "%d 0 obj\n", o->number); + rdaddsc(&rs, text); + + if (!o->main.text && o->stream.text) { + sprintf(text, "<<\n/Length %d\n>>\n", o->stream.pos); + rdaddsc(&o->main, text); + } + + assert(o->main.text); + rdaddsc(&rs, o->main.text); + sfree(o->main.text); + + if (rs.text[rs.pos-1] != '\n') + rdaddc(&rs, '\n'); + + if (o->stream.text) { + /* + * FIXME: If we ever start compressing stream data then + * it will have zero bytes in it, so we'll have to be + * more careful than this. + */ + rdaddsc(&rs, "stream\n"); + rdaddsc(&rs, o->stream.text); + rdaddsc(&rs, "\nendstream\n"); + sfree(o->stream.text); + } + + rdaddsc(&rs, "endobj\n"); + + o->final = rs.text; + o->size = rs.pos; + } + + /* + * Write out the PDF file. + */ + + fp = fopen(filename, "wb"); + if (!fp) { + error(err_cantopenw, filename); + return; + } + + /* + * Header + */ + fileoff = fprintf(fp, "%%PDF-1.3\n"); + + /* + * Body + */ + for (o = olist.head; o; o = o->next) { + o->fileoff = fileoff; + fwrite(o->final, 1, o->size, fp); + fileoff += o->size; + } + + /* + * Cross-reference table + */ + fprintf(fp, "xref\n"); + assert(olist.head->number == 1); + fprintf(fp, "0 %d\n", olist.tail->number + 1); + fprintf(fp, "0000000000 65535 f \n"); + for (o = olist.head; o; o = o->next) { + char entry[40]; + sprintf(entry, "%010d 00000 n \n", o->fileoff); + assert(strlen(entry) == 20); + fputs(entry, fp); + } + + /* + * Trailer + */ + fprintf(fp, "trailer\n<<\n/Size %d\n/Root %d 0 R\n>>\n", + olist.tail->number + 1, cat->number); + fprintf(fp, "startxref\n%d\n%%%%EOF\n", fileoff); + + fclose(fp); + + sfree(filename); +} + +static object *new_object(objlist *list) +{ + object *obj = mknew(object); + + obj->list = list; + + obj->main.text = NULL; + obj->main.pos = obj->main.size = 0; + obj->stream.text = NULL; + obj->stream.pos = obj->stream.size = 0; + + obj->number = list->number++; + + obj->next = NULL; + if (list->tail) + list->tail->next = obj; + else + list->head = obj; + list->tail = obj; + + obj->size = 0; + obj->final = NULL; + + return obj; +} + +static void objtext(object *o, char const *text) +{ + rdaddsc(&o->main, text); +} + +static void objstream(object *o, char const *text) +{ + rdaddsc(&o->stream, text); +} + +static void objref(object *o, object *dest) +{ + char buf[40]; + sprintf(buf, "%d 0 R", dest->number); + rdaddsc(&o->main, buf); +} + +static void make_pages_node(object *node, object *parent, page_data *first, + page_data *last, object *resources) +{ + int count; + page_data *page; + char buf[80]; + + objtext(node, "<<\n/Type /Pages\n"); + if (parent) { + objtext(node, "/Parent "); + objref(node, parent); + objtext(node, "\n"); + } + + /* + * Count the pages in this stretch, to see if there are few + * enough to reference directly. + */ + count = 0; + for (page = first; page; page = page->next) { + count++; + if (page == last) + break; + } + + sprintf(buf, "/Count %d\n/Kids [\n", count); + objtext(node, buf); + + if (count > TREE_BRANCH) { + int i; + page_data *thisfirst, *thislast; + + page = first; + + for (i = 0; i < TREE_BRANCH; i++) { + int number = (i+1) * count / TREE_BRANCH - i * count / TREE_BRANCH; + thisfirst = page; + while (number--) { + thislast = page; + page = page->next; + } + + if (thisfirst == thislast) { + objref(node, (object *)thisfirst->spare); + objtext((object *)thisfirst->spare, "/Parent "); + objref((object *)thisfirst->spare, node); + objtext((object *)thisfirst->spare, "\n"); + } else { + object *newnode = new_object(node->list); + make_pages_node(newnode, node, thisfirst, thislast, NULL); + objref(node, newnode); + } + objtext(node, "\n"); + } + + assert(thislast == last || page == NULL); + + } else { + for (page = first; page; page = page->next) { + objref(node, (object *)page->spare); + objtext(node, "\n"); + objtext((object *)page->spare, "/Parent "); + objref((object *)page->spare, node); + objtext((object *)page->spare, "\n"); + if (page == last) + break; + } + } + + objtext(node, "]\n"); + + if (resources) { + objtext(node, "/Resources "); + objref(node, resources); + objtext(node, "\n"); + } + + objtext(node, ">>\n"); +} @@ -0,0 +1,144 @@ +/* + * PostScript backend for Halibut + */ + +#include <assert.h> +#include "halibut.h" +#include "paper.h" + +paragraph *ps_config_filename(char *filename) +{ + paragraph *p; + wchar_t *ufilename, *up; + int len; + + p = mknew(paragraph); + memset(p, 0, sizeof(*p)); + p->type = para_Config; + p->next = NULL; + p->fpos.filename = "<command line>"; + p->fpos.line = p->fpos.col = -1; + + ufilename = ufroma_dup(filename); + len = ustrlen(ufilename) + 2 + lenof(L"ps-filename"); + p->keyword = mknewa(wchar_t, len); + up = p->keyword; + ustrcpy(up, L"ps-filename"); + up = uadv(up); + ustrcpy(up, ufilename); + up = uadv(up); + *up = L'\0'; + assert(up - p->keyword < len); + sfree(ufilename); + + return p; +} + +void ps_backend(paragraph *sourceform, keywordlist *keywords, + indexdata *idx, void *vdoc) { + document *doc = (document *)vdoc; + int font_index; + font_encoding *fe; + page_data *page; + int pageno; + FILE *fp; + char *filename; + paragraph *p; + + IGNORE(keywords); + IGNORE(idx); + + filename = dupstr("output.ps"); + for (p = sourceform; p; p = p->next) { + p->private_data = NULL; + if (p->type == para_Config && p->parent) { + if (!ustricmp(p->keyword, L"ps-filename")) { + sfree(filename); + filename = utoa_dup(uadv(p->keyword)); + } + } + } + + fp = fopen(filename, "w"); + if (!fp) { + error(err_cantopenw, filename); + return; + } + + fprintf(fp, "%%!PS-Adobe-1.0\n"); + for (pageno = 0, page = doc->pages; page; page = page->next) + pageno++; + fprintf(fp, "%%%%Pages: %d\n", pageno); + fprintf(fp, "%%%%EndComments\n"); + + fprintf(fp, "%%%%BeginProlog\n"); + fprintf(fp, "%%%%EndProlog\n"); + + fprintf(fp, "%%%%BeginSetup\n"); + /* + * Re-encode and re-metric the fonts. + */ + font_index = 0; + for (fe = doc->fonts->head; fe; fe = fe->next) { + char fname[40]; + int i; + + sprintf(fname, "f%d", font_index++); + fe->name = dupstr(fname); + + fprintf(fp, "/%s findfont dup length dict begin\n", fe->font->name); + fprintf(fp, "{1 index /FID ne {def} {pop pop} ifelse} forall\n"); + fprintf(fp, "/Encoding [\n"); + for (i = 0; i < 256; i++) + fprintf(fp, "/%s\n", fe->vector[i] ? fe->vector[i] : ".notdef"); + fprintf(fp, "] def /Metrics 256 dict dup begin\n"); + for (i = 0; i < 256; i++) { + if (fe->indices[i] >= 0) { + double width = fe->font->widths[fe->indices[i]]; + fprintf(fp, "/%s %g def\n", fe->vector[i], + 1000.0 * width / 4096.0); + } + } + fprintf(fp, "end def currentdict end\n"); + fprintf(fp, "/fontname-%s exch definefont /%s exch def\n\n", + fe->name, fe->name); + } + fprintf(fp, "%%%%EndSetup\n"); + + /* + * Output the text. + */ + pageno = 0; + for (page = doc->pages; page; page = page->next) { + text_fragment *frag; + + pageno++; + fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno); + fprintf(fp, "%%%%BeginPageSetup\n"); + fprintf(fp, "%%%%EndPageSetup\n"); + + for (frag = page->first_text; frag; frag = frag->next) { + char *c; + + fprintf(fp, "%s %d scalefont setfont %g %g moveto (", + frag->fe->name, frag->fontsize, + frag->x/4096.0, frag->y/4096.0); + + for (c = frag->text; *c; c++) { + if (*c == '(' || *c == ')' || *c == '\\') + fputc('\\', fp); + fputc(*c, fp); + } + + fprintf(fp, ") show\n"); + } + + fprintf(fp, "showpage\n"); + } + + fprintf(fp, "%%%%EOF\n"); + + fclose(fp); + + sfree(filename); +} @@ -209,7 +209,7 @@ paragraph *text_config_filename(char *filename) } void text_backend(paragraph *sourceform, keywordlist *keywords, - indexdata *idx) { + indexdata *idx, void *unused) { paragraph *p; textconfig conf; word *prefix, *body, *wp; @@ -219,6 +219,7 @@ void text_backend(paragraph *sourceform, keywordlist *keywords, int nesting, nestindent; int indentb, indenta; + IGNORE(unused); IGNORE(keywords); /* we don't happen to need this */ IGNORE(idx); /* or this */ @@ -472,18 +473,20 @@ static void text_rdaddwc(rdstringc *rs, word *text, word *end) { } } -static int text_width(word *); +static int text_width(void *, word *); -static int text_width_list(word *text) { +static int text_width_list(void *ctx, word *text) { int w = 0; while (text) { - w += text_width(text); + w += text_width(ctx, text); text = text->next; } return w; } -static int text_width(word *text) { +static int text_width(void *ctx, word *text) { + IGNORE(ctx); + switch (text->type) { case word_HyperLink: case word_HyperEnd: @@ -504,7 +507,7 @@ static int text_width(word *text) { : 0) + (text_convert(text->text, NULL) ? ustrlen(text->text) : - text_width_list(text->alt))); + text_width_list(ctx, text->alt))); case word_WhiteSpace: case word_EmphSpace: @@ -560,7 +563,7 @@ static void text_heading(FILE *fp, word *tprefix, word *nprefix, word *text, wrapwidth = indent + width; } - wrapping = wrap_para(text, firstlinewidth, wrapwidth, text_width); + wrapping = wrap_para(text, firstlinewidth, wrapwidth, text_width, NULL, 0); for (p = wrapping; p; p = p->next) { text_rdaddwc(&t, p->begin, p->end); length = (t.text ? strlen(t.text) : 0); @@ -628,7 +631,7 @@ static void text_para(FILE *fp, word *prefix, char *prefixextra, word *text, } else e = indent + extraindent; - wrapping = wrap_para(text, firstlinewidth, width, text_width); + wrapping = wrap_para(text, firstlinewidth, width, text_width, NULL, 0); for (p = wrapping; p; p = p->next) { rdstringc t = { 0, 0, NULL }; text_rdaddwc(&t, p->begin, p->end); @@ -72,7 +72,7 @@ paragraph *whlp_config_filename(char *filename) } void whlp_backend(paragraph *sourceform, keywordlist *keywords, - indexdata *idx) { + indexdata *idx, void *unused) { WHLP h; char *filename, *cntname; paragraph *p, *lastsect; @@ -83,6 +83,8 @@ void whlp_backend(paragraph *sourceform, keywordlist *keywords, indexentry *ie; int done_contents_topic = FALSE; + IGNORE(unused); + h = state.h = whlp_new(); state.keywords = keywords; state.idx = idx; @@ -744,13 +744,15 @@ static void xhtml_free_file(xhtmlfile* xfile) * Main function. */ void xhtml_backend(paragraph *sourceform, keywordlist *in_keywords, - indexdata *in_idx) + indexdata *in_idx, void *unused) { /* int i;*/ indexentry *ientry; int ti; xhtmlsection *xsect; + IGNORE(unused); + sourceparas = sourceform; conf = xhtml_configure(sourceform); keywords = in_keywords; @@ -326,7 +326,7 @@ struct tagWrappedLine { int nspaces; /* number of whitespaces in line */ int shortfall; /* how much shorter than max width */ }; -wrappedline *wrap_para(word *, int, int, int (*)(word *)); +wrappedline *wrap_para(word *, int, int, int (*)(void *, word *), void *, int); void wrap_free(wrappedline *); /* @@ -422,31 +422,48 @@ struct userstyle_Tag { /* * bk_text.c */ -void text_backend(paragraph *, keywordlist *, indexdata *); +void text_backend(paragraph *, keywordlist *, indexdata *, void *); paragraph *text_config_filename(char *filename); /* * bk_xhtml.c */ -void xhtml_backend(paragraph *, keywordlist *, indexdata *); +void xhtml_backend(paragraph *, keywordlist *, indexdata *, void *); paragraph *xhtml_config_filename(char *filename); /* * bk_whlp.c */ -void whlp_backend(paragraph *, keywordlist *, indexdata *); +void whlp_backend(paragraph *, keywordlist *, indexdata *, void *); paragraph *whlp_config_filename(char *filename); /* * bk_man.c */ -void man_backend(paragraph *, keywordlist *, indexdata *); +void man_backend(paragraph *, keywordlist *, indexdata *, void *); paragraph *man_config_filename(char *filename); /* * bk_info.c */ -void info_backend(paragraph *, keywordlist *, indexdata *); +void info_backend(paragraph *, keywordlist *, indexdata *, void *); paragraph *info_config_filename(char *filename); +/* + * bk_paper.c + */ +void *paper_pre_backend(paragraph *, keywordlist *, indexdata *); + +/* + * bk_ps.c + */ +void ps_backend(paragraph *, keywordlist *, indexdata *, void *); +paragraph *ps_config_filename(char *filename); + +/* + * bk_pdf.c + */ +void pdf_backend(paragraph *, keywordlist *, indexdata *, void *); +paragraph *pdf_config_filename(char *filename); + #endif @@ -12,6 +12,8 @@ static char *helptext[] = { " --winhelp[=filename] generate Windows Help output", " --man[=filename] generate man page output", " --info[=filename] generate GNU info output", + " --ps[=filename] generate PostScript output", + " --pdf[=filename] generate PDF output", " -Cfoo:bar:baz append \\cfg{foo}{bar}{baz} to input", " --precise report column numbers in error messages", " --help display this text", @@ -11,20 +11,29 @@ static void dbg_prtsource(paragraph *sourceform); static void dbg_prtwordlist(int level, word *w); static void dbg_prtkws(keywordlist *kws); +static const struct pre_backend { + void *(*func)(paragraph *, keywordlist *, indexdata *); + int bitfield; +} pre_backends[] = { + {paper_pre_backend, 0x0001} +}; + static const struct backend { char *name; - void (*func)(paragraph *, keywordlist *, indexdata *); + void (*func)(paragraph *, keywordlist *, indexdata *, void *); paragraph *(*filename)(char *filename); - int bitfield; + int bitfield, prebackend_bitfield; } backends[] = { - {"text", text_backend, text_config_filename, 0x0001}, - {"xhtml", xhtml_backend, xhtml_config_filename, 0x0002}, - {"html", xhtml_backend, xhtml_config_filename, 0x0002}, - {"hlp", whlp_backend, whlp_config_filename, 0x0004}, - {"whlp", whlp_backend, whlp_config_filename, 0x0004}, - {"winhelp", whlp_backend, whlp_config_filename, 0x0004}, - {"man", man_backend, man_config_filename, 0x0008}, - {"info", info_backend, info_config_filename, 0x0010}, + {"text", text_backend, text_config_filename, 0x0001, 0}, + {"xhtml", xhtml_backend, xhtml_config_filename, 0x0002, 0}, + {"html", xhtml_backend, xhtml_config_filename, 0x0002, 0}, + {"hlp", whlp_backend, whlp_config_filename, 0x0004, 0}, + {"whlp", whlp_backend, whlp_config_filename, 0x0004, 0}, + {"winhelp", whlp_backend, whlp_config_filename, 0x0004, 0}, + {"man", man_backend, man_config_filename, 0x0008, 0}, + {"info", info_backend, info_config_filename, 0x0010, 0}, + {"ps", ps_backend, ps_config_filename, 0x0020, 0x0001}, + {"pdf", pdf_backend, pdf_config_filename, 0x0040, 0x0001}, }; int main(int argc, char **argv) { @@ -34,9 +43,10 @@ int main(int argc, char **argv) { int errs; int reportcols; int debug; - int backendbits; + int backendbits, prebackbits; int k, b; paragraph *cfg, *cfg_tail; + void *pre_backend_data[16]; /* * Set up initial (default) parameters. @@ -307,13 +317,39 @@ int main(int argc, char **argv) { } /* + * Select and run the pre-backends. + */ + prebackbits = 0; + for (k = 0; k < (int)lenof(backends); k++) + if (backendbits == 0 || (backendbits & backends[k].bitfield)) + prebackbits |= backends[k].prebackend_bitfield; + for (k = 0; k < (int)lenof(pre_backends); k++) + if (prebackbits & pre_backends[k].bitfield) { + assert(k < (int)lenof(pre_backend_data)); + pre_backend_data[k] = + pre_backends[k].func(sourceform, keywords, idx); + } + + /* * Run the selected set of backends. */ for (k = b = 0; k < (int)lenof(backends); k++) if (b != backends[k].bitfield) { b = backends[k].bitfield; - if (backendbits == 0 || (backendbits & b)) - backends[k].func(sourceform, keywords, idx); + if (backendbits == 0 || (backendbits & b)) { + void *pbd = NULL; + int pbb = backends[k].prebackend_bitfield; + int m; + + for (m = 0; m < (int)lenof(pre_backends); m++) + if (pbb & pre_backends[m].bitfield) { + assert(m < (int)lenof(pre_backend_data)); + pbd = pre_backend_data[m]; + break; + } + + backends[k].func(sourceform, keywords, idx, pbd); + } } free_para_list(sourceform); @@ -228,8 +228,39 @@ void mark_attr_ends(paragraph *sourceform) { } } +/* + * This function implements the optimal paragraph wrapping + * algorithm, pretty much as used in TeX. A cost function is + * defined for each line of the wrapped paragraph (typically some + * convex function of the difference between the line's length and + * its desired length), and a dynamic programming approach is used + * to optimise globally across all possible layouts of the + * paragraph to find the one with the minimum total cost. + * + * The function as implemented here gives a choice of two options + * for the cost function: + * + * - If `natural_space' is zero, then the algorithm attempts to + * make each line the maximum possible width (either `width' or + * `subsequentwidth' depending on whether it's the first line of + * the paragraph or not), and the cost function is simply the + * square of the unused space at the end of each line. This is a + * simple mechanism suitable for use in fixed-pitch environments + * such as plain text displayed on a terminal. + * + * - However, if `natural_space' is positive, the algorithm + * assumes the medium is fully graphical and that the width of + * space characters can be adjusted finely, and it attempts to + * make each _space character_ the width given in + * `natural_space'. (The provided width function should return + * the _minimum_ acceptable width of a space character in this + * case.) Therefore, the cost function for a line is dependent + * on the number of spaces on that line as well as the amount by + * which the line width differs from the optimum. + */ wrappedline *wrap_para(word *text, int width, int subsequentwidth, - int (*widthfn)(word *)) { + int (*widthfn)(void *, word *), void *ctx, + int natural_space) { wrappedline *head = NULL, **ptr = &head; int nwords, wordsize; struct wrapword { @@ -254,7 +285,7 @@ wrappedline *wrap_para(word *text, int width, int subsequentwidth, wrapwords[nwords].width = 0; wrapwords[nwords].begin = text; while (text) { - wrapwords[nwords].width += widthfn(text); + wrapwords[nwords].width += widthfn(ctx, text); wrapwords[nwords].end = text->next; if (text->next && (text->next->type == word_WhiteSpace || text->next->type == word_EmphSpace || @@ -264,7 +295,7 @@ wrappedline *wrap_para(word *text, int width, int subsequentwidth, } if (text && text->next && (text->next->type == word_WhiteSpace || text->next->type == word_EmphSpace)) { - wrapwords[nwords].spacewidth = widthfn(text->next); + wrapwords[nwords].spacewidth = widthfn(ctx, text->next); text = text->next; } else { wrapwords[nwords].spacewidth = 0; @@ -283,18 +314,20 @@ wrappedline *wrap_para(word *text, int width, int subsequentwidth, int best = -1; int bestcost = 0; int cost; - int linelen = 0, spacewidth = 0; - int seenspace; + int linelen = 0, spacewidth = 0, minspacewidth = 0; + int nspaces; int thiswidth = (i == 0 ? width : subsequentwidth); j = 0; - seenspace = 0; + nspaces = 0; while (i+j < nwords) { /* * See what happens if we put j+1 words on this line. */ - if (spacewidth) - seenspace = 1; + if (spacewidth) { + nspaces++; + minspacewidth = spacewidth; + } linelen += spacewidth + wrapwords[i+j].width; spacewidth = wrapwords[i+j].spacewidth; j++; @@ -308,17 +341,80 @@ wrappedline *wrap_para(word *text, int width, int subsequentwidth, if (best > 0) break; } - if (i+j == nwords) { - /* - * Special case: if we're at the very end of the - * paragraph, we don't score penalty points for the - * white space left on the line. - */ - cost = 0; + + /* + * Compute the cost of this line. The method of doing + * this differs hugely depending on whether + * natural_space is nonzero or not. + */ + if (natural_space) { + if (!nspaces && linelen > thiswidth) { + /* + * Special case: if there are no spaces at all + * on the line because one single word is too + * long for its line, cost is zero because + * there's nothing we can do about it anyway. + */ + cost = 0; + } else { + int shortfall = thiswidth - linelen; + int spaceextra = shortfall / (nspaces ? nspaces : 1); + int spaceshortfall = natural_space - + (minspacewidth + spaceextra); + + if (i+j == nwords && spaceshortfall < 0) { + /* + * Special case: on the very last line of + * the paragraph, we don't score penalty + * points for having to _stretch_ the line, + * since we won't stretch it anyway. + * However, we score penalties as normal + * for having to squeeze it. + */ + cost = 0; + } else { + /* + * Squaring this number is tricky since + * it's liable to be quite big. Let's + * divide it through by 256. + */ + int x = spaceshortfall >> 8; + int xf = spaceshortfall & 0xFF; + + /* + * Not counting strange variable-fixed- + * point oddities, we are computing + * + * (x+xf)^2 = x^2 + 2*x*xf + xf*xf + * + * except that _our_ xf is 256 times the + * one listed there. + */ + + cost = x * x; + cost += (2 * x * xf) >> 8; + } + } } else { - cost = (thiswidth-linelen) * (thiswidth-linelen); - cost += wrapwords[i+j].cost; + if (i+j == nwords) { + /* + * Special case: if we're at the very end of the + * paragraph, we don't score penalty points for the + * white space left on the line. + */ + cost = 0; + } else { + cost = (thiswidth-linelen) * (thiswidth-linelen); + } } + + /* + * Add in the cost of wrapping all lines after this + * point too. + */ + if (i+j < nwords) + cost += wrapwords[i+j].cost; + /* * We compare bestcost >= cost, not bestcost > cost, * because in cases where the costs are identical we @@ -0,0 +1,235 @@ +/* + * Paper printing definitions. + * + * This header file defines data structures and constants which are + * shared between bk_paper.c and its clients bk_ps.c and bk_pdf.c. + */ + +#ifndef HALIBUT_PAPER_H +#define HALIBUT_PAPER_H + +typedef struct document_Tag document; +typedef struct font_data_Tag font_data; +typedef struct font_encoding_Tag font_encoding; +typedef struct font_list_Tag font_list; +typedef struct para_data_Tag para_data; +typedef struct line_data_Tag line_data; +typedef struct page_data_Tag page_data; +typedef struct subfont_map_entry_Tag subfont_map_entry; +typedef struct text_fragment_Tag text_fragment; + +/* + * This data structure represents the overall document, in the form + * it will be given to the client backends. + */ +struct document_Tag { + int paper_width, paper_height; + font_list *fonts; + page_data *pages; +}; + +/* + * This data structure represents a particular font. + */ +struct font_data_Tag { + /* + * Specify the PostScript name of the font and its point size. + */ + const char *name; + /* + * An array of pointers to the available glyph names, and their + * corresponding character widths. These two arrays have + * parallel indices. + */ + int nglyphs; + const char *const *glyphs; + const int *widths; + /* + * For reasonably speedy lookup, we set up a 65536-element + * table representing the Unicode BMP (I can conveniently + * restrict myself to the BMP for the moment since I happen to + * know that no glyph in the Adobe Glyph List falls outside + * it), whose elements are indices into the above two arrays. + */ + unsigned short bmp[65536]; + /* + * At some point I'm going to divide the font into sub-fonts + * with largely non-overlapping encoding vectors. This array + * will track which glyphs go into which subfonts. Also here I + * keep track of the latest subfont of any given font, so I can + * go back and extend its encoding. + */ + subfont_map_entry *subfont_map; + font_encoding *latest_subfont; + /* + * The font list to which this font belongs. + */ + font_list *list; +}; + +struct subfont_map_entry_Tag { + font_encoding *subfont; + unsigned char position; +}; + +/* + * This data structure represents a sub-font: a font with an + * encoding vector. + */ +struct font_encoding_Tag { + font_encoding *next; + + char *name; /* used by client backends */ + + font_data *font; /* the parent font structure */ + const char *vector[256]; /* the actual encoding vector */ + int indices[256]; /* indices back into main font struct */ + wchar_t to_unicode[256]; /* PDF will want to know this */ + int free_pos; /* space left to extend encoding */ +}; + +/* + * This data structure represents the overall list of sub-fonts in + * the whole document. + */ +struct font_list_Tag { + font_encoding *head; + font_encoding *tail; +}; + +/* + * Constants defining array indices for the various fonts used in a + * paragraph. + */ +enum { + FONT_NORMAL, + FONT_EMPH, + FONT_CODE, + NFONTS +}; + +/* + * This is the data structure which is stored in the private_data + * field of each paragraph. It divides the paragraph up into a + * linked list of lines, while at the same time providing for those + * lines to be linked together into a much longer list spanning the + * whole document for page-breaking purposes. + */ + +struct para_data_Tag { + /* + * Data about the fonts used in this paragraph. Indices are the + * FONT_* constants defined above. + */ + font_data *fonts[NFONTS]; + int sizes[NFONTS]; + /* + * Pointers to the first and last line of the paragraph. The + * line structures are linked into a list, which runs from + * `first' to `last' as might be expected. However, the list + * does not terminate there: first->prev will end up pointing + * to the last line of the previous paragraph in most cases, + * and likewise last->next will point to the first line of the + * next paragraph. + */ + line_data *first; /* first line in paragraph */ + line_data *last; /* last line in paragraph */ +}; + +struct line_data_Tag { + /* + * The parent paragraph. + */ + para_data *pdata; + /* + * Pointers to join lines into a linked list. + */ + line_data *prev; + line_data *next; + /* + * The extent of the text displayed on this line. Also mention + * its starting x position, and by how much the width of spaces + * needs to be adjusted for paragraph justification. + * + * (`last' may be NULL if it's more convenient.) + */ + word *first; + word *last; + int xpos; + int space_adjust; /* for justifying paragraphs */ + /* + * Auxiliary text: a section number in a margin, or a list item + * bullet or number. Also mention where to display this text + * relative to the left margin. + */ + word *aux_text; + int aux_left_indent; + /* + * This line might have a non-negotiable page break before it. + * Also there will be space required above and below it; also I + * store the physical line height (defined as the maximum of + * the heights of the three fonts in the pdata) because it's + * easier than looking it up repeatedly during page breaking. + */ + int page_break; + int space_before; + int space_after; + int line_height; + /* + * These fields are used in the page breaking algorithm. + */ + int bestcost; + int shortfall, text, space; + line_data *page_last; /* last line on a page starting here */ + /* + * After page breaking, we can assign an actual y-coordinate on + * the page to each line. Also we store a pointer back to the + * page structure itself. + */ + int ypos; + page_data *page; +}; + +/* + * This data structure is constructed to describe each page of the + * printed output. + */ +struct page_data_Tag { + /* + * Pointers to join pages into a linked list. + */ + page_data *prev; + page_data *next; + /* + * The set of lines displayed on this page. + */ + line_data *first_line; + line_data *last_line; + /* + * After text rendering: the set of actual pieces of text + * needing to be displayed on this page. + */ + text_fragment *first_text; + text_fragment *last_text; + /* + * This spare pointer field is for use by the client backends. + */ + void *spare; +}; + +struct text_fragment_Tag { + text_fragment *next; + int x, y; + font_encoding *fe; + int fontsize; + char *text; +}; + +/* + * Functions and data exported from psdata.c. + */ +wchar_t ps_glyph_to_unicode(char const *glyph); +extern const char *const ps_std_glyphs[]; +const int *ps_std_font_widths(char const *fontname); + +#endif diff --git a/psdata.c b/psdata.c new file mode 100644 index 0000000..aa5fe10 --- /dev/null +++ b/psdata.c @@ -0,0 +1,2114 @@ +/* + * Data, and supporting functions, for PostScript-based output + * formats. + */ + +#include "halibut.h" + +/* ---------------------------------------------------------------------- + * Mapping between PS character names (/aacute, /zcaron etc) and + * Unicode code points. + * + * Generated from the Adobe Glyph List at + * + * http://partners.adobe.com/asn/tech/type/glyphlist.txt + * + * by a succession of Perl/sh fragments, quoted alongside each + * array. + */ + +/* + +grep '^[^#;][^;]*;[^ ][^ ][^ ][^ ]$' glyphlist.txt | sort -t\; +0 -1 | \ + cut -f1 -d\; | perl -ne 'chomp; print "\"$_\", "' | \ + fold -s -w68 | sed 's/^/ /'; echo + + */ +static const char *const ps_glyphs_alphabetic[] = { + "A", "AE", "AEacute", "AEmacron", "AEsmall", "Aacute", + "Aacutesmall", "Abreve", "Abreveacute", "Abrevecyrillic", + "Abrevedotbelow", "Abrevegrave", "Abrevehookabove", "Abrevetilde", + "Acaron", "Acircle", "Acircumflex", "Acircumflexacute", + "Acircumflexdotbelow", "Acircumflexgrave", "Acircumflexhookabove", + "Acircumflexsmall", "Acircumflextilde", "Acute", "Acutesmall", + "Acyrillic", "Adblgrave", "Adieresis", "Adieresiscyrillic", + "Adieresismacron", "Adieresissmall", "Adotbelow", "Adotmacron", + "Agrave", "Agravesmall", "Ahookabove", "Aiecyrillic", + "Ainvertedbreve", "Alpha", "Alphatonos", "Amacron", "Amonospace", + "Aogonek", "Aring", "Aringacute", "Aringbelow", "Aringsmall", + "Asmall", "Atilde", "Atildesmall", "Aybarmenian", "B", "Bcircle", + "Bdotaccent", "Bdotbelow", "Becyrillic", "Benarmenian", "Beta", + "Bhook", "Blinebelow", "Bmonospace", "Brevesmall", "Bsmall", + "Btopbar", "C", "Caarmenian", "Cacute", "Caron", "Caronsmall", + "Ccaron", "Ccedilla", "Ccedillaacute", "Ccedillasmall", "Ccircle", + "Ccircumflex", "Cdot", "Cdotaccent", "Cedillasmall", "Chaarmenian", + "Cheabkhasiancyrillic", "Checyrillic", + "Chedescenderabkhasiancyrillic", "Chedescendercyrillic", + "Chedieresiscyrillic", "Cheharmenian", "Chekhakassiancyrillic", + "Cheverticalstrokecyrillic", "Chi", "Chook", "Circumflexsmall", + "Cmonospace", "Coarmenian", "Csmall", "D", "DZ", "DZcaron", + "Daarmenian", "Dafrican", "Dcaron", "Dcedilla", "Dcircle", + "Dcircumflexbelow", "Dcroat", "Ddotaccent", "Ddotbelow", + "Decyrillic", "Deicoptic", "Delta", "Deltagreek", "Dhook", + "Dieresis", "DieresisAcute", "DieresisGrave", "Dieresissmall", + "Digammagreek", "Djecyrillic", "Dlinebelow", "Dmonospace", + "Dotaccentsmall", "Dslash", "Dsmall", "Dtopbar", "Dz", "Dzcaron", + "Dzeabkhasiancyrillic", "Dzecyrillic", "Dzhecyrillic", "E", + "Eacute", "Eacutesmall", "Ebreve", "Ecaron", "Ecedillabreve", + "Echarmenian", "Ecircle", "Ecircumflex", "Ecircumflexacute", + "Ecircumflexbelow", "Ecircumflexdotbelow", "Ecircumflexgrave", + "Ecircumflexhookabove", "Ecircumflexsmall", "Ecircumflextilde", + "Ecyrillic", "Edblgrave", "Edieresis", "Edieresissmall", "Edot", + "Edotaccent", "Edotbelow", "Efcyrillic", "Egrave", "Egravesmall", + "Eharmenian", "Ehookabove", "Eightroman", "Einvertedbreve", + "Eiotifiedcyrillic", "Elcyrillic", "Elevenroman", "Emacron", + "Emacronacute", "Emacrongrave", "Emcyrillic", "Emonospace", + "Encyrillic", "Endescendercyrillic", "Eng", "Enghecyrillic", + "Enhookcyrillic", "Eogonek", "Eopen", "Epsilon", "Epsilontonos", + "Ercyrillic", "Ereversed", "Ereversedcyrillic", "Escyrillic", + "Esdescendercyrillic", "Esh", "Esmall", "Eta", "Etarmenian", + "Etatonos", "Eth", "Ethsmall", "Etilde", "Etildebelow", "Euro", + "Ezh", "Ezhcaron", "Ezhreversed", "F", "Fcircle", "Fdotaccent", + "Feharmenian", "Feicoptic", "Fhook", "Fitacyrillic", "Fiveroman", + "Fmonospace", "Fourroman", "Fsmall", "G", "GBsquare", "Gacute", + "Gamma", "Gammaafrican", "Gangiacoptic", "Gbreve", "Gcaron", + "Gcedilla", "Gcircle", "Gcircumflex", "Gcommaaccent", "Gdot", + "Gdotaccent", "Gecyrillic", "Ghadarmenian", + "Ghemiddlehookcyrillic", "Ghestrokecyrillic", "Gheupturncyrillic", + "Ghook", "Gimarmenian", "Gjecyrillic", "Gmacron", "Gmonospace", + "Grave", "Gravesmall", "Gsmall", "Gsmallhook", "Gstroke", "H", + "H18533", "H18543", "H18551", "H22073", "HPsquare", + "Haabkhasiancyrillic", "Hadescendercyrillic", "Hardsigncyrillic", + "Hbar", "Hbrevebelow", "Hcedilla", "Hcircle", "Hcircumflex", + "Hdieresis", "Hdotaccent", "Hdotbelow", "Hmonospace", "Hoarmenian", + "Horicoptic", "Hsmall", "Hungarumlaut", "Hungarumlautsmall", + "Hzsquare", "I", "IAcyrillic", "IJ", "IUcyrillic", "Iacute", + "Iacutesmall", "Ibreve", "Icaron", "Icircle", "Icircumflex", + "Icircumflexsmall", "Icyrillic", "Idblgrave", "Idieresis", + "Idieresisacute", "Idieresiscyrillic", "Idieresissmall", "Idot", + "Idotaccent", "Idotbelow", "Iebrevecyrillic", "Iecyrillic", + "Ifraktur", "Igrave", "Igravesmall", "Ihookabove", "Iicyrillic", + "Iinvertedbreve", "Iishortcyrillic", "Imacron", "Imacroncyrillic", + "Imonospace", "Iniarmenian", "Iocyrillic", "Iogonek", "Iota", + "Iotaafrican", "Iotadieresis", "Iotatonos", "Ismall", "Istroke", + "Itilde", "Itildebelow", "Izhitsacyrillic", + "Izhitsadblgravecyrillic", "J", "Jaarmenian", "Jcircle", + "Jcircumflex", "Jecyrillic", "Jheharmenian", "Jmonospace", + "Jsmall", "K", "KBsquare", "KKsquare", "Kabashkircyrillic", + "Kacute", "Kacyrillic", "Kadescendercyrillic", "Kahookcyrillic", + "Kappa", "Kastrokecyrillic", "Kaverticalstrokecyrillic", "Kcaron", + "Kcedilla", "Kcircle", "Kcommaaccent", "Kdotbelow", "Keharmenian", + "Kenarmenian", "Khacyrillic", "Kheicoptic", "Khook", "Kjecyrillic", + "Klinebelow", "Kmonospace", "Koppacyrillic", "Koppagreek", + "Ksicyrillic", "Ksmall", "L", "LJ", "LL", "Lacute", "Lambda", + "Lcaron", "Lcedilla", "Lcircle", "Lcircumflexbelow", + "Lcommaaccent", "Ldot", "Ldotaccent", "Ldotbelow", + "Ldotbelowmacron", "Liwnarmenian", "Lj", "Ljecyrillic", + "Llinebelow", "Lmonospace", "Lslash", "Lslashsmall", "Lsmall", "M", + "MBsquare", "Macron", "Macronsmall", "Macute", "Mcircle", + "Mdotaccent", "Mdotbelow", "Menarmenian", "Mmonospace", "Msmall", + "Mturned", "Mu", "N", "NJ", "Nacute", "Ncaron", "Ncedilla", + "Ncircle", "Ncircumflexbelow", "Ncommaaccent", "Ndotaccent", + "Ndotbelow", "Nhookleft", "Nineroman", "Nj", "Njecyrillic", + "Nlinebelow", "Nmonospace", "Nowarmenian", "Nsmall", "Ntilde", + "Ntildesmall", "Nu", "O", "OE", "OEsmall", "Oacute", "Oacutesmall", + "Obarredcyrillic", "Obarreddieresiscyrillic", "Obreve", "Ocaron", + "Ocenteredtilde", "Ocircle", "Ocircumflex", "Ocircumflexacute", + "Ocircumflexdotbelow", "Ocircumflexgrave", "Ocircumflexhookabove", + "Ocircumflexsmall", "Ocircumflextilde", "Ocyrillic", "Odblacute", + "Odblgrave", "Odieresis", "Odieresiscyrillic", "Odieresissmall", + "Odotbelow", "Ogoneksmall", "Ograve", "Ogravesmall", "Oharmenian", + "Ohm", "Ohookabove", "Ohorn", "Ohornacute", "Ohorndotbelow", + "Ohorngrave", "Ohornhookabove", "Ohorntilde", "Ohungarumlaut", + "Oi", "Oinvertedbreve", "Omacron", "Omacronacute", "Omacrongrave", + "Omega", "Omegacyrillic", "Omegagreek", "Omegaroundcyrillic", + "Omegatitlocyrillic", "Omegatonos", "Omicron", "Omicrontonos", + "Omonospace", "Oneroman", "Oogonek", "Oogonekmacron", "Oopen", + "Oslash", "Oslashacute", "Oslashsmall", "Osmall", "Ostrokeacute", + "Otcyrillic", "Otilde", "Otildeacute", "Otildedieresis", + "Otildesmall", "P", "Pacute", "Pcircle", "Pdotaccent", + "Pecyrillic", "Peharmenian", "Pemiddlehookcyrillic", "Phi", + "Phook", "Pi", "Piwrarmenian", "Pmonospace", "Psi", "Psicyrillic", + "Psmall", "Q", "Qcircle", "Qmonospace", "Qsmall", "R", + "Raarmenian", "Racute", "Rcaron", "Rcedilla", "Rcircle", + "Rcommaaccent", "Rdblgrave", "Rdotaccent", "Rdotbelow", + "Rdotbelowmacron", "Reharmenian", "Rfraktur", "Rho", "Ringsmall", + "Rinvertedbreve", "Rlinebelow", "Rmonospace", "Rsmall", + "Rsmallinverted", "Rsmallinvertedsuperior", "S", "SF010000", + "SF020000", "SF030000", "SF040000", "SF050000", "SF060000", + "SF070000", "SF080000", "SF090000", "SF100000", "SF110000", + "SF190000", "SF200000", "SF210000", "SF220000", "SF230000", + "SF240000", "SF250000", "SF260000", "SF270000", "SF280000", + "SF360000", "SF370000", "SF380000", "SF390000", "SF400000", + "SF410000", "SF420000", "SF430000", "SF440000", "SF450000", + "SF460000", "SF470000", "SF480000", "SF490000", "SF500000", + "SF510000", "SF520000", "SF530000", "SF540000", "Sacute", + "Sacutedotaccent", "Sampigreek", "Scaron", "Scarondotaccent", + "Scaronsmall", "Scedilla", "Schwa", "Schwacyrillic", + "Schwadieresiscyrillic", "Scircle", "Scircumflex", "Scommaaccent", + "Sdotaccent", "Sdotbelow", "Sdotbelowdotaccent", "Seharmenian", + "Sevenroman", "Shaarmenian", "Shacyrillic", "Shchacyrillic", + "Sheicoptic", "Shhacyrillic", "Shimacoptic", "Sigma", "Sixroman", + "Smonospace", "Softsigncyrillic", "Ssmall", "Stigmagreek", "T", + "Tau", "Tbar", "Tcaron", "Tcedilla", "Tcircle", "Tcircumflexbelow", + "Tcommaaccent", "Tdotaccent", "Tdotbelow", "Tecyrillic", + "Tedescendercyrillic", "Tenroman", "Tetsecyrillic", "Theta", + "Thook", "Thorn", "Thornsmall", "Threeroman", "Tildesmall", + "Tiwnarmenian", "Tlinebelow", "Tmonospace", "Toarmenian", + "Tonefive", "Tonesix", "Tonetwo", "Tretroflexhook", "Tsecyrillic", + "Tshecyrillic", "Tsmall", "Twelveroman", "Tworoman", "U", "Uacute", + "Uacutesmall", "Ubreve", "Ucaron", "Ucircle", "Ucircumflex", + "Ucircumflexbelow", "Ucircumflexsmall", "Ucyrillic", "Udblacute", + "Udblgrave", "Udieresis", "Udieresisacute", "Udieresisbelow", + "Udieresiscaron", "Udieresiscyrillic", "Udieresisgrave", + "Udieresismacron", "Udieresissmall", "Udotbelow", "Ugrave", + "Ugravesmall", "Uhookabove", "Uhorn", "Uhornacute", + "Uhorndotbelow", "Uhorngrave", "Uhornhookabove", "Uhorntilde", + "Uhungarumlaut", "Uhungarumlautcyrillic", "Uinvertedbreve", + "Ukcyrillic", "Umacron", "Umacroncyrillic", "Umacrondieresis", + "Umonospace", "Uogonek", "Upsilon", "Upsilon1", + "Upsilonacutehooksymbolgreek", "Upsilonafrican", "Upsilondieresis", + "Upsilondieresishooksymbolgreek", "Upsilonhooksymbol", + "Upsilontonos", "Uring", "Ushortcyrillic", "Usmall", + "Ustraightcyrillic", "Ustraightstrokecyrillic", "Utilde", + "Utildeacute", "Utildebelow", "V", "Vcircle", "Vdotbelow", + "Vecyrillic", "Vewarmenian", "Vhook", "Vmonospace", "Voarmenian", + "Vsmall", "Vtilde", "W", "Wacute", "Wcircle", "Wcircumflex", + "Wdieresis", "Wdotaccent", "Wdotbelow", "Wgrave", "Wmonospace", + "Wsmall", "X", "Xcircle", "Xdieresis", "Xdotaccent", "Xeharmenian", + "Xi", "Xmonospace", "Xsmall", "Y", "Yacute", "Yacutesmall", + "Yatcyrillic", "Ycircle", "Ycircumflex", "Ydieresis", + "Ydieresissmall", "Ydotaccent", "Ydotbelow", "Yericyrillic", + "Yerudieresiscyrillic", "Ygrave", "Yhook", "Yhookabove", + "Yiarmenian", "Yicyrillic", "Yiwnarmenian", "Ymonospace", "Ysmall", + "Ytilde", "Yusbigcyrillic", "Yusbigiotifiedcyrillic", + "Yuslittlecyrillic", "Yuslittleiotifiedcyrillic", "Z", + "Zaarmenian", "Zacute", "Zcaron", "Zcaronsmall", "Zcircle", + "Zcircumflex", "Zdot", "Zdotaccent", "Zdotbelow", "Zecyrillic", + "Zedescendercyrillic", "Zedieresiscyrillic", "Zeta", "Zhearmenian", + "Zhebrevecyrillic", "Zhecyrillic", "Zhedescendercyrillic", + "Zhedieresiscyrillic", "Zlinebelow", "Zmonospace", "Zsmall", + "Zstroke", "a", "aabengali", "aacute", "aadeva", "aagujarati", + "aagurmukhi", "aamatragurmukhi", "aarusquare", + "aavowelsignbengali", "aavowelsigndeva", "aavowelsigngujarati", + "abbreviationmarkarmenian", "abbreviationsigndeva", "abengali", + "abopomofo", "abreve", "abreveacute", "abrevecyrillic", + "abrevedotbelow", "abrevegrave", "abrevehookabove", "abrevetilde", + "acaron", "acircle", "acircumflex", "acircumflexacute", + "acircumflexdotbelow", "acircumflexgrave", "acircumflexhookabove", + "acircumflextilde", "acute", "acutebelowcmb", "acutecmb", + "acutecomb", "acutedeva", "acutelowmod", "acutetonecmb", + "acyrillic", "adblgrave", "addakgurmukhi", "adeva", "adieresis", + "adieresiscyrillic", "adieresismacron", "adotbelow", "adotmacron", + "ae", "aeacute", "aekorean", "aemacron", "afii00208", "afii08941", + "afii10017", "afii10018", "afii10019", "afii10020", "afii10021", + "afii10022", "afii10023", "afii10024", "afii10025", "afii10026", + "afii10027", "afii10028", "afii10029", "afii10030", "afii10031", + "afii10032", "afii10033", "afii10034", "afii10035", "afii10036", + "afii10037", "afii10038", "afii10039", "afii10040", "afii10041", + "afii10042", "afii10043", "afii10044", "afii10045", "afii10046", + "afii10047", "afii10048", "afii10049", "afii10050", "afii10051", + "afii10052", "afii10053", "afii10054", "afii10055", "afii10056", + "afii10057", "afii10058", "afii10059", "afii10060", "afii10061", + "afii10062", "afii10063", "afii10064", "afii10065", "afii10066", + "afii10067", "afii10068", "afii10069", "afii10070", "afii10071", + "afii10072", "afii10073", "afii10074", "afii10075", "afii10076", + "afii10077", "afii10078", "afii10079", "afii10080", "afii10081", + "afii10082", "afii10083", "afii10084", "afii10085", "afii10086", + "afii10087", "afii10088", "afii10089", "afii10090", "afii10091", + "afii10092", "afii10093", "afii10094", "afii10095", "afii10096", + "afii10097", "afii10098", "afii10099", "afii10100", "afii10101", + "afii10102", "afii10103", "afii10104", "afii10105", "afii10106", + "afii10107", "afii10108", "afii10109", "afii10110", "afii10145", + "afii10146", "afii10147", "afii10148", "afii10192", "afii10193", + "afii10194", "afii10195", "afii10196", "afii10831", "afii10832", + "afii10846", "afii299", "afii300", "afii301", "afii57381", + "afii57388", "afii57392", "afii57393", "afii57394", "afii57395", + "afii57396", "afii57397", "afii57398", "afii57399", "afii57400", + "afii57401", "afii57403", "afii57407", "afii57409", "afii57410", + "afii57411", "afii57412", "afii57413", "afii57414", "afii57415", + "afii57416", "afii57417", "afii57418", "afii57419", "afii57420", + "afii57421", "afii57422", "afii57423", "afii57424", "afii57425", + "afii57426", "afii57427", "afii57428", "afii57429", "afii57430", + "afii57431", "afii57432", "afii57433", "afii57434", "afii57440", + "afii57441", "afii57442", "afii57443", "afii57444", "afii57445", + "afii57446", "afii57448", "afii57449", "afii57450", "afii57451", + "afii57452", "afii57453", "afii57454", "afii57455", "afii57456", + "afii57457", "afii57458", "afii57470", "afii57505", "afii57506", + "afii57507", "afii57508", "afii57509", "afii57511", "afii57512", + "afii57513", "afii57514", "afii57519", "afii57534", "afii57636", + "afii57645", "afii57658", "afii57664", "afii57665", "afii57666", + "afii57667", "afii57668", "afii57669", "afii57670", "afii57671", + "afii57672", "afii57673", "afii57674", "afii57675", "afii57676", + "afii57677", "afii57678", "afii57679", "afii57680", "afii57681", + "afii57682", "afii57683", "afii57684", "afii57685", "afii57686", + "afii57687", "afii57688", "afii57689", "afii57690", "afii57694", + "afii57695", "afii57700", "afii57705", "afii57716", "afii57717", + "afii57718", "afii57723", "afii57793", "afii57794", "afii57795", + "afii57796", "afii57797", "afii57798", "afii57799", "afii57800", + "afii57801", "afii57802", "afii57803", "afii57804", "afii57806", + "afii57807", "afii57839", "afii57841", "afii57842", "afii57929", + "afii61248", "afii61289", "afii61352", "afii61573", "afii61574", + "afii61575", "afii61664", "afii63167", "afii64937", "agrave", + "agujarati", "agurmukhi", "ahiragana", "ahookabove", "aibengali", + "aibopomofo", "aideva", "aiecyrillic", "aigujarati", "aigurmukhi", + "aimatragurmukhi", "ainarabic", "ainfinalarabic", + "aininitialarabic", "ainmedialarabic", "ainvertedbreve", + "aivowelsignbengali", "aivowelsigndeva", "aivowelsigngujarati", + "akatakana", "akatakanahalfwidth", "akorean", "alef", "alefarabic", + "alefdageshhebrew", "aleffinalarabic", "alefhamzaabovearabic", + "alefhamzaabovefinalarabic", "alefhamzabelowarabic", + "alefhamzabelowfinalarabic", "alefhebrew", "aleflamedhebrew", + "alefmaddaabovearabic", "alefmaddaabovefinalarabic", + "alefmaksuraarabic", "alefmaksurafinalarabic", + "alefmaksurainitialarabic", "alefmaksuramedialarabic", + "alefpatahhebrew", "alefqamatshebrew", "aleph", "allequal", + "alpha", "alphatonos", "amacron", "amonospace", "ampersand", + "ampersandmonospace", "ampersandsmall", "amsquare", "anbopomofo", + "angbopomofo", "angkhankhuthai", "angle", "anglebracketleft", + "anglebracketleftvertical", "anglebracketright", + "anglebracketrightvertical", "angleleft", "angleright", "angstrom", + "anoteleia", "anudattadeva", "anusvarabengali", "anusvaradeva", + "anusvaragujarati", "aogonek", "apaatosquare", "aparen", + "apostrophearmenian", "apostrophemod", "apple", "approaches", + "approxequal", "approxequalorimage", "approximatelyequal", + "araeaekorean", "araeakorean", "arc", "arighthalfring", "aring", + "aringacute", "aringbelow", "arrowboth", "arrowdashdown", + "arrowdashleft", "arrowdashright", "arrowdashup", "arrowdblboth", + "arrowdbldown", "arrowdblleft", "arrowdblright", "arrowdblup", + "arrowdown", "arrowdownleft", "arrowdownright", "arrowdownwhite", + "arrowheaddownmod", "arrowheadleftmod", "arrowheadrightmod", + "arrowheadupmod", "arrowhorizex", "arrowleft", "arrowleftdbl", + "arrowleftdblstroke", "arrowleftoverright", "arrowleftwhite", + "arrowright", "arrowrightdblstroke", "arrowrightheavy", + "arrowrightoverleft", "arrowrightwhite", "arrowtableft", + "arrowtabright", "arrowup", "arrowupdn", "arrowupdnbse", + "arrowupdownbase", "arrowupleft", "arrowupleftofdown", + "arrowupright", "arrowupwhite", "arrowvertex", "asciicircum", + "asciicircummonospace", "asciitilde", "asciitildemonospace", + "ascript", "ascriptturned", "asmallhiragana", "asmallkatakana", + "asmallkatakanahalfwidth", "asterisk", "asteriskaltonearabic", + "asteriskarabic", "asteriskmath", "asteriskmonospace", + "asterisksmall", "asterism", "asuperior", "asymptoticallyequal", + "at", "atilde", "atmonospace", "atsmall", "aturned", "aubengali", + "aubopomofo", "audeva", "augujarati", "augurmukhi", + "aulengthmarkbengali", "aumatragurmukhi", "auvowelsignbengali", + "auvowelsigndeva", "auvowelsigngujarati", "avagrahadeva", + "aybarmenian", "ayin", "ayinaltonehebrew", "ayinhebrew", "b", + "babengali", "backslash", "backslashmonospace", "badeva", + "bagujarati", "bagurmukhi", "bahiragana", "bahtthai", "bakatakana", + "bar", "barmonospace", "bbopomofo", "bcircle", "bdotaccent", + "bdotbelow", "beamedsixteenthnotes", "because", "becyrillic", + "beharabic", "behfinalarabic", "behinitialarabic", "behiragana", + "behmedialarabic", "behmeeminitialarabic", "behmeemisolatedarabic", + "behnoonfinalarabic", "bekatakana", "benarmenian", "bet", "beta", + "betasymbolgreek", "betdagesh", "betdageshhebrew", "bethebrew", + "betrafehebrew", "bhabengali", "bhadeva", "bhagujarati", + "bhagurmukhi", "bhook", "bihiragana", "bikatakana", + "bilabialclick", "bindigurmukhi", "birusquare", "blackcircle", + "blackdiamond", "blackdownpointingtriangle", + "blackleftpointingpointer", "blackleftpointingtriangle", + "blacklenticularbracketleft", "blacklenticularbracketleftvertical", + "blacklenticularbracketright", + "blacklenticularbracketrightvertical", "blacklowerlefttriangle", + "blacklowerrighttriangle", "blackrectangle", + "blackrightpointingpointer", "blackrightpointingtriangle", + "blacksmallsquare", "blacksmilingface", "blacksquare", "blackstar", + "blackupperlefttriangle", "blackupperrighttriangle", + "blackuppointingsmalltriangle", "blackuppointingtriangle", "blank", + "blinebelow", "block", "bmonospace", "bobaimaithai", "bohiragana", + "bokatakana", "bparen", "bqsquare", "braceex", "braceleft", + "braceleftbt", "braceleftmid", "braceleftmonospace", + "braceleftsmall", "bracelefttp", "braceleftvertical", "braceright", + "bracerightbt", "bracerightmid", "bracerightmonospace", + "bracerightsmall", "bracerighttp", "bracerightvertical", + "bracketleft", "bracketleftbt", "bracketleftex", + "bracketleftmonospace", "bracketlefttp", "bracketright", + "bracketrightbt", "bracketrightex", "bracketrightmonospace", + "bracketrighttp", "breve", "brevebelowcmb", "brevecmb", + "breveinvertedbelowcmb", "breveinvertedcmb", + "breveinverteddoublecmb", "bridgebelowcmb", + "bridgeinvertedbelowcmb", "brokenbar", "bstroke", "bsuperior", + "btopbar", "buhiragana", "bukatakana", "bullet", "bulletinverse", + "bulletoperator", "bullseye", "c", "caarmenian", "cabengali", + "cacute", "cadeva", "cagujarati", "cagurmukhi", "calsquare", + "candrabindubengali", "candrabinducmb", "candrabindudeva", + "candrabindugujarati", "capslock", "careof", "caron", + "caronbelowcmb", "caroncmb", "carriagereturn", "cbopomofo", + "ccaron", "ccedilla", "ccedillaacute", "ccircle", "ccircumflex", + "ccurl", "cdot", "cdotaccent", "cdsquare", "cedilla", "cedillacmb", + "cent", "centigrade", "centinferior", "centmonospace", + "centoldstyle", "centsuperior", "chaarmenian", "chabengali", + "chadeva", "chagujarati", "chagurmukhi", "chbopomofo", + "cheabkhasiancyrillic", "checkmark", "checyrillic", + "chedescenderabkhasiancyrillic", "chedescendercyrillic", + "chedieresiscyrillic", "cheharmenian", "chekhakassiancyrillic", + "cheverticalstrokecyrillic", "chi", "chieuchacirclekorean", + "chieuchaparenkorean", "chieuchcirclekorean", "chieuchkorean", + "chieuchparenkorean", "chochangthai", "chochanthai", + "chochingthai", "chochoethai", "chook", "cieucacirclekorean", + "cieucaparenkorean", "cieuccirclekorean", "cieuckorean", + "cieucparenkorean", "cieucuparenkorean", "circle", + "circlemultiply", "circleot", "circleplus", "circlepostalmark", + "circlewithlefthalfblack", "circlewithrighthalfblack", + "circumflex", "circumflexbelowcmb", "circumflexcmb", "clear", + "clickalveolar", "clickdental", "clicklateral", "clickretroflex", + "club", "clubsuitblack", "clubsuitwhite", "cmcubedsquare", + "cmonospace", "cmsquaredsquare", "coarmenian", "colon", + "colonmonetary", "colonmonospace", "colonsign", "colonsmall", + "colontriangularhalfmod", "colontriangularmod", "comma", + "commaabovecmb", "commaaboverightcmb", "commaaccent", + "commaarabic", "commaarmenian", "commainferior", "commamonospace", + "commareversedabovecmb", "commareversedmod", "commasmall", + "commasuperior", "commaturnedabovecmb", "commaturnedmod", + "compass", "congruent", "contourintegral", "control", "controlACK", + "controlBEL", "controlBS", "controlCAN", "controlCR", "controlDC1", + "controlDC2", "controlDC3", "controlDC4", "controlDEL", + "controlDLE", "controlEM", "controlENQ", "controlEOT", + "controlESC", "controlETB", "controlETX", "controlFF", "controlFS", + "controlGS", "controlHT", "controlLF", "controlNAK", "controlRS", + "controlSI", "controlSO", "controlSOT", "controlSTX", "controlSUB", + "controlSYN", "controlUS", "controlVT", "copyright", + "copyrightsans", "copyrightserif", "cornerbracketleft", + "cornerbracketlefthalfwidth", "cornerbracketleftvertical", + "cornerbracketright", "cornerbracketrighthalfwidth", + "cornerbracketrightvertical", "corporationsquare", "cosquare", + "coverkgsquare", "cparen", "cruzeiro", "cstretched", "curlyand", + "curlyor", "currency", "cyrBreve", "cyrFlex", "cyrbreve", + "cyrflex", "d", "daarmenian", "dabengali", "dadarabic", "dadeva", + "dadfinalarabic", "dadinitialarabic", "dadmedialarabic", "dagesh", + "dageshhebrew", "dagger", "daggerdbl", "dagujarati", "dagurmukhi", + "dahiragana", "dakatakana", "dalarabic", "dalet", "daletdagesh", + "daletdageshhebrew", "dalethebrew", "dalfinalarabic", + "dammaarabic", "dammalowarabic", "dammatanaltonearabic", + "dammatanarabic", "danda", "dargahebrew", "dargalefthebrew", + "dasiapneumatacyrilliccmb", "dblGrave", "dblanglebracketleft", + "dblanglebracketleftvertical", "dblanglebracketright", + "dblanglebracketrightvertical", "dblarchinvertedbelowcmb", + "dblarrowleft", "dblarrowright", "dbldanda", "dblgrave", + "dblgravecmb", "dblintegral", "dbllowline", "dbllowlinecmb", + "dbloverlinecmb", "dblprimemod", "dblverticalbar", + "dblverticallineabovecmb", "dbopomofo", "dbsquare", "dcaron", + "dcedilla", "dcircle", "dcircumflexbelow", "dcroat", "ddabengali", + "ddadeva", "ddagujarati", "ddagurmukhi", "ddalarabic", + "ddalfinalarabic", "dddhadeva", "ddhabengali", "ddhadeva", + "ddhagujarati", "ddhagurmukhi", "ddotaccent", "ddotbelow", + "decimalseparatorarabic", "decimalseparatorpersian", "decyrillic", + "degree", "dehihebrew", "dehiragana", "deicoptic", "dekatakana", + "deleteleft", "deleteright", "delta", "deltaturned", + "denominatorminusonenumeratorbengali", "dezh", "dhabengali", + "dhadeva", "dhagujarati", "dhagurmukhi", "dhook", "dialytikatonos", + "dialytikatonoscmb", "diamond", "diamondsuitwhite", "dieresis", + "dieresisacute", "dieresisbelowcmb", "dieresiscmb", + "dieresisgrave", "dieresistonos", "dihiragana", "dikatakana", + "dittomark", "divide", "divides", "divisionslash", "djecyrillic", + "dkshade", "dlinebelow", "dlsquare", "dmacron", "dmonospace", + "dnblock", "dochadathai", "dodekthai", "dohiragana", "dokatakana", + "dollar", "dollarinferior", "dollarmonospace", "dollaroldstyle", + "dollarsmall", "dollarsuperior", "dong", "dorusquare", "dotaccent", + "dotaccentcmb", "dotbelowcmb", "dotbelowcomb", "dotkatakana", + "dotlessi", "dotlessj", "dotlessjstrokehook", "dotmath", + "dottedcircle", "doubleyodpatah", "doubleyodpatahhebrew", + "downtackbelowcmb", "downtackmod", "dparen", "dsuperior", "dtail", + "dtopbar", "duhiragana", "dukatakana", "dz", "dzaltone", "dzcaron", + "dzcurl", "dzeabkhasiancyrillic", "dzecyrillic", "dzhecyrillic", + "e", "eacute", "earth", "ebengali", "ebopomofo", "ebreve", + "ecandradeva", "ecandragujarati", "ecandravowelsigndeva", + "ecandravowelsigngujarati", "ecaron", "ecedillabreve", + "echarmenian", "echyiwnarmenian", "ecircle", "ecircumflex", + "ecircumflexacute", "ecircumflexbelow", "ecircumflexdotbelow", + "ecircumflexgrave", "ecircumflexhookabove", "ecircumflextilde", + "ecyrillic", "edblgrave", "edeva", "edieresis", "edot", + "edotaccent", "edotbelow", "eegurmukhi", "eematragurmukhi", + "efcyrillic", "egrave", "egujarati", "eharmenian", "ehbopomofo", + "ehiragana", "ehookabove", "eibopomofo", "eight", "eightarabic", + "eightbengali", "eightcircle", "eightcircleinversesansserif", + "eightdeva", "eighteencircle", "eighteenparen", "eighteenperiod", + "eightgujarati", "eightgurmukhi", "eighthackarabic", + "eighthangzhou", "eighthnotebeamed", "eightideographicparen", + "eightinferior", "eightmonospace", "eightoldstyle", "eightparen", + "eightperiod", "eightpersian", "eightroman", "eightsuperior", + "eightthai", "einvertedbreve", "eiotifiedcyrillic", "ekatakana", + "ekatakanahalfwidth", "ekonkargurmukhi", "ekorean", "elcyrillic", + "element", "elevencircle", "elevenparen", "elevenperiod", + "elevenroman", "ellipsis", "ellipsisvertical", "emacron", + "emacronacute", "emacrongrave", "emcyrillic", "emdash", + "emdashvertical", "emonospace", "emphasismarkarmenian", "emptyset", + "enbopomofo", "encyrillic", "endash", "endashvertical", + "endescendercyrillic", "eng", "engbopomofo", "enghecyrillic", + "enhookcyrillic", "enspace", "eogonek", "eokorean", "eopen", + "eopenclosed", "eopenreversed", "eopenreversedclosed", + "eopenreversedhook", "eparen", "epsilon", "epsilontonos", "equal", + "equalmonospace", "equalsmall", "equalsuperior", "equivalence", + "erbopomofo", "ercyrillic", "ereversed", "ereversedcyrillic", + "escyrillic", "esdescendercyrillic", "esh", "eshcurl", + "eshortdeva", "eshortvowelsigndeva", "eshreversedloop", + "eshsquatreversed", "esmallhiragana", "esmallkatakana", + "esmallkatakanahalfwidth", "estimated", "esuperior", "eta", + "etarmenian", "etatonos", "eth", "etilde", "etildebelow", + "etnahtafoukhhebrew", "etnahtafoukhlefthebrew", "etnahtahebrew", + "etnahtalefthebrew", "eturned", "eukorean", "euro", + "evowelsignbengali", "evowelsigndeva", "evowelsigngujarati", + "exclam", "exclamarmenian", "exclamdbl", "exclamdown", + "exclamdownsmall", "exclammonospace", "exclamsmall", "existential", + "ezh", "ezhcaron", "ezhcurl", "ezhreversed", "ezhtail", "f", + "fadeva", "fagurmukhi", "fahrenheit", "fathaarabic", + "fathalowarabic", "fathatanarabic", "fbopomofo", "fcircle", + "fdotaccent", "feharabic", "feharmenian", "fehfinalarabic", + "fehinitialarabic", "fehmedialarabic", "feicoptic", "female", "ff", + "ffi", "ffl", "fi", "fifteencircle", "fifteenparen", + "fifteenperiod", "figuredash", "filledbox", "filledrect", + "finalkaf", "finalkafdagesh", "finalkafdageshhebrew", + "finalkafhebrew", "finalmem", "finalmemhebrew", "finalnun", + "finalnunhebrew", "finalpe", "finalpehebrew", "finaltsadi", + "finaltsadihebrew", "firsttonechinese", "fisheye", "fitacyrillic", + "five", "fivearabic", "fivebengali", "fivecircle", + "fivecircleinversesansserif", "fivedeva", "fiveeighths", + "fivegujarati", "fivegurmukhi", "fivehackarabic", "fivehangzhou", + "fiveideographicparen", "fiveinferior", "fivemonospace", + "fiveoldstyle", "fiveparen", "fiveperiod", "fivepersian", + "fiveroman", "fivesuperior", "fivethai", "fl", "florin", + "fmonospace", "fmsquare", "fofanthai", "fofathai", "fongmanthai", + "forall", "four", "fourarabic", "fourbengali", "fourcircle", + "fourcircleinversesansserif", "fourdeva", "fourgujarati", + "fourgurmukhi", "fourhackarabic", "fourhangzhou", + "fourideographicparen", "fourinferior", "fourmonospace", + "fournumeratorbengali", "fouroldstyle", "fourparen", "fourperiod", + "fourpersian", "fourroman", "foursuperior", "fourteencircle", + "fourteenparen", "fourteenperiod", "fourthai", "fourthtonechinese", + "fparen", "fraction", "franc", "g", "gabengali", "gacute", + "gadeva", "gafarabic", "gaffinalarabic", "gafinitialarabic", + "gafmedialarabic", "gagujarati", "gagurmukhi", "gahiragana", + "gakatakana", "gamma", "gammalatinsmall", "gammasuperior", + "gangiacoptic", "gbopomofo", "gbreve", "gcaron", "gcedilla", + "gcircle", "gcircumflex", "gcommaaccent", "gdot", "gdotaccent", + "gecyrillic", "gehiragana", "gekatakana", "geometricallyequal", + "gereshaccenthebrew", "gereshhebrew", "gereshmuqdamhebrew", + "germandbls", "gershayimaccenthebrew", "gershayimhebrew", + "getamark", "ghabengali", "ghadarmenian", "ghadeva", "ghagujarati", + "ghagurmukhi", "ghainarabic", "ghainfinalarabic", + "ghaininitialarabic", "ghainmedialarabic", "ghemiddlehookcyrillic", + "ghestrokecyrillic", "gheupturncyrillic", "ghhadeva", + "ghhagurmukhi", "ghook", "ghzsquare", "gihiragana", "gikatakana", + "gimarmenian", "gimel", "gimeldagesh", "gimeldageshhebrew", + "gimelhebrew", "gjecyrillic", "glottalinvertedstroke", + "glottalstop", "glottalstopinverted", "glottalstopmod", + "glottalstopreversed", "glottalstopreversedmod", + "glottalstopreversedsuperior", "glottalstopstroke", + "glottalstopstrokereversed", "gmacron", "gmonospace", "gohiragana", + "gokatakana", "gparen", "gpasquare", "gradient", "grave", + "gravebelowcmb", "gravecmb", "gravecomb", "gravedeva", + "gravelowmod", "gravemonospace", "gravetonecmb", "greater", + "greaterequal", "greaterequalorless", "greatermonospace", + "greaterorequivalent", "greaterorless", "greateroverequal", + "greatersmall", "gscript", "gstroke", "guhiragana", + "guillemotleft", "guillemotright", "guilsinglleft", + "guilsinglright", "gukatakana", "guramusquare", "gysquare", "h", + "haabkhasiancyrillic", "haaltonearabic", "habengali", + "hadescendercyrillic", "hadeva", "hagujarati", "hagurmukhi", + "haharabic", "hahfinalarabic", "hahinitialarabic", "hahiragana", + "hahmedialarabic", "haitusquare", "hakatakana", + "hakatakanahalfwidth", "halantgurmukhi", "hamzaarabic", + "hamzalowarabic", "hangulfiller", "hardsigncyrillic", + "harpoonleftbarbup", "harpoonrightbarbup", "hasquare", + "hatafpatah", "hatafpatah16", "hatafpatah23", "hatafpatah2f", + "hatafpatahhebrew", "hatafpatahnarrowhebrew", + "hatafpatahquarterhebrew", "hatafpatahwidehebrew", "hatafqamats", + "hatafqamats1b", "hatafqamats28", "hatafqamats34", + "hatafqamatshebrew", "hatafqamatsnarrowhebrew", + "hatafqamatsquarterhebrew", "hatafqamatswidehebrew", "hatafsegol", + "hatafsegol17", "hatafsegol24", "hatafsegol30", "hatafsegolhebrew", + "hatafsegolnarrowhebrew", "hatafsegolquarterhebrew", + "hatafsegolwidehebrew", "hbar", "hbopomofo", "hbrevebelow", + "hcedilla", "hcircle", "hcircumflex", "hdieresis", "hdotaccent", + "hdotbelow", "he", "heart", "heartsuitblack", "heartsuitwhite", + "hedagesh", "hedageshhebrew", "hehaltonearabic", "heharabic", + "hehebrew", "hehfinalaltonearabic", "hehfinalalttwoarabic", + "hehfinalarabic", "hehhamzaabovefinalarabic", + "hehhamzaaboveisolatedarabic", "hehinitialaltonearabic", + "hehinitialarabic", "hehiragana", "hehmedialaltonearabic", + "hehmedialarabic", "heiseierasquare", "hekatakana", + "hekatakanahalfwidth", "hekutaarusquare", "henghook", + "herutusquare", "het", "hethebrew", "hhook", "hhooksuperior", + "hieuhacirclekorean", "hieuhaparenkorean", "hieuhcirclekorean", + "hieuhkorean", "hieuhparenkorean", "hihiragana", "hikatakana", + "hikatakanahalfwidth", "hiriq", "hiriq14", "hiriq21", "hiriq2d", + "hiriqhebrew", "hiriqnarrowhebrew", "hiriqquarterhebrew", + "hiriqwidehebrew", "hlinebelow", "hmonospace", "hoarmenian", + "hohipthai", "hohiragana", "hokatakana", "hokatakanahalfwidth", + "holam", "holam19", "holam26", "holam32", "holamhebrew", + "holamnarrowhebrew", "holamquarterhebrew", "holamwidehebrew", + "honokhukthai", "hookabovecomb", "hookcmb", + "hookpalatalizedbelowcmb", "hookretroflexbelowcmb", "hoonsquare", + "horicoptic", "horizontalbar", "horncmb", "hotsprings", "house", + "hparen", "hsuperior", "hturned", "huhiragana", "huiitosquare", + "hukatakana", "hukatakanahalfwidth", "hungarumlaut", + "hungarumlautcmb", "hv", "hyphen", "hypheninferior", + "hyphenmonospace", "hyphensmall", "hyphensuperior", "hyphentwo", + "i", "iacute", "iacyrillic", "ibengali", "ibopomofo", "ibreve", + "icaron", "icircle", "icircumflex", "icyrillic", "idblgrave", + "ideographearthcircle", "ideographfirecircle", + "ideographicallianceparen", "ideographiccallparen", + "ideographiccentrecircle", "ideographicclose", "ideographiccomma", + "ideographiccommaleft", "ideographiccongratulationparen", + "ideographiccorrectcircle", "ideographicearthparen", + "ideographicenterpriseparen", "ideographicexcellentcircle", + "ideographicfestivalparen", "ideographicfinancialcircle", + "ideographicfinancialparen", "ideographicfireparen", + "ideographichaveparen", "ideographichighcircle", + "ideographiciterationmark", "ideographiclaborcircle", + "ideographiclaborparen", "ideographicleftcircle", + "ideographiclowcircle", "ideographicmedicinecircle", + "ideographicmetalparen", "ideographicmoonparen", + "ideographicnameparen", "ideographicperiod", + "ideographicprintcircle", "ideographicreachparen", + "ideographicrepresentparen", "ideographicresourceparen", + "ideographicrightcircle", "ideographicsecretcircle", + "ideographicselfparen", "ideographicsocietyparen", + "ideographicspace", "ideographicspecialparen", + "ideographicstockparen", "ideographicstudyparen", + "ideographicsunparen", "ideographicsuperviseparen", + "ideographicwaterparen", "ideographicwoodparen", "ideographiczero", + "ideographmetalcircle", "ideographmooncircle", + "ideographnamecircle", "ideographsuncircle", + "ideographwatercircle", "ideographwoodcircle", "ideva", + "idieresis", "idieresisacute", "idieresiscyrillic", "idotbelow", + "iebrevecyrillic", "iecyrillic", "ieungacirclekorean", + "ieungaparenkorean", "ieungcirclekorean", "ieungkorean", + "ieungparenkorean", "igrave", "igujarati", "igurmukhi", + "ihiragana", "ihookabove", "iibengali", "iicyrillic", "iideva", + "iigujarati", "iigurmukhi", "iimatragurmukhi", "iinvertedbreve", + "iishortcyrillic", "iivowelsignbengali", "iivowelsigndeva", + "iivowelsigngujarati", "ij", "ikatakana", "ikatakanahalfwidth", + "ikorean", "ilde", "iluyhebrew", "imacron", "imacroncyrillic", + "imageorapproximatelyequal", "imatragurmukhi", "imonospace", + "increment", "infinity", "iniarmenian", "integral", + "integralbottom", "integralbt", "integralex", "integraltop", + "integraltp", "intersection", "intisquare", "invbullet", + "invcircle", "invsmileface", "iocyrillic", "iogonek", "iota", + "iotadieresis", "iotadieresistonos", "iotalatin", "iotatonos", + "iparen", "irigurmukhi", "ismallhiragana", "ismallkatakana", + "ismallkatakanahalfwidth", "issharbengali", "istroke", "isuperior", + "iterationhiragana", "iterationkatakana", "itilde", "itildebelow", + "iubopomofo", "iucyrillic", "ivowelsignbengali", "ivowelsigndeva", + "ivowelsigngujarati", "izhitsacyrillic", "izhitsadblgravecyrillic", + "j", "jaarmenian", "jabengali", "jadeva", "jagujarati", + "jagurmukhi", "jbopomofo", "jcaron", "jcircle", "jcircumflex", + "jcrossedtail", "jdotlessstroke", "jecyrillic", "jeemarabic", + "jeemfinalarabic", "jeeminitialarabic", "jeemmedialarabic", + "jeharabic", "jehfinalarabic", "jhabengali", "jhadeva", + "jhagujarati", "jhagurmukhi", "jheharmenian", "jis", "jmonospace", + "jparen", "jsuperior", "k", "kabashkircyrillic", "kabengali", + "kacute", "kacyrillic", "kadescendercyrillic", "kadeva", "kaf", + "kafarabic", "kafdagesh", "kafdageshhebrew", "kaffinalarabic", + "kafhebrew", "kafinitialarabic", "kafmedialarabic", + "kafrafehebrew", "kagujarati", "kagurmukhi", "kahiragana", + "kahookcyrillic", "kakatakana", "kakatakanahalfwidth", "kappa", + "kappasymbolgreek", "kapyeounmieumkorean", "kapyeounphieuphkorean", + "kapyeounpieupkorean", "kapyeounssangpieupkorean", "karoriisquare", + "kashidaautoarabic", "kashidaautonosidebearingarabic", + "kasmallkatakana", "kasquare", "kasraarabic", "kasratanarabic", + "kastrokecyrillic", "katahiraprolongmarkhalfwidth", + "kaverticalstrokecyrillic", "kbopomofo", "kcalsquare", "kcaron", + "kcedilla", "kcircle", "kcommaaccent", "kdotbelow", "keharmenian", + "kehiragana", "kekatakana", "kekatakanahalfwidth", "kenarmenian", + "kesmallkatakana", "kgreenlandic", "khabengali", "khacyrillic", + "khadeva", "khagujarati", "khagurmukhi", "khaharabic", + "khahfinalarabic", "khahinitialarabic", "khahmedialarabic", + "kheicoptic", "khhadeva", "khhagurmukhi", "khieukhacirclekorean", + "khieukhaparenkorean", "khieukhcirclekorean", "khieukhkorean", + "khieukhparenkorean", "khokhaithai", "khokhonthai", "khokhuatthai", + "khokhwaithai", "khomutthai", "khook", "khorakhangthai", + "khzsquare", "kihiragana", "kikatakana", "kikatakanahalfwidth", + "kiroguramusquare", "kiromeetorusquare", "kirosquare", + "kiyeokacirclekorean", "kiyeokaparenkorean", "kiyeokcirclekorean", + "kiyeokkorean", "kiyeokparenkorean", "kiyeoksioskorean", + "kjecyrillic", "klinebelow", "klsquare", "kmcubedsquare", + "kmonospace", "kmsquaredsquare", "kohiragana", "kohmsquare", + "kokaithai", "kokatakana", "kokatakanahalfwidth", "kooposquare", + "koppacyrillic", "koreanstandardsymbol", "koroniscmb", "kparen", + "kpasquare", "ksicyrillic", "ktsquare", "kturned", "kuhiragana", + "kukatakana", "kukatakanahalfwidth", "kvsquare", "kwsquare", "l", + "labengali", "lacute", "ladeva", "lagujarati", "lagurmukhi", + "lakkhangyaothai", "lamaleffinalarabic", + "lamalefhamzaabovefinalarabic", "lamalefhamzaaboveisolatedarabic", + "lamalefhamzabelowfinalarabic", "lamalefhamzabelowisolatedarabic", + "lamalefisolatedarabic", "lamalefmaddaabovefinalarabic", + "lamalefmaddaaboveisolatedarabic", "lamarabic", "lambda", + "lambdastroke", "lamed", "lameddagesh", "lameddageshhebrew", + "lamedhebrew", "lamfinalarabic", "lamhahinitialarabic", + "laminitialarabic", "lamjeeminitialarabic", "lamkhahinitialarabic", + "lamlamhehisolatedarabic", "lammedialarabic", + "lammeemhahinitialarabic", "lammeeminitialarabic", "largecircle", + "lbar", "lbelt", "lbopomofo", "lcaron", "lcedilla", "lcircle", + "lcircumflexbelow", "lcommaaccent", "ldot", "ldotaccent", + "ldotbelow", "ldotbelowmacron", "leftangleabovecmb", + "lefttackbelowcmb", "less", "lessequal", "lessequalorgreater", + "lessmonospace", "lessorequivalent", "lessorgreater", + "lessoverequal", "lesssmall", "lezh", "lfblock", "lhookretroflex", + "lira", "liwnarmenian", "lj", "ljecyrillic", "ll", "lladeva", + "llagujarati", "llinebelow", "llladeva", "llvocalicbengali", + "llvocalicdeva", "llvocalicvowelsignbengali", + "llvocalicvowelsigndeva", "lmiddletilde", "lmonospace", "lmsquare", + "lochulathai", "logicaland", "logicalnot", "logicalnotreversed", + "logicalor", "lolingthai", "longs", "lowlinecenterline", + "lowlinecmb", "lowlinedashed", "lozenge", "lparen", "lslash", + "lsquare", "lsuperior", "ltshade", "luthai", "lvocalicbengali", + "lvocalicdeva", "lvocalicvowelsignbengali", + "lvocalicvowelsigndeva", "lxsquare", "m", "mabengali", "macron", + "macronbelowcmb", "macroncmb", "macronlowmod", "macronmonospace", + "macute", "madeva", "magujarati", "magurmukhi", "mahapakhhebrew", + "mahapakhlefthebrew", "mahiragana", "maichattawalowleftthai", + "maichattawalowrightthai", "maichattawathai", + "maichattawaupperleftthai", "maieklowleftthai", + "maieklowrightthai", "maiekthai", "maiekupperleftthai", + "maihanakatleftthai", "maihanakatthai", "maitaikhuleftthai", + "maitaikhuthai", "maitholowleftthai", "maitholowrightthai", + "maithothai", "maithoupperleftthai", "maitrilowleftthai", + "maitrilowrightthai", "maitrithai", "maitriupperleftthai", + "maiyamokthai", "makatakana", "makatakanahalfwidth", "male", + "mansyonsquare", "maqafhebrew", "mars", "masoracirclehebrew", + "masquare", "mbopomofo", "mbsquare", "mcircle", "mcubedsquare", + "mdotaccent", "mdotbelow", "meemarabic", "meemfinalarabic", + "meeminitialarabic", "meemmedialarabic", "meemmeeminitialarabic", + "meemmeemisolatedarabic", "meetorusquare", "mehiragana", + "meizierasquare", "mekatakana", "mekatakanahalfwidth", "mem", + "memdagesh", "memdageshhebrew", "memhebrew", "menarmenian", + "merkhahebrew", "merkhakefulahebrew", "merkhakefulalefthebrew", + "merkhalefthebrew", "mhook", "mhzsquare", + "middledotkatakanahalfwidth", "middot", "mieumacirclekorean", + "mieumaparenkorean", "mieumcirclekorean", "mieumkorean", + "mieumpansioskorean", "mieumparenkorean", "mieumpieupkorean", + "mieumsioskorean", "mihiragana", "mikatakana", + "mikatakanahalfwidth", "minus", "minusbelowcmb", "minuscircle", + "minusmod", "minusplus", "minute", "miribaarusquare", "mirisquare", + "mlonglegturned", "mlsquare", "mmcubedsquare", "mmonospace", + "mmsquaredsquare", "mohiragana", "mohmsquare", "mokatakana", + "mokatakanahalfwidth", "molsquare", "momathai", "moverssquare", + "moverssquaredsquare", "mparen", "mpasquare", "mssquare", + "msuperior", "mturned", "mu", "mu1", "muasquare", "muchgreater", + "muchless", "mufsquare", "mugreek", "mugsquare", "muhiragana", + "mukatakana", "mukatakanahalfwidth", "mulsquare", "multiply", + "mumsquare", "munahhebrew", "munahlefthebrew", "musicalnote", + "musicalnotedbl", "musicflatsign", "musicsharpsign", "mussquare", + "muvsquare", "muwsquare", "mvmegasquare", "mvsquare", + "mwmegasquare", "mwsquare", "n", "nabengali", "nabla", "nacute", + "nadeva", "nagujarati", "nagurmukhi", "nahiragana", "nakatakana", + "nakatakanahalfwidth", "napostrophe", "nasquare", "nbopomofo", + "nbspace", "ncaron", "ncedilla", "ncircle", "ncircumflexbelow", + "ncommaaccent", "ndotaccent", "ndotbelow", "nehiragana", + "nekatakana", "nekatakanahalfwidth", "newsheqelsign", "nfsquare", + "ngabengali", "ngadeva", "ngagujarati", "ngagurmukhi", + "ngonguthai", "nhiragana", "nhookleft", "nhookretroflex", + "nieunacirclekorean", "nieunaparenkorean", "nieuncieuckorean", + "nieuncirclekorean", "nieunhieuhkorean", "nieunkorean", + "nieunpansioskorean", "nieunparenkorean", "nieunsioskorean", + "nieuntikeutkorean", "nihiragana", "nikatakana", + "nikatakanahalfwidth", "nikhahitleftthai", "nikhahitthai", "nine", + "ninearabic", "ninebengali", "ninecircle", + "ninecircleinversesansserif", "ninedeva", "ninegujarati", + "ninegurmukhi", "ninehackarabic", "ninehangzhou", + "nineideographicparen", "nineinferior", "ninemonospace", + "nineoldstyle", "nineparen", "nineperiod", "ninepersian", + "nineroman", "ninesuperior", "nineteencircle", "nineteenparen", + "nineteenperiod", "ninethai", "nj", "njecyrillic", "nkatakana", + "nkatakanahalfwidth", "nlegrightlong", "nlinebelow", "nmonospace", + "nmsquare", "nnabengali", "nnadeva", "nnagujarati", "nnagurmukhi", + "nnnadeva", "nohiragana", "nokatakana", "nokatakanahalfwidth", + "nonbreakingspace", "nonenthai", "nonuthai", "noonarabic", + "noonfinalarabic", "noonghunnaarabic", "noonghunnafinalarabic", + "nooninitialarabic", "noonjeeminitialarabic", + "noonjeemisolatedarabic", "noonmedialarabic", + "noonmeeminitialarabic", "noonmeemisolatedarabic", + "noonnoonfinalarabic", "notcontains", "notelement", "notelementof", + "notequal", "notgreater", "notgreaternorequal", + "notgreaternorless", "notidentical", "notless", "notlessnorequal", + "notparallel", "notprecedes", "notsubset", "notsucceeds", + "notsuperset", "nowarmenian", "nparen", "nssquare", "nsuperior", + "ntilde", "nu", "nuhiragana", "nukatakana", "nukatakanahalfwidth", + "nuktabengali", "nuktadeva", "nuktagujarati", "nuktagurmukhi", + "numbersign", "numbersignmonospace", "numbersignsmall", + "numeralsigngreek", "numeralsignlowergreek", "numero", "nun", + "nundagesh", "nundageshhebrew", "nunhebrew", "nvsquare", + "nwsquare", "nyabengali", "nyadeva", "nyagujarati", "nyagurmukhi", + "o", "oacute", "oangthai", "obarred", "obarredcyrillic", + "obarreddieresiscyrillic", "obengali", "obopomofo", "obreve", + "ocandradeva", "ocandragujarati", "ocandravowelsigndeva", + "ocandravowelsigngujarati", "ocaron", "ocircle", "ocircumflex", + "ocircumflexacute", "ocircumflexdotbelow", "ocircumflexgrave", + "ocircumflexhookabove", "ocircumflextilde", "ocyrillic", + "odblacute", "odblgrave", "odeva", "odieresis", + "odieresiscyrillic", "odotbelow", "oe", "oekorean", "ogonek", + "ogonekcmb", "ograve", "ogujarati", "oharmenian", "ohiragana", + "ohookabove", "ohorn", "ohornacute", "ohorndotbelow", "ohorngrave", + "ohornhookabove", "ohorntilde", "ohungarumlaut", "oi", + "oinvertedbreve", "okatakana", "okatakanahalfwidth", "okorean", + "olehebrew", "omacron", "omacronacute", "omacrongrave", "omdeva", + "omega", "omega1", "omegacyrillic", "omegalatinclosed", + "omegaroundcyrillic", "omegatitlocyrillic", "omegatonos", + "omgujarati", "omicron", "omicrontonos", "omonospace", "one", + "onearabic", "onebengali", "onecircle", + "onecircleinversesansserif", "onedeva", "onedotenleader", + "oneeighth", "onefitted", "onegujarati", "onegurmukhi", + "onehackarabic", "onehalf", "onehangzhou", "oneideographicparen", + "oneinferior", "onemonospace", "onenumeratorbengali", + "oneoldstyle", "oneparen", "oneperiod", "onepersian", "onequarter", + "oneroman", "onesuperior", "onethai", "onethird", "oogonek", + "oogonekmacron", "oogurmukhi", "oomatragurmukhi", "oopen", + "oparen", "openbullet", "option", "ordfeminine", "ordmasculine", + "orthogonal", "oshortdeva", "oshortvowelsigndeva", "oslash", + "oslashacute", "osmallhiragana", "osmallkatakana", + "osmallkatakanahalfwidth", "ostrokeacute", "osuperior", + "otcyrillic", "otilde", "otildeacute", "otildedieresis", + "oubopomofo", "overline", "overlinecenterline", "overlinecmb", + "overlinedashed", "overlinedblwavy", "overlinewavy", "overscore", + "ovowelsignbengali", "ovowelsigndeva", "ovowelsigngujarati", "p", + "paampssquare", "paasentosquare", "pabengali", "pacute", "padeva", + "pagedown", "pageup", "pagujarati", "pagurmukhi", "pahiragana", + "paiyannoithai", "pakatakana", "palatalizationcyrilliccmb", + "palochkacyrillic", "pansioskorean", "paragraph", "parallel", + "parenleft", "parenleftaltonearabic", "parenleftbt", "parenleftex", + "parenleftinferior", "parenleftmonospace", "parenleftsmall", + "parenleftsuperior", "parenlefttp", "parenleftvertical", + "parenright", "parenrightaltonearabic", "parenrightbt", + "parenrightex", "parenrightinferior", "parenrightmonospace", + "parenrightsmall", "parenrightsuperior", "parenrighttp", + "parenrightvertical", "partialdiff", "paseqhebrew", "pashtahebrew", + "pasquare", "patah", "patah11", "patah1d", "patah2a", + "patahhebrew", "patahnarrowhebrew", "patahquarterhebrew", + "patahwidehebrew", "pazerhebrew", "pbopomofo", "pcircle", + "pdotaccent", "pe", "pecyrillic", "pedagesh", "pedageshhebrew", + "peezisquare", "pefinaldageshhebrew", "peharabic", "peharmenian", + "pehebrew", "pehfinalarabic", "pehinitialarabic", "pehiragana", + "pehmedialarabic", "pekatakana", "pemiddlehookcyrillic", + "perafehebrew", "percent", "percentarabic", "percentmonospace", + "percentsmall", "period", "periodarmenian", "periodcentered", + "periodhalfwidth", "periodinferior", "periodmonospace", + "periodsmall", "periodsuperior", "perispomenigreekcmb", + "perpendicular", "perthousand", "peseta", "pfsquare", "phabengali", + "phadeva", "phagujarati", "phagurmukhi", "phi", "phi1", + "phieuphacirclekorean", "phieuphaparenkorean", + "phieuphcirclekorean", "phieuphkorean", "phieuphparenkorean", + "philatin", "phinthuthai", "phisymbolgreek", "phook", + "phophanthai", "phophungthai", "phosamphaothai", "pi", + "pieupacirclekorean", "pieupaparenkorean", "pieupcieuckorean", + "pieupcirclekorean", "pieupkiyeokkorean", "pieupkorean", + "pieupparenkorean", "pieupsioskiyeokkorean", "pieupsioskorean", + "pieupsiostikeutkorean", "pieupthieuthkorean", "pieuptikeutkorean", + "pihiragana", "pikatakana", "pisymbolgreek", "piwrarmenian", + "plus", "plusbelowcmb", "pluscircle", "plusminus", "plusmod", + "plusmonospace", "plussmall", "plussuperior", "pmonospace", + "pmsquare", "pohiragana", "pointingindexdownwhite", + "pointingindexleftwhite", "pointingindexrightwhite", + "pointingindexupwhite", "pokatakana", "poplathai", "postalmark", + "postalmarkface", "pparen", "precedes", "prescription", "primemod", + "primereversed", "product", "projective", "prolongedkana", + "propellor", "propersubset", "propersuperset", "proportion", + "proportional", "psi", "psicyrillic", "psilipneumatacyrilliccmb", + "pssquare", "puhiragana", "pukatakana", "pvsquare", "pwsquare", + "q", "qadeva", "qadmahebrew", "qafarabic", "qaffinalarabic", + "qafinitialarabic", "qafmedialarabic", "qamats", "qamats10", + "qamats1a", "qamats1c", "qamats27", "qamats29", "qamats33", + "qamatsde", "qamatshebrew", "qamatsnarrowhebrew", + "qamatsqatanhebrew", "qamatsqatannarrowhebrew", + "qamatsqatanquarterhebrew", "qamatsqatanwidehebrew", + "qamatsquarterhebrew", "qamatswidehebrew", "qarneyparahebrew", + "qbopomofo", "qcircle", "qhook", "qmonospace", "qof", "qofdagesh", + "qofdageshhebrew", "qofhebrew", "qparen", "quarternote", "qubuts", + "qubuts18", "qubuts25", "qubuts31", "qubutshebrew", + "qubutsnarrowhebrew", "qubutsquarterhebrew", "qubutswidehebrew", + "question", "questionarabic", "questionarmenian", "questiondown", + "questiondownsmall", "questiongreek", "questionmonospace", + "questionsmall", "quotedbl", "quotedblbase", "quotedblleft", + "quotedblmonospace", "quotedblprime", "quotedblprimereversed", + "quotedblright", "quoteleft", "quoteleftreversed", "quotereversed", + "quoteright", "quoterightn", "quotesinglbase", "quotesingle", + "quotesinglemonospace", "r", "raarmenian", "rabengali", "racute", + "radeva", "radical", "radicalex", "radoverssquare", + "radoverssquaredsquare", "radsquare", "rafe", "rafehebrew", + "ragujarati", "ragurmukhi", "rahiragana", "rakatakana", + "rakatakanahalfwidth", "ralowerdiagonalbengali", + "ramiddlediagonalbengali", "ramshorn", "ratio", "rbopomofo", + "rcaron", "rcedilla", "rcircle", "rcommaaccent", "rdblgrave", + "rdotaccent", "rdotbelow", "rdotbelowmacron", "referencemark", + "reflexsubset", "reflexsuperset", "registered", "registersans", + "registerserif", "reharabic", "reharmenian", "rehfinalarabic", + "rehiragana", "rekatakana", "rekatakanahalfwidth", "resh", + "reshdageshhebrew", "reshhebrew", "reversedtilde", "reviahebrew", + "reviamugrashhebrew", "revlogicalnot", "rfishhook", + "rfishhookreversed", "rhabengali", "rhadeva", "rho", "rhook", + "rhookturned", "rhookturnedsuperior", "rhosymbolgreek", + "rhotichookmod", "rieulacirclekorean", "rieulaparenkorean", + "rieulcirclekorean", "rieulhieuhkorean", "rieulkiyeokkorean", + "rieulkiyeoksioskorean", "rieulkorean", "rieulmieumkorean", + "rieulpansioskorean", "rieulparenkorean", "rieulphieuphkorean", + "rieulpieupkorean", "rieulpieupsioskorean", "rieulsioskorean", + "rieulthieuthkorean", "rieultikeutkorean", + "rieulyeorinhieuhkorean", "rightangle", "righttackbelowcmb", + "righttriangle", "rihiragana", "rikatakana", "rikatakanahalfwidth", + "ring", "ringbelowcmb", "ringcmb", "ringhalfleft", + "ringhalfleftarmenian", "ringhalfleftbelowcmb", + "ringhalfleftcentered", "ringhalfright", "ringhalfrightbelowcmb", + "ringhalfrightcentered", "rinvertedbreve", "rittorusquare", + "rlinebelow", "rlongleg", "rlonglegturned", "rmonospace", + "rohiragana", "rokatakana", "rokatakanahalfwidth", "roruathai", + "rparen", "rrabengali", "rradeva", "rragurmukhi", "rreharabic", + "rrehfinalarabic", "rrvocalicbengali", "rrvocalicdeva", + "rrvocalicgujarati", "rrvocalicvowelsignbengali", + "rrvocalicvowelsigndeva", "rrvocalicvowelsigngujarati", + "rsuperior", "rtblock", "rturned", "rturnedsuperior", "ruhiragana", + "rukatakana", "rukatakanahalfwidth", "rupeemarkbengali", + "rupeesignbengali", "rupiah", "ruthai", "rvocalicbengali", + "rvocalicdeva", "rvocalicgujarati", "rvocalicvowelsignbengali", + "rvocalicvowelsigndeva", "rvocalicvowelsigngujarati", "s", + "sabengali", "sacute", "sacutedotaccent", "sadarabic", "sadeva", + "sadfinalarabic", "sadinitialarabic", "sadmedialarabic", + "sagujarati", "sagurmukhi", "sahiragana", "sakatakana", + "sakatakanahalfwidth", "sallallahoualayhewasallamarabic", "samekh", + "samekhdagesh", "samekhdageshhebrew", "samekhhebrew", "saraaathai", + "saraaethai", "saraaimaimalaithai", "saraaimaimuanthai", + "saraamthai", "saraathai", "saraethai", "saraiileftthai", + "saraiithai", "saraileftthai", "saraithai", "saraothai", + "saraueeleftthai", "saraueethai", "saraueleftthai", "sarauethai", + "sarauthai", "sarauuthai", "sbopomofo", "scaron", + "scarondotaccent", "scedilla", "schwa", "schwacyrillic", + "schwadieresiscyrillic", "schwahook", "scircle", "scircumflex", + "scommaaccent", "sdotaccent", "sdotbelow", "sdotbelowdotaccent", + "seagullbelowcmb", "second", "secondtonechinese", "section", + "seenarabic", "seenfinalarabic", "seeninitialarabic", + "seenmedialarabic", "segol", "segol13", "segol1f", "segol2c", + "segolhebrew", "segolnarrowhebrew", "segolquarterhebrew", + "segoltahebrew", "segolwidehebrew", "seharmenian", "sehiragana", + "sekatakana", "sekatakanahalfwidth", "semicolon", + "semicolonarabic", "semicolonmonospace", "semicolonsmall", + "semivoicedmarkkana", "semivoicedmarkkanahalfwidth", "sentisquare", + "sentosquare", "seven", "sevenarabic", "sevenbengali", + "sevencircle", "sevencircleinversesansserif", "sevendeva", + "seveneighths", "sevengujarati", "sevengurmukhi", + "sevenhackarabic", "sevenhangzhou", "sevenideographicparen", + "seveninferior", "sevenmonospace", "sevenoldstyle", "sevenparen", + "sevenperiod", "sevenpersian", "sevenroman", "sevensuperior", + "seventeencircle", "seventeenparen", "seventeenperiod", + "seventhai", "sfthyphen", "shaarmenian", "shabengali", + "shacyrillic", "shaddaarabic", "shaddadammaarabic", + "shaddadammatanarabic", "shaddafathaarabic", "shaddakasraarabic", + "shaddakasratanarabic", "shade", "shadedark", "shadelight", + "shademedium", "shadeva", "shagujarati", "shagurmukhi", + "shalshelethebrew", "shbopomofo", "shchacyrillic", "sheenarabic", + "sheenfinalarabic", "sheeninitialarabic", "sheenmedialarabic", + "sheicoptic", "sheqel", "sheqelhebrew", "sheva", "sheva115", + "sheva15", "sheva22", "sheva2e", "shevahebrew", + "shevanarrowhebrew", "shevaquarterhebrew", "shevawidehebrew", + "shhacyrillic", "shimacoptic", "shin", "shindagesh", + "shindageshhebrew", "shindageshshindot", "shindageshshindothebrew", + "shindageshsindot", "shindageshsindothebrew", "shindothebrew", + "shinhebrew", "shinshindot", "shinshindothebrew", "shinsindot", + "shinsindothebrew", "shook", "sigma", "sigma1", "sigmafinal", + "sigmalunatesymbolgreek", "sihiragana", "sikatakana", + "sikatakanahalfwidth", "siluqhebrew", "siluqlefthebrew", "similar", + "sindothebrew", "siosacirclekorean", "siosaparenkorean", + "sioscieuckorean", "sioscirclekorean", "sioskiyeokkorean", + "sioskorean", "siosnieunkorean", "siosparenkorean", + "siospieupkorean", "siostikeutkorean", "six", "sixarabic", + "sixbengali", "sixcircle", "sixcircleinversesansserif", "sixdeva", + "sixgujarati", "sixgurmukhi", "sixhackarabic", "sixhangzhou", + "sixideographicparen", "sixinferior", "sixmonospace", + "sixoldstyle", "sixparen", "sixperiod", "sixpersian", "sixroman", + "sixsuperior", "sixteencircle", + "sixteencurrencydenominatorbengali", "sixteenparen", + "sixteenperiod", "sixthai", "slash", "slashmonospace", "slong", + "slongdotaccent", "smileface", "smonospace", "sofpasuqhebrew", + "softhyphen", "softsigncyrillic", "sohiragana", "sokatakana", + "sokatakanahalfwidth", "soliduslongoverlaycmb", + "solidusshortoverlaycmb", "sorusithai", "sosalathai", "sosothai", + "sosuathai", "space", "spacehackarabic", "spade", "spadesuitblack", + "spadesuitwhite", "sparen", "squarebelowcmb", "squarecc", + "squarecm", "squarediagonalcrosshatchfill", "squarehorizontalfill", + "squarekg", "squarekm", "squarekmcapital", "squareln", "squarelog", + "squaremg", "squaremil", "squaremm", "squaremsquared", + "squareorthogonalcrosshatchfill", + "squareupperlefttolowerrightfill", + "squareupperrighttolowerleftfill", "squareverticalfill", + "squarewhitewithsmallblack", "srsquare", "ssabengali", "ssadeva", + "ssagujarati", "ssangcieuckorean", "ssanghieuhkorean", + "ssangieungkorean", "ssangkiyeokkorean", "ssangnieunkorean", + "ssangpieupkorean", "ssangsioskorean", "ssangtikeutkorean", + "ssuperior", "sterling", "sterlingmonospace", + "strokelongoverlaycmb", "strokeshortoverlaycmb", "subset", + "subsetnotequal", "subsetorequal", "succeeds", "suchthat", + "suhiragana", "sukatakana", "sukatakanahalfwidth", "sukunarabic", + "summation", "sun", "superset", "supersetnotequal", + "supersetorequal", "svsquare", "syouwaerasquare", "t", "tabengali", + "tackdown", "tackleft", "tadeva", "tagujarati", "tagurmukhi", + "taharabic", "tahfinalarabic", "tahinitialarabic", "tahiragana", + "tahmedialarabic", "taisyouerasquare", "takatakana", + "takatakanahalfwidth", "tatweelarabic", "tau", "tav", "tavdages", + "tavdagesh", "tavdageshhebrew", "tavhebrew", "tbar", "tbopomofo", + "tcaron", "tccurl", "tcedilla", "tcheharabic", "tchehfinalarabic", + "tchehinitialarabic", "tchehmedialarabic", "tcircle", + "tcircumflexbelow", "tcommaaccent", "tdieresis", "tdotaccent", + "tdotbelow", "tecyrillic", "tedescendercyrillic", "teharabic", + "tehfinalarabic", "tehhahinitialarabic", "tehhahisolatedarabic", + "tehinitialarabic", "tehiragana", "tehjeeminitialarabic", + "tehjeemisolatedarabic", "tehmarbutaarabic", + "tehmarbutafinalarabic", "tehmedialarabic", "tehmeeminitialarabic", + "tehmeemisolatedarabic", "tehnoonfinalarabic", "tekatakana", + "tekatakanahalfwidth", "telephone", "telephoneblack", + "telishagedolahebrew", "telishaqetanahebrew", "tencircle", + "tenideographicparen", "tenparen", "tenperiod", "tenroman", "tesh", + "tet", "tetdagesh", "tetdageshhebrew", "tethebrew", + "tetsecyrillic", "tevirhebrew", "tevirlefthebrew", "thabengali", + "thadeva", "thagujarati", "thagurmukhi", "thalarabic", + "thalfinalarabic", "thanthakhatlowleftthai", + "thanthakhatlowrightthai", "thanthakhatthai", + "thanthakhatupperleftthai", "theharabic", "thehfinalarabic", + "thehinitialarabic", "thehmedialarabic", "thereexists", + "therefore", "theta", "theta1", "thetasymbolgreek", + "thieuthacirclekorean", "thieuthaparenkorean", + "thieuthcirclekorean", "thieuthkorean", "thieuthparenkorean", + "thirteencircle", "thirteenparen", "thirteenperiod", + "thonangmonthothai", "thook", "thophuthaothai", "thorn", + "thothahanthai", "thothanthai", "thothongthai", "thothungthai", + "thousandcyrillic", "thousandsseparatorarabic", + "thousandsseparatorpersian", "three", "threearabic", + "threebengali", "threecircle", "threecircleinversesansserif", + "threedeva", "threeeighths", "threegujarati", "threegurmukhi", + "threehackarabic", "threehangzhou", "threeideographicparen", + "threeinferior", "threemonospace", "threenumeratorbengali", + "threeoldstyle", "threeparen", "threeperiod", "threepersian", + "threequarters", "threequartersemdash", "threeroman", + "threesuperior", "threethai", "thzsquare", "tihiragana", + "tikatakana", "tikatakanahalfwidth", "tikeutacirclekorean", + "tikeutaparenkorean", "tikeutcirclekorean", "tikeutkorean", + "tikeutparenkorean", "tilde", "tildebelowcmb", "tildecmb", + "tildecomb", "tildedoublecmb", "tildeoperator", "tildeoverlaycmb", + "tildeverticalcmb", "timescircle", "tipehahebrew", + "tipehalefthebrew", "tippigurmukhi", "titlocyrilliccmb", + "tiwnarmenian", "tlinebelow", "tmonospace", "toarmenian", + "tohiragana", "tokatakana", "tokatakanahalfwidth", + "tonebarextrahighmod", "tonebarextralowmod", "tonebarhighmod", + "tonebarlowmod", "tonebarmidmod", "tonefive", "tonesix", "tonetwo", + "tonos", "tonsquare", "topatakthai", "tortoiseshellbracketleft", + "tortoiseshellbracketleftsmall", + "tortoiseshellbracketleftvertical", "tortoiseshellbracketright", + "tortoiseshellbracketrightsmall", + "tortoiseshellbracketrightvertical", "totaothai", "tpalatalhook", + "tparen", "trademark", "trademarksans", "trademarkserif", + "tretroflexhook", "triagdn", "triaglf", "triagrt", "triagup", "ts", + "tsadi", "tsadidagesh", "tsadidageshhebrew", "tsadihebrew", + "tsecyrillic", "tsere", "tsere12", "tsere1e", "tsere2b", + "tserehebrew", "tserenarrowhebrew", "tserequarterhebrew", + "tserewidehebrew", "tshecyrillic", "tsuperior", "ttabengali", + "ttadeva", "ttagujarati", "ttagurmukhi", "tteharabic", + "ttehfinalarabic", "ttehinitialarabic", "ttehmedialarabic", + "tthabengali", "tthadeva", "tthagujarati", "tthagurmukhi", + "tturned", "tuhiragana", "tukatakana", "tukatakanahalfwidth", + "tusmallhiragana", "tusmallkatakana", "tusmallkatakanahalfwidth", + "twelvecircle", "twelveparen", "twelveperiod", "twelveroman", + "twentycircle", "twentyhangzhou", "twentyparen", "twentyperiod", + "two", "twoarabic", "twobengali", "twocircle", + "twocircleinversesansserif", "twodeva", "twodotenleader", + "twodotleader", "twodotleadervertical", "twogujarati", + "twogurmukhi", "twohackarabic", "twohangzhou", + "twoideographicparen", "twoinferior", "twomonospace", + "twonumeratorbengali", "twooldstyle", "twoparen", "twoperiod", + "twopersian", "tworoman", "twostroke", "twosuperior", "twothai", + "twothirds", "u", "uacute", "ubar", "ubengali", "ubopomofo", + "ubreve", "ucaron", "ucircle", "ucircumflex", "ucircumflexbelow", + "ucyrillic", "udattadeva", "udblacute", "udblgrave", "udeva", + "udieresis", "udieresisacute", "udieresisbelow", "udieresiscaron", + "udieresiscyrillic", "udieresisgrave", "udieresismacron", + "udotbelow", "ugrave", "ugujarati", "ugurmukhi", "uhiragana", + "uhookabove", "uhorn", "uhornacute", "uhorndotbelow", "uhorngrave", + "uhornhookabove", "uhorntilde", "uhungarumlaut", + "uhungarumlautcyrillic", "uinvertedbreve", "ukatakana", + "ukatakanahalfwidth", "ukcyrillic", "ukorean", "umacron", + "umacroncyrillic", "umacrondieresis", "umatragurmukhi", + "umonospace", "underscore", "underscoredbl", "underscoremonospace", + "underscorevertical", "underscorewavy", "union", "universal", + "uogonek", "uparen", "upblock", "upperdothebrew", "upsilon", + "upsilondieresis", "upsilondieresistonos", "upsilonlatin", + "upsilontonos", "uptackbelowcmb", "uptackmod", "uragurmukhi", + "uring", "ushortcyrillic", "usmallhiragana", "usmallkatakana", + "usmallkatakanahalfwidth", "ustraightcyrillic", + "ustraightstrokecyrillic", "utilde", "utildeacute", "utildebelow", + "uubengali", "uudeva", "uugujarati", "uugurmukhi", + "uumatragurmukhi", "uuvowelsignbengali", "uuvowelsigndeva", + "uuvowelsigngujarati", "uvowelsignbengali", "uvowelsigndeva", + "uvowelsigngujarati", "v", "vadeva", "vagujarati", "vagurmukhi", + "vakatakana", "vav", "vavdagesh", "vavdagesh65", "vavdageshhebrew", + "vavhebrew", "vavholam", "vavholamhebrew", "vavvavhebrew", + "vavyodhebrew", "vcircle", "vdotbelow", "vecyrillic", "veharabic", + "vehfinalarabic", "vehinitialarabic", "vehmedialarabic", + "vekatakana", "venus", "verticalbar", "verticallineabovecmb", + "verticallinebelowcmb", "verticallinelowmod", "verticallinemod", + "vewarmenian", "vhook", "vikatakana", "viramabengali", + "viramadeva", "viramagujarati", "visargabengali", "visargadeva", + "visargagujarati", "vmonospace", "voarmenian", + "voicediterationhiragana", "voicediterationkatakana", + "voicedmarkkana", "voicedmarkkanahalfwidth", "vokatakana", + "vparen", "vtilde", "vturned", "vuhiragana", "vukatakana", "w", + "wacute", "waekorean", "wahiragana", "wakatakana", + "wakatakanahalfwidth", "wakorean", "wasmallhiragana", + "wasmallkatakana", "wattosquare", "wavedash", + "wavyunderscorevertical", "wawarabic", "wawfinalarabic", + "wawhamzaabovearabic", "wawhamzaabovefinalarabic", "wbsquare", + "wcircle", "wcircumflex", "wdieresis", "wdotaccent", "wdotbelow", + "wehiragana", "weierstrass", "wekatakana", "wekorean", "weokorean", + "wgrave", "whitebullet", "whitecircle", "whitecircleinverse", + "whitecornerbracketleft", "whitecornerbracketleftvertical", + "whitecornerbracketright", "whitecornerbracketrightvertical", + "whitediamond", "whitediamondcontainingblacksmalldiamond", + "whitedownpointingsmalltriangle", "whitedownpointingtriangle", + "whiteleftpointingsmalltriangle", "whiteleftpointingtriangle", + "whitelenticularbracketleft", "whitelenticularbracketright", + "whiterightpointingsmalltriangle", "whiterightpointingtriangle", + "whitesmallsquare", "whitesmilingface", "whitesquare", "whitestar", + "whitetelephone", "whitetortoiseshellbracketleft", + "whitetortoiseshellbracketright", "whiteuppointingsmalltriangle", + "whiteuppointingtriangle", "wihiragana", "wikatakana", "wikorean", + "wmonospace", "wohiragana", "wokatakana", "wokatakanahalfwidth", + "won", "wonmonospace", "wowaenthai", "wparen", "wring", + "wsuperior", "wturned", "wynn", "x", "xabovecmb", "xbopomofo", + "xcircle", "xdieresis", "xdotaccent", "xeharmenian", "xi", + "xmonospace", "xparen", "xsuperior", "y", "yaadosquare", + "yabengali", "yacute", "yadeva", "yaekorean", "yagujarati", + "yagurmukhi", "yahiragana", "yakatakana", "yakatakanahalfwidth", + "yakorean", "yamakkanthai", "yasmallhiragana", "yasmallkatakana", + "yasmallkatakanahalfwidth", "yatcyrillic", "ycircle", + "ycircumflex", "ydieresis", "ydotaccent", "ydotbelow", "yeharabic", + "yehbarreearabic", "yehbarreefinalarabic", "yehfinalarabic", + "yehhamzaabovearabic", "yehhamzaabovefinalarabic", + "yehhamzaaboveinitialarabic", "yehhamzaabovemedialarabic", + "yehinitialarabic", "yehmedialarabic", "yehmeeminitialarabic", + "yehmeemisolatedarabic", "yehnoonfinalarabic", + "yehthreedotsbelowarabic", "yekorean", "yen", "yenmonospace", + "yeokorean", "yeorinhieuhkorean", "yerahbenyomohebrew", + "yerahbenyomolefthebrew", "yericyrillic", "yerudieresiscyrillic", + "yesieungkorean", "yesieungpansioskorean", "yesieungsioskorean", + "yetivhebrew", "ygrave", "yhook", "yhookabove", "yiarmenian", + "yicyrillic", "yikorean", "yinyang", "yiwnarmenian", "ymonospace", + "yod", "yoddagesh", "yoddageshhebrew", "yodhebrew", "yodyodhebrew", + "yodyodpatahhebrew", "yohiragana", "yoikorean", "yokatakana", + "yokatakanahalfwidth", "yokorean", "yosmallhiragana", + "yosmallkatakana", "yosmallkatakanahalfwidth", "yotgreek", + "yoyaekorean", "yoyakorean", "yoyakthai", "yoyingthai", "yparen", + "ypogegrammeni", "ypogegrammenigreekcmb", "yr", "yring", + "ysuperior", "ytilde", "yturned", "yuhiragana", "yuikorean", + "yukatakana", "yukatakanahalfwidth", "yukorean", "yusbigcyrillic", + "yusbigiotifiedcyrillic", "yuslittlecyrillic", + "yuslittleiotifiedcyrillic", "yusmallhiragana", "yusmallkatakana", + "yusmallkatakanahalfwidth", "yuyekorean", "yuyeokorean", + "yyabengali", "yyadeva", "z", "zaarmenian", "zacute", "zadeva", + "zagurmukhi", "zaharabic", "zahfinalarabic", "zahinitialarabic", + "zahiragana", "zahmedialarabic", "zainarabic", "zainfinalarabic", + "zakatakana", "zaqefgadolhebrew", "zaqefqatanhebrew", + "zarqahebrew", "zayin", "zayindagesh", "zayindageshhebrew", + "zayinhebrew", "zbopomofo", "zcaron", "zcircle", "zcircumflex", + "zcurl", "zdot", "zdotaccent", "zdotbelow", "zecyrillic", + "zedescendercyrillic", "zedieresiscyrillic", "zehiragana", + "zekatakana", "zero", "zeroarabic", "zerobengali", "zerodeva", + "zerogujarati", "zerogurmukhi", "zerohackarabic", "zeroinferior", + "zeromonospace", "zerooldstyle", "zeropersian", "zerosuperior", + "zerothai", "zerowidthjoiner", "zerowidthnonjoiner", + "zerowidthspace", "zeta", "zhbopomofo", "zhearmenian", + "zhebrevecyrillic", "zhecyrillic", "zhedescendercyrillic", + "zhedieresiscyrillic", "zihiragana", "zikatakana", "zinorhebrew", + "zlinebelow", "zmonospace", "zohiragana", "zokatakana", "zparen", + "zretroflexhook", "zstroke", "zuhiragana", "zukatakana", +}; + +/* + +grep '^[^#;][^;]*;[^ ][^ ][^ ][^ ]$' glyphlist.txt | sort -t\; +0 -1 | \ + cut -f2 -d\; | perl -ne 'chomp; print "0x$_, "' | \ + fold -s -w68 | sed 's/^/ /'; echo + + */ +static const unsigned short ps_codes_alphabetic[] = { + 0x0041, 0x00C6, 0x01FC, 0x01E2, 0xF7E6, 0x00C1, 0xF7E1, 0x0102, + 0x1EAE, 0x04D0, 0x1EB6, 0x1EB0, 0x1EB2, 0x1EB4, 0x01CD, 0x24B6, + 0x00C2, 0x1EA4, 0x1EAC, 0x1EA6, 0x1EA8, 0xF7E2, 0x1EAA, 0xF6C9, + 0xF7B4, 0x0410, 0x0200, 0x00C4, 0x04D2, 0x01DE, 0xF7E4, 0x1EA0, + 0x01E0, 0x00C0, 0xF7E0, 0x1EA2, 0x04D4, 0x0202, 0x0391, 0x0386, + 0x0100, 0xFF21, 0x0104, 0x00C5, 0x01FA, 0x1E00, 0xF7E5, 0xF761, + 0x00C3, 0xF7E3, 0x0531, 0x0042, 0x24B7, 0x1E02, 0x1E04, 0x0411, + 0x0532, 0x0392, 0x0181, 0x1E06, 0xFF22, 0xF6F4, 0xF762, 0x0182, + 0x0043, 0x053E, 0x0106, 0xF6CA, 0xF6F5, 0x010C, 0x00C7, 0x1E08, + 0xF7E7, 0x24B8, 0x0108, 0x010A, 0x010A, 0xF7B8, 0x0549, 0x04BC, + 0x0427, 0x04BE, 0x04B6, 0x04F4, 0x0543, 0x04CB, 0x04B8, 0x03A7, + 0x0187, 0xF6F6, 0xFF23, 0x0551, 0xF763, 0x0044, 0x01F1, 0x01C4, + 0x0534, 0x0189, 0x010E, 0x1E10, 0x24B9, 0x1E12, 0x0110, 0x1E0A, + 0x1E0C, 0x0414, 0x03EE, 0x2206, 0x0394, 0x018A, 0xF6CB, 0xF6CC, + 0xF6CD, 0xF7A8, 0x03DC, 0x0402, 0x1E0E, 0xFF24, 0xF6F7, 0x0110, + 0xF764, 0x018B, 0x01F2, 0x01C5, 0x04E0, 0x0405, 0x040F, 0x0045, + 0x00C9, 0xF7E9, 0x0114, 0x011A, 0x1E1C, 0x0535, 0x24BA, 0x00CA, + 0x1EBE, 0x1E18, 0x1EC6, 0x1EC0, 0x1EC2, 0xF7EA, 0x1EC4, 0x0404, + 0x0204, 0x00CB, 0xF7EB, 0x0116, 0x0116, 0x1EB8, 0x0424, 0x00C8, + 0xF7E8, 0x0537, 0x1EBA, 0x2167, 0x0206, 0x0464, 0x041B, 0x216A, + 0x0112, 0x1E16, 0x1E14, 0x041C, 0xFF25, 0x041D, 0x04A2, 0x014A, + 0x04A4, 0x04C7, 0x0118, 0x0190, 0x0395, 0x0388, 0x0420, 0x018E, + 0x042D, 0x0421, 0x04AA, 0x01A9, 0xF765, 0x0397, 0x0538, 0x0389, + 0x00D0, 0xF7F0, 0x1EBC, 0x1E1A, 0x20AC, 0x01B7, 0x01EE, 0x01B8, + 0x0046, 0x24BB, 0x1E1E, 0x0556, 0x03E4, 0x0191, 0x0472, 0x2164, + 0xFF26, 0x2163, 0xF766, 0x0047, 0x3387, 0x01F4, 0x0393, 0x0194, + 0x03EA, 0x011E, 0x01E6, 0x0122, 0x24BC, 0x011C, 0x0122, 0x0120, + 0x0120, 0x0413, 0x0542, 0x0494, 0x0492, 0x0490, 0x0193, 0x0533, + 0x0403, 0x1E20, 0xFF27, 0xF6CE, 0xF760, 0xF767, 0x029B, 0x01E4, + 0x0048, 0x25CF, 0x25AA, 0x25AB, 0x25A1, 0x33CB, 0x04A8, 0x04B2, + 0x042A, 0x0126, 0x1E2A, 0x1E28, 0x24BD, 0x0124, 0x1E26, 0x1E22, + 0x1E24, 0xFF28, 0x0540, 0x03E8, 0xF768, 0xF6CF, 0xF6F8, 0x3390, + 0x0049, 0x042F, 0x0132, 0x042E, 0x00CD, 0xF7ED, 0x012C, 0x01CF, + 0x24BE, 0x00CE, 0xF7EE, 0x0406, 0x0208, 0x00CF, 0x1E2E, 0x04E4, + 0xF7EF, 0x0130, 0x0130, 0x1ECA, 0x04D6, 0x0415, 0x2111, 0x00CC, + 0xF7EC, 0x1EC8, 0x0418, 0x020A, 0x0419, 0x012A, 0x04E2, 0xFF29, + 0x053B, 0x0401, 0x012E, 0x0399, 0x0196, 0x03AA, 0x038A, 0xF769, + 0x0197, 0x0128, 0x1E2C, 0x0474, 0x0476, 0x004A, 0x0541, 0x24BF, + 0x0134, 0x0408, 0x054B, 0xFF2A, 0xF76A, 0x004B, 0x3385, 0x33CD, + 0x04A0, 0x1E30, 0x041A, 0x049A, 0x04C3, 0x039A, 0x049E, 0x049C, + 0x01E8, 0x0136, 0x24C0, 0x0136, 0x1E32, 0x0554, 0x053F, 0x0425, + 0x03E6, 0x0198, 0x040C, 0x1E34, 0xFF2B, 0x0480, 0x03DE, 0x046E, + 0xF76B, 0x004C, 0x01C7, 0xF6BF, 0x0139, 0x039B, 0x013D, 0x013B, + 0x24C1, 0x1E3C, 0x013B, 0x013F, 0x013F, 0x1E36, 0x1E38, 0x053C, + 0x01C8, 0x0409, 0x1E3A, 0xFF2C, 0x0141, 0xF6F9, 0xF76C, 0x004D, + 0x3386, 0xF6D0, 0xF7AF, 0x1E3E, 0x24C2, 0x1E40, 0x1E42, 0x0544, + 0xFF2D, 0xF76D, 0x019C, 0x039C, 0x004E, 0x01CA, 0x0143, 0x0147, + 0x0145, 0x24C3, 0x1E4A, 0x0145, 0x1E44, 0x1E46, 0x019D, 0x2168, + 0x01CB, 0x040A, 0x1E48, 0xFF2E, 0x0546, 0xF76E, 0x00D1, 0xF7F1, + 0x039D, 0x004F, 0x0152, 0xF6FA, 0x00D3, 0xF7F3, 0x04E8, 0x04EA, + 0x014E, 0x01D1, 0x019F, 0x24C4, 0x00D4, 0x1ED0, 0x1ED8, 0x1ED2, + 0x1ED4, 0xF7F4, 0x1ED6, 0x041E, 0x0150, 0x020C, 0x00D6, 0x04E6, + 0xF7F6, 0x1ECC, 0xF6FB, 0x00D2, 0xF7F2, 0x0555, 0x2126, 0x1ECE, + 0x01A0, 0x1EDA, 0x1EE2, 0x1EDC, 0x1EDE, 0x1EE0, 0x0150, 0x01A2, + 0x020E, 0x014C, 0x1E52, 0x1E50, 0x2126, 0x0460, 0x03A9, 0x047A, + 0x047C, 0x038F, 0x039F, 0x038C, 0xFF2F, 0x2160, 0x01EA, 0x01EC, + 0x0186, 0x00D8, 0x01FE, 0xF7F8, 0xF76F, 0x01FE, 0x047E, 0x00D5, + 0x1E4C, 0x1E4E, 0xF7F5, 0x0050, 0x1E54, 0x24C5, 0x1E56, 0x041F, + 0x054A, 0x04A6, 0x03A6, 0x01A4, 0x03A0, 0x0553, 0xFF30, 0x03A8, + 0x0470, 0xF770, 0x0051, 0x24C6, 0xFF31, 0xF771, 0x0052, 0x054C, + 0x0154, 0x0158, 0x0156, 0x24C7, 0x0156, 0x0210, 0x1E58, 0x1E5A, + 0x1E5C, 0x0550, 0x211C, 0x03A1, 0xF6FC, 0x0212, 0x1E5E, 0xFF32, + 0xF772, 0x0281, 0x02B6, 0x0053, 0x250C, 0x2514, 0x2510, 0x2518, + 0x253C, 0x252C, 0x2534, 0x251C, 0x2524, 0x2500, 0x2502, 0x2561, + 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, + 0x255B, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, + 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, + 0x2552, 0x2553, 0x256B, 0x256A, 0x015A, 0x1E64, 0x03E0, 0x0160, + 0x1E66, 0xF6FD, 0x015E, 0x018F, 0x04D8, 0x04DA, 0x24C8, 0x015C, + 0x0218, 0x1E60, 0x1E62, 0x1E68, 0x054D, 0x2166, 0x0547, 0x0428, + 0x0429, 0x03E2, 0x04BA, 0x03EC, 0x03A3, 0x2165, 0xFF33, 0x042C, + 0xF773, 0x03DA, 0x0054, 0x03A4, 0x0166, 0x0164, 0x0162, 0x24C9, + 0x1E70, 0x0162, 0x1E6A, 0x1E6C, 0x0422, 0x04AC, 0x2169, 0x04B4, + 0x0398, 0x01AC, 0x00DE, 0xF7FE, 0x2162, 0xF6FE, 0x054F, 0x1E6E, + 0xFF34, 0x0539, 0x01BC, 0x0184, 0x01A7, 0x01AE, 0x0426, 0x040B, + 0xF774, 0x216B, 0x2161, 0x0055, 0x00DA, 0xF7FA, 0x016C, 0x01D3, + 0x24CA, 0x00DB, 0x1E76, 0xF7FB, 0x0423, 0x0170, 0x0214, 0x00DC, + 0x01D7, 0x1E72, 0x01D9, 0x04F0, 0x01DB, 0x01D5, 0xF7FC, 0x1EE4, + 0x00D9, 0xF7F9, 0x1EE6, 0x01AF, 0x1EE8, 0x1EF0, 0x1EEA, 0x1EEC, + 0x1EEE, 0x0170, 0x04F2, 0x0216, 0x0478, 0x016A, 0x04EE, 0x1E7A, + 0xFF35, 0x0172, 0x03A5, 0x03D2, 0x03D3, 0x01B1, 0x03AB, 0x03D4, + 0x03D2, 0x038E, 0x016E, 0x040E, 0xF775, 0x04AE, 0x04B0, 0x0168, + 0x1E78, 0x1E74, 0x0056, 0x24CB, 0x1E7E, 0x0412, 0x054E, 0x01B2, + 0xFF36, 0x0548, 0xF776, 0x1E7C, 0x0057, 0x1E82, 0x24CC, 0x0174, + 0x1E84, 0x1E86, 0x1E88, 0x1E80, 0xFF37, 0xF777, 0x0058, 0x24CD, + 0x1E8C, 0x1E8A, 0x053D, 0x039E, 0xFF38, 0xF778, 0x0059, 0x00DD, + 0xF7FD, 0x0462, 0x24CE, 0x0176, 0x0178, 0xF7FF, 0x1E8E, 0x1EF4, + 0x042B, 0x04F8, 0x1EF2, 0x01B3, 0x1EF6, 0x0545, 0x0407, 0x0552, + 0xFF39, 0xF779, 0x1EF8, 0x046A, 0x046C, 0x0466, 0x0468, 0x005A, + 0x0536, 0x0179, 0x017D, 0xF6FF, 0x24CF, 0x1E90, 0x017B, 0x017B, + 0x1E92, 0x0417, 0x0498, 0x04DE, 0x0396, 0x053A, 0x04C1, 0x0416, + 0x0496, 0x04DC, 0x1E94, 0xFF3A, 0xF77A, 0x01B5, 0x0061, 0x0986, + 0x00E1, 0x0906, 0x0A86, 0x0A06, 0x0A3E, 0x3303, 0x09BE, 0x093E, + 0x0ABE, 0x055F, 0x0970, 0x0985, 0x311A, 0x0103, 0x1EAF, 0x04D1, + 0x1EB7, 0x1EB1, 0x1EB3, 0x1EB5, 0x01CE, 0x24D0, 0x00E2, 0x1EA5, + 0x1EAD, 0x1EA7, 0x1EA9, 0x1EAB, 0x00B4, 0x0317, 0x0301, 0x0301, + 0x0954, 0x02CF, 0x0341, 0x0430, 0x0201, 0x0A71, 0x0905, 0x00E4, + 0x04D3, 0x01DF, 0x1EA1, 0x01E1, 0x00E6, 0x01FD, 0x3150, 0x01E3, + 0x2015, 0x20A4, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, + 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, + 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, + 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, + 0x042D, 0x042E, 0x042F, 0x0490, 0x0402, 0x0403, 0x0404, 0x0405, + 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x040E, + 0xF6C4, 0xF6C5, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, + 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, + 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, + 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, + 0x044D, 0x044E, 0x044F, 0x0491, 0x0452, 0x0453, 0x0454, 0x0455, + 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045E, + 0x040F, 0x0462, 0x0472, 0x0474, 0xF6C6, 0x045F, 0x0463, 0x0473, + 0x0475, 0xF6C7, 0xF6C8, 0x04D9, 0x200E, 0x200F, 0x200D, 0x066A, + 0x060C, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, + 0x0667, 0x0668, 0x0669, 0x061B, 0x061F, 0x0621, 0x0622, 0x0623, + 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, + 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, + 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, + 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0648, 0x0649, + 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, + 0x0652, 0x0647, 0x06A4, 0x067E, 0x0686, 0x0698, 0x06AF, 0x0679, + 0x0688, 0x0691, 0x06BA, 0x06D2, 0x06D5, 0x20AA, 0x05BE, 0x05C3, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFB2A, 0xFB2B, 0xFB4B, 0xFB1F, 0x05F0, + 0x05F1, 0x05F2, 0xFB35, 0x05B4, 0x05B5, 0x05B6, 0x05BB, 0x05B8, + 0x05B7, 0x05B0, 0x05B2, 0x05B1, 0x05B3, 0x05C2, 0x05C1, 0x05B9, + 0x05BC, 0x05BD, 0x05BF, 0x05C0, 0x02BC, 0x2105, 0x2113, 0x2116, + 0x202C, 0x202D, 0x202E, 0x200C, 0x066D, 0x02BD, 0x00E0, 0x0A85, + 0x0A05, 0x3042, 0x1EA3, 0x0990, 0x311E, 0x0910, 0x04D5, 0x0A90, + 0x0A10, 0x0A48, 0x0639, 0xFECA, 0xFECB, 0xFECC, 0x0203, 0x09C8, + 0x0948, 0x0AC8, 0x30A2, 0xFF71, 0x314F, 0x05D0, 0x0627, 0xFB30, + 0xFE8E, 0x0623, 0xFE84, 0x0625, 0xFE88, 0x05D0, 0xFB4F, 0x0622, + 0xFE82, 0x0649, 0xFEF0, 0xFEF3, 0xFEF4, 0xFB2E, 0xFB2F, 0x2135, + 0x224C, 0x03B1, 0x03AC, 0x0101, 0xFF41, 0x0026, 0xFF06, 0xF726, + 0x33C2, 0x3122, 0x3124, 0x0E5A, 0x2220, 0x3008, 0xFE3F, 0x3009, + 0xFE40, 0x2329, 0x232A, 0x212B, 0x0387, 0x0952, 0x0982, 0x0902, + 0x0A82, 0x0105, 0x3300, 0x249C, 0x055A, 0x02BC, 0xF8FF, 0x2250, + 0x2248, 0x2252, 0x2245, 0x318E, 0x318D, 0x2312, 0x1E9A, 0x00E5, + 0x01FB, 0x1E01, 0x2194, 0x21E3, 0x21E0, 0x21E2, 0x21E1, 0x21D4, + 0x21D3, 0x21D0, 0x21D2, 0x21D1, 0x2193, 0x2199, 0x2198, 0x21E9, + 0x02C5, 0x02C2, 0x02C3, 0x02C4, 0xF8E7, 0x2190, 0x21D0, 0x21CD, + 0x21C6, 0x21E6, 0x2192, 0x21CF, 0x279E, 0x21C4, 0x21E8, 0x21E4, + 0x21E5, 0x2191, 0x2195, 0x21A8, 0x21A8, 0x2196, 0x21C5, 0x2197, + 0x21E7, 0xF8E6, 0x005E, 0xFF3E, 0x007E, 0xFF5E, 0x0251, 0x0252, + 0x3041, 0x30A1, 0xFF67, 0x002A, 0x066D, 0x066D, 0x2217, 0xFF0A, + 0xFE61, 0x2042, 0xF6E9, 0x2243, 0x0040, 0x00E3, 0xFF20, 0xFE6B, + 0x0250, 0x0994, 0x3120, 0x0914, 0x0A94, 0x0A14, 0x09D7, 0x0A4C, + 0x09CC, 0x094C, 0x0ACC, 0x093D, 0x0561, 0x05E2, 0xFB20, 0x05E2, + 0x0062, 0x09AC, 0x005C, 0xFF3C, 0x092C, 0x0AAC, 0x0A2C, 0x3070, + 0x0E3F, 0x30D0, 0x007C, 0xFF5C, 0x3105, 0x24D1, 0x1E03, 0x1E05, + 0x266C, 0x2235, 0x0431, 0x0628, 0xFE90, 0xFE91, 0x3079, 0xFE92, + 0xFC9F, 0xFC08, 0xFC6D, 0x30D9, 0x0562, 0x05D1, 0x03B2, 0x03D0, + 0xFB31, 0xFB31, 0x05D1, 0xFB4C, 0x09AD, 0x092D, 0x0AAD, 0x0A2D, + 0x0253, 0x3073, 0x30D3, 0x0298, 0x0A02, 0x3331, 0x25CF, 0x25C6, + 0x25BC, 0x25C4, 0x25C0, 0x3010, 0xFE3B, 0x3011, 0xFE3C, 0x25E3, + 0x25E2, 0x25AC, 0x25BA, 0x25B6, 0x25AA, 0x263B, 0x25A0, 0x2605, + 0x25E4, 0x25E5, 0x25B4, 0x25B2, 0x2423, 0x1E07, 0x2588, 0xFF42, + 0x0E1A, 0x307C, 0x30DC, 0x249D, 0x33C3, 0xF8F4, 0x007B, 0xF8F3, + 0xF8F2, 0xFF5B, 0xFE5B, 0xF8F1, 0xFE37, 0x007D, 0xF8FE, 0xF8FD, + 0xFF5D, 0xFE5C, 0xF8FC, 0xFE38, 0x005B, 0xF8F0, 0xF8EF, 0xFF3B, + 0xF8EE, 0x005D, 0xF8FB, 0xF8FA, 0xFF3D, 0xF8F9, 0x02D8, 0x032E, + 0x0306, 0x032F, 0x0311, 0x0361, 0x032A, 0x033A, 0x00A6, 0x0180, + 0xF6EA, 0x0183, 0x3076, 0x30D6, 0x2022, 0x25D8, 0x2219, 0x25CE, + 0x0063, 0x056E, 0x099A, 0x0107, 0x091A, 0x0A9A, 0x0A1A, 0x3388, + 0x0981, 0x0310, 0x0901, 0x0A81, 0x21EA, 0x2105, 0x02C7, 0x032C, + 0x030C, 0x21B5, 0x3118, 0x010D, 0x00E7, 0x1E09, 0x24D2, 0x0109, + 0x0255, 0x010B, 0x010B, 0x33C5, 0x00B8, 0x0327, 0x00A2, 0x2103, + 0xF6DF, 0xFFE0, 0xF7A2, 0xF6E0, 0x0579, 0x099B, 0x091B, 0x0A9B, + 0x0A1B, 0x3114, 0x04BD, 0x2713, 0x0447, 0x04BF, 0x04B7, 0x04F5, + 0x0573, 0x04CC, 0x04B9, 0x03C7, 0x3277, 0x3217, 0x3269, 0x314A, + 0x3209, 0x0E0A, 0x0E08, 0x0E09, 0x0E0C, 0x0188, 0x3276, 0x3216, + 0x3268, 0x3148, 0x3208, 0x321C, 0x25CB, 0x2297, 0x2299, 0x2295, + 0x3036, 0x25D0, 0x25D1, 0x02C6, 0x032D, 0x0302, 0x2327, 0x01C2, + 0x01C0, 0x01C1, 0x01C3, 0x2663, 0x2663, 0x2667, 0x33A4, 0xFF43, + 0x33A0, 0x0581, 0x003A, 0x20A1, 0xFF1A, 0x20A1, 0xFE55, 0x02D1, + 0x02D0, 0x002C, 0x0313, 0x0315, 0xF6C3, 0x060C, 0x055D, 0xF6E1, + 0xFF0C, 0x0314, 0x02BD, 0xFE50, 0xF6E2, 0x0312, 0x02BB, 0x263C, + 0x2245, 0x222E, 0x2303, 0x0006, 0x0007, 0x0008, 0x0018, 0x000D, + 0x0011, 0x0012, 0x0013, 0x0014, 0x007F, 0x0010, 0x0019, 0x0005, + 0x0004, 0x001B, 0x0017, 0x0003, 0x000C, 0x001C, 0x001D, 0x0009, + 0x000A, 0x0015, 0x001E, 0x000F, 0x000E, 0x0002, 0x0001, 0x001A, + 0x0016, 0x001F, 0x000B, 0x00A9, 0xF8E9, 0xF6D9, 0x300C, 0xFF62, + 0xFE41, 0x300D, 0xFF63, 0xFE42, 0x337F, 0x33C7, 0x33C6, 0x249E, + 0x20A2, 0x0297, 0x22CF, 0x22CE, 0x00A4, 0xF6D1, 0xF6D2, 0xF6D4, + 0xF6D5, 0x0064, 0x0564, 0x09A6, 0x0636, 0x0926, 0xFEBE, 0xFEBF, + 0xFEC0, 0x05BC, 0x05BC, 0x2020, 0x2021, 0x0AA6, 0x0A26, 0x3060, + 0x30C0, 0x062F, 0x05D3, 0xFB33, 0xFB33, 0x05D3, 0xFEAA, 0x064F, + 0x064F, 0x064C, 0x064C, 0x0964, 0x05A7, 0x05A7, 0x0485, 0xF6D3, + 0x300A, 0xFE3D, 0x300B, 0xFE3E, 0x032B, 0x21D4, 0x21D2, 0x0965, + 0xF6D6, 0x030F, 0x222C, 0x2017, 0x0333, 0x033F, 0x02BA, 0x2016, + 0x030E, 0x3109, 0x33C8, 0x010F, 0x1E11, 0x24D3, 0x1E13, 0x0111, + 0x09A1, 0x0921, 0x0AA1, 0x0A21, 0x0688, 0xFB89, 0x095C, 0x09A2, + 0x0922, 0x0AA2, 0x0A22, 0x1E0B, 0x1E0D, 0x066B, 0x066B, 0x0434, + 0x00B0, 0x05AD, 0x3067, 0x03EF, 0x30C7, 0x232B, 0x2326, 0x03B4, + 0x018D, 0x09F8, 0x02A4, 0x09A7, 0x0927, 0x0AA7, 0x0A27, 0x0257, + 0x0385, 0x0344, 0x2666, 0x2662, 0x00A8, 0xF6D7, 0x0324, 0x0308, + 0xF6D8, 0x0385, 0x3062, 0x30C2, 0x3003, 0x00F7, 0x2223, 0x2215, + 0x0452, 0x2593, 0x1E0F, 0x3397, 0x0111, 0xFF44, 0x2584, 0x0E0E, + 0x0E14, 0x3069, 0x30C9, 0x0024, 0xF6E3, 0xFF04, 0xF724, 0xFE69, + 0xF6E4, 0x20AB, 0x3326, 0x02D9, 0x0307, 0x0323, 0x0323, 0x30FB, + 0x0131, 0xF6BE, 0x0284, 0x22C5, 0x25CC, 0xFB1F, 0xFB1F, 0x031E, + 0x02D5, 0x249F, 0xF6EB, 0x0256, 0x018C, 0x3065, 0x30C5, 0x01F3, + 0x02A3, 0x01C6, 0x02A5, 0x04E1, 0x0455, 0x045F, 0x0065, 0x00E9, + 0x2641, 0x098F, 0x311C, 0x0115, 0x090D, 0x0A8D, 0x0945, 0x0AC5, + 0x011B, 0x1E1D, 0x0565, 0x0587, 0x24D4, 0x00EA, 0x1EBF, 0x1E19, + 0x1EC7, 0x1EC1, 0x1EC3, 0x1EC5, 0x0454, 0x0205, 0x090F, 0x00EB, + 0x0117, 0x0117, 0x1EB9, 0x0A0F, 0x0A47, 0x0444, 0x00E8, 0x0A8F, + 0x0567, 0x311D, 0x3048, 0x1EBB, 0x311F, 0x0038, 0x0668, 0x09EE, + 0x2467, 0x2791, 0x096E, 0x2471, 0x2485, 0x2499, 0x0AEE, 0x0A6E, + 0x0668, 0x3028, 0x266B, 0x3227, 0x2088, 0xFF18, 0xF738, 0x247B, + 0x248F, 0x06F8, 0x2177, 0x2078, 0x0E58, 0x0207, 0x0465, 0x30A8, + 0xFF74, 0x0A74, 0x3154, 0x043B, 0x2208, 0x246A, 0x247E, 0x2492, + 0x217A, 0x2026, 0x22EE, 0x0113, 0x1E17, 0x1E15, 0x043C, 0x2014, + 0xFE31, 0xFF45, 0x055B, 0x2205, 0x3123, 0x043D, 0x2013, 0xFE32, + 0x04A3, 0x014B, 0x3125, 0x04A5, 0x04C8, 0x2002, 0x0119, 0x3153, + 0x025B, 0x029A, 0x025C, 0x025E, 0x025D, 0x24A0, 0x03B5, 0x03AD, + 0x003D, 0xFF1D, 0xFE66, 0x207C, 0x2261, 0x3126, 0x0440, 0x0258, + 0x044D, 0x0441, 0x04AB, 0x0283, 0x0286, 0x090E, 0x0946, 0x01AA, + 0x0285, 0x3047, 0x30A7, 0xFF6A, 0x212E, 0xF6EC, 0x03B7, 0x0568, + 0x03AE, 0x00F0, 0x1EBD, 0x1E1B, 0x0591, 0x0591, 0x0591, 0x0591, + 0x01DD, 0x3161, 0x20AC, 0x09C7, 0x0947, 0x0AC7, 0x0021, 0x055C, + 0x203C, 0x00A1, 0xF7A1, 0xFF01, 0xF721, 0x2203, 0x0292, 0x01EF, + 0x0293, 0x01B9, 0x01BA, 0x0066, 0x095E, 0x0A5E, 0x2109, 0x064E, + 0x064E, 0x064B, 0x3108, 0x24D5, 0x1E1F, 0x0641, 0x0586, 0xFED2, + 0xFED3, 0xFED4, 0x03E5, 0x2640, 0xFB00, 0xFB03, 0xFB04, 0xFB01, + 0x246E, 0x2482, 0x2496, 0x2012, 0x25A0, 0x25AC, 0x05DA, 0xFB3A, + 0xFB3A, 0x05DA, 0x05DD, 0x05DD, 0x05DF, 0x05DF, 0x05E3, 0x05E3, + 0x05E5, 0x05E5, 0x02C9, 0x25C9, 0x0473, 0x0035, 0x0665, 0x09EB, + 0x2464, 0x278E, 0x096B, 0x215D, 0x0AEB, 0x0A6B, 0x0665, 0x3025, + 0x3224, 0x2085, 0xFF15, 0xF735, 0x2478, 0x248C, 0x06F5, 0x2174, + 0x2075, 0x0E55, 0xFB02, 0x0192, 0xFF46, 0x3399, 0x0E1F, 0x0E1D, + 0x0E4F, 0x2200, 0x0034, 0x0664, 0x09EA, 0x2463, 0x278D, 0x096A, + 0x0AEA, 0x0A6A, 0x0664, 0x3024, 0x3223, 0x2084, 0xFF14, 0x09F7, + 0xF734, 0x2477, 0x248B, 0x06F4, 0x2173, 0x2074, 0x246D, 0x2481, + 0x2495, 0x0E54, 0x02CB, 0x24A1, 0x2044, 0x20A3, 0x0067, 0x0997, + 0x01F5, 0x0917, 0x06AF, 0xFB93, 0xFB94, 0xFB95, 0x0A97, 0x0A17, + 0x304C, 0x30AC, 0x03B3, 0x0263, 0x02E0, 0x03EB, 0x310D, 0x011F, + 0x01E7, 0x0123, 0x24D6, 0x011D, 0x0123, 0x0121, 0x0121, 0x0433, + 0x3052, 0x30B2, 0x2251, 0x059C, 0x05F3, 0x059D, 0x00DF, 0x059E, + 0x05F4, 0x3013, 0x0998, 0x0572, 0x0918, 0x0A98, 0x0A18, 0x063A, + 0xFECE, 0xFECF, 0xFED0, 0x0495, 0x0493, 0x0491, 0x095A, 0x0A5A, + 0x0260, 0x3393, 0x304E, 0x30AE, 0x0563, 0x05D2, 0xFB32, 0xFB32, + 0x05D2, 0x0453, 0x01BE, 0x0294, 0x0296, 0x02C0, 0x0295, 0x02C1, + 0x02E4, 0x02A1, 0x02A2, 0x1E21, 0xFF47, 0x3054, 0x30B4, 0x24A2, + 0x33AC, 0x2207, 0x0060, 0x0316, 0x0300, 0x0300, 0x0953, 0x02CE, + 0xFF40, 0x0340, 0x003E, 0x2265, 0x22DB, 0xFF1E, 0x2273, 0x2277, + 0x2267, 0xFE65, 0x0261, 0x01E5, 0x3050, 0x00AB, 0x00BB, 0x2039, + 0x203A, 0x30B0, 0x3318, 0x33C9, 0x0068, 0x04A9, 0x06C1, 0x09B9, + 0x04B3, 0x0939, 0x0AB9, 0x0A39, 0x062D, 0xFEA2, 0xFEA3, 0x306F, + 0xFEA4, 0x332A, 0x30CF, 0xFF8A, 0x0A4D, 0x0621, 0x0621, 0x3164, + 0x044A, 0x21BC, 0x21C0, 0x33CA, 0x05B2, 0x05B2, 0x05B2, 0x05B2, + 0x05B2, 0x05B2, 0x05B2, 0x05B2, 0x05B3, 0x05B3, 0x05B3, 0x05B3, + 0x05B3, 0x05B3, 0x05B3, 0x05B3, 0x05B1, 0x05B1, 0x05B1, 0x05B1, + 0x05B1, 0x05B1, 0x05B1, 0x05B1, 0x0127, 0x310F, 0x1E2B, 0x1E29, + 0x24D7, 0x0125, 0x1E27, 0x1E23, 0x1E25, 0x05D4, 0x2665, 0x2665, + 0x2661, 0xFB34, 0xFB34, 0x06C1, 0x0647, 0x05D4, 0xFBA7, 0xFEEA, + 0xFEEA, 0xFBA5, 0xFBA4, 0xFBA8, 0xFEEB, 0x3078, 0xFBA9, 0xFEEC, + 0x337B, 0x30D8, 0xFF8D, 0x3336, 0x0267, 0x3339, 0x05D7, 0x05D7, + 0x0266, 0x02B1, 0x327B, 0x321B, 0x326D, 0x314E, 0x320D, 0x3072, + 0x30D2, 0xFF8B, 0x05B4, 0x05B4, 0x05B4, 0x05B4, 0x05B4, 0x05B4, + 0x05B4, 0x05B4, 0x1E96, 0xFF48, 0x0570, 0x0E2B, 0x307B, 0x30DB, + 0xFF8E, 0x05B9, 0x05B9, 0x05B9, 0x05B9, 0x05B9, 0x05B9, 0x05B9, + 0x05B9, 0x0E2E, 0x0309, 0x0309, 0x0321, 0x0322, 0x3342, 0x03E9, + 0x2015, 0x031B, 0x2668, 0x2302, 0x24A3, 0x02B0, 0x0265, 0x3075, + 0x3333, 0x30D5, 0xFF8C, 0x02DD, 0x030B, 0x0195, 0x002D, 0xF6E5, + 0xFF0D, 0xFE63, 0xF6E6, 0x2010, 0x0069, 0x00ED, 0x044F, 0x0987, + 0x3127, 0x012D, 0x01D0, 0x24D8, 0x00EE, 0x0456, 0x0209, 0x328F, + 0x328B, 0x323F, 0x323A, 0x32A5, 0x3006, 0x3001, 0xFF64, 0x3237, + 0x32A3, 0x322F, 0x323D, 0x329D, 0x3240, 0x3296, 0x3236, 0x322B, + 0x3232, 0x32A4, 0x3005, 0x3298, 0x3238, 0x32A7, 0x32A6, 0x32A9, + 0x322E, 0x322A, 0x3234, 0x3002, 0x329E, 0x3243, 0x3239, 0x323E, + 0x32A8, 0x3299, 0x3242, 0x3233, 0x3000, 0x3235, 0x3231, 0x323B, + 0x3230, 0x323C, 0x322C, 0x322D, 0x3007, 0x328E, 0x328A, 0x3294, + 0x3290, 0x328C, 0x328D, 0x0907, 0x00EF, 0x1E2F, 0x04E5, 0x1ECB, + 0x04D7, 0x0435, 0x3275, 0x3215, 0x3267, 0x3147, 0x3207, 0x00EC, + 0x0A87, 0x0A07, 0x3044, 0x1EC9, 0x0988, 0x0438, 0x0908, 0x0A88, + 0x0A08, 0x0A40, 0x020B, 0x0439, 0x09C0, 0x0940, 0x0AC0, 0x0133, + 0x30A4, 0xFF72, 0x3163, 0x02DC, 0x05AC, 0x012B, 0x04E3, 0x2253, + 0x0A3F, 0xFF49, 0x2206, 0x221E, 0x056B, 0x222B, 0x2321, 0x2321, + 0xF8F5, 0x2320, 0x2320, 0x2229, 0x3305, 0x25D8, 0x25D9, 0x263B, + 0x0451, 0x012F, 0x03B9, 0x03CA, 0x0390, 0x0269, 0x03AF, 0x24A4, + 0x0A72, 0x3043, 0x30A3, 0xFF68, 0x09FA, 0x0268, 0xF6ED, 0x309D, + 0x30FD, 0x0129, 0x1E2D, 0x3129, 0x044E, 0x09BF, 0x093F, 0x0ABF, + 0x0475, 0x0477, 0x006A, 0x0571, 0x099C, 0x091C, 0x0A9C, 0x0A1C, + 0x3110, 0x01F0, 0x24D9, 0x0135, 0x029D, 0x025F, 0x0458, 0x062C, + 0xFE9E, 0xFE9F, 0xFEA0, 0x0698, 0xFB8B, 0x099D, 0x091D, 0x0A9D, + 0x0A1D, 0x057B, 0x3004, 0xFF4A, 0x24A5, 0x02B2, 0x006B, 0x04A1, + 0x0995, 0x1E31, 0x043A, 0x049B, 0x0915, 0x05DB, 0x0643, 0xFB3B, + 0xFB3B, 0xFEDA, 0x05DB, 0xFEDB, 0xFEDC, 0xFB4D, 0x0A95, 0x0A15, + 0x304B, 0x04C4, 0x30AB, 0xFF76, 0x03BA, 0x03F0, 0x3171, 0x3184, + 0x3178, 0x3179, 0x330D, 0x0640, 0x0640, 0x30F5, 0x3384, 0x0650, + 0x064D, 0x049F, 0xFF70, 0x049D, 0x310E, 0x3389, 0x01E9, 0x0137, + 0x24DA, 0x0137, 0x1E33, 0x0584, 0x3051, 0x30B1, 0xFF79, 0x056F, + 0x30F6, 0x0138, 0x0996, 0x0445, 0x0916, 0x0A96, 0x0A16, 0x062E, + 0xFEA6, 0xFEA7, 0xFEA8, 0x03E7, 0x0959, 0x0A59, 0x3278, 0x3218, + 0x326A, 0x314B, 0x320A, 0x0E02, 0x0E05, 0x0E03, 0x0E04, 0x0E5B, + 0x0199, 0x0E06, 0x3391, 0x304D, 0x30AD, 0xFF77, 0x3315, 0x3316, + 0x3314, 0x326E, 0x320E, 0x3260, 0x3131, 0x3200, 0x3133, 0x045C, + 0x1E35, 0x3398, 0x33A6, 0xFF4B, 0x33A2, 0x3053, 0x33C0, 0x0E01, + 0x30B3, 0xFF7A, 0x331E, 0x0481, 0x327F, 0x0343, 0x24A6, 0x33AA, + 0x046F, 0x33CF, 0x029E, 0x304F, 0x30AF, 0xFF78, 0x33B8, 0x33BE, + 0x006C, 0x09B2, 0x013A, 0x0932, 0x0AB2, 0x0A32, 0x0E45, 0xFEFC, + 0xFEF8, 0xFEF7, 0xFEFA, 0xFEF9, 0xFEFB, 0xFEF6, 0xFEF5, 0x0644, + 0x03BB, 0x019B, 0x05DC, 0xFB3C, 0xFB3C, 0x05DC, 0xFEDE, 0xFCCA, + 0xFEDF, 0xFCC9, 0xFCCB, 0xFDF2, 0xFEE0, 0xFD88, 0xFCCC, 0x25EF, + 0x019A, 0x026C, 0x310C, 0x013E, 0x013C, 0x24DB, 0x1E3D, 0x013C, + 0x0140, 0x0140, 0x1E37, 0x1E39, 0x031A, 0x0318, 0x003C, 0x2264, + 0x22DA, 0xFF1C, 0x2272, 0x2276, 0x2266, 0xFE64, 0x026E, 0x258C, + 0x026D, 0x20A4, 0x056C, 0x01C9, 0x0459, 0xF6C0, 0x0933, 0x0AB3, + 0x1E3B, 0x0934, 0x09E1, 0x0961, 0x09E3, 0x0963, 0x026B, 0xFF4C, + 0x33D0, 0x0E2C, 0x2227, 0x00AC, 0x2310, 0x2228, 0x0E25, 0x017F, + 0xFE4E, 0x0332, 0xFE4D, 0x25CA, 0x24A7, 0x0142, 0x2113, 0xF6EE, + 0x2591, 0x0E26, 0x098C, 0x090C, 0x09E2, 0x0962, 0x33D3, 0x006D, + 0x09AE, 0x00AF, 0x0331, 0x0304, 0x02CD, 0xFFE3, 0x1E3F, 0x092E, + 0x0AAE, 0x0A2E, 0x05A4, 0x05A4, 0x307E, 0xF895, 0xF894, 0x0E4B, + 0xF893, 0xF88C, 0xF88B, 0x0E48, 0xF88A, 0xF884, 0x0E31, 0xF889, + 0x0E47, 0xF88F, 0xF88E, 0x0E49, 0xF88D, 0xF892, 0xF891, 0x0E4A, + 0xF890, 0x0E46, 0x30DE, 0xFF8F, 0x2642, 0x3347, 0x05BE, 0x2642, + 0x05AF, 0x3383, 0x3107, 0x33D4, 0x24DC, 0x33A5, 0x1E41, 0x1E43, + 0x0645, 0xFEE2, 0xFEE3, 0xFEE4, 0xFCD1, 0xFC48, 0x334D, 0x3081, + 0x337E, 0x30E1, 0xFF92, 0x05DE, 0xFB3E, 0xFB3E, 0x05DE, 0x0574, + 0x05A5, 0x05A6, 0x05A6, 0x05A5, 0x0271, 0x3392, 0xFF65, 0x00B7, + 0x3272, 0x3212, 0x3264, 0x3141, 0x3170, 0x3204, 0x316E, 0x316F, + 0x307F, 0x30DF, 0xFF90, 0x2212, 0x0320, 0x2296, 0x02D7, 0x2213, + 0x2032, 0x334A, 0x3349, 0x0270, 0x3396, 0x33A3, 0xFF4D, 0x339F, + 0x3082, 0x33C1, 0x30E2, 0xFF93, 0x33D6, 0x0E21, 0x33A7, 0x33A8, + 0x24A8, 0x33AB, 0x33B3, 0xF6EF, 0x026F, 0x00B5, 0x00B5, 0x3382, + 0x226B, 0x226A, 0x338C, 0x03BC, 0x338D, 0x3080, 0x30E0, 0xFF91, + 0x3395, 0x00D7, 0x339B, 0x05A3, 0x05A3, 0x266A, 0x266B, 0x266D, + 0x266F, 0x33B2, 0x33B6, 0x33BC, 0x33B9, 0x33B7, 0x33BF, 0x33BD, + 0x006E, 0x09A8, 0x2207, 0x0144, 0x0928, 0x0AA8, 0x0A28, 0x306A, + 0x30CA, 0xFF85, 0x0149, 0x3381, 0x310B, 0x00A0, 0x0148, 0x0146, + 0x24DD, 0x1E4B, 0x0146, 0x1E45, 0x1E47, 0x306D, 0x30CD, 0xFF88, + 0x20AA, 0x338B, 0x0999, 0x0919, 0x0A99, 0x0A19, 0x0E07, 0x3093, + 0x0272, 0x0273, 0x326F, 0x320F, 0x3135, 0x3261, 0x3136, 0x3134, + 0x3168, 0x3201, 0x3167, 0x3166, 0x306B, 0x30CB, 0xFF86, 0xF899, + 0x0E4D, 0x0039, 0x0669, 0x09EF, 0x2468, 0x2792, 0x096F, 0x0AEF, + 0x0A6F, 0x0669, 0x3029, 0x3228, 0x2089, 0xFF19, 0xF739, 0x247C, + 0x2490, 0x06F9, 0x2178, 0x2079, 0x2472, 0x2486, 0x249A, 0x0E59, + 0x01CC, 0x045A, 0x30F3, 0xFF9D, 0x019E, 0x1E49, 0xFF4E, 0x339A, + 0x09A3, 0x0923, 0x0AA3, 0x0A23, 0x0929, 0x306E, 0x30CE, 0xFF89, + 0x00A0, 0x0E13, 0x0E19, 0x0646, 0xFEE6, 0x06BA, 0xFB9F, 0xFEE7, + 0xFCD2, 0xFC4B, 0xFEE8, 0xFCD5, 0xFC4E, 0xFC8D, 0x220C, 0x2209, + 0x2209, 0x2260, 0x226F, 0x2271, 0x2279, 0x2262, 0x226E, 0x2270, + 0x2226, 0x2280, 0x2284, 0x2281, 0x2285, 0x0576, 0x24A9, 0x33B1, + 0x207F, 0x00F1, 0x03BD, 0x306C, 0x30CC, 0xFF87, 0x09BC, 0x093C, + 0x0ABC, 0x0A3C, 0x0023, 0xFF03, 0xFE5F, 0x0374, 0x0375, 0x2116, + 0x05E0, 0xFB40, 0xFB40, 0x05E0, 0x33B5, 0x33BB, 0x099E, 0x091E, + 0x0A9E, 0x0A1E, 0x006F, 0x00F3, 0x0E2D, 0x0275, 0x04E9, 0x04EB, + 0x0993, 0x311B, 0x014F, 0x0911, 0x0A91, 0x0949, 0x0AC9, 0x01D2, + 0x24DE, 0x00F4, 0x1ED1, 0x1ED9, 0x1ED3, 0x1ED5, 0x1ED7, 0x043E, + 0x0151, 0x020D, 0x0913, 0x00F6, 0x04E7, 0x1ECD, 0x0153, 0x315A, + 0x02DB, 0x0328, 0x00F2, 0x0A93, 0x0585, 0x304A, 0x1ECF, 0x01A1, + 0x1EDB, 0x1EE3, 0x1EDD, 0x1EDF, 0x1EE1, 0x0151, 0x01A3, 0x020F, + 0x30AA, 0xFF75, 0x3157, 0x05AB, 0x014D, 0x1E53, 0x1E51, 0x0950, + 0x03C9, 0x03D6, 0x0461, 0x0277, 0x047B, 0x047D, 0x03CE, 0x0AD0, + 0x03BF, 0x03CC, 0xFF4F, 0x0031, 0x0661, 0x09E7, 0x2460, 0x278A, + 0x0967, 0x2024, 0x215B, 0xF6DC, 0x0AE7, 0x0A67, 0x0661, 0x00BD, + 0x3021, 0x3220, 0x2081, 0xFF11, 0x09F4, 0xF731, 0x2474, 0x2488, + 0x06F1, 0x00BC, 0x2170, 0x00B9, 0x0E51, 0x2153, 0x01EB, 0x01ED, + 0x0A13, 0x0A4B, 0x0254, 0x24AA, 0x25E6, 0x2325, 0x00AA, 0x00BA, + 0x221F, 0x0912, 0x094A, 0x00F8, 0x01FF, 0x3049, 0x30A9, 0xFF6B, + 0x01FF, 0xF6F0, 0x047F, 0x00F5, 0x1E4D, 0x1E4F, 0x3121, 0x203E, + 0xFE4A, 0x0305, 0xFE49, 0xFE4C, 0xFE4B, 0x00AF, 0x09CB, 0x094B, + 0x0ACB, 0x0070, 0x3380, 0x332B, 0x09AA, 0x1E55, 0x092A, 0x21DF, + 0x21DE, 0x0AAA, 0x0A2A, 0x3071, 0x0E2F, 0x30D1, 0x0484, 0x04C0, + 0x317F, 0x00B6, 0x2225, 0x0028, 0xFD3E, 0xF8ED, 0xF8EC, 0x208D, + 0xFF08, 0xFE59, 0x207D, 0xF8EB, 0xFE35, 0x0029, 0xFD3F, 0xF8F8, + 0xF8F7, 0x208E, 0xFF09, 0xFE5A, 0x207E, 0xF8F6, 0xFE36, 0x2202, + 0x05C0, 0x0599, 0x33A9, 0x05B7, 0x05B7, 0x05B7, 0x05B7, 0x05B7, + 0x05B7, 0x05B7, 0x05B7, 0x05A1, 0x3106, 0x24DF, 0x1E57, 0x05E4, + 0x043F, 0xFB44, 0xFB44, 0x333B, 0xFB43, 0x067E, 0x057A, 0x05E4, + 0xFB57, 0xFB58, 0x307A, 0xFB59, 0x30DA, 0x04A7, 0xFB4E, 0x0025, + 0x066A, 0xFF05, 0xFE6A, 0x002E, 0x0589, 0x00B7, 0xFF61, 0xF6E7, + 0xFF0E, 0xFE52, 0xF6E8, 0x0342, 0x22A5, 0x2030, 0x20A7, 0x338A, + 0x09AB, 0x092B, 0x0AAB, 0x0A2B, 0x03C6, 0x03D5, 0x327A, 0x321A, + 0x326C, 0x314D, 0x320C, 0x0278, 0x0E3A, 0x03D5, 0x01A5, 0x0E1E, + 0x0E1C, 0x0E20, 0x03C0, 0x3273, 0x3213, 0x3176, 0x3265, 0x3172, + 0x3142, 0x3205, 0x3174, 0x3144, 0x3175, 0x3177, 0x3173, 0x3074, + 0x30D4, 0x03D6, 0x0583, 0x002B, 0x031F, 0x2295, 0x00B1, 0x02D6, + 0xFF0B, 0xFE62, 0x207A, 0xFF50, 0x33D8, 0x307D, 0x261F, 0x261C, + 0x261E, 0x261D, 0x30DD, 0x0E1B, 0x3012, 0x3020, 0x24AB, 0x227A, + 0x211E, 0x02B9, 0x2035, 0x220F, 0x2305, 0x30FC, 0x2318, 0x2282, + 0x2283, 0x2237, 0x221D, 0x03C8, 0x0471, 0x0486, 0x33B0, 0x3077, + 0x30D7, 0x33B4, 0x33BA, 0x0071, 0x0958, 0x05A8, 0x0642, 0xFED6, + 0xFED7, 0xFED8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, + 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, 0x05B8, + 0x05B8, 0x05B8, 0x059F, 0x3111, 0x24E0, 0x02A0, 0xFF51, 0x05E7, + 0xFB47, 0xFB47, 0x05E7, 0x24AC, 0x2669, 0x05BB, 0x05BB, 0x05BB, + 0x05BB, 0x05BB, 0x05BB, 0x05BB, 0x05BB, 0x003F, 0x061F, 0x055E, + 0x00BF, 0xF7BF, 0x037E, 0xFF1F, 0xF73F, 0x0022, 0x201E, 0x201C, + 0xFF02, 0x301E, 0x301D, 0x201D, 0x2018, 0x201B, 0x201B, 0x2019, + 0x0149, 0x201A, 0x0027, 0xFF07, 0x0072, 0x057C, 0x09B0, 0x0155, + 0x0930, 0x221A, 0xF8E5, 0x33AE, 0x33AF, 0x33AD, 0x05BF, 0x05BF, + 0x0AB0, 0x0A30, 0x3089, 0x30E9, 0xFF97, 0x09F1, 0x09F0, 0x0264, + 0x2236, 0x3116, 0x0159, 0x0157, 0x24E1, 0x0157, 0x0211, 0x1E59, + 0x1E5B, 0x1E5D, 0x203B, 0x2286, 0x2287, 0x00AE, 0xF8E8, 0xF6DA, + 0x0631, 0x0580, 0xFEAE, 0x308C, 0x30EC, 0xFF9A, 0x05E8, 0xFB48, + 0x05E8, 0x223D, 0x0597, 0x0597, 0x2310, 0x027E, 0x027F, 0x09DD, + 0x095D, 0x03C1, 0x027D, 0x027B, 0x02B5, 0x03F1, 0x02DE, 0x3271, + 0x3211, 0x3263, 0x3140, 0x313A, 0x3169, 0x3139, 0x313B, 0x316C, + 0x3203, 0x313F, 0x313C, 0x316B, 0x313D, 0x313E, 0x316A, 0x316D, + 0x221F, 0x0319, 0x22BF, 0x308A, 0x30EA, 0xFF98, 0x02DA, 0x0325, + 0x030A, 0x02BF, 0x0559, 0x031C, 0x02D3, 0x02BE, 0x0339, 0x02D2, + 0x0213, 0x3351, 0x1E5F, 0x027C, 0x027A, 0xFF52, 0x308D, 0x30ED, + 0xFF9B, 0x0E23, 0x24AD, 0x09DC, 0x0931, 0x0A5C, 0x0691, 0xFB8D, + 0x09E0, 0x0960, 0x0AE0, 0x09C4, 0x0944, 0x0AC4, 0xF6F1, 0x2590, + 0x0279, 0x02B4, 0x308B, 0x30EB, 0xFF99, 0x09F2, 0x09F3, 0xF6DD, + 0x0E24, 0x098B, 0x090B, 0x0A8B, 0x09C3, 0x0943, 0x0AC3, 0x0073, + 0x09B8, 0x015B, 0x1E65, 0x0635, 0x0938, 0xFEBA, 0xFEBB, 0xFEBC, + 0x0AB8, 0x0A38, 0x3055, 0x30B5, 0xFF7B, 0xFDFA, 0x05E1, 0xFB41, + 0xFB41, 0x05E1, 0x0E32, 0x0E41, 0x0E44, 0x0E43, 0x0E33, 0x0E30, + 0x0E40, 0xF886, 0x0E35, 0xF885, 0x0E34, 0x0E42, 0xF888, 0x0E37, + 0xF887, 0x0E36, 0x0E38, 0x0E39, 0x3119, 0x0161, 0x1E67, 0x015F, + 0x0259, 0x04D9, 0x04DB, 0x025A, 0x24E2, 0x015D, 0x0219, 0x1E61, + 0x1E63, 0x1E69, 0x033C, 0x2033, 0x02CA, 0x00A7, 0x0633, 0xFEB2, + 0xFEB3, 0xFEB4, 0x05B6, 0x05B6, 0x05B6, 0x05B6, 0x05B6, 0x05B6, + 0x05B6, 0x0592, 0x05B6, 0x057D, 0x305B, 0x30BB, 0xFF7E, 0x003B, + 0x061B, 0xFF1B, 0xFE54, 0x309C, 0xFF9F, 0x3322, 0x3323, 0x0037, + 0x0667, 0x09ED, 0x2466, 0x2790, 0x096D, 0x215E, 0x0AED, 0x0A6D, + 0x0667, 0x3027, 0x3226, 0x2087, 0xFF17, 0xF737, 0x247A, 0x248E, + 0x06F7, 0x2176, 0x2077, 0x2470, 0x2484, 0x2498, 0x0E57, 0x00AD, + 0x0577, 0x09B6, 0x0448, 0x0651, 0xFC61, 0xFC5E, 0xFC60, 0xFC62, + 0xFC5F, 0x2592, 0x2593, 0x2591, 0x2592, 0x0936, 0x0AB6, 0x0A36, + 0x0593, 0x3115, 0x0449, 0x0634, 0xFEB6, 0xFEB7, 0xFEB8, 0x03E3, + 0x20AA, 0x20AA, 0x05B0, 0x05B0, 0x05B0, 0x05B0, 0x05B0, 0x05B0, + 0x05B0, 0x05B0, 0x05B0, 0x04BB, 0x03ED, 0x05E9, 0xFB49, 0xFB49, + 0xFB2C, 0xFB2C, 0xFB2D, 0xFB2D, 0x05C1, 0x05E9, 0xFB2A, 0xFB2A, + 0xFB2B, 0xFB2B, 0x0282, 0x03C3, 0x03C2, 0x03C2, 0x03F2, 0x3057, + 0x30B7, 0xFF7C, 0x05BD, 0x05BD, 0x223C, 0x05C2, 0x3274, 0x3214, + 0x317E, 0x3266, 0x317A, 0x3145, 0x317B, 0x3206, 0x317D, 0x317C, + 0x0036, 0x0666, 0x09EC, 0x2465, 0x278F, 0x096C, 0x0AEC, 0x0A6C, + 0x0666, 0x3026, 0x3225, 0x2086, 0xFF16, 0xF736, 0x2479, 0x248D, + 0x06F6, 0x2175, 0x2076, 0x246F, 0x09F9, 0x2483, 0x2497, 0x0E56, + 0x002F, 0xFF0F, 0x017F, 0x1E9B, 0x263A, 0xFF53, 0x05C3, 0x00AD, + 0x044C, 0x305D, 0x30BD, 0xFF7F, 0x0338, 0x0337, 0x0E29, 0x0E28, + 0x0E0B, 0x0E2A, 0x0020, 0x0020, 0x2660, 0x2660, 0x2664, 0x24AE, + 0x033B, 0x33C4, 0x339D, 0x25A9, 0x25A4, 0x338F, 0x339E, 0x33CE, + 0x33D1, 0x33D2, 0x338E, 0x33D5, 0x339C, 0x33A1, 0x25A6, 0x25A7, + 0x25A8, 0x25A5, 0x25A3, 0x33DB, 0x09B7, 0x0937, 0x0AB7, 0x3149, + 0x3185, 0x3180, 0x3132, 0x3165, 0x3143, 0x3146, 0x3138, 0xF6F2, + 0x00A3, 0xFFE1, 0x0336, 0x0335, 0x2282, 0x228A, 0x2286, 0x227B, + 0x220B, 0x3059, 0x30B9, 0xFF7D, 0x0652, 0x2211, 0x263C, 0x2283, + 0x228B, 0x2287, 0x33DC, 0x337C, 0x0074, 0x09A4, 0x22A4, 0x22A3, + 0x0924, 0x0AA4, 0x0A24, 0x0637, 0xFEC2, 0xFEC3, 0x305F, 0xFEC4, + 0x337D, 0x30BF, 0xFF80, 0x0640, 0x03C4, 0x05EA, 0xFB4A, 0xFB4A, + 0xFB4A, 0x05EA, 0x0167, 0x310A, 0x0165, 0x02A8, 0x0163, 0x0686, + 0xFB7B, 0xFB7C, 0xFB7D, 0x24E3, 0x1E71, 0x0163, 0x1E97, 0x1E6B, + 0x1E6D, 0x0442, 0x04AD, 0x062A, 0xFE96, 0xFCA2, 0xFC0C, 0xFE97, + 0x3066, 0xFCA1, 0xFC0B, 0x0629, 0xFE94, 0xFE98, 0xFCA4, 0xFC0E, + 0xFC73, 0x30C6, 0xFF83, 0x2121, 0x260E, 0x05A0, 0x05A9, 0x2469, + 0x3229, 0x247D, 0x2491, 0x2179, 0x02A7, 0x05D8, 0xFB38, 0xFB38, + 0x05D8, 0x04B5, 0x059B, 0x059B, 0x09A5, 0x0925, 0x0AA5, 0x0A25, + 0x0630, 0xFEAC, 0xF898, 0xF897, 0x0E4C, 0xF896, 0x062B, 0xFE9A, + 0xFE9B, 0xFE9C, 0x2203, 0x2234, 0x03B8, 0x03D1, 0x03D1, 0x3279, + 0x3219, 0x326B, 0x314C, 0x320B, 0x246C, 0x2480, 0x2494, 0x0E11, + 0x01AD, 0x0E12, 0x00FE, 0x0E17, 0x0E10, 0x0E18, 0x0E16, 0x0482, + 0x066C, 0x066C, 0x0033, 0x0663, 0x09E9, 0x2462, 0x278C, 0x0969, + 0x215C, 0x0AE9, 0x0A69, 0x0663, 0x3023, 0x3222, 0x2083, 0xFF13, + 0x09F6, 0xF733, 0x2476, 0x248A, 0x06F3, 0x00BE, 0xF6DE, 0x2172, + 0x00B3, 0x0E53, 0x3394, 0x3061, 0x30C1, 0xFF81, 0x3270, 0x3210, + 0x3262, 0x3137, 0x3202, 0x02DC, 0x0330, 0x0303, 0x0303, 0x0360, + 0x223C, 0x0334, 0x033E, 0x2297, 0x0596, 0x0596, 0x0A70, 0x0483, + 0x057F, 0x1E6F, 0xFF54, 0x0569, 0x3068, 0x30C8, 0xFF84, 0x02E5, + 0x02E9, 0x02E6, 0x02E8, 0x02E7, 0x01BD, 0x0185, 0x01A8, 0x0384, + 0x3327, 0x0E0F, 0x3014, 0xFE5D, 0xFE39, 0x3015, 0xFE5E, 0xFE3A, + 0x0E15, 0x01AB, 0x24AF, 0x2122, 0xF8EA, 0xF6DB, 0x0288, 0x25BC, + 0x25C4, 0x25BA, 0x25B2, 0x02A6, 0x05E6, 0xFB46, 0xFB46, 0x05E6, + 0x0446, 0x05B5, 0x05B5, 0x05B5, 0x05B5, 0x05B5, 0x05B5, 0x05B5, + 0x05B5, 0x045B, 0xF6F3, 0x099F, 0x091F, 0x0A9F, 0x0A1F, 0x0679, + 0xFB67, 0xFB68, 0xFB69, 0x09A0, 0x0920, 0x0AA0, 0x0A20, 0x0287, + 0x3064, 0x30C4, 0xFF82, 0x3063, 0x30C3, 0xFF6F, 0x246B, 0x247F, + 0x2493, 0x217B, 0x2473, 0x5344, 0x2487, 0x249B, 0x0032, 0x0662, + 0x09E8, 0x2461, 0x278B, 0x0968, 0x2025, 0x2025, 0xFE30, 0x0AE8, + 0x0A68, 0x0662, 0x3022, 0x3221, 0x2082, 0xFF12, 0x09F5, 0xF732, + 0x2475, 0x2489, 0x06F2, 0x2171, 0x01BB, 0x00B2, 0x0E52, 0x2154, + 0x0075, 0x00FA, 0x0289, 0x0989, 0x3128, 0x016D, 0x01D4, 0x24E4, + 0x00FB, 0x1E77, 0x0443, 0x0951, 0x0171, 0x0215, 0x0909, 0x00FC, + 0x01D8, 0x1E73, 0x01DA, 0x04F1, 0x01DC, 0x01D6, 0x1EE5, 0x00F9, + 0x0A89, 0x0A09, 0x3046, 0x1EE7, 0x01B0, 0x1EE9, 0x1EF1, 0x1EEB, + 0x1EED, 0x1EEF, 0x0171, 0x04F3, 0x0217, 0x30A6, 0xFF73, 0x0479, + 0x315C, 0x016B, 0x04EF, 0x1E7B, 0x0A41, 0xFF55, 0x005F, 0x2017, + 0xFF3F, 0xFE33, 0xFE4F, 0x222A, 0x2200, 0x0173, 0x24B0, 0x2580, + 0x05C4, 0x03C5, 0x03CB, 0x03B0, 0x028A, 0x03CD, 0x031D, 0x02D4, + 0x0A73, 0x016F, 0x045E, 0x3045, 0x30A5, 0xFF69, 0x04AF, 0x04B1, + 0x0169, 0x1E79, 0x1E75, 0x098A, 0x090A, 0x0A8A, 0x0A0A, 0x0A42, + 0x09C2, 0x0942, 0x0AC2, 0x09C1, 0x0941, 0x0AC1, 0x0076, 0x0935, + 0x0AB5, 0x0A35, 0x30F7, 0x05D5, 0xFB35, 0xFB35, 0xFB35, 0x05D5, + 0xFB4B, 0xFB4B, 0x05F0, 0x05F1, 0x24E5, 0x1E7F, 0x0432, 0x06A4, + 0xFB6B, 0xFB6C, 0xFB6D, 0x30F9, 0x2640, 0x007C, 0x030D, 0x0329, + 0x02CC, 0x02C8, 0x057E, 0x028B, 0x30F8, 0x09CD, 0x094D, 0x0ACD, + 0x0983, 0x0903, 0x0A83, 0xFF56, 0x0578, 0x309E, 0x30FE, 0x309B, + 0xFF9E, 0x30FA, 0x24B1, 0x1E7D, 0x028C, 0x3094, 0x30F4, 0x0077, + 0x1E83, 0x3159, 0x308F, 0x30EF, 0xFF9C, 0x3158, 0x308E, 0x30EE, + 0x3357, 0x301C, 0xFE34, 0x0648, 0xFEEE, 0x0624, 0xFE86, 0x33DD, + 0x24E6, 0x0175, 0x1E85, 0x1E87, 0x1E89, 0x3091, 0x2118, 0x30F1, + 0x315E, 0x315D, 0x1E81, 0x25E6, 0x25CB, 0x25D9, 0x300E, 0xFE43, + 0x300F, 0xFE44, 0x25C7, 0x25C8, 0x25BF, 0x25BD, 0x25C3, 0x25C1, + 0x3016, 0x3017, 0x25B9, 0x25B7, 0x25AB, 0x263A, 0x25A1, 0x2606, + 0x260F, 0x3018, 0x3019, 0x25B5, 0x25B3, 0x3090, 0x30F0, 0x315F, + 0xFF57, 0x3092, 0x30F2, 0xFF66, 0x20A9, 0xFFE6, 0x0E27, 0x24B2, + 0x1E98, 0x02B7, 0x028D, 0x01BF, 0x0078, 0x033D, 0x3112, 0x24E7, + 0x1E8D, 0x1E8B, 0x056D, 0x03BE, 0xFF58, 0x24B3, 0x02E3, 0x0079, + 0x334E, 0x09AF, 0x00FD, 0x092F, 0x3152, 0x0AAF, 0x0A2F, 0x3084, + 0x30E4, 0xFF94, 0x3151, 0x0E4E, 0x3083, 0x30E3, 0xFF6C, 0x0463, + 0x24E8, 0x0177, 0x00FF, 0x1E8F, 0x1EF5, 0x064A, 0x06D2, 0xFBAF, + 0xFEF2, 0x0626, 0xFE8A, 0xFE8B, 0xFE8C, 0xFEF3, 0xFEF4, 0xFCDD, + 0xFC58, 0xFC94, 0x06D1, 0x3156, 0x00A5, 0xFFE5, 0x3155, 0x3186, + 0x05AA, 0x05AA, 0x044B, 0x04F9, 0x3181, 0x3183, 0x3182, 0x059A, + 0x1EF3, 0x01B4, 0x1EF7, 0x0575, 0x0457, 0x3162, 0x262F, 0x0582, + 0xFF59, 0x05D9, 0xFB39, 0xFB39, 0x05D9, 0x05F2, 0xFB1F, 0x3088, + 0x3189, 0x30E8, 0xFF96, 0x315B, 0x3087, 0x30E7, 0xFF6E, 0x03F3, + 0x3188, 0x3187, 0x0E22, 0x0E0D, 0x24B4, 0x037A, 0x0345, 0x01A6, + 0x1E99, 0x02B8, 0x1EF9, 0x028E, 0x3086, 0x318C, 0x30E6, 0xFF95, + 0x3160, 0x046B, 0x046D, 0x0467, 0x0469, 0x3085, 0x30E5, 0xFF6D, + 0x318B, 0x318A, 0x09DF, 0x095F, 0x007A, 0x0566, 0x017A, 0x095B, + 0x0A5B, 0x0638, 0xFEC6, 0xFEC7, 0x3056, 0xFEC8, 0x0632, 0xFEB0, + 0x30B6, 0x0595, 0x0594, 0x0598, 0x05D6, 0xFB36, 0xFB36, 0x05D6, + 0x3117, 0x017E, 0x24E9, 0x1E91, 0x0291, 0x017C, 0x017C, 0x1E93, + 0x0437, 0x0499, 0x04DF, 0x305C, 0x30BC, 0x0030, 0x0660, 0x09E6, + 0x0966, 0x0AE6, 0x0A66, 0x0660, 0x2080, 0xFF10, 0xF730, 0x06F0, + 0x2070, 0x0E50, 0xFEFF, 0x200C, 0x200B, 0x03B6, 0x3113, 0x056A, + 0x04C2, 0x0436, 0x0497, 0x04DD, 0x3058, 0x30B8, 0x05AE, 0x1E95, + 0xFF5A, 0x305E, 0x30BE, 0x24B5, 0x0290, 0x01B6, 0x305A, 0x30BA, +}; + +wchar_t ps_glyph_to_unicode(char const *glyph) +{ + int i, j, k, c; + + i = -1; + j = lenof(ps_glyphs_alphabetic); + while (j-i > 1) { + k = (i + j) / 2; + c = strcmp(glyph, ps_glyphs_alphabetic[k]); + + if (c == 0) + return ps_codes_alphabetic[k]; + else if (c < 0) + j = k; + else + i = k; + } + + return 0xFFFF; /* illegal value means not found */ +} + +/* ---------------------------------------------------------------------- + * Data about the standard fonts: available glyphs and font metrics. + */ + +/* + * Character set list extracted from the back of the PostScript + * Language Reference Manual. + * + * I'm going to include a bit of shell which creates a file + * containing the list of characters, and then several further bits + * of shell that process it in different ways. + */ + +/* + +tr -s ' \n' '\n' << EOF > stdchars.txt +A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +a b c d e f g h i j k l m n o p q r s t u v w x y z +AE Aacute Acircumflex Adieresis Agrave Aring Atilde +Ccedilla +Eacute Ecircumflex Edieresis Egrave +Eth +Iacute Icircumflex Idieresis Igrave +Lslash +Ntilde +OE Oacute Ocircumflex Odieresis Ograve Oslash Otilde +Scaron +Thorn +Uacute Ucircumflex Udieresis Ugrave +Yacute Ydieresis +Zcaron +ae aacute acircumflex adieresis agrave aring atilde +ccedilla +eacute ecircumflex edieresis egrave +eth +iacute icircumflex idieresis igrave +lslash +ntilde +oe oacute ocircumflex odieresis ograve oslash otilde +scaron +thorn +uacute ucircumflex udieresis ugrave +yacute ydieresis +zcaron +acute ampersand asciicircum asciitilde asterisk at backslash bar +braceleft braceright bracketleft bracketright breve brokenbar bullet +caron cedilla cent circumflex colon comma copyright currency dagger +daggerdbl degree dieresis divide dollar dotaccent dotlessi eight +ellipsis emdash endash equal exclam exclamdown fi five fl florin +four fraction germandbls grave greater guillemotleft guillemotright +guilsinglleft guilsinglright hungarumlaut hyphen less logicalnot +macron minus mu multiply nine numbersign ogonek one onehalf onequarter +onesuperior ordfeminine ordmasculine paragraph parenleft parenright +percent period periodcentered perthousand plus plusminus question +questiondown quotedbl quotedblbase quotedblleft quotedblright quoteleft +quoteright quotesinglbase quotesingle registered ring section semicolon +seven six slash space sterling three threequarters threesuperior tilde +trademark two twosuperior underscore yen zero +EOF + + */ + +/* + * A simple string array giving the glyph list. + */ + +/* + +perl -ne 'chomp; print "\"$_\", "; END { print "NULL" }' stdchars.txt | \ + fold -s -w68 | sed 's/^/ /' + +*/ + +const char *const ps_std_glyphs[] = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "AE", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", + "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", + "Egrave", "Eth", "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Lslash", "Ntilde", "OE", "Oacute", "Ocircumflex", "Odieresis", + "Ograve", "Oslash", "Otilde", "Scaron", "Thorn", "Uacute", + "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", + "Zcaron", "ae", "aacute", "acircumflex", "adieresis", "agrave", + "aring", "atilde", "ccedilla", "eacute", "ecircumflex", + "edieresis", "egrave", "eth", "iacute", "icircumflex", "idieresis", + "igrave", "lslash", "ntilde", "oe", "oacute", "ocircumflex", + "odieresis", "ograve", "oslash", "otilde", "scaron", "thorn", + "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", + "ydieresis", "zcaron", "acute", "ampersand", "asciicircum", + "asciitilde", "asterisk", "at", "backslash", "bar", "braceleft", + "braceright", "bracketleft", "bracketright", "breve", "brokenbar", + "bullet", "caron", "cedilla", "cent", "circumflex", "colon", + "comma", "copyright", "currency", "dagger", "daggerdbl", "degree", + "dieresis", "divide", "dollar", "dotaccent", "dotlessi", "eight", + "ellipsis", "emdash", "endash", "equal", "exclam", "exclamdown", + "fi", "five", "fl", "florin", "four", "fraction", "germandbls", + "grave", "greater", "guillemotleft", "guillemotright", + "guilsinglleft", "guilsinglright", "hungarumlaut", "hyphen", + "less", "logicalnot", "macron", "minus", "mu", "multiply", "nine", + "numbersign", "ogonek", "one", "onehalf", "onequarter", + "onesuperior", "ordfeminine", "ordmasculine", "paragraph", + "parenleft", "parenright", "percent", "period", "periodcentered", + "perthousand", "plus", "plusminus", "question", "questiondown", + "quotedbl", "quotedblbase", "quotedblleft", "quotedblright", + "quoteleft", "quoteright", "quotesinglbase", "quotesingle", + "registered", "ring", "section", "semicolon", "seven", "six", + "slash", "space", "sterling", "three", "threequarters", + "threesuperior", "tilde", "trademark", "two", "twosuperior", + "underscore", "yen", "zero", NULL +}; + +/* + * Character width information from the standard PS fonts. I can + * see no more sensible way to get hold of this information than by + * extracting it from GhostScript. + * + * Initial experimentation with this technique yielded a load of + * floating-point values, which on closer examination all turned + * out (modulo rounding error due to decimal representation) to be + * exact multiples of 1/4096. Accordingly I now store all these + * arrays as integers with a scale of 4096. + */ + +/* + +for i in Times-Roman Times-Italic Times-Bold Times-BoldItalic \ + Helvetica Helvetica-Oblique Helvetica-Bold Helvetica-BoldOblique \ + Courier Courier-Oblique Courier-Bold Courier-BoldOblique; do + echo " {\"$i\", {" + (echo "/fn /$i findfont def"; + echo '/cw { fn dup length dict begin'; + echo '{1 index /FID ne {def} {pop pop} ifelse} forall'; + echo '/Encoding Encoding dup length array copy def'; + echo 'Encoding exch 65 exch put'; + echo 'currentdict end /Spingly exch definefont setfont'; + echo '(A) stringwidth pop 4096 mul round cvi /Spingly undefinefont} def'; + perl -ne 'chomp; print "/$_ cw ==\n"' stdchars.txt) | \ + gs -q -sDEVICE=nullpage - | sed 's/$/,/' | tr '\n' ' ' | \ + fold -s -w68 | sed 's/^/ /'; echo + echo " }}," +done + +*/ + +static const struct ps_std_font_data { + char const *name; + int widths[lenof(ps_std_glyphs)-1]; +} ps_std_fonts[] = { + {"Times-Roman", { + 2957, 2732, 2732, 2957, 2502, 2277, 2957, 2957, 1363, 1593, 2957, + 2502, 3641, 2957, 2957, 2277, 2957, 2732, 2277, 2502, 2957, 2957, + 3866, 2957, 2957, 2502, 1818, 2048, 1818, 2048, 1818, 1363, 2048, + 2048, 1138, 1138, 2048, 1138, 3186, 2048, 2048, 2048, 2048, 1363, + 1593, 1138, 2048, 2048, 2957, 2048, 2048, 1818, 3641, 2957, 2957, + 2957, 2957, 2957, 2957, 2732, 2502, 2502, 2502, 2502, 2957, 1363, + 1363, 1363, 1363, 2502, 2957, 3641, 2957, 2957, 2957, 2957, 2957, + 2957, 2277, 2277, 2957, 2957, 2957, 2957, 2957, 2957, 2502, 2732, + 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1818, + 2048, 1138, 1138, 1138, 1138, 1138, 2048, 2957, 2048, 2048, 2048, + 2048, 2048, 2048, 1593, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 1818, 1363, 3186, 1921, 2215, 2048, 3772, 1138, 819, 1966, 1966, + 1363, 1363, 1363, 819, 1433, 1363, 1363, 2048, 1363, 1138, 1024, + 3112, 2048, 2048, 2048, 1638, 1363, 2310, 2048, 1363, 1138, 2048, + 4096, 4096, 2048, 2310, 1363, 1363, 2277, 2048, 2277, 2048, 2048, + 684, 2048, 1363, 2310, 2048, 2048, 1363, 1363, 1363, 1363, 2310, + 2310, 1363, 2310, 2048, 2310, 2048, 2048, 1363, 2048, 3072, 3072, + 1228, 1130, 1269, 1855, 1363, 1363, 3411, 1024, 1024, 4096, 2310, + 2310, 1818, 1818, 1671, 1818, 1818, 1818, 1363, 1363, 1363, 737, + 3112, 1363, 2048, 1138, 2048, 2048, 1138, 1024, 2048, 2048, 3072, + 1228, 1363, 4014, 2048, 1228, 2048, 2048, 2048, + }}, + {"Times-Italic", { + 2502, 2502, 2732, 2957, 2502, 2502, 2957, 2957, 1363, 1818, 2732, + 2277, 3411, 2732, 2957, 2502, 2957, 2502, 2048, 2277, 2957, 2502, + 3411, 2502, 2277, 2277, 2048, 2048, 1818, 2048, 1818, 1138, 2048, + 2048, 1138, 1138, 1818, 1138, 2957, 2048, 2048, 2048, 2048, 1593, + 1593, 1138, 2048, 1818, 2732, 1818, 1818, 1593, 3641, 2502, 2502, + 2502, 2502, 2502, 2502, 2732, 2502, 2502, 2502, 2502, 2957, 1363, + 1363, 1363, 1363, 2277, 2732, 3866, 2957, 2957, 2957, 2957, 2957, + 2957, 2048, 2502, 2957, 2957, 2957, 2957, 2277, 2277, 2277, 2732, + 2048, 2048, 2048, 2048, 2048, 2048, 1818, 1818, 1818, 1818, 1818, + 2048, 1138, 1138, 1138, 1138, 1138, 2048, 2732, 2048, 2048, 2048, + 2048, 2048, 2048, 1593, 2048, 2048, 2048, 2048, 2048, 1818, 1818, + 1593, 1363, 3186, 1728, 2215, 2048, 3768, 1138, 1126, 1638, 1638, + 1593, 1593, 1363, 1126, 1433, 1363, 1363, 2048, 1363, 1363, 1024, + 3112, 2048, 2048, 2048, 1638, 1363, 2764, 2048, 1363, 1138, 2048, + 3641, 3641, 2048, 2764, 1363, 1593, 2048, 2048, 2048, 2048, 2048, + 684, 2048, 1363, 2764, 2048, 2048, 1363, 1363, 1363, 1363, 2764, + 2764, 1363, 2764, 2048, 2764, 2048, 2048, 1363, 2048, 3072, 3072, + 1228, 1130, 1269, 2142, 1363, 1363, 3411, 1024, 1024, 4096, 2764, + 2764, 2048, 2048, 1720, 2277, 2277, 2277, 1363, 1363, 1363, 876, + 3112, 1363, 2048, 1363, 2048, 2048, 1138, 1024, 2048, 2048, 3072, + 1228, 1363, 4014, 2048, 1228, 2048, 2048, 2048, + }}, + {"Times-Bold", { + 2957, 2732, 2957, 2957, 2732, 2502, 3186, 3186, 1593, 2048, 3186, + 2732, 3866, 2957, 3186, 2502, 3186, 2957, 2277, 2732, 2957, 2957, + 4096, 2957, 2957, 2732, 2048, 2277, 1818, 2277, 1818, 1363, 2048, + 2277, 1138, 1363, 2277, 1138, 3411, 2277, 2048, 2277, 2277, 1818, + 1593, 1363, 2277, 2048, 2957, 2048, 2048, 1818, 4096, 2957, 2957, + 2957, 2957, 2957, 2957, 2957, 2732, 2732, 2732, 2732, 2957, 1593, + 1593, 1593, 1593, 2732, 2957, 4096, 3186, 3186, 3186, 3186, 3186, + 3186, 2277, 2502, 2957, 2957, 2957, 2957, 2957, 2957, 2732, 2957, + 2048, 2048, 2048, 2048, 2048, 2048, 1818, 1818, 1818, 1818, 1818, + 2048, 1138, 1138, 1138, 1138, 1138, 2277, 2957, 2048, 2048, 2048, + 2048, 2048, 2048, 1593, 2277, 2277, 2277, 2277, 2277, 2048, 2048, + 1818, 1363, 3411, 2379, 2129, 2048, 3809, 1138, 901, 1613, 1613, + 1363, 1363, 1363, 901, 1433, 1363, 1363, 2048, 1363, 1363, 1024, + 3059, 2048, 2048, 2048, 1638, 1363, 2334, 2048, 1363, 1138, 2048, + 4096, 4096, 2048, 2334, 1363, 1363, 2277, 2048, 2277, 2048, 2048, + 684, 2277, 1363, 2334, 2048, 2048, 1363, 1363, 1363, 1363, 2334, + 2334, 1363, 2334, 2277, 2334, 2048, 2048, 1363, 2048, 3072, 3072, + 1228, 1228, 1351, 2211, 1363, 1363, 4096, 1024, 1024, 4096, 2334, + 2334, 2048, 2048, 2273, 2048, 2048, 2048, 1363, 1363, 1363, 1138, + 3059, 1363, 2048, 1363, 2048, 2048, 1138, 1024, 2048, 2048, 3072, + 1228, 1363, 4096, 2048, 1228, 2048, 2048, 2048, + }}, + {"Times-BoldItalic", { + 2732, 2732, 2732, 2957, 2732, 2732, 2957, 3186, 1593, 2048, 2732, + 2502, 3641, 2957, 2957, 2502, 2957, 2732, 2277, 2502, 2957, 2732, + 3641, 2732, 2502, 2502, 2048, 2048, 1818, 2048, 1818, 1363, 2048, + 2277, 1138, 1138, 2048, 1138, 3186, 2277, 2048, 2048, 2048, 1593, + 1593, 1138, 2277, 1818, 2732, 2048, 1818, 1593, 3866, 2732, 2732, + 2732, 2732, 2732, 2732, 2732, 2732, 2732, 2732, 2732, 2957, 1593, + 1593, 1593, 1593, 2502, 2957, 3866, 2957, 2957, 2957, 2957, 2957, + 2957, 2277, 2502, 2957, 2957, 2957, 2957, 2502, 2502, 2502, 2957, + 2048, 2048, 2048, 2048, 2048, 2048, 1818, 1818, 1818, 1818, 1818, + 2048, 1138, 1138, 1138, 1138, 1138, 2277, 2957, 2048, 2048, 2048, + 2048, 2048, 2048, 1593, 2048, 2277, 2277, 2277, 2277, 1818, 1818, + 1593, 1363, 3186, 2334, 2334, 2048, 3407, 1138, 901, 1425, 1425, + 1363, 1363, 1363, 901, 1433, 1363, 1363, 2048, 1363, 1363, 1024, + 3059, 2048, 2048, 2048, 1638, 1363, 2334, 2048, 1363, 1138, 2048, + 4096, 4096, 2048, 2334, 1593, 1593, 2277, 2048, 2277, 2048, 2048, + 684, 2048, 1363, 2334, 2048, 2048, 1363, 1363, 1363, 1363, 2334, + 2482, 1363, 2482, 2359, 2334, 2048, 2048, 1363, 2048, 3072, 3072, + 1228, 1089, 1228, 2048, 1363, 1363, 3411, 1024, 1024, 4096, 2334, + 2334, 2048, 2048, 2273, 2048, 2048, 2048, 1363, 1363, 1363, 1138, + 3059, 1363, 2048, 1363, 2048, 2048, 1138, 1024, 2048, 2048, 3072, + 1228, 1363, 4096, 2048, 1228, 2048, 2048, 2048, + }}, + {"Helvetica", { + 2732, 2732, 2957, 2957, 2732, 2502, 3186, 2957, 1138, 2048, 2732, + 2277, 3411, 2957, 3186, 2732, 3186, 2957, 2732, 2502, 2957, 2732, + 3866, 2732, 2732, 2502, 2277, 2277, 2048, 2277, 2277, 1138, 2277, + 2277, 909, 909, 2048, 909, 3411, 2277, 2277, 2277, 2277, 1363, + 2048, 1138, 2277, 2048, 2957, 2048, 2048, 2048, 4096, 2732, 2732, + 2732, 2732, 2732, 2732, 2957, 2732, 2732, 2732, 2732, 2957, 1138, + 1138, 1138, 1138, 2277, 2957, 4096, 3186, 3186, 3186, 3186, 3186, + 3186, 2732, 2727, 2957, 2957, 2957, 2957, 2727, 2732, 2502, 3641, + 2277, 2277, 2277, 2277, 2277, 2277, 2048, 2277, 2277, 2277, 2277, + 2277, 1138, 1138, 1138, 1138, 909, 2277, 3866, 2277, 2277, 2277, + 2277, 2502, 2277, 2048, 2273, 2277, 2277, 2277, 2277, 2048, 2048, + 2048, 1363, 2732, 1921, 2392, 1593, 4157, 1138, 1064, 1368, 1368, + 1138, 1138, 1363, 1064, 1433, 1363, 1363, 2277, 1363, 1138, 1138, + 3018, 2277, 2277, 2277, 2482, 1363, 2392, 2277, 1363, 1138, 2277, + 4096, 4096, 2277, 2392, 1138, 1363, 2048, 2277, 2048, 2277, 2277, + 684, 2502, 1363, 2392, 2277, 2277, 1363, 1363, 1363, 1363, 2392, + 2392, 1363, 2392, 2277, 2392, 2277, 2277, 1363, 2277, 3559, 3559, + 1437, 1515, 1495, 2199, 1363, 1363, 3641, 1138, 1138, 4096, 2392, + 2392, 2277, 2502, 1454, 1363, 1363, 1363, 909, 905, 909, 782, 3018, + 1363, 2277, 1138, 2277, 2277, 1138, 1138, 2277, 2277, 3559, 1437, + 1363, 4096, 2277, 1437, 2277, 2277, 2277, + }}, + {"Helvetica-Oblique", { + 2732, 2732, 2957, 2957, 2732, 2502, 3186, 2957, 1138, 2048, 2732, + 2277, 3411, 2957, 3186, 2732, 3186, 2957, 2732, 2502, 2957, 2732, + 3866, 2732, 2732, 2502, 2277, 2277, 2048, 2277, 2277, 1138, 2277, + 2277, 909, 909, 2048, 909, 3411, 2277, 2277, 2277, 2277, 1363, + 2048, 1138, 2277, 2048, 2957, 2048, 2048, 2048, 4096, 2732, 2732, + 2732, 2732, 2732, 2732, 2957, 2732, 2732, 2732, 2732, 2957, 1138, + 1138, 1138, 1138, 2277, 2957, 4096, 3186, 3186, 3186, 3186, 3186, + 3186, 2732, 2732, 2957, 2957, 2957, 2957, 2732, 2732, 2502, 3641, + 2277, 2277, 2277, 2277, 2277, 2277, 2048, 2277, 2277, 2277, 2277, + 2277, 1138, 1138, 1138, 1138, 909, 2277, 3866, 2277, 2277, 2277, + 2277, 2502, 2277, 2048, 2277, 2277, 2277, 2277, 2277, 2048, 2048, + 2048, 1363, 2732, 1921, 2392, 1593, 4157, 1138, 1064, 1368, 1368, + 1138, 1138, 1363, 1064, 1433, 1363, 1363, 2277, 1363, 1138, 1138, + 3018, 2277, 2277, 2277, 2482, 1363, 2392, 2277, 1363, 1138, 2277, + 4096, 4096, 2277, 2392, 1138, 1363, 2048, 2277, 2048, 2277, 2277, + 684, 2502, 1363, 2392, 2277, 2277, 1363, 1363, 1363, 1363, 2392, + 2392, 1363, 2392, 2277, 2392, 2277, 2277, 1363, 2277, 3878, 3878, + 1597, 1515, 1495, 2199, 1363, 1363, 3641, 1138, 1138, 4096, 2392, + 2392, 2277, 2502, 1454, 1363, 1363, 1363, 909, 909, 909, 782, 3018, + 1363, 2277, 1138, 2277, 2277, 1138, 1138, 2277, 2277, 3878, 1597, + 1363, 4096, 2277, 1597, 2277, 2277, 2277, + }}, + {"Helvetica-Bold", { + 2957, 2957, 2957, 2957, 2732, 2502, 3186, 2957, 1138, 2277, 2957, + 2502, 3411, 2957, 3186, 2732, 3186, 2957, 2732, 2502, 2957, 2732, + 3866, 2732, 2732, 2502, 2277, 2502, 2277, 2502, 2277, 1363, 2502, + 2502, 1138, 1138, 2277, 1138, 3641, 2502, 2502, 2502, 2502, 1593, + 2277, 1363, 2502, 2277, 3186, 2277, 2277, 2048, 4096, 2957, 2957, + 2957, 2957, 2957, 2957, 2957, 2732, 2732, 2732, 2732, 2957, 1138, + 1138, 1138, 1138, 2502, 2957, 4096, 3186, 3186, 3186, 3186, 3186, + 3186, 2732, 2732, 2957, 2957, 2957, 2957, 2732, 2732, 2502, 3641, + 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, + 2502, 1138, 1138, 1138, 1138, 1138, 2502, 3866, 2502, 2502, 2502, + 2502, 2502, 2502, 2277, 2502, 2502, 2502, 2502, 2502, 2277, 2277, + 2048, 1363, 2957, 2392, 2392, 1593, 3993, 1138, 1146, 1593, 1593, + 1363, 1363, 1363, 1146, 1433, 1363, 1363, 2277, 1363, 1363, 1138, + 3018, 2277, 2277, 2277, 2482, 1363, 2392, 2277, 1363, 1138, 2277, + 4096, 4096, 2277, 2392, 1363, 1363, 2502, 2277, 2502, 2277, 2277, + 684, 2502, 1363, 2392, 2277, 2277, 1363, 1363, 1363, 1363, 2392, + 2392, 1363, 2392, 2502, 2392, 2277, 2277, 1363, 2277, 3559, 3559, + 1437, 1515, 1495, 2277, 1363, 1363, 3641, 1138, 1138, 4096, 2392, + 2392, 2502, 2502, 1941, 2048, 2048, 2048, 1138, 1138, 1138, 974, + 3018, 1363, 2277, 1363, 2277, 2277, 1138, 1138, 2277, 2277, 3559, + 1437, 1363, 4096, 2277, 1437, 2277, 2277, 2277, + }}, + {"Helvetica-BoldOblique", { + 2957, 2957, 2957, 2957, 2732, 2502, 3186, 2957, 1138, 2277, 2957, + 2502, 3411, 2957, 3186, 2732, 3186, 2957, 2732, 2502, 2957, 2732, + 3866, 2732, 2732, 2502, 2277, 2502, 2277, 2502, 2277, 1363, 2502, + 2502, 1138, 1138, 2277, 1138, 3641, 2502, 2502, 2502, 2502, 1593, + 2277, 1363, 2502, 2277, 3186, 2277, 2277, 2048, 4096, 2957, 2957, + 2957, 2957, 2957, 2957, 2957, 2732, 2732, 2732, 2732, 2957, 1138, + 1138, 1138, 1138, 2502, 2957, 4096, 3186, 3186, 3186, 3186, 3186, + 3186, 2732, 2732, 2957, 2957, 2957, 2957, 2732, 2732, 2502, 3641, + 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, 2277, + 2502, 1138, 1138, 1138, 1138, 1138, 2502, 3866, 2502, 2502, 2502, + 2502, 2502, 2502, 2277, 2502, 2502, 2502, 2502, 2502, 2277, 2277, + 2048, 1363, 2957, 2392, 2392, 1593, 3993, 1138, 1146, 1593, 1593, + 1363, 1363, 1363, 1146, 1433, 1363, 1363, 2277, 1363, 1363, 1138, + 3018, 2277, 2277, 2277, 2482, 1363, 2392, 2277, 1363, 1138, 2277, + 4096, 4096, 2277, 2392, 1363, 1363, 2502, 2277, 2502, 2277, 2277, + 684, 2502, 1363, 2392, 2277, 2277, 1363, 1363, 1363, 1363, 2392, + 2392, 1363, 2392, 2502, 2392, 2277, 2277, 1363, 2277, 4321, 4321, + 1818, 1515, 1495, 2277, 1363, 1363, 3641, 1138, 1138, 4096, 2392, + 2392, 2502, 2502, 1941, 2048, 2048, 2048, 1138, 1138, 1138, 974, + 3018, 1363, 2277, 1363, 2277, 2277, 1138, 1138, 2277, 2277, 4321, + 1818, 1363, 4096, 2277, 1818, 2277, 2277, 2277, + }}, + {"Courier", { + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + }}, + {"Courier-Oblique", { + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + }}, + {"Courier-Bold", { + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + }}, + {"Courier-BoldOblique", { + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + 2457, 2457, 2457, 2457, 2457, 2457, 2457, 2457, + }}, +}; + +const int *ps_std_font_widths(char const *fontname) +{ + int i; + + for (i = 0; i < (int)lenof(ps_std_fonts[i].widths); i++) + if (!strcmp(ps_std_fonts[i].name, fontname)) + return ps_std_fonts[i].widths; + + return NULL; +} |