+static table_head_t*head_new(ttf_t*ttf)
+{
+ table_head_t*head = rfx_calloc(sizeof(table_head_t));
+ head->units_per_em = 1024;
+ int t;
+ if(ttf->num_glyphs) {
+ head->xmin = ttf->glyphs[0].xmin;
+ head->ymin = ttf->glyphs[0].ymin;
+ head->xmax = ttf->glyphs[0].xmax;
+ head->ymax = ttf->glyphs[0].ymax;
+ for(t=1;t<ttf->num_glyphs;t++) {
+ if(ttf->glyphs[t].xmin < head->xmin) head->xmin = ttf->glyphs[t].xmin;
+ if(ttf->glyphs[t].ymin < head->ymin) head->ymin = ttf->glyphs[t].ymin;
+ if(ttf->glyphs[t].xmax > head->xmax) head->xmax = ttf->glyphs[t].xmax;
+ if(ttf->glyphs[t].ymax > head->ymax) head->ymax = ttf->glyphs[t].ymax;
+ }
+ }
+ head->macStyle = 0;
+ head->lowest_readable_size = 8; // not sure what font renderers actually do with this
+ head->dir_hint = 0;
+ return head;
+}
+static int head_parse(ttf_t*ttf, memreader_t*r)
+{
+ ttf->head = rfx_calloc(sizeof(table_head_t));
+ U32 version = readU32(r);
+ if(version!=VERSION_1_0)
+ msg("<warning> Font HEAD has unknown version %08x", version);
+ U32 revision = readU32(r);
+ U32 checksum2 = readU32(r);
+ U32 magic = readU32(r);
+ if(magic!=0x5f0f3cf5)
+ msg("<warning> Font HEAD has unknown magic number %08x", magic);
+ ttf->head->flags = readU16(r);
+ ttf->head->units_per_em = readU16(r);
+ readU32(r);readU32(r); //created
+ readU32(r);readU32(r); //modified
+ ttf->head->xmin = readU16(r);
+ ttf->head->ymin = readU16(r);
+ ttf->head->xmax = readU16(r);
+ ttf->head->ymax = readU16(r);
+ ttf->head->macStyle = readU16(r);
+ ttf->head->lowest_readable_size = readU16(r); //in pixels
+ ttf->head->dir_hint = readS16(r);
+ int loc_index = readS16(r); //used in 'loca' table
+ if(loc_index>1)
+ msg("<warning> loca index format %d unknown", loc_index);
+ U16 glyph_data_format = readS16(r);
+ if(glyph_data_format!=0)
+ msg("<warning> Font glyph data format unknown: %04x", glyph_data_format);
+ if(r->pos < r->size) {
+ msg("<warning> Leftover bytes (%d) in HEAD tag", r->size - r->pos);
+ }
+ return loc_index;
+}
+static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size)
+{
+ writeU32(w, 0x10000);
+ writeU32(w, 0x10000);
+ writeU32(w, 0); //checksum
+ writeU32(w, 0x5f0f3cf5); //magic
+ writeU16(w, ttf->head->flags);
+ writeU16(w, ttf->head->units_per_em);
+ writeU32(w, 0);writeU32(w, 0); //created
+ writeU32(w, 0);writeU32(w, 0); //modified
+ writeU16(w, ttf->head->xmin);
+ writeU16(w, ttf->head->ymin);
+ writeU16(w, ttf->head->xmax);
+ writeU16(w, ttf->head->ymax);
+ writeU16(w, ttf->head->macStyle);
+ writeU16(w, ttf->head->lowest_readable_size);
+ writeS16(w, ttf->head->dir_hint);
+ writeS16(w, loca_size); //loca index size (32 bit)
+ writeS16(w, 0); //glyph data format
+}
+static void head_dump(ttf_t*ttf)
+{
+ printf("head->flags: %d\n", ttf->head->flags);
+ printf("head->units_per_em: %d\n", ttf->head->units_per_em);
+ printf("head->xmin: %d\n", ttf->head->xmin);
+ printf("head->ymin: %d\n", ttf->head->ymin);
+ printf("head->xmax: %d\n", ttf->head->xmax);
+ printf("head->ymax: %d\n", ttf->head->ymax);
+ printf("head->macStyle: %d\n", ttf->head->macStyle);
+ printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size);
+ printf("head->dir_hint: %d\n", ttf->head->dir_hint);
+}
+static void head_delete(ttf_t*ttf)
+{
+ if(ttf->head) {
+ free(ttf->head);
+ ttf->head=0;
+ }
+}
+
+static table_os2_t*os2_new(ttf_t*ttf)
+{
+ table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t));
+ if(ttf->num_glyphs) {
+ int average_width=0;
+ int t;
+ for(t=0;t<ttf->num_glyphs;t++) {
+ average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing);
+ }
+ os2->xAvgCharWidth = average_width / ttf->num_glyphs;
+ }
+
+ /* that's what everybody seems to fill in */
+ os2->usWeightClass = 400;
+ os2->usWidthClass = 5;
+
+ if(ttf->head) {
+ int advance = (ttf->head->xmax - ttf->head->xmin)/2;
+ int height = (ttf->head->xmax - ttf->head->xmin);
+ int ymid = height/2;
+ /* I do believe a sane font rendering engine will actually use
+ the font advance here- the subscript/superscript position will
+ not be the same for each glyph */
+ os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2;
+ os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2;
+ os2->ySubscriptXOffset = advance;
+ os2->ySubscriptYOffset = 0;
+ os2->ySuperscriptXOffset = advance;
+ os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2;
+ os2->yStrikeoutSize = ttf->head->units_per_em / 10;
+ os2->yStrikeoutPosition = ymid;
+ os2->usWinAscent = ttf->head->ymax;
+ os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin;
+ os2->sxHeight = ymid;
+ os2->sCapHeight = height*2/3;
+ }
+ os2->panose_Weight = 4;
+
+ /* strictly speaking we'd have to set 92/64 bits in these tables, depending on
+ what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */
+ os2->ulCharRange[0] = 1;
+ os2->ulCharRange[1] = 0;
+ os2->ulCharRange[2] = 0;
+ os2->ulCharRange[3] = 0;
+ os2->ulCodePageRange1 = 1;
+ os2->ulCodePageRange2 = 0;
+
+ if(ttf->unicode_size) {
+ int min,max;
+ for(min=0;min<ttf->unicode_size;min++)
+ if(ttf->unicode[min]) break;
+ for(max=ttf->unicode_size-1;max>=0;max--)
+ if(ttf->unicode[max]) break;
+ if(min<=max) {
+ os2->fsFirstCharIndex = min;
+ os2->fsLastCharIndex = max;
+ }
+ }
+ os2->sTypoAscender = ttf->ascent;
+ os2->sTypoDescender = ttf->descent;
+ os2->sTypoLineGap = ttf->lineGap;
+
+ os2->usDefaultChar = 0;
+ os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0;
+ os2->usMaxContext = 0; // we don't use ligatures yet
+ return os2;
+}