diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/writettf.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/font/writettf.c | 1573 |
1 files changed, 1573 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/writettf.c b/Build/source/texk/web2c/luatexdir/font/writettf.c new file mode 100644 index 00000000000..cf034e98d0a --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/writettf.c @@ -0,0 +1,1573 @@ +/* + +Copyright 1996-2006 Han The Thanh <thanh@pdftex.org> +Copyright 2006-2010 Taco Hoekwater <taco@luatex.org> + +This file is part of LuaTeX. + +LuaTeX is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. + +LuaTeX is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU General Public License along +with LuaTeX; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "ptexlib.h" +#include "font/writettf.h" +#include <string.h> + +#define DEFAULT_NTABS 14 +#define NEW_CMAP_SIZE 2 + +#define ttf_putchar(A) strbuf_putchar(pdf->fb, (A)) +#define ttf_offset() strbuf_offset(pdf->fb) +#define ttf_seek_outbuf(A) strbuf_seek(pdf->fb, (A)) + +unsigned char *ttf_buffer = NULL; +int ttf_size = 0; +int ttf_curbyte = 0; + +typedef struct { + /*tex the name of glyph */ + char *name; + /*tex the new index of glyph in output file */ + long newindex; + +} ttfenc_entry; + +typedef struct { + TTF_USHORT platform_id; + TTF_USHORT encoding_id; + TTF_USHORT language_id; + TTF_USHORT name_id; + TTF_USHORT length; + TTF_USHORT offset; + TTF_USHORT new_offset; + TTF_USHORT new_length; +} name_record; + +typedef struct { + char *ttf_name; + TTF_USHORT pid; + TTF_USHORT eid; + long *table; +} ttf_cmap_entry; + +static TTF_USHORT ntabs; +static TTF_USHORT upem; +static TTF_FIXED post_format; +static TTF_SHORT loca_format; +static TTF_ULONG last_glyf_offset; +static TTF_USHORT glyphs_count; +static TTF_USHORT new_glyphs_count; +static TTF_USHORT nhmtxs; +static TTF_USHORT new_ntabs; + +glyph_entry *glyph_tab; +dirtab_entry *dir_tab; + +static long *glyph_index; +static cmap_entry *cmap_tab, new_cmap_tab[NEW_CMAP_SIZE]; +static name_record *name_tab; +static int name_record_num; +static char *name_buf; +static int name_buf_size; +static char *glyph_name_buf; +static TTF_ULONG checksum; +static TTF_ULONG tab_length; +static TTF_ULONG tmp_ulong; +static TTF_ULONG checkSumAdjustment_offset; +FILE *ttf_file; +static ttfenc_entry ttfenc_tab[256]; + +/*tex A pointer to the current font descriptor: */ + +fd_entry *fd_cur; + +static struct avl_table *ttf_cmap_tree = NULL; + +int ttf_length; + +char notdef[] = ".notdef"; + +const char *mac_glyph_names[] = { + /* 0x00 */ + notdef, ".null", "CR", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", + "plus", "comma", + /* 0x10 */ + "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", "semicolon", "less", + /* 0x20 */ + "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", + /* 0x30 */ + "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "bracketleft", "backslash", + /* 0x40 */ + "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", + "e", "f", "g", "h", "i", "j", "k", "l", + /* 0x50 */ + "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "braceleft", "bar", + /* 0x60 */ + "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", + "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", + /* 0x70 */ + "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", + "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", + /* 0x80 */ + "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", + "section", "bullet", "paragraph", "germandbls", "registered", "copyright", + "trademark", "acute", "dieresis", "notequal", + /* 0x90 */ + "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", + "mu", "partialdiff", "Sigma", "Pi", "pi", "integral", "ordfeminine", + "ordmasculine", "Omega", + /* 0xa0 */ + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", + "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", + "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", + /* 0xb0 */ + "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", + "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", + "currency", "guilsinglleft", "guilsinglright", + /* 0xc0 */ + "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", + "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", + /* 0xd0 */ + "Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", "Ucircumflex", + "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", + "ring", "cedilla", "hungarumlaut", + /* 0xe0 */ + "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", + "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", + "minus", + /* 0xf0 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idot", + "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", + /* 0x100 */ + "ccaron", "dmacron" +}; + +const char *ambiguous_names[] = { + "Delta", /* increment */ + "Omega", /* Ohm */ + "Pi", /* product */ + "Sigma", /* summation */ + "dmacron", /* dslash */ + "macron", /* overscore */ + "periodcentered", /* middot */ + NULL +}; + +static const char *newtabnames[] = { + "OS/2", + "PCLT", + "cmap", + "cvt ", + "fpgm", + "glyf", + "head", + "hhea", + "hmtx", + "loca", + "maxp", + "name", + "post", + "prep" +}; + +/* Back to code. Low-level helpers first. */ + +static ttf_cmap_entry *new_ttf_cmap_entry(void) +{ + ttf_cmap_entry *e; + e = xtalloc(1, ttf_cmap_entry); + e->ttf_name = NULL; + e->table = NULL; + return e; +} + +static void destroy_ttf_cmap_entry(void *pa, void *pb) +{ + ttf_cmap_entry *p; + (void) pb; + p = (ttf_cmap_entry *) pa; + xfree(p->ttf_name); + xfree(p->table); + xfree(p); +} + +void ttf_free(void) +{ + if (ttf_cmap_tree != NULL) + avl_destroy(ttf_cmap_tree, destroy_ttf_cmap_entry); +} + +static int comp_ttf_cmap_entry(const void *pa, const void *pb, void *p) +{ + const ttf_cmap_entry *p1 = (const ttf_cmap_entry *) pa, + *p2 = (const ttf_cmap_entry *) pb; + int i; + (void) p; + if ((i = strcmp(p1->ttf_name, p2->ttf_name)) != 0) + return i; + cmp_return(p1->pid, p2->pid); + cmp_return(p1->eid, p2->eid); + return 0; +} + +static unsigned char ttf_addchksm(unsigned char b) +{ + tmp_ulong = (tmp_ulong << 8) + b; + tab_length++; + if (tab_length % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + return b; +} + +static TTF_ULONG ttf_getchksm(PDF pdf) +{ + while (tab_length % 4 != 0) { + /*tex |ttf_addchksm| updates |tab_length| */ + ttf_putchar(ttf_addchksm(0)); + } + return checksum; +} + +long ttf_putnum(PDF pdf, int s, long n) +{ + long i = n; + char buf[TTF_LONG_SIZE + 1], *p = buf; + while (s-- > 0) { + *p++ = (char) (i & 0xFF); + i >>= 8; + } + p--; + while (p >= buf) + ttf_putchar(ttf_addchksm((unsigned char) (*p--))); + return n; +} + +long ttf_getnum(int s) +{ + long i = 0; + int c; + while (s > 0) { + if (ttf_eof()) + normal_error("ttf font","unexpected EOF"); + c = ttf_getchar(); + i = (i << 8) + c; + s--; + } + return i; +} + +static long ttf_funit(long n) +{ + if (n < 0) + return -((-n / upem) * 1000 + ((-n % upem) * 1000) / upem); + else + return (n / upem) * 1000 + ((n % upem) * 1000) / upem; +} + +static void ttf_ncopy(PDF pdf, int n) +{ + while (n-- > 0) + copy_byte(); +} + +dirtab_entry *ttf_name_lookup(const char *s, boolean required) +{ + dirtab_entry *tab; + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + if (strncmp(tab->tag, s, 4) == 0) + break; + } + if (tab - dir_tab == ntabs) { + if (required) + formatted_error("ttf font","can't find table '%s'", s); + else + tab = NULL; + } + return tab; +} + +dirtab_entry *ttf_seek_tab(const char *name, TTF_LONG offset) +{ + dirtab_entry *tab = ttf_name_lookup(name, true); + ttf_curbyte = (int) (tab->offset + (unsigned long) offset); + return tab; +} + +static void ttf_seek_off(TTF_LONG offset) +{ + ttf_curbyte = (int) offset; +} + +static void ttf_copy_encoding(void) +{ + int i, *q; + void **aa; + char **glyph_names; + struct avl_traverser t; + if (fd_cur->fe != NULL) { + glyph_names = fd_cur->fe->glyph_names; + for (i = 0; i < 256; i++) + ttfenc_tab[i].name = (char *) notdef; + /*tex This is a workaround for a bug of AcroReader 4.0: */ + if (strcmp(glyph_names[97], "a") == 0) { + q = xtalloc(1, int); + *q = 'a'; + aa = avl_probe(fd_cur->tx_tree, q); + if (aa == NULL) { + /*tex Is this a problem? */ + } + } + /*tex Take over collected characters from \TeX, reencode them. */ + avl_t_init(&t, fd_cur->tx_tree); + for (q = (int *) avl_t_first(&t, fd_cur->tx_tree); q != NULL; q = (int *) avl_t_next(&t)) { + ttfenc_tab[*q].name = glyph_names[*q]; + } + make_subset_tag(fd_cur); + } +} + +#define ttf_append_byte(B) do { \ + if (name_tab[i].platform_id == 3) { \ + *q++ = 0; \ + } \ + *q++ = B; \ +} while (0) + +static char *strip_spaces_and_delims(char *s, int l) +{ + static char buf[SMALL_BUF_SIZE]; + char *p = buf; + int i; + for (i = 0; i < l; s++, i++) { + if (*s == '(' || *s == ')' || *s == '<' || *s == '>' || + *s == '[' || *s == ']' || *s == '{' || *s == '}' || + *s == '/' || *s == '%' || isspace((unsigned char)*s)) + continue; + *p++ = *s; + } + *p = 0; + return buf; +} + +static void ttf_read_name(void) +{ + int i, j; + dirtab_entry *tab = ttf_seek_tab("name", TTF_USHORT_SIZE); + char *p, buf[SMALL_BUF_SIZE]; + name_record_num = get_ushort(); + name_tab = xtalloc((unsigned) name_record_num, name_record); + name_buf_size = (int) ((unsigned) tab->length - (3 * TTF_USHORT_SIZE + (TTF_ULONG) name_record_num * 6 * TTF_USHORT_SIZE)); + name_buf = xtalloc((unsigned) name_buf_size, char); + ttf_skip(TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + name_tab[i].platform_id = get_ushort(); + name_tab[i].encoding_id = get_ushort(); + name_tab[i].language_id = get_ushort(); + name_tab[i].name_id = get_ushort(); + name_tab[i].length = get_ushort(); + name_tab[i].offset = get_ushort(); + } + for (p = name_buf; p - name_buf < name_buf_size; p++) + *p = get_char(); + /*tex Look for the \POSTSCRIPT\ font name. */ + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 1 && + name_tab[i].encoding_id == 0 && name_tab[i].name_id == 6) { + xfree(fd_cur->fontname); + fd_cur->fontname = xstrdup(strip_spaces_and_delims(name_buf + name_tab[i].offset, name_tab[i].length)); + fd_cur->font_dim[FONTNAME_CODE].set = true; + break; + } + } + if (!fd_cur->font_dim[FONTNAME_CODE].set) { + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 3 && + (name_tab[i].encoding_id == 0 || name_tab[i].encoding_id == 1) + && name_tab[i].name_id == 6) { + xfree(fd_cur->fontname); + assert(name_tab[i].length < sizeof(buf)); + for (j = 0, p = buf; j < name_tab[i].length; j += 2) + *p++ = name_buf[name_tab[i].offset + j + 1]; + *p = 0; + fd_cur->fontname = xstrdup(strip_spaces_and_delims(buf, (int) strlen(buf))); + fd_cur->font_dim[FONTNAME_CODE].set = true; + break; + } + } + } +} + +static void ttf_read_mapx(void) +{ + glyph_entry *glyph; + ttf_seek_tab("maxp", TTF_FIXED_SIZE); + glyph_tab = xtalloc((unsigned) (1 + (glyphs_count = get_ushort())), glyph_entry); + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) { + glyph->newindex = -1; + glyph->newoffset = 0; + glyph->name_index = 0; + glyph->name = (char *) notdef; + } + glyph_index = xtalloc((unsigned) (glyphs_count + 1), long); + /*tex index of the |.notdef| glyph */ + glyph_index[0] = 0; + /*tex index of the |.null| glyph */ + glyph_index[1] = 1; +} + +void ttf_read_head(void) +{ + ttf_seek_tab("head", 2 * TTF_FIXED_SIZE + 2 * TTF_ULONG_SIZE + TTF_USHORT_SIZE); + upem = get_ushort(); + ttf_skip(16); + fd_cur->font_dim[FONTBBOX1_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX2_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX3_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX4_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[FONTBBOX1_CODE].set = true; + fd_cur->font_dim[FONTBBOX2_CODE].set = true; + fd_cur->font_dim[FONTBBOX3_CODE].set = true; + fd_cur->font_dim[FONTBBOX4_CODE].set = true; + ttf_skip(2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE); + loca_format = get_short(); +} + +void ttf_read_hhea(void) +{ + ttf_seek_tab("hhea", TTF_FIXED_SIZE); + fd_cur->font_dim[ASCENT_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[DESCENT_CODE].val = (int) ttf_funit(get_fword()); + fd_cur->font_dim[ASCENT_CODE].set = true; + fd_cur->font_dim[DESCENT_CODE].set = true; + ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE); + nhmtxs = get_ushort(); +} + +void ttf_read_pclt(void) +{ + if (ttf_name_lookup("PCLT", false) == NULL) + return; + ttf_seek_tab("PCLT", TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE); + fd_cur->font_dim[XHEIGHT_CODE].val = (int) ttf_funit(get_ushort()); + ttf_skip(2 * TTF_USHORT_SIZE); + fd_cur->font_dim[CAPHEIGHT_CODE].val = (int) ttf_funit(get_ushort()); + fd_cur->font_dim[XHEIGHT_CODE].set = true; + fd_cur->font_dim[CAPHEIGHT_CODE].set = true; +} + +static void ttf_read_hmtx(void) +{ + glyph_entry *glyph; + TTF_UFWORD last_advWidth; + ttf_seek_tab("hmtx", 0); + for (glyph = glyph_tab; glyph - glyph_tab < nhmtxs; glyph++) { + glyph->advWidth = get_ufword(); + glyph->lsb = (TTF_FWORD) get_ufword(); + } + if (nhmtxs < glyphs_count) { + last_advWidth = glyph[-1].advWidth; + for (; glyph - glyph_tab < glyphs_count; glyph++) { + glyph->advWidth = last_advWidth; + glyph->lsb = (TTF_FWORD) get_ufword(); + } + } +} + +void ttf_read_post(void) +{ + int k, nnames; + long length; + long int_part, frac_part; + int sign = 1; + TTF_FIXED italic_angle; + char *p; + glyph_entry *glyph; + const dirtab_entry *tab = ttf_seek_tab("post", 0); + post_format = get_fixed(); + italic_angle = get_fixed(); + int_part = (long) (italic_angle >> 16); + if (int_part > 0x7FFF) { + /*tex a negative number */ + int_part = 0x10000 - int_part; + sign = -1; + } + frac_part = (long) (italic_angle % 0x10000); + fd_cur->font_dim[ITALIC_ANGLE_CODE].val = (int) (sign * ((double) int_part + (double) frac_part * 1.0 / 0x10000)); + fd_cur->font_dim[ITALIC_ANGLE_CODE].set = true; + if (glyph_tab == NULL) { + /*tex We were being called from |writeotf|. */ + return; + } + ttf_skip(2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + switch (post_format) { + case 0x10000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name = (const char *) mac_glyph_names[glyph - glyph_tab]; + glyph->name_index = (TTF_USHORT) (glyph - glyph_tab); + } + break; + case 0x20000: + /*tex Some fonts have this value different from |nglyphs|: */ + nnames = get_ushort(); + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) { + glyph->name_index = get_ushort(); + } + length = (long) ((long) tab->length - (long) ((long) ttf_curbyte - (long) tab->offset)); + glyph_name_buf = xtalloc((unsigned) length, char); + for (p = glyph_name_buf; p - glyph_name_buf < length;) { + for (k = get_byte(); k > 0; k--) + *p++ = get_char(); + *p++ = 0; + } + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) { + if (glyph->name_index < NMACGLYPHS) + glyph->name = mac_glyph_names[glyph->name_index]; + else { + p = glyph_name_buf; + k = glyph->name_index - NMACGLYPHS; + for (; k > 0; k--) + p = strend(p) + 1; + glyph->name = p; + } + } + break; + default: + formatted_warning("ttf font", "unsupported format '%.8X' of 'post' table, assuming 3.0", (unsigned int) post_format); + case 0x00030000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name_index = (TTF_USHORT) (glyph - glyph_tab); + } + } +} + +static void ttf_read_loca(void) +{ + glyph_entry *glyph; + ttf_seek_tab("loca", 0); + if (loca_format != 0) + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = (TTF_LONG) get_ulong(); + else + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = get_ushort() << 1; +} + +void otc_read_tabdir(int index) +{ + unsigned long i, num, rem=0; + dirtab_entry *tab; + /*tex Ignore the tag |ttcf|. */ + ttf_skip(TTF_FIXED_SIZE); + /*tex Ignore the version number. */ + ttf_skip(TTF_ULONG_SIZE); + num = get_ulong(); + for (i = 0; i < num; i++) { + if (i==index) rem = get_ulong(); else ttf_skip(TTF_ULONG_SIZE); + } + ttf_skip(rem - TTF_FIXED_SIZE - (num+2)*TTF_ULONG_SIZE); + /*tex Ignore the |sfnt| number. */ + ttf_skip(TTF_FIXED_SIZE); + dir_tab = xtalloc(ntabs = get_ushort(), dirtab_entry); + ttf_skip(3 * TTF_USHORT_SIZE); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (i = 0; i < 4; i++) + tab->tag[i] = get_char(); + tab->checksum = get_ulong(); + tab->offset = get_ulong(); + tab->length = get_ulong(); + } +} + +void ttf_read_tabdir(void) +{ + int i; + dirtab_entry *tab; + /*tex Ignore the |sfnt| number. */ + ttf_skip(TTF_FIXED_SIZE); + dir_tab = xtalloc(ntabs = get_ushort(), dirtab_entry); + ttf_skip(3 * TTF_USHORT_SIZE); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (i = 0; i < 4; i++) + tab->tag[i] = get_char(); + tab->checksum = get_ulong(); + tab->offset = get_ulong(); + tab->length = get_ulong(); + } +} + +static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid, boolean warn) +{ + seg_entry *seg_tab, *s; + TTF_USHORT *glyphId, format, segCount; + TTF_USHORT ncmapsubtabs, tmp_pid, tmp_eid; + TTF_ULONG cmap_offset, tmp_offset; + long n, i, k, length, index; + ttf_cmap_entry tmp_e, *p; + void **aa; + /*tex Look up in |ttf_cmap_tree| first, return if found. */ + tmp_e.ttf_name = ttf_name; + tmp_e.pid = (TTF_USHORT) pid; + tmp_e.eid = (TTF_USHORT) eid; + if (ttf_cmap_tree == NULL) { + ttf_cmap_tree = avl_create(comp_ttf_cmap_entry, NULL, &avl_xallocator); + assert(ttf_cmap_tree != NULL); + } + p = (ttf_cmap_entry *) avl_find(ttf_cmap_tree, &tmp_e); + if (p != NULL) + return p; + /*tex It's not found so we have to read it. We skip the table version number (0). */ + ttf_seek_tab("cmap", TTF_USHORT_SIZE); + ncmapsubtabs = get_ushort(); + cmap_offset = (TTF_ULONG) (ttf_curbyte - 2 * TTF_USHORT_SIZE); + cmap_tab = xtalloc(ncmapsubtabs, cmap_entry); + for (i = 0; i < ncmapsubtabs; ++i) { + tmp_pid = get_ushort(); + tmp_eid = get_ushort(); + tmp_offset = get_ulong(); + if (tmp_pid == pid && tmp_eid == eid) { + ttf_seek_off((TTF_LONG) (cmap_offset + tmp_offset)); + format = get_ushort(); + if (format == 4) + goto read_cmap_format_4; + else { + if (warn) { + formatted_warning("ttf font", "cmap format %i unsupported", format); + } + return NULL; + } + } + } + if (warn) { + formatted_warning("ttf font", "cannot find cmap subtable for (pid,eid) = (%i,%i)", pid, eid); + } + return NULL; + /*tex We jump here: */ + read_cmap_format_4: + /*tex Initialize the new entry. */ + p = new_ttf_cmap_entry(); + p->ttf_name = xstrdup(ttf_name); + p->pid = (TTF_USHORT) pid; + p->eid = (TTF_USHORT) eid; + p->table = xtalloc(0x10000, long); + for (i = 0; i < 0x10000; ++i) { + /*tex Yet unassigned: */ + p->table[i] = -1; + } + /*tex Read the subtable. */ + /*tex length of subtable */ + length = get_ushort(); + /*tex skip the version number */ + (void) get_ushort(); + segCount = get_ushort() / 2; + /*tex skip searchRange */ + (void) get_ushort(); + /*tex skip entrySelector */ + (void) get_ushort(); + /*tex skip rangeShift */ + (void) get_ushort(); + seg_tab = xtalloc(segCount, seg_entry); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->endCode = get_ushort(); + /*tex skip reversedPad */ + (void) get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->startCode = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idDelta = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idRangeOffset = get_ushort(); + length -= 8 * TTF_USHORT_SIZE + 4 * segCount * TTF_USHORT_SIZE; + /*tex number of glyphID's */ + n = length / TTF_USHORT_SIZE; + glyphId = xtalloc((unsigned) n, TTF_USHORT); + for (i = 0; i < n; i++) + glyphId[i] = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) { + for (i = s->startCode; i <= s->endCode; i++) { + if (i == 0xFFFF) + break; + if (s->idRangeOffset != 0xFFFF) { + if (s->idRangeOffset == 0) + index = (s->idDelta + i) & 0xFFFF; + else { + k = (i - s->startCode) + s->idRangeOffset / 2 + (s - seg_tab) - segCount; + index = glyphId[k]; + if (index != 0) + index = (index + s->idDelta) & 0xFFFF; + } + if (index >= glyphs_count) + formatted_error("ttf font", + "cmap issue, glyph index %li out of range [0..%i)", + index, glyphs_count); + if (p->table[i] != -1) + formatted_warning("ttf font", + "cmap issue, multiple glyphs are mapped to unicode %.4lX, %li will be used, %li is ignored)", + i, p->table[i], index); + else + p->table[i] = index; + } + } + } + xfree(seg_tab); + xfree(glyphId); + aa = avl_probe(ttf_cmap_tree, p); + if (aa == NULL) { + /*tex Is this a problem? */ + } + return p; +} + +static void ttf_read_font(void) +{ + ttf_read_tabdir(); + if (ttf_name_lookup("PCLT", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("fpgm", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("cvt ", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("prep", false) == NULL) + new_ntabs--; + ttf_read_mapx(); + ttf_read_head(); + ttf_read_hhea(); + ttf_read_pclt(); + ttf_read_hmtx(); + ttf_read_post(); + ttf_read_loca(); + ttf_read_name(); +} + +static void ttf_reset_chksm(PDF pdf, dirtab_entry * tab) +{ + checksum = 0; + tab_length = 0; + tmp_ulong = 0; + tab->offset = (TTF_ULONG) ttf_offset(); + if (tab->offset % 4 != 0) + formatted_warning("ttf font","offset of `%4.4s' is not a multiple of 4", tab->tag); +} + +static void ttf_set_chksm(PDF pdf, dirtab_entry * tab) +{ + tab->length = (TTF_ULONG) ttf_offset() - tab->offset; + tab->checksum = ttf_getchksm(pdf); +} + +static void ttf_copytab(PDF pdf, const char *name) +{ + long i; + dirtab_entry *tab = ttf_seek_tab(name, 0); + ttf_reset_chksm(pdf, tab); + for (i = (long) tab->length; i > 0; i--) + copy_char(); + ttf_set_chksm(pdf, tab); +} + +#define BYTE_ENCODING_LENGTH ((256)*TTF_BYTE_SIZE + 3*TTF_USHORT_SIZE) + +static void ttf_byte_encoding(PDF pdf) +{ + ttfenc_entry *e; + /*tex Format number (0: byte encoding table) */ + (void) put_ushort(0); + /*tex The length of the table */ + (void) put_ushort(BYTE_ENCODING_LENGTH); + /*tex The version number */ + (void) put_ushort(0); + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) + if (e->newindex < 256) { + put_byte(e->newindex); + } else { + if (e->name != notdef) + formatted_warning("ttf font", + "glyph '%s' has been mapped to '%s' in 'ttf_byte_encoding' cmap table", + e->name, notdef); + /*tex |.notdef|: */ + put_byte(0); + } +} + +#define TRIMMED_TABLE_MAP_LENGTH (TTF_USHORT_SIZE*(5 + (256))) + +static void ttf_trimmed_table_map(PDF pdf) +{ + ttfenc_entry *e; + /*tex format number 6: trimmed table mapping */ + (void) put_ushort(6); + (void) put_ushort(TRIMMED_TABLE_MAP_LENGTH); + /*tex version number 0 */ + (void) put_ushort(0); + /*tex first character code */ + (void) put_ushort(0); + /*tex number of character code in table: */ + (void) put_ushort(256); + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) { + (void) put_ushort(e->newindex); + } +} + +#define SEG_MAP_DELTA_LENGTH ((16 + (256))*TTF_USHORT_SIZE) + +static void ttf_seg_map_delta(PDF pdf) +{ + ttfenc_entry *e; + /*tex format number (4: segment mapping to delta values) */ + (void) put_ushort(4); + (void) put_ushort(SEG_MAP_DELTA_LENGTH); + /*tex version number */ + (void) put_ushort(0); + /*tex 2*segCount */ + (void) put_ushort(4); + /*tex searchRange */ + (void) put_ushort(4); + /*tex entrySelector */ + (void) put_ushort(1); + /*tex rangeShift */ + (void) put_ushort(0); + /*tex endCount[0] */ + (void) put_ushort(0xF0FF); + /*tex endCount[1] */ + (void) put_ushort(0xFFFF); + /*tex reversedPad */ + (void) put_ushort(0); + /*tex startCount[0] */ + (void) put_ushort(0xF000); + /*tex startCount[1] */ + (void) put_ushort(0xFFFF); + /*tex idDelta[0] */ + (void) put_ushort(0); + /*tex idDelta[1] */ + (void) put_ushort(1); + /*tex idRangeOffset[0] */ + (void) put_ushort(2 * TTF_USHORT_SIZE); + /*tex idRangeOffset[1] */ + (void) put_ushort(0); + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) { + (void) put_ushort(e->newindex); + } +} + +#define CMAP_ENTRY_LENGTH (2*TTF_USHORT_SIZE + TTF_ULONG_SIZE) + +static void ttf_select_cmap(void) +{ + /*tex Macintosh */ + new_cmap_tab[0].platform_id = 1; + /*tex Symbol; ignore code page */ + new_cmap_tab[0].encoding_id = 0; + /*tex byte encoding (0) or trimmed table mapping (6) */ + new_cmap_tab[0].format = (TTF_USHORT) (new_glyphs_count < 256 ? 0 : 6); + /*tex Microsoft */ + new_cmap_tab[1].platform_id = 3; + /*tex Symbol; ignore code page */ + new_cmap_tab[1].encoding_id = 0; + /*tex segment mapping to delta */ + new_cmap_tab[1].format = 4; +} + +static void ttf_write_cmap(PDF pdf) +{ + cmap_entry *ce; + long offset; + dirtab_entry *tab = ttf_name_lookup("cmap", true); + ttf_select_cmap(); + ttf_reset_chksm(pdf, tab); + /*tex Table version number 0. */ + (void) put_ushort(0); + /*tex Number of encoding tables. */ + (void) put_ushort(NEW_CMAP_SIZE); + offset = 2 * TTF_USHORT_SIZE + NEW_CMAP_SIZE * CMAP_ENTRY_LENGTH; + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + ce->offset = (TTF_ULONG) offset; + switch (ce->format) { + case 0: + offset += BYTE_ENCODING_LENGTH; + break; + case 4: + offset += SEG_MAP_DELTA_LENGTH; + break; + case 6: + offset += TRIMMED_TABLE_MAP_LENGTH; + break; + default: + normal_error("ttf font","invalid format (it should not have happened)"); + } + (void) put_ushort(ce->platform_id); + (void) put_ushort(ce->encoding_id); + put_ulong((long) ce->offset); + } + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + switch (ce->format) { + case 0: + ttf_byte_encoding(pdf); + break; + case 4: + ttf_seg_map_delta(pdf); + break; + case 6: + ttf_trimmed_table_map(pdf); + break; + } + } + ttf_set_chksm(pdf, tab); +} + +static int prepend_subset_tags(int index, char *p) +{ + boolean is_unicode; + int i; + is_unicode = (name_tab[index].platform_id == 3); + if (is_unicode) { + for (i = 0; i < 6; ++i) { + *p++ = 0; + *p++ = fd_cur->subset_tag[i]; + } + *p++ = 0; + *p++ = '+'; + return 14; + } else { + strncpy(p, fd_cur->subset_tag, 6); + p += 6; + *p++ = '+'; + return 7; + } +} + + +static void ttf_write_name(PDF pdf) +{ + int i, l; + char *p; + int new_name_buf_size; + char *new_name_buf; + name_record *n; + dirtab_entry *tab = ttf_name_lookup("name", true); + if (is_subsetted(fd_cur->fm)) { + l = 0; + for (i = 0; i < name_record_num; i++) { + /*tex Maximum lengh of new stogare area. */ + l += name_tab[i].length + 14; + } + new_name_buf = xtalloc((unsigned) l, char); + /*tex Additional space for subset tags. */ + p = new_name_buf; + for (i = 0; i < name_record_num; i++) { + n = name_tab + i; + n->new_offset = (TTF_USHORT) (p - new_name_buf); + if ((n->name_id == 1 || n->name_id == 3 || + n->name_id == 4 || n->name_id == 6) && + ((n->platform_id == 1 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 1))) { + l = prepend_subset_tags(i, p); + p += l; + } else + l = 0; + memcpy(p, name_buf + n->offset, n->length); + p += n->length; + n->new_length = (TTF_USHORT) (n->length + l); + } + new_name_buf_size = (int) (p - new_name_buf); + } else { + new_name_buf = name_buf; + new_name_buf_size = name_buf_size; + } + ttf_reset_chksm(pdf, tab); + (void) put_ushort(0); + /*tex Format selector. */ + (void) put_ushort(name_record_num); + (void) put_ushort(3 * TTF_USHORT_SIZE + name_record_num * 6 * TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + (void) put_ushort(name_tab[i].platform_id); + (void) put_ushort(name_tab[i].encoding_id); + (void) put_ushort(name_tab[i].language_id); + (void) put_ushort(name_tab[i].name_id); + (void) put_ushort(name_tab[i].new_length); + (void) put_ushort(name_tab[i].new_offset); + } + for (p = new_name_buf; p - new_name_buf < new_name_buf_size; p++) + put_char(*p); + ttf_set_chksm(pdf, tab); + if (new_name_buf != name_buf) + xfree(new_name_buf); +} + +static void ttf_write_dirtab(PDF pdf) +{ + dirtab_entry *tab; + TTF_ULONG i, k; + char *p; + const int save_offset = ttf_offset(); + ttf_seek_outbuf(TABDIR_OFF); + if (is_subsetted(fd_cur->fm)) { + for (i = 0; i < DEFAULT_NTABS; i++) { + tab = ttf_name_lookup(newtabnames[i], false); + if (tab == NULL) + continue; + for (k = 0; k < 4; k++) + put_char(tab->tag[k]); + put_ulong((long) tab->checksum); + put_ulong((long) tab->offset); + put_ulong((long) tab->length); + } + } else { + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (k = 0; k < 4; k++) + put_char(tab->tag[k]); + put_ulong((long) tab->checksum); + put_ulong((long) tab->offset); + put_ulong((long) tab->length); + } + } + /*tex adjust |checkSumAdjustment| */ + tmp_ulong = 0; + checksum = 0; + for (p = (char *) pdf->fb->data, i = 0; i < (unsigned) save_offset;) { + tmp_ulong = (tmp_ulong << 8) + (TTF_ULONG) * p++; + i++; + if (i % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + } + if (i % 4 != 0) { + formatted_warning("ttf font","font length '%li' is not a multiple of 4", i); + checksum <<= 8 * (4 - i % 4); + } + k = 0xB1B0AFBA - checksum; + ttf_seek_outbuf((int) checkSumAdjustment_offset); + put_ulong((long) k); + ttf_seek_outbuf(save_offset); +} + +static void ttf_write_glyf(PDF pdf) +{ + long *id, k; + TTF_USHORT idx; + TTF_USHORT flags; + dirtab_entry *tab = ttf_name_lookup("glyf", true); + const long glyf_offset = (long) tab->offset; + const long new_glyf_offset = ttf_offset(); + ttf_reset_chksm(pdf, tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph_tab[*id].newoffset = ttf_offset() - new_glyf_offset; + if (glyph_tab[*id].offset != glyph_tab[*id + 1].offset) { + ttf_seek_off(glyf_offset + glyph_tab[*id].offset); + k = copy_short(); + ttf_ncopy(pdf, 4 * TTF_FWORD_SIZE); + if (k < 0) { + do { + flags = copy_ushort(); + idx = get_ushort(); + if (glyph_tab[idx].newindex < 0) { + glyph_tab[idx].newindex = (TTF_SHORT) new_glyphs_count; + glyph_index[new_glyphs_count++] = idx; + /*tex + Here we change |new_glyphs_count|, which appears in + the condition of the |for| loop. + */ + } + (void) put_ushort(glyph_tab[idx].newindex); + if (flags & ARG_1_AND_2_ARE_WORDS) + ttf_ncopy(pdf, 2 * TTF_SHORT_SIZE); + else + ttf_ncopy(pdf, TTF_USHORT_SIZE); + if (flags & WE_HAVE_A_SCALE) + ttf_ncopy(pdf, TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + ttf_ncopy(pdf, 2 * TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_A_TWO_BY_TWO) + ttf_ncopy(pdf, 4 * TTF_F2DOT14_SIZE); + } while (flags & MORE_COMPONENTS); + if (flags & WE_HAVE_INSTRUCTIONS) + ttf_ncopy(pdf, copy_ushort()); + } else + ttf_ncopy(pdf, (int) (glyph_tab[*id + 1].offset - glyph_tab[*id].offset - TTF_USHORT_SIZE - 4 * TTF_FWORD_SIZE)); + } + } + last_glyf_offset = (TTF_ULONG) ttf_offset() - (TTF_ULONG) new_glyf_offset; + ttf_set_chksm(pdf, tab); +} + +/*tex + + Reindexing glyphs: we append index of used glyphs to |glyph_index| while + going through |ttfenc_tab|. After appending a new entry to |glyph_index| we + set field |newindex| of corresponding entries in both |glyph_tab| and + |ttfenc_tab| to the newly created index. + +*/ + +static void ttf_reindex_glyphs(void) +{ + ttfenc_entry *e; + glyph_entry *glyph; + int index; + long *t; + ttf_cmap_entry *cmap = NULL; + boolean cmap_not_found = false; + for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) { + /*tex The index of the |.notdef| glyph */ + e->newindex = 0; + /*tex Handle the case of reencoded fonts. */ + if (e->name == notdef) + continue; + /*tex Scan form |index123|. */ + if (sscanf(e->name, GLYPH_PREFIX_INDEX "%i", &index) == 1) { + if (index >= glyphs_count) { + formatted_warning("ttf font","'%s' out of valid range [0..%i)", e->name, glyphs_count); + continue; + } + glyph = glyph_tab + index; + goto append_new_glyph; + } + /*tex Scan form |uniABCD|. */ + if (sscanf(e->name, GLYPH_PREFIX_UNICODE "%X", &index) == 1) { + if (cmap == NULL && !cmap_not_found) { + /*tex Need to read the \UNICODE\ mapping, i.e. |(pid,eid) = (3,1) or (0,3)|. */ + cmap = ttf_read_cmap(fd_cur->fm->ff_name, 3, 1, false); + if (cmap == NULL) + cmap = ttf_read_cmap(fd_cur->fm->ff_name, 0, 3, false); + if (cmap == NULL) { + /*tex Once only. */ + normal_warning("ttf font", "no unicode mapping found, all 'uniXXXX' names will be ignored"); + cmap_not_found = true; + } + } + if (cmap == NULL) + continue; + t = cmap->table; + if (t[index] != -1) { + if (t[index] >= glyphs_count) { + formatted_warning("ttf font", "'%s' is mapped to index %li which is out of valid range [0..%i)", + e->name, t[index], glyphs_count); + continue; + } + glyph = glyph_tab + t[index]; + goto append_new_glyph; + } else { + formatted_warning("ttf font","unicode %s%.4X is not mapped to any glyph", GLYPH_PREFIX_UNICODE, index); + continue; + } + } + /*tex Look up by name: */ + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) + if (glyph->name != notdef && strcmp(glyph->name, e->name) == 0) + break; + if (!(glyph - glyph_tab < glyphs_count)) { + formatted_warning("ttf font","glyph '%s' not found", e->name); + continue; + } + append_new_glyph: + if (glyph->newindex < 0) { + glyph_index[new_glyphs_count] = (short) (glyph - glyph_tab); + glyph->newindex = (TTF_SHORT) new_glyphs_count; + new_glyphs_count++; + } + e->newindex = glyph->newindex; + } +} + +/*tex + + To calculate the checkSum for the 'head' table which itself includes the + checkSumAdjustment entry for the entire font, do the following: + + \startitemize + \startitem + Set the checkSumAdjustment to 0. + \stopitem + \startitem + Calculate the checksum for all the tables including the |head| table + and enter that value into the table directory. + \stopitem + \startitem + Calculate the checksum for the entire font. + \stopitem + \startitem + Subtract that value from the hex value B1B0AFBA. + \stopitem + \startitem + Store the result in checkSumAdjustment. + \stopitem + \startitemize + + The checkSum for the 'head table which includes the checkSumAdjustment entry + for the entire font is now incorrect. That is not a problem. Do not change + it. An application attempting to verify that the 'head' table has not changed + should calculate the checkSum for that table by not including the + checkSumAdjustment value, and compare the result with the entry in the table + directory. + + The table directory also includes the offset of the associated tagged table + from the beginning of the font file and the length of that table. + +*/ + +static void ttf_write_head(PDF pdf) +{ + dirtab_entry *tab; + tab = ttf_seek_tab("head", 0); + ttf_reset_chksm(pdf, tab); + ttf_ncopy(pdf, 2 * TTF_FIXED_SIZE); + checkSumAdjustment_offset = (TTF_ULONG) ttf_offset(); + put_ulong(0); + /*tex skip |checkSumAdjustment| */ + ttf_skip(TTF_ULONG_SIZE); + ttf_ncopy(pdf, TTF_ULONG_SIZE + 2 * TTF_USHORT_SIZE + 16 + 4 * TTF_FWORD_SIZE + 2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE); + if (is_subsetted(fd_cur->fm)) { + (void) put_short(loca_format); + (void) put_short(0); + } else + ttf_ncopy(pdf, 2 * TTF_SHORT_SIZE); + ttf_set_chksm(pdf, tab); +} + +static void ttf_write_hhea(PDF pdf) +{ + dirtab_entry *tab; + tab = ttf_seek_tab("hhea", 0); + ttf_reset_chksm(pdf, tab); + ttf_ncopy(pdf, TTF_FIXED_SIZE + 3 * TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE); + (void) put_ushort(new_glyphs_count); + ttf_set_chksm(pdf, tab); +} + +static void ttf_write_htmx(PDF pdf) +{ + long *id; + dirtab_entry *tab = ttf_seek_tab("hmtx", 0); + ttf_reset_chksm(pdf, tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + put_ufword(glyph_tab[*id].advWidth); + put_ufword(glyph_tab[*id].lsb); + } + ttf_set_chksm(pdf, tab); +} + +static void ttf_write_loca(PDF pdf) +{ + long *id; + dirtab_entry *tab = ttf_seek_tab("loca", 0); + ttf_reset_chksm(pdf, tab); + loca_format = 0; + if (last_glyf_offset >= 0x00020000 || (last_glyf_offset & 1)) + loca_format = 1; + else + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + if (glyph_tab[*id].newoffset & 1) { + loca_format = 1; + break; + } + if (loca_format != 0) { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + put_ulong(glyph_tab[*id].newoffset); + put_ulong((long) last_glyf_offset); + } else { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + (void) put_ushort(glyph_tab[*id].newoffset / 2); + (void) put_ushort((long) (last_glyf_offset / 2)); + } + ttf_set_chksm(pdf, tab); +} + +static void ttf_write_mapx(PDF pdf) +{ + dirtab_entry *tab = ttf_seek_tab("maxp", TTF_FIXED_SIZE + TTF_USHORT_SIZE); + ttf_reset_chksm(pdf, tab); + put_fixed(0x00010000); + (void) put_ushort(new_glyphs_count); + ttf_ncopy(pdf, 13 * TTF_USHORT_SIZE); + ttf_set_chksm(pdf, tab); +} + +static void ttf_write_OS2(PDF pdf) +{ + dirtab_entry *tab = ttf_seek_tab("OS/2", 0); + TTF_USHORT version; + ttf_reset_chksm(pdf, tab); + version = get_ushort(); + if (version > 3) { + formatted_error("ttf font","unknown version '%.4X' of OS/2 table", version); + } + /*tex fix version to 1 */ + (void) put_ushort(0x0001); + ttf_ncopy(pdf,2 * TTF_USHORT_SIZE + 13 * TTF_SHORT_SIZE + 10 * TTF_BYTE_SIZE); + /*tex |ulUnicodeRange| 1--4 */ + ttf_skip(4 * TTF_ULONG_SIZE); + /*tex Basic Latin + Latin-1 Supplement (0x0000--0x00FF) */ + put_ulong(0x00000003); + /*tex Private Use (0xE000--0xF8FF) */ + put_ulong(0x10000000); + put_ulong(0x00000000); + put_ulong(0x00000000); + /*tex |achVendID| + |fsSelection| */ + ttf_ncopy(pdf, 4 * TTF_CHAR_SIZE + TTF_USHORT_SIZE); + ttf_skip(2 * TTF_USHORT_SIZE); + /*tex |usFirstCharIndex| */ + (void) put_ushort(0x0000); + /*tex |usLastCharIndex| */ + (void) put_ushort(0xF0FF); + ttf_ncopy(pdf, 5 * TTF_USHORT_SIZE); + /*tex For version 0 the OS/2 table ends here, the rest is for version 1. */ + /*tex Symbol Character Set: don't use any code page */ + put_ulong(0x80000000); + put_ulong(0x00000000); + ttf_set_chksm(pdf, tab); +} + +static boolean unsafe_name(const char *s) +{ + const char **p; + for (p = ambiguous_names; *p != NULL; p++) + if (strcmp(s, *p) == 0) + return true; + return false; +} + +static void ttf_write_post(PDF pdf) +{ + dirtab_entry *tab = ttf_seek_tab("post", TTF_FIXED_SIZE); + glyph_entry *glyph; + const char *s; + long *id; + int k, l; + ttf_reset_chksm(pdf, tab); + if (!fd_cur->write_ttf_glyph_names || post_format == 0x00030000) { + put_fixed(0x00030000); + ttf_ncopy(pdf, TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + } else { + put_fixed(0x00020000); + ttf_ncopy(pdf, TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE); + (void) put_ushort(new_glyphs_count); + k = 0; + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS || unsafe_name(glyph->name)) + glyph->name_index = (TTF_USHORT) (NMACGLYPHS + k++); + (void) put_ushort(glyph->name_index); + } + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS) { + s = glyph->name; + l = (int) strlen(s); + put_byte(l); + while (l-- > 0) + put_char(*s++); + } + } + } + ttf_set_chksm(pdf, tab); +} + +static void ttf_init_font(PDF pdf, int n) +{ + int i, k; + for (i = 1, k = 0; i <= n; i <<= 1, k++); + /*tex font version */ + put_fixed(0x00010000); + /*tex number of tables */ + (void) put_ushort(n); + /*tex search range */ + (void) put_ushort(i << 3); + /*tex entry selector */ + (void) put_ushort(k - 1); + /*tex range shift */ + (void) put_ushort((n << 4) - (i << 3)); + ttf_seek_outbuf(TABDIR_OFF + n * 4 * TTF_ULONG_SIZE); +} + +static void ttf_subset_font(PDF pdf) +{ + ttf_init_font(pdf, new_ntabs); + if (ttf_name_lookup("PCLT", false) != NULL) + ttf_copytab(pdf, "PCLT"); + if (ttf_name_lookup("fpgm", false) != NULL) + ttf_copytab(pdf, "fpgm"); + if (ttf_name_lookup("cvt ", false) != NULL) + ttf_copytab(pdf, "cvt "); + if (ttf_name_lookup("prep", false) != NULL) + ttf_copytab(pdf, "prep"); + ttf_reindex_glyphs(); + ttf_write_glyf(pdf); + ttf_write_loca(pdf); + ttf_write_OS2(pdf); + ttf_write_head(pdf); + ttf_write_hhea(pdf); + ttf_write_htmx(pdf); + ttf_write_mapx(pdf); + ttf_write_name(pdf); + ttf_write_post(pdf); + ttf_write_cmap(pdf); + ttf_write_dirtab(pdf); +} + +static void ttf_copy_font(PDF pdf) +{ + dirtab_entry *tab; + ttf_init_font(pdf, ntabs); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + if (strncmp(tab->tag, "head", 4) == 0) + ttf_write_head(pdf); + else + ttf_copytab(pdf, tab->tag); + } + ttf_write_dirtab(pdf); +} + +void writettf(PDF pdf, fd_entry * fd) +{ + int callback_id; + int file_opened = 0; + /* The next one is global inside |writettf.c| */ + fd_cur = fd; + if (is_subsetted(fd_cur->fm) && (fd_cur->fe == NULL)) { + normal_error("ttf font","subset must be a reencoded font"); + } + ttf_curbyte = 0; + ttf_size = 0; + cur_file_name = luatex_find_file(fd_cur->fm->ff_name, find_truetype_file_callback); + if (cur_file_name == NULL) { + formatted_error("ttf font","cannot find font file for reading '%s'", fd_cur->fm->ff_name); + } + callback_id = callback_defined(read_truetype_file_callback); + if (callback_id > 0) { + if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &ttf_buffer, &ttf_size) && file_opened && ttf_size > 0) { + /* We're okay. */ + } else { + formatted_error("ttf font","cannot open font file for reading '%s'", cur_file_name); + } + } else { + if (!ttf_open(cur_file_name)) { + formatted_error("ttf font","cannot open font file for reading '%s'", cur_file_name); + } + ttf_read_file(); + ttf_close(); + } + if (tracefilenames) { + if (is_subsetted(fd_cur->fm)) + tex_printf("<%s", cur_file_name); + else + tex_printf("<<%s", cur_file_name); + } + fd_cur->ff_found = true; + new_glyphs_count = 2; + new_ntabs = DEFAULT_NTABS; + dir_tab = NULL; + glyph_tab = NULL; + glyph_index = NULL; + glyph_name_buf = NULL; + name_tab = NULL; + name_buf = NULL; + ttf_read_font(); + pdf_save_offset(pdf); + pdf_flush(pdf); + if (is_subsetted(fd_cur->fm)) { + ttf_copy_encoding(); + ttf_subset_font(pdf); + } else + ttf_copy_font(pdf); + ttf_length = ttf_offset(); + xfree(dir_tab); + xfree(glyph_tab); + xfree(glyph_index); + xfree(glyph_name_buf); + xfree(name_tab); + xfree(name_buf); + if (tracefilenames) { + if (is_subsetted(fd_cur->fm)) + tex_printf(">"); + else + tex_printf(">>"); + } + xfree(ttf_buffer); + cur_file_name = NULL; +} + +static void do_writeotf(PDF pdf, fd_entry * fd) +{ + long i; + dirtab_entry *tab; + (void) fd; + dir_tab = NULL; + glyph_tab = NULL; + if (tracefilenames) + tex_printf("<<%s", cur_file_name); + ttf_read_tabdir(); + /*tex Read teh font parameters. */ + if (ttf_name_lookup("head", false) != NULL) + ttf_read_head(); + if (ttf_name_lookup("hhea", false) != NULL) + ttf_read_hhea(); + if (ttf_name_lookup("PCLT", false) != NULL) + ttf_read_pclt(); + if (ttf_name_lookup("post", false) != NULL) + ttf_read_post(); + /*tex Copy the font file: */ + if (ttf_name_lookup("CFF2", false) != NULL) + tab = ttf_seek_tab("CFF2", 0); + else + tab = ttf_seek_tab("CFF ", 0); + for (i = (long) tab->length; i > 0; i--) { + copy_char(); + } + xfree(dir_tab); + if (tracefilenames) + tex_printf(">>"); +} + +void writeotf(PDF pdf, fd_entry * fd) +{ + int callback_id; + int file_opened = 0; + fd_cur = fd; + ttf_curbyte = 0; + ttf_size = 0; + cur_file_name = luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback); + if (cur_file_name == NULL) { + formatted_error("otf font","cannot find font file for reading '%s'", fd_cur->fm->ff_name); + } + callback_id = callback_defined(read_opentype_file_callback); + if (callback_id > 0) { + if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &ttf_buffer, &ttf_size) && file_opened && ttf_size > 0) { + /*tex We're okay. */ + } else { + formatted_error("otf font","cannot open font file for reading '%s'", cur_file_name); + } + } else { + if (!otf_open(cur_file_name)) { + formatted_error("otf font","cannot open font file for reading '%s'", cur_file_name); + } + ttf_read_file(); + ttf_close(); + } + fd_cur->ff_found = true; + do_writeotf(pdf, fd); + xfree(ttf_buffer); + cur_file_name = NULL; +} + |