summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c
new file mode 100644
index 00000000000..f592d48d101
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/table/otl/coverage.c
@@ -0,0 +1,256 @@
+#include "support/util.h"
+#include "otfcc/table/otl/coverage.h"
+
+static INLINE void disposeCoverage(MOVE otl_Coverage *coverage) {
+ for (glyphid_t j = 0; j < coverage->numGlyphs; j++) {
+ Handle.dispose(&coverage->glyphs[j]);
+ }
+ FREE(coverage->glyphs);
+}
+caryll_standardRefTypeFn(otl_Coverage, disposeCoverage);
+
+static void growCoverage(otl_Coverage *coverage, uint32_t n) {
+ if (!n) return;
+ if (n > coverage->capacity) {
+ if (!coverage->capacity) coverage->capacity = 0x10;
+ while (n > coverage->capacity)
+ coverage->capacity += (coverage->capacity >> 1) & 0xFFFFFF;
+ RESIZE(coverage->glyphs, coverage->capacity);
+ }
+}
+static void clearCoverage(otl_Coverage *coverage, uint32_t n) {
+ if (!coverage || !coverage->glyphs) return;
+ for (glyphid_t j = 0; j < coverage->numGlyphs; j++) {
+ Handle.dispose(&coverage->glyphs[j]);
+ }
+ growCoverage(coverage, n);
+ coverage->numGlyphs = n;
+}
+
+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 void pushToCoverage(otl_Coverage *coverage, MOVE otfcc_GlyphHandle h) {
+ coverage->numGlyphs += 1;
+ growCoverage(coverage, coverage->numGlyphs);
+ coverage->glyphs[coverage->numGlyphs - 1] = h;
+}
+
+static otl_Coverage *readCoverage(const uint8_t *data, uint32_t tableLength, uint32_t offset) {
+ otl_Coverage *coverage = otl_iCoverage.create();
+ if (tableLength < offset + 4) return coverage;
+ uint16_t format = read_16u(data + offset);
+ switch (format) {
+ case 1: {
+ uint16_t glyphCount = read_16u(data + offset + 2);
+ if (tableLength < offset + 4 + glyphCount * 2) return coverage;
+ coverage_entry *hash = NULL;
+ for (uint16_t j = 0; j < glyphCount; j++) {
+ coverage_entry *item = NULL;
+ int gid = read_16u(data + offset + 4 + j * 2);
+ HASH_FIND_INT(hash, &gid, item);
+ if (!item) {
+ NEW(item);
+ item->gid = gid;
+ item->covIndex = j;
+ HASH_ADD_INT(hash, gid, item);
+ }
+ }
+ HASH_SORT(hash, by_covIndex);
+ coverage_entry *e, *tmp;
+ HASH_ITER(hh, hash, e, tmp) {
+ pushToCoverage(coverage, Handle.fromIndex(e->gid));
+ HASH_DEL(hash, e);
+ FREE(e);
+ }
+ break;
+ }
+ case 2: {
+ uint16_t rangeCount = read_16u(data + offset + 2);
+ if (tableLength < offset + 4 + rangeCount * 6) return coverage;
+ 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 startCoverageIndex = 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 = startCoverageIndex + k;
+ HASH_ADD_INT(hash, gid, item);
+ }
+ }
+ }
+ HASH_SORT(hash, by_covIndex);
+ coverage_entry *e, *tmp;
+ HASH_ITER(hh, hash, e, tmp) {
+ pushToCoverage(coverage, Handle.fromIndex(e->gid));
+ HASH_DEL(hash, e);
+ FREE(e);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return coverage;
+}
+
+static json_value *dumpCoverage(const otl_Coverage *coverage) {
+ json_value *a = json_array_new(coverage->numGlyphs);
+ for (glyphid_t j = 0; j < coverage->numGlyphs; j++) {
+ json_array_push(a, json_string_new(coverage->glyphs[j].name));
+ }
+ return preserialize(a);
+}
+
+static otl_Coverage *parseCoverage(const json_value *cov) {
+ otl_Coverage *c = otl_iCoverage.create();
+ if (!cov || cov->type != json_array) return c;
+
+ for (glyphid_t j = 0; j < cov->u.array.length; j++) {
+ if (cov->u.array.values[j]->type == json_string) {
+ pushToCoverage(c,
+ Handle.fromName(sdsnewlen(cov->u.array.values[j]->u.string.ptr,
+ cov->u.array.values[j]->u.string.length)));
+ }
+ }
+ return c;
+}
+
+static int by_gid(const void *a, const void *b) {
+ return *((const glyphid_t *)a) - *((const glyphid_t *)b);
+}
+
+static caryll_Buffer *buildCoverageFormat(const otl_Coverage *coverage, uint16_t format) {
+ // sort the gids in coverage
+ if (!coverage->numGlyphs) {
+ caryll_Buffer *buf = bufnew();
+ bufwrite16b(buf, 2);
+ bufwrite16b(buf, 0);
+ return buf;
+ }
+ glyphid_t *r;
+ NEW(r, coverage->numGlyphs);
+ glyphid_t jj = 0;
+ for (glyphid_t j = 0; j < coverage->numGlyphs; j++) {
+ r[jj] = coverage->glyphs[j].index;
+ jj++;
+ }
+ qsort(r, jj, sizeof(glyphid_t), by_gid);
+
+ caryll_Buffer *format1 = bufnew();
+ bufwrite16b(format1, 1);
+ bufwrite16b(format1, jj);
+ for (glyphid_t j = 0; j < jj; j++) {
+ bufwrite16b(format1, r[j]);
+ }
+ if (jj < 2) {
+ FREE(r);
+ return format1;
+ }
+
+ caryll_Buffer *format2 = bufnew();
+ bufwrite16b(format2, 2);
+ caryll_Buffer *ranges = bufnew();
+ glyphid_t startGID = r[0];
+ glyphid_t endGID = startGID;
+ glyphid_t lastGID = startGID;
+ glyphid_t nRanges = 0;
+ for (glyphid_t j = 1; j < jj; j++) {
+ glyphid_t current = r[j];
+ if (current <= lastGID) continue;
+ if (current == endGID + 1) {
+ endGID = current;
+ } else {
+ bufwrite16b(ranges, startGID);
+ bufwrite16b(ranges, endGID);
+ bufwrite16b(ranges, j + startGID - endGID - 1);
+ nRanges += 1;
+ startGID = endGID = current;
+ }
+ lastGID = current;
+ }
+ bufwrite16b(ranges, startGID);
+ bufwrite16b(ranges, endGID);
+ bufwrite16b(ranges, jj + startGID - endGID - 1);
+ nRanges += 1;
+ bufwrite16b(format2, nRanges);
+ bufwrite_bufdel(format2, ranges);
+
+ if (format == 1) {
+ buffree(format2);
+ FREE(r);
+ return format1;
+ } else if (format == 2) {
+ buffree(format1);
+ FREE(r);
+ return format2;
+ } else {
+ if (buflen(format1) < buflen(format2)) {
+ buffree(format2);
+ FREE(r);
+ return format1;
+ } else {
+ buffree(format1);
+ FREE(r);
+ return format2;
+ }
+ }
+}
+
+static caryll_Buffer *buildCoverage(const otl_Coverage *coverage) {
+ return buildCoverageFormat(coverage, 0);
+}
+
+static int byHandleGID(const void *a, const void *b) {
+ return ((const glyph_handle *)a)->index - ((const glyph_handle *)b)->index;
+}
+
+static void shrinkCoverage(otl_Coverage *coverage, bool dosort) {
+ if (!coverage) return;
+ glyphid_t k = 0;
+ for (glyphid_t j = 0; j < coverage->numGlyphs; j++) {
+ if (coverage->glyphs[j].name) {
+ coverage->glyphs[k++] = coverage->glyphs[j];
+ } else {
+ Handle.dispose(&coverage->glyphs[j]);
+ }
+ }
+ if (dosort) {
+ qsort(coverage->glyphs, k, sizeof(glyph_handle), byHandleGID);
+ glyphid_t skip = 0;
+ for (glyphid_t rear = 1; rear < k; rear++) {
+ if (coverage->glyphs[rear].index == coverage->glyphs[rear - skip - 1].index) {
+ Handle.dispose(&coverage->glyphs[rear]);
+ skip += 1;
+ } else {
+ coverage->glyphs[rear - skip] = coverage->glyphs[rear];
+ }
+ }
+ k -= skip;
+ }
+ coverage->numGlyphs = k;
+}
+
+const struct __otfcc_ICoverage otl_iCoverage = {
+ caryll_standardRefTypeMethods(otl_Coverage),
+ .clear = clearCoverage,
+ .read = readCoverage,
+ .dump = dumpCoverage,
+ .parse = parseCoverage,
+ .build = buildCoverage,
+ .buildFormat = buildCoverageFormat,
+ .shrink = shrinkCoverage,
+ .push = pushToCoverage,
+};