diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c new file mode 100644 index 00000000000..da09b2b3bee --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c @@ -0,0 +1,237 @@ +#include "support/util.h" +#include "otfcc/table/otl/classdef.h" + +static INLINE void disposeClassDef(otl_ClassDef *cd) { + if (cd->glyphs) { + for (glyphid_t j = 0; j < cd->numGlyphs; j++) { + Handle.dispose(&cd->glyphs[j]); + } + FREE(cd->glyphs); + } + FREE(cd->classes); +} +caryll_standardRefTypeFn(otl_ClassDef, disposeClassDef); + +static void growClassdef(otl_ClassDef *cd, uint32_t n) { + if (!n) return; + if (n > cd->capacity) { + if (!cd->capacity) cd->capacity = 0x10; + while (n > cd->capacity) + cd->capacity += (cd->capacity >> 1) & 0xFFFFFF; + RESIZE(cd->glyphs, cd->capacity); + RESIZE(cd->classes, cd->capacity); + } +} +static void pushClassDef(otl_ClassDef *cd, MOVE otfcc_GlyphHandle h, glyphclass_t cls) { + cd->numGlyphs += 1; + growClassdef(cd, cd->numGlyphs); + cd->glyphs[cd->numGlyphs - 1] = h; + cd->classes[cd->numGlyphs - 1] = cls; + if (cls > cd->maxclass) cd->maxclass = cls; +} + +typedef struct { + int gid; + int covIndex; + UT_hash_handle hh; +} coverage_entry; + +static int by_covIndex(coverage_entry *a, coverage_entry *b) { + return a->covIndex - b->covIndex; +} + +static otl_ClassDef *readClassDef(const uint8_t *data, uint32_t tableLength, uint32_t offset) { + otl_ClassDef *cd = otl_iClassDef.create(); + if (tableLength < offset + 4) return cd; + uint16_t format = read_16u(data + offset); + if (format == 1 && tableLength >= offset + 6) { + glyphid_t startGID = read_16u(data + offset + 2); + glyphid_t count = read_16u(data + offset + 4); + if (count && tableLength >= offset + 6 + count * 2) { + for (glyphid_t j = 0; j < count; j++) { + pushClassDef(cd, Handle.fromIndex(startGID + j), read_16u(data + offset + 6 + j * 2)); + } + return cd; + } + } else if (format == 2) { + // The ranges may overlap. + // Use hashtable. + uint16_t rangeCount = read_16u(data + offset + 2); + if (tableLength < offset + 4 + rangeCount * 6) return cd; + coverage_entry *hash = NULL; + for (uint16_t j = 0; j < rangeCount; j++) { + uint16_t start = read_16u(data + offset + 4 + 6 * j); + uint16_t end = read_16u(data + offset + 4 + 6 * j + 2); + uint16_t cls = read_16u(data + offset + 4 + 6 * j + 4); + for (int k = start; k <= end; k++) { + coverage_entry *item = NULL; + HASH_FIND_INT(hash, &k, item); + if (!item) { + NEW(item); + item->gid = k; + item->covIndex = cls; + HASH_ADD_INT(hash, gid, item); + } + } + } + HASH_SORT(hash, by_covIndex); + coverage_entry *e, *tmp; + HASH_ITER(hh, hash, e, tmp) { + pushClassDef(cd, Handle.fromIndex(e->gid), e->covIndex); + HASH_DEL(hash, e); + FREE(e); + } + return cd; + } + return cd; +} + +static otl_ClassDef *expandClassDef(otl_Coverage *cov, otl_ClassDef *ocd) { + otl_ClassDef *cd = otl_iClassDef.create(); + coverage_entry *hash = NULL; + for (glyphid_t j = 0; j < ocd->numGlyphs; j++) { + int gid = ocd->glyphs[j].index; + int cid = ocd->classes[j]; + coverage_entry *item = NULL; + HASH_FIND_INT(hash, &gid, item); + if (!item) { + NEW(item); + item->gid = gid; + item->covIndex = cid; + HASH_ADD_INT(hash, gid, item); + } + } + for (glyphid_t j = 0; j < cov->numGlyphs; j++) { + int gid = cov->glyphs[j].index; + coverage_entry *item = NULL; + HASH_FIND_INT(hash, &gid, item); + if (!item) { + NEW(item); + item->gid = gid; + item->covIndex = 0; + HASH_ADD_INT(hash, gid, item); + } + } + coverage_entry *e, *tmp; + HASH_ITER(hh, hash, e, tmp) { + pushClassDef(cd, Handle.fromIndex(e->gid), e->covIndex); + HASH_DEL(hash, e); + FREE(e); + } + otl_iClassDef.free(ocd); + return cd; +} + +static json_value *dumpClassDef(const otl_ClassDef *cd) { + json_value *a = json_object_new(cd->numGlyphs); + for (glyphid_t j = 0; j < cd->numGlyphs; j++) { + json_object_push(a, cd->glyphs[j].name, json_integer_new(cd->classes[j])); + } + return preserialize(a); +} + +static otl_ClassDef *parseClassDef(const json_value *_cd) { + if (!_cd || _cd->type != json_object) return NULL; + otl_ClassDef *cd = otl_iClassDef.create(); + for (glyphid_t j = 0; j < _cd->u.object.length; j++) { + glyph_handle h = Handle.fromName(sdsnewlen(_cd->u.object.values[j].name, _cd->u.object.values[j].name_length)); + json_value *_cid = _cd->u.object.values[j].value; + glyphclass_t cls = 0; + if (_cid->type == json_integer) { + cls = _cid->u.integer; + } else if (_cid->type == json_double) { + cls = _cid->u.dbl; + } + pushClassDef(cd, h, cls); + } + return cd; +} + +typedef struct { + glyphid_t gid; + glyphclass_t cid; +} classdef_sortrecord; + +static int by_gid(const void *a, const void *b) { + return ((const classdef_sortrecord *)a)->gid - ((const classdef_sortrecord *)b)->gid; +} +static caryll_Buffer *buildClassDef(const otl_ClassDef *cd) { + caryll_Buffer *buf = bufnew(); + bufwrite16b(buf, 2); + if (!cd->numGlyphs) { // no glyphs, return a blank classdef + bufwrite16b(buf, 0); + return buf; + } + + classdef_sortrecord *r; + NEW(r, cd->numGlyphs); + glyphid_t jj = 0; + for (glyphid_t j = 0; j < cd->numGlyphs; j++) { + if (cd->classes[j]) { + r[jj].gid = cd->glyphs[j].index; + r[jj].cid = cd->classes[j]; + jj++; + } + } + if (!jj) { // The classdef has only class 0 + FREE(r); + bufwrite16b(buf, 0); + return buf; + } + qsort(r, jj, sizeof(classdef_sortrecord), by_gid); + + glyphid_t startGID = r[0].gid; + glyphid_t endGID = startGID; + glyphclass_t lastClass = r[0].cid; + glyphid_t nRanges = 0; + glyphid_t lastGID = startGID; + caryll_Buffer *ranges = bufnew(); + for (glyphid_t j = 1; j < jj; j++) { + glyphid_t current = r[j].gid; + if (current <= lastGID) continue; + if (current == endGID + 1 && r[j].cid == lastClass) { + endGID = current; + } else { + bufwrite16b(ranges, startGID); + bufwrite16b(ranges, endGID); + bufwrite16b(ranges, lastClass); + nRanges += 1; + startGID = endGID = current; + lastClass = r[j].cid; + } + lastGID = current; + } + bufwrite16b(ranges, startGID); + bufwrite16b(ranges, endGID); + bufwrite16b(ranges, lastClass); + nRanges += 1; + bufwrite16b(buf, nRanges); + bufwrite_bufdel(buf, ranges); + FREE(r); + return buf; +} + +static void shrinkClassDef(otl_ClassDef *cd) { + glyphid_t k = 0; + for (glyphid_t j = 0; j < cd->numGlyphs; j++) { + if (cd->glyphs[j].name) { + cd->glyphs[k] = cd->glyphs[j]; + cd->classes[k] = cd->classes[j]; + k++; + } else { + Handle.dispose(&cd->glyphs[j]); + } + } + cd->numGlyphs = k; +} + +const struct __otfcc_IClassDef otl_iClassDef = { + caryll_standardRefTypeMethods(otl_ClassDef), + .read = readClassDef, + .expand = expandClassDef, + .dump = dumpClassDef, + .parse = parseClassDef, + .build = buildClassDef, + .shrink = shrinkClassDef, + .push = pushClassDef, +}; |