summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/classdef.c
diff options
context:
space:
mode:
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.c237
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,
+};