summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/tt_glyf.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tt_glyf.w669
1 files changed, 669 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/tt_glyf.w b/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
new file mode 100644
index 00000000000..b22d5748284
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
@@ -0,0 +1,669 @@
+% tt_glyf.w
+%
+% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
+% 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/>.
+
+@* Subsetting glyf, updating loca, hmtx, etc.
+
+@ @c
+#include "ptexlib.h"
+
+#include "font/sfnt.h"
+#include "font/tt_table.h"
+#include "font/tt_glyf.h"
+#include "font/writettf.h"
+
+static const char _svn_version[] =
+ "$Id: tt_glyf.w 3584 2010-04-02 17:45:55Z hhenkel $ "
+"$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/font/tt_glyf.w $";
+
+@ @c
+#define NUM_GLYPH_LIMIT 65534
+#define TABLE_DATA_ALLOC_SIZE 40960
+#define GLYPH_ARRAY_ALLOC_SIZE 256
+
+static USHORT find_empty_slot(struct tt_glyphs *g)
+{
+ USHORT gid;
+
+ ASSERT(g);
+
+ for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
+ if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
+ break;
+ }
+ if (gid == NUM_GLYPH_LIMIT)
+ TT_ERROR("No empty glyph slot available.");
+
+ return gid;
+}
+
+USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
+{
+ USHORT idx, new_gid = 0;
+
+ ASSERT(g);
+
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (gid == g->gd[idx].ogid) {
+ new_gid = g->gd[idx].gid;
+ break;
+ }
+ }
+
+ return new_gid;
+}
+
+USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
+{
+ USHORT idx;
+
+ ASSERT(g);
+
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (gid == g->gd[idx].gid)
+ break;
+ }
+ if (idx == g->num_glyphs)
+ idx = 0;
+
+ return idx;
+}
+
+USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
+{
+ ASSERT(g);
+
+ if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
+ WARN("Slot %u already used.", new_gid);
+ } else {
+ if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
+ TT_ERROR("Too many glyphs.");
+
+ if (g->num_glyphs >= g->max_glyphs) {
+ g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
+ g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
+ }
+ g->gd[g->num_glyphs].gid = new_gid;
+ g->gd[g->num_glyphs].ogid = gid;
+ g->gd[g->num_glyphs].length = 0;
+ g->gd[g->num_glyphs].data = NULL;
+ g->used_slot[new_gid / 8] =
+ (unsigned char) (g->used_slot[new_gid /
+ 8] | (1 << (7 - (new_gid % 8))));
+ g->num_glyphs++;
+ }
+
+ if (new_gid > g->last_gid) {
+ g->last_gid = new_gid;
+ }
+
+ return new_gid;
+}
+
+
+@ Initialization
+@c
+struct tt_glyphs *tt_build_init(void)
+{
+ struct tt_glyphs *g;
+
+ g = NEW(1, struct tt_glyphs);
+
+ g->num_glyphs = 0;
+ g->max_glyphs = 0;
+ g->last_gid = 0;
+ g->emsize = 1;
+ g->default_advh = 0;
+ g->default_tsb = 0;
+ g->gd = NULL;
+ g->used_slot = NEW(8192, unsigned char);
+ memset(g->used_slot, 0, 8192);
+ tt_add_glyph(g, 0, 0);
+
+ return g;
+}
+
+void tt_build_finish(struct tt_glyphs *g)
+{
+ if (g) {
+ if (g->gd) {
+ USHORT idx;
+ for (idx = 0; idx < g->num_glyphs; idx++) {
+ if (g->gd[idx].data)
+ RELEASE(g->gd[idx].data);
+ }
+ RELEASE(g->gd);
+ }
+ if (g->used_slot)
+ RELEASE(g->used_slot);
+ RELEASE(g);
+ }
+}
+
+static int glyf_cmp(const void *v1, const void *v2)
+{
+ int cmp = 0;
+ const struct tt_glyph_desc *sv1, *sv2;
+
+ sv1 = (const struct tt_glyph_desc *) v1;
+ sv2 = (const struct tt_glyph_desc *) v2;
+
+ if (sv1->gid == sv2->gid)
+ cmp = 0;
+ else if (sv1->gid < sv2->gid)
+ cmp = -1;
+ else
+ cmp = 1;
+
+ return cmp;
+}
+
+@ @c
+int tt_build_tables(sfnt * sfont, struct tt_glyphs *g)
+{
+ char *hmtx_table_data = NULL, *loca_table_data = NULL;
+ char *glyf_table_data = NULL;
+ ULONG hmtx_table_size, loca_table_size, glyf_table_size;
+ /* some information available from other TrueType table */
+ struct tt_head_table *head = NULL;
+ struct tt_hhea_table *hhea = NULL;
+ struct tt_maxp_table *maxp = NULL;
+ struct tt_longMetrics *hmtx, *vmtx = NULL;
+ struct tt_os2__table *os2;
+ /* temp */
+ ULONG *location, offset;
+ long i;
+ USHORT *w_stat; /* Estimate most frequently appeared width */
+
+ ASSERT(g);
+
+ if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+ TT_ERROR("Invalid font type");
+
+ if (g->num_glyphs > NUM_GLYPH_LIMIT)
+ TT_ERROR("Too many glyphs.");
+
+ /*
+ Read head, hhea, maxp, loca:
+
+ unitsPerEm --> head
+
+ numHMetrics --> hhea
+
+ indexToLocFormat --> head
+
+ numGlyphs --> maxp
+ */
+ head = tt_read_head_table(sfont);
+ hhea = tt_read_hhea_table(sfont);
+ maxp = tt_read_maxp_table(sfont);
+
+ if (hhea->metricDataFormat != 0)
+ TT_ERROR("Unknown metricDataFormat.");
+
+ g->emsize = head->unitsPerEm;
+
+ sfnt_locate_table(sfont, "hmtx");
+ hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+
+ os2 = tt_read_os2__table(sfont);
+ if (os2) {
+ g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+ g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+
+ /* dvipdfmx does this elsewhere! */
+ fd_cur->font_dim[STEMV_CODE].val =
+ (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
+ }
+
+ if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+ struct tt_vhea_table *vhea;
+ vhea = tt_read_vhea_table(sfont);
+ sfnt_locate_table(sfont, "vmtx");
+ vmtx =
+ tt_read_longMetrics(sfont, maxp->numGlyphs,
+ vhea->numOfLongVerMetrics);
+ RELEASE(vhea);
+ } else {
+ vmtx = NULL;
+ }
+
+ sfnt_locate_table(sfont, "loca");
+ location = NEW(maxp->numGlyphs + 1, ULONG);
+ if (head->indexToLocFormat == 0) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+ } else if (head->indexToLocFormat == 1) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = sfnt_get_ulong(sfont);
+ } else {
+ TT_ERROR("Unknown IndexToLocFormat.");
+ }
+
+ w_stat = NEW(g->emsize + 2, USHORT);
+ memset(w_stat, 0,
+ (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
+ /*
+ * Read glyf table.
+ */
+ offset = sfnt_locate_table(sfont, "glyf");
+ /*
+ The |num_glyphs| may grow when composite glyph is found.
+ A component of glyph refered by a composite glyph is appended
+ to |used_glyphs| if it is not already registered in |used_glyphs|.
+ Glyph programs of composite glyphs are modified so that it
+ correctly refer to new gid of their components.
+ */
+ for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
+ USHORT gid; /* old gid */
+ ULONG loc, len;
+ BYTE *p, *endptr;
+ SHORT number_of_contours;
+
+ if (i >= g->num_glyphs) /* finished */
+ break;
+
+ gid = g->gd[i].ogid;
+ if (gid >= maxp->numGlyphs)
+ TT_ERROR("Invalid glyph index (gid %u)", gid);
+
+ loc = location[gid];
+ len = location[gid + 1] - loc;
+ g->gd[i].advw = hmtx[gid].advance;
+ g->gd[i].lsb = hmtx[gid].sideBearing;
+ if (vmtx) {
+ g->gd[i].advh = vmtx[gid].advance;
+ g->gd[i].tsb = vmtx[gid].sideBearing;
+ } else {
+ g->gd[i].advh = g->default_advh;
+ g->gd[i].tsb = g->default_tsb;
+ }
+ g->gd[i].length = len;
+ g->gd[i].data = NULL;
+ if (g->gd[i].advw <= g->emsize) {
+ w_stat[g->gd[i].advw]++;
+ } else {
+ w_stat[g->emsize + 1]++; /* larger than em */
+ }
+
+ if (len == 0) { /* Does not contains any data. */
+ continue;
+ } else if (len < 10) {
+ TT_ERROR("Invalid TrueType glyph data (gid %u).", gid);
+ }
+
+ g->gd[i].data = p = NEW(len, BYTE);
+ endptr = p + len;
+
+ sfnt_seek_set(sfont, (long) (offset + loc));
+ number_of_contours = sfnt_get_short(sfont);
+ p += sfnt_put_short(p, number_of_contours);
+
+ /* BoundingBox: FWord x 4 */
+ g->gd[i].llx = sfnt_get_short(sfont);
+ g->gd[i].lly = sfnt_get_short(sfont);
+ g->gd[i].urx = sfnt_get_short(sfont);
+ g->gd[i].ury = sfnt_get_short(sfont);
+ /* |_FIXME_| */
+#if 1
+ if (!vmtx) /* |vertOriginY == sTypeAscender| */
+ g->gd[i].tsb =
+ (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+#endif
+ p += sfnt_put_short(p, g->gd[i].llx);
+ p += sfnt_put_short(p, g->gd[i].lly);
+ p += sfnt_put_short(p, g->gd[i].urx);
+ p += sfnt_put_short(p, g->gd[i].ury);
+
+ /* Read evrything else. */
+ sfnt_read(p, (int) len - 10, sfont);
+ /*
+ Fix GIDs of composite glyphs.
+ */
+ if (number_of_contours < 0) {
+ USHORT flags, cgid, new_gid; /* flag, gid of a component */
+ do {
+ if (p >= endptr)
+ TT_ERROR("Invalid TrueType glyph data (gid %u): %u bytes",
+ gid, (unsigned int) len);
+ /*
+ * Flags and gid of component glyph are both USHORT.
+ */
+ flags = (USHORT) (((*p) << 8) | *(p + 1));
+ p += 2;
+ cgid = (USHORT) (((*p) << 8) | *(p + 1));
+ if (cgid >= maxp->numGlyphs) {
+ TT_ERROR("Invalid gid (%u > %u) in composite glyph %u.",
+ cgid, maxp->numGlyphs, gid);
+ }
+ new_gid = tt_find_glyph(g, cgid);
+ if (new_gid == 0) {
+ new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
+ }
+ p += sfnt_put_ushort(p, new_gid);
+ /*
+ * Just skip remaining part.
+ */
+ p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
+ if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
+ p += 2;
+ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
+ p += 4;
+ else if (flags & WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
+ p += 8;
+ } while (flags & MORE_COMPONENTS);
+ /*
+ TrueType instructions comes here:
+
+ |length_of_instruction| (|ushort|)
+
+ instruction (|byte * length_of_instruction|)
+ */
+ }
+ }
+ RELEASE(location);
+ RELEASE(hmtx);
+ if (vmtx)
+ RELEASE(vmtx);
+
+ {
+ int max_count = -1;
+
+ g->dw = g->gd[0].advw;
+ for (i = 0; i < g->emsize + 1; i++) {
+ if (w_stat[i] > max_count) {
+ max_count = w_stat[i];
+ g->dw = (USHORT) i;
+ }
+ }
+ }
+ RELEASE(w_stat);
+
+ qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
+ {
+ USHORT prev, last_advw;
+ char *p, *q;
+ int padlen, num_hm_known;
+
+ glyf_table_size = 0UL;
+ num_hm_known = 0;
+ last_advw = g->gd[g->num_glyphs - 1].advw;
+ for (i = g->num_glyphs - 1; i >= 0; i--) {
+ padlen =
+ (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+ glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
+ if (!num_hm_known && last_advw != g->gd[i].advw) {
+ hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
+ num_hm_known = 1;
+ }
+ }
+ /* All advance widths are same. */
+ if (!num_hm_known) {
+ hhea->numberOfHMetrics = 1;
+ }
+ hmtx_table_size =
+ (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
+
+ /*
+ Choosing short format does not always give good result
+ when compressed. Sometimes increases size.
+ */
+ if (glyf_table_size < 0x20000UL) {
+ head->indexToLocFormat = 0;
+ loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
+ } else {
+ head->indexToLocFormat = 1;
+ loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
+ }
+
+ hmtx_table_data = p = NEW(hmtx_table_size, char);
+ loca_table_data = q = NEW(loca_table_size, char);
+ glyf_table_data = NEW(glyf_table_size, char);
+
+ offset = 0UL;
+ prev = 0;
+ for (i = 0; i < g->num_glyphs; i++) {
+ long gap, j;
+ gap = (long) g->gd[i].gid - prev - 1;
+ for (j = 1; j <= gap; j++) {
+ if (prev + j == hhea->numberOfHMetrics - 1) {
+ p += sfnt_put_ushort(p, last_advw);
+ } else if (prev + j < hhea->numberOfHMetrics) {
+ p += sfnt_put_ushort(p, 0);
+ }
+ p += sfnt_put_short(p, 0);
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+ }
+ padlen =
+ (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+ if (g->gd[i].gid < hhea->numberOfHMetrics) {
+ p += sfnt_put_ushort(p, g->gd[i].advw);
+ }
+ p += sfnt_put_short(p, g->gd[i].lsb);
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+ memset(glyf_table_data + offset, 0,
+ (size_t) (g->gd[i].length + (ULONG) padlen));
+ memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
+ offset += (g->gd[i].length + (ULONG) padlen);
+ prev = g->gd[i].gid;
+ /* free data here since it consume much memory */
+ RELEASE(g->gd[i].data);
+ g->gd[i].length = 0;
+ g->gd[i].data = NULL;
+ }
+ if (head->indexToLocFormat == 0) {
+ q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+ } else {
+ q += sfnt_put_ulong(q, (LONG) offset);
+ }
+
+ sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data,
+ hmtx_table_size);
+ sfnt_set_table(sfont, "loca", (char *) loca_table_data,
+ loca_table_size);
+ sfnt_set_table(sfont, "glyf", (char *) glyf_table_data,
+ glyf_table_size);
+ }
+
+ head->checkSumAdjustment = 0;
+ maxp->numGlyphs = (USHORT) (g->last_gid + 1);
+
+ /* TODO */
+ sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
+ sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
+ sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
+ RELEASE(maxp);
+ RELEASE(hhea);
+ RELEASE(head);
+ if (os2)
+ RELEASE(os2);
+
+ return 0;
+}
+
+int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
+{
+ struct tt_head_table *head = NULL;
+ struct tt_hhea_table *hhea = NULL;
+ struct tt_maxp_table *maxp = NULL;
+ struct tt_longMetrics *hmtx, *vmtx = NULL;
+ struct tt_os2__table *os2;
+ /* temp */
+ ULONG *location, offset;
+ long i;
+ USHORT *w_stat;
+
+ ASSERT(g);
+
+ if (sfont == NULL ||
+#ifdef XETEX
+ sfont->ft_face == NULL
+#elif defined(pdfTeX)
+ sfont->buffer == NULL
+#else
+ sfont->stream == NULL
+#endif
+ )
+ TT_ERROR("File not opened.");
+
+ if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+ TT_ERROR("Invalid font type");
+
+ /*
+ Read head, hhea, maxp, loca:
+
+ unitsPerEm --> head
+
+ numHMetrics --> hhea
+
+ indexToLocFormat --> head
+
+ numGlyphs --> maxp
+ */
+ head = tt_read_head_table(sfont);
+ hhea = tt_read_hhea_table(sfont);
+ maxp = tt_read_maxp_table(sfont);
+
+ if (hhea->metricDataFormat != 0)
+ TT_ERROR("Unknown metricDataFormat.");
+
+ g->emsize = head->unitsPerEm;
+
+ sfnt_locate_table(sfont, "hmtx");
+ hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+
+ os2 = tt_read_os2__table(sfont);
+ g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+ g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+
+ if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+ struct tt_vhea_table *vhea;
+ vhea = tt_read_vhea_table(sfont);
+ sfnt_locate_table(sfont, "vmtx");
+ vmtx =
+ tt_read_longMetrics(sfont, maxp->numGlyphs,
+ vhea->numOfLongVerMetrics);
+ RELEASE(vhea);
+ } else {
+ vmtx = NULL;
+ }
+
+ sfnt_locate_table(sfont, "loca");
+ location = NEW(maxp->numGlyphs + 1, ULONG);
+ if (head->indexToLocFormat == 0) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+ } else if (head->indexToLocFormat == 1) {
+ for (i = 0; i <= maxp->numGlyphs; i++)
+ location[i] = sfnt_get_ulong(sfont);
+ } else {
+ TT_ERROR("Unknown IndexToLocFormat.");
+ }
+
+ w_stat = NEW(g->emsize + 2, USHORT);
+ memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
+ /*
+ Read glyf table.
+ */
+ offset = sfnt_locate_table(sfont, "glyf");
+ for (i = 0; i < g->num_glyphs; i++) {
+ USHORT gid; /* old gid */
+ ULONG loc, len;
+ SHORT number_of_contours;
+
+ gid = g->gd[i].ogid;
+ if (gid >= maxp->numGlyphs)
+ TT_ERROR("Invalid glyph index (gid %u)", gid);
+
+ loc = location[gid];
+ len = location[gid + 1] - loc;
+ g->gd[i].advw = hmtx[gid].advance;
+ g->gd[i].lsb = hmtx[gid].sideBearing;
+ if (vmtx) {
+ g->gd[i].advh = vmtx[gid].advance;
+ g->gd[i].tsb = vmtx[gid].sideBearing;
+ } else {
+ g->gd[i].advh = g->default_advh;
+ g->gd[i].tsb = g->default_tsb;
+ }
+ g->gd[i].length = len;
+ g->gd[i].data = NULL;
+
+ if (g->gd[i].advw <= g->emsize) {
+ w_stat[g->gd[i].advw]++;
+ } else {
+ w_stat[g->emsize + 1]++; /* larger than em */
+ }
+
+ if (len == 0) { /* Does not contains any data. */
+ continue;
+ } else if (len < 10) {
+ TT_ERROR("Invalid TrueType glyph data (gid %u).", gid);
+ }
+
+ sfnt_seek_set(sfont, (long) (offset + loc));
+ number_of_contours = sfnt_get_short(sfont);
+
+ /* BoundingBox: FWord x 4 */
+ g->gd[i].llx = sfnt_get_short(sfont);
+ g->gd[i].lly = sfnt_get_short(sfont);
+ g->gd[i].urx = sfnt_get_short(sfont);
+ g->gd[i].ury = sfnt_get_short(sfont);
+ /* |_FIXME_| */
+#if 1
+ if (!vmtx) /* |vertOriginY == sTypeAscender| */
+ g->gd[i].tsb =
+ (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+#endif
+ }
+ RELEASE(location);
+ RELEASE(hmtx);
+ RELEASE(maxp);
+ RELEASE(hhea);
+ RELEASE(head);
+ RELEASE(os2);
+
+ if (vmtx)
+ RELEASE(vmtx);
+
+ {
+ int max_count = -1;
+
+ g->dw = g->gd[0].advw;
+ for (i = 0; i < g->emsize + 1; i++) {
+ if (w_stat[i] > max_count) {
+ max_count = w_stat[i];
+ g->dw = (USHORT) i;
+ }
+ }
+ }
+ RELEASE(w_stat);
+
+
+ return 0;
+}